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/dex_file-inl.h"
     20 #include "dex/primitive.h"
     21 #include "hidden_api.h"
     22 #include "veridex.h"
     23 
     24 namespace art {
     25 
     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 
     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 
     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 
     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 
     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 
    122 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 
    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 
    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 
    252 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 
    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 
    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 
    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