1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "resolver.h"
18
19 #include "dex/dex_file-inl.h"
20 #include "dex/primitive.h"
21 #include "hidden_api.h"
22 #include "veridex.h"
23
24 namespace art {
25
Run()26 void VeridexResolver::Run() {
27 size_t class_def_count = dex_file_.NumClassDefs();
28 for (size_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) {
29 const DexFile::ClassDef& class_def = dex_file_.GetClassDef(class_def_index);
30 std::string name(dex_file_.StringByTypeIdx(class_def.class_idx_));
31 auto existing = type_map_.find(name);
32 if (existing != type_map_.end()) {
33 // Class already exists, cache it and move on.
34 type_infos_[class_def.class_idx_.index_] = *existing->second;
35 continue;
36 }
37 type_infos_[class_def.class_idx_.index_] = VeriClass(Primitive::Type::kPrimNot, 0, &class_def);
38 type_map_[name] = &(type_infos_[class_def.class_idx_.index_]);
39
40 const uint8_t* class_data = dex_file_.GetClassData(class_def);
41 if (class_data == nullptr) {
42 // Empty class.
43 continue;
44 }
45
46 ClassDataItemIterator it(dex_file_, class_data);
47 for (; it.HasNextStaticField(); it.Next()) {
48 field_infos_[it.GetMemberIndex()] = it.DataPointer();
49 }
50 for (; it.HasNextInstanceField(); it.Next()) {
51 field_infos_[it.GetMemberIndex()] = it.DataPointer();
52 }
53 for (; it.HasNextMethod(); it.Next()) {
54 method_infos_[it.GetMemberIndex()] = it.DataPointer();
55 }
56 }
57 }
58
HasSameNameAndSignature(const DexFile & dex_file,const DexFile::MethodId & method_id,const char * method_name,const char * type)59 static bool HasSameNameAndSignature(const DexFile& dex_file,
60 const DexFile::MethodId& method_id,
61 const char* method_name,
62 const char* type) {
63 return strcmp(method_name, dex_file.GetMethodName(method_id)) == 0 &&
64 strcmp(type, dex_file.GetMethodSignature(method_id).ToString().c_str()) == 0;
65 }
66
HasSameNameAndSignature(const DexFile & dex_file,const DexFile::MethodId & method_id,const char * method_name,const Signature & signature)67 static bool HasSameNameAndSignature(const DexFile& dex_file,
68 const DexFile::MethodId& method_id,
69 const char* method_name,
70 const Signature& signature) {
71 return strcmp(method_name, dex_file.GetMethodName(method_id)) == 0 &&
72 dex_file.GetMethodSignature(method_id) == signature;
73 }
74
HasSameNameAndType(const DexFile & dex_file,const DexFile::FieldId & field_id,const char * field_name,const char * field_type)75 static bool HasSameNameAndType(const DexFile& dex_file,
76 const DexFile::FieldId& field_id,
77 const char* field_name,
78 const char* field_type) {
79 return strcmp(field_name, dex_file.GetFieldName(field_id)) == 0 &&
80 strcmp(field_type, dex_file.GetFieldTypeDescriptor(field_id)) == 0;
81 }
82
GetVeriClass(dex::TypeIndex index)83 VeriClass* VeridexResolver::GetVeriClass(dex::TypeIndex index) {
84 CHECK_LT(index.index_, dex_file_.NumTypeIds());
85 // Lookup in our local cache.
86 VeriClass* cls = &type_infos_[index.index_];
87 if (cls->IsUninitialized()) {
88 // Class is defined in another dex file. Lookup in the global cache.
89 std::string name(dex_file_.StringByTypeIdx(index));
90 auto existing = type_map_.find(name);
91 if (existing == type_map_.end()) {
92 // Class hasn't been defined, so check if it's an array class.
93 size_t last_array = name.find_last_of('[');
94 if (last_array == std::string::npos) {
95 // There is no such class.
96 return nullptr;
97 } else {
98 // Class is an array class. Check if its most enclosed component type (which is not
99 // an array class) has been defined.
100 std::string klass_name = name.substr(last_array + 1);
101 existing = type_map_.find(klass_name);
102 if (existing == type_map_.end()) {
103 // There is no such class, so there is no such array.
104 return nullptr;
105 } else {
106 // Create the type, and cache it locally and globally.
107 type_infos_[index.index_] = VeriClass(
108 existing->second->GetKind(), last_array + 1, existing->second->GetClassDef());
109 cls = &(type_infos_[index.index_]);
110 type_map_[name] = cls;
111 }
112 }
113 } else {
114 // Cache the found class.
115 cls = existing->second;
116 type_infos_[index.index_] = *cls;
117 }
118 }
119 return cls;
120 }
121
GetResolverOf(const VeriClass & kls) const122 VeridexResolver* VeridexResolver::GetResolverOf(const VeriClass& kls) const {
123 auto resolver_it = dex_resolvers_.lower_bound(reinterpret_cast<uintptr_t>(kls.GetClassDef()));
124 --resolver_it;
125
126 // Check the class def pointer is indeed in the mapped dex file range.
127 const DexFile& dex_file = resolver_it->second->dex_file_;
128 CHECK_LT(reinterpret_cast<uintptr_t>(dex_file.Begin()),
129 reinterpret_cast<uintptr_t>(kls.GetClassDef()));
130 CHECK_GT(reinterpret_cast<uintptr_t>(dex_file.Begin()) + dex_file.Size(),
131 reinterpret_cast<uintptr_t>(kls.GetClassDef()));
132 return resolver_it->second;
133 }
134
LookupMethodIn(const VeriClass & kls,const char * method_name,const Signature & method_signature)135 VeriMethod VeridexResolver::LookupMethodIn(const VeriClass& kls,
136 const char* method_name,
137 const Signature& method_signature) {
138 if (kls.IsPrimitive()) {
139 // Primitive classes don't have methods.
140 return nullptr;
141 }
142 if (kls.IsArray()) {
143 // Array classes don't have methods, but inherit the ones in j.l.Object.
144 return LookupMethodIn(*VeriClass::object_, method_name, method_signature);
145 }
146 // Get the resolver where `kls` is from.
147 VeridexResolver* resolver = GetResolverOf(kls);
148
149 // Look at methods declared in `kls`.
150 const DexFile& other_dex_file = resolver->dex_file_;
151 const uint8_t* class_data = other_dex_file.GetClassData(*kls.GetClassDef());
152 if (class_data != nullptr) {
153 ClassDataItemIterator it(other_dex_file, class_data);
154 it.SkipAllFields();
155 for (; it.HasNextMethod(); it.Next()) {
156 const DexFile::MethodId& other_method_id = other_dex_file.GetMethodId(it.GetMemberIndex());
157 if (HasSameNameAndSignature(other_dex_file,
158 other_method_id,
159 method_name,
160 method_signature)) {
161 return it.DataPointer();
162 }
163 }
164 }
165
166 // Look at methods in `kls`'s super class hierarchy.
167 if (kls.GetClassDef()->superclass_idx_.IsValid()) {
168 VeriClass* super = resolver->GetVeriClass(kls.GetClassDef()->superclass_idx_);
169 if (super != nullptr) {
170 VeriMethod super_method = resolver->LookupMethodIn(*super, method_name, method_signature);
171 if (super_method != nullptr) {
172 return super_method;
173 }
174 }
175 }
176
177 // Look at methods in `kls`'s interface hierarchy.
178 const DexFile::TypeList* interfaces = other_dex_file.GetInterfacesList(*kls.GetClassDef());
179 if (interfaces != nullptr) {
180 for (size_t i = 0; i < interfaces->Size(); i++) {
181 dex::TypeIndex idx = interfaces->GetTypeItem(i).type_idx_;
182 VeriClass* itf = resolver->GetVeriClass(idx);
183 if (itf != nullptr) {
184 VeriMethod itf_method = resolver->LookupMethodIn(*itf, method_name, method_signature);
185 if (itf_method != nullptr) {
186 return itf_method;
187 }
188 }
189 }
190 }
191 return nullptr;
192 }
193
LookupFieldIn(const VeriClass & kls,const char * field_name,const char * field_type)194 VeriField VeridexResolver::LookupFieldIn(const VeriClass& kls,
195 const char* field_name,
196 const char* field_type) {
197 if (kls.IsPrimitive()) {
198 // Primitive classes don't have fields.
199 return nullptr;
200 }
201 if (kls.IsArray()) {
202 // Array classes don't have fields.
203 return nullptr;
204 }
205 // Get the resolver where `kls` is from.
206 VeridexResolver* resolver = GetResolverOf(kls);
207
208 // Look at fields declared in `kls`.
209 const DexFile& other_dex_file = resolver->dex_file_;
210 const uint8_t* class_data = other_dex_file.GetClassData(*kls.GetClassDef());
211 if (class_data != nullptr) {
212 ClassDataItemIterator it(other_dex_file, class_data);
213 for (; it.HasNextStaticField() || it.HasNextInstanceField(); it.Next()) {
214 const DexFile::FieldId& other_field_id = other_dex_file.GetFieldId(it.GetMemberIndex());
215 if (HasSameNameAndType(other_dex_file,
216 other_field_id,
217 field_name,
218 field_type)) {
219 return it.DataPointer();
220 }
221 }
222 }
223
224 // Look at fields in `kls`'s interface hierarchy.
225 const DexFile::TypeList* interfaces = other_dex_file.GetInterfacesList(*kls.GetClassDef());
226 if (interfaces != nullptr) {
227 for (size_t i = 0; i < interfaces->Size(); i++) {
228 dex::TypeIndex idx = interfaces->GetTypeItem(i).type_idx_;
229 VeriClass* itf = resolver->GetVeriClass(idx);
230 if (itf != nullptr) {
231 VeriField itf_field = resolver->LookupFieldIn(*itf, field_name, field_type);
232 if (itf_field != nullptr) {
233 return itf_field;
234 }
235 }
236 }
237 }
238
239 // Look at fields in `kls`'s super class hierarchy.
240 if (kls.GetClassDef()->superclass_idx_.IsValid()) {
241 VeriClass* super = resolver->GetVeriClass(kls.GetClassDef()->superclass_idx_);
242 if (super != nullptr) {
243 VeriField super_field = resolver->LookupFieldIn(*super, field_name, field_type);
244 if (super_field != nullptr) {
245 return super_field;
246 }
247 }
248 }
249 return nullptr;
250 }
251
LookupDeclaredMethodIn(const VeriClass & kls,const char * method_name,const char * type) const252 VeriMethod VeridexResolver::LookupDeclaredMethodIn(const VeriClass& kls,
253 const char* method_name,
254 const char* type) const {
255 if (kls.IsPrimitive()) {
256 return nullptr;
257 }
258 if (kls.IsArray()) {
259 return nullptr;
260 }
261 VeridexResolver* resolver = GetResolverOf(kls);
262 const DexFile& other_dex_file = resolver->dex_file_;
263 const uint8_t* class_data = other_dex_file.GetClassData(*kls.GetClassDef());
264 if (class_data != nullptr) {
265 ClassDataItemIterator it(other_dex_file, class_data);
266 it.SkipAllFields();
267 for (; it.HasNextMethod(); it.Next()) {
268 const DexFile::MethodId& other_method_id = other_dex_file.GetMethodId(it.GetMemberIndex());
269 if (HasSameNameAndSignature(other_dex_file,
270 other_method_id,
271 method_name,
272 type)) {
273 return it.DataPointer();
274 }
275 }
276 }
277 return nullptr;
278 }
279
GetMethod(uint32_t method_index)280 VeriMethod VeridexResolver::GetMethod(uint32_t method_index) {
281 VeriMethod method_info = method_infos_[method_index];
282 if (method_info == nullptr) {
283 // Method is defined in another dex file.
284 const DexFile::MethodId& method_id = dex_file_.GetMethodId(method_index);
285 VeriClass* kls = GetVeriClass(method_id.class_idx_);
286 if (kls == nullptr) {
287 return nullptr;
288 }
289 // Class found, now lookup the method in it.
290 method_info = LookupMethodIn(*kls,
291 dex_file_.GetMethodName(method_id),
292 dex_file_.GetMethodSignature(method_id));
293 method_infos_[method_index] = method_info;
294 }
295 return method_info;
296 }
297
GetField(uint32_t field_index)298 VeriField VeridexResolver::GetField(uint32_t field_index) {
299 VeriField field_info = field_infos_[field_index];
300 if (field_info == nullptr) {
301 // Field is defined in another dex file.
302 const DexFile::FieldId& field_id = dex_file_.GetFieldId(field_index);
303 VeriClass* kls = GetVeriClass(field_id.class_idx_);
304 if (kls == nullptr) {
305 return nullptr;
306 }
307 // Class found, now lookup the field in it.
308 field_info = LookupFieldIn(*kls,
309 dex_file_.GetFieldName(field_id),
310 dex_file_.GetFieldTypeDescriptor(field_id));
311 field_infos_[field_index] = field_info;
312 }
313 return field_info;
314 }
315
ResolveAll()316 void VeridexResolver::ResolveAll() {
317 for (uint32_t i = 0; i < dex_file_.NumTypeIds(); ++i) {
318 if (GetVeriClass(dex::TypeIndex(i)) == nullptr) {
319 LOG(WARNING) << "Unresolved " << dex_file_.PrettyType(dex::TypeIndex(i));
320 }
321 }
322
323 for (uint32_t i = 0; i < dex_file_.NumMethodIds(); ++i) {
324 if (GetMethod(i) == nullptr) {
325 LOG(WARNING) << "Unresolved: " << dex_file_.PrettyMethod(i);
326 }
327 }
328
329 for (uint32_t i = 0; i < dex_file_.NumFieldIds(); ++i) {
330 if (GetField(i) == nullptr) {
331 LOG(WARNING) << "Unresolved: " << dex_file_.PrettyField(i);
332 }
333 }
334 }
335
336 } // namespace art
337