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