xref: /aosp_15_r20/tools/dexter/slicer/tryblocks_encoder.cc (revision f0dffb02cdb5c647d21204e89a92a1ffae2dad87)
1*f0dffb02SXin Li /*
2*f0dffb02SXin Li  * Copyright (C) 2017 The Android Open Source Project
3*f0dffb02SXin Li  *
4*f0dffb02SXin Li  * Licensed under the Apache License, Version 2.0 (the "License");
5*f0dffb02SXin Li  * you may not use this file except in compliance with the License.
6*f0dffb02SXin Li  * You may obtain a copy of the License at
7*f0dffb02SXin Li  *
8*f0dffb02SXin Li  *      http://www.apache.org/licenses/LICENSE-2.0
9*f0dffb02SXin Li  *
10*f0dffb02SXin Li  * Unless required by applicable law or agreed to in writing, software
11*f0dffb02SXin Li  * distributed under the License is distributed on an "AS IS" BASIS,
12*f0dffb02SXin Li  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*f0dffb02SXin Li  * See the License for the specific language governing permissions and
14*f0dffb02SXin Li  * limitations under the License.
15*f0dffb02SXin Li  */
16*f0dffb02SXin Li 
17*f0dffb02SXin Li #include "slicer/tryblocks_encoder.h"
18*f0dffb02SXin Li 
19*f0dffb02SXin Li #include "slicer/chronometer.h"
20*f0dffb02SXin Li #include "slicer/common.h"
21*f0dffb02SXin Li 
22*f0dffb02SXin Li namespace lir {
23*f0dffb02SXin Li 
Visit(TryBlockEnd * try_end)24*f0dffb02SXin Li bool TryBlocksEncoder::Visit(TryBlockEnd* try_end) {
25*f0dffb02SXin Li   const dex::u4 begin_offset = try_end->try_begin->offset;
26*f0dffb02SXin Li   const dex::u4 end_offset = try_end->offset;
27*f0dffb02SXin Li   SLICER_CHECK_GT(end_offset, begin_offset);
28*f0dffb02SXin Li   SLICER_CHECK_LT(end_offset - begin_offset, (1 << 16));
29*f0dffb02SXin Li 
30*f0dffb02SXin Li   // generate the "try_item"
31*f0dffb02SXin Li   dex::TryBlock try_block = {};
32*f0dffb02SXin Li   try_block.start_addr = begin_offset;
33*f0dffb02SXin Li   try_block.insn_count = end_offset - begin_offset;
34*f0dffb02SXin Li   try_block.handler_off = handlers_.size();
35*f0dffb02SXin Li   tries_.Push(try_block);
36*f0dffb02SXin Li 
37*f0dffb02SXin Li   // generate the "encoded_catch_handler"
38*f0dffb02SXin Li   dex::s4 catch_count = try_end->handlers.size();
39*f0dffb02SXin Li   handlers_.PushSLeb128(try_end->catch_all ? -catch_count : catch_count);
40*f0dffb02SXin Li   for (int catch_index = 0; catch_index < catch_count; ++catch_index) {
41*f0dffb02SXin Li     const CatchHandler& handler = try_end->handlers[catch_index];
42*f0dffb02SXin Li     // type_idx
43*f0dffb02SXin Li     handlers_.PushULeb128(handler.ir_type->orig_index);
44*f0dffb02SXin Li     // address
45*f0dffb02SXin Li     SLICER_CHECK_NE(handler.label->offset, kInvalidOffset);
46*f0dffb02SXin Li     handlers_.PushULeb128(handler.label->offset);
47*f0dffb02SXin Li   }
48*f0dffb02SXin Li   if (try_end->catch_all != nullptr) {
49*f0dffb02SXin Li     // address
50*f0dffb02SXin Li     SLICER_CHECK_NE(try_end->catch_all->offset, kInvalidOffset);
51*f0dffb02SXin Li     handlers_.PushULeb128(try_end->catch_all->offset);
52*f0dffb02SXin Li   }
53*f0dffb02SXin Li 
54*f0dffb02SXin Li   return true;
55*f0dffb02SXin Li }
56*f0dffb02SXin Li 
Encode(ir::Code * ir_code,std::shared_ptr<ir::DexFile> dex_ir)57*f0dffb02SXin Li void TryBlocksEncoder::Encode(ir::Code* ir_code, std::shared_ptr<ir::DexFile> dex_ir) {
58*f0dffb02SXin Li   SLICER_CHECK(handlers_.empty());
59*f0dffb02SXin Li   SLICER_CHECK(tries_.empty());
60*f0dffb02SXin Li 
61*f0dffb02SXin Li   // first, count the number of try blocks
62*f0dffb02SXin Li   struct TryBlockEndVisitor : public Visitor {
63*f0dffb02SXin Li     int tries_count = 0;
64*f0dffb02SXin Li     bool Visit(TryBlockEnd* try_end) override {
65*f0dffb02SXin Li       ++tries_count;
66*f0dffb02SXin Li       return true;
67*f0dffb02SXin Li     }
68*f0dffb02SXin Li   };
69*f0dffb02SXin Li   TryBlockEndVisitor visitor;
70*f0dffb02SXin Li   for (auto instr : instructions_) {
71*f0dffb02SXin Li     instr->Accept(&visitor);
72*f0dffb02SXin Li   }
73*f0dffb02SXin Li   int tries_count = visitor.tries_count;
74*f0dffb02SXin Li   SLICER_CHECK_LT(tries_count, (1 << 16));
75*f0dffb02SXin Li 
76*f0dffb02SXin Li   // no try blocks?
77*f0dffb02SXin Li   if (tries_count == 0) {
78*f0dffb02SXin Li     ir_code->try_blocks = {};
79*f0dffb02SXin Li     ir_code->catch_handlers = {};
80*f0dffb02SXin Li     return;
81*f0dffb02SXin Li   }
82*f0dffb02SXin Li 
83*f0dffb02SXin Li   // "encoded_catch_handler_list.size"
84*f0dffb02SXin Li   handlers_.PushULeb128(tries_count);
85*f0dffb02SXin Li 
86*f0dffb02SXin Li   // generate the try blocks & encoded catch handlers
87*f0dffb02SXin Li   //
88*f0dffb02SXin Li   // NOTE: try_item[tries_count] :
89*f0dffb02SXin Li   //  "Elements of the array must be non-overlapping in range and
90*f0dffb02SXin Li   //  in order from low to high address. This element is only present
91*f0dffb02SXin Li   //  if tries_size is non-zero"
92*f0dffb02SXin Li   //
93*f0dffb02SXin Li   // NOTE: we're not de-duplicating catch_handlers
94*f0dffb02SXin Li   //   (generate one catch_handler for each try block)
95*f0dffb02SXin Li   //
96*f0dffb02SXin Li   for (auto instr : instructions_) {
97*f0dffb02SXin Li     instr->Accept(this);
98*f0dffb02SXin Li   }
99*f0dffb02SXin Li   SLICER_CHECK(!tries_.empty());
100*f0dffb02SXin Li   SLICER_CHECK(!handlers_.empty());
101*f0dffb02SXin Li   tries_.Seal(1);
102*f0dffb02SXin Li   handlers_.Seal(1);
103*f0dffb02SXin Li 
104*f0dffb02SXin Li   // update ir::Code
105*f0dffb02SXin Li   auto tries_ptr = tries_.ptr<const dex::TryBlock>(0);
106*f0dffb02SXin Li   ir_code->try_blocks = slicer::ArrayView<const dex::TryBlock>(tries_ptr, tries_count);
107*f0dffb02SXin Li   ir_code->catch_handlers = slicer::MemView(handlers_.data(), handlers_.size());
108*f0dffb02SXin Li 
109*f0dffb02SXin Li   // attach the generated try/catch blocks to the dex IR
110*f0dffb02SXin Li   dex_ir->AttachBuffer(std::move(tries_));
111*f0dffb02SXin Li   dex_ir->AttachBuffer(std::move(handlers_));
112*f0dffb02SXin Li }
113*f0dffb02SXin Li 
114*f0dffb02SXin Li }  // namespace lir
115