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