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/class_accessor-inl.h"
20 #include "dex/dex_file-inl.h"
21 #include "dex/primitive.h"
22 #include "dex/signature-inl.h"
23 #include "hidden_api.h"
24 #include "veridex.h"
25 
26 namespace art {
27 
Run()28 void VeridexResolver::Run() {
29   for (ClassAccessor accessor : dex_file_.GetClasses()) {
30     std::string name(accessor.GetDescriptor());
31     auto existing = type_map_.find(name);
32     const uint32_t type_idx = accessor.GetClassIdx().index_;
33     if (existing != type_map_.end()) {
34       // Class already exists, cache it and move on.
35       type_infos_[type_idx] = *existing->second;
36       continue;
37     }
38     type_infos_[type_idx] = VeriClass(Primitive::Type::kPrimNot, 0, &accessor.GetClassDef());
39     type_map_[name] = &type_infos_[type_idx];
40     for (const ClassAccessor::Field& field : accessor.GetFields()) {
41       field_infos_[field.GetIndex()] = field.GetDataPointer();
42     }
43     for (const ClassAccessor::Method& method : accessor.GetMethods()) {
44       method_infos_[method.GetIndex()] = method.GetDataPointer();
45     }
46   }
47 }
48 
HasSameNameAndSignature(const DexFile & dex_file,const dex::MethodId & method_id,const char * method_name,const char * type)49 static bool HasSameNameAndSignature(const DexFile& dex_file,
50                                     const dex::MethodId& method_id,
51                                     const char* method_name,
52                                     const char* type) {
53   return strcmp(method_name, dex_file.GetMethodName(method_id)) == 0 &&
54       strcmp(type, dex_file.GetMethodSignature(method_id).ToString().c_str()) == 0;
55 }
56 
HasSameNameAndSignature(const DexFile & dex_file,const dex::MethodId & method_id,const char * method_name,const Signature & signature)57 static bool HasSameNameAndSignature(const DexFile& dex_file,
58                                     const dex::MethodId& method_id,
59                                     const char* method_name,
60                                     const Signature& signature) {
61   return strcmp(method_name, dex_file.GetMethodName(method_id)) == 0 &&
62       dex_file.GetMethodSignature(method_id) == signature;
63 }
64 
HasSameNameAndType(const DexFile & dex_file,const dex::FieldId & field_id,const char * field_name,const char * field_type)65 static bool HasSameNameAndType(const DexFile& dex_file,
66                                const dex::FieldId& field_id,
67                                const char* field_name,
68                                const char* field_type) {
69   return strcmp(field_name, dex_file.GetFieldName(field_id)) == 0 &&
70       strcmp(field_type, dex_file.GetFieldTypeDescriptor(field_id)) == 0;
71 }
72 
GetVeriClass(dex::TypeIndex index)73 VeriClass* VeridexResolver::GetVeriClass(dex::TypeIndex index) {
74   CHECK_LT(index.index_, dex_file_.NumTypeIds());
75   // Lookup in our local cache.
76   VeriClass* cls = &type_infos_[index.index_];
77   if (cls->IsUninitialized()) {
78     // Class is defined in another dex file. Lookup in the global cache.
79     std::string name(dex_file_.StringByTypeIdx(index));
80     auto existing = type_map_.find(name);
81     if (existing == type_map_.end()) {
82       // Class hasn't been defined, so check if it's an array class.
83       size_t last_array = name.find_last_of('[');
84       if (last_array == std::string::npos) {
85         // There is no such class.
86         return nullptr;
87       } else {
88         // Class is an array class. Check if its most enclosed component type (which is not
89         // an array class) has been defined.
90         std::string klass_name = name.substr(last_array + 1);
91         existing = type_map_.find(klass_name);
92         if (existing == type_map_.end()) {
93           // There is no such class, so there is no such array.
94           return nullptr;
95         } else {
96           // Create the type, and cache it locally and globally.
97           type_infos_[index.index_] = VeriClass(
98               existing->second->GetKind(), last_array + 1, existing->second->GetClassDef());
99           cls = &(type_infos_[index.index_]);
100           type_map_[name] = cls;
101         }
102       }
103     } else {
104       // Cache the found class.
105       cls = existing->second;
106       type_infos_[index.index_] = *cls;
107     }
108   }
109   return cls;
110 }
111 
GetResolverOf(const VeriClass & kls) const112 VeridexResolver* VeridexResolver::GetResolverOf(const VeriClass& kls) const {
113   auto resolver_it = dex_resolvers_.lower_bound(reinterpret_cast<uintptr_t>(kls.GetClassDef()));
114   --resolver_it;
115 
116   // Check the class def pointer is indeed in the mapped dex file range.
117   const DexFile& dex_file = resolver_it->second->dex_file_;
118   CHECK_LT(reinterpret_cast<uintptr_t>(dex_file.Begin()),
119            reinterpret_cast<uintptr_t>(kls.GetClassDef()));
120   CHECK_GT(reinterpret_cast<uintptr_t>(dex_file.Begin()) + dex_file.Size(),
121            reinterpret_cast<uintptr_t>(kls.GetClassDef()));
122   return resolver_it->second;
123 }
124 
LookupMethodIn(const VeriClass & kls,const char * method_name,const Signature & method_signature)125 VeriMethod VeridexResolver::LookupMethodIn(const VeriClass& kls,
126                                            const char* method_name,
127                                            const Signature& method_signature) {
128   if (kls.IsPrimitive()) {
129     // Primitive classes don't have methods.
130     return nullptr;
131   }
132   if (kls.IsArray()) {
133     // Array classes don't have methods, but inherit the ones in j.l.Object.
134     return LookupMethodIn(*VeriClass::object_, method_name, method_signature);
135   }
136   // Get the resolver where `kls` is from.
137   VeridexResolver* resolver = GetResolverOf(kls);
138 
139   // Look at methods declared in `kls`.
140   const DexFile& other_dex_file = resolver->dex_file_;
141   ClassAccessor other_dex_accessor(other_dex_file, *kls.GetClassDef());
142   for (const ClassAccessor::Method& method : other_dex_accessor.GetMethods()) {
143     const dex::MethodId& other_method_id = other_dex_file.GetMethodId(method.GetIndex());
144     if (HasSameNameAndSignature(other_dex_file,
145                                 other_method_id,
146                                 method_name,
147                                 method_signature)) {
148       return method.GetDataPointer();
149     }
150   }
151 
152   // Look at methods in `kls`'s super class hierarchy.
153   if (kls.GetClassDef()->superclass_idx_.IsValid()) {
154     VeriClass* super = resolver->GetVeriClass(kls.GetClassDef()->superclass_idx_);
155     if (super != nullptr) {
156       VeriMethod super_method = resolver->LookupMethodIn(*super, method_name, method_signature);
157       if (super_method != nullptr) {
158         return super_method;
159       }
160     }
161   }
162 
163   // Look at methods in `kls`'s interface hierarchy.
164   const dex::TypeList* interfaces = other_dex_file.GetInterfacesList(*kls.GetClassDef());
165   if (interfaces != nullptr) {
166     for (size_t i = 0; i < interfaces->Size(); i++) {
167       dex::TypeIndex idx = interfaces->GetTypeItem(i).type_idx_;
168       VeriClass* itf = resolver->GetVeriClass(idx);
169       if (itf != nullptr) {
170         VeriMethod itf_method = resolver->LookupMethodIn(*itf, method_name, method_signature);
171         if (itf_method != nullptr) {
172           return itf_method;
173         }
174       }
175     }
176   }
177   return nullptr;
178 }
179 
LookupFieldIn(const VeriClass & kls,const char * field_name,const char * field_type)180 VeriField VeridexResolver::LookupFieldIn(const VeriClass& kls,
181                                          const char* field_name,
182                                          const char* field_type) {
183   if (kls.IsPrimitive()) {
184     // Primitive classes don't have fields.
185     return nullptr;
186   }
187   if (kls.IsArray()) {
188     // Array classes don't have fields.
189     return nullptr;
190   }
191   // Get the resolver where `kls` is from.
192   VeridexResolver* resolver = GetResolverOf(kls);
193 
194   // Look at fields declared in `kls`.
195   const DexFile& other_dex_file = resolver->dex_file_;
196   ClassAccessor other_dex_accessor(other_dex_file, *kls.GetClassDef());
197   for (const ClassAccessor::Field& field : other_dex_accessor.GetFields()) {
198     const dex::FieldId& other_field_id = other_dex_file.GetFieldId(field.GetIndex());
199     if (HasSameNameAndType(other_dex_file,
200                            other_field_id,
201                            field_name,
202                            field_type)) {
203       return field.GetDataPointer();
204     }
205   }
206 
207   // Look at fields in `kls`'s interface hierarchy.
208   const dex::TypeList* interfaces = other_dex_file.GetInterfacesList(*kls.GetClassDef());
209   if (interfaces != nullptr) {
210     for (size_t i = 0; i < interfaces->Size(); i++) {
211       dex::TypeIndex idx = interfaces->GetTypeItem(i).type_idx_;
212       VeriClass* itf = resolver->GetVeriClass(idx);
213       if (itf != nullptr) {
214         VeriField itf_field = resolver->LookupFieldIn(*itf, field_name, field_type);
215         if (itf_field != nullptr) {
216           return itf_field;
217         }
218       }
219     }
220   }
221 
222   // Look at fields in `kls`'s super class hierarchy.
223   if (kls.GetClassDef()->superclass_idx_.IsValid()) {
224     VeriClass* super = resolver->GetVeriClass(kls.GetClassDef()->superclass_idx_);
225     if (super != nullptr) {
226       VeriField super_field = resolver->LookupFieldIn(*super, field_name, field_type);
227       if (super_field != nullptr) {
228         return super_field;
229       }
230     }
231   }
232   return nullptr;
233 }
234 
LookupDeclaredMethodIn(const VeriClass & kls,const char * method_name,const char * type) const235 VeriMethod VeridexResolver::LookupDeclaredMethodIn(const VeriClass& kls,
236                                                    const char* method_name,
237                                                    const char* type) const {
238   if (kls.IsPrimitive()) {
239     return nullptr;
240   }
241   if (kls.IsArray()) {
242     return nullptr;
243   }
244   VeridexResolver* resolver = GetResolverOf(kls);
245   const DexFile& other_dex_file = resolver->dex_file_;
246   ClassAccessor other_dex_accessor(other_dex_file, *kls.GetClassDef());
247   for (const ClassAccessor::Method& method : other_dex_accessor.GetMethods()) {
248     if (HasSameNameAndSignature(other_dex_file,
249                                 other_dex_file.GetMethodId(method.GetIndex()),
250                                 method_name,
251                                 type)) {
252       return method.GetDataPointer();
253     }
254   }
255   return nullptr;
256 }
257 
GetMethod(uint32_t method_index)258 VeriMethod VeridexResolver::GetMethod(uint32_t method_index) {
259   VeriMethod method_info = method_infos_[method_index];
260   if (method_info == nullptr) {
261     // Method is defined in another dex file.
262     const dex::MethodId& method_id = dex_file_.GetMethodId(method_index);
263     VeriClass* kls = GetVeriClass(method_id.class_idx_);
264     if (kls == nullptr) {
265       return nullptr;
266     }
267     // Class found, now lookup the method in it.
268     method_info = LookupMethodIn(*kls,
269                                  dex_file_.GetMethodName(method_id),
270                                  dex_file_.GetMethodSignature(method_id));
271     method_infos_[method_index] = method_info;
272   }
273   return method_info;
274 }
275 
GetField(uint32_t field_index)276 VeriField VeridexResolver::GetField(uint32_t field_index) {
277   VeriField field_info = field_infos_[field_index];
278   if (field_info == nullptr) {
279     // Field is defined in another dex file.
280     const dex::FieldId& field_id = dex_file_.GetFieldId(field_index);
281     VeriClass* kls = GetVeriClass(field_id.class_idx_);
282     if (kls == nullptr) {
283       return nullptr;
284     }
285     // Class found, now lookup the field in it.
286     field_info = LookupFieldIn(*kls,
287                                dex_file_.GetFieldName(field_id),
288                                dex_file_.GetFieldTypeDescriptor(field_id));
289     field_infos_[field_index] = field_info;
290   }
291   return field_info;
292 }
293 
ResolveAll()294 void VeridexResolver::ResolveAll() {
295   for (uint32_t i = 0; i < dex_file_.NumTypeIds(); ++i) {
296     if (GetVeriClass(dex::TypeIndex(i)) == nullptr) {
297       LOG(WARNING) << "Unresolved " << dex_file_.PrettyType(dex::TypeIndex(i));
298     }
299   }
300 
301   for (uint32_t i = 0; i < dex_file_.NumMethodIds(); ++i) {
302     if (GetMethod(i) == nullptr) {
303       LOG(WARNING) << "Unresolved: " << dex_file_.PrettyMethod(i);
304     }
305   }
306 
307   for (uint32_t i = 0; i < dex_file_.NumFieldIds(); ++i) {
308     if (GetField(i) == nullptr) {
309       LOG(WARNING) << "Unresolved: " << dex_file_.PrettyField(i);
310     }
311   }
312 }
313 
314 }  // namespace art
315