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