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