xref: /aosp_15_r20/external/zucchini/disassembler_dex.cc (revision a03ca8b91e029cd15055c20c78c2e087c84792e4)
1*a03ca8b9SKrzysztof Kosiński // Copyright 2018 The Chromium Authors. All rights reserved.
2*a03ca8b9SKrzysztof Kosiński // Use of this source code is governed by a BSD-style license that can be
3*a03ca8b9SKrzysztof Kosiński // found in the LICENSE file.
4*a03ca8b9SKrzysztof Kosiński 
5*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/disassembler_dex.h"
6*a03ca8b9SKrzysztof Kosiński 
7*a03ca8b9SKrzysztof Kosiński #include <stddef.h>
8*a03ca8b9SKrzysztof Kosiński #include <stdlib.h>
9*a03ca8b9SKrzysztof Kosiński 
10*a03ca8b9SKrzysztof Kosiński #include <algorithm>
11*a03ca8b9SKrzysztof Kosiński #include <cctype>
12*a03ca8b9SKrzysztof Kosiński #include <cmath>
13*a03ca8b9SKrzysztof Kosiński #include <iterator>
14*a03ca8b9SKrzysztof Kosiński #include <optional>
15*a03ca8b9SKrzysztof Kosiński #include <set>
16*a03ca8b9SKrzysztof Kosiński #include <utility>
17*a03ca8b9SKrzysztof Kosiński 
18*a03ca8b9SKrzysztof Kosiński #include "base/bind.h"
19*a03ca8b9SKrzysztof Kosiński #include "base/callback.h"
20*a03ca8b9SKrzysztof Kosiński #include "base/logging.h"
21*a03ca8b9SKrzysztof Kosiński #include "base/numerics/checked_math.h"
22*a03ca8b9SKrzysztof Kosiński #include "base/numerics/safe_conversions.h"
23*a03ca8b9SKrzysztof Kosiński #include "base/strings/stringprintf.h"
24*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/buffer_source.h"
25*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/buffer_view.h"
26*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/io_utils.h"
27*a03ca8b9SKrzysztof Kosiński 
28*a03ca8b9SKrzysztof Kosiński namespace zucchini {
29*a03ca8b9SKrzysztof Kosiński 
30*a03ca8b9SKrzysztof Kosiński namespace {
31*a03ca8b9SKrzysztof Kosiński 
32*a03ca8b9SKrzysztof Kosiński // A DEX item specified by an offset, if absent, has a sentinel value of 0 since
33*a03ca8b9SKrzysztof Kosiński // 0 is never a valid item offset (it points to magic at start of DEX).
34*a03ca8b9SKrzysztof Kosiński constexpr offset_t kDexSentinelOffset = 0U;
35*a03ca8b9SKrzysztof Kosiński 
36*a03ca8b9SKrzysztof Kosiński // A DEX item specified by an index, if absent, has a sentinel value of
37*a03ca8b9SKrzysztof Kosiński // NO_INDEX = 0xFFFFFFFF. This is represented as an offset_t for uniformity.
38*a03ca8b9SKrzysztof Kosiński constexpr offset_t kDexSentinelIndexAsOffset = 0xFFFFFFFFU;
39*a03ca8b9SKrzysztof Kosiński 
40*a03ca8b9SKrzysztof Kosiński static_assert(kDexSentinelIndexAsOffset != kInvalidOffset,
41*a03ca8b9SKrzysztof Kosiński               "Sentinel should not be confused with invalid offset.");
42*a03ca8b9SKrzysztof Kosiński 
43*a03ca8b9SKrzysztof Kosiński // Size of a Dalvik instruction unit. Need to cast to signed int because
44*a03ca8b9SKrzysztof Kosiński // sizeof() gives size_t, which dominates when operated on ptrdiff_t, then
45*a03ca8b9SKrzysztof Kosiński // wrecks havoc for base::checked_cast<int16_t>().
46*a03ca8b9SKrzysztof Kosiński constexpr int kInstrUnitSize = static_cast<int>(sizeof(uint16_t));
47*a03ca8b9SKrzysztof Kosiński 
48*a03ca8b9SKrzysztof Kosiński // Checks if |offset| is byte aligned to 32 bits or 4 bytes.
Is32BitAligned(offset_t offset)49*a03ca8b9SKrzysztof Kosiński bool Is32BitAligned(offset_t offset) {
50*a03ca8b9SKrzysztof Kosiński   return offset % 4 == 0;
51*a03ca8b9SKrzysztof Kosiński }
52*a03ca8b9SKrzysztof Kosiński 
53*a03ca8b9SKrzysztof Kosiński // Returns a lower bound for the size of an item of type |type_item_code|.
54*a03ca8b9SKrzysztof Kosiński // - For fixed-length items (e.g., kTypeFieldIdItem) this is the exact size.
55*a03ca8b9SKrzysztof Kosiński // - For variant-length items (e.g., kTypeCodeItem), returns a value that is
56*a03ca8b9SKrzysztof Kosiński //   known to be less than the item length (e.g., header size).
57*a03ca8b9SKrzysztof Kosiński // - For items not handled by this function, returns 1 for sanity check.
GetItemBaseSize(uint16_t type_item_code)58*a03ca8b9SKrzysztof Kosiński size_t GetItemBaseSize(uint16_t type_item_code) {
59*a03ca8b9SKrzysztof Kosiński   switch (type_item_code) {
60*a03ca8b9SKrzysztof Kosiński     case dex::kTypeStringIdItem:
61*a03ca8b9SKrzysztof Kosiński       return sizeof(dex::StringIdItem);
62*a03ca8b9SKrzysztof Kosiński     case dex::kTypeTypeIdItem:
63*a03ca8b9SKrzysztof Kosiński       return sizeof(dex::TypeIdItem);
64*a03ca8b9SKrzysztof Kosiński     case dex::kTypeProtoIdItem:
65*a03ca8b9SKrzysztof Kosiński       return sizeof(dex::ProtoIdItem);
66*a03ca8b9SKrzysztof Kosiński     case dex::kTypeFieldIdItem:
67*a03ca8b9SKrzysztof Kosiński       return sizeof(dex::FieldIdItem);
68*a03ca8b9SKrzysztof Kosiński     case dex::kTypeMethodIdItem:
69*a03ca8b9SKrzysztof Kosiński       return sizeof(dex::MethodIdItem);
70*a03ca8b9SKrzysztof Kosiński     case dex::kTypeClassDefItem:
71*a03ca8b9SKrzysztof Kosiński       return sizeof(dex::ClassDefItem);
72*a03ca8b9SKrzysztof Kosiński     case dex::kTypeCallSiteIdItem:
73*a03ca8b9SKrzysztof Kosiński       return sizeof(dex::CallSiteIdItem);
74*a03ca8b9SKrzysztof Kosiński     case dex::kTypeMethodHandleItem:
75*a03ca8b9SKrzysztof Kosiński       return sizeof(dex::MethodHandleItem);
76*a03ca8b9SKrzysztof Kosiński     // No need to handle dex::kTypeMapList.
77*a03ca8b9SKrzysztof Kosiński     case dex::kTypeTypeList:
78*a03ca8b9SKrzysztof Kosiński       return sizeof(uint32_t);  // Variable-length.
79*a03ca8b9SKrzysztof Kosiński     case dex::kTypeAnnotationSetRefList:
80*a03ca8b9SKrzysztof Kosiński       return sizeof(uint32_t);  // Variable-length.
81*a03ca8b9SKrzysztof Kosiński     case dex::kTypeAnnotationSetItem:
82*a03ca8b9SKrzysztof Kosiński       return sizeof(uint32_t);  // Variable-length.
83*a03ca8b9SKrzysztof Kosiński     case dex::kTypeCodeItem:
84*a03ca8b9SKrzysztof Kosiński       return sizeof(dex::CodeItem);  // Variable-length.
85*a03ca8b9SKrzysztof Kosiński     case dex::kTypeAnnotationsDirectoryItem:
86*a03ca8b9SKrzysztof Kosiński       return sizeof(dex::AnnotationsDirectoryItem);  // Variable-length.
87*a03ca8b9SKrzysztof Kosiński     default:
88*a03ca8b9SKrzysztof Kosiński       return 1U;  // Unhandled item. For sanity check assume size >= 1.
89*a03ca8b9SKrzysztof Kosiński   }
90*a03ca8b9SKrzysztof Kosiński }
91*a03ca8b9SKrzysztof Kosiński 
92*a03ca8b9SKrzysztof Kosiński /******** CodeItemParser ********/
93*a03ca8b9SKrzysztof Kosiński 
94*a03ca8b9SKrzysztof Kosiński // A parser to extract successive code items from a DEX image whose header has
95*a03ca8b9SKrzysztof Kosiński // been parsed.
96*a03ca8b9SKrzysztof Kosiński class CodeItemParser {
97*a03ca8b9SKrzysztof Kosiński  public:
98*a03ca8b9SKrzysztof Kosiński   using size_type = BufferSource::size_type;
99*a03ca8b9SKrzysztof Kosiński 
CodeItemParser(ConstBufferView image)100*a03ca8b9SKrzysztof Kosiński   explicit CodeItemParser(ConstBufferView image) : image_(image) {}
101*a03ca8b9SKrzysztof Kosiński 
102*a03ca8b9SKrzysztof Kosiński   // Initializes the parser, returns true on success and false on error.
Init(const dex::MapItem & code_map_item)103*a03ca8b9SKrzysztof Kosiński   bool Init(const dex::MapItem& code_map_item) {
104*a03ca8b9SKrzysztof Kosiński     // Sanity check to quickly fail if |code_map_item.offset| or
105*a03ca8b9SKrzysztof Kosiński     // |code_map_item.size| is too large. This is a heuristic because code item
106*a03ca8b9SKrzysztof Kosiński     // sizes need to be parsed (sizeof(dex::CodeItem) is a lower bound).
107*a03ca8b9SKrzysztof Kosiński     if (!image_.covers_array(code_map_item.offset, code_map_item.size,
108*a03ca8b9SKrzysztof Kosiński                              sizeof(dex::CodeItem))) {
109*a03ca8b9SKrzysztof Kosiński       return false;
110*a03ca8b9SKrzysztof Kosiński     }
111*a03ca8b9SKrzysztof Kosiński     source_ = std::move(BufferSource(image_).Skip(code_map_item.offset));
112*a03ca8b9SKrzysztof Kosiński     return true;
113*a03ca8b9SKrzysztof Kosiński   }
114*a03ca8b9SKrzysztof Kosiński 
115*a03ca8b9SKrzysztof Kosiński   // Extracts the header of the next code item, and skips the variable-length
116*a03ca8b9SKrzysztof Kosiński   // data. Returns the offset of the code item if successful. Otherwise returns
117*a03ca8b9SKrzysztof Kosiński   // kInvalidOffset, and thereafter the parser becomes valid. For reference,
118*a03ca8b9SKrzysztof Kosiński   // here's a pseudo-struct of a complete code item:
119*a03ca8b9SKrzysztof Kosiński   //
120*a03ca8b9SKrzysztof Kosiński   // struct code_item {
121*a03ca8b9SKrzysztof Kosiński   //   // 4-byte aligned here.
122*a03ca8b9SKrzysztof Kosiński   //   // 16-byte header defined (dex::CodeItem).
123*a03ca8b9SKrzysztof Kosiński   //   uint16_t registers_size;
124*a03ca8b9SKrzysztof Kosiński   //   uint16_t ins_size;
125*a03ca8b9SKrzysztof Kosiński   //   uint16_t outs_size;
126*a03ca8b9SKrzysztof Kosiński   //   uint16_t tries_size;
127*a03ca8b9SKrzysztof Kosiński   //   uint32_t debug_info_off;
128*a03ca8b9SKrzysztof Kosiński   //   uint32_t insns_size;
129*a03ca8b9SKrzysztof Kosiński   //
130*a03ca8b9SKrzysztof Kosiński   //   // Variable-length data follow.
131*a03ca8b9SKrzysztof Kosiński   //   uint16_t insns[insns_size];  // Instruction bytes.
132*a03ca8b9SKrzysztof Kosiński   //   uint16_t padding[(tries_size > 0 && insns_size % 2 == 1) ? 1 : 0];
133*a03ca8b9SKrzysztof Kosiński   //
134*a03ca8b9SKrzysztof Kosiński   //   if (tries_size > 0) {
135*a03ca8b9SKrzysztof Kosiński   //     // 4-byte aligned here.
136*a03ca8b9SKrzysztof Kosiński   //     struct try_item {  // dex::TryItem.
137*a03ca8b9SKrzysztof Kosiński   //       uint32_t start_addr;
138*a03ca8b9SKrzysztof Kosiński   //       uint16_t insn_count;
139*a03ca8b9SKrzysztof Kosiński   //       uint16_t handler_off;
140*a03ca8b9SKrzysztof Kosiński   //     } tries[tries_size];
141*a03ca8b9SKrzysztof Kosiński   //
142*a03ca8b9SKrzysztof Kosiński   //     struct encoded_catch_handler_list {
143*a03ca8b9SKrzysztof Kosiński   //       uleb128 handlers_size;
144*a03ca8b9SKrzysztof Kosiński   //       struct encoded_catch_handler {
145*a03ca8b9SKrzysztof Kosiński   //         sleb128 encoded_catch_handler_size;
146*a03ca8b9SKrzysztof Kosiński   //         struct encoded_type_addr_pair {
147*a03ca8b9SKrzysztof Kosiński   //           uleb128 type_idx;
148*a03ca8b9SKrzysztof Kosiński   //           uleb128 addr;
149*a03ca8b9SKrzysztof Kosiński   //         } handlers[abs(encoded_catch_handler_size)];
150*a03ca8b9SKrzysztof Kosiński   //         if (encoded_catch_handler_size <= 0) {
151*a03ca8b9SKrzysztof Kosiński   //           uleb128 catch_all_addr;
152*a03ca8b9SKrzysztof Kosiński   //         }
153*a03ca8b9SKrzysztof Kosiński   //       } handlers_list[handlers_size];
154*a03ca8b9SKrzysztof Kosiński   //     } handlers_group;  // Confusingly called "handlers" in DEX doc.
155*a03ca8b9SKrzysztof Kosiński   //   }
156*a03ca8b9SKrzysztof Kosiński   //
157*a03ca8b9SKrzysztof Kosiński   //   // Padding to 4-bytes align next code_item *only if more exist*.
158*a03ca8b9SKrzysztof Kosiński   // }
GetNext()159*a03ca8b9SKrzysztof Kosiński   offset_t GetNext() {
160*a03ca8b9SKrzysztof Kosiński     // Read header CodeItem.
161*a03ca8b9SKrzysztof Kosiński     if (!source_.AlignOn(image_, 4U))
162*a03ca8b9SKrzysztof Kosiński       return kInvalidOffset;
163*a03ca8b9SKrzysztof Kosiński     const offset_t code_item_offset =
164*a03ca8b9SKrzysztof Kosiński         base::checked_cast<offset_t>(source_.begin() - image_.begin());
165*a03ca8b9SKrzysztof Kosiński     const auto* code_item = source_.GetPointer<const dex::CodeItem>();
166*a03ca8b9SKrzysztof Kosiński     if (!code_item)
167*a03ca8b9SKrzysztof Kosiński       return kInvalidOffset;
168*a03ca8b9SKrzysztof Kosiński     DCHECK(Is32BitAligned(code_item_offset));
169*a03ca8b9SKrzysztof Kosiński 
170*a03ca8b9SKrzysztof Kosiński     // TODO(huangs): Fail if |code_item->insns_size == 0| (Constraint A1).
171*a03ca8b9SKrzysztof Kosiński     // Skip instruction bytes.
172*a03ca8b9SKrzysztof Kosiński     if (!source_.GetArray<uint16_t>(code_item->insns_size))
173*a03ca8b9SKrzysztof Kosiński       return kInvalidOffset;
174*a03ca8b9SKrzysztof Kosiński     // Skip padding if present.
175*a03ca8b9SKrzysztof Kosiński     if (code_item->tries_size > 0 && !source_.AlignOn(image_, 4U))
176*a03ca8b9SKrzysztof Kosiński       return kInvalidOffset;
177*a03ca8b9SKrzysztof Kosiński 
178*a03ca8b9SKrzysztof Kosiński     // Skip tries[] and handlers_group to arrive at the next code item. Parsing
179*a03ca8b9SKrzysztof Kosiński     // is nontrivial due to use of uleb128 / sleb128.
180*a03ca8b9SKrzysztof Kosiński     if (code_item->tries_size > 0) {
181*a03ca8b9SKrzysztof Kosiński       // Skip (try_item) tries[].
182*a03ca8b9SKrzysztof Kosiński       if (!source_.GetArray<dex::TryItem>(code_item->tries_size))
183*a03ca8b9SKrzysztof Kosiński         return kInvalidOffset;
184*a03ca8b9SKrzysztof Kosiński 
185*a03ca8b9SKrzysztof Kosiński       // Skip handlers_group.
186*a03ca8b9SKrzysztof Kosiński       uint32_t handlers_size = 0;
187*a03ca8b9SKrzysztof Kosiński       if (!source_.GetUleb128(&handlers_size))
188*a03ca8b9SKrzysztof Kosiński         return kInvalidOffset;
189*a03ca8b9SKrzysztof Kosiński       // Sanity check to quickly reject excessively large |handlers_size|.
190*a03ca8b9SKrzysztof Kosiński       if (source_.Remaining() < static_cast<size_type>(handlers_size))
191*a03ca8b9SKrzysztof Kosiński         return kInvalidOffset;
192*a03ca8b9SKrzysztof Kosiński 
193*a03ca8b9SKrzysztof Kosiński       // Skip (encoded_catch_handler) handlers_list[].
194*a03ca8b9SKrzysztof Kosiński       for (uint32_t k = 0; k < handlers_size; ++k) {
195*a03ca8b9SKrzysztof Kosiński         int32_t encoded_catch_handler_size = 0;
196*a03ca8b9SKrzysztof Kosiński         if (!source_.GetSleb128(&encoded_catch_handler_size))
197*a03ca8b9SKrzysztof Kosiński           return kInvalidOffset;
198*a03ca8b9SKrzysztof Kosiński         const size_type abs_size = std::abs(encoded_catch_handler_size);
199*a03ca8b9SKrzysztof Kosiński         if (source_.Remaining() < abs_size)  // Sanity check.
200*a03ca8b9SKrzysztof Kosiński           return kInvalidOffset;
201*a03ca8b9SKrzysztof Kosiński         // Skip (encoded_type_addr_pair) handlers[].
202*a03ca8b9SKrzysztof Kosiński         for (size_type j = 0; j < abs_size; ++j) {
203*a03ca8b9SKrzysztof Kosiński           if (!source_.SkipLeb128() || !source_.SkipLeb128())
204*a03ca8b9SKrzysztof Kosiński             return kInvalidOffset;
205*a03ca8b9SKrzysztof Kosiński         }
206*a03ca8b9SKrzysztof Kosiński         // Skip catch_all_addr.
207*a03ca8b9SKrzysztof Kosiński         if (encoded_catch_handler_size <= 0) {
208*a03ca8b9SKrzysztof Kosiński           if (!source_.SkipLeb128())
209*a03ca8b9SKrzysztof Kosiński             return kInvalidOffset;
210*a03ca8b9SKrzysztof Kosiński         }
211*a03ca8b9SKrzysztof Kosiński       }
212*a03ca8b9SKrzysztof Kosiński     }
213*a03ca8b9SKrzysztof Kosiński     // Success! |code_item->insns_size| is validated, but its content is still
214*a03ca8b9SKrzysztof Kosiński     // considered unsafe and requires validation.
215*a03ca8b9SKrzysztof Kosiński     return code_item_offset;
216*a03ca8b9SKrzysztof Kosiński   }
217*a03ca8b9SKrzysztof Kosiński 
218*a03ca8b9SKrzysztof Kosiński   // Given |code_item_offset| that points to the start of a valid code item in
219*a03ca8b9SKrzysztof Kosiński   // |image|, returns |insns| bytes as ConstBufferView.
GetCodeItemInsns(ConstBufferView image,offset_t code_item_offset)220*a03ca8b9SKrzysztof Kosiński   static ConstBufferView GetCodeItemInsns(ConstBufferView image,
221*a03ca8b9SKrzysztof Kosiński                                           offset_t code_item_offset) {
222*a03ca8b9SKrzysztof Kosiński     BufferSource source(BufferSource(image).Skip(code_item_offset));
223*a03ca8b9SKrzysztof Kosiński     const auto* code_item = source.GetPointer<const dex::CodeItem>();
224*a03ca8b9SKrzysztof Kosiński     DCHECK(code_item);
225*a03ca8b9SKrzysztof Kosiński     BufferRegion insns{0, code_item->insns_size * kInstrUnitSize};
226*a03ca8b9SKrzysztof Kosiński     DCHECK(source.covers(insns));
227*a03ca8b9SKrzysztof Kosiński     return source[insns];
228*a03ca8b9SKrzysztof Kosiński   }
229*a03ca8b9SKrzysztof Kosiński 
230*a03ca8b9SKrzysztof Kosiński  private:
231*a03ca8b9SKrzysztof Kosiński   ConstBufferView image_;
232*a03ca8b9SKrzysztof Kosiński   BufferSource source_;
233*a03ca8b9SKrzysztof Kosiński };
234*a03ca8b9SKrzysztof Kosiński 
235*a03ca8b9SKrzysztof Kosiński /******** InstructionParser ********/
236*a03ca8b9SKrzysztof Kosiński 
237*a03ca8b9SKrzysztof Kosiński // A class that successively reads |code_item| for Dalvik instructions, which
238*a03ca8b9SKrzysztof Kosiński // are found at |insns|, spanning |insns_size| uint16_t "units". These units
239*a03ca8b9SKrzysztof Kosiński // store instructions followed by optional non-instruction "payload". Finding
240*a03ca8b9SKrzysztof Kosiński // payload boundary requires parsing: On finding an instruction that uses (and
241*a03ca8b9SKrzysztof Kosiński // points to) payload, the boundary is updated.
242*a03ca8b9SKrzysztof Kosiński class InstructionParser {
243*a03ca8b9SKrzysztof Kosiński  public:
244*a03ca8b9SKrzysztof Kosiński   struct Value {
245*a03ca8b9SKrzysztof Kosiński     offset_t instr_offset;
246*a03ca8b9SKrzysztof Kosiński     const dex::Instruction* instr = nullptr;  // null for unknown instructions.
247*a03ca8b9SKrzysztof Kosiński   };
248*a03ca8b9SKrzysztof Kosiński 
249*a03ca8b9SKrzysztof Kosiński   // Returns pointer to DEX Instruction data for |opcode|, or null if |opcode|
250*a03ca8b9SKrzysztof Kosiński   // is unknown. An internal initialize-on-first-use table is used for fast
251*a03ca8b9SKrzysztof Kosiński   // lookup.
FindDalvikInstruction(uint8_t opcode)252*a03ca8b9SKrzysztof Kosiński   const dex::Instruction* FindDalvikInstruction(uint8_t opcode) {
253*a03ca8b9SKrzysztof Kosiński     static bool is_init = false;
254*a03ca8b9SKrzysztof Kosiński     static const dex::Instruction* instruction_table[256];
255*a03ca8b9SKrzysztof Kosiński     if (!is_init) {
256*a03ca8b9SKrzysztof Kosiński       is_init = true;
257*a03ca8b9SKrzysztof Kosiński       std::fill(std::begin(instruction_table), std::end(instruction_table),
258*a03ca8b9SKrzysztof Kosiński                 nullptr);
259*a03ca8b9SKrzysztof Kosiński       for (const dex::Instruction& instr : dex::kByteCode) {
260*a03ca8b9SKrzysztof Kosiński         std::fill(instruction_table + instr.opcode,
261*a03ca8b9SKrzysztof Kosiński                   instruction_table + instr.opcode + instr.variant, &instr);
262*a03ca8b9SKrzysztof Kosiński       }
263*a03ca8b9SKrzysztof Kosiński     }
264*a03ca8b9SKrzysztof Kosiński     return instruction_table[opcode];
265*a03ca8b9SKrzysztof Kosiński   }
266*a03ca8b9SKrzysztof Kosiński 
267*a03ca8b9SKrzysztof Kosiński   InstructionParser() = default;
268*a03ca8b9SKrzysztof Kosiński 
InstructionParser(ConstBufferView image,offset_t base_offset)269*a03ca8b9SKrzysztof Kosiński   InstructionParser(ConstBufferView image, offset_t base_offset)
270*a03ca8b9SKrzysztof Kosiński       : image_begin_(image.begin()),
271*a03ca8b9SKrzysztof Kosiński         insns_(CodeItemParser::GetCodeItemInsns(image, base_offset)),
272*a03ca8b9SKrzysztof Kosiński         payload_boundary_(insns_.end()) {}
273*a03ca8b9SKrzysztof Kosiński 
274*a03ca8b9SKrzysztof Kosiński   // Reads the next instruction. On success, makes the data read available via
275*a03ca8b9SKrzysztof Kosiński   // value() and returns true. Otherwise (done or found error) returns false.
ReadNext()276*a03ca8b9SKrzysztof Kosiński   bool ReadNext() {
277*a03ca8b9SKrzysztof Kosiński     // Do not scan past payload boundary.
278*a03ca8b9SKrzysztof Kosiński     if (insns_.begin() >= payload_boundary_)
279*a03ca8b9SKrzysztof Kosiński       return false;
280*a03ca8b9SKrzysztof Kosiński 
281*a03ca8b9SKrzysztof Kosiński     const offset_t instr_offset =
282*a03ca8b9SKrzysztof Kosiński         base::checked_cast<offset_t>(insns_.begin() - image_begin_);
283*a03ca8b9SKrzysztof Kosiński     const uint8_t op = insns_.read<uint8_t>(0);
284*a03ca8b9SKrzysztof Kosiński     const dex::Instruction* instr = FindDalvikInstruction(op);
285*a03ca8b9SKrzysztof Kosiński 
286*a03ca8b9SKrzysztof Kosiński     // Stop on finding unknown instructions. ODEX files might trigger this.
287*a03ca8b9SKrzysztof Kosiński     if (!instr) {
288*a03ca8b9SKrzysztof Kosiński       LOG(WARNING) << "Unknown Dalvik instruction detected at "
289*a03ca8b9SKrzysztof Kosiński                    << AsHex<8>(instr_offset) << ".";
290*a03ca8b9SKrzysztof Kosiński       return false;
291*a03ca8b9SKrzysztof Kosiński     }
292*a03ca8b9SKrzysztof Kosiński 
293*a03ca8b9SKrzysztof Kosiński     const int instr_length_units = instr->layout;
294*a03ca8b9SKrzysztof Kosiński     const size_t instr_length_bytes = instr_length_units * kInstrUnitSize;
295*a03ca8b9SKrzysztof Kosiński     if (insns_.size() < instr_length_bytes)
296*a03ca8b9SKrzysztof Kosiński       return false;
297*a03ca8b9SKrzysztof Kosiński 
298*a03ca8b9SKrzysztof Kosiński     // Handle instructions with variable-length data payload (31t).
299*a03ca8b9SKrzysztof Kosiński     if (instr->opcode == 0x26 ||  // fill-array-data
300*a03ca8b9SKrzysztof Kosiński         instr->opcode == 0x2B ||  // packed-switch
301*a03ca8b9SKrzysztof Kosiński         instr->opcode == 0x2C) {  // sparse-switch
302*a03ca8b9SKrzysztof Kosiński       const int32_t unsafe_payload_rel_units = insns_.read<int32_t>(2);
303*a03ca8b9SKrzysztof Kosiński       // Payload must be in current code item, after current instruction.
304*a03ca8b9SKrzysztof Kosiński       if (unsafe_payload_rel_units < instr_length_units ||
305*a03ca8b9SKrzysztof Kosiński           static_cast<uint32_t>(unsafe_payload_rel_units) >=
306*a03ca8b9SKrzysztof Kosiński               insns_.size() / kInstrUnitSize) {
307*a03ca8b9SKrzysztof Kosiński         LOG(WARNING) << "Invalid payload found.";
308*a03ca8b9SKrzysztof Kosiński         return false;
309*a03ca8b9SKrzysztof Kosiński       }
310*a03ca8b9SKrzysztof Kosiński       // Update boundary between instructions and payload.
311*a03ca8b9SKrzysztof Kosiński       const ConstBufferView::const_iterator payload_it =
312*a03ca8b9SKrzysztof Kosiński           insns_.begin() + unsafe_payload_rel_units * kInstrUnitSize;
313*a03ca8b9SKrzysztof Kosiński       payload_boundary_ = std::min(payload_boundary_, payload_it);
314*a03ca8b9SKrzysztof Kosiński     }
315*a03ca8b9SKrzysztof Kosiński 
316*a03ca8b9SKrzysztof Kosiński     insns_.remove_prefix(instr_length_bytes);
317*a03ca8b9SKrzysztof Kosiński     value_ = {instr_offset, instr};
318*a03ca8b9SKrzysztof Kosiński     return true;
319*a03ca8b9SKrzysztof Kosiński   }
320*a03ca8b9SKrzysztof Kosiński 
value() const321*a03ca8b9SKrzysztof Kosiński   const Value& value() const { return value_; }
322*a03ca8b9SKrzysztof Kosiński 
323*a03ca8b9SKrzysztof Kosiński  private:
324*a03ca8b9SKrzysztof Kosiński   ConstBufferView::const_iterator image_begin_;
325*a03ca8b9SKrzysztof Kosiński   ConstBufferView insns_;
326*a03ca8b9SKrzysztof Kosiński   ConstBufferView::const_iterator payload_boundary_;
327*a03ca8b9SKrzysztof Kosiński   Value value_;
328*a03ca8b9SKrzysztof Kosiński };
329*a03ca8b9SKrzysztof Kosiński 
330*a03ca8b9SKrzysztof Kosiński /******** InstructionReferenceReader ********/
331*a03ca8b9SKrzysztof Kosiński 
332*a03ca8b9SKrzysztof Kosiński // A class to visit |code_items|, parse instructions, and emit embedded
333*a03ca8b9SKrzysztof Kosiński // References of a type determined by |filter_| and |mapper_|. Only References
334*a03ca8b9SKrzysztof Kosiński // located in |[lo, hi)| are emitted. |lo| and |hi| are assumed to never
335*a03ca8b9SKrzysztof Kosiński // straddle the body of a Reference.
336*a03ca8b9SKrzysztof Kosiński class InstructionReferenceReader : public ReferenceReader {
337*a03ca8b9SKrzysztof Kosiński  public:
338*a03ca8b9SKrzysztof Kosiński   // A function that takes a parsed Dalvik instruction and decides whether it
339*a03ca8b9SKrzysztof Kosiński   // contains a specific type of Reference. If true, then returns the Reference
340*a03ca8b9SKrzysztof Kosiński   // location. Otherwise returns kInvalidOffset.
341*a03ca8b9SKrzysztof Kosiński   using Filter =
342*a03ca8b9SKrzysztof Kosiński       base::RepeatingCallback<offset_t(const InstructionParser::Value&)>;
343*a03ca8b9SKrzysztof Kosiński   // A function that takes Reference location from |filter_| to extract the
344*a03ca8b9SKrzysztof Kosiński   // stored target. If valid, returns it. Otherwise returns kInvalidOffset.
345*a03ca8b9SKrzysztof Kosiński   using Mapper = base::RepeatingCallback<offset_t(offset_t)>;
346*a03ca8b9SKrzysztof Kosiński 
InstructionReferenceReader(ConstBufferView image,offset_t lo,offset_t hi,const std::vector<offset_t> & code_item_offsets,Filter && filter,Mapper && mapper)347*a03ca8b9SKrzysztof Kosiński   InstructionReferenceReader(ConstBufferView image,
348*a03ca8b9SKrzysztof Kosiński                              offset_t lo,
349*a03ca8b9SKrzysztof Kosiński                              offset_t hi,
350*a03ca8b9SKrzysztof Kosiński                              const std::vector<offset_t>& code_item_offsets,
351*a03ca8b9SKrzysztof Kosiński                              Filter&& filter,
352*a03ca8b9SKrzysztof Kosiński                              Mapper&& mapper)
353*a03ca8b9SKrzysztof Kosiński       : image_(image),
354*a03ca8b9SKrzysztof Kosiński         lo_(lo),
355*a03ca8b9SKrzysztof Kosiński         hi_(hi),
356*a03ca8b9SKrzysztof Kosiński         end_it_(code_item_offsets.end()),
357*a03ca8b9SKrzysztof Kosiński         filter_(std::move(filter)),
358*a03ca8b9SKrzysztof Kosiński         mapper_(std::move(mapper)) {
359*a03ca8b9SKrzysztof Kosiński     const auto begin_it = code_item_offsets.begin();
360*a03ca8b9SKrzysztof Kosiński     // Use binary search to find the code item that contains |lo_|.
361*a03ca8b9SKrzysztof Kosiński     auto comp = [](offset_t test_offset, offset_t code_item_offset) {
362*a03ca8b9SKrzysztof Kosiński       return test_offset < code_item_offset;
363*a03ca8b9SKrzysztof Kosiński     };
364*a03ca8b9SKrzysztof Kosiński     cur_it_ = std::upper_bound(begin_it, end_it_, lo_, comp);
365*a03ca8b9SKrzysztof Kosiński     if (cur_it_ != begin_it)
366*a03ca8b9SKrzysztof Kosiński       --cur_it_;
367*a03ca8b9SKrzysztof Kosiński     parser_ = InstructionParser(image_, *cur_it_);
368*a03ca8b9SKrzysztof Kosiński   }
369*a03ca8b9SKrzysztof Kosiński 
370*a03ca8b9SKrzysztof Kosiński   // ReferenceReader:
GetNext()371*a03ca8b9SKrzysztof Kosiński   std::optional<Reference> GetNext() override {
372*a03ca8b9SKrzysztof Kosiński     while (true) {
373*a03ca8b9SKrzysztof Kosiński       while (parser_.ReadNext()) {
374*a03ca8b9SKrzysztof Kosiński         const auto& v = parser_.value();
375*a03ca8b9SKrzysztof Kosiński         DCHECK_NE(v.instr, nullptr);
376*a03ca8b9SKrzysztof Kosiński         if (v.instr_offset >= hi_)
377*a03ca8b9SKrzysztof Kosiński           return std::nullopt;
378*a03ca8b9SKrzysztof Kosiński         const offset_t location = filter_.Run(v);
379*a03ca8b9SKrzysztof Kosiński         if (location == kInvalidOffset || location < lo_)
380*a03ca8b9SKrzysztof Kosiński           continue;
381*a03ca8b9SKrzysztof Kosiński         // The general check is |location + reference_width > hi_|. However, by
382*a03ca8b9SKrzysztof Kosiński         // assumption |hi_| and |lo_| do not straddle the body of a Reference.
383*a03ca8b9SKrzysztof Kosiński         // So |reference_width| is unneeded.
384*a03ca8b9SKrzysztof Kosiński         if (location >= hi_)
385*a03ca8b9SKrzysztof Kosiński           return std::nullopt;
386*a03ca8b9SKrzysztof Kosiński         offset_t target = mapper_.Run(location);
387*a03ca8b9SKrzysztof Kosiński         if (target != kInvalidOffset)
388*a03ca8b9SKrzysztof Kosiński           return Reference{location, target};
389*a03ca8b9SKrzysztof Kosiński         else
390*a03ca8b9SKrzysztof Kosiński           LOG(WARNING) << "Invalid target at " << AsHex<8>(location) << ".";
391*a03ca8b9SKrzysztof Kosiński       }
392*a03ca8b9SKrzysztof Kosiński       ++cur_it_;
393*a03ca8b9SKrzysztof Kosiński       if (cur_it_ == end_it_)
394*a03ca8b9SKrzysztof Kosiński         return std::nullopt;
395*a03ca8b9SKrzysztof Kosiński       parser_ = InstructionParser(image_, *cur_it_);
396*a03ca8b9SKrzysztof Kosiński     }
397*a03ca8b9SKrzysztof Kosiński   }
398*a03ca8b9SKrzysztof Kosiński 
399*a03ca8b9SKrzysztof Kosiński  private:
400*a03ca8b9SKrzysztof Kosiński   const ConstBufferView image_;
401*a03ca8b9SKrzysztof Kosiński   const offset_t lo_;
402*a03ca8b9SKrzysztof Kosiński   const offset_t hi_;
403*a03ca8b9SKrzysztof Kosiński   const std::vector<offset_t>::const_iterator end_it_;
404*a03ca8b9SKrzysztof Kosiński   const Filter filter_;
405*a03ca8b9SKrzysztof Kosiński   const Mapper mapper_;
406*a03ca8b9SKrzysztof Kosiński   std::vector<offset_t>::const_iterator cur_it_;
407*a03ca8b9SKrzysztof Kosiński   InstructionParser parser_;
408*a03ca8b9SKrzysztof Kosiński };
409*a03ca8b9SKrzysztof Kosiński 
410*a03ca8b9SKrzysztof Kosiński /******** ItemReferenceReader ********/
411*a03ca8b9SKrzysztof Kosiński 
412*a03ca8b9SKrzysztof Kosiński // A class to visit fixed-size item elements (determined by |item_size|) and
413*a03ca8b9SKrzysztof Kosiński // emit a "member variable of interest" (MVI, determined by |rel_location| and
414*a03ca8b9SKrzysztof Kosiński // |mapper|) as Reference. Only MVIs lying in |[lo, hi)| are emitted. |lo| and
415*a03ca8b9SKrzysztof Kosiński // |hi| are assumed to never straddle the body of a Reference.
416*a03ca8b9SKrzysztof Kosiński class ItemReferenceReader : public ReferenceReader {
417*a03ca8b9SKrzysztof Kosiński  public:
418*a03ca8b9SKrzysztof Kosiński   // A function that takes an MVI's location and emit its target offset.
419*a03ca8b9SKrzysztof Kosiński   using Mapper = base::RepeatingCallback<offset_t(offset_t)>;
420*a03ca8b9SKrzysztof Kosiński 
421*a03ca8b9SKrzysztof Kosiński   // |item_size| is the size of a fixed-size item. |rel_location| is the
422*a03ca8b9SKrzysztof Kosiński   // relative location of MVI from the start of the item containing it.
423*a03ca8b9SKrzysztof Kosiński   // |rel_item_offset| is the offset to use relative to |item_offset| in cases
424*a03ca8b9SKrzysztof Kosiński   // where a value other than |rel_location| is required. For an example of this
425*a03ca8b9SKrzysztof Kosiński   // see ReadMethodHandleFieldOrMethodId.
ItemReferenceReader(offset_t lo,offset_t hi,const dex::MapItem & map_item,size_t item_size,size_t rel_location,Mapper && mapper,bool mapper_wants_item=false)426*a03ca8b9SKrzysztof Kosiński   ItemReferenceReader(offset_t lo,
427*a03ca8b9SKrzysztof Kosiński                       offset_t hi,
428*a03ca8b9SKrzysztof Kosiński                       const dex::MapItem& map_item,
429*a03ca8b9SKrzysztof Kosiński                       size_t item_size,
430*a03ca8b9SKrzysztof Kosiński                       size_t rel_location,
431*a03ca8b9SKrzysztof Kosiński                       Mapper&& mapper,
432*a03ca8b9SKrzysztof Kosiński                       bool mapper_wants_item = false)
433*a03ca8b9SKrzysztof Kosiński       : hi_(hi),
434*a03ca8b9SKrzysztof Kosiński         item_base_offset_(base::checked_cast<offset_t>(map_item.offset)),
435*a03ca8b9SKrzysztof Kosiński         num_items_(base::checked_cast<uint32_t>(map_item.size)),
436*a03ca8b9SKrzysztof Kosiński         item_size_(base::checked_cast<uint32_t>(item_size)),
437*a03ca8b9SKrzysztof Kosiński         rel_location_(base::checked_cast<uint32_t>(rel_location)),
438*a03ca8b9SKrzysztof Kosiński         mapper_input_delta_(
439*a03ca8b9SKrzysztof Kosiński             mapper_wants_item ? 0 : base::checked_cast<uint32_t>(rel_location)),
440*a03ca8b9SKrzysztof Kosiński         mapper_(std::move(mapper)) {
441*a03ca8b9SKrzysztof Kosiński     static_assert(sizeof(decltype(map_item.offset)) <= sizeof(offset_t),
442*a03ca8b9SKrzysztof Kosiński                   "map_item.offset too large.");
443*a03ca8b9SKrzysztof Kosiński     static_assert(sizeof(decltype(map_item.size)) <= sizeof(offset_t),
444*a03ca8b9SKrzysztof Kosiński                   "map_item.size too large.");
445*a03ca8b9SKrzysztof Kosiński     if (!item_base_offset_) {
446*a03ca8b9SKrzysztof Kosiński       // Empty item: Assign |cur_idx| to |num_items_| to skip everything.
447*a03ca8b9SKrzysztof Kosiński       cur_idx_ = num_items_;
448*a03ca8b9SKrzysztof Kosiński     } else if (lo < item_base_offset_) {
449*a03ca8b9SKrzysztof Kosiński       cur_idx_ = 0;
450*a03ca8b9SKrzysztof Kosiński     } else if (lo < OffsetOfIndex(num_items_)) {
451*a03ca8b9SKrzysztof Kosiński       cur_idx_ = (lo - item_base_offset_) / item_size_;
452*a03ca8b9SKrzysztof Kosiński       // Fine-tune: Advance if |lo| lies beyond the MVI.
453*a03ca8b9SKrzysztof Kosiński       if (lo > OffsetOfIndex(cur_idx_) + rel_location_)
454*a03ca8b9SKrzysztof Kosiński         ++cur_idx_;
455*a03ca8b9SKrzysztof Kosiński     } else {
456*a03ca8b9SKrzysztof Kosiński       cur_idx_ = num_items_;
457*a03ca8b9SKrzysztof Kosiński     }
458*a03ca8b9SKrzysztof Kosiński   }
459*a03ca8b9SKrzysztof Kosiński 
460*a03ca8b9SKrzysztof Kosiński   // ReferenceReader:
GetNext()461*a03ca8b9SKrzysztof Kosiński   std::optional<Reference> GetNext() override {
462*a03ca8b9SKrzysztof Kosiński     while (cur_idx_ < num_items_) {
463*a03ca8b9SKrzysztof Kosiński       const offset_t item_offset = OffsetOfIndex(cur_idx_);
464*a03ca8b9SKrzysztof Kosiński       const offset_t location = item_offset + rel_location_;
465*a03ca8b9SKrzysztof Kosiński       // The general check is |location + reference_width > hi_|. However, by
466*a03ca8b9SKrzysztof Kosiński       // assumption |hi_| and |lo_| do not straddle the body of a Reference. So
467*a03ca8b9SKrzysztof Kosiński       // |reference_width| is unneeded.
468*a03ca8b9SKrzysztof Kosiński       if (location >= hi_)
469*a03ca8b9SKrzysztof Kosiński         break;
470*a03ca8b9SKrzysztof Kosiński 
471*a03ca8b9SKrzysztof Kosiński       // |location == item_offset + mapper_input_delta_| in the majority of
472*a03ca8b9SKrzysztof Kosiński       // cases. The exception is when |mapper_| wants an item aligned location
473*a03ca8b9SKrzysztof Kosiński       // instead e.g. ReadMethodHandleFieldOrMethodId.
474*a03ca8b9SKrzysztof Kosiński       const offset_t target = mapper_.Run(item_offset + mapper_input_delta_);
475*a03ca8b9SKrzysztof Kosiński 
476*a03ca8b9SKrzysztof Kosiński       // kDexSentinelOffset (0) may appear for the following:
477*a03ca8b9SKrzysztof Kosiński       // - ProtoIdItem: parameters_off.
478*a03ca8b9SKrzysztof Kosiński       // - ClassDefItem: interfaces_off, annotations_off, class_data_off,
479*a03ca8b9SKrzysztof Kosiński       //   static_values_off.
480*a03ca8b9SKrzysztof Kosiński       // - AnnotationsDirectoryItem: class_annotations_off.
481*a03ca8b9SKrzysztof Kosiński       // - AnnotationSetRefItem: annotations_off.
482*a03ca8b9SKrzysztof Kosiński       // kDexSentinelIndexAsOffset (0xFFFFFFFF) may appear for the following:
483*a03ca8b9SKrzysztof Kosiński       // - ClassDefItem: superclass_idx, source_file_idx.
484*a03ca8b9SKrzysztof Kosiński       // - MethodHandleItem: |mapper_| uses ReadMethodHandleFieldOrMethodId and
485*a03ca8b9SKrzysztof Kosiński       //   determines the item at |cur_idx_| is not of the required reference
486*a03ca8b9SKrzysztof Kosiński       //   type.
487*a03ca8b9SKrzysztof Kosiński       if (target == kDexSentinelOffset || target == kDexSentinelIndexAsOffset) {
488*a03ca8b9SKrzysztof Kosiński         ++cur_idx_;
489*a03ca8b9SKrzysztof Kosiński         continue;
490*a03ca8b9SKrzysztof Kosiński       }
491*a03ca8b9SKrzysztof Kosiński 
492*a03ca8b9SKrzysztof Kosiński       if (target == kInvalidOffset) {
493*a03ca8b9SKrzysztof Kosiński         LOG(WARNING) << "Invalid item target at " << AsHex<8>(location) << ".";
494*a03ca8b9SKrzysztof Kosiński         break;
495*a03ca8b9SKrzysztof Kosiński       }
496*a03ca8b9SKrzysztof Kosiński       ++cur_idx_;
497*a03ca8b9SKrzysztof Kosiński       return Reference{location, target};
498*a03ca8b9SKrzysztof Kosiński     }
499*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
500*a03ca8b9SKrzysztof Kosiński   }
501*a03ca8b9SKrzysztof Kosiński 
502*a03ca8b9SKrzysztof Kosiński  private:
OffsetOfIndex(uint32_t idx)503*a03ca8b9SKrzysztof Kosiński   offset_t OffsetOfIndex(uint32_t idx) {
504*a03ca8b9SKrzysztof Kosiński     return base::checked_cast<uint32_t>(item_base_offset_ + idx * item_size_);
505*a03ca8b9SKrzysztof Kosiński   }
506*a03ca8b9SKrzysztof Kosiński 
507*a03ca8b9SKrzysztof Kosiński   const offset_t hi_;
508*a03ca8b9SKrzysztof Kosiński   const offset_t item_base_offset_;
509*a03ca8b9SKrzysztof Kosiński   const uint32_t num_items_;
510*a03ca8b9SKrzysztof Kosiński   const uint32_t item_size_;
511*a03ca8b9SKrzysztof Kosiński   const uint32_t rel_location_;
512*a03ca8b9SKrzysztof Kosiński   const uint32_t mapper_input_delta_;
513*a03ca8b9SKrzysztof Kosiński   const Mapper mapper_;
514*a03ca8b9SKrzysztof Kosiński   offset_t cur_idx_ = 0;
515*a03ca8b9SKrzysztof Kosiński };
516*a03ca8b9SKrzysztof Kosiński 
517*a03ca8b9SKrzysztof Kosiński // Parses a flattened jagged list of lists of items that looks like:
518*a03ca8b9SKrzysztof Kosiński //   NTTT|NTT|NTTTT|N|NTT...
519*a03ca8b9SKrzysztof Kosiński // where |N| is an uint32_t representing the number of items in each sub-list,
520*a03ca8b9SKrzysztof Kosiński // and "T" is a fixed-size item (|item_width|) of type "T". On success, stores
521*a03ca8b9SKrzysztof Kosiński // the offset of each |T| into |item_offsets|, and returns true. Otherwise
522*a03ca8b9SKrzysztof Kosiński // (e.g., on finding any structural problem) returns false.
ParseItemOffsets(ConstBufferView image,const dex::MapItem & map_item,size_t item_width,std::vector<offset_t> * item_offsets)523*a03ca8b9SKrzysztof Kosiński bool ParseItemOffsets(ConstBufferView image,
524*a03ca8b9SKrzysztof Kosiński                       const dex::MapItem& map_item,
525*a03ca8b9SKrzysztof Kosiński                       size_t item_width,
526*a03ca8b9SKrzysztof Kosiński                       std::vector<offset_t>* item_offsets) {
527*a03ca8b9SKrzysztof Kosiński   // Sanity check: |image| should at least fit |map_item.size| copies of "N".
528*a03ca8b9SKrzysztof Kosiński   if (!image.covers_array(map_item.offset, map_item.size, sizeof(uint32_t)))
529*a03ca8b9SKrzysztof Kosiński     return false;
530*a03ca8b9SKrzysztof Kosiński   BufferSource source = std::move(BufferSource(image).Skip(map_item.offset));
531*a03ca8b9SKrzysztof Kosiński   item_offsets->clear();
532*a03ca8b9SKrzysztof Kosiński   for (uint32_t i = 0; i < map_item.size; ++i) {
533*a03ca8b9SKrzysztof Kosiński     if (!source.AlignOn(image, 4U))
534*a03ca8b9SKrzysztof Kosiński       return false;
535*a03ca8b9SKrzysztof Kosiński     uint32_t unsafe_size;
536*a03ca8b9SKrzysztof Kosiński     if (!source.GetValue<uint32_t>(&unsafe_size))
537*a03ca8b9SKrzysztof Kosiński       return false;
538*a03ca8b9SKrzysztof Kosiński     DCHECK(Is32BitAligned(
539*a03ca8b9SKrzysztof Kosiński         base::checked_cast<offset_t>(source.begin() - image.begin())));
540*a03ca8b9SKrzysztof Kosiński     if (!source.covers_array(0, unsafe_size, item_width))
541*a03ca8b9SKrzysztof Kosiński       return false;
542*a03ca8b9SKrzysztof Kosiński     for (uint32_t j = 0; j < unsafe_size; ++j) {
543*a03ca8b9SKrzysztof Kosiński       item_offsets->push_back(
544*a03ca8b9SKrzysztof Kosiński           base::checked_cast<offset_t>(source.begin() - image.begin()));
545*a03ca8b9SKrzysztof Kosiński       source.Skip(item_width);
546*a03ca8b9SKrzysztof Kosiński     }
547*a03ca8b9SKrzysztof Kosiński   }
548*a03ca8b9SKrzysztof Kosiński   return true;
549*a03ca8b9SKrzysztof Kosiński }
550*a03ca8b9SKrzysztof Kosiński 
551*a03ca8b9SKrzysztof Kosiński // Parses AnnotationDirectoryItems of the format (using RegEx) "(AF*M*P*)*",
552*a03ca8b9SKrzysztof Kosiński // where:
553*a03ca8b9SKrzysztof Kosiński //   A = AnnotationsDirectoryItem (contains class annotation),
554*a03ca8b9SKrzysztof Kosiński //   F = FieldAnnotation,
555*a03ca8b9SKrzysztof Kosiński //   M = MethodAnnotation,
556*a03ca8b9SKrzysztof Kosiński //   P = ParameterAnnotation.
557*a03ca8b9SKrzysztof Kosiński // On success, stores the offsets of each class, field, method and parameter
558*a03ca8b9SKrzysztof Kosiński // annotation for each item into |*_annotation_offsets|. Otherwise on finding
559*a03ca8b9SKrzysztof Kosiński // structural issues returns false.
ParseAnnotationsDirectoryItems(ConstBufferView image,const dex::MapItem & annotations_directory_map_item,std::vector<offset_t> * annotations_directory_item_offsets,std::vector<offset_t> * field_annotation_offsets,std::vector<offset_t> * method_annotation_offsets,std::vector<offset_t> * parameter_annotation_offsets)560*a03ca8b9SKrzysztof Kosiński bool ParseAnnotationsDirectoryItems(
561*a03ca8b9SKrzysztof Kosiński     ConstBufferView image,
562*a03ca8b9SKrzysztof Kosiński     const dex::MapItem& annotations_directory_map_item,
563*a03ca8b9SKrzysztof Kosiński     std::vector<offset_t>* annotations_directory_item_offsets,
564*a03ca8b9SKrzysztof Kosiński     std::vector<offset_t>* field_annotation_offsets,
565*a03ca8b9SKrzysztof Kosiński     std::vector<offset_t>* method_annotation_offsets,
566*a03ca8b9SKrzysztof Kosiński     std::vector<offset_t>* parameter_annotation_offsets) {
567*a03ca8b9SKrzysztof Kosiński   // Sanity check: |image| should at least fit
568*a03ca8b9SKrzysztof Kosiński   // |annotations_directory_map_item.size| copies of "A".
569*a03ca8b9SKrzysztof Kosiński   if (!image.covers_array(annotations_directory_map_item.offset,
570*a03ca8b9SKrzysztof Kosiński                           annotations_directory_map_item.size,
571*a03ca8b9SKrzysztof Kosiński                           sizeof(dex::AnnotationsDirectoryItem))) {
572*a03ca8b9SKrzysztof Kosiński     return false;
573*a03ca8b9SKrzysztof Kosiński   }
574*a03ca8b9SKrzysztof Kosiński   BufferSource source = std::move(
575*a03ca8b9SKrzysztof Kosiński       BufferSource(image).Skip(annotations_directory_map_item.offset));
576*a03ca8b9SKrzysztof Kosiński   annotations_directory_item_offsets->clear();
577*a03ca8b9SKrzysztof Kosiński   field_annotation_offsets->clear();
578*a03ca8b9SKrzysztof Kosiński   method_annotation_offsets->clear();
579*a03ca8b9SKrzysztof Kosiński   parameter_annotation_offsets->clear();
580*a03ca8b9SKrzysztof Kosiński 
581*a03ca8b9SKrzysztof Kosiński   // Helper to process sublists.
582*a03ca8b9SKrzysztof Kosiński   auto parse_list = [&source, image](uint32_t unsafe_size, size_t item_width,
583*a03ca8b9SKrzysztof Kosiński                                      std::vector<offset_t>* item_offsets) {
584*a03ca8b9SKrzysztof Kosiński     DCHECK(Is32BitAligned(
585*a03ca8b9SKrzysztof Kosiński         base::checked_cast<offset_t>(source.begin() - image.begin())));
586*a03ca8b9SKrzysztof Kosiński     if (!source.covers_array(0, unsafe_size, item_width))
587*a03ca8b9SKrzysztof Kosiński       return false;
588*a03ca8b9SKrzysztof Kosiński     item_offsets->reserve(item_offsets->size() + unsafe_size);
589*a03ca8b9SKrzysztof Kosiński     for (uint32_t i = 0; i < unsafe_size; ++i) {
590*a03ca8b9SKrzysztof Kosiński       item_offsets->push_back(
591*a03ca8b9SKrzysztof Kosiński           base::checked_cast<offset_t>(source.begin() - image.begin()));
592*a03ca8b9SKrzysztof Kosiński       source.Skip(item_width);
593*a03ca8b9SKrzysztof Kosiński     }
594*a03ca8b9SKrzysztof Kosiński     return true;
595*a03ca8b9SKrzysztof Kosiński   };
596*a03ca8b9SKrzysztof Kosiński 
597*a03ca8b9SKrzysztof Kosiński   annotations_directory_item_offsets->reserve(
598*a03ca8b9SKrzysztof Kosiński       annotations_directory_map_item.size);
599*a03ca8b9SKrzysztof Kosiński   for (uint32_t i = 0; i < annotations_directory_map_item.size; ++i) {
600*a03ca8b9SKrzysztof Kosiński     if (!source.AlignOn(image, 4U))
601*a03ca8b9SKrzysztof Kosiński       return false;
602*a03ca8b9SKrzysztof Kosiński     // Parse header.
603*a03ca8b9SKrzysztof Kosiński     annotations_directory_item_offsets->push_back(
604*a03ca8b9SKrzysztof Kosiński         base::checked_cast<offset_t>(source.begin() - image.begin()));
605*a03ca8b9SKrzysztof Kosiński     dex::AnnotationsDirectoryItem unsafe_annotations_directory_item;
606*a03ca8b9SKrzysztof Kosiński     if (!source.GetValue(&unsafe_annotations_directory_item))
607*a03ca8b9SKrzysztof Kosiński       return false;
608*a03ca8b9SKrzysztof Kosiński     // Parse sublists.
609*a03ca8b9SKrzysztof Kosiński     if (!(parse_list(unsafe_annotations_directory_item.fields_size,
610*a03ca8b9SKrzysztof Kosiński                      sizeof(dex::FieldAnnotation), field_annotation_offsets) &&
611*a03ca8b9SKrzysztof Kosiński           parse_list(unsafe_annotations_directory_item.annotated_methods_size,
612*a03ca8b9SKrzysztof Kosiński                      sizeof(dex::MethodAnnotation),
613*a03ca8b9SKrzysztof Kosiński                      method_annotation_offsets) &&
614*a03ca8b9SKrzysztof Kosiński           parse_list(
615*a03ca8b9SKrzysztof Kosiński               unsafe_annotations_directory_item.annotated_parameters_size,
616*a03ca8b9SKrzysztof Kosiński               sizeof(dex::ParameterAnnotation),
617*a03ca8b9SKrzysztof Kosiński               parameter_annotation_offsets))) {
618*a03ca8b9SKrzysztof Kosiński       return false;
619*a03ca8b9SKrzysztof Kosiński     }
620*a03ca8b9SKrzysztof Kosiński   }
621*a03ca8b9SKrzysztof Kosiński   return true;
622*a03ca8b9SKrzysztof Kosiński }
623*a03ca8b9SKrzysztof Kosiński 
624*a03ca8b9SKrzysztof Kosiński /******** CachedItemListReferenceReader ********/
625*a03ca8b9SKrzysztof Kosiński 
626*a03ca8b9SKrzysztof Kosiński // A class that takes sorted |item_offsets|, and emits all member variable of
627*a03ca8b9SKrzysztof Kosiński // interest (MVIs) that fall inside |[lo, hi)|. The MVI of each item has
628*a03ca8b9SKrzysztof Kosiński // location of |rel_location| from item offset, and has target extracted with
629*a03ca8b9SKrzysztof Kosiński // |mapper| (which performs validation). By the "atomicity assumption",
630*a03ca8b9SKrzysztof Kosiński // [|lo, hi)| never cut across an MVI.
631*a03ca8b9SKrzysztof Kosiński class CachedItemListReferenceReader : public ReferenceReader {
632*a03ca8b9SKrzysztof Kosiński  public:
633*a03ca8b9SKrzysztof Kosiński   // A function that takes an MVI's location and emit its target offset.
634*a03ca8b9SKrzysztof Kosiński   using Mapper = base::RepeatingCallback<offset_t(offset_t)>;
635*a03ca8b9SKrzysztof Kosiński 
CachedItemListReferenceReader(offset_t lo,offset_t hi,uint32_t rel_location,const std::vector<offset_t> & item_offsets,Mapper && mapper)636*a03ca8b9SKrzysztof Kosiński   CachedItemListReferenceReader(offset_t lo,
637*a03ca8b9SKrzysztof Kosiński                                 offset_t hi,
638*a03ca8b9SKrzysztof Kosiński                                 uint32_t rel_location,
639*a03ca8b9SKrzysztof Kosiński                                 const std::vector<offset_t>& item_offsets,
640*a03ca8b9SKrzysztof Kosiński                                 Mapper&& mapper)
641*a03ca8b9SKrzysztof Kosiński       : hi_(hi),
642*a03ca8b9SKrzysztof Kosiński         rel_location_(rel_location),
643*a03ca8b9SKrzysztof Kosiński         end_it_(item_offsets.cend()),
644*a03ca8b9SKrzysztof Kosiński         mapper_(mapper) {
645*a03ca8b9SKrzysztof Kosiński     cur_it_ = std::upper_bound(item_offsets.cbegin(), item_offsets.cend(), lo);
646*a03ca8b9SKrzysztof Kosiński     // Adding |rel_location_| is necessary as references can be offset from the
647*a03ca8b9SKrzysztof Kosiński     // start of the item.
648*a03ca8b9SKrzysztof Kosiński     if (cur_it_ != item_offsets.begin() && *(cur_it_ - 1) + rel_location_ >= lo)
649*a03ca8b9SKrzysztof Kosiński       --cur_it_;
650*a03ca8b9SKrzysztof Kosiński   }
651*a03ca8b9SKrzysztof Kosiński   CachedItemListReferenceReader(const CachedItemListReferenceReader&) = delete;
652*a03ca8b9SKrzysztof Kosiński   const CachedItemListReferenceReader& operator=(
653*a03ca8b9SKrzysztof Kosiński       const CachedItemListReferenceReader&) = delete;
654*a03ca8b9SKrzysztof Kosiński 
655*a03ca8b9SKrzysztof Kosiński   // ReferenceReader:
GetNext()656*a03ca8b9SKrzysztof Kosiński   std::optional<Reference> GetNext() override {
657*a03ca8b9SKrzysztof Kosiński     while (cur_it_ < end_it_) {
658*a03ca8b9SKrzysztof Kosiński       const offset_t location = *cur_it_ + rel_location_;
659*a03ca8b9SKrzysztof Kosiński       if (location >= hi_)  // Check is simplified by atomicity assumption.
660*a03ca8b9SKrzysztof Kosiński         break;
661*a03ca8b9SKrzysztof Kosiński       const offset_t target = mapper_.Run(location);
662*a03ca8b9SKrzysztof Kosiński       if (target == kInvalidOffset) {
663*a03ca8b9SKrzysztof Kosiński         LOG(WARNING) << "Invalid item target at " << AsHex<8>(location) << ".";
664*a03ca8b9SKrzysztof Kosiński         break;
665*a03ca8b9SKrzysztof Kosiński       }
666*a03ca8b9SKrzysztof Kosiński       ++cur_it_;
667*a03ca8b9SKrzysztof Kosiński 
668*a03ca8b9SKrzysztof Kosiński       // kDexSentinelOffset is a sentinel for;
669*a03ca8b9SKrzysztof Kosiński       // - AnnotationsDirectoryItem: class_annotations_off
670*a03ca8b9SKrzysztof Kosiński       if (target == kDexSentinelOffset)
671*a03ca8b9SKrzysztof Kosiński         continue;
672*a03ca8b9SKrzysztof Kosiński       return Reference{location, target};
673*a03ca8b9SKrzysztof Kosiński     }
674*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
675*a03ca8b9SKrzysztof Kosiński   }
676*a03ca8b9SKrzysztof Kosiński 
677*a03ca8b9SKrzysztof Kosiński  private:
678*a03ca8b9SKrzysztof Kosiński   const offset_t hi_;
679*a03ca8b9SKrzysztof Kosiński   const uint32_t rel_location_;
680*a03ca8b9SKrzysztof Kosiński   const std::vector<offset_t>::const_iterator end_it_;
681*a03ca8b9SKrzysztof Kosiński   const Mapper mapper_;
682*a03ca8b9SKrzysztof Kosiński   std::vector<offset_t>::const_iterator cur_it_;
683*a03ca8b9SKrzysztof Kosiński };
684*a03ca8b9SKrzysztof Kosiński 
685*a03ca8b9SKrzysztof Kosiński // Reads an INT index at |location| in |image| and translates the index to the
686*a03ca8b9SKrzysztof Kosiński // offset of a fixed-size item specified by |target_map_item| and
687*a03ca8b9SKrzysztof Kosiński // |target_item_size|. Returns the target offset if valid, or kInvalidOffset
688*a03ca8b9SKrzysztof Kosiński // otherwise. This is compatible with
689*a03ca8b9SKrzysztof Kosiński // CachedReferenceListReferenceReader::Mapper,
690*a03ca8b9SKrzysztof Kosiński // InstructionReferenceReader::Mapper, and ItemReferenceReader::Mapper.
691*a03ca8b9SKrzysztof Kosiński template <typename INT>
ReadTargetIndex(ConstBufferView image,const dex::MapItem & target_map_item,size_t target_item_size,offset_t location)692*a03ca8b9SKrzysztof Kosiński static offset_t ReadTargetIndex(ConstBufferView image,
693*a03ca8b9SKrzysztof Kosiński                                 const dex::MapItem& target_map_item,
694*a03ca8b9SKrzysztof Kosiński                                 size_t target_item_size,
695*a03ca8b9SKrzysztof Kosiński                                 offset_t location) {
696*a03ca8b9SKrzysztof Kosiński   static_assert(sizeof(INT) <= sizeof(offset_t),
697*a03ca8b9SKrzysztof Kosiński                 "INT may not fit into offset_t.");
698*a03ca8b9SKrzysztof Kosiński   const offset_t unsafe_idx = image.read<INT>(location);
699*a03ca8b9SKrzysztof Kosiński   // kDexSentinalIndexAsOffset (0xFFFFFFFF) is a sentinel for
700*a03ca8b9SKrzysztof Kosiński   // - ClassDefItem: superclass_idx, source_file_idx.
701*a03ca8b9SKrzysztof Kosiński   if (unsafe_idx == kDexSentinelIndexAsOffset)
702*a03ca8b9SKrzysztof Kosiński     return unsafe_idx;
703*a03ca8b9SKrzysztof Kosiński   if (unsafe_idx >= target_map_item.size)
704*a03ca8b9SKrzysztof Kosiński     return kInvalidOffset;
705*a03ca8b9SKrzysztof Kosiński   return target_map_item.offset +
706*a03ca8b9SKrzysztof Kosiński          base::checked_cast<offset_t>(unsafe_idx * target_item_size);
707*a03ca8b9SKrzysztof Kosiński }
708*a03ca8b9SKrzysztof Kosiński 
709*a03ca8b9SKrzysztof Kosiński // Reads a field or method index of the MethodHandleItem located at |location|
710*a03ca8b9SKrzysztof Kosiński // in |image| and translates |method_handle_item.field_or_method_id| to the
711*a03ca8b9SKrzysztof Kosiński // offset of a fixed-size item specified by |target_map_item| and
712*a03ca8b9SKrzysztof Kosiński // |target_item_size|. The index is deemed to be of the correct target type if
713*a03ca8b9SKrzysztof Kosiński // |method_handle_item.method_handle_type| falls within the range [|min_type|,
714*a03ca8b9SKrzysztof Kosiński // |max_type|]. If the target type is correct ReadTargetIndex is called.
715*a03ca8b9SKrzysztof Kosiński // Returns the target offset if valid, or kDexSentinelIndexAsOffset if
716*a03ca8b9SKrzysztof Kosiński // |method_handle_item.method_handle_type| is of the wrong type, or
717*a03ca8b9SKrzysztof Kosiński // kInvalidOffset otherwise.
718*a03ca8b9SKrzysztof Kosiński //
719*a03ca8b9SKrzysztof Kosiński // As of DEX version 39 MethodHandleType values for FieldId and MethodId each
720*a03ca8b9SKrzysztof Kosiński // form one consecutive block of values. If this changes, then the interface to
721*a03ca8b9SKrzysztof Kosiński // this function will need to be redesigned.
ReadMethodHandleFieldOrMethodId(ConstBufferView image,const dex::MapItem & target_map_item,size_t target_item_size,dex::MethodHandleType min_type,dex::MethodHandleType max_type,offset_t location)722*a03ca8b9SKrzysztof Kosiński static offset_t ReadMethodHandleFieldOrMethodId(
723*a03ca8b9SKrzysztof Kosiński     ConstBufferView image,
724*a03ca8b9SKrzysztof Kosiński     const dex::MapItem& target_map_item,
725*a03ca8b9SKrzysztof Kosiński     size_t target_item_size,
726*a03ca8b9SKrzysztof Kosiński     dex::MethodHandleType min_type,
727*a03ca8b9SKrzysztof Kosiński     dex::MethodHandleType max_type,
728*a03ca8b9SKrzysztof Kosiński     offset_t location) {
729*a03ca8b9SKrzysztof Kosiński   dex::MethodHandleItem method_handle_item =
730*a03ca8b9SKrzysztof Kosiński       image.read<dex::MethodHandleItem>(location);
731*a03ca8b9SKrzysztof Kosiński 
732*a03ca8b9SKrzysztof Kosiński   // Cannot use base::checked_cast as dex::MethodHandleType is an enum class so
733*a03ca8b9SKrzysztof Kosiński   // static_assert on the size instead.
734*a03ca8b9SKrzysztof Kosiński   static_assert(sizeof(decltype(dex::MethodHandleItem::method_handle_type)) <=
735*a03ca8b9SKrzysztof Kosiński                     sizeof(dex::MethodHandleType),
736*a03ca8b9SKrzysztof Kosiński                 "dex::MethodHandleItem::method_handle_type may not fit into "
737*a03ca8b9SKrzysztof Kosiński                 "dex::MethodHandleType.");
738*a03ca8b9SKrzysztof Kosiński   dex::MethodHandleType method_handle_type =
739*a03ca8b9SKrzysztof Kosiński       static_cast<dex::MethodHandleType>(method_handle_item.method_handle_type);
740*a03ca8b9SKrzysztof Kosiński 
741*a03ca8b9SKrzysztof Kosiński   if (method_handle_type >= dex::MethodHandleType::kMaxMethodHandleType) {
742*a03ca8b9SKrzysztof Kosiński     return kInvalidOffset;
743*a03ca8b9SKrzysztof Kosiński   }
744*a03ca8b9SKrzysztof Kosiński 
745*a03ca8b9SKrzysztof Kosiński   // Use DexSentinelIndexAsOffset to skip the item as it isn't of the
746*a03ca8b9SKrzysztof Kosiński   // corresponding method handle type.
747*a03ca8b9SKrzysztof Kosiński   if (method_handle_type < min_type || method_handle_type > max_type) {
748*a03ca8b9SKrzysztof Kosiński     return kDexSentinelIndexAsOffset;
749*a03ca8b9SKrzysztof Kosiński   }
750*a03ca8b9SKrzysztof Kosiński 
751*a03ca8b9SKrzysztof Kosiński   return ReadTargetIndex<decltype(dex::MethodHandleItem::field_or_method_id)>(
752*a03ca8b9SKrzysztof Kosiński       image, target_map_item, target_item_size,
753*a03ca8b9SKrzysztof Kosiński       location + offsetof(dex::MethodHandleItem, field_or_method_id));
754*a03ca8b9SKrzysztof Kosiński }
755*a03ca8b9SKrzysztof Kosiński 
756*a03ca8b9SKrzysztof Kosiński // Reads uint32_t value in |image| at (valid) |location| and checks whether it
757*a03ca8b9SKrzysztof Kosiński // is a safe offset of a fixed-size item. Returns the target offset (possibly a
758*a03ca8b9SKrzysztof Kosiński // sentinel) if valid, or kInvalidOffset otherwise. This is compatible with
759*a03ca8b9SKrzysztof Kosiński // CachedReferenceListReferenceReader::Mapper,
760*a03ca8b9SKrzysztof Kosiński // InstructionReferenceReader::Mapper, and ItemReferenceReader::Mapper.
ReadTargetOffset32(ConstBufferView image,offset_t location)761*a03ca8b9SKrzysztof Kosiński static offset_t ReadTargetOffset32(ConstBufferView image, offset_t location) {
762*a03ca8b9SKrzysztof Kosiński   const offset_t unsafe_target =
763*a03ca8b9SKrzysztof Kosiński       static_cast<offset_t>(image.read<uint32_t>(location));
764*a03ca8b9SKrzysztof Kosiński   // Skip and don't validate kDexSentinelOffset as it is indicative of an
765*a03ca8b9SKrzysztof Kosiński   // empty reference.
766*a03ca8b9SKrzysztof Kosiński   if (unsafe_target == kDexSentinelOffset)
767*a03ca8b9SKrzysztof Kosiński     return unsafe_target;
768*a03ca8b9SKrzysztof Kosiński 
769*a03ca8b9SKrzysztof Kosiński   // TODO(huangs): Check that |unsafe_target| is within the correct data
770*a03ca8b9SKrzysztof Kosiński   // section.
771*a03ca8b9SKrzysztof Kosiński   if (unsafe_target >= image.size())
772*a03ca8b9SKrzysztof Kosiński     return kInvalidOffset;
773*a03ca8b9SKrzysztof Kosiński   return unsafe_target;
774*a03ca8b9SKrzysztof Kosiński }
775*a03ca8b9SKrzysztof Kosiński 
776*a03ca8b9SKrzysztof Kosiński /******** ReferenceWriterAdaptor ********/
777*a03ca8b9SKrzysztof Kosiński 
778*a03ca8b9SKrzysztof Kosiński // A ReferenceWriter that adapts a callback that performs type-specific
779*a03ca8b9SKrzysztof Kosiński // Reference writes.
780*a03ca8b9SKrzysztof Kosiński class ReferenceWriterAdaptor : public ReferenceWriter {
781*a03ca8b9SKrzysztof Kosiński  public:
782*a03ca8b9SKrzysztof Kosiński   using Writer = base::RepeatingCallback<void(Reference, MutableBufferView)>;
783*a03ca8b9SKrzysztof Kosiński 
ReferenceWriterAdaptor(MutableBufferView image,Writer && writer)784*a03ca8b9SKrzysztof Kosiński   ReferenceWriterAdaptor(MutableBufferView image, Writer&& writer)
785*a03ca8b9SKrzysztof Kosiński       : image_(image), writer_(std::move(writer)) {}
786*a03ca8b9SKrzysztof Kosiński 
787*a03ca8b9SKrzysztof Kosiński   // ReferenceWriter:
PutNext(Reference ref)788*a03ca8b9SKrzysztof Kosiński   void PutNext(Reference ref) override { writer_.Run(ref, image_); }
789*a03ca8b9SKrzysztof Kosiński 
790*a03ca8b9SKrzysztof Kosiński  private:
791*a03ca8b9SKrzysztof Kosiński   MutableBufferView image_;
792*a03ca8b9SKrzysztof Kosiński   Writer writer_;
793*a03ca8b9SKrzysztof Kosiński };
794*a03ca8b9SKrzysztof Kosiński 
795*a03ca8b9SKrzysztof Kosiński // Helper that's compatible with ReferenceWriterAdaptor::Writer.
796*a03ca8b9SKrzysztof Kosiński // Given that |ref.target| points to the start of a fixed size DEX item (e.g.,
797*a03ca8b9SKrzysztof Kosiński // FieldIdItem), translates |ref.target| to item index, and writes the result to
798*a03ca8b9SKrzysztof Kosiński // |ref.location| as |INT|.
799*a03ca8b9SKrzysztof Kosiński template <typename INT>
WriteTargetIndex(const dex::MapItem & target_map_item,size_t target_item_size,Reference ref,MutableBufferView image)800*a03ca8b9SKrzysztof Kosiński static void WriteTargetIndex(const dex::MapItem& target_map_item,
801*a03ca8b9SKrzysztof Kosiński                              size_t target_item_size,
802*a03ca8b9SKrzysztof Kosiński                              Reference ref,
803*a03ca8b9SKrzysztof Kosiński                              MutableBufferView image) {
804*a03ca8b9SKrzysztof Kosiński   const size_t unsafe_idx =
805*a03ca8b9SKrzysztof Kosiński       (ref.target - target_map_item.offset) / target_item_size;
806*a03ca8b9SKrzysztof Kosiński   // Verify that index is within bound.
807*a03ca8b9SKrzysztof Kosiński   if (unsafe_idx >= target_map_item.size) {
808*a03ca8b9SKrzysztof Kosiński     LOG(ERROR) << "Target index out of bounds at: " << AsHex<8>(ref.location)
809*a03ca8b9SKrzysztof Kosiński                << ".";
810*a03ca8b9SKrzysztof Kosiński     return;
811*a03ca8b9SKrzysztof Kosiński   }
812*a03ca8b9SKrzysztof Kosiński   // Verify that |ref.target| points to start of item.
813*a03ca8b9SKrzysztof Kosiński   DCHECK_EQ(ref.target, target_map_item.offset + unsafe_idx * target_item_size);
814*a03ca8b9SKrzysztof Kosiński   image.write<INT>(ref.location, base::checked_cast<INT>(unsafe_idx));
815*a03ca8b9SKrzysztof Kosiński }
816*a03ca8b9SKrzysztof Kosiński 
817*a03ca8b9SKrzysztof Kosiński // Buffer for ReadDexHeader() to optionally return results.
818*a03ca8b9SKrzysztof Kosiński struct ReadDexHeaderResults {
819*a03ca8b9SKrzysztof Kosiński   BufferSource source;
820*a03ca8b9SKrzysztof Kosiński   const dex::HeaderItem* header;
821*a03ca8b9SKrzysztof Kosiński   int dex_version;
822*a03ca8b9SKrzysztof Kosiński };
823*a03ca8b9SKrzysztof Kosiński 
824*a03ca8b9SKrzysztof Kosiński // Returns whether |image| points to a DEX file. If this is a possibility and
825*a03ca8b9SKrzysztof Kosiński // |opt_results| is not null, then uses it to pass extracted data to enable
826*a03ca8b9SKrzysztof Kosiński // further parsing.
ReadDexHeader(ConstBufferView image,ReadDexHeaderResults * opt_results)827*a03ca8b9SKrzysztof Kosiński bool ReadDexHeader(ConstBufferView image, ReadDexHeaderResults* opt_results) {
828*a03ca8b9SKrzysztof Kosiński   // This part needs to be fairly efficient since it may be called many times.
829*a03ca8b9SKrzysztof Kosiński   BufferSource source(image);
830*a03ca8b9SKrzysztof Kosiński   const dex::HeaderItem* header = source.GetPointer<dex::HeaderItem>();
831*a03ca8b9SKrzysztof Kosiński   if (!header)
832*a03ca8b9SKrzysztof Kosiński     return false;
833*a03ca8b9SKrzysztof Kosiński   if (header->magic[0] != 'd' || header->magic[1] != 'e' ||
834*a03ca8b9SKrzysztof Kosiński       header->magic[2] != 'x' || header->magic[3] != '\n' ||
835*a03ca8b9SKrzysztof Kosiński       header->magic[7] != '\0') {
836*a03ca8b9SKrzysztof Kosiński     return false;
837*a03ca8b9SKrzysztof Kosiński   }
838*a03ca8b9SKrzysztof Kosiński 
839*a03ca8b9SKrzysztof Kosiński   // Magic matches: More detailed tests can be conducted.
840*a03ca8b9SKrzysztof Kosiński   int dex_version = 0;
841*a03ca8b9SKrzysztof Kosiński   for (int i = 4; i < 7; ++i) {
842*a03ca8b9SKrzysztof Kosiński     if (!isdigit(header->magic[i]))
843*a03ca8b9SKrzysztof Kosiński       return false;
844*a03ca8b9SKrzysztof Kosiński     dex_version = dex_version * 10 + (header->magic[i] - '0');
845*a03ca8b9SKrzysztof Kosiński   }
846*a03ca8b9SKrzysztof Kosiński 
847*a03ca8b9SKrzysztof Kosiński   // Only support DEX versions 35, 37, 38, and 39
848*a03ca8b9SKrzysztof Kosiński   if (dex_version != 35 && dex_version != 37 && dex_version != 38 &&
849*a03ca8b9SKrzysztof Kosiński       dex_version != 39) {
850*a03ca8b9SKrzysztof Kosiński     return false;
851*a03ca8b9SKrzysztof Kosiński   }
852*a03ca8b9SKrzysztof Kosiński 
853*a03ca8b9SKrzysztof Kosiński   if (header->file_size > image.size() ||
854*a03ca8b9SKrzysztof Kosiński       header->file_size < sizeof(dex::HeaderItem) ||
855*a03ca8b9SKrzysztof Kosiński       header->map_off < sizeof(dex::HeaderItem)) {
856*a03ca8b9SKrzysztof Kosiński     return false;
857*a03ca8b9SKrzysztof Kosiński   }
858*a03ca8b9SKrzysztof Kosiński 
859*a03ca8b9SKrzysztof Kosiński   if (opt_results)
860*a03ca8b9SKrzysztof Kosiński     *opt_results = {source, header, dex_version};
861*a03ca8b9SKrzysztof Kosiński   return true;
862*a03ca8b9SKrzysztof Kosiński }
863*a03ca8b9SKrzysztof Kosiński 
864*a03ca8b9SKrzysztof Kosiński }  // namespace
865*a03ca8b9SKrzysztof Kosiński 
866*a03ca8b9SKrzysztof Kosiński /******** DisassemblerDex ********/
867*a03ca8b9SKrzysztof Kosiński 
DisassemblerDex()868*a03ca8b9SKrzysztof Kosiński DisassemblerDex::DisassemblerDex() : Disassembler(4) {}
869*a03ca8b9SKrzysztof Kosiński 
870*a03ca8b9SKrzysztof Kosiński DisassemblerDex::~DisassemblerDex() = default;
871*a03ca8b9SKrzysztof Kosiński 
872*a03ca8b9SKrzysztof Kosiński // static.
QuickDetect(ConstBufferView image)873*a03ca8b9SKrzysztof Kosiński bool DisassemblerDex::QuickDetect(ConstBufferView image) {
874*a03ca8b9SKrzysztof Kosiński   return ReadDexHeader(image, nullptr);
875*a03ca8b9SKrzysztof Kosiński }
876*a03ca8b9SKrzysztof Kosiński 
GetExeType() const877*a03ca8b9SKrzysztof Kosiński ExecutableType DisassemblerDex::GetExeType() const {
878*a03ca8b9SKrzysztof Kosiński   return kExeTypeDex;
879*a03ca8b9SKrzysztof Kosiński }
880*a03ca8b9SKrzysztof Kosiński 
GetExeTypeString() const881*a03ca8b9SKrzysztof Kosiński std::string DisassemblerDex::GetExeTypeString() const {
882*a03ca8b9SKrzysztof Kosiński   return base::StringPrintf("DEX (version %d)", dex_version_);
883*a03ca8b9SKrzysztof Kosiński }
884*a03ca8b9SKrzysztof Kosiński 
MakeReferenceGroups() const885*a03ca8b9SKrzysztof Kosiński std::vector<ReferenceGroup> DisassemblerDex::MakeReferenceGroups() const {
886*a03ca8b9SKrzysztof Kosiński   // Must follow DisassemblerDex::ReferenceType order. Initialized on first use.
887*a03ca8b9SKrzysztof Kosiński   return {
888*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kTypeIdToDescriptorStringId), PoolTag(kStringId)},
889*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadTypeIdToDescriptorStringId32,
890*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteStringId32},
891*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kProtoIdToShortyStringId), PoolTag(kStringId)},
892*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadProtoIdToShortyStringId32,
893*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteStringId32},
894*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kFieldIdToNameStringId), PoolTag(kStringId)},
895*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadFieldToNameStringId32,
896*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteStringId32},
897*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kMethodIdToNameStringId), PoolTag(kStringId)},
898*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadMethodIdToNameStringId32,
899*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteStringId32},
900*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kClassDefToSourceFileStringId), PoolTag(kStringId)},
901*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadClassDefToSourceFileStringId32,
902*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteStringId32},
903*a03ca8b9SKrzysztof Kosiński       {{2, TypeTag(kCodeToStringId16), PoolTag(kStringId)},
904*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadCodeToStringId16,
905*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteStringId16},
906*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kCodeToStringId32), PoolTag(kStringId)},
907*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadCodeToStringId32,
908*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteStringId32},
909*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kProtoIdToReturnTypeId), PoolTag(kTypeId)},
910*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadProtoIdToReturnTypeId32,
911*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteTypeId32},
912*a03ca8b9SKrzysztof Kosiński       {{2, TypeTag(kFieldIdToClassTypeId), PoolTag(kTypeId)},
913*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadFieldToClassTypeId16,
914*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteTypeId16},
915*a03ca8b9SKrzysztof Kosiński       {{2, TypeTag(kFieldIdToTypeId), PoolTag(kTypeId)},
916*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadFieldToTypeId16,
917*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteTypeId16},
918*a03ca8b9SKrzysztof Kosiński       {{2, TypeTag(kMethodIdToClassTypeId), PoolTag(kTypeId)},
919*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadMethodIdToClassTypeId16,
920*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteTypeId16},
921*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kClassDefToClassTypeId), PoolTag(kTypeId)},
922*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadClassDefToClassTypeId32,
923*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteTypeId32},
924*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kClassDefToSuperClassTypeId), PoolTag(kTypeId)},
925*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadClassDefToSuperClassTypeId32,
926*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteTypeId32},
927*a03ca8b9SKrzysztof Kosiński       {{2, TypeTag(kTypeListToTypeId), PoolTag(kTypeId)},
928*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadTypeListToTypeId16,
929*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteTypeId16},
930*a03ca8b9SKrzysztof Kosiński       {{2, TypeTag(kCodeToTypeId), PoolTag(kTypeId)},
931*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadCodeToTypeId16,
932*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteTypeId16},
933*a03ca8b9SKrzysztof Kosiński       {{2, TypeTag(kCodeToProtoId), PoolTag(kProtoId)},
934*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadCodeToProtoId16,
935*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteProtoId16},
936*a03ca8b9SKrzysztof Kosiński       {{2, TypeTag(kMethodIdToProtoId), PoolTag(kProtoId)},
937*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadMethodIdToProtoId16,
938*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteProtoId16},
939*a03ca8b9SKrzysztof Kosiński       {{2, TypeTag(kCodeToFieldId), PoolTag(kFieldId)},
940*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadCodeToFieldId16,
941*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteFieldId16},
942*a03ca8b9SKrzysztof Kosiński       {{2, TypeTag(kMethodHandleToFieldId), PoolTag(kFieldId)},
943*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadMethodHandleToFieldId16,
944*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteFieldId16},
945*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kAnnotationsDirectoryToFieldId), PoolTag(kFieldId)},
946*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadAnnotationsDirectoryToFieldId32,
947*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteFieldId32},
948*a03ca8b9SKrzysztof Kosiński       {{2, TypeTag(kCodeToMethodId), PoolTag(kMethodId)},
949*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadCodeToMethodId16,
950*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteMethodId16},
951*a03ca8b9SKrzysztof Kosiński       {{2, TypeTag(kMethodHandleToMethodId), PoolTag(kMethodId)},
952*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadMethodHandleToMethodId16,
953*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteMethodId16},
954*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kAnnotationsDirectoryToMethodId), PoolTag(kMethodId)},
955*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadAnnotationsDirectoryToMethodId32,
956*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteMethodId32},
957*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kAnnotationsDirectoryToParameterMethodId),
958*a03ca8b9SKrzysztof Kosiński         PoolTag(kMethodId)},
959*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadAnnotationsDirectoryToParameterMethodId32,
960*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteMethodId32},
961*a03ca8b9SKrzysztof Kosiński       {{2, TypeTag(kCodeToCallSiteId), PoolTag(kCallSiteId)},
962*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadCodeToCallSiteId16,
963*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteCallSiteId16},
964*a03ca8b9SKrzysztof Kosiński       {{2, TypeTag(kCodeToMethodHandle), PoolTag(kMethodHandle)},
965*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadCodeToMethodHandle16,
966*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteMethodHandle16},
967*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kProtoIdToParametersTypeList), PoolTag(kTypeList)},
968*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadProtoIdToParametersTypeList,
969*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteAbs32},
970*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kClassDefToInterfacesTypeList), PoolTag(kTypeList)},
971*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadClassDefToInterfacesTypeList,
972*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteAbs32},
973*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kAnnotationsDirectoryToParameterAnnotationSetRef),
974*a03ca8b9SKrzysztof Kosiński         PoolTag(kAnnotationSetRefList)},
975*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::
976*a03ca8b9SKrzysztof Kosiński            MakeReadAnnotationsDirectoryToParameterAnnotationSetRef,
977*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteAbs32},
978*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kAnnotationSetRefListToAnnotationSet),
979*a03ca8b9SKrzysztof Kosiński         PoolTag(kAnnotionSet)},
980*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadAnnotationSetRefListToAnnotationSet,
981*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteAbs32},
982*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kAnnotationsDirectoryToClassAnnotationSet),
983*a03ca8b9SKrzysztof Kosiński         PoolTag(kAnnotionSet)},
984*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadAnnotationsDirectoryToClassAnnotationSet,
985*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteAbs32},
986*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kAnnotationsDirectoryToFieldAnnotationSet),
987*a03ca8b9SKrzysztof Kosiński         PoolTag(kAnnotionSet)},
988*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadAnnotationsDirectoryToFieldAnnotationSet,
989*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteAbs32},
990*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kAnnotationsDirectoryToMethodAnnotationSet),
991*a03ca8b9SKrzysztof Kosiński         PoolTag(kAnnotionSet)},
992*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadAnnotationsDirectoryToMethodAnnotationSet,
993*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteAbs32},
994*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kClassDefToClassData), PoolTag(kClassData)},
995*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadClassDefToClassData,
996*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteAbs32},
997*a03ca8b9SKrzysztof Kosiński       {{1, TypeTag(kCodeToRelCode8), PoolTag(kCode)},
998*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadCodeToRelCode8,
999*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteRelCode8},
1000*a03ca8b9SKrzysztof Kosiński       {{2, TypeTag(kCodeToRelCode16), PoolTag(kCode)},
1001*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadCodeToRelCode16,
1002*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteRelCode16},
1003*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kCodeToRelCode32), PoolTag(kCode)},
1004*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadCodeToRelCode32,
1005*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteRelCode32},
1006*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kStringIdToStringData), PoolTag(kStringData)},
1007*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadStringIdToStringData,
1008*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteAbs32},
1009*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kAnnotationSetToAnnotation), PoolTag(kAnnotation)},
1010*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadAnnotationSetToAnnotation,
1011*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteAbs32},
1012*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kClassDefToStaticValuesEncodedArray),
1013*a03ca8b9SKrzysztof Kosiński         PoolTag(kEncodedArray)},
1014*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadClassDefToStaticValuesEncodedArray,
1015*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteAbs32},
1016*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kClassDefToAnnotationDirectory),
1017*a03ca8b9SKrzysztof Kosiński         PoolTag(kAnnotationsDirectory)},
1018*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadClassDefToAnnotationDirectory,
1019*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteAbs32},
1020*a03ca8b9SKrzysztof Kosiński       {{4, TypeTag(kCallSiteIdToCallSite), PoolTag(kCallSite)},
1021*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeReadCallSiteIdToCallSite32,
1022*a03ca8b9SKrzysztof Kosiński        &DisassemblerDex::MakeWriteAbs32},
1023*a03ca8b9SKrzysztof Kosiński   };
1024*a03ca8b9SKrzysztof Kosiński }
1025*a03ca8b9SKrzysztof Kosiński 
MakeReadStringIdToStringData(offset_t lo,offset_t hi)1026*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerDex::MakeReadStringIdToStringData(
1027*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1028*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1029*a03ca8b9SKrzysztof Kosiński   // dex::StringIdItem::string_data_off mapper.
1030*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(ReadTargetOffset32, image_);
1031*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1032*a03ca8b9SKrzysztof Kosiński       lo, hi, string_map_item_, sizeof(dex::StringIdItem),
1033*a03ca8b9SKrzysztof Kosiński       offsetof(dex::StringIdItem, string_data_off), std::move(mapper));
1034*a03ca8b9SKrzysztof Kosiński }
1035*a03ca8b9SKrzysztof Kosiński 
1036*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadTypeIdToDescriptorStringId32(offset_t lo,offset_t hi)1037*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadTypeIdToDescriptorStringId32(offset_t lo,
1038*a03ca8b9SKrzysztof Kosiński                                                       offset_t hi) {
1039*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(
1040*a03ca8b9SKrzysztof Kosiński       ReadTargetIndex<decltype(dex::TypeIdItem::descriptor_idx)>, image_,
1041*a03ca8b9SKrzysztof Kosiński       string_map_item_, sizeof(dex::StringIdItem));
1042*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1043*a03ca8b9SKrzysztof Kosiński       lo, hi, type_map_item_, sizeof(dex::TypeIdItem),
1044*a03ca8b9SKrzysztof Kosiński       offsetof(dex::TypeIdItem, descriptor_idx), std::move(mapper));
1045*a03ca8b9SKrzysztof Kosiński }
1046*a03ca8b9SKrzysztof Kosiński 
1047*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadProtoIdToShortyStringId32(offset_t lo,offset_t hi)1048*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadProtoIdToShortyStringId32(offset_t lo, offset_t hi) {
1049*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(
1050*a03ca8b9SKrzysztof Kosiński       ReadTargetIndex<decltype(dex::ProtoIdItem::shorty_idx)>, image_,
1051*a03ca8b9SKrzysztof Kosiński       string_map_item_, sizeof(dex::StringIdItem));
1052*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1053*a03ca8b9SKrzysztof Kosiński       lo, hi, proto_map_item_, sizeof(dex::ProtoIdItem),
1054*a03ca8b9SKrzysztof Kosiński       offsetof(dex::ProtoIdItem, shorty_idx), std::move(mapper));
1055*a03ca8b9SKrzysztof Kosiński }
1056*a03ca8b9SKrzysztof Kosiński 
1057*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadProtoIdToReturnTypeId32(offset_t lo,offset_t hi)1058*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadProtoIdToReturnTypeId32(offset_t lo, offset_t hi) {
1059*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(
1060*a03ca8b9SKrzysztof Kosiński       ReadTargetIndex<decltype(dex::ProtoIdItem::return_type_idx)>, image_,
1061*a03ca8b9SKrzysztof Kosiński       type_map_item_, sizeof(dex::TypeIdItem));
1062*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1063*a03ca8b9SKrzysztof Kosiński       lo, hi, proto_map_item_, sizeof(dex::ProtoIdItem),
1064*a03ca8b9SKrzysztof Kosiński       offsetof(dex::ProtoIdItem, return_type_idx), std::move(mapper));
1065*a03ca8b9SKrzysztof Kosiński }
1066*a03ca8b9SKrzysztof Kosiński 
1067*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadProtoIdToParametersTypeList(offset_t lo,offset_t hi)1068*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadProtoIdToParametersTypeList(offset_t lo, offset_t hi) {
1069*a03ca8b9SKrzysztof Kosiński   // dex::ProtoIdItem::parameters_off mapper.
1070*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(ReadTargetOffset32, image_);
1071*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1072*a03ca8b9SKrzysztof Kosiński       lo, hi, proto_map_item_, sizeof(dex::ProtoIdItem),
1073*a03ca8b9SKrzysztof Kosiński       offsetof(dex::ProtoIdItem, parameters_off), std::move(mapper));
1074*a03ca8b9SKrzysztof Kosiński }
1075*a03ca8b9SKrzysztof Kosiński 
MakeReadFieldToClassTypeId16(offset_t lo,offset_t hi)1076*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerDex::MakeReadFieldToClassTypeId16(
1077*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1078*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1079*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(
1080*a03ca8b9SKrzysztof Kosiński       ReadTargetIndex<decltype(dex::FieldIdItem::class_idx)>, image_,
1081*a03ca8b9SKrzysztof Kosiński       type_map_item_, sizeof(dex::TypeIdItem));
1082*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1083*a03ca8b9SKrzysztof Kosiński       lo, hi, field_map_item_, sizeof(dex::FieldIdItem),
1084*a03ca8b9SKrzysztof Kosiński       offsetof(dex::FieldIdItem, class_idx), std::move(mapper));
1085*a03ca8b9SKrzysztof Kosiński }
1086*a03ca8b9SKrzysztof Kosiński 
MakeReadFieldToTypeId16(offset_t lo,offset_t hi)1087*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerDex::MakeReadFieldToTypeId16(
1088*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1089*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1090*a03ca8b9SKrzysztof Kosiński   auto mapper =
1091*a03ca8b9SKrzysztof Kosiński       base::BindRepeating(ReadTargetIndex<decltype(dex::FieldIdItem::type_idx)>,
1092*a03ca8b9SKrzysztof Kosiński                           image_, type_map_item_, sizeof(dex::TypeIdItem));
1093*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1094*a03ca8b9SKrzysztof Kosiński       lo, hi, field_map_item_, sizeof(dex::FieldIdItem),
1095*a03ca8b9SKrzysztof Kosiński       offsetof(dex::FieldIdItem, type_idx), std::move(mapper));
1096*a03ca8b9SKrzysztof Kosiński }
1097*a03ca8b9SKrzysztof Kosiński 
MakeReadFieldToNameStringId32(offset_t lo,offset_t hi)1098*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerDex::MakeReadFieldToNameStringId32(
1099*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1100*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1101*a03ca8b9SKrzysztof Kosiński   auto mapper =
1102*a03ca8b9SKrzysztof Kosiński       base::BindRepeating(ReadTargetIndex<decltype(dex::FieldIdItem::name_idx)>,
1103*a03ca8b9SKrzysztof Kosiński                           image_, string_map_item_, sizeof(dex::StringIdItem));
1104*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1105*a03ca8b9SKrzysztof Kosiński       lo, hi, field_map_item_, sizeof(dex::FieldIdItem),
1106*a03ca8b9SKrzysztof Kosiński       offsetof(dex::FieldIdItem, name_idx), std::move(mapper));
1107*a03ca8b9SKrzysztof Kosiński }
1108*a03ca8b9SKrzysztof Kosiński 
1109*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadMethodIdToClassTypeId16(offset_t lo,offset_t hi)1110*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadMethodIdToClassTypeId16(offset_t lo, offset_t hi) {
1111*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(
1112*a03ca8b9SKrzysztof Kosiński       ReadTargetIndex<decltype(dex::MethodIdItem::class_idx)>, image_,
1113*a03ca8b9SKrzysztof Kosiński       type_map_item_, sizeof(dex::TypeIdItem));
1114*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1115*a03ca8b9SKrzysztof Kosiński       lo, hi, method_map_item_, sizeof(dex::MethodIdItem),
1116*a03ca8b9SKrzysztof Kosiński       offsetof(dex::MethodIdItem, class_idx), std::move(mapper));
1117*a03ca8b9SKrzysztof Kosiński }
1118*a03ca8b9SKrzysztof Kosiński 
MakeReadMethodIdToProtoId16(offset_t lo,offset_t hi)1119*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerDex::MakeReadMethodIdToProtoId16(
1120*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1121*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1122*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(
1123*a03ca8b9SKrzysztof Kosiński       ReadTargetIndex<decltype(dex::MethodIdItem::proto_idx)>, image_,
1124*a03ca8b9SKrzysztof Kosiński       proto_map_item_, sizeof(dex::ProtoIdItem));
1125*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1126*a03ca8b9SKrzysztof Kosiński       lo, hi, method_map_item_, sizeof(dex::MethodIdItem),
1127*a03ca8b9SKrzysztof Kosiński       offsetof(dex::MethodIdItem, proto_idx), std::move(mapper));
1128*a03ca8b9SKrzysztof Kosiński }
1129*a03ca8b9SKrzysztof Kosiński 
1130*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadMethodIdToNameStringId32(offset_t lo,offset_t hi)1131*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadMethodIdToNameStringId32(offset_t lo, offset_t hi) {
1132*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(
1133*a03ca8b9SKrzysztof Kosiński       ReadTargetIndex<decltype(dex::MethodIdItem::name_idx)>, image_,
1134*a03ca8b9SKrzysztof Kosiński       string_map_item_, sizeof(dex::StringIdItem));
1135*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1136*a03ca8b9SKrzysztof Kosiński       lo, hi, method_map_item_, sizeof(dex::MethodIdItem),
1137*a03ca8b9SKrzysztof Kosiński       offsetof(dex::MethodIdItem, name_idx), std::move(mapper));
1138*a03ca8b9SKrzysztof Kosiński }
1139*a03ca8b9SKrzysztof Kosiński 
1140*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadClassDefToClassTypeId32(offset_t lo,offset_t hi)1141*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadClassDefToClassTypeId32(offset_t lo, offset_t hi) {
1142*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(
1143*a03ca8b9SKrzysztof Kosiński       ReadTargetIndex<decltype(dex::ClassDefItem::superclass_idx)>, image_,
1144*a03ca8b9SKrzysztof Kosiński       type_map_item_, sizeof(dex::TypeIdItem));
1145*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1146*a03ca8b9SKrzysztof Kosiński       lo, hi, class_def_map_item_, sizeof(dex::ClassDefItem),
1147*a03ca8b9SKrzysztof Kosiński       offsetof(dex::ClassDefItem, class_idx), std::move(mapper));
1148*a03ca8b9SKrzysztof Kosiński }
1149*a03ca8b9SKrzysztof Kosiński 
1150*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadClassDefToSuperClassTypeId32(offset_t lo,offset_t hi)1151*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadClassDefToSuperClassTypeId32(offset_t lo,
1152*a03ca8b9SKrzysztof Kosiński                                                       offset_t hi) {
1153*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(
1154*a03ca8b9SKrzysztof Kosiński       ReadTargetIndex<decltype(dex::ClassDefItem::superclass_idx)>, image_,
1155*a03ca8b9SKrzysztof Kosiński       type_map_item_, sizeof(dex::TypeIdItem));
1156*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1157*a03ca8b9SKrzysztof Kosiński       lo, hi, class_def_map_item_, sizeof(dex::ClassDefItem),
1158*a03ca8b9SKrzysztof Kosiński       offsetof(dex::ClassDefItem, superclass_idx), std::move(mapper));
1159*a03ca8b9SKrzysztof Kosiński }
1160*a03ca8b9SKrzysztof Kosiński 
1161*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadClassDefToInterfacesTypeList(offset_t lo,offset_t hi)1162*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadClassDefToInterfacesTypeList(offset_t lo,
1163*a03ca8b9SKrzysztof Kosiński                                                       offset_t hi) {
1164*a03ca8b9SKrzysztof Kosiński   // dex::ClassDefItem::interfaces_off mapper.
1165*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(ReadTargetOffset32, image_);
1166*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1167*a03ca8b9SKrzysztof Kosiński       lo, hi, class_def_map_item_, sizeof(dex::ClassDefItem),
1168*a03ca8b9SKrzysztof Kosiński       offsetof(dex::ClassDefItem, interfaces_off), std::move(mapper));
1169*a03ca8b9SKrzysztof Kosiński }
1170*a03ca8b9SKrzysztof Kosiński 
1171*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadClassDefToSourceFileStringId32(offset_t lo,offset_t hi)1172*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadClassDefToSourceFileStringId32(offset_t lo,
1173*a03ca8b9SKrzysztof Kosiński                                                         offset_t hi) {
1174*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(
1175*a03ca8b9SKrzysztof Kosiński       ReadTargetIndex<decltype(dex::ClassDefItem::source_file_idx)>, image_,
1176*a03ca8b9SKrzysztof Kosiński       string_map_item_, sizeof(dex::StringIdItem));
1177*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1178*a03ca8b9SKrzysztof Kosiński       lo, hi, class_def_map_item_, sizeof(dex::ClassDefItem),
1179*a03ca8b9SKrzysztof Kosiński       offsetof(dex::ClassDefItem, source_file_idx), std::move(mapper));
1180*a03ca8b9SKrzysztof Kosiński }
1181*a03ca8b9SKrzysztof Kosiński 
1182*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadClassDefToAnnotationDirectory(offset_t lo,offset_t hi)1183*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadClassDefToAnnotationDirectory(offset_t lo,
1184*a03ca8b9SKrzysztof Kosiński                                                        offset_t hi) {
1185*a03ca8b9SKrzysztof Kosiński   // dex::ClassDefItem::annotations_off mapper.
1186*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(ReadTargetOffset32, image_);
1187*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1188*a03ca8b9SKrzysztof Kosiński       lo, hi, class_def_map_item_, sizeof(dex::ClassDefItem),
1189*a03ca8b9SKrzysztof Kosiński       offsetof(dex::ClassDefItem, annotations_off), std::move(mapper));
1190*a03ca8b9SKrzysztof Kosiński }
1191*a03ca8b9SKrzysztof Kosiński 
MakeReadClassDefToClassData(offset_t lo,offset_t hi)1192*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerDex::MakeReadClassDefToClassData(
1193*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1194*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1195*a03ca8b9SKrzysztof Kosiński   // dex::ClassDefItem::class_data_off mapper.
1196*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(ReadTargetOffset32, image_);
1197*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1198*a03ca8b9SKrzysztof Kosiński       lo, hi, class_def_map_item_, sizeof(dex::ClassDefItem),
1199*a03ca8b9SKrzysztof Kosiński       offsetof(dex::ClassDefItem, class_data_off), std::move(mapper));
1200*a03ca8b9SKrzysztof Kosiński }
1201*a03ca8b9SKrzysztof Kosiński 
1202*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadClassDefToStaticValuesEncodedArray(offset_t lo,offset_t hi)1203*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadClassDefToStaticValuesEncodedArray(offset_t lo,
1204*a03ca8b9SKrzysztof Kosiński                                                             offset_t hi) {
1205*a03ca8b9SKrzysztof Kosiński   // dex::ClassDefItem::static_values_off mapper.
1206*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(ReadTargetOffset32, image_);
1207*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1208*a03ca8b9SKrzysztof Kosiński       lo, hi, class_def_map_item_, sizeof(dex::ClassDefItem),
1209*a03ca8b9SKrzysztof Kosiński       offsetof(dex::ClassDefItem, static_values_off), std::move(mapper));
1210*a03ca8b9SKrzysztof Kosiński }
1211*a03ca8b9SKrzysztof Kosiński 
1212*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadCallSiteIdToCallSite32(offset_t lo,offset_t hi)1213*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadCallSiteIdToCallSite32(offset_t lo, offset_t hi) {
1214*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(ReadTargetOffset32, image_);
1215*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1216*a03ca8b9SKrzysztof Kosiński       lo, hi, call_site_map_item_, sizeof(dex::CallSiteIdItem),
1217*a03ca8b9SKrzysztof Kosiński       offsetof(dex::CallSiteIdItem, call_site_off), std::move(mapper));
1218*a03ca8b9SKrzysztof Kosiński }
1219*a03ca8b9SKrzysztof Kosiński 
1220*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadMethodHandleToFieldId16(offset_t lo,offset_t hi)1221*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadMethodHandleToFieldId16(offset_t lo, offset_t hi) {
1222*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(ReadMethodHandleFieldOrMethodId, image_,
1223*a03ca8b9SKrzysztof Kosiński                                     field_map_item_, sizeof(dex::FieldIdItem),
1224*a03ca8b9SKrzysztof Kosiński                                     dex::MethodHandleType::kStaticPut,
1225*a03ca8b9SKrzysztof Kosiński                                     dex::MethodHandleType::kInstanceGet);
1226*a03ca8b9SKrzysztof Kosiński   // Use |mapper_wants_item == true| for ItemReferenceReader such that
1227*a03ca8b9SKrzysztof Kosiński   // |location| is aligned with MethodHandleItem when passed to |mapper|. This
1228*a03ca8b9SKrzysztof Kosiński   // allows ReadMethodHandleFieldOrMethodId to safely determine whether the
1229*a03ca8b9SKrzysztof Kosiński   // reference in the MethodHandleItem is of the correct type to be emitted.
1230*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1231*a03ca8b9SKrzysztof Kosiński       lo, hi, method_handle_map_item_, sizeof(dex::MethodHandleItem),
1232*a03ca8b9SKrzysztof Kosiński       offsetof(dex::MethodHandleItem, field_or_method_id), std::move(mapper),
1233*a03ca8b9SKrzysztof Kosiński       /*mapper_wants_item=*/true);
1234*a03ca8b9SKrzysztof Kosiński }
1235*a03ca8b9SKrzysztof Kosiński 
1236*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadMethodHandleToMethodId16(offset_t lo,offset_t hi)1237*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadMethodHandleToMethodId16(offset_t lo, offset_t hi) {
1238*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(ReadMethodHandleFieldOrMethodId, image_,
1239*a03ca8b9SKrzysztof Kosiński                                     method_map_item_, sizeof(dex::MethodIdItem),
1240*a03ca8b9SKrzysztof Kosiński                                     dex::MethodHandleType::kInvokeStatic,
1241*a03ca8b9SKrzysztof Kosiński                                     dex::MethodHandleType::kInvokeInterface);
1242*a03ca8b9SKrzysztof Kosiński   // Use |mapper_wants_item == true| for ItemReferenceReader such that
1243*a03ca8b9SKrzysztof Kosiński   // |location| is aligned with MethodHandleItem when passed to |mapper|. This
1244*a03ca8b9SKrzysztof Kosiński   // allows ReadMethodHandleFieldOrMethodId to safely determine whether the
1245*a03ca8b9SKrzysztof Kosiński   // reference in the MethodHandleItem is of the correct type to be emitted.
1246*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ItemReferenceReader>(
1247*a03ca8b9SKrzysztof Kosiński       lo, hi, method_handle_map_item_, sizeof(dex::MethodHandleItem),
1248*a03ca8b9SKrzysztof Kosiński       offsetof(dex::MethodHandleItem, field_or_method_id), std::move(mapper),
1249*a03ca8b9SKrzysztof Kosiński       /*mapper_wants_item=*/true);
1250*a03ca8b9SKrzysztof Kosiński }
1251*a03ca8b9SKrzysztof Kosiński 
MakeReadTypeListToTypeId16(offset_t lo,offset_t hi)1252*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerDex::MakeReadTypeListToTypeId16(
1253*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1254*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1255*a03ca8b9SKrzysztof Kosiński   auto mapper =
1256*a03ca8b9SKrzysztof Kosiński       base::BindRepeating(ReadTargetIndex<decltype(dex::TypeItem::type_idx)>,
1257*a03ca8b9SKrzysztof Kosiński                           image_, type_map_item_, sizeof(dex::TypeIdItem));
1258*a03ca8b9SKrzysztof Kosiński   return std::make_unique<CachedItemListReferenceReader>(
1259*a03ca8b9SKrzysztof Kosiński       lo, hi, offsetof(dex::TypeItem, type_idx), type_list_offsets_,
1260*a03ca8b9SKrzysztof Kosiński       std::move(mapper));
1261*a03ca8b9SKrzysztof Kosiński }
1262*a03ca8b9SKrzysztof Kosiński 
1263*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadAnnotationSetToAnnotation(offset_t lo,offset_t hi)1264*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadAnnotationSetToAnnotation(offset_t lo, offset_t hi) {
1265*a03ca8b9SKrzysztof Kosiński   // dex::AnnotationOffItem::annotation_off mapper.
1266*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(ReadTargetOffset32, image_);
1267*a03ca8b9SKrzysztof Kosiński   return std::make_unique<CachedItemListReferenceReader>(
1268*a03ca8b9SKrzysztof Kosiński       lo, hi, offsetof(dex::AnnotationOffItem, annotation_off),
1269*a03ca8b9SKrzysztof Kosiński       annotation_set_offsets_, std::move(mapper));
1270*a03ca8b9SKrzysztof Kosiński }
1271*a03ca8b9SKrzysztof Kosiński 
1272*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadAnnotationSetRefListToAnnotationSet(offset_t lo,offset_t hi)1273*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadAnnotationSetRefListToAnnotationSet(offset_t lo,
1274*a03ca8b9SKrzysztof Kosiński                                                              offset_t hi) {
1275*a03ca8b9SKrzysztof Kosiński   // dex::AnnotationSetRefItem::annotations_off mapper.
1276*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(ReadTargetOffset32, image_);
1277*a03ca8b9SKrzysztof Kosiński   return std::make_unique<CachedItemListReferenceReader>(
1278*a03ca8b9SKrzysztof Kosiński       lo, hi, offsetof(dex::AnnotationSetRefItem, annotations_off),
1279*a03ca8b9SKrzysztof Kosiński       annotation_set_ref_list_offsets_, std::move(mapper));
1280*a03ca8b9SKrzysztof Kosiński }
1281*a03ca8b9SKrzysztof Kosiński 
1282*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadAnnotationsDirectoryToClassAnnotationSet(offset_t lo,offset_t hi)1283*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadAnnotationsDirectoryToClassAnnotationSet(offset_t lo,
1284*a03ca8b9SKrzysztof Kosiński                                                                   offset_t hi) {
1285*a03ca8b9SKrzysztof Kosiński   // dex::AnnotationsDirectoryItem::class_annotations_off mapper.
1286*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(ReadTargetOffset32, image_);
1287*a03ca8b9SKrzysztof Kosiński   return std::make_unique<CachedItemListReferenceReader>(
1288*a03ca8b9SKrzysztof Kosiński       lo, hi, offsetof(dex::AnnotationsDirectoryItem, class_annotations_off),
1289*a03ca8b9SKrzysztof Kosiński       annotations_directory_item_offsets_, std::move(mapper));
1290*a03ca8b9SKrzysztof Kosiński }
1291*a03ca8b9SKrzysztof Kosiński 
1292*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadAnnotationsDirectoryToFieldId32(offset_t lo,offset_t hi)1293*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadAnnotationsDirectoryToFieldId32(offset_t lo,
1294*a03ca8b9SKrzysztof Kosiński                                                          offset_t hi) {
1295*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(
1296*a03ca8b9SKrzysztof Kosiński       ReadTargetIndex<decltype(dex::FieldAnnotation::field_idx)>, image_,
1297*a03ca8b9SKrzysztof Kosiński       field_map_item_, sizeof(dex::FieldIdItem));
1298*a03ca8b9SKrzysztof Kosiński   return std::make_unique<CachedItemListReferenceReader>(
1299*a03ca8b9SKrzysztof Kosiński       lo, hi, offsetof(dex::FieldAnnotation, field_idx),
1300*a03ca8b9SKrzysztof Kosiński       annotations_directory_item_field_annotation_offsets_, std::move(mapper));
1301*a03ca8b9SKrzysztof Kosiński }
1302*a03ca8b9SKrzysztof Kosiński 
1303*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadAnnotationsDirectoryToFieldAnnotationSet(offset_t lo,offset_t hi)1304*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadAnnotationsDirectoryToFieldAnnotationSet(offset_t lo,
1305*a03ca8b9SKrzysztof Kosiński                                                                   offset_t hi) {
1306*a03ca8b9SKrzysztof Kosiński   // dex::FieldAnnotation::annotations_off mapper.
1307*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(ReadTargetOffset32, image_);
1308*a03ca8b9SKrzysztof Kosiński   return std::make_unique<CachedItemListReferenceReader>(
1309*a03ca8b9SKrzysztof Kosiński       lo, hi, offsetof(dex::FieldAnnotation, annotations_off),
1310*a03ca8b9SKrzysztof Kosiński       annotations_directory_item_field_annotation_offsets_, std::move(mapper));
1311*a03ca8b9SKrzysztof Kosiński }
1312*a03ca8b9SKrzysztof Kosiński 
1313*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadAnnotationsDirectoryToMethodId32(offset_t lo,offset_t hi)1314*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadAnnotationsDirectoryToMethodId32(offset_t lo,
1315*a03ca8b9SKrzysztof Kosiński                                                           offset_t hi) {
1316*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(
1317*a03ca8b9SKrzysztof Kosiński       ReadTargetIndex<decltype(dex::MethodAnnotation::method_idx)>, image_,
1318*a03ca8b9SKrzysztof Kosiński       method_map_item_, sizeof(dex::MethodIdItem));
1319*a03ca8b9SKrzysztof Kosiński   return std::make_unique<CachedItemListReferenceReader>(
1320*a03ca8b9SKrzysztof Kosiński       lo, hi, offsetof(dex::MethodAnnotation, method_idx),
1321*a03ca8b9SKrzysztof Kosiński       annotations_directory_item_method_annotation_offsets_, std::move(mapper));
1322*a03ca8b9SKrzysztof Kosiński }
1323*a03ca8b9SKrzysztof Kosiński 
1324*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadAnnotationsDirectoryToMethodAnnotationSet(offset_t lo,offset_t hi)1325*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadAnnotationsDirectoryToMethodAnnotationSet(
1326*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1327*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1328*a03ca8b9SKrzysztof Kosiński   // dex::MethodAnnotation::annotations_off mapper.
1329*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(ReadTargetOffset32, image_);
1330*a03ca8b9SKrzysztof Kosiński   return std::make_unique<CachedItemListReferenceReader>(
1331*a03ca8b9SKrzysztof Kosiński       lo, hi, offsetof(dex::MethodAnnotation, annotations_off),
1332*a03ca8b9SKrzysztof Kosiński       annotations_directory_item_method_annotation_offsets_, std::move(mapper));
1333*a03ca8b9SKrzysztof Kosiński }
1334*a03ca8b9SKrzysztof Kosiński 
1335*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadAnnotationsDirectoryToParameterMethodId32(offset_t lo,offset_t hi)1336*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadAnnotationsDirectoryToParameterMethodId32(
1337*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1338*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1339*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(
1340*a03ca8b9SKrzysztof Kosiński       ReadTargetIndex<decltype(dex::ParameterAnnotation::method_idx)>, image_,
1341*a03ca8b9SKrzysztof Kosiński       method_map_item_, sizeof(dex::MethodIdItem));
1342*a03ca8b9SKrzysztof Kosiński   return std::make_unique<CachedItemListReferenceReader>(
1343*a03ca8b9SKrzysztof Kosiński       lo, hi, offsetof(dex::ParameterAnnotation, method_idx),
1344*a03ca8b9SKrzysztof Kosiński       annotations_directory_item_parameter_annotation_offsets_,
1345*a03ca8b9SKrzysztof Kosiński       std::move(mapper));
1346*a03ca8b9SKrzysztof Kosiński }
1347*a03ca8b9SKrzysztof Kosiński 
1348*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader>
MakeReadAnnotationsDirectoryToParameterAnnotationSetRef(offset_t lo,offset_t hi)1349*a03ca8b9SKrzysztof Kosiński DisassemblerDex::MakeReadAnnotationsDirectoryToParameterAnnotationSetRef(
1350*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1351*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1352*a03ca8b9SKrzysztof Kosiński   // dex::ParameterAnnotation::annotations_off mapper.
1353*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(ReadTargetOffset32, image_);
1354*a03ca8b9SKrzysztof Kosiński   return std::make_unique<CachedItemListReferenceReader>(
1355*a03ca8b9SKrzysztof Kosiński       lo, hi, offsetof(dex::ParameterAnnotation, annotations_off),
1356*a03ca8b9SKrzysztof Kosiński       annotations_directory_item_parameter_annotation_offsets_,
1357*a03ca8b9SKrzysztof Kosiński       std::move(mapper));
1358*a03ca8b9SKrzysztof Kosiński }
1359*a03ca8b9SKrzysztof Kosiński 
1360*a03ca8b9SKrzysztof Kosiński // MakeReadCode* readers use offset relative to the instruction beginning based
1361*a03ca8b9SKrzysztof Kosiński // on the instruction format ID.
1362*a03ca8b9SKrzysztof Kosiński // See https://source.android.com/devices/tech/dalvik/instruction-formats
1363*a03ca8b9SKrzysztof Kosiński 
MakeReadCodeToStringId16(offset_t lo,offset_t hi)1364*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerDex::MakeReadCodeToStringId16(
1365*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1366*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1367*a03ca8b9SKrzysztof Kosiński   auto filter = base::BindRepeating(
1368*a03ca8b9SKrzysztof Kosiński       [](const InstructionParser::Value& value) -> offset_t {
1369*a03ca8b9SKrzysztof Kosiński         if (value.instr->format == dex::FormatId::c &&
1370*a03ca8b9SKrzysztof Kosiński             (value.instr->opcode == 0x1A)) {  // const-string
1371*a03ca8b9SKrzysztof Kosiński           // BBBB from e.g., const-string vAA, string@BBBB.
1372*a03ca8b9SKrzysztof Kosiński           return value.instr_offset + 2;
1373*a03ca8b9SKrzysztof Kosiński         }
1374*a03ca8b9SKrzysztof Kosiński         return kInvalidOffset;
1375*a03ca8b9SKrzysztof Kosiński       });
1376*a03ca8b9SKrzysztof Kosiński   auto mapper =
1377*a03ca8b9SKrzysztof Kosiński       base::BindRepeating(ReadTargetIndex<uint16_t>, image_, string_map_item_,
1378*a03ca8b9SKrzysztof Kosiński                           sizeof(dex::StringIdItem));
1379*a03ca8b9SKrzysztof Kosiński   return std::make_unique<InstructionReferenceReader>(
1380*a03ca8b9SKrzysztof Kosiński       image_, lo, hi, code_item_offsets_, std::move(filter), std::move(mapper));
1381*a03ca8b9SKrzysztof Kosiński }
1382*a03ca8b9SKrzysztof Kosiński 
MakeReadCodeToStringId32(offset_t lo,offset_t hi)1383*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerDex::MakeReadCodeToStringId32(
1384*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1385*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1386*a03ca8b9SKrzysztof Kosiński   auto filter = base::BindRepeating(
1387*a03ca8b9SKrzysztof Kosiński       [](const InstructionParser::Value& value) -> offset_t {
1388*a03ca8b9SKrzysztof Kosiński         if (value.instr->format == dex::FormatId::c &&
1389*a03ca8b9SKrzysztof Kosiński             (value.instr->opcode == 0x1B)) {  // const-string/jumbo
1390*a03ca8b9SKrzysztof Kosiński           // BBBBBBBB from e.g., const-string/jumbo vAA, string@BBBBBBBB.
1391*a03ca8b9SKrzysztof Kosiński           return value.instr_offset + 2;
1392*a03ca8b9SKrzysztof Kosiński         }
1393*a03ca8b9SKrzysztof Kosiński         return kInvalidOffset;
1394*a03ca8b9SKrzysztof Kosiński       });
1395*a03ca8b9SKrzysztof Kosiński   auto mapper =
1396*a03ca8b9SKrzysztof Kosiński       base::BindRepeating(ReadTargetIndex<uint32_t>, image_, string_map_item_,
1397*a03ca8b9SKrzysztof Kosiński                           sizeof(dex::StringIdItem));
1398*a03ca8b9SKrzysztof Kosiński   return std::make_unique<InstructionReferenceReader>(
1399*a03ca8b9SKrzysztof Kosiński       image_, lo, hi, code_item_offsets_, std::move(filter), std::move(mapper));
1400*a03ca8b9SKrzysztof Kosiński }
1401*a03ca8b9SKrzysztof Kosiński 
MakeReadCodeToTypeId16(offset_t lo,offset_t hi)1402*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerDex::MakeReadCodeToTypeId16(
1403*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1404*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1405*a03ca8b9SKrzysztof Kosiński   auto filter = base::BindRepeating(
1406*a03ca8b9SKrzysztof Kosiński       [](const InstructionParser::Value& value) -> offset_t {
1407*a03ca8b9SKrzysztof Kosiński         if (value.instr->format == dex::FormatId::c &&
1408*a03ca8b9SKrzysztof Kosiński             (value.instr->opcode == 0x1C ||   // const-class
1409*a03ca8b9SKrzysztof Kosiński              value.instr->opcode == 0x1F ||   // check-cast
1410*a03ca8b9SKrzysztof Kosiński              value.instr->opcode == 0x20 ||   // instance-of
1411*a03ca8b9SKrzysztof Kosiński              value.instr->opcode == 0x22 ||   // new-instance
1412*a03ca8b9SKrzysztof Kosiński              value.instr->opcode == 0x23 ||   // new-array
1413*a03ca8b9SKrzysztof Kosiński              value.instr->opcode == 0x24 ||   // filled-new-array
1414*a03ca8b9SKrzysztof Kosiński              value.instr->opcode == 0x25)) {  // filled-new-array/range
1415*a03ca8b9SKrzysztof Kosiński           // BBBB from e.g., const-class vAA, type@BBBB.
1416*a03ca8b9SKrzysztof Kosiński           return value.instr_offset + 2;
1417*a03ca8b9SKrzysztof Kosiński         }
1418*a03ca8b9SKrzysztof Kosiński         return kInvalidOffset;
1419*a03ca8b9SKrzysztof Kosiński       });
1420*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(ReadTargetIndex<uint16_t>, image_,
1421*a03ca8b9SKrzysztof Kosiński                                     type_map_item_, sizeof(dex::TypeIdItem));
1422*a03ca8b9SKrzysztof Kosiński   return std::make_unique<InstructionReferenceReader>(
1423*a03ca8b9SKrzysztof Kosiński       image_, lo, hi, code_item_offsets_, std::move(filter), std::move(mapper));
1424*a03ca8b9SKrzysztof Kosiński }
1425*a03ca8b9SKrzysztof Kosiński 
MakeReadCodeToProtoId16(offset_t lo,offset_t hi)1426*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerDex::MakeReadCodeToProtoId16(
1427*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1428*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1429*a03ca8b9SKrzysztof Kosiński   auto filter = base::BindRepeating(
1430*a03ca8b9SKrzysztof Kosiński       [](const InstructionParser::Value& value) -> offset_t {
1431*a03ca8b9SKrzysztof Kosiński         if (value.instr->format == dex::FormatId::c) {
1432*a03ca8b9SKrzysztof Kosiński           if (value.instr->opcode == 0xFA ||  // invoke-polymorphic
1433*a03ca8b9SKrzysztof Kosiński               value.instr->opcode == 0xFB) {  // invoke-polymorphic/range
1434*a03ca8b9SKrzysztof Kosiński             // HHHH from e.g, invoke-polymorphic {vC, vD, vE, vF, vG},
1435*a03ca8b9SKrzysztof Kosiński             //   meth@BBBB, proto@HHHH
1436*a03ca8b9SKrzysztof Kosiński             return value.instr_offset + 6;
1437*a03ca8b9SKrzysztof Kosiński           }
1438*a03ca8b9SKrzysztof Kosiński           if (value.instr->opcode == 0xFF) {  // const-method-type
1439*a03ca8b9SKrzysztof Kosiński             // BBBB from e.g., const-method-type vAA, proto@BBBB
1440*a03ca8b9SKrzysztof Kosiński             return value.instr_offset + 2;
1441*a03ca8b9SKrzysztof Kosiński           }
1442*a03ca8b9SKrzysztof Kosiński         }
1443*a03ca8b9SKrzysztof Kosiński         return kInvalidOffset;
1444*a03ca8b9SKrzysztof Kosiński       });
1445*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(ReadTargetIndex<uint16_t>, image_,
1446*a03ca8b9SKrzysztof Kosiński                                     proto_map_item_, sizeof(dex::ProtoIdItem));
1447*a03ca8b9SKrzysztof Kosiński   return std::make_unique<InstructionReferenceReader>(
1448*a03ca8b9SKrzysztof Kosiński       image_, lo, hi, code_item_offsets_, std::move(filter), std::move(mapper));
1449*a03ca8b9SKrzysztof Kosiński }
1450*a03ca8b9SKrzysztof Kosiński 
MakeReadCodeToCallSiteId16(offset_t lo,offset_t hi)1451*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerDex::MakeReadCodeToCallSiteId16(
1452*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1453*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1454*a03ca8b9SKrzysztof Kosiński   auto filter = base::BindRepeating(
1455*a03ca8b9SKrzysztof Kosiński       [](const InstructionParser::Value& value) -> offset_t {
1456*a03ca8b9SKrzysztof Kosiński         if (value.instr->format == dex::FormatId::c &&
1457*a03ca8b9SKrzysztof Kosiński             (value.instr->opcode == 0xFC ||   // invoke-custom
1458*a03ca8b9SKrzysztof Kosiński              value.instr->opcode == 0xFD)) {  // invoke-custom/range
1459*a03ca8b9SKrzysztof Kosiński           // BBBB from e.g, invoke-custom {vC, vD, vE, vF, vG},
1460*a03ca8b9SKrzysztof Kosiński           //   call_site@BBBB
1461*a03ca8b9SKrzysztof Kosiński           return value.instr_offset + 2;
1462*a03ca8b9SKrzysztof Kosiński         }
1463*a03ca8b9SKrzysztof Kosiński         return kInvalidOffset;
1464*a03ca8b9SKrzysztof Kosiński       });
1465*a03ca8b9SKrzysztof Kosiński   auto mapper =
1466*a03ca8b9SKrzysztof Kosiński       base::BindRepeating(ReadTargetIndex<uint16_t>, image_,
1467*a03ca8b9SKrzysztof Kosiński                           call_site_map_item_, sizeof(dex::CallSiteIdItem));
1468*a03ca8b9SKrzysztof Kosiński   return std::make_unique<InstructionReferenceReader>(
1469*a03ca8b9SKrzysztof Kosiński       image_, lo, hi, code_item_offsets_, std::move(filter), std::move(mapper));
1470*a03ca8b9SKrzysztof Kosiński }
1471*a03ca8b9SKrzysztof Kosiński 
MakeReadCodeToMethodHandle16(offset_t lo,offset_t hi)1472*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerDex::MakeReadCodeToMethodHandle16(
1473*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1474*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1475*a03ca8b9SKrzysztof Kosiński   auto filter = base::BindRepeating(
1476*a03ca8b9SKrzysztof Kosiński       [](const InstructionParser::Value& value) -> offset_t {
1477*a03ca8b9SKrzysztof Kosiński         if (value.instr->format == dex::FormatId::c &&
1478*a03ca8b9SKrzysztof Kosiński             value.instr->opcode == 0xFE) {  // const-method-handle
1479*a03ca8b9SKrzysztof Kosiński           // BBBB from e.g, const-method-handle vAA, method_handle@BBBB
1480*a03ca8b9SKrzysztof Kosiński           return value.instr_offset + 2;
1481*a03ca8b9SKrzysztof Kosiński         }
1482*a03ca8b9SKrzysztof Kosiński         return kInvalidOffset;
1483*a03ca8b9SKrzysztof Kosiński       });
1484*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(ReadTargetIndex<uint16_t>, image_,
1485*a03ca8b9SKrzysztof Kosiński                                     method_handle_map_item_,
1486*a03ca8b9SKrzysztof Kosiński                                     sizeof(dex::MethodHandleItem));
1487*a03ca8b9SKrzysztof Kosiński   return std::make_unique<InstructionReferenceReader>(
1488*a03ca8b9SKrzysztof Kosiński       image_, lo, hi, code_item_offsets_, std::move(filter), std::move(mapper));
1489*a03ca8b9SKrzysztof Kosiński }
1490*a03ca8b9SKrzysztof Kosiński 
MakeReadCodeToFieldId16(offset_t lo,offset_t hi)1491*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerDex::MakeReadCodeToFieldId16(
1492*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1493*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1494*a03ca8b9SKrzysztof Kosiński   auto filter = base::BindRepeating(
1495*a03ca8b9SKrzysztof Kosiński       [](const InstructionParser::Value& value) -> offset_t {
1496*a03ca8b9SKrzysztof Kosiński         if (value.instr->format == dex::FormatId::c &&
1497*a03ca8b9SKrzysztof Kosiński             (value.instr->opcode == 0x52 ||   // iinstanceop (iget-*, iput-*)
1498*a03ca8b9SKrzysztof Kosiński              value.instr->opcode == 0x60)) {  // sstaticop (sget-*, sput-*)
1499*a03ca8b9SKrzysztof Kosiński           // CCCC from e.g., iget vA, vB, field@CCCC.
1500*a03ca8b9SKrzysztof Kosiński           return value.instr_offset + 2;
1501*a03ca8b9SKrzysztof Kosiński         }
1502*a03ca8b9SKrzysztof Kosiński         return kInvalidOffset;
1503*a03ca8b9SKrzysztof Kosiński       });
1504*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(ReadTargetIndex<uint16_t>, image_,
1505*a03ca8b9SKrzysztof Kosiński                                     field_map_item_, sizeof(dex::FieldIdItem));
1506*a03ca8b9SKrzysztof Kosiński   return std::make_unique<InstructionReferenceReader>(
1507*a03ca8b9SKrzysztof Kosiński       image_, lo, hi, code_item_offsets_, std::move(filter), std::move(mapper));
1508*a03ca8b9SKrzysztof Kosiński }
1509*a03ca8b9SKrzysztof Kosiński 
MakeReadCodeToMethodId16(offset_t lo,offset_t hi)1510*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerDex::MakeReadCodeToMethodId16(
1511*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1512*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1513*a03ca8b9SKrzysztof Kosiński   auto filter = base::BindRepeating(
1514*a03ca8b9SKrzysztof Kosiński       [](const InstructionParser::Value& value) -> offset_t {
1515*a03ca8b9SKrzysztof Kosiński         if (value.instr->format == dex::FormatId::c &&
1516*a03ca8b9SKrzysztof Kosiński             (value.instr->opcode == 0x6E ||   // invoke-kind
1517*a03ca8b9SKrzysztof Kosiński              value.instr->opcode == 0x74 ||   // invoke-kind/range
1518*a03ca8b9SKrzysztof Kosiński              value.instr->opcode == 0xFA ||   // invoke-polymorphic
1519*a03ca8b9SKrzysztof Kosiński              value.instr->opcode == 0xFB)) {  // invoke-polymorphic/range
1520*a03ca8b9SKrzysztof Kosiński           // BBBB from e.g., invoke-virtual {vC, vD, vE, vF, vG}, meth@BBBB.
1521*a03ca8b9SKrzysztof Kosiński           return value.instr_offset + 2;
1522*a03ca8b9SKrzysztof Kosiński         }
1523*a03ca8b9SKrzysztof Kosiński         return kInvalidOffset;
1524*a03ca8b9SKrzysztof Kosiński       });
1525*a03ca8b9SKrzysztof Kosiński   auto mapper =
1526*a03ca8b9SKrzysztof Kosiński       base::BindRepeating(ReadTargetIndex<uint16_t>, image_, method_map_item_,
1527*a03ca8b9SKrzysztof Kosiński                           sizeof(dex::MethodIdItem));
1528*a03ca8b9SKrzysztof Kosiński   return std::make_unique<InstructionReferenceReader>(
1529*a03ca8b9SKrzysztof Kosiński       image_, lo, hi, code_item_offsets_, std::move(filter), std::move(mapper));
1530*a03ca8b9SKrzysztof Kosiński }
1531*a03ca8b9SKrzysztof Kosiński 
MakeReadCodeToRelCode8(offset_t lo,offset_t hi)1532*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerDex::MakeReadCodeToRelCode8(
1533*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1534*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1535*a03ca8b9SKrzysztof Kosiński   auto filter = base::BindRepeating(
1536*a03ca8b9SKrzysztof Kosiński       [](const InstructionParser::Value& value) -> offset_t {
1537*a03ca8b9SKrzysztof Kosiński         if (value.instr->format == dex::FormatId::t &&
1538*a03ca8b9SKrzysztof Kosiński             value.instr->opcode == 0x28) {  // goto
1539*a03ca8b9SKrzysztof Kosiński           // +AA from e.g., goto +AA.
1540*a03ca8b9SKrzysztof Kosiński           return value.instr_offset + 1;
1541*a03ca8b9SKrzysztof Kosiński         }
1542*a03ca8b9SKrzysztof Kosiński         return kInvalidOffset;
1543*a03ca8b9SKrzysztof Kosiński       });
1544*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(
1545*a03ca8b9SKrzysztof Kosiński       [](DisassemblerDex* dis, offset_t location) {
1546*a03ca8b9SKrzysztof Kosiński         // Address is relative to the current instruction, which begins 1 unit
1547*a03ca8b9SKrzysztof Kosiński         // before |location|. This needs to be subtracted out. Also, store as
1548*a03ca8b9SKrzysztof Kosiński         // int32_t so |unsafe_delta - 1| won't underflow!
1549*a03ca8b9SKrzysztof Kosiński         int32_t unsafe_delta = dis->image_.read<int8_t>(location);
1550*a03ca8b9SKrzysztof Kosiński         offset_t unsafe_target = static_cast<offset_t>(
1551*a03ca8b9SKrzysztof Kosiński             location + (unsafe_delta - 1) * kInstrUnitSize);
1552*a03ca8b9SKrzysztof Kosiński         // TODO(huangs): Check that |unsafe_target| stays within code item.
1553*a03ca8b9SKrzysztof Kosiński         return unsafe_target;
1554*a03ca8b9SKrzysztof Kosiński       },
1555*a03ca8b9SKrzysztof Kosiński       base::Unretained(this));
1556*a03ca8b9SKrzysztof Kosiński   return std::make_unique<InstructionReferenceReader>(
1557*a03ca8b9SKrzysztof Kosiński       image_, lo, hi, code_item_offsets_, std::move(filter), std::move(mapper));
1558*a03ca8b9SKrzysztof Kosiński }
1559*a03ca8b9SKrzysztof Kosiński 
MakeReadCodeToRelCode16(offset_t lo,offset_t hi)1560*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerDex::MakeReadCodeToRelCode16(
1561*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1562*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1563*a03ca8b9SKrzysztof Kosiński   auto filter = base::BindRepeating(
1564*a03ca8b9SKrzysztof Kosiński       [](const InstructionParser::Value& value) -> offset_t {
1565*a03ca8b9SKrzysztof Kosiński         if (value.instr->format == dex::FormatId::t &&
1566*a03ca8b9SKrzysztof Kosiński             (value.instr->opcode == 0x29 ||   // goto/16
1567*a03ca8b9SKrzysztof Kosiński              value.instr->opcode == 0x32 ||   // if-test
1568*a03ca8b9SKrzysztof Kosiński              value.instr->opcode == 0x38)) {  // if-testz
1569*a03ca8b9SKrzysztof Kosiński           // +AAAA from e.g., goto/16 +AAAA.
1570*a03ca8b9SKrzysztof Kosiński           return value.instr_offset + 2;
1571*a03ca8b9SKrzysztof Kosiński         }
1572*a03ca8b9SKrzysztof Kosiński         return kInvalidOffset;
1573*a03ca8b9SKrzysztof Kosiński       });
1574*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(
1575*a03ca8b9SKrzysztof Kosiński       [](DisassemblerDex* dis, offset_t location) {
1576*a03ca8b9SKrzysztof Kosiński         // Address is relative to the current instruction, which begins 1 unit
1577*a03ca8b9SKrzysztof Kosiński         // before |location|. This needs to be subtracted out. Also, store as
1578*a03ca8b9SKrzysztof Kosiński         // int32_t so |unsafe_delta - 1| won't underflow!
1579*a03ca8b9SKrzysztof Kosiński         int32_t unsafe_delta = dis->image_.read<int16_t>(location);
1580*a03ca8b9SKrzysztof Kosiński         offset_t unsafe_target = static_cast<offset_t>(
1581*a03ca8b9SKrzysztof Kosiński             location + (unsafe_delta - 1) * kInstrUnitSize);
1582*a03ca8b9SKrzysztof Kosiński         // TODO(huangs): Check that |unsafe_target| stays within code item.
1583*a03ca8b9SKrzysztof Kosiński         return unsafe_target;
1584*a03ca8b9SKrzysztof Kosiński       },
1585*a03ca8b9SKrzysztof Kosiński       base::Unretained(this));
1586*a03ca8b9SKrzysztof Kosiński   return std::make_unique<InstructionReferenceReader>(
1587*a03ca8b9SKrzysztof Kosiński       image_, lo, hi, code_item_offsets_, std::move(filter), std::move(mapper));
1588*a03ca8b9SKrzysztof Kosiński }
1589*a03ca8b9SKrzysztof Kosiński 
MakeReadCodeToRelCode32(offset_t lo,offset_t hi)1590*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerDex::MakeReadCodeToRelCode32(
1591*a03ca8b9SKrzysztof Kosiński     offset_t lo,
1592*a03ca8b9SKrzysztof Kosiński     offset_t hi) {
1593*a03ca8b9SKrzysztof Kosiński   auto filter = base::BindRepeating(
1594*a03ca8b9SKrzysztof Kosiński       [](const InstructionParser::Value& value) -> offset_t {
1595*a03ca8b9SKrzysztof Kosiński         if (value.instr->format == dex::FormatId::t &&
1596*a03ca8b9SKrzysztof Kosiński             (value.instr->opcode == 0x26 ||   // fill-array-data
1597*a03ca8b9SKrzysztof Kosiński              value.instr->opcode == 0x2A ||   // goto/32
1598*a03ca8b9SKrzysztof Kosiński              value.instr->opcode == 0x2B ||   // packed-switch
1599*a03ca8b9SKrzysztof Kosiński              value.instr->opcode == 0x2C)) {  // sparse-switch
1600*a03ca8b9SKrzysztof Kosiński           // +BBBBBBBB from e.g., fill-array-data vAA, +BBBBBBBB.
1601*a03ca8b9SKrzysztof Kosiński           // +AAAAAAAA from e.g., goto/32 +AAAAAAAA.
1602*a03ca8b9SKrzysztof Kosiński           return value.instr_offset + 2;
1603*a03ca8b9SKrzysztof Kosiński         }
1604*a03ca8b9SKrzysztof Kosiński         return kInvalidOffset;
1605*a03ca8b9SKrzysztof Kosiński       });
1606*a03ca8b9SKrzysztof Kosiński   auto mapper = base::BindRepeating(
1607*a03ca8b9SKrzysztof Kosiński       [](DisassemblerDex* dis, offset_t location) {
1608*a03ca8b9SKrzysztof Kosiński         // Address is relative to the current instruction, which begins 1 unit
1609*a03ca8b9SKrzysztof Kosiński         // before |location|. This needs to be subtracted out. Use int64_t to
1610*a03ca8b9SKrzysztof Kosiński         // avoid underflow and overflow.
1611*a03ca8b9SKrzysztof Kosiński         int64_t unsafe_delta = dis->image_.read<int32_t>(location);
1612*a03ca8b9SKrzysztof Kosiński         int64_t unsafe_target = location + (unsafe_delta - 1) * kInstrUnitSize;
1613*a03ca8b9SKrzysztof Kosiński 
1614*a03ca8b9SKrzysztof Kosiński         // TODO(huangs): Check that |unsafe_target| stays within code item.
1615*a03ca8b9SKrzysztof Kosiński         offset_t checked_unsafe_target =
1616*a03ca8b9SKrzysztof Kosiński             static_cast<offset_t>(base::CheckedNumeric<offset_t>(unsafe_target)
1617*a03ca8b9SKrzysztof Kosiński                                       .ValueOrDefault(kInvalidOffset));
1618*a03ca8b9SKrzysztof Kosiński         return checked_unsafe_target < kOffsetBound ? checked_unsafe_target
1619*a03ca8b9SKrzysztof Kosiński                                                     : kInvalidOffset;
1620*a03ca8b9SKrzysztof Kosiński       },
1621*a03ca8b9SKrzysztof Kosiński       base::Unretained(this));
1622*a03ca8b9SKrzysztof Kosiński   return std::make_unique<InstructionReferenceReader>(
1623*a03ca8b9SKrzysztof Kosiński       image_, lo, hi, code_item_offsets_, std::move(filter), std::move(mapper));
1624*a03ca8b9SKrzysztof Kosiński }
1625*a03ca8b9SKrzysztof Kosiński 
MakeWriteStringId16(MutableBufferView image)1626*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteStringId16(
1627*a03ca8b9SKrzysztof Kosiński     MutableBufferView image) {
1628*a03ca8b9SKrzysztof Kosiński   auto writer = base::BindRepeating(
1629*a03ca8b9SKrzysztof Kosiński       WriteTargetIndex<uint16_t>, string_map_item_, sizeof(dex::StringIdItem));
1630*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer));
1631*a03ca8b9SKrzysztof Kosiński }
1632*a03ca8b9SKrzysztof Kosiński 
MakeWriteStringId32(MutableBufferView image)1633*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteStringId32(
1634*a03ca8b9SKrzysztof Kosiński     MutableBufferView image) {
1635*a03ca8b9SKrzysztof Kosiński   auto writer = base::BindRepeating(
1636*a03ca8b9SKrzysztof Kosiński       WriteTargetIndex<uint32_t>, string_map_item_, sizeof(dex::StringIdItem));
1637*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer));
1638*a03ca8b9SKrzysztof Kosiński }
1639*a03ca8b9SKrzysztof Kosiński 
MakeWriteTypeId16(MutableBufferView image)1640*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteTypeId16(
1641*a03ca8b9SKrzysztof Kosiński     MutableBufferView image) {
1642*a03ca8b9SKrzysztof Kosiński   auto writer = base::BindRepeating(WriteTargetIndex<uint16_t>, type_map_item_,
1643*a03ca8b9SKrzysztof Kosiński                                     sizeof(dex::TypeIdItem));
1644*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer));
1645*a03ca8b9SKrzysztof Kosiński }
1646*a03ca8b9SKrzysztof Kosiński 
MakeWriteTypeId32(MutableBufferView image)1647*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteTypeId32(
1648*a03ca8b9SKrzysztof Kosiński     MutableBufferView image) {
1649*a03ca8b9SKrzysztof Kosiński   auto writer = base::BindRepeating(WriteTargetIndex<uint32_t>, type_map_item_,
1650*a03ca8b9SKrzysztof Kosiński                                     sizeof(dex::TypeIdItem));
1651*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer));
1652*a03ca8b9SKrzysztof Kosiński }
1653*a03ca8b9SKrzysztof Kosiński 
MakeWriteProtoId16(MutableBufferView image)1654*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteProtoId16(
1655*a03ca8b9SKrzysztof Kosiński     MutableBufferView image) {
1656*a03ca8b9SKrzysztof Kosiński   auto writer = base::BindRepeating(WriteTargetIndex<uint16_t>, proto_map_item_,
1657*a03ca8b9SKrzysztof Kosiński                                     sizeof(dex::ProtoIdItem));
1658*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer));
1659*a03ca8b9SKrzysztof Kosiński }
1660*a03ca8b9SKrzysztof Kosiński 
MakeWriteFieldId16(MutableBufferView image)1661*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteFieldId16(
1662*a03ca8b9SKrzysztof Kosiński     MutableBufferView image) {
1663*a03ca8b9SKrzysztof Kosiński   auto writer = base::BindRepeating(WriteTargetIndex<uint16_t>, field_map_item_,
1664*a03ca8b9SKrzysztof Kosiński                                     sizeof(dex::FieldIdItem));
1665*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer));
1666*a03ca8b9SKrzysztof Kosiński }
1667*a03ca8b9SKrzysztof Kosiński 
MakeWriteFieldId32(MutableBufferView image)1668*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteFieldId32(
1669*a03ca8b9SKrzysztof Kosiński     MutableBufferView image) {
1670*a03ca8b9SKrzysztof Kosiński   auto writer = base::BindRepeating(WriteTargetIndex<uint32_t>, field_map_item_,
1671*a03ca8b9SKrzysztof Kosiński                                     sizeof(dex::FieldIdItem));
1672*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer));
1673*a03ca8b9SKrzysztof Kosiński }
1674*a03ca8b9SKrzysztof Kosiński 
MakeWriteMethodId16(MutableBufferView image)1675*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteMethodId16(
1676*a03ca8b9SKrzysztof Kosiński     MutableBufferView image) {
1677*a03ca8b9SKrzysztof Kosiński   auto writer = base::BindRepeating(
1678*a03ca8b9SKrzysztof Kosiński       WriteTargetIndex<uint16_t>, method_map_item_, sizeof(dex::MethodIdItem));
1679*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer));
1680*a03ca8b9SKrzysztof Kosiński }
1681*a03ca8b9SKrzysztof Kosiński 
MakeWriteMethodId32(MutableBufferView image)1682*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteMethodId32(
1683*a03ca8b9SKrzysztof Kosiński     MutableBufferView image) {
1684*a03ca8b9SKrzysztof Kosiński   auto writer = base::BindRepeating(
1685*a03ca8b9SKrzysztof Kosiński       WriteTargetIndex<uint32_t>, method_map_item_, sizeof(dex::MethodIdItem));
1686*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer));
1687*a03ca8b9SKrzysztof Kosiński }
1688*a03ca8b9SKrzysztof Kosiński 
MakeWriteCallSiteId16(MutableBufferView image)1689*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteCallSiteId16(
1690*a03ca8b9SKrzysztof Kosiński     MutableBufferView image) {
1691*a03ca8b9SKrzysztof Kosiński   auto writer =
1692*a03ca8b9SKrzysztof Kosiński       base::BindRepeating(WriteTargetIndex<uint16_t>, call_site_map_item_,
1693*a03ca8b9SKrzysztof Kosiński                           sizeof(dex::CallSiteIdItem));
1694*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer));
1695*a03ca8b9SKrzysztof Kosiński }
1696*a03ca8b9SKrzysztof Kosiński 
MakeWriteMethodHandle16(MutableBufferView image)1697*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteMethodHandle16(
1698*a03ca8b9SKrzysztof Kosiński     MutableBufferView image) {
1699*a03ca8b9SKrzysztof Kosiński   auto writer =
1700*a03ca8b9SKrzysztof Kosiński       base::BindRepeating(WriteTargetIndex<uint16_t>, method_handle_map_item_,
1701*a03ca8b9SKrzysztof Kosiński                           sizeof(dex::MethodHandleItem));
1702*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer));
1703*a03ca8b9SKrzysztof Kosiński }
1704*a03ca8b9SKrzysztof Kosiński 
MakeWriteRelCode8(MutableBufferView image)1705*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteRelCode8(
1706*a03ca8b9SKrzysztof Kosiński     MutableBufferView image) {
1707*a03ca8b9SKrzysztof Kosiński   auto writer = base::BindRepeating([](Reference ref, MutableBufferView image) {
1708*a03ca8b9SKrzysztof Kosiński     ptrdiff_t unsafe_byte_diff =
1709*a03ca8b9SKrzysztof Kosiński         static_cast<ptrdiff_t>(ref.target) - ref.location;
1710*a03ca8b9SKrzysztof Kosiński     DCHECK_EQ(0, unsafe_byte_diff % kInstrUnitSize);
1711*a03ca8b9SKrzysztof Kosiński     // |delta| is relative to start of instruction, which is 1 unit before
1712*a03ca8b9SKrzysztof Kosiński     // |ref.location|. The subtraction above removed too much, so +1 to fix.
1713*a03ca8b9SKrzysztof Kosiński     base::CheckedNumeric<int8_t> delta((unsafe_byte_diff / kInstrUnitSize) + 1);
1714*a03ca8b9SKrzysztof Kosiński     if (!delta.IsValid()) {
1715*a03ca8b9SKrzysztof Kosiński       LOG(ERROR) << "Invalid reference at: " << AsHex<8>(ref.location) << ".";
1716*a03ca8b9SKrzysztof Kosiński       return;
1717*a03ca8b9SKrzysztof Kosiński     }
1718*a03ca8b9SKrzysztof Kosiński     image.write<int8_t>(ref.location, delta.ValueOrDie());
1719*a03ca8b9SKrzysztof Kosiński   });
1720*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer));
1721*a03ca8b9SKrzysztof Kosiński }
1722*a03ca8b9SKrzysztof Kosiński 
MakeWriteRelCode16(MutableBufferView image)1723*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteRelCode16(
1724*a03ca8b9SKrzysztof Kosiński     MutableBufferView image) {
1725*a03ca8b9SKrzysztof Kosiński   auto writer = base::BindRepeating([](Reference ref, MutableBufferView image) {
1726*a03ca8b9SKrzysztof Kosiński     ptrdiff_t unsafe_byte_diff =
1727*a03ca8b9SKrzysztof Kosiński         static_cast<ptrdiff_t>(ref.target) - ref.location;
1728*a03ca8b9SKrzysztof Kosiński     DCHECK_EQ(0, unsafe_byte_diff % kInstrUnitSize);
1729*a03ca8b9SKrzysztof Kosiński     // |delta| is relative to start of instruction, which is 1 unit before
1730*a03ca8b9SKrzysztof Kosiński     // |ref.location|. The subtraction above removed too much, so +1 to fix.
1731*a03ca8b9SKrzysztof Kosiński     base::CheckedNumeric<int16_t> delta((unsafe_byte_diff / kInstrUnitSize) +
1732*a03ca8b9SKrzysztof Kosiński                                         1);
1733*a03ca8b9SKrzysztof Kosiński     if (!delta.IsValid()) {
1734*a03ca8b9SKrzysztof Kosiński       LOG(ERROR) << "Invalid reference at: " << AsHex<8>(ref.location) << ".";
1735*a03ca8b9SKrzysztof Kosiński       return;
1736*a03ca8b9SKrzysztof Kosiński     }
1737*a03ca8b9SKrzysztof Kosiński     image.write<int16_t>(ref.location, delta.ValueOrDie());
1738*a03ca8b9SKrzysztof Kosiński   });
1739*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer));
1740*a03ca8b9SKrzysztof Kosiński }
1741*a03ca8b9SKrzysztof Kosiński 
MakeWriteRelCode32(MutableBufferView image)1742*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteRelCode32(
1743*a03ca8b9SKrzysztof Kosiński     MutableBufferView image) {
1744*a03ca8b9SKrzysztof Kosiński   auto writer = base::BindRepeating([](Reference ref, MutableBufferView image) {
1745*a03ca8b9SKrzysztof Kosiński     ptrdiff_t unsafe_byte_diff =
1746*a03ca8b9SKrzysztof Kosiński         static_cast<ptrdiff_t>(ref.target) - ref.location;
1747*a03ca8b9SKrzysztof Kosiński     DCHECK_EQ(0, unsafe_byte_diff % kInstrUnitSize);
1748*a03ca8b9SKrzysztof Kosiński     // |delta| is relative to start of instruction, which is 1 unit before
1749*a03ca8b9SKrzysztof Kosiński     // |ref.location|. The subtraction above removed too much, so +1 to fix.
1750*a03ca8b9SKrzysztof Kosiński     base::CheckedNumeric<int32_t> delta((unsafe_byte_diff / kInstrUnitSize) +
1751*a03ca8b9SKrzysztof Kosiński                                         1);
1752*a03ca8b9SKrzysztof Kosiński     if (!delta.IsValid()) {
1753*a03ca8b9SKrzysztof Kosiński       LOG(ERROR) << "Invalid reference at: " << AsHex<8>(ref.location) << ".";
1754*a03ca8b9SKrzysztof Kosiński       return;
1755*a03ca8b9SKrzysztof Kosiński     }
1756*a03ca8b9SKrzysztof Kosiński     image.write<int32_t>(ref.location, delta.ValueOrDie());
1757*a03ca8b9SKrzysztof Kosiński   });
1758*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer));
1759*a03ca8b9SKrzysztof Kosiński }
1760*a03ca8b9SKrzysztof Kosiński 
MakeWriteAbs32(MutableBufferView image)1761*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteAbs32(
1762*a03ca8b9SKrzysztof Kosiński     MutableBufferView image) {
1763*a03ca8b9SKrzysztof Kosiński   auto writer = base::BindRepeating([](Reference ref, MutableBufferView image) {
1764*a03ca8b9SKrzysztof Kosiński     image.write<uint32_t>(ref.location, ref.target);
1765*a03ca8b9SKrzysztof Kosiński   });
1766*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer));
1767*a03ca8b9SKrzysztof Kosiński }
1768*a03ca8b9SKrzysztof Kosiński 
Parse(ConstBufferView image)1769*a03ca8b9SKrzysztof Kosiński bool DisassemblerDex::Parse(ConstBufferView image) {
1770*a03ca8b9SKrzysztof Kosiński   image_ = image;
1771*a03ca8b9SKrzysztof Kosiński   return ParseHeader();
1772*a03ca8b9SKrzysztof Kosiński }
1773*a03ca8b9SKrzysztof Kosiński 
ParseHeader()1774*a03ca8b9SKrzysztof Kosiński bool DisassemblerDex::ParseHeader() {
1775*a03ca8b9SKrzysztof Kosiński   ReadDexHeaderResults results;
1776*a03ca8b9SKrzysztof Kosiński   if (!ReadDexHeader(image_, &results))
1777*a03ca8b9SKrzysztof Kosiński     return false;
1778*a03ca8b9SKrzysztof Kosiński 
1779*a03ca8b9SKrzysztof Kosiński   header_ = results.header;
1780*a03ca8b9SKrzysztof Kosiński   dex_version_ = results.dex_version;
1781*a03ca8b9SKrzysztof Kosiński   BufferSource source = results.source;
1782*a03ca8b9SKrzysztof Kosiński 
1783*a03ca8b9SKrzysztof Kosiński   // DEX header contains file size, so use it to resize |image_| right away.
1784*a03ca8b9SKrzysztof Kosiński   image_.shrink(header_->file_size);
1785*a03ca8b9SKrzysztof Kosiński 
1786*a03ca8b9SKrzysztof Kosiński   // Read map list. This is not a fixed-size array, so instead of reading
1787*a03ca8b9SKrzysztof Kosiński   // MapList directly, read |MapList::size| first, then visit elements in
1788*a03ca8b9SKrzysztof Kosiński   // |MapList::list|.
1789*a03ca8b9SKrzysztof Kosiński   static_assert(
1790*a03ca8b9SKrzysztof Kosiński       offsetof(dex::MapList, list) == sizeof(decltype(dex::MapList::size)),
1791*a03ca8b9SKrzysztof Kosiński       "MapList size error.");
1792*a03ca8b9SKrzysztof Kosiński   source = std::move(BufferSource(image_).Skip(header_->map_off));
1793*a03ca8b9SKrzysztof Kosiński   decltype(dex::MapList::size) list_size = 0;
1794*a03ca8b9SKrzysztof Kosiński   if (!source.GetValue(&list_size) || list_size > dex::kMaxItemListSize)
1795*a03ca8b9SKrzysztof Kosiński     return false;
1796*a03ca8b9SKrzysztof Kosiński   const auto* item_list = source.GetArray<const dex::MapItem>(list_size);
1797*a03ca8b9SKrzysztof Kosiński   if (!item_list)
1798*a03ca8b9SKrzysztof Kosiński     return false;
1799*a03ca8b9SKrzysztof Kosiński 
1800*a03ca8b9SKrzysztof Kosiński   // Read and validate map list, ensuring that required item types are present.
1801*a03ca8b9SKrzysztof Kosiński   // GetItemBaseSize() should have an entry for each item.
1802*a03ca8b9SKrzysztof Kosiński   for (offset_t i = 0; i < list_size; ++i) {
1803*a03ca8b9SKrzysztof Kosiński     const dex::MapItem* item = &item_list[i];
1804*a03ca8b9SKrzysztof Kosiński     // Reject unreasonably large |item->size|.
1805*a03ca8b9SKrzysztof Kosiński     size_t item_size = GetItemBaseSize(item->type);
1806*a03ca8b9SKrzysztof Kosiński     // Confusing name: |item->size| is actually the number of items.
1807*a03ca8b9SKrzysztof Kosiński     if (!image_.covers_array(item->offset, item->size, item_size))
1808*a03ca8b9SKrzysztof Kosiński       return false;
1809*a03ca8b9SKrzysztof Kosiński     if (!map_item_map_.insert(std::make_pair(item->type, item)).second)
1810*a03ca8b9SKrzysztof Kosiński       return false;  // A given type must appear at most once.
1811*a03ca8b9SKrzysztof Kosiński   }
1812*a03ca8b9SKrzysztof Kosiński 
1813*a03ca8b9SKrzysztof Kosiński   // Make local copies of main map items.
1814*a03ca8b9SKrzysztof Kosiński   if (map_item_map_.count(dex::kTypeStringIdItem)) {
1815*a03ca8b9SKrzysztof Kosiński     string_map_item_ = *map_item_map_[dex::kTypeStringIdItem];
1816*a03ca8b9SKrzysztof Kosiński   }
1817*a03ca8b9SKrzysztof Kosiński   if (map_item_map_.count(dex::kTypeTypeIdItem)) {
1818*a03ca8b9SKrzysztof Kosiński     type_map_item_ = *map_item_map_[dex::kTypeTypeIdItem];
1819*a03ca8b9SKrzysztof Kosiński   }
1820*a03ca8b9SKrzysztof Kosiński   if (map_item_map_.count(dex::kTypeProtoIdItem)) {
1821*a03ca8b9SKrzysztof Kosiński     proto_map_item_ = *map_item_map_[dex::kTypeProtoIdItem];
1822*a03ca8b9SKrzysztof Kosiński   }
1823*a03ca8b9SKrzysztof Kosiński   if (map_item_map_.count(dex::kTypeFieldIdItem)) {
1824*a03ca8b9SKrzysztof Kosiński     field_map_item_ = *map_item_map_[dex::kTypeFieldIdItem];
1825*a03ca8b9SKrzysztof Kosiński   }
1826*a03ca8b9SKrzysztof Kosiński   if (map_item_map_.count(dex::kTypeMethodIdItem)) {
1827*a03ca8b9SKrzysztof Kosiński     method_map_item_ = *map_item_map_[dex::kTypeMethodIdItem];
1828*a03ca8b9SKrzysztof Kosiński   }
1829*a03ca8b9SKrzysztof Kosiński   if (map_item_map_.count(dex::kTypeClassDefItem)) {
1830*a03ca8b9SKrzysztof Kosiński     class_def_map_item_ = *map_item_map_[dex::kTypeClassDefItem];
1831*a03ca8b9SKrzysztof Kosiński   }
1832*a03ca8b9SKrzysztof Kosiński   if (map_item_map_.count(dex::kTypeCallSiteIdItem)) {
1833*a03ca8b9SKrzysztof Kosiński     call_site_map_item_ = *map_item_map_[dex::kTypeCallSiteIdItem];
1834*a03ca8b9SKrzysztof Kosiński   }
1835*a03ca8b9SKrzysztof Kosiński   if (map_item_map_.count(dex::kTypeMethodHandleItem)) {
1836*a03ca8b9SKrzysztof Kosiński     method_handle_map_item_ = *map_item_map_[dex::kTypeMethodHandleItem];
1837*a03ca8b9SKrzysztof Kosiński   }
1838*a03ca8b9SKrzysztof Kosiński   if (map_item_map_.count(dex::kTypeTypeList)) {
1839*a03ca8b9SKrzysztof Kosiński     type_list_map_item_ = *map_item_map_[dex::kTypeTypeList];
1840*a03ca8b9SKrzysztof Kosiński   }
1841*a03ca8b9SKrzysztof Kosiński   if (map_item_map_.count(dex::kTypeAnnotationSetRefList)) {
1842*a03ca8b9SKrzysztof Kosiński     annotation_set_ref_list_map_item_ =
1843*a03ca8b9SKrzysztof Kosiński         *map_item_map_[dex::kTypeAnnotationSetRefList];
1844*a03ca8b9SKrzysztof Kosiński   }
1845*a03ca8b9SKrzysztof Kosiński   if (map_item_map_.count(dex::kTypeAnnotationSetItem)) {
1846*a03ca8b9SKrzysztof Kosiński     annotation_set_map_item_ = *map_item_map_[dex::kTypeAnnotationSetItem];
1847*a03ca8b9SKrzysztof Kosiński   }
1848*a03ca8b9SKrzysztof Kosiński   if (map_item_map_.count(dex::kTypeCodeItem)) {
1849*a03ca8b9SKrzysztof Kosiński     code_map_item_ = *map_item_map_[dex::kTypeCodeItem];
1850*a03ca8b9SKrzysztof Kosiński   }
1851*a03ca8b9SKrzysztof Kosiński   if (map_item_map_.count(dex::kTypeAnnotationsDirectoryItem)) {
1852*a03ca8b9SKrzysztof Kosiński     annotations_directory_map_item_ =
1853*a03ca8b9SKrzysztof Kosiński         *map_item_map_[dex::kTypeAnnotationsDirectoryItem];
1854*a03ca8b9SKrzysztof Kosiński   }
1855*a03ca8b9SKrzysztof Kosiński 
1856*a03ca8b9SKrzysztof Kosiński   // Iteratively parse variable length lists, annotations directory items, and
1857*a03ca8b9SKrzysztof Kosiński   // code items blocks. Any failure would indicate invalid DEX. Success
1858*a03ca8b9SKrzysztof Kosiński   // indicates that no structural problem is found. However, contained
1859*a03ca8b9SKrzysztof Kosiński   // references data read from parsed items still require validation.
1860*a03ca8b9SKrzysztof Kosiński   if (!(ParseItemOffsets(image_, type_list_map_item_, sizeof(dex::TypeItem),
1861*a03ca8b9SKrzysztof Kosiński                          &type_list_offsets_) &&
1862*a03ca8b9SKrzysztof Kosiński         ParseItemOffsets(image_, annotation_set_ref_list_map_item_,
1863*a03ca8b9SKrzysztof Kosiński                          sizeof(dex::AnnotationSetRefItem),
1864*a03ca8b9SKrzysztof Kosiński                          &annotation_set_ref_list_offsets_) &&
1865*a03ca8b9SKrzysztof Kosiński         ParseItemOffsets(image_, annotation_set_map_item_,
1866*a03ca8b9SKrzysztof Kosiński                          sizeof(dex::AnnotationOffItem),
1867*a03ca8b9SKrzysztof Kosiński                          &annotation_set_offsets_) &&
1868*a03ca8b9SKrzysztof Kosiński         ParseAnnotationsDirectoryItems(
1869*a03ca8b9SKrzysztof Kosiński             image_, annotations_directory_map_item_,
1870*a03ca8b9SKrzysztof Kosiński             &annotations_directory_item_offsets_,
1871*a03ca8b9SKrzysztof Kosiński             &annotations_directory_item_field_annotation_offsets_,
1872*a03ca8b9SKrzysztof Kosiński             &annotations_directory_item_method_annotation_offsets_,
1873*a03ca8b9SKrzysztof Kosiński             &annotations_directory_item_parameter_annotation_offsets_))) {
1874*a03ca8b9SKrzysztof Kosiński     return false;
1875*a03ca8b9SKrzysztof Kosiński   }
1876*a03ca8b9SKrzysztof Kosiński   CodeItemParser code_item_parser(image_);
1877*a03ca8b9SKrzysztof Kosiński   if (!code_item_parser.Init(code_map_item_))
1878*a03ca8b9SKrzysztof Kosiński     return false;
1879*a03ca8b9SKrzysztof Kosiński   code_item_offsets_.resize(code_map_item_.size);
1880*a03ca8b9SKrzysztof Kosiński   for (size_t i = 0; i < code_map_item_.size; ++i) {
1881*a03ca8b9SKrzysztof Kosiński     const offset_t code_item_offset = code_item_parser.GetNext();
1882*a03ca8b9SKrzysztof Kosiński     if (code_item_offset == kInvalidOffset)
1883*a03ca8b9SKrzysztof Kosiński       return false;
1884*a03ca8b9SKrzysztof Kosiński     code_item_offsets_[i] = code_item_offset;
1885*a03ca8b9SKrzysztof Kosiński   }
1886*a03ca8b9SKrzysztof Kosiński   // DEX files are required to have parsable code items.
1887*a03ca8b9SKrzysztof Kosiński   return !code_item_offsets_.empty();
1888*a03ca8b9SKrzysztof Kosiński }
1889*a03ca8b9SKrzysztof Kosiński 
1890*a03ca8b9SKrzysztof Kosiński }  // namespace zucchini
1891