blob: 8ea031410967b852a29a965ff1f49d12eda0ab08 [file] [log] [blame]
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +00001// 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
Samuel Huanga8a2a942018-04-09 15:18:17 +00007#include <stddef.h>
8#include <stdlib.h>
9
10#include <algorithm>
11#include <cctype>
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +000012#include <cmath>
Samuel Huanga8a2a942018-04-09 15:18:17 +000013#include <iterator>
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +000014#include <set>
15#include <utility>
16
Samuel Huanga8a2a942018-04-09 15:18:17 +000017#include "base/bind.h"
18#include "base/callback.h"
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +000019#include "base/logging.h"
Peter Kastingead42e92021-07-08 15:04:58 +000020#include "base/numerics/checked_math.h"
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +000021#include "base/numerics/safe_conversions.h"
22#include "base/strings/stringprintf.h"
23#include "components/zucchini/buffer_source.h"
24#include "components/zucchini/buffer_view.h"
Samuel Huanga8a2a942018-04-09 15:18:17 +000025#include "components/zucchini/io_utils.h"
Anton Bikineev1a965512021-05-15 22:35:36 +000026#include "third_party/abseil-cpp/absl/types/optional.h"
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +000027
28namespace zucchini {
29
30namespace {
31
Calder Kitagawa18379912018-06-05 14:10:29 +000032// 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).
34constexpr 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.
38constexpr offset_t kDexSentinelIndexAsOffset = 0xFFFFFFFFU;
39
40static_assert(kDexSentinelIndexAsOffset != kInvalidOffset,
41 "Sentinel should not be confused with invalid offset.");
42
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +000043// 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>().
46constexpr int kInstrUnitSize = static_cast<int>(sizeof(uint16_t));
47
Calder Kitagawa6b80ac72018-06-11 13:54:24 +000048// Checks if |offset| is byte aligned to 32 bits or 4 bytes.
49bool Is32BitAligned(offset_t offset) {
50 return offset % 4 == 0;
51}
52
Samuel Huang06a9be12018-07-11 20:02:23 +000053// 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.
58size_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);
ckitagawa26518ff2021-09-03 15:48:28 +000072 case dex::kTypeCallSiteIdItem:
73 return sizeof(dex::CallSiteIdItem);
74 case dex::kTypeMethodHandleItem:
75 return sizeof(dex::MethodHandleItem);
Samuel Huang06a9be12018-07-11 20:02:23 +000076 // 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
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +000092/******** CodeItemParser ********/
93
94// A parser to extract successive code items from a DEX image whose header has
95// been parsed.
96class CodeItemParser {
97 public:
98 using size_type = BufferSource::size_type;
99
100 explicit CodeItemParser(ConstBufferView image) : image_(image) {}
101
102 // Initializes the parser, returns true on success and false on error.
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 // }
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;
Calder Kitagawa6b80ac72018-06-11 13:54:24 +0000168 DCHECK(Is32BitAligned(code_item_offset));
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +0000169
Samuel Huangd758cb72018-07-19 14:32:28 +0000170 // TODO(huangs): Fail if |code_item->insns_size == 0| (Constraint A1).
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +0000171 // 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.
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
Samuel Huanga8a2a942018-04-09 15:18:17 +0000235/******** 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.
242class 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.
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
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.
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
321 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.
336class 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
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:
Anton Bikineev1a965512021-05-15 22:35:36 +0000371 absl::optional<Reference> GetNext() override {
Calder Kitagawa18379912018-06-05 14:10:29 +0000372 while (true) {
Samuel Huanga8a2a942018-04-09 15:18:17 +0000373 while (parser_.ReadNext()) {
374 const auto& v = parser_.value();
375 DCHECK_NE(v.instr, nullptr);
376 if (v.instr_offset >= hi_)
Anton Bikineev1a965512021-05-15 22:35:36 +0000377 return absl::nullopt;
Samuel Huanga8a2a942018-04-09 15:18:17 +0000378 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_)
Anton Bikineev1a965512021-05-15 22:35:36 +0000385 return absl::nullopt;
Samuel Huanga8a2a942018-04-09 15:18:17 +0000386 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_)
Anton Bikineev1a965512021-05-15 22:35:36 +0000394 return absl::nullopt;
Samuel Huanga8a2a942018-04-09 15:18:17 +0000395 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.
416class 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.
ckitagawa26518ff2021-09-03 15:48:28 +0000423 // |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.
Samuel Huanga8a2a942018-04-09 15:18:17 +0000426 ItemReferenceReader(offset_t lo,
427 offset_t hi,
428 const dex::MapItem& map_item,
429 size_t item_size,
430 size_t rel_location,
ckitagawa26518ff2021-09-03 15:48:28 +0000431 Mapper&& mapper,
432 bool mapper_wants_item = false)
Samuel Huanga8a2a942018-04-09 15:18:17 +0000433 : 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)),
ckitagawa26518ff2021-09-03 15:48:28 +0000438 mapper_input_delta_(
439 mapper_wants_item ? 0 : base::checked_cast<uint32_t>(rel_location)),
Samuel Huanga8a2a942018-04-09 15:18:17 +0000440 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.");
Calder Kitagawa18379912018-06-05 14:10:29 +0000445 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_) {
Samuel Huanga8a2a942018-04-09 15:18:17 +0000449 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:
Anton Bikineev1a965512021-05-15 22:35:36 +0000461 absl::optional<Reference> GetNext() override {
Calder Kitagawa6b80ac72018-06-11 13:54:24 +0000462 while (cur_idx_ < num_items_) {
Calder Kitagawa18379912018-06-05 14:10:29 +0000463 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_)
Calder Kitagawa6b80ac72018-06-11 13:54:24 +0000469 break;
ckitagawa26518ff2021-09-03 15:48:28 +0000470
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_);
Calder Kitagawa18379912018-06-05 14:10:29 +0000475
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.
ckitagawa26518ff2021-09-03 15:48:28 +0000484 // - MethodHandleItem: |mapper_| uses ReadMethodHandleFieldOrMethodId and
485 // determines the item at |cur_idx_| is not of the required reference
486 // type.
Calder Kitagawa18379912018-06-05 14:10:29 +0000487 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) << ".";
Calder Kitagawa6b80ac72018-06-11 13:54:24 +0000494 break;
Calder Kitagawa18379912018-06-05 14:10:29 +0000495 }
496 ++cur_idx_;
497 return Reference{location, target};
Samuel Huanga8a2a942018-04-09 15:18:17 +0000498 }
Anton Bikineev1a965512021-05-15 22:35:36 +0000499 return absl::nullopt;
Samuel Huanga8a2a942018-04-09 15:18:17 +0000500 }
501
502 private:
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_;
ckitagawa26518ff2021-09-03 15:48:28 +0000512 const uint32_t mapper_input_delta_;
Samuel Huanga8a2a942018-04-09 15:18:17 +0000513 const Mapper mapper_;
514 offset_t cur_idx_ = 0;
515};
516
Calder Kitagawa6b80ac72018-06-11 13:54:24 +0000517// 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
Calder Kitagawa1b257092018-06-12 14:37:39 +0000521// the offset of each |T| into |item_offsets|, and returns true. Otherwise
Calder Kitagawa6b80ac72018-06-11 13:54:24 +0000522// (e.g., on finding any structural problem) returns false.
523bool 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
Calder Kitagawa1b257092018-06-12 14:37:39 +0000551// 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.
560bool 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
Calder Kitagawa6b80ac72018-06-11 13:54:24 +0000624/******** 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
Calder Kitagawa1b257092018-06-12 14:37:39 +0000629// |mapper| (which performs validation). By the "atomicity assumption",
630// [|lo, hi)| never cut across an MVI.
Calder Kitagawa6b80ac72018-06-11 13:54:24 +0000631class 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
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);
Calder Kitagawa1b257092018-06-12 14:37:39 +0000646 // 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)
Calder Kitagawa6b80ac72018-06-11 13:54:24 +0000649 --cur_it_;
650 }
Samuel Huangf137bf42021-08-13 15:42:26 +0000651 CachedItemListReferenceReader(const CachedItemListReferenceReader&) = delete;
652 const CachedItemListReferenceReader& operator=(
653 const CachedItemListReferenceReader&) = delete;
Calder Kitagawa6b80ac72018-06-11 13:54:24 +0000654
655 // ReferenceReader:
Anton Bikineev1a965512021-05-15 22:35:36 +0000656 absl::optional<Reference> GetNext() override {
Calder Kitagawa6b80ac72018-06-11 13:54:24 +0000657 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 }
Anton Bikineev1a965512021-05-15 22:35:36 +0000674 return absl::nullopt;
Calder Kitagawa6b80ac72018-06-11 13:54:24 +0000675 }
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_;
Calder Kitagawa6b80ac72018-06-11 13:54:24 +0000683};
684
Samuel Huanga8a2a942018-04-09 15:18:17 +0000685// 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
Calder Kitagawa6b80ac72018-06-11 13:54:24 +0000688// otherwise. This is compatible with
689// CachedReferenceListReferenceReader::Mapper,
690// InstructionReferenceReader::Mapper, and ItemReferenceReader::Mapper.
Samuel Huanga8a2a942018-04-09 15:18:17 +0000691template <typename INT>
692static 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);
Calder Kitagawa18379912018-06-05 14:10:29 +0000699 // kDexSentinalIndexAsOffset (0xFFFFFFFF) is a sentinel for
700 // - ClassDefItem: superclass_idx, source_file_idx.
701 if (unsafe_idx == kDexSentinelIndexAsOffset)
702 return unsafe_idx;
Samuel Huanga8a2a942018-04-09 15:18:17 +0000703 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
ckitagawa26518ff2021-09-03 15:48:28 +0000709// 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.
722static 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
Calder Kitagawa18379912018-06-05 14:10:29 +0000756// 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
Calder Kitagawa6b80ac72018-06-11 13:54:24 +0000759// CachedReferenceListReferenceReader::Mapper,
760// InstructionReferenceReader::Mapper, and ItemReferenceReader::Mapper.
Calder Kitagawa18379912018-06-05 14:10:29 +0000761static 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
Samuel Huanga8a2a942018-04-09 15:18:17 +0000776/******** ReferenceWriterAdaptor ********/
777
778// A ReferenceWriter that adapts a callback that performs type-specific
779// Reference writes.
780class ReferenceWriterAdaptor : public ReferenceWriter {
781 public:
782 using Writer = base::RepeatingCallback<void(Reference, MutableBufferView)>;
783
784 ReferenceWriterAdaptor(MutableBufferView image, Writer&& writer)
785 : image_(image), writer_(std::move(writer)) {}
786
787 // ReferenceWriter:
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|.
799template <typename INT>
800static void WriteTargetIndex(const dex::MapItem& target_map_item,
801 size_t target_item_size,
802 Reference ref,
803 MutableBufferView image) {
Calder Kitagawa3a5639a2018-07-09 18:53:48 +0000804 const size_t unsafe_idx =
805 (ref.target - target_map_item.offset) / target_item_size;
Samuel Huanga8a2a942018-04-09 15:18:17 +0000806 // Verify that index is within bound.
Calder Kitagawa3a5639a2018-07-09 18:53:48 +0000807 if (unsafe_idx >= target_map_item.size) {
808 LOG(ERROR) << "Target index out of bounds at: " << AsHex<8>(ref.location)
809 << ".";
810 return;
811 }
Samuel Huanga8a2a942018-04-09 15:18:17 +0000812 // Verify that |ref.target| points to start of item.
Calder Kitagawa3a5639a2018-07-09 18:53:48 +0000813 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));
Samuel Huanga8a2a942018-04-09 15:18:17 +0000815}
816
817// Buffer for ReadDexHeader() to optionally return results.
818struct 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.
827bool 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
ckitagawa1269b5c2021-09-07 21:12:21 +0000847 // Only support DEX versions 35, 37, 38, and 39
848 if (dex_version != 35 && dex_version != 37 && dex_version != 38 &&
849 dex_version != 39) {
Samuel Huanga8a2a942018-04-09 15:18:17 +0000850 return false;
ckitagawa1269b5c2021-09-07 21:12:21 +0000851 }
Samuel Huanga8a2a942018-04-09 15:18:17 +0000852
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
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +0000866/******** DisassemblerDex ********/
867
868DisassemblerDex::DisassemblerDex() : Disassembler(4) {}
869
870DisassemblerDex::~DisassemblerDex() = default;
871
872// static.
873bool DisassemblerDex::QuickDetect(ConstBufferView image) {
874 return ReadDexHeader(image, nullptr);
875}
876
877ExecutableType DisassemblerDex::GetExeType() const {
878 return kExeTypeDex;
879}
880
881std::string DisassemblerDex::GetExeTypeString() const {
882 return base::StringPrintf("DEX (version %d)", dex_version_);
883}
884
885std::vector<ReferenceGroup> DisassemblerDex::MakeReferenceGroups() const {
Samuel Huanga8a2a942018-04-09 15:18:17 +0000886 // Must follow DisassemblerDex::ReferenceType order. Initialized on first use.
887 return {
Calder Kitagawa18379912018-06-05 14:10:29 +0000888 {{4, TypeTag(kTypeIdToDescriptorStringId), PoolTag(kStringId)},
889 &DisassemblerDex::MakeReadTypeIdToDescriptorStringId32,
890 &DisassemblerDex::MakeWriteStringId32},
891 {{4, TypeTag(kProtoIdToShortyStringId), PoolTag(kStringId)},
892 &DisassemblerDex::MakeReadProtoIdToShortyStringId32,
893 &DisassemblerDex::MakeWriteStringId32},
Samuel Huanga8a2a942018-04-09 15:18:17 +0000894 {{4, TypeTag(kFieldIdToNameStringId), PoolTag(kStringId)},
895 &DisassemblerDex::MakeReadFieldToNameStringId32,
896 &DisassemblerDex::MakeWriteStringId32},
Calder Kitagawa18379912018-06-05 14:10:29 +0000897 {{4, TypeTag(kMethodIdToNameStringId), PoolTag(kStringId)},
898 &DisassemblerDex::MakeReadMethodIdToNameStringId32,
899 &DisassemblerDex::MakeWriteStringId32},
900 {{4, TypeTag(kClassDefToSourceFileStringId), PoolTag(kStringId)},
901 &DisassemblerDex::MakeReadClassDefToSourceFileStringId32,
902 &DisassemblerDex::MakeWriteStringId32},
Samuel Huanga8a2a942018-04-09 15:18:17 +0000903 {{2, TypeTag(kCodeToStringId16), PoolTag(kStringId)},
904 &DisassemblerDex::MakeReadCodeToStringId16,
905 &DisassemblerDex::MakeWriteStringId16},
906 {{4, TypeTag(kCodeToStringId32), PoolTag(kStringId)},
907 &DisassemblerDex::MakeReadCodeToStringId32,
908 &DisassemblerDex::MakeWriteStringId32},
Calder Kitagawa18379912018-06-05 14:10:29 +0000909 {{4, TypeTag(kProtoIdToReturnTypeId), PoolTag(kTypeId)},
910 &DisassemblerDex::MakeReadProtoIdToReturnTypeId32,
911 &DisassemblerDex::MakeWriteTypeId32},
Samuel Huanga8a2a942018-04-09 15:18:17 +0000912 {{2, TypeTag(kFieldIdToClassTypeId), PoolTag(kTypeId)},
913 &DisassemblerDex::MakeReadFieldToClassTypeId16,
914 &DisassemblerDex::MakeWriteTypeId16},
915 {{2, TypeTag(kFieldIdToTypeId), PoolTag(kTypeId)},
916 &DisassemblerDex::MakeReadFieldToTypeId16,
917 &DisassemblerDex::MakeWriteTypeId16},
Calder Kitagawa18379912018-06-05 14:10:29 +0000918 {{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},
Calder Kitagawa6b80ac72018-06-11 13:54:24 +0000927 {{2, TypeTag(kTypeListToTypeId), PoolTag(kTypeId)},
928 &DisassemblerDex::MakeReadTypeListToTypeId16,
929 &DisassemblerDex::MakeWriteTypeId16},
Samuel Huanga8a2a942018-04-09 15:18:17 +0000930 {{2, TypeTag(kCodeToTypeId), PoolTag(kTypeId)},
931 &DisassemblerDex::MakeReadCodeToTypeId16,
932 &DisassemblerDex::MakeWriteTypeId16},
ckitagawa26518ff2021-09-03 15:48:28 +0000933 {{2, TypeTag(kCodeToProtoId), PoolTag(kProtoId)},
934 &DisassemblerDex::MakeReadCodeToProtoId16,
935 &DisassemblerDex::MakeWriteProtoId16},
Calder Kitagawa18379912018-06-05 14:10:29 +0000936 {{2, TypeTag(kMethodIdToProtoId), PoolTag(kProtoId)},
937 &DisassemblerDex::MakeReadMethodIdToProtoId16,
938 &DisassemblerDex::MakeWriteProtoId16},
Samuel Huanga8a2a942018-04-09 15:18:17 +0000939 {{2, TypeTag(kCodeToFieldId), PoolTag(kFieldId)},
940 &DisassemblerDex::MakeReadCodeToFieldId16,
941 &DisassemblerDex::MakeWriteFieldId16},
ckitagawa26518ff2021-09-03 15:48:28 +0000942 {{2, TypeTag(kMethodHandleToFieldId), PoolTag(kFieldId)},
943 &DisassemblerDex::MakeReadMethodHandleToFieldId16,
944 &DisassemblerDex::MakeWriteFieldId16},
Calder Kitagawa1b257092018-06-12 14:37:39 +0000945 {{4, TypeTag(kAnnotationsDirectoryToFieldId), PoolTag(kFieldId)},
946 &DisassemblerDex::MakeReadAnnotationsDirectoryToFieldId32,
947 &DisassemblerDex::MakeWriteFieldId32},
Samuel Huanga8a2a942018-04-09 15:18:17 +0000948 {{2, TypeTag(kCodeToMethodId), PoolTag(kMethodId)},
949 &DisassemblerDex::MakeReadCodeToMethodId16,
950 &DisassemblerDex::MakeWriteMethodId16},
ckitagawa26518ff2021-09-03 15:48:28 +0000951 {{2, TypeTag(kMethodHandleToMethodId), PoolTag(kMethodId)},
952 &DisassemblerDex::MakeReadMethodHandleToMethodId16,
953 &DisassemblerDex::MakeWriteMethodId16},
Calder Kitagawa1b257092018-06-12 14:37:39 +0000954 {{4, TypeTag(kAnnotationsDirectoryToMethodId), PoolTag(kMethodId)},
955 &DisassemblerDex::MakeReadAnnotationsDirectoryToMethodId32,
956 &DisassemblerDex::MakeWriteMethodId32},
957 {{4, TypeTag(kAnnotationsDirectoryToParameterMethodId),
958 PoolTag(kMethodId)},
959 &DisassemblerDex::MakeReadAnnotationsDirectoryToParameterMethodId32,
960 &DisassemblerDex::MakeWriteMethodId32},
ckitagawa26518ff2021-09-03 15:48:28 +0000961 {{2, TypeTag(kCodeToCallSiteId), PoolTag(kCallSiteId)},
962 &DisassemblerDex::MakeReadCodeToCallSiteId16,
963 &DisassemblerDex::MakeWriteCallSiteId16},
ckitagawa1269b5c2021-09-07 21:12:21 +0000964 {{2, TypeTag(kCodeToMethodHandle), PoolTag(kMethodHandle)},
965 &DisassemblerDex::MakeReadCodeToMethodHandle16,
966 &DisassemblerDex::MakeWriteMethodHandle16},
Calder Kitagawa18379912018-06-05 14:10:29 +0000967 {{4, TypeTag(kProtoIdToParametersTypeList), PoolTag(kTypeList)},
968 &DisassemblerDex::MakeReadProtoIdToParametersTypeList,
969 &DisassemblerDex::MakeWriteAbs32},
970 {{4, TypeTag(kClassDefToInterfacesTypeList), PoolTag(kTypeList)},
971 &DisassemblerDex::MakeReadClassDefToInterfacesTypeList,
972 &DisassemblerDex::MakeWriteAbs32},
Calder Kitagawa1b257092018-06-12 14:37:39 +0000973 {{4, TypeTag(kAnnotationsDirectoryToParameterAnnotationSetRef),
974 PoolTag(kAnnotationSetRefList)},
975 &DisassemblerDex::
976 MakeReadAnnotationsDirectoryToParameterAnnotationSetRef,
977 &DisassemblerDex::MakeWriteAbs32},
Calder Kitagawa6b80ac72018-06-11 13:54:24 +0000978 {{4, TypeTag(kAnnotationSetRefListToAnnotationSet),
979 PoolTag(kAnnotionSet)},
980 &DisassemblerDex::MakeReadAnnotationSetRefListToAnnotationSet,
981 &DisassemblerDex::MakeWriteAbs32},
Calder Kitagawa1b257092018-06-12 14:37:39 +0000982 {{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},
Calder Kitagawa18379912018-06-05 14:10:29 +0000994 {{4, TypeTag(kClassDefToClassData), PoolTag(kClassData)},
995 &DisassemblerDex::MakeReadClassDefToClassData,
996 &DisassemblerDex::MakeWriteAbs32},
997 {{1, TypeTag(kCodeToRelCode8), PoolTag(kCode)},
998 &DisassemblerDex::MakeReadCodeToRelCode8,
999 &DisassemblerDex::MakeWriteRelCode8},
Samuel Huanga8a2a942018-04-09 15:18:17 +00001000 {{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},
Calder Kitagawa6b80ac72018-06-11 13:54:24 +00001009 {{4, TypeTag(kAnnotationSetToAnnotation), PoolTag(kAnnotation)},
1010 &DisassemblerDex::MakeReadAnnotationSetToAnnotation,
1011 &DisassemblerDex::MakeWriteAbs32},
Calder Kitagawa18379912018-06-05 14:10:29 +00001012 {{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},
ckitagawa26518ff2021-09-03 15:48:28 +00001020 {{4, TypeTag(kCallSiteIdToCallSite), PoolTag(kCallSite)},
1021 &DisassemblerDex::MakeReadCallSiteIdToCallSite32,
1022 &DisassemblerDex::MakeWriteAbs32},
Samuel Huanga8a2a942018-04-09 15:18:17 +00001023 };
1024}
1025
1026std::unique_ptr<ReferenceReader> DisassemblerDex::MakeReadStringIdToStringData(
1027 offset_t lo,
1028 offset_t hi) {
Calder Kitagawa18379912018-06-05 14:10:29 +00001029 // dex::StringIdItem::string_data_off mapper.
1030 auto mapper = base::BindRepeating(ReadTargetOffset32, image_);
Samuel Huanga8a2a942018-04-09 15:18:17 +00001031 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
Calder Kitagawa18379912018-06-05 14:10:29 +00001036std::unique_ptr<ReferenceReader>
1037DisassemblerDex::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
1047std::unique_ptr<ReferenceReader>
1048DisassemblerDex::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
1057std::unique_ptr<ReferenceReader>
1058DisassemblerDex::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
1067std::unique_ptr<ReferenceReader>
1068DisassemblerDex::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
Samuel Huanga8a2a942018-04-09 15:18:17 +00001076std::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
1087std::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
1098std::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
Calder Kitagawa18379912018-06-05 14:10:29 +00001109std::unique_ptr<ReferenceReader>
1110DisassemblerDex::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
1119std::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
1130std::unique_ptr<ReferenceReader>
1131DisassemblerDex::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
1140std::unique_ptr<ReferenceReader>
1141DisassemblerDex::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
1150std::unique_ptr<ReferenceReader>
1151DisassemblerDex::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
1161std::unique_ptr<ReferenceReader>
1162DisassemblerDex::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
1171std::unique_ptr<ReferenceReader>
1172DisassemblerDex::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
1182std::unique_ptr<ReferenceReader>
1183DisassemblerDex::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
1192std::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
1202std::unique_ptr<ReferenceReader>
1203DisassemblerDex::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
ckitagawa26518ff2021-09-03 15:48:28 +00001212std::unique_ptr<ReferenceReader>
1213DisassemblerDex::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
1220std::unique_ptr<ReferenceReader>
1221DisassemblerDex::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
1236std::unique_ptr<ReferenceReader>
1237DisassemblerDex::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
Calder Kitagawa6b80ac72018-06-11 13:54:24 +00001252std::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
1263std::unique_ptr<ReferenceReader>
1264DisassemblerDex::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
1272std::unique_ptr<ReferenceReader>
1273DisassemblerDex::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
Calder Kitagawa1b257092018-06-12 14:37:39 +00001282std::unique_ptr<ReferenceReader>
1283DisassemblerDex::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
1292std::unique_ptr<ReferenceReader>
1293DisassemblerDex::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
1303std::unique_ptr<ReferenceReader>
1304DisassemblerDex::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
1313std::unique_ptr<ReferenceReader>
1314DisassemblerDex::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
1324std::unique_ptr<ReferenceReader>
1325DisassemblerDex::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
1335std::unique_ptr<ReferenceReader>
1336DisassemblerDex::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
1348std::unique_ptr<ReferenceReader>
1349DisassemblerDex::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
ckitagawa26518ff2021-09-03 15:48:28 +00001360// 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
Samuel Huanga8a2a942018-04-09 15:18:17 +00001364std::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
1383std::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
1402std::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
ckitagawa26518ff2021-09-03 15:48:28 +00001426std::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 {
ckitagawa1269b5c2021-09-07 21:12:21 +00001431 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 }
ckitagawa26518ff2021-09-03 15:48:28 +00001442 }
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
1451std::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
ckitagawa1269b5c2021-09-07 21:12:21 +00001472std::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
Samuel Huanga8a2a942018-04-09 15:18:17 +00001491std::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
1510std::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
ckitagawa26518ff2021-09-03 15:48:28 +00001517 value.instr->opcode == 0x74 || // invoke-kind/range
1518 value.instr->opcode == 0xFA || // invoke-polymorphic
1519 value.instr->opcode == 0xFB)) { // invoke-polymorphic/range
Samuel Huanga8a2a942018-04-09 15:18:17 +00001520 // 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
Calder Kitagawa18379912018-06-05 14:10:29 +00001532std::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
Samuel Huanga8a2a942018-04-09 15:18:17 +00001560std::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
1590std::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
Calder Kitagawa620015b2018-07-11 14:55:44 +00001609 // 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
Samuel Huanga8a2a942018-04-09 15:18:17 +00001614 // TODO(huangs): Check that |unsafe_target| stays within code item.
Calder Kitagawa620015b2018-07-11 14:55:44 +00001615 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;
Samuel Huanga8a2a942018-04-09 15:18:17 +00001620 },
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
1626std::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
1633std::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
1640std::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
Calder Kitagawa18379912018-06-05 14:10:29 +00001647std::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
1654std::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
Samuel Huanga8a2a942018-04-09 15:18:17 +00001661std::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
Calder Kitagawa18379912018-06-05 14:10:29 +00001668std::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
Samuel Huanga8a2a942018-04-09 15:18:17 +00001675std::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
Calder Kitagawa18379912018-06-05 14:10:29 +00001682std::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
ckitagawa26518ff2021-09-03 15:48:28 +00001689std::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
ckitagawa1269b5c2021-09-07 21:12:21 +00001697std::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
Calder Kitagawa18379912018-06-05 14:10:29 +00001705std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteRelCode8(
1706 MutableBufferView image) {
1707 auto writer = base::BindRepeating([](Reference ref, MutableBufferView image) {
Calder Kitagawa40a74cc2018-07-04 20:44:27 +00001708 ptrdiff_t unsafe_byte_diff =
1709 static_cast<ptrdiff_t>(ref.target) - ref.location;
1710 DCHECK_EQ(0, unsafe_byte_diff % kInstrUnitSize);
Calder Kitagawa18379912018-06-05 14:10:29 +00001711 // |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.
Calder Kitagawa40a74cc2018-07-04 20:44:27 +00001713 base::CheckedNumeric<int8_t> delta((unsafe_byte_diff / kInstrUnitSize) + 1);
1714 if (!delta.IsValid()) {
Calder Kitagawa3a5639a2018-07-09 18:53:48 +00001715 LOG(ERROR) << "Invalid reference at: " << AsHex<8>(ref.location) << ".";
Calder Kitagawa40a74cc2018-07-04 20:44:27 +00001716 return;
1717 }
1718 image.write<int8_t>(ref.location, delta.ValueOrDie());
Calder Kitagawa18379912018-06-05 14:10:29 +00001719 });
1720 return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer));
1721}
1722
Samuel Huanga8a2a942018-04-09 15:18:17 +00001723std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteRelCode16(
1724 MutableBufferView image) {
1725 auto writer = base::BindRepeating([](Reference ref, MutableBufferView image) {
Calder Kitagawa40a74cc2018-07-04 20:44:27 +00001726 ptrdiff_t unsafe_byte_diff =
1727 static_cast<ptrdiff_t>(ref.target) - ref.location;
1728 DCHECK_EQ(0, unsafe_byte_diff % kInstrUnitSize);
Samuel Huanga8a2a942018-04-09 15:18:17 +00001729 // |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.
Calder Kitagawa40a74cc2018-07-04 20:44:27 +00001731 base::CheckedNumeric<int16_t> delta((unsafe_byte_diff / kInstrUnitSize) +
1732 1);
1733 if (!delta.IsValid()) {
Calder Kitagawa3a5639a2018-07-09 18:53:48 +00001734 LOG(ERROR) << "Invalid reference at: " << AsHex<8>(ref.location) << ".";
Calder Kitagawa40a74cc2018-07-04 20:44:27 +00001735 return;
1736 }
1737 image.write<int16_t>(ref.location, delta.ValueOrDie());
Samuel Huanga8a2a942018-04-09 15:18:17 +00001738 });
1739 return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer));
1740}
1741
1742std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteRelCode32(
1743 MutableBufferView image) {
1744 auto writer = base::BindRepeating([](Reference ref, MutableBufferView image) {
Calder Kitagawa40a74cc2018-07-04 20:44:27 +00001745 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()) {
Calder Kitagawa3a5639a2018-07-09 18:53:48 +00001753 LOG(ERROR) << "Invalid reference at: " << AsHex<8>(ref.location) << ".";
Calder Kitagawa40a74cc2018-07-04 20:44:27 +00001754 return;
1755 }
1756 image.write<int32_t>(ref.location, delta.ValueOrDie());
Samuel Huanga8a2a942018-04-09 15:18:17 +00001757 });
1758 return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer));
1759}
1760
1761std::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));
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +00001767}
1768
1769bool DisassemblerDex::Parse(ConstBufferView image) {
1770 image_ = image;
1771 return ParseHeader();
1772}
1773
1774bool 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.
ckitagawa26518ff2021-09-03 15:48:28 +00001801 // GetItemBaseSize() should have an entry for each item.
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +00001802 for (offset_t i = 0; i < list_size; ++i) {
1803 const dex::MapItem* item = &item_list[i];
Samuel Huang06a9be12018-07-11 20:02:23 +00001804 // 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))
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +00001808 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.
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +00001811 }
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +00001812
1813 // Make local copies of main map items.
ckitagawa26518ff2021-09-03 15:48:28 +00001814 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 }
Calder Kitagawa6b80ac72018-06-11 13:54:24 +00001841 if (map_item_map_.count(dex::kTypeAnnotationSetRefList)) {
1842 annotation_set_ref_list_map_item_ =
1843 *map_item_map_[dex::kTypeAnnotationSetRefList];
1844 }
ckitagawa26518ff2021-09-03 15:48:28 +00001845 if (map_item_map_.count(dex::kTypeAnnotationSetItem)) {
Calder Kitagawa6b80ac72018-06-11 13:54:24 +00001846 annotation_set_map_item_ = *map_item_map_[dex::kTypeAnnotationSetItem];
ckitagawa26518ff2021-09-03 15:48:28 +00001847 }
1848 if (map_item_map_.count(dex::kTypeCodeItem)) {
1849 code_map_item_ = *map_item_map_[dex::kTypeCodeItem];
1850 }
Calder Kitagawa1b257092018-06-12 14:37:39 +00001851 if (map_item_map_.count(dex::kTypeAnnotationsDirectoryItem)) {
1852 annotations_directory_map_item_ =
1853 *map_item_map_[dex::kTypeAnnotationsDirectoryItem];
Calder Kitagawa6b80ac72018-06-11 13:54:24 +00001854 }
1855
Calder Kitagawa1b257092018-06-12 14:37:39 +00001856 // 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 }
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +00001876 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 }
Calder Kitagawa82e84722018-06-28 21:48:40 +00001886 // DEX files are required to have parsable code items.
1887 return !code_item_offsets_.empty();
Etienne Pierre-Dorayfff1ca32018-03-29 13:33:46 +00001888}
1889
1890} // namespace zucchini