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