blob: df097b6263bf23173ea9a341f8987d9366518211 [file] [log] [blame]
Nicolas Geoffraydd96ed32018-03-21 11:00:14 +00001/*
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
Mathieu Chartier8f75f7b2018-08-06 23:38:48 -070019#include "dex/class_accessor-inl.h"
Nicolas Geoffraydd96ed32018-03-21 11:00:14 +000020#include "dex/dex_file-inl.h"
21#include "dex/primitive.h"
Andreas Gampead1aa632019-01-02 10:30:54 -080022#include "dex/signature-inl.h"
Nicolas Geoffray534a0a12018-03-24 20:02:25 +000023#include "hidden_api.h"
Nicolas Geoffraydd96ed32018-03-21 11:00:14 +000024#include "veridex.h"
25
26namespace art {
27
28void VeridexResolver::Run() {
Mathieu Chartier8f75f7b2018-08-06 23:38:48 -070029 for (ClassAccessor accessor : dex_file_.GetClasses()) {
30 std::string name(accessor.GetDescriptor());
Nicolas Geoffraydd96ed32018-03-21 11:00:14 +000031 auto existing = type_map_.find(name);
Mathieu Chartier8f75f7b2018-08-06 23:38:48 -070032 const uint32_t type_idx = accessor.GetClassIdx().index_;
Nicolas Geoffraydd96ed32018-03-21 11:00:14 +000033 if (existing != type_map_.end()) {
34 // Class already exists, cache it and move on.
Mathieu Chartier8f75f7b2018-08-06 23:38:48 -070035 type_infos_[type_idx] = *existing->second;
Nicolas Geoffraydd96ed32018-03-21 11:00:14 +000036 continue;
37 }
Mathieu Chartier8f75f7b2018-08-06 23:38:48 -070038 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();
Nicolas Geoffraydd96ed32018-03-21 11:00:14 +000042 }
Mathieu Chartier8f75f7b2018-08-06 23:38:48 -070043 for (const ClassAccessor::Method& method : accessor.GetMethods()) {
44 method_infos_[method.GetIndex()] = method.GetDataPointer();
Nicolas Geoffraydd96ed32018-03-21 11:00:14 +000045 }
46 }
47}
48
Nicolas Geoffraye8264772018-03-22 22:16:41 +000049static bool HasSameNameAndSignature(const DexFile& dex_file,
Andreas Gampe3f1dcd32018-12-28 09:39:56 -080050 const dex::MethodId& method_id,
Nicolas Geoffraye8264772018-03-22 22:16:41 +000051 const char* method_name,
Nicolas Geoffray2ebff052018-04-04 22:32:03 +010052 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
57static bool HasSameNameAndSignature(const DexFile& dex_file,
Andreas Gampe3f1dcd32018-12-28 09:39:56 -080058 const dex::MethodId& method_id,
Nicolas Geoffray2ebff052018-04-04 22:32:03 +010059 const char* method_name,
Nicolas Geoffraye8264772018-03-22 22:16:41 +000060 const Signature& signature) {
61 return strcmp(method_name, dex_file.GetMethodName(method_id)) == 0 &&
62 dex_file.GetMethodSignature(method_id) == signature;
63}
64
65static bool HasSameNameAndType(const DexFile& dex_file,
Andreas Gampe3f1dcd32018-12-28 09:39:56 -080066 const dex::FieldId& field_id,
Nicolas Geoffraye8264772018-03-22 22:16:41 +000067 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
73VeriClass* 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
112VeridexResolver* 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
125VeriMethod 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_;
Mathieu Chartier8f75f7b2018-08-06 23:38:48 -0700141 ClassAccessor other_dex_accessor(other_dex_file, *kls.GetClassDef());
142 for (const ClassAccessor::Method& method : other_dex_accessor.GetMethods()) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800143 const dex::MethodId& other_method_id = other_dex_file.GetMethodId(method.GetIndex());
Mathieu Chartier8f75f7b2018-08-06 23:38:48 -0700144 if (HasSameNameAndSignature(other_dex_file,
145 other_method_id,
146 method_name,
147 method_signature)) {
148 return method.GetDataPointer();
Nicolas Geoffraye8264772018-03-22 22:16:41 +0000149 }
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.
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800164 const dex::TypeList* interfaces = other_dex_file.GetInterfacesList(*kls.GetClassDef());
Nicolas Geoffraye8264772018-03-22 22:16:41 +0000165 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
180VeriField 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_;
Mathieu Chartier8f75f7b2018-08-06 23:38:48 -0700196 ClassAccessor other_dex_accessor(other_dex_file, *kls.GetClassDef());
197 for (const ClassAccessor::Field& field : other_dex_accessor.GetFields()) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800198 const dex::FieldId& other_field_id = other_dex_file.GetFieldId(field.GetIndex());
Mathieu Chartier8f75f7b2018-08-06 23:38:48 -0700199 if (HasSameNameAndType(other_dex_file,
200 other_field_id,
201 field_name,
202 field_type)) {
203 return field.GetDataPointer();
Nicolas Geoffraye8264772018-03-22 22:16:41 +0000204 }
205 }
206
207 // Look at fields in `kls`'s interface hierarchy.
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800208 const dex::TypeList* interfaces = other_dex_file.GetInterfacesList(*kls.GetClassDef());
Nicolas Geoffraye8264772018-03-22 22:16:41 +0000209 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
Nicolas Geoffray2ebff052018-04-04 22:32:03 +0100235VeriMethod 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_;
Mathieu Chartier8f75f7b2018-08-06 23:38:48 -0700246 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();
Nicolas Geoffray2ebff052018-04-04 22:32:03 +0100253 }
254 }
255 return nullptr;
256}
257
Nicolas Geoffraye8264772018-03-22 22:16:41 +0000258VeriMethod 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.
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800262 const dex::MethodId& method_id = dex_file_.GetMethodId(method_index);
Nicolas Geoffraye8264772018-03-22 22:16:41 +0000263 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
276VeriField 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.
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800280 const dex::FieldId& field_id = dex_file_.GetFieldId(field_index);
Nicolas Geoffraye8264772018-03-22 22:16:41 +0000281 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
Nicolas Geoffray11ed0272018-03-28 18:18:48 +0100294void VeridexResolver::ResolveAll() {
Nicolas Geoffraye8264772018-03-22 22:16:41 +0000295 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) {
Nicolas Geoffray11ed0272018-03-28 18:18:48 +0100303 LOG(WARNING) << "Unresolved: " << dex_file_.PrettyMethod(i);
Nicolas Geoffraye8264772018-03-22 22:16:41 +0000304 }
305 }
306
307 for (uint32_t i = 0; i < dex_file_.NumFieldIds(); ++i) {
308 if (GetField(i) == nullptr) {
Nicolas Geoffray11ed0272018-03-28 18:18:48 +0100309 LOG(WARNING) << "Unresolved: " << dex_file_.PrettyField(i);
Nicolas Geoffraye8264772018-03-22 22:16:41 +0000310 }
311 }
312}
313
Nicolas Geoffraydd96ed32018-03-21 11:00:14 +0000314} // namespace art