• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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