Home | History | Annotate | Download | only in veridex
      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 
     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 
     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 
     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 
     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 
     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 
    112 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 
    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 
    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 
    235 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 
    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 
    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 
    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