1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2011 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "dex_file.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include <limits.h>
20*795d594fSAndroid Build Coastguard Worker #include <stdio.h>
21*795d594fSAndroid Build Coastguard Worker #include <stdlib.h>
22*795d594fSAndroid Build Coastguard Worker #include <string.h>
23*795d594fSAndroid Build Coastguard Worker #include <zlib.h>
24*795d594fSAndroid Build Coastguard Worker
25*795d594fSAndroid Build Coastguard Worker #include <memory>
26*795d594fSAndroid Build Coastguard Worker #include <optional>
27*795d594fSAndroid Build Coastguard Worker #include <ostream>
28*795d594fSAndroid Build Coastguard Worker #include <sstream>
29*795d594fSAndroid Build Coastguard Worker #include <type_traits>
30*795d594fSAndroid Build Coastguard Worker
31*795d594fSAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
32*795d594fSAndroid Build Coastguard Worker #include "base/hiddenapi_domain.h"
33*795d594fSAndroid Build Coastguard Worker #include "base/leb128.h"
34*795d594fSAndroid Build Coastguard Worker #include "base/pointer_size.h"
35*795d594fSAndroid Build Coastguard Worker #include "base/stl_util.h"
36*795d594fSAndroid Build Coastguard Worker #include "class_accessor-inl.h"
37*795d594fSAndroid Build Coastguard Worker #include "compact_dex_file.h"
38*795d594fSAndroid Build Coastguard Worker #include "descriptors_names.h"
39*795d594fSAndroid Build Coastguard Worker #include "dex_file-inl.h"
40*795d594fSAndroid Build Coastguard Worker #include "standard_dex_file.h"
41*795d594fSAndroid Build Coastguard Worker #include "utf-inl.h"
42*795d594fSAndroid Build Coastguard Worker
43*795d594fSAndroid Build Coastguard Worker namespace art {
44*795d594fSAndroid Build Coastguard Worker
45*795d594fSAndroid Build Coastguard Worker using android::base::StringPrintf;
46*795d594fSAndroid Build Coastguard Worker
47*795d594fSAndroid Build Coastguard Worker using dex::CallSiteIdItem;
48*795d594fSAndroid Build Coastguard Worker using dex::ClassDef;
49*795d594fSAndroid Build Coastguard Worker using dex::FieldId;
50*795d594fSAndroid Build Coastguard Worker using dex::MapList;
51*795d594fSAndroid Build Coastguard Worker using dex::MapItem;
52*795d594fSAndroid Build Coastguard Worker using dex::MethodHandleItem;
53*795d594fSAndroid Build Coastguard Worker using dex::MethodId;
54*795d594fSAndroid Build Coastguard Worker using dex::ProtoId;
55*795d594fSAndroid Build Coastguard Worker using dex::StringId;
56*795d594fSAndroid Build Coastguard Worker using dex::TryItem;
57*795d594fSAndroid Build Coastguard Worker using dex::TypeId;
58*795d594fSAndroid Build Coastguard Worker using dex::TypeList;
59*795d594fSAndroid Build Coastguard Worker
60*795d594fSAndroid Build Coastguard Worker static_assert(sizeof(dex::StringIndex) == sizeof(uint32_t), "StringIndex size is wrong");
61*795d594fSAndroid Build Coastguard Worker static_assert(std::is_trivially_copyable<dex::StringIndex>::value, "StringIndex not trivial");
62*795d594fSAndroid Build Coastguard Worker static_assert(sizeof(dex::TypeIndex) == sizeof(uint16_t), "TypeIndex size is wrong");
63*795d594fSAndroid Build Coastguard Worker static_assert(std::is_trivially_copyable<dex::TypeIndex>::value, "TypeIndex not trivial");
64*795d594fSAndroid Build Coastguard Worker
65*795d594fSAndroid Build Coastguard Worker // Print the SHA1 as 20-byte hexadecimal string.
ToString() const66*795d594fSAndroid Build Coastguard Worker std::string DexFile::Sha1::ToString() const {
67*795d594fSAndroid Build Coastguard Worker auto data = this->data();
68*795d594fSAndroid Build Coastguard Worker auto part = [d = data](int i) { return d[i] << 24 | d[i + 1] << 16 | d[i + 2] << 8 | d[i + 3]; };
69*795d594fSAndroid Build Coastguard Worker return StringPrintf("%08x%08x%08x%08x%08x", part(0), part(4), part(8), part(12), part(16));
70*795d594fSAndroid Build Coastguard Worker }
71*795d594fSAndroid Build Coastguard Worker
CalculateChecksum() const72*795d594fSAndroid Build Coastguard Worker uint32_t DexFile::CalculateChecksum() const {
73*795d594fSAndroid Build Coastguard Worker return CalculateChecksum(Begin(), Size());
74*795d594fSAndroid Build Coastguard Worker }
75*795d594fSAndroid Build Coastguard Worker
CalculateChecksum(const uint8_t * begin,size_t size)76*795d594fSAndroid Build Coastguard Worker uint32_t DexFile::CalculateChecksum(const uint8_t* begin, size_t size) {
77*795d594fSAndroid Build Coastguard Worker const uint32_t non_sum_bytes = OFFSETOF_MEMBER(DexFile::Header, signature_);
78*795d594fSAndroid Build Coastguard Worker return ChecksumMemoryRange(begin + non_sum_bytes, size - non_sum_bytes);
79*795d594fSAndroid Build Coastguard Worker }
80*795d594fSAndroid Build Coastguard Worker
ChecksumMemoryRange(const uint8_t * begin,size_t size)81*795d594fSAndroid Build Coastguard Worker uint32_t DexFile::ChecksumMemoryRange(const uint8_t* begin, size_t size) {
82*795d594fSAndroid Build Coastguard Worker return adler32(adler32(0L, Z_NULL, 0), begin, size);
83*795d594fSAndroid Build Coastguard Worker }
84*795d594fSAndroid Build Coastguard Worker
IsReadOnly() const85*795d594fSAndroid Build Coastguard Worker bool DexFile::IsReadOnly() const {
86*795d594fSAndroid Build Coastguard Worker CHECK(container_.get() != nullptr);
87*795d594fSAndroid Build Coastguard Worker return container_->IsReadOnly();
88*795d594fSAndroid Build Coastguard Worker }
89*795d594fSAndroid Build Coastguard Worker
EnableWrite() const90*795d594fSAndroid Build Coastguard Worker bool DexFile::EnableWrite() const {
91*795d594fSAndroid Build Coastguard Worker CHECK(container_.get() != nullptr);
92*795d594fSAndroid Build Coastguard Worker return container_->EnableWrite();
93*795d594fSAndroid Build Coastguard Worker }
94*795d594fSAndroid Build Coastguard Worker
DisableWrite() const95*795d594fSAndroid Build Coastguard Worker bool DexFile::DisableWrite() const {
96*795d594fSAndroid Build Coastguard Worker CHECK(container_.get() != nullptr);
97*795d594fSAndroid Build Coastguard Worker return container_->DisableWrite();
98*795d594fSAndroid Build Coastguard Worker }
99*795d594fSAndroid Build Coastguard Worker
GetExpectedHeaderSize() const100*795d594fSAndroid Build Coastguard Worker uint32_t DexFile::Header::GetExpectedHeaderSize() const {
101*795d594fSAndroid Build Coastguard Worker uint32_t version = GetVersion();
102*795d594fSAndroid Build Coastguard Worker return version == 0 ? 0 : version < 41 ? sizeof(Header) : sizeof(HeaderV41);
103*795d594fSAndroid Build Coastguard Worker }
104*795d594fSAndroid Build Coastguard Worker
HasDexContainer() const105*795d594fSAndroid Build Coastguard Worker bool DexFile::Header::HasDexContainer() const {
106*795d594fSAndroid Build Coastguard Worker if (CompactDexFile::IsMagicValid(magic_.data())) {
107*795d594fSAndroid Build Coastguard Worker return false;
108*795d594fSAndroid Build Coastguard Worker }
109*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(header_size_, GetExpectedHeaderSize());
110*795d594fSAndroid Build Coastguard Worker return header_size_ >= sizeof(HeaderV41);
111*795d594fSAndroid Build Coastguard Worker }
112*795d594fSAndroid Build Coastguard Worker
HeaderOffset() const113*795d594fSAndroid Build Coastguard Worker uint32_t DexFile::Header::HeaderOffset() const {
114*795d594fSAndroid Build Coastguard Worker return HasDexContainer() ? reinterpret_cast<const HeaderV41*>(this)->header_offset_ : 0;
115*795d594fSAndroid Build Coastguard Worker }
116*795d594fSAndroid Build Coastguard Worker
ContainerSize() const117*795d594fSAndroid Build Coastguard Worker uint32_t DexFile::Header::ContainerSize() const {
118*795d594fSAndroid Build Coastguard Worker return HasDexContainer() ? reinterpret_cast<const HeaderV41*>(this)->container_size_ : file_size_;
119*795d594fSAndroid Build Coastguard Worker }
120*795d594fSAndroid Build Coastguard Worker
SetDexContainer(size_t header_offset,size_t container_size)121*795d594fSAndroid Build Coastguard Worker void DexFile::Header::SetDexContainer(size_t header_offset, size_t container_size) {
122*795d594fSAndroid Build Coastguard Worker if (HasDexContainer()) {
123*795d594fSAndroid Build Coastguard Worker DCHECK_LE(header_offset, container_size);
124*795d594fSAndroid Build Coastguard Worker DCHECK_LE(file_size_, container_size - header_offset);
125*795d594fSAndroid Build Coastguard Worker data_off_ = 0;
126*795d594fSAndroid Build Coastguard Worker data_size_ = 0;
127*795d594fSAndroid Build Coastguard Worker auto* headerV41 = reinterpret_cast<HeaderV41*>(this);
128*795d594fSAndroid Build Coastguard Worker DCHECK_GE(header_size_, sizeof(*headerV41));
129*795d594fSAndroid Build Coastguard Worker headerV41->header_offset_ = header_offset;
130*795d594fSAndroid Build Coastguard Worker headerV41->container_size_ = container_size;
131*795d594fSAndroid Build Coastguard Worker } else {
132*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(header_offset, 0u);
133*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(container_size, file_size_);
134*795d594fSAndroid Build Coastguard Worker }
135*795d594fSAndroid Build Coastguard Worker }
136*795d594fSAndroid Build Coastguard Worker
137*795d594fSAndroid Build Coastguard Worker template <typename T>
GetSection(const uint32_t * offset,DexFileContainer * container)138*795d594fSAndroid Build Coastguard Worker ALWAYS_INLINE const T* DexFile::GetSection(const uint32_t* offset, DexFileContainer* container) {
139*795d594fSAndroid Build Coastguard Worker size_t size = container->End() - begin_;
140*795d594fSAndroid Build Coastguard Worker if (size < sizeof(Header)) {
141*795d594fSAndroid Build Coastguard Worker return nullptr; // Invalid dex file.
142*795d594fSAndroid Build Coastguard Worker }
143*795d594fSAndroid Build Coastguard Worker // Compact dex is inconsistent: section offsets are relative to the
144*795d594fSAndroid Build Coastguard Worker // header as opposed to the data section like all other its offsets.
145*795d594fSAndroid Build Coastguard Worker if (CompactDexFile::IsMagicValid(begin_)) {
146*795d594fSAndroid Build Coastguard Worker const uint8_t* data = reinterpret_cast<const uint8_t*>(header_);
147*795d594fSAndroid Build Coastguard Worker return reinterpret_cast<const T*>(data + *offset);
148*795d594fSAndroid Build Coastguard Worker }
149*795d594fSAndroid Build Coastguard Worker return reinterpret_cast<const T*>(data_.data() + *offset);
150*795d594fSAndroid Build Coastguard Worker }
151*795d594fSAndroid Build Coastguard Worker
DexFile(const uint8_t * base,const std::string & location,uint32_t location_checksum,const OatDexFile * oat_dex_file,std::shared_ptr<DexFileContainer> container,bool is_compact_dex)152*795d594fSAndroid Build Coastguard Worker DexFile::DexFile(const uint8_t* base,
153*795d594fSAndroid Build Coastguard Worker const std::string& location,
154*795d594fSAndroid Build Coastguard Worker uint32_t location_checksum,
155*795d594fSAndroid Build Coastguard Worker const OatDexFile* oat_dex_file,
156*795d594fSAndroid Build Coastguard Worker std::shared_ptr<DexFileContainer> container,
157*795d594fSAndroid Build Coastguard Worker bool is_compact_dex)
158*795d594fSAndroid Build Coastguard Worker : begin_(base),
159*795d594fSAndroid Build Coastguard Worker data_(GetDataRange(base, container.get())),
160*795d594fSAndroid Build Coastguard Worker location_(location),
161*795d594fSAndroid Build Coastguard Worker location_checksum_(location_checksum),
162*795d594fSAndroid Build Coastguard Worker header_(reinterpret_cast<const Header*>(base)),
163*795d594fSAndroid Build Coastguard Worker string_ids_(GetSection<StringId>(&header_->string_ids_off_, container.get())),
164*795d594fSAndroid Build Coastguard Worker type_ids_(GetSection<TypeId>(&header_->type_ids_off_, container.get())),
165*795d594fSAndroid Build Coastguard Worker field_ids_(GetSection<FieldId>(&header_->field_ids_off_, container.get())),
166*795d594fSAndroid Build Coastguard Worker method_ids_(GetSection<MethodId>(&header_->method_ids_off_, container.get())),
167*795d594fSAndroid Build Coastguard Worker proto_ids_(GetSection<ProtoId>(&header_->proto_ids_off_, container.get())),
168*795d594fSAndroid Build Coastguard Worker class_defs_(GetSection<ClassDef>(&header_->class_defs_off_, container.get())),
169*795d594fSAndroid Build Coastguard Worker method_handles_(nullptr),
170*795d594fSAndroid Build Coastguard Worker num_method_handles_(0),
171*795d594fSAndroid Build Coastguard Worker call_site_ids_(nullptr),
172*795d594fSAndroid Build Coastguard Worker num_call_site_ids_(0),
173*795d594fSAndroid Build Coastguard Worker hiddenapi_class_data_(nullptr),
174*795d594fSAndroid Build Coastguard Worker oat_dex_file_(oat_dex_file),
175*795d594fSAndroid Build Coastguard Worker container_(std::move(container)),
176*795d594fSAndroid Build Coastguard Worker is_compact_dex_(is_compact_dex),
177*795d594fSAndroid Build Coastguard Worker hiddenapi_domain_(hiddenapi::Domain::kApplication) {
178*795d594fSAndroid Build Coastguard Worker CHECK(begin_ != nullptr) << GetLocation();
179*795d594fSAndroid Build Coastguard Worker // Check base (=header) alignment.
180*795d594fSAndroid Build Coastguard Worker // Must be 4-byte aligned to avoid undefined behavior when accessing
181*795d594fSAndroid Build Coastguard Worker // any of the sections via a pointer.
182*795d594fSAndroid Build Coastguard Worker CHECK_ALIGNED(begin_, alignof(Header));
183*795d594fSAndroid Build Coastguard Worker
184*795d594fSAndroid Build Coastguard Worker if (DataSize() < sizeof(Header)) {
185*795d594fSAndroid Build Coastguard Worker // Don't go further if the data doesn't even contain a header.
186*795d594fSAndroid Build Coastguard Worker return;
187*795d594fSAndroid Build Coastguard Worker }
188*795d594fSAndroid Build Coastguard Worker
189*795d594fSAndroid Build Coastguard Worker InitializeSectionsFromMapList();
190*795d594fSAndroid Build Coastguard Worker }
191*795d594fSAndroid Build Coastguard Worker
~DexFile()192*795d594fSAndroid Build Coastguard Worker DexFile::~DexFile() {
193*795d594fSAndroid Build Coastguard Worker // We don't call DeleteGlobalRef on dex_object_ because we're only called by DestroyJavaVM, and
194*795d594fSAndroid Build Coastguard Worker // that's only called after DetachCurrentThread, which means there's no JNIEnv. We could
195*795d594fSAndroid Build Coastguard Worker // re-attach, but cleaning up these global references is not obviously useful. It's not as if
196*795d594fSAndroid Build Coastguard Worker // the global reference table is otherwise empty!
197*795d594fSAndroid Build Coastguard Worker }
198*795d594fSAndroid Build Coastguard Worker
Init(std::string * error_msg)199*795d594fSAndroid Build Coastguard Worker bool DexFile::Init(std::string* error_msg) {
200*795d594fSAndroid Build Coastguard Worker CHECK_GE(container_->End(), reinterpret_cast<const uint8_t*>(header_));
201*795d594fSAndroid Build Coastguard Worker size_t container_size = container_->End() - reinterpret_cast<const uint8_t*>(header_);
202*795d594fSAndroid Build Coastguard Worker if (container_size < sizeof(Header)) {
203*795d594fSAndroid Build Coastguard Worker *error_msg = StringPrintf("Unable to open '%s' : File size is too small to fit dex header",
204*795d594fSAndroid Build Coastguard Worker location_.c_str());
205*795d594fSAndroid Build Coastguard Worker return false;
206*795d594fSAndroid Build Coastguard Worker }
207*795d594fSAndroid Build Coastguard Worker if (!CheckMagicAndVersion(error_msg)) {
208*795d594fSAndroid Build Coastguard Worker return false;
209*795d594fSAndroid Build Coastguard Worker }
210*795d594fSAndroid Build Coastguard Worker if (!IsCompactDexFile()) {
211*795d594fSAndroid Build Coastguard Worker uint32_t expected_header_size = header_->GetExpectedHeaderSize();
212*795d594fSAndroid Build Coastguard Worker if (header_->header_size_ != expected_header_size) {
213*795d594fSAndroid Build Coastguard Worker *error_msg = StringPrintf("Unable to open '%s' : Header size is %u but %u was expected",
214*795d594fSAndroid Build Coastguard Worker location_.c_str(),
215*795d594fSAndroid Build Coastguard Worker header_->header_size_,
216*795d594fSAndroid Build Coastguard Worker expected_header_size);
217*795d594fSAndroid Build Coastguard Worker return false;
218*795d594fSAndroid Build Coastguard Worker }
219*795d594fSAndroid Build Coastguard Worker }
220*795d594fSAndroid Build Coastguard Worker if (container_size < header_->file_size_) {
221*795d594fSAndroid Build Coastguard Worker *error_msg = StringPrintf("Unable to open '%s' : File size is %zu but the header expects %u",
222*795d594fSAndroid Build Coastguard Worker location_.c_str(),
223*795d594fSAndroid Build Coastguard Worker container_size,
224*795d594fSAndroid Build Coastguard Worker header_->file_size_);
225*795d594fSAndroid Build Coastguard Worker return false;
226*795d594fSAndroid Build Coastguard Worker }
227*795d594fSAndroid Build Coastguard Worker return true;
228*795d594fSAndroid Build Coastguard Worker }
229*795d594fSAndroid Build Coastguard Worker
CheckMagicAndVersion(std::string * error_msg) const230*795d594fSAndroid Build Coastguard Worker bool DexFile::CheckMagicAndVersion(std::string* error_msg) const {
231*795d594fSAndroid Build Coastguard Worker if (!IsMagicValid()) {
232*795d594fSAndroid Build Coastguard Worker std::ostringstream oss;
233*795d594fSAndroid Build Coastguard Worker oss << "Unrecognized magic number in " << GetLocation() << ":"
234*795d594fSAndroid Build Coastguard Worker << " " << header_->magic_[0]
235*795d594fSAndroid Build Coastguard Worker << " " << header_->magic_[1]
236*795d594fSAndroid Build Coastguard Worker << " " << header_->magic_[2]
237*795d594fSAndroid Build Coastguard Worker << " " << header_->magic_[3];
238*795d594fSAndroid Build Coastguard Worker *error_msg = oss.str();
239*795d594fSAndroid Build Coastguard Worker return false;
240*795d594fSAndroid Build Coastguard Worker }
241*795d594fSAndroid Build Coastguard Worker if (!IsVersionValid()) {
242*795d594fSAndroid Build Coastguard Worker std::ostringstream oss;
243*795d594fSAndroid Build Coastguard Worker oss << "Unrecognized version number in " << GetLocation() << ":"
244*795d594fSAndroid Build Coastguard Worker << " " << header_->magic_[4]
245*795d594fSAndroid Build Coastguard Worker << " " << header_->magic_[5]
246*795d594fSAndroid Build Coastguard Worker << " " << header_->magic_[6]
247*795d594fSAndroid Build Coastguard Worker << " " << header_->magic_[7];
248*795d594fSAndroid Build Coastguard Worker *error_msg = oss.str();
249*795d594fSAndroid Build Coastguard Worker return false;
250*795d594fSAndroid Build Coastguard Worker }
251*795d594fSAndroid Build Coastguard Worker return true;
252*795d594fSAndroid Build Coastguard Worker }
253*795d594fSAndroid Build Coastguard Worker
GetDataRange(const uint8_t * data,DexFileContainer * container)254*795d594fSAndroid Build Coastguard Worker ArrayRef<const uint8_t> DexFile::GetDataRange(const uint8_t* data, DexFileContainer* container) {
255*795d594fSAndroid Build Coastguard Worker // NB: This function must survive random data to pass fuzzing and testing.
256*795d594fSAndroid Build Coastguard Worker CHECK(container != nullptr);
257*795d594fSAndroid Build Coastguard Worker CHECK_GE(data, container->Begin());
258*795d594fSAndroid Build Coastguard Worker CHECK_LE(data, container->End());
259*795d594fSAndroid Build Coastguard Worker size_t size = container->End() - data;
260*795d594fSAndroid Build Coastguard Worker if (size >= sizeof(StandardDexFile::Header) && StandardDexFile::IsMagicValid(data)) {
261*795d594fSAndroid Build Coastguard Worker auto header = reinterpret_cast<const DexFile::Header*>(data);
262*795d594fSAndroid Build Coastguard Worker CHECK_EQ(container->Data().size(), 0u) << "Unsupported for standard dex";
263*795d594fSAndroid Build Coastguard Worker if (size >= sizeof(HeaderV41) && header->header_size_ >= sizeof(HeaderV41)) {
264*795d594fSAndroid Build Coastguard Worker auto headerV41 = reinterpret_cast<const DexFile::HeaderV41*>(data);
265*795d594fSAndroid Build Coastguard Worker data -= headerV41->header_offset_; // Allow underflow and later overflow.
266*795d594fSAndroid Build Coastguard Worker size = headerV41->container_size_;
267*795d594fSAndroid Build Coastguard Worker } else {
268*795d594fSAndroid Build Coastguard Worker size = header->file_size_;
269*795d594fSAndroid Build Coastguard Worker }
270*795d594fSAndroid Build Coastguard Worker } else if (size >= sizeof(CompactDexFile::Header) && CompactDexFile::IsMagicValid(data)) {
271*795d594fSAndroid Build Coastguard Worker auto header = reinterpret_cast<const CompactDexFile::Header*>(data);
272*795d594fSAndroid Build Coastguard Worker // TODO: Remove. This is a hack. See comment of the Data method.
273*795d594fSAndroid Build Coastguard Worker ArrayRef<const uint8_t> separate_data = container->Data();
274*795d594fSAndroid Build Coastguard Worker if (separate_data.size() > 0) {
275*795d594fSAndroid Build Coastguard Worker return separate_data;
276*795d594fSAndroid Build Coastguard Worker }
277*795d594fSAndroid Build Coastguard Worker // Shared compact dex data is located at the end after all dex files.
278*795d594fSAndroid Build Coastguard Worker data += std::min<size_t>(header->data_off_, size);
279*795d594fSAndroid Build Coastguard Worker size = header->data_size_;
280*795d594fSAndroid Build Coastguard Worker }
281*795d594fSAndroid Build Coastguard Worker // The returned range is guaranteed to be in bounds of the container memory.
282*795d594fSAndroid Build Coastguard Worker return {data, std::min<size_t>(size, container->End() - data)};
283*795d594fSAndroid Build Coastguard Worker }
284*795d594fSAndroid Build Coastguard Worker
InitializeSectionsFromMapList()285*795d594fSAndroid Build Coastguard Worker void DexFile::InitializeSectionsFromMapList() {
286*795d594fSAndroid Build Coastguard Worker // NB: This function must survive random data to pass fuzzing and testing.
287*795d594fSAndroid Build Coastguard Worker static_assert(sizeof(MapList) <= sizeof(Header));
288*795d594fSAndroid Build Coastguard Worker DCHECK_GE(DataSize(), sizeof(MapList));
289*795d594fSAndroid Build Coastguard Worker if (header_->map_off_ == 0 || header_->map_off_ > DataSize() - sizeof(MapList)) {
290*795d594fSAndroid Build Coastguard Worker // Bad offset. The dex file verifier runs after this method and will reject the file.
291*795d594fSAndroid Build Coastguard Worker return;
292*795d594fSAndroid Build Coastguard Worker }
293*795d594fSAndroid Build Coastguard Worker const uint8_t* map_list_raw = DataBegin() + header_->map_off_;
294*795d594fSAndroid Build Coastguard Worker if (map_list_raw < Begin()) {
295*795d594fSAndroid Build Coastguard Worker return;
296*795d594fSAndroid Build Coastguard Worker }
297*795d594fSAndroid Build Coastguard Worker const MapList* map_list = reinterpret_cast<const MapList*>(map_list_raw);
298*795d594fSAndroid Build Coastguard Worker const size_t count = map_list->size_;
299*795d594fSAndroid Build Coastguard Worker
300*795d594fSAndroid Build Coastguard Worker size_t map_limit =
301*795d594fSAndroid Build Coastguard Worker (DataSize() - OFFSETOF_MEMBER(MapList, list_) - header_->map_off_) / sizeof(MapItem);
302*795d594fSAndroid Build Coastguard Worker if (count > map_limit) {
303*795d594fSAndroid Build Coastguard Worker // Too many items. The dex file verifier runs after
304*795d594fSAndroid Build Coastguard Worker // this method and will reject the file as it is malformed.
305*795d594fSAndroid Build Coastguard Worker return;
306*795d594fSAndroid Build Coastguard Worker }
307*795d594fSAndroid Build Coastguard Worker
308*795d594fSAndroid Build Coastguard Worker // Construct pointers to certain arrays without any checks. If they are outside the
309*795d594fSAndroid Build Coastguard Worker // data, the dex file verification should fail and these pointers should not be used.
310*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < count; ++i) {
311*795d594fSAndroid Build Coastguard Worker const MapItem& map_item = map_list->list_[i];
312*795d594fSAndroid Build Coastguard Worker if (map_item.type_ == kDexTypeMethodHandleItem) {
313*795d594fSAndroid Build Coastguard Worker method_handles_ = GetSection<MethodHandleItem>(&map_item.offset_, container_.get());
314*795d594fSAndroid Build Coastguard Worker num_method_handles_ = map_item.size_;
315*795d594fSAndroid Build Coastguard Worker } else if (map_item.type_ == kDexTypeCallSiteIdItem) {
316*795d594fSAndroid Build Coastguard Worker call_site_ids_ = GetSection<CallSiteIdItem>(&map_item.offset_, container_.get());
317*795d594fSAndroid Build Coastguard Worker num_call_site_ids_ = map_item.size_;
318*795d594fSAndroid Build Coastguard Worker } else if (map_item.type_ == kDexTypeHiddenapiClassData) {
319*795d594fSAndroid Build Coastguard Worker hiddenapi_class_data_ =
320*795d594fSAndroid Build Coastguard Worker reinterpret_cast<const dex::HiddenapiClassData*>(DataBegin() + map_item.offset_);
321*795d594fSAndroid Build Coastguard Worker } else {
322*795d594fSAndroid Build Coastguard Worker // Pointers to other sections are not necessary to retain in the DexFile struct.
323*795d594fSAndroid Build Coastguard Worker // Other items have pointers directly into their data.
324*795d594fSAndroid Build Coastguard Worker }
325*795d594fSAndroid Build Coastguard Worker }
326*795d594fSAndroid Build Coastguard Worker }
327*795d594fSAndroid Build Coastguard Worker
GetVersion() const328*795d594fSAndroid Build Coastguard Worker uint32_t DexFile::Header::GetVersion() const {
329*795d594fSAndroid Build Coastguard Worker const char* version = reinterpret_cast<const char*>(&magic_[kDexMagicSize]);
330*795d594fSAndroid Build Coastguard Worker return atoi(version);
331*795d594fSAndroid Build Coastguard Worker }
332*795d594fSAndroid Build Coastguard Worker
FindClassDef(dex::TypeIndex type_idx) const333*795d594fSAndroid Build Coastguard Worker const ClassDef* DexFile::FindClassDef(dex::TypeIndex type_idx) const {
334*795d594fSAndroid Build Coastguard Worker size_t num_class_defs = NumClassDefs();
335*795d594fSAndroid Build Coastguard Worker // Fast path for rare no class defs case.
336*795d594fSAndroid Build Coastguard Worker if (num_class_defs == 0) {
337*795d594fSAndroid Build Coastguard Worker return nullptr;
338*795d594fSAndroid Build Coastguard Worker }
339*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < num_class_defs; ++i) {
340*795d594fSAndroid Build Coastguard Worker const ClassDef& class_def = GetClassDef(i);
341*795d594fSAndroid Build Coastguard Worker if (class_def.class_idx_ == type_idx) {
342*795d594fSAndroid Build Coastguard Worker return &class_def;
343*795d594fSAndroid Build Coastguard Worker }
344*795d594fSAndroid Build Coastguard Worker }
345*795d594fSAndroid Build Coastguard Worker return nullptr;
346*795d594fSAndroid Build Coastguard Worker }
347*795d594fSAndroid Build Coastguard Worker
GetCodeItemOffset(const ClassDef & class_def,uint32_t method_idx) const348*795d594fSAndroid Build Coastguard Worker std::optional<uint32_t> DexFile::GetCodeItemOffset(const ClassDef &class_def,
349*795d594fSAndroid Build Coastguard Worker uint32_t method_idx) const {
350*795d594fSAndroid Build Coastguard Worker ClassAccessor accessor(*this, class_def);
351*795d594fSAndroid Build Coastguard Worker CHECK(accessor.HasClassData());
352*795d594fSAndroid Build Coastguard Worker for (const ClassAccessor::Method &method : accessor.GetMethods()) {
353*795d594fSAndroid Build Coastguard Worker if (method.GetIndex() == method_idx) {
354*795d594fSAndroid Build Coastguard Worker return method.GetCodeItemOffset();
355*795d594fSAndroid Build Coastguard Worker }
356*795d594fSAndroid Build Coastguard Worker }
357*795d594fSAndroid Build Coastguard Worker return std::nullopt;
358*795d594fSAndroid Build Coastguard Worker }
359*795d594fSAndroid Build Coastguard Worker
FindCodeItemOffset(const dex::ClassDef & class_def,uint32_t dex_method_idx) const360*795d594fSAndroid Build Coastguard Worker uint32_t DexFile::FindCodeItemOffset(const dex::ClassDef &class_def,
361*795d594fSAndroid Build Coastguard Worker uint32_t dex_method_idx) const {
362*795d594fSAndroid Build Coastguard Worker std::optional<uint32_t> val = GetCodeItemOffset(class_def, dex_method_idx);
363*795d594fSAndroid Build Coastguard Worker CHECK(val.has_value()) << "Unable to find method " << dex_method_idx;
364*795d594fSAndroid Build Coastguard Worker return *val;
365*795d594fSAndroid Build Coastguard Worker }
366*795d594fSAndroid Build Coastguard Worker
FindFieldId(const TypeId & declaring_klass,const StringId & name,const TypeId & type) const367*795d594fSAndroid Build Coastguard Worker const FieldId* DexFile::FindFieldId(const TypeId& declaring_klass,
368*795d594fSAndroid Build Coastguard Worker const StringId& name,
369*795d594fSAndroid Build Coastguard Worker const TypeId& type) const {
370*795d594fSAndroid Build Coastguard Worker // Binary search MethodIds knowing that they are sorted by class_idx, name_idx then proto_idx
371*795d594fSAndroid Build Coastguard Worker const dex::TypeIndex class_idx = GetIndexForTypeId(declaring_klass);
372*795d594fSAndroid Build Coastguard Worker const dex::StringIndex name_idx = GetIndexForStringId(name);
373*795d594fSAndroid Build Coastguard Worker const dex::TypeIndex type_idx = GetIndexForTypeId(type);
374*795d594fSAndroid Build Coastguard Worker int32_t lo = 0;
375*795d594fSAndroid Build Coastguard Worker int32_t hi = NumFieldIds() - 1;
376*795d594fSAndroid Build Coastguard Worker while (hi >= lo) {
377*795d594fSAndroid Build Coastguard Worker int32_t mid = (hi + lo) / 2;
378*795d594fSAndroid Build Coastguard Worker const FieldId& field = GetFieldId(mid);
379*795d594fSAndroid Build Coastguard Worker if (class_idx > field.class_idx_) {
380*795d594fSAndroid Build Coastguard Worker lo = mid + 1;
381*795d594fSAndroid Build Coastguard Worker } else if (class_idx < field.class_idx_) {
382*795d594fSAndroid Build Coastguard Worker hi = mid - 1;
383*795d594fSAndroid Build Coastguard Worker } else {
384*795d594fSAndroid Build Coastguard Worker if (name_idx > field.name_idx_) {
385*795d594fSAndroid Build Coastguard Worker lo = mid + 1;
386*795d594fSAndroid Build Coastguard Worker } else if (name_idx < field.name_idx_) {
387*795d594fSAndroid Build Coastguard Worker hi = mid - 1;
388*795d594fSAndroid Build Coastguard Worker } else {
389*795d594fSAndroid Build Coastguard Worker if (type_idx > field.type_idx_) {
390*795d594fSAndroid Build Coastguard Worker lo = mid + 1;
391*795d594fSAndroid Build Coastguard Worker } else if (type_idx < field.type_idx_) {
392*795d594fSAndroid Build Coastguard Worker hi = mid - 1;
393*795d594fSAndroid Build Coastguard Worker } else {
394*795d594fSAndroid Build Coastguard Worker return &field;
395*795d594fSAndroid Build Coastguard Worker }
396*795d594fSAndroid Build Coastguard Worker }
397*795d594fSAndroid Build Coastguard Worker }
398*795d594fSAndroid Build Coastguard Worker }
399*795d594fSAndroid Build Coastguard Worker return nullptr;
400*795d594fSAndroid Build Coastguard Worker }
401*795d594fSAndroid Build Coastguard Worker
FindMethodId(const TypeId & declaring_klass,const StringId & name,const ProtoId & signature) const402*795d594fSAndroid Build Coastguard Worker const MethodId* DexFile::FindMethodId(const TypeId& declaring_klass,
403*795d594fSAndroid Build Coastguard Worker const StringId& name,
404*795d594fSAndroid Build Coastguard Worker const ProtoId& signature) const {
405*795d594fSAndroid Build Coastguard Worker // Binary search MethodIds knowing that they are sorted by class_idx, name_idx then proto_idx
406*795d594fSAndroid Build Coastguard Worker const dex::TypeIndex class_idx = GetIndexForTypeId(declaring_klass);
407*795d594fSAndroid Build Coastguard Worker const dex::StringIndex name_idx = GetIndexForStringId(name);
408*795d594fSAndroid Build Coastguard Worker const dex::ProtoIndex proto_idx = GetIndexForProtoId(signature);
409*795d594fSAndroid Build Coastguard Worker return FindMethodIdByIndex(class_idx, name_idx, proto_idx);
410*795d594fSAndroid Build Coastguard Worker }
411*795d594fSAndroid Build Coastguard Worker
FindMethodIdByIndex(dex::TypeIndex class_idx,dex::StringIndex name_idx,dex::ProtoIndex proto_idx) const412*795d594fSAndroid Build Coastguard Worker const MethodId* DexFile::FindMethodIdByIndex(dex::TypeIndex class_idx,
413*795d594fSAndroid Build Coastguard Worker dex::StringIndex name_idx,
414*795d594fSAndroid Build Coastguard Worker dex::ProtoIndex proto_idx) const {
415*795d594fSAndroid Build Coastguard Worker // Binary search MethodIds knowing that they are sorted by class_idx, name_idx then proto_idx
416*795d594fSAndroid Build Coastguard Worker int32_t lo = 0;
417*795d594fSAndroid Build Coastguard Worker int32_t hi = NumMethodIds() - 1;
418*795d594fSAndroid Build Coastguard Worker while (hi >= lo) {
419*795d594fSAndroid Build Coastguard Worker int32_t mid = (hi + lo) / 2;
420*795d594fSAndroid Build Coastguard Worker const MethodId& method = GetMethodId(mid);
421*795d594fSAndroid Build Coastguard Worker if (class_idx > method.class_idx_) {
422*795d594fSAndroid Build Coastguard Worker lo = mid + 1;
423*795d594fSAndroid Build Coastguard Worker } else if (class_idx < method.class_idx_) {
424*795d594fSAndroid Build Coastguard Worker hi = mid - 1;
425*795d594fSAndroid Build Coastguard Worker } else {
426*795d594fSAndroid Build Coastguard Worker if (name_idx > method.name_idx_) {
427*795d594fSAndroid Build Coastguard Worker lo = mid + 1;
428*795d594fSAndroid Build Coastguard Worker } else if (name_idx < method.name_idx_) {
429*795d594fSAndroid Build Coastguard Worker hi = mid - 1;
430*795d594fSAndroid Build Coastguard Worker } else {
431*795d594fSAndroid Build Coastguard Worker if (proto_idx > method.proto_idx_) {
432*795d594fSAndroid Build Coastguard Worker lo = mid + 1;
433*795d594fSAndroid Build Coastguard Worker } else if (proto_idx < method.proto_idx_) {
434*795d594fSAndroid Build Coastguard Worker hi = mid - 1;
435*795d594fSAndroid Build Coastguard Worker } else {
436*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(class_idx, method.class_idx_);
437*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(proto_idx, method.proto_idx_);
438*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(name_idx, method.name_idx_);
439*795d594fSAndroid Build Coastguard Worker return &method;
440*795d594fSAndroid Build Coastguard Worker }
441*795d594fSAndroid Build Coastguard Worker }
442*795d594fSAndroid Build Coastguard Worker }
443*795d594fSAndroid Build Coastguard Worker }
444*795d594fSAndroid Build Coastguard Worker return nullptr;
445*795d594fSAndroid Build Coastguard Worker }
446*795d594fSAndroid Build Coastguard Worker
FindStringId(const char * string) const447*795d594fSAndroid Build Coastguard Worker const StringId* DexFile::FindStringId(const char* string) const {
448*795d594fSAndroid Build Coastguard Worker int32_t lo = 0;
449*795d594fSAndroid Build Coastguard Worker int32_t hi = NumStringIds() - 1;
450*795d594fSAndroid Build Coastguard Worker while (hi >= lo) {
451*795d594fSAndroid Build Coastguard Worker int32_t mid = (hi + lo) / 2;
452*795d594fSAndroid Build Coastguard Worker const StringId& str_id = GetStringId(dex::StringIndex(mid));
453*795d594fSAndroid Build Coastguard Worker const char* str = GetStringData(str_id);
454*795d594fSAndroid Build Coastguard Worker int compare = CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(string, str);
455*795d594fSAndroid Build Coastguard Worker if (compare > 0) {
456*795d594fSAndroid Build Coastguard Worker lo = mid + 1;
457*795d594fSAndroid Build Coastguard Worker } else if (compare < 0) {
458*795d594fSAndroid Build Coastguard Worker hi = mid - 1;
459*795d594fSAndroid Build Coastguard Worker } else {
460*795d594fSAndroid Build Coastguard Worker return &str_id;
461*795d594fSAndroid Build Coastguard Worker }
462*795d594fSAndroid Build Coastguard Worker }
463*795d594fSAndroid Build Coastguard Worker return nullptr;
464*795d594fSAndroid Build Coastguard Worker }
465*795d594fSAndroid Build Coastguard Worker
FindTypeId(std::string_view descriptor) const466*795d594fSAndroid Build Coastguard Worker const TypeId* DexFile::FindTypeId(std::string_view descriptor) const {
467*795d594fSAndroid Build Coastguard Worker int32_t lo = 0;
468*795d594fSAndroid Build Coastguard Worker int32_t hi = NumTypeIds() - 1;
469*795d594fSAndroid Build Coastguard Worker while (hi >= lo) {
470*795d594fSAndroid Build Coastguard Worker int32_t mid = (hi + lo) / 2;
471*795d594fSAndroid Build Coastguard Worker const TypeId& type_id = GetTypeId(dex::TypeIndex(mid));
472*795d594fSAndroid Build Coastguard Worker std::string_view mid_descriptor = GetTypeDescriptorView(type_id);
473*795d594fSAndroid Build Coastguard Worker int compare = CompareDescriptors(descriptor, mid_descriptor);
474*795d594fSAndroid Build Coastguard Worker if (compare > 0) {
475*795d594fSAndroid Build Coastguard Worker lo = mid + 1;
476*795d594fSAndroid Build Coastguard Worker } else if (compare < 0) {
477*795d594fSAndroid Build Coastguard Worker hi = mid - 1;
478*795d594fSAndroid Build Coastguard Worker } else {
479*795d594fSAndroid Build Coastguard Worker return &type_id;
480*795d594fSAndroid Build Coastguard Worker }
481*795d594fSAndroid Build Coastguard Worker }
482*795d594fSAndroid Build Coastguard Worker return nullptr;
483*795d594fSAndroid Build Coastguard Worker }
484*795d594fSAndroid Build Coastguard Worker
FindTypeId(dex::StringIndex string_idx) const485*795d594fSAndroid Build Coastguard Worker const TypeId* DexFile::FindTypeId(dex::StringIndex string_idx) const {
486*795d594fSAndroid Build Coastguard Worker int32_t lo = 0;
487*795d594fSAndroid Build Coastguard Worker int32_t hi = NumTypeIds() - 1;
488*795d594fSAndroid Build Coastguard Worker while (hi >= lo) {
489*795d594fSAndroid Build Coastguard Worker int32_t mid = (hi + lo) / 2;
490*795d594fSAndroid Build Coastguard Worker const TypeId& type_id = GetTypeId(dex::TypeIndex(mid));
491*795d594fSAndroid Build Coastguard Worker if (string_idx > type_id.descriptor_idx_) {
492*795d594fSAndroid Build Coastguard Worker lo = mid + 1;
493*795d594fSAndroid Build Coastguard Worker } else if (string_idx < type_id.descriptor_idx_) {
494*795d594fSAndroid Build Coastguard Worker hi = mid - 1;
495*795d594fSAndroid Build Coastguard Worker } else {
496*795d594fSAndroid Build Coastguard Worker return &type_id;
497*795d594fSAndroid Build Coastguard Worker }
498*795d594fSAndroid Build Coastguard Worker }
499*795d594fSAndroid Build Coastguard Worker return nullptr;
500*795d594fSAndroid Build Coastguard Worker }
501*795d594fSAndroid Build Coastguard Worker
FindProtoId(dex::TypeIndex return_type_idx,const dex::TypeIndex * signature_type_idxs,uint32_t signature_length) const502*795d594fSAndroid Build Coastguard Worker const ProtoId* DexFile::FindProtoId(dex::TypeIndex return_type_idx,
503*795d594fSAndroid Build Coastguard Worker const dex::TypeIndex* signature_type_idxs,
504*795d594fSAndroid Build Coastguard Worker uint32_t signature_length) const {
505*795d594fSAndroid Build Coastguard Worker int32_t lo = 0;
506*795d594fSAndroid Build Coastguard Worker int32_t hi = NumProtoIds() - 1;
507*795d594fSAndroid Build Coastguard Worker while (hi >= lo) {
508*795d594fSAndroid Build Coastguard Worker int32_t mid = (hi + lo) / 2;
509*795d594fSAndroid Build Coastguard Worker const dex::ProtoIndex proto_idx = static_cast<dex::ProtoIndex>(mid);
510*795d594fSAndroid Build Coastguard Worker const ProtoId& proto = GetProtoId(proto_idx);
511*795d594fSAndroid Build Coastguard Worker int compare = return_type_idx.index_ - proto.return_type_idx_.index_;
512*795d594fSAndroid Build Coastguard Worker if (compare == 0) {
513*795d594fSAndroid Build Coastguard Worker DexFileParameterIterator it(*this, proto);
514*795d594fSAndroid Build Coastguard Worker size_t i = 0;
515*795d594fSAndroid Build Coastguard Worker while (it.HasNext() && i < signature_length && compare == 0) {
516*795d594fSAndroid Build Coastguard Worker compare = signature_type_idxs[i].index_ - it.GetTypeIdx().index_;
517*795d594fSAndroid Build Coastguard Worker it.Next();
518*795d594fSAndroid Build Coastguard Worker i++;
519*795d594fSAndroid Build Coastguard Worker }
520*795d594fSAndroid Build Coastguard Worker if (compare == 0) {
521*795d594fSAndroid Build Coastguard Worker if (it.HasNext()) {
522*795d594fSAndroid Build Coastguard Worker compare = -1;
523*795d594fSAndroid Build Coastguard Worker } else if (i < signature_length) {
524*795d594fSAndroid Build Coastguard Worker compare = 1;
525*795d594fSAndroid Build Coastguard Worker }
526*795d594fSAndroid Build Coastguard Worker }
527*795d594fSAndroid Build Coastguard Worker }
528*795d594fSAndroid Build Coastguard Worker if (compare > 0) {
529*795d594fSAndroid Build Coastguard Worker lo = mid + 1;
530*795d594fSAndroid Build Coastguard Worker } else if (compare < 0) {
531*795d594fSAndroid Build Coastguard Worker hi = mid - 1;
532*795d594fSAndroid Build Coastguard Worker } else {
533*795d594fSAndroid Build Coastguard Worker return &proto;
534*795d594fSAndroid Build Coastguard Worker }
535*795d594fSAndroid Build Coastguard Worker }
536*795d594fSAndroid Build Coastguard Worker return nullptr;
537*795d594fSAndroid Build Coastguard Worker }
538*795d594fSAndroid Build Coastguard Worker
539*795d594fSAndroid Build Coastguard Worker // Given a signature place the type ids into the given vector
CreateTypeList(std::string_view signature,dex::TypeIndex * return_type_idx,std::vector<dex::TypeIndex> * param_type_idxs) const540*795d594fSAndroid Build Coastguard Worker bool DexFile::CreateTypeList(std::string_view signature,
541*795d594fSAndroid Build Coastguard Worker dex::TypeIndex* return_type_idx,
542*795d594fSAndroid Build Coastguard Worker std::vector<dex::TypeIndex>* param_type_idxs) const {
543*795d594fSAndroid Build Coastguard Worker if (signature[0] != '(') {
544*795d594fSAndroid Build Coastguard Worker return false;
545*795d594fSAndroid Build Coastguard Worker }
546*795d594fSAndroid Build Coastguard Worker size_t offset = 1;
547*795d594fSAndroid Build Coastguard Worker size_t end = signature.size();
548*795d594fSAndroid Build Coastguard Worker bool process_return = false;
549*795d594fSAndroid Build Coastguard Worker while (offset < end) {
550*795d594fSAndroid Build Coastguard Worker size_t start_offset = offset;
551*795d594fSAndroid Build Coastguard Worker char c = signature[offset];
552*795d594fSAndroid Build Coastguard Worker offset++;
553*795d594fSAndroid Build Coastguard Worker if (c == ')') {
554*795d594fSAndroid Build Coastguard Worker process_return = true;
555*795d594fSAndroid Build Coastguard Worker continue;
556*795d594fSAndroid Build Coastguard Worker }
557*795d594fSAndroid Build Coastguard Worker while (c == '[') { // process array prefix
558*795d594fSAndroid Build Coastguard Worker if (offset >= end) { // expect some descriptor following [
559*795d594fSAndroid Build Coastguard Worker return false;
560*795d594fSAndroid Build Coastguard Worker }
561*795d594fSAndroid Build Coastguard Worker c = signature[offset];
562*795d594fSAndroid Build Coastguard Worker offset++;
563*795d594fSAndroid Build Coastguard Worker }
564*795d594fSAndroid Build Coastguard Worker if (c == 'L') { // process type descriptors
565*795d594fSAndroid Build Coastguard Worker do {
566*795d594fSAndroid Build Coastguard Worker if (offset >= end) { // unexpected early termination of descriptor
567*795d594fSAndroid Build Coastguard Worker return false;
568*795d594fSAndroid Build Coastguard Worker }
569*795d594fSAndroid Build Coastguard Worker c = signature[offset];
570*795d594fSAndroid Build Coastguard Worker offset++;
571*795d594fSAndroid Build Coastguard Worker } while (c != ';');
572*795d594fSAndroid Build Coastguard Worker }
573*795d594fSAndroid Build Coastguard Worker std::string_view descriptor(signature.data() + start_offset, offset - start_offset);
574*795d594fSAndroid Build Coastguard Worker const TypeId* type_id = FindTypeId(descriptor);
575*795d594fSAndroid Build Coastguard Worker if (type_id == nullptr) {
576*795d594fSAndroid Build Coastguard Worker return false;
577*795d594fSAndroid Build Coastguard Worker }
578*795d594fSAndroid Build Coastguard Worker dex::TypeIndex type_idx = GetIndexForTypeId(*type_id);
579*795d594fSAndroid Build Coastguard Worker if (!process_return) {
580*795d594fSAndroid Build Coastguard Worker param_type_idxs->push_back(type_idx);
581*795d594fSAndroid Build Coastguard Worker } else {
582*795d594fSAndroid Build Coastguard Worker *return_type_idx = type_idx;
583*795d594fSAndroid Build Coastguard Worker return offset == end; // return true if the signature had reached a sensible end
584*795d594fSAndroid Build Coastguard Worker }
585*795d594fSAndroid Build Coastguard Worker }
586*795d594fSAndroid Build Coastguard Worker return false; // failed to correctly parse return type
587*795d594fSAndroid Build Coastguard Worker }
588*795d594fSAndroid Build Coastguard Worker
FindTryItem(const TryItem * try_items,uint32_t tries_size,uint32_t address)589*795d594fSAndroid Build Coastguard Worker int32_t DexFile::FindTryItem(const TryItem* try_items, uint32_t tries_size, uint32_t address) {
590*795d594fSAndroid Build Coastguard Worker uint32_t min = 0;
591*795d594fSAndroid Build Coastguard Worker uint32_t max = tries_size;
592*795d594fSAndroid Build Coastguard Worker while (min < max) {
593*795d594fSAndroid Build Coastguard Worker const uint32_t mid = (min + max) / 2;
594*795d594fSAndroid Build Coastguard Worker
595*795d594fSAndroid Build Coastguard Worker const TryItem& ti = try_items[mid];
596*795d594fSAndroid Build Coastguard Worker const uint32_t start = ti.start_addr_;
597*795d594fSAndroid Build Coastguard Worker const uint32_t end = start + ti.insn_count_;
598*795d594fSAndroid Build Coastguard Worker
599*795d594fSAndroid Build Coastguard Worker if (address < start) {
600*795d594fSAndroid Build Coastguard Worker max = mid;
601*795d594fSAndroid Build Coastguard Worker } else if (address >= end) {
602*795d594fSAndroid Build Coastguard Worker min = mid + 1;
603*795d594fSAndroid Build Coastguard Worker } else { // We have a winner!
604*795d594fSAndroid Build Coastguard Worker return mid;
605*795d594fSAndroid Build Coastguard Worker }
606*795d594fSAndroid Build Coastguard Worker }
607*795d594fSAndroid Build Coastguard Worker // No match.
608*795d594fSAndroid Build Coastguard Worker return -1;
609*795d594fSAndroid Build Coastguard Worker }
610*795d594fSAndroid Build Coastguard Worker
611*795d594fSAndroid Build Coastguard Worker // Read a signed integer. "zwidth" is the zero-based byte count.
ReadSignedInt(const uint8_t * ptr,int zwidth)612*795d594fSAndroid Build Coastguard Worker int32_t DexFile::ReadSignedInt(const uint8_t* ptr, int zwidth) {
613*795d594fSAndroid Build Coastguard Worker int32_t val = 0;
614*795d594fSAndroid Build Coastguard Worker for (int i = zwidth; i >= 0; --i) {
615*795d594fSAndroid Build Coastguard Worker val = ((uint32_t)val >> 8) | (((int32_t)*ptr++) << 24);
616*795d594fSAndroid Build Coastguard Worker }
617*795d594fSAndroid Build Coastguard Worker val >>= (3 - zwidth) * 8;
618*795d594fSAndroid Build Coastguard Worker return val;
619*795d594fSAndroid Build Coastguard Worker }
620*795d594fSAndroid Build Coastguard Worker
621*795d594fSAndroid Build Coastguard Worker // Read an unsigned integer. "zwidth" is the zero-based byte count,
622*795d594fSAndroid Build Coastguard Worker // "fill_on_right" indicates which side we want to zero-fill from.
ReadUnsignedInt(const uint8_t * ptr,int zwidth,bool fill_on_right)623*795d594fSAndroid Build Coastguard Worker uint32_t DexFile::ReadUnsignedInt(const uint8_t* ptr, int zwidth, bool fill_on_right) {
624*795d594fSAndroid Build Coastguard Worker uint32_t val = 0;
625*795d594fSAndroid Build Coastguard Worker for (int i = zwidth; i >= 0; --i) {
626*795d594fSAndroid Build Coastguard Worker val = (val >> 8) | (((uint32_t)*ptr++) << 24);
627*795d594fSAndroid Build Coastguard Worker }
628*795d594fSAndroid Build Coastguard Worker if (!fill_on_right) {
629*795d594fSAndroid Build Coastguard Worker val >>= (3 - zwidth) * 8;
630*795d594fSAndroid Build Coastguard Worker }
631*795d594fSAndroid Build Coastguard Worker return val;
632*795d594fSAndroid Build Coastguard Worker }
633*795d594fSAndroid Build Coastguard Worker
634*795d594fSAndroid Build Coastguard Worker // Read a signed long. "zwidth" is the zero-based byte count.
ReadSignedLong(const uint8_t * ptr,int zwidth)635*795d594fSAndroid Build Coastguard Worker int64_t DexFile::ReadSignedLong(const uint8_t* ptr, int zwidth) {
636*795d594fSAndroid Build Coastguard Worker int64_t val = 0;
637*795d594fSAndroid Build Coastguard Worker for (int i = zwidth; i >= 0; --i) {
638*795d594fSAndroid Build Coastguard Worker val = ((uint64_t)val >> 8) | (((int64_t)*ptr++) << 56);
639*795d594fSAndroid Build Coastguard Worker }
640*795d594fSAndroid Build Coastguard Worker val >>= (7 - zwidth) * 8;
641*795d594fSAndroid Build Coastguard Worker return val;
642*795d594fSAndroid Build Coastguard Worker }
643*795d594fSAndroid Build Coastguard Worker
644*795d594fSAndroid Build Coastguard Worker // Read an unsigned long. "zwidth" is the zero-based byte count,
645*795d594fSAndroid Build Coastguard Worker // "fill_on_right" indicates which side we want to zero-fill from.
ReadUnsignedLong(const uint8_t * ptr,int zwidth,bool fill_on_right)646*795d594fSAndroid Build Coastguard Worker uint64_t DexFile::ReadUnsignedLong(const uint8_t* ptr, int zwidth, bool fill_on_right) {
647*795d594fSAndroid Build Coastguard Worker uint64_t val = 0;
648*795d594fSAndroid Build Coastguard Worker for (int i = zwidth; i >= 0; --i) {
649*795d594fSAndroid Build Coastguard Worker val = (val >> 8) | (((uint64_t)*ptr++) << 56);
650*795d594fSAndroid Build Coastguard Worker }
651*795d594fSAndroid Build Coastguard Worker if (!fill_on_right) {
652*795d594fSAndroid Build Coastguard Worker val >>= (7 - zwidth) * 8;
653*795d594fSAndroid Build Coastguard Worker }
654*795d594fSAndroid Build Coastguard Worker return val;
655*795d594fSAndroid Build Coastguard Worker }
656*795d594fSAndroid Build Coastguard Worker
AppendPrettyMethod(uint32_t method_idx,bool with_signature,std::string * const result) const657*795d594fSAndroid Build Coastguard Worker void DexFile::AppendPrettyMethod(uint32_t method_idx,
658*795d594fSAndroid Build Coastguard Worker bool with_signature,
659*795d594fSAndroid Build Coastguard Worker std::string* const result) const {
660*795d594fSAndroid Build Coastguard Worker if (method_idx >= NumMethodIds()) {
661*795d594fSAndroid Build Coastguard Worker android::base::StringAppendF(result, "<<invalid-method-idx-%d>>", method_idx);
662*795d594fSAndroid Build Coastguard Worker return;
663*795d594fSAndroid Build Coastguard Worker }
664*795d594fSAndroid Build Coastguard Worker const MethodId& method_id = GetMethodId(method_idx);
665*795d594fSAndroid Build Coastguard Worker const ProtoId* proto_id = with_signature ? &GetProtoId(method_id.proto_idx_) : nullptr;
666*795d594fSAndroid Build Coastguard Worker if (with_signature) {
667*795d594fSAndroid Build Coastguard Worker AppendPrettyDescriptor(GetTypeDescriptor(proto_id->return_type_idx_), result);
668*795d594fSAndroid Build Coastguard Worker result->push_back(' ');
669*795d594fSAndroid Build Coastguard Worker }
670*795d594fSAndroid Build Coastguard Worker AppendPrettyDescriptor(GetMethodDeclaringClassDescriptor(method_id), result);
671*795d594fSAndroid Build Coastguard Worker result->push_back('.');
672*795d594fSAndroid Build Coastguard Worker result->append(GetMethodName(method_id));
673*795d594fSAndroid Build Coastguard Worker if (with_signature) {
674*795d594fSAndroid Build Coastguard Worker result->push_back('(');
675*795d594fSAndroid Build Coastguard Worker const TypeList* params = GetProtoParameters(*proto_id);
676*795d594fSAndroid Build Coastguard Worker if (params != nullptr) {
677*795d594fSAndroid Build Coastguard Worker const char* separator = "";
678*795d594fSAndroid Build Coastguard Worker for (uint32_t i = 0u, size = params->Size(); i != size; ++i) {
679*795d594fSAndroid Build Coastguard Worker result->append(separator);
680*795d594fSAndroid Build Coastguard Worker separator = ", ";
681*795d594fSAndroid Build Coastguard Worker AppendPrettyDescriptor(GetTypeDescriptor(params->GetTypeItem(i).type_idx_), result);
682*795d594fSAndroid Build Coastguard Worker }
683*795d594fSAndroid Build Coastguard Worker }
684*795d594fSAndroid Build Coastguard Worker result->push_back(')');
685*795d594fSAndroid Build Coastguard Worker }
686*795d594fSAndroid Build Coastguard Worker }
687*795d594fSAndroid Build Coastguard Worker
PrettyField(uint32_t field_idx,bool with_type) const688*795d594fSAndroid Build Coastguard Worker std::string DexFile::PrettyField(uint32_t field_idx, bool with_type) const {
689*795d594fSAndroid Build Coastguard Worker if (field_idx >= NumFieldIds()) {
690*795d594fSAndroid Build Coastguard Worker return StringPrintf("<<invalid-field-idx-%d>>", field_idx);
691*795d594fSAndroid Build Coastguard Worker }
692*795d594fSAndroid Build Coastguard Worker const FieldId& field_id = GetFieldId(field_idx);
693*795d594fSAndroid Build Coastguard Worker std::string result;
694*795d594fSAndroid Build Coastguard Worker if (with_type) {
695*795d594fSAndroid Build Coastguard Worker AppendPrettyDescriptor(GetFieldTypeDescriptor(field_id), &result);
696*795d594fSAndroid Build Coastguard Worker result += ' ';
697*795d594fSAndroid Build Coastguard Worker }
698*795d594fSAndroid Build Coastguard Worker AppendPrettyDescriptor(GetFieldDeclaringClassDescriptor(field_id), &result);
699*795d594fSAndroid Build Coastguard Worker result += '.';
700*795d594fSAndroid Build Coastguard Worker result += GetFieldName(field_id);
701*795d594fSAndroid Build Coastguard Worker return result;
702*795d594fSAndroid Build Coastguard Worker }
703*795d594fSAndroid Build Coastguard Worker
PrettyType(dex::TypeIndex type_idx) const704*795d594fSAndroid Build Coastguard Worker std::string DexFile::PrettyType(dex::TypeIndex type_idx) const {
705*795d594fSAndroid Build Coastguard Worker if (type_idx.index_ >= NumTypeIds()) {
706*795d594fSAndroid Build Coastguard Worker return StringPrintf("<<invalid-type-idx-%d>>", type_idx.index_);
707*795d594fSAndroid Build Coastguard Worker }
708*795d594fSAndroid Build Coastguard Worker const TypeId& type_id = GetTypeId(type_idx);
709*795d594fSAndroid Build Coastguard Worker return PrettyDescriptor(GetTypeDescriptor(type_id));
710*795d594fSAndroid Build Coastguard Worker }
711*795d594fSAndroid Build Coastguard Worker
GetProtoIndexForCallSite(uint32_t call_site_idx) const712*795d594fSAndroid Build Coastguard Worker dex::ProtoIndex DexFile::GetProtoIndexForCallSite(uint32_t call_site_idx) const {
713*795d594fSAndroid Build Coastguard Worker const CallSiteIdItem& csi = GetCallSiteId(call_site_idx);
714*795d594fSAndroid Build Coastguard Worker CallSiteArrayValueIterator it(*this, csi);
715*795d594fSAndroid Build Coastguard Worker it.Next();
716*795d594fSAndroid Build Coastguard Worker it.Next();
717*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(EncodedArrayValueIterator::ValueType::kMethodType, it.GetValueType());
718*795d594fSAndroid Build Coastguard Worker return dex::ProtoIndex(it.GetJavaValue().i);
719*795d594fSAndroid Build Coastguard Worker }
720*795d594fSAndroid Build Coastguard Worker
721*795d594fSAndroid Build Coastguard Worker // Checks that visibility is as expected. Includes special behavior for M and
722*795d594fSAndroid Build Coastguard Worker // before to allow runtime and build visibility when expecting runtime.
operator <<(std::ostream & os,const DexFile & dex_file)723*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const DexFile& dex_file) {
724*795d594fSAndroid Build Coastguard Worker os << StringPrintf("[DexFile: %s dex-checksum=%08x location-checksum=%08x %p-%p]",
725*795d594fSAndroid Build Coastguard Worker dex_file.GetLocation().c_str(),
726*795d594fSAndroid Build Coastguard Worker dex_file.GetHeader().checksum_, dex_file.GetLocationChecksum(),
727*795d594fSAndroid Build Coastguard Worker dex_file.Begin(), dex_file.Begin() + dex_file.Size());
728*795d594fSAndroid Build Coastguard Worker return os;
729*795d594fSAndroid Build Coastguard Worker }
730*795d594fSAndroid Build Coastguard Worker
EncodedArrayValueIterator(const DexFile & dex_file,const uint8_t * array_data)731*795d594fSAndroid Build Coastguard Worker EncodedArrayValueIterator::EncodedArrayValueIterator(const DexFile& dex_file,
732*795d594fSAndroid Build Coastguard Worker const uint8_t* array_data)
733*795d594fSAndroid Build Coastguard Worker : dex_file_(dex_file),
734*795d594fSAndroid Build Coastguard Worker array_size_(),
735*795d594fSAndroid Build Coastguard Worker pos_(-1),
736*795d594fSAndroid Build Coastguard Worker ptr_(array_data),
737*795d594fSAndroid Build Coastguard Worker type_(kByte) {
738*795d594fSAndroid Build Coastguard Worker array_size_ = (ptr_ != nullptr) ? DecodeUnsignedLeb128(&ptr_) : 0;
739*795d594fSAndroid Build Coastguard Worker if (array_size_ > 0) {
740*795d594fSAndroid Build Coastguard Worker bool ok [[maybe_unused]] = MaybeNext();
741*795d594fSAndroid Build Coastguard Worker }
742*795d594fSAndroid Build Coastguard Worker }
743*795d594fSAndroid Build Coastguard Worker
MaybeNext()744*795d594fSAndroid Build Coastguard Worker bool EncodedArrayValueIterator::MaybeNext() {
745*795d594fSAndroid Build Coastguard Worker pos_++;
746*795d594fSAndroid Build Coastguard Worker if (pos_ >= array_size_) {
747*795d594fSAndroid Build Coastguard Worker type_ = kEndOfInput;
748*795d594fSAndroid Build Coastguard Worker return true;
749*795d594fSAndroid Build Coastguard Worker }
750*795d594fSAndroid Build Coastguard Worker uint8_t value_type = *ptr_++;
751*795d594fSAndroid Build Coastguard Worker uint8_t value_arg = value_type >> kEncodedValueArgShift;
752*795d594fSAndroid Build Coastguard Worker size_t width = value_arg + 1; // assume and correct later
753*795d594fSAndroid Build Coastguard Worker type_ = static_cast<ValueType>(value_type & kEncodedValueTypeMask);
754*795d594fSAndroid Build Coastguard Worker switch (type_) {
755*795d594fSAndroid Build Coastguard Worker case kBoolean:
756*795d594fSAndroid Build Coastguard Worker jval_.i = (value_arg != 0) ? 1 : 0;
757*795d594fSAndroid Build Coastguard Worker width = 0;
758*795d594fSAndroid Build Coastguard Worker break;
759*795d594fSAndroid Build Coastguard Worker case kByte:
760*795d594fSAndroid Build Coastguard Worker jval_.i = DexFile::ReadSignedInt(ptr_, value_arg);
761*795d594fSAndroid Build Coastguard Worker CHECK(IsInt<8>(jval_.i));
762*795d594fSAndroid Build Coastguard Worker break;
763*795d594fSAndroid Build Coastguard Worker case kShort:
764*795d594fSAndroid Build Coastguard Worker jval_.i = DexFile::ReadSignedInt(ptr_, value_arg);
765*795d594fSAndroid Build Coastguard Worker CHECK(IsInt<16>(jval_.i));
766*795d594fSAndroid Build Coastguard Worker break;
767*795d594fSAndroid Build Coastguard Worker case kChar:
768*795d594fSAndroid Build Coastguard Worker jval_.i = DexFile::ReadUnsignedInt(ptr_, value_arg, false);
769*795d594fSAndroid Build Coastguard Worker CHECK(IsUint<16>(jval_.i));
770*795d594fSAndroid Build Coastguard Worker break;
771*795d594fSAndroid Build Coastguard Worker case kInt:
772*795d594fSAndroid Build Coastguard Worker jval_.i = DexFile::ReadSignedInt(ptr_, value_arg);
773*795d594fSAndroid Build Coastguard Worker break;
774*795d594fSAndroid Build Coastguard Worker case kLong:
775*795d594fSAndroid Build Coastguard Worker jval_.j = DexFile::ReadSignedLong(ptr_, value_arg);
776*795d594fSAndroid Build Coastguard Worker break;
777*795d594fSAndroid Build Coastguard Worker case kFloat:
778*795d594fSAndroid Build Coastguard Worker jval_.i = DexFile::ReadUnsignedInt(ptr_, value_arg, true);
779*795d594fSAndroid Build Coastguard Worker break;
780*795d594fSAndroid Build Coastguard Worker case kDouble:
781*795d594fSAndroid Build Coastguard Worker jval_.j = DexFile::ReadUnsignedLong(ptr_, value_arg, true);
782*795d594fSAndroid Build Coastguard Worker break;
783*795d594fSAndroid Build Coastguard Worker case kString:
784*795d594fSAndroid Build Coastguard Worker case kType:
785*795d594fSAndroid Build Coastguard Worker case kMethodType:
786*795d594fSAndroid Build Coastguard Worker case kMethodHandle:
787*795d594fSAndroid Build Coastguard Worker jval_.i = DexFile::ReadUnsignedInt(ptr_, value_arg, false);
788*795d594fSAndroid Build Coastguard Worker break;
789*795d594fSAndroid Build Coastguard Worker case kField:
790*795d594fSAndroid Build Coastguard Worker case kMethod:
791*795d594fSAndroid Build Coastguard Worker case kEnum:
792*795d594fSAndroid Build Coastguard Worker case kArray:
793*795d594fSAndroid Build Coastguard Worker case kAnnotation:
794*795d594fSAndroid Build Coastguard Worker return false;
795*795d594fSAndroid Build Coastguard Worker case kNull:
796*795d594fSAndroid Build Coastguard Worker jval_.l = nullptr;
797*795d594fSAndroid Build Coastguard Worker width = 0;
798*795d594fSAndroid Build Coastguard Worker break;
799*795d594fSAndroid Build Coastguard Worker default:
800*795d594fSAndroid Build Coastguard Worker return false;
801*795d594fSAndroid Build Coastguard Worker }
802*795d594fSAndroid Build Coastguard Worker ptr_ += width;
803*795d594fSAndroid Build Coastguard Worker return true;
804*795d594fSAndroid Build Coastguard Worker }
805*795d594fSAndroid Build Coastguard Worker
806*795d594fSAndroid Build Coastguard Worker namespace dex {
807*795d594fSAndroid Build Coastguard Worker
operator <<(std::ostream & os,const ProtoIndex & index)808*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const ProtoIndex& index) {
809*795d594fSAndroid Build Coastguard Worker os << "ProtoIndex[" << index.index_ << "]";
810*795d594fSAndroid Build Coastguard Worker return os;
811*795d594fSAndroid Build Coastguard Worker }
812*795d594fSAndroid Build Coastguard Worker
operator <<(std::ostream & os,const StringIndex & index)813*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const StringIndex& index) {
814*795d594fSAndroid Build Coastguard Worker os << "StringIndex[" << index.index_ << "]";
815*795d594fSAndroid Build Coastguard Worker return os;
816*795d594fSAndroid Build Coastguard Worker }
817*795d594fSAndroid Build Coastguard Worker
operator <<(std::ostream & os,const TypeIndex & index)818*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const TypeIndex& index) {
819*795d594fSAndroid Build Coastguard Worker os << "TypeIndex[" << index.index_ << "]";
820*795d594fSAndroid Build Coastguard Worker return os;
821*795d594fSAndroid Build Coastguard Worker }
822*795d594fSAndroid Build Coastguard Worker
823*795d594fSAndroid Build Coastguard Worker } // namespace dex
824*795d594fSAndroid Build Coastguard Worker
825*795d594fSAndroid Build Coastguard Worker } // namespace art
826