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