1 /*
2 * Copyright (C) 2008 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 /*
18 * Operations on an Object.
19 */
20 #include "Dalvik.h"
21
22 /*
23 * Find a matching field, in the current class only.
24 *
25 * Returns NULL if the field can't be found. (Does not throw an exception.)
26 */
dvmFindInstanceField(const ClassObject * clazz,const char * fieldName,const char * signature)27 InstField* dvmFindInstanceField(const ClassObject* clazz,
28 const char* fieldName, const char* signature)
29 {
30 InstField* pField;
31 int i;
32
33 assert(clazz != NULL);
34
35 /*
36 * Find a field with a matching name and signature. The Java programming
37 * language does not allow you to have two fields with the same name
38 * and different types, but the Java VM spec does allow it, so we can't
39 * bail out early when the name matches.
40 */
41 pField = clazz->ifields;
42 for (i = 0; i < clazz->ifieldCount; i++, pField++) {
43 if (strcmp(fieldName, pField->field.name) == 0 &&
44 strcmp(signature, pField->field.signature) == 0)
45 {
46 return pField;
47 }
48 }
49
50 return NULL;
51 }
52
53 /*
54 * Find a matching field, in this class or a superclass.
55 *
56 * Searching through interfaces isn't necessary, because interface fields
57 * are inherently public/static/final.
58 *
59 * Returns NULL if the field can't be found. (Does not throw an exception.)
60 */
dvmFindInstanceFieldHier(const ClassObject * clazz,const char * fieldName,const char * signature)61 InstField* dvmFindInstanceFieldHier(const ClassObject* clazz,
62 const char* fieldName, const char* signature)
63 {
64 InstField* pField;
65
66 /*
67 * Search for a match in the current class.
68 */
69 pField = dvmFindInstanceField(clazz, fieldName, signature);
70 if (pField != NULL)
71 return pField;
72
73 if (clazz->super != NULL)
74 return dvmFindInstanceFieldHier(clazz->super, fieldName, signature);
75 else
76 return NULL;
77 }
78
79
80 /*
81 * Find a matching field, in this class or an interface.
82 *
83 * Returns NULL if the field can't be found. (Does not throw an exception.)
84 */
dvmFindStaticField(const ClassObject * clazz,const char * fieldName,const char * signature)85 StaticField* dvmFindStaticField(const ClassObject* clazz,
86 const char* fieldName, const char* signature)
87 {
88 StaticField* pField;
89 int i;
90
91 assert(clazz != NULL);
92
93 /*
94 * Find a field with a matching name and signature. As with instance
95 * fields, the VM allows you to have two fields with the same name so
96 * long as they have different types.
97 */
98 pField = clazz->sfields;
99 for (i = 0; i < clazz->sfieldCount; i++, pField++) {
100 if (strcmp(fieldName, pField->field.name) == 0 &&
101 strcmp(signature, pField->field.signature) == 0)
102 {
103 return pField;
104 }
105 }
106
107 return NULL;
108 }
109
110 /*
111 * Find a matching field, in this class or a superclass.
112 *
113 * Returns NULL if the field can't be found. (Does not throw an exception.)
114 */
dvmFindStaticFieldHier(const ClassObject * clazz,const char * fieldName,const char * signature)115 StaticField* dvmFindStaticFieldHier(const ClassObject* clazz,
116 const char* fieldName, const char* signature)
117 {
118 StaticField* pField;
119
120 /*
121 * Search for a match in the current class.
122 */
123 pField = dvmFindStaticField(clazz, fieldName, signature);
124 if (pField != NULL)
125 return pField;
126
127 /*
128 * See if it's in any of our interfaces. We don't check interfaces
129 * inherited from the superclass yet.
130 *
131 * (Note the set may have been stripped down because of redundancy with
132 * the superclass; see notes in createIftable.)
133 */
134 int i = 0;
135 if (clazz->super != NULL) {
136 assert(clazz->iftableCount >= clazz->super->iftableCount);
137 i = clazz->super->iftableCount;
138 }
139 for ( ; i < clazz->iftableCount; i++) {
140 ClassObject* iface = clazz->iftable[i].clazz;
141 pField = dvmFindStaticField(iface, fieldName, signature);
142 if (pField != NULL)
143 return pField;
144 }
145
146 if (clazz->super != NULL)
147 return dvmFindStaticFieldHier(clazz->super, fieldName, signature);
148 else
149 return NULL;
150 }
151
152 /*
153 * Find a matching field, in this class or a superclass.
154 *
155 * We scan both the static and instance field lists in the class. If it's
156 * not found there, we check the direct interfaces, and then recursively
157 * scan the superclasses. This is the order prescribed in the VM spec
158 * (v2 5.4.3.2).
159 *
160 * In most cases we know that we're looking for either a static or an
161 * instance field and there's no value in searching through both types.
162 * During verification we need to recognize and reject certain unusual
163 * situations, and we won't see them unless we walk the lists this way.
164 */
dvmFindFieldHier(const ClassObject * clazz,const char * fieldName,const char * signature)165 Field* dvmFindFieldHier(const ClassObject* clazz, const char* fieldName,
166 const char* signature)
167 {
168 Field* pField;
169
170 /*
171 * Search for a match in the current class. Which set we scan first
172 * doesn't really matter.
173 */
174 pField = (Field*) dvmFindStaticField(clazz, fieldName, signature);
175 if (pField != NULL)
176 return pField;
177 pField = (Field*) dvmFindInstanceField(clazz, fieldName, signature);
178 if (pField != NULL)
179 return pField;
180
181 /*
182 * See if it's in any of our interfaces. We don't check interfaces
183 * inherited from the superclass yet.
184 */
185 int i = 0;
186 if (clazz->super != NULL) {
187 assert(clazz->iftableCount >= clazz->super->iftableCount);
188 i = clazz->super->iftableCount;
189 }
190 for ( ; i < clazz->iftableCount; i++) {
191 ClassObject* iface = clazz->iftable[i].clazz;
192 pField = (Field*) dvmFindStaticField(iface, fieldName, signature);
193 if (pField != NULL)
194 return pField;
195 }
196
197 if (clazz->super != NULL)
198 return dvmFindFieldHier(clazz->super, fieldName, signature);
199 else
200 return NULL;
201 }
202
203
204 /*
205 * Compare the given name, return type, and argument types with the contents
206 * of the given method. This returns 0 if they are equal and non-zero if not.
207 */
compareMethodHelper(Method * method,const char * methodName,const char * returnType,size_t argCount,const char ** argTypes)208 static inline int compareMethodHelper(Method* method, const char* methodName,
209 const char* returnType, size_t argCount, const char** argTypes)
210 {
211 DexParameterIterator iterator;
212 const DexProto* proto;
213
214 if (strcmp(methodName, method->name) != 0) {
215 return 1;
216 }
217
218 proto = &method->prototype;
219
220 if (strcmp(returnType, dexProtoGetReturnType(proto)) != 0) {
221 return 1;
222 }
223
224 if (dexProtoGetParameterCount(proto) != argCount) {
225 return 1;
226 }
227
228 dexParameterIteratorInit(&iterator, proto);
229
230 for (/*argCount*/; argCount != 0; argCount--, argTypes++) {
231 const char* argType = *argTypes;
232 const char* paramType = dexParameterIteratorNextDescriptor(&iterator);
233
234 if (paramType == NULL) {
235 /* Param list ended early; no match */
236 break;
237 } else if (strcmp(argType, paramType) != 0) {
238 /* Types aren't the same; no match. */
239 break;
240 }
241 }
242
243 if (argCount == 0) {
244 /* We ran through all the given arguments... */
245 if (dexParameterIteratorNextDescriptor(&iterator) == NULL) {
246 /* ...and through all the method's arguments; success! */
247 return 0;
248 }
249 }
250
251 return 1;
252 }
253
254 /*
255 * Get the count of arguments in the given method descriptor string,
256 * and also find a pointer to the return type.
257 */
countArgsAndFindReturnType(const char * descriptor,const char ** pReturnType)258 static inline size_t countArgsAndFindReturnType(const char* descriptor,
259 const char** pReturnType)
260 {
261 size_t count = 0;
262 bool bogus = false;
263 bool done = false;
264
265 assert(*descriptor == '(');
266 descriptor++;
267
268 while (!done) {
269 switch (*descriptor) {
270 case 'B': case 'C': case 'D': case 'F':
271 case 'I': case 'J': case 'S': case 'Z': {
272 count++;
273 break;
274 }
275 case '[': {
276 do {
277 descriptor++;
278 } while (*descriptor == '[');
279 /*
280 * Don't increment count, as it will be taken care of
281 * by the next iteration. Also, decrement descriptor
282 * to compensate for the increment below the switch.
283 */
284 descriptor--;
285 break;
286 }
287 case 'L': {
288 do {
289 descriptor++;
290 } while ((*descriptor != ';') && (*descriptor != '\0'));
291 count++;
292 if (*descriptor == '\0') {
293 /* Bogus descriptor. */
294 done = true;
295 bogus = true;
296 }
297 break;
298 }
299 case ')': {
300 /*
301 * Note: The loop will exit after incrementing descriptor
302 * one more time, so it then points at the return type.
303 */
304 done = true;
305 break;
306 }
307 default: {
308 /* Bogus descriptor. */
309 done = true;
310 bogus = true;
311 break;
312 }
313 }
314
315 descriptor++;
316 }
317
318 if (bogus) {
319 *pReturnType = NULL;
320 return 0;
321 }
322
323 *pReturnType = descriptor;
324 return count;
325 }
326
327 /*
328 * Copy the argument types into the given array using the given buffer
329 * for the contents.
330 */
copyTypes(char * buffer,const char ** argTypes,size_t argCount,const char * descriptor)331 static inline void copyTypes(char* buffer, const char** argTypes,
332 size_t argCount, const char* descriptor)
333 {
334 size_t i;
335 char c;
336
337 /* Skip the '('. */
338 descriptor++;
339
340 for (i = 0; i < argCount; i++) {
341 argTypes[i] = buffer;
342
343 /* Copy all the array markers and one extra character. */
344 do {
345 c = *(descriptor++);
346 *(buffer++) = c;
347 } while (c == '[');
348
349 if (c == 'L') {
350 /* Copy the rest of a class name. */
351 do {
352 c = *(descriptor++);
353 *(buffer++) = c;
354 } while (c != ';');
355 }
356
357 *(buffer++) = '\0';
358 }
359 }
360
361 /*
362 * Look for a match in the given class. Returns the match if found
363 * or NULL if not.
364 */
findMethodInListByDescriptor(const ClassObject * clazz,bool findVirtual,bool isHier,const char * name,const char * descriptor)365 static Method* findMethodInListByDescriptor(const ClassObject* clazz,
366 bool findVirtual, bool isHier, const char* name, const char* descriptor)
367 {
368 const char* returnType;
369 size_t argCount = countArgsAndFindReturnType(descriptor, &returnType);
370
371 if (returnType == NULL) {
372 LOGW("Bogus method descriptor: %s\n", descriptor);
373 return NULL;
374 }
375
376 /*
377 * Make buffer big enough for all the argument type characters and
378 * one '\0' per argument. The "- 2" is because "returnType -
379 * descriptor" includes two parens.
380 */
381 char buffer[argCount + (returnType - descriptor) - 2];
382 const char* argTypes[argCount];
383
384 copyTypes(buffer, argTypes, argCount, descriptor);
385
386 while (clazz != NULL) {
387 Method* methods;
388 size_t methodCount;
389 size_t i;
390
391 if (findVirtual) {
392 methods = clazz->virtualMethods;
393 methodCount = clazz->virtualMethodCount;
394 } else {
395 methods = clazz->directMethods;
396 methodCount = clazz->directMethodCount;
397 }
398
399 for (i = 0; i < methodCount; i++) {
400 Method* method = &methods[i];
401 if (compareMethodHelper(method, name, returnType, argCount,
402 argTypes) == 0) {
403 return method;
404 }
405 }
406
407 if (! isHier) {
408 break;
409 }
410
411 clazz = clazz->super;
412 }
413
414 return NULL;
415 }
416
417 /*
418 * Look for a match in the given clazz. Returns the match if found
419 * or NULL if not.
420 *
421 * "wantedType" should be METHOD_VIRTUAL or METHOD_DIRECT to indicate the
422 * list to search through. If the match can come from either list, use
423 * MATCH_UNKNOWN to scan both.
424 */
findMethodInListByProto(const ClassObject * clazz,MethodType wantedType,bool isHier,const char * name,const DexProto * proto)425 static Method* findMethodInListByProto(const ClassObject* clazz,
426 MethodType wantedType, bool isHier, const char* name, const DexProto* proto)
427 {
428 while (clazz != NULL) {
429 int i;
430
431 /*
432 * Check the virtual and/or direct method lists.
433 */
434 if (wantedType == METHOD_VIRTUAL || wantedType == METHOD_UNKNOWN) {
435 for (i = 0; i < clazz->virtualMethodCount; i++) {
436 Method* method = &clazz->virtualMethods[i];
437 if (dvmCompareNameProtoAndMethod(name, proto, method) == 0) {
438 return method;
439 }
440 }
441 }
442 if (wantedType == METHOD_DIRECT || wantedType == METHOD_UNKNOWN) {
443 for (i = 0; i < clazz->directMethodCount; i++) {
444 Method* method = &clazz->directMethods[i];
445 if (dvmCompareNameProtoAndMethod(name, proto, method) == 0) {
446 return method;
447 }
448 }
449 }
450
451 if (! isHier) {
452 break;
453 }
454
455 clazz = clazz->super;
456 }
457
458 return NULL;
459 }
460
461 /*
462 * Find a "virtual" method in a class.
463 *
464 * Does not chase into the superclass.
465 *
466 * Returns NULL if the method can't be found. (Does not throw an exception.)
467 */
dvmFindVirtualMethodByDescriptor(const ClassObject * clazz,const char * methodName,const char * descriptor)468 Method* dvmFindVirtualMethodByDescriptor(const ClassObject* clazz,
469 const char* methodName, const char* descriptor)
470 {
471 return findMethodInListByDescriptor(clazz, true, false,
472 methodName, descriptor);
473
474 // TODO? - throw IncompatibleClassChangeError if a match is
475 // found in the directMethods list, rather than NotFoundError.
476 // Note we could have been called by dvmFindVirtualMethodHier though.
477 }
478
479
480 /*
481 * Find a "virtual" method in a class, knowing only the name. This is
482 * only useful in limited circumstances, e.g. when searching for a member
483 * of an annotation class.
484 *
485 * Does not chase into the superclass.
486 *
487 * Returns NULL if the method can't be found. (Does not throw an exception.)
488 */
dvmFindVirtualMethodByName(const ClassObject * clazz,const char * methodName)489 Method* dvmFindVirtualMethodByName(const ClassObject* clazz,
490 const char* methodName)
491 {
492 Method* methods = clazz->virtualMethods;
493 int methodCount = clazz->virtualMethodCount;
494 int i;
495
496 for (i = 0; i < methodCount; i++) {
497 if (strcmp(methods[i].name, methodName) == 0)
498 return &methods[i];
499 }
500
501 return NULL;
502 }
503
504 /*
505 * Find a "virtual" method in a class.
506 *
507 * Does not chase into the superclass.
508 *
509 * Returns NULL if the method can't be found. (Does not throw an exception.)
510 */
dvmFindVirtualMethod(const ClassObject * clazz,const char * methodName,const DexProto * proto)511 Method* dvmFindVirtualMethod(const ClassObject* clazz, const char* methodName,
512 const DexProto* proto)
513 {
514 return findMethodInListByProto(clazz, METHOD_VIRTUAL, false, methodName,
515 proto);
516 }
517
518 /*
519 * Find a "virtual" method in a class. If we don't find it, try the
520 * superclass.
521 *
522 * Returns NULL if the method can't be found. (Does not throw an exception.)
523 */
dvmFindVirtualMethodHierByDescriptor(const ClassObject * clazz,const char * methodName,const char * descriptor)524 Method* dvmFindVirtualMethodHierByDescriptor(const ClassObject* clazz,
525 const char* methodName, const char* descriptor)
526 {
527 return findMethodInListByDescriptor(clazz, true, true,
528 methodName, descriptor);
529 }
530
531 /*
532 * Find a "virtual" method in a class. If we don't find it, try the
533 * superclass.
534 *
535 * Returns NULL if the method can't be found. (Does not throw an exception.)
536 */
dvmFindVirtualMethodHier(const ClassObject * clazz,const char * methodName,const DexProto * proto)537 Method* dvmFindVirtualMethodHier(const ClassObject* clazz,
538 const char* methodName, const DexProto* proto)
539 {
540 return findMethodInListByProto(clazz, METHOD_VIRTUAL, true, methodName,
541 proto);
542 }
543
544 /*
545 * Find a "direct" method (static, private, or "<*init>").
546 *
547 * Returns NULL if the method can't be found. (Does not throw an exception.)
548 */
dvmFindDirectMethodByDescriptor(const ClassObject * clazz,const char * methodName,const char * descriptor)549 Method* dvmFindDirectMethodByDescriptor(const ClassObject* clazz,
550 const char* methodName, const char* descriptor)
551 {
552 return findMethodInListByDescriptor(clazz, false, false,
553 methodName, descriptor);
554 }
555
556 /*
557 * Find a "direct" method. If we don't find it, try the superclass. This
558 * is only appropriate for static methods, but will work for all direct
559 * methods.
560 *
561 * Returns NULL if the method can't be found. (Does not throw an exception.)
562 */
dvmFindDirectMethodHierByDescriptor(const ClassObject * clazz,const char * methodName,const char * descriptor)563 Method* dvmFindDirectMethodHierByDescriptor(const ClassObject* clazz,
564 const char* methodName, const char* descriptor)
565 {
566 return findMethodInListByDescriptor(clazz, false, true,
567 methodName, descriptor);
568 }
569
570 /*
571 * Find a "direct" method (static or "<*init>").
572 *
573 * Returns NULL if the method can't be found. (Does not throw an exception.)
574 */
dvmFindDirectMethod(const ClassObject * clazz,const char * methodName,const DexProto * proto)575 Method* dvmFindDirectMethod(const ClassObject* clazz, const char* methodName,
576 const DexProto* proto)
577 {
578 return findMethodInListByProto(clazz, METHOD_DIRECT, false, methodName,
579 proto);
580 }
581
582 /*
583 * Find a "direct" method in a class. If we don't find it, try the
584 * superclass.
585 *
586 * Returns NULL if the method can't be found. (Does not throw an exception.)
587 */
dvmFindDirectMethodHier(const ClassObject * clazz,const char * methodName,const DexProto * proto)588 Method* dvmFindDirectMethodHier(const ClassObject* clazz,
589 const char* methodName, const DexProto* proto)
590 {
591 return findMethodInListByProto(clazz, METHOD_DIRECT, true, methodName,
592 proto);
593 }
594
595 /*
596 * Find a virtual or static method in a class. If we don't find it, try the
597 * superclass. This is compatible with the VM spec (v2 5.4.3.3) method
598 * search order, but it stops short of scanning through interfaces (which
599 * should be done after this function completes).
600 *
601 * In most cases we know that we're looking for either a static or an
602 * instance field and there's no value in searching through both types.
603 * During verification we need to recognize and reject certain unusual
604 * situations, and we won't see them unless we walk the lists this way.
605 *
606 * Returns NULL if the method can't be found. (Does not throw an exception.)
607 */
dvmFindMethodHier(const ClassObject * clazz,const char * methodName,const DexProto * proto)608 Method* dvmFindMethodHier(const ClassObject* clazz, const char* methodName,
609 const DexProto* proto)
610 {
611 return findMethodInListByProto(clazz, METHOD_UNKNOWN, true, methodName,
612 proto);
613 }
614
615
616 /*
617 * We have a method pointer for a method in "clazz", but it might be
618 * pointing to a method in a derived class. We want to find the actual entry
619 * from the class' vtable. If "clazz" is an interface, we have to do a
620 * little more digging.
621 *
622 * (This is used for reflection and JNI "call method" calls.)
623 */
dvmGetVirtualizedMethod(const ClassObject * clazz,const Method * meth)624 const Method* dvmGetVirtualizedMethod(const ClassObject* clazz,
625 const Method* meth)
626 {
627 Method* actualMeth;
628 int methodIndex;
629
630 assert(!dvmIsStaticMethod(meth));
631
632 if (dvmIsPrivateMethod(meth)) // no vtable entry for these
633 return meth;
634
635 /*
636 * If the method was declared in an interface, we need to scan through
637 * the class' list of interfaces for it, and find the vtable index
638 * from that.
639 *
640 * TODO: use the interface cache.
641 */
642 if (dvmIsInterfaceClass(meth->clazz)) {
643 int i;
644
645 for (i = 0; i < clazz->iftableCount; i++) {
646 if (clazz->iftable[i].clazz == meth->clazz)
647 break;
648 }
649 if (i == clazz->iftableCount) {
650 dvmThrowException("Ljava/lang/IncompatibleClassChangeError;",
651 "invoking method from interface not implemented by class");
652 return NULL;
653 }
654
655 methodIndex = clazz->iftable[i].methodIndexArray[meth->methodIndex];
656 } else {
657 methodIndex = meth->methodIndex;
658 }
659
660 assert(methodIndex >= 0 && methodIndex < clazz->vtableCount);
661 actualMeth = clazz->vtable[methodIndex];
662
663 /*
664 * Make sure there's code to execute.
665 */
666 if (dvmIsAbstractMethod(actualMeth)) {
667 dvmThrowException("Ljava/lang/AbstractMethodError;", NULL);
668 return NULL;
669 }
670 assert(!dvmIsMirandaMethod(actualMeth));
671
672 return actualMeth;
673 }
674
675 /*
676 * Get the source file for a method.
677 */
dvmGetMethodSourceFile(const Method * meth)678 const char* dvmGetMethodSourceFile(const Method* meth)
679 {
680 /*
681 * TODO: A method's debug info can override the default source
682 * file for a class, so we should account for that possibility
683 * here.
684 */
685 return meth->clazz->sourceFile;
686 }
687
688 /*
689 * Dump some information about an object.
690 */
dvmDumpObject(const Object * obj)691 void dvmDumpObject(const Object* obj)
692 {
693 ClassObject* clazz;
694 int i;
695
696 if (obj == NULL || obj->clazz == NULL) {
697 LOGW("Null or malformed object not dumped\n");
698 return;
699 }
700
701 clazz = obj->clazz;
702 LOGD("----- Object dump: %p (%s, %d bytes) -----\n",
703 obj, clazz->descriptor, (int) clazz->objectSize);
704 //printHexDump(obj, clazz->objectSize);
705 LOGD(" Fields:\n");
706 while (clazz != NULL) {
707 LOGD(" -- %s\n", clazz->descriptor);
708 for (i = 0; i < clazz->ifieldCount; i++) {
709 const InstField* pField = &clazz->ifields[i];
710 char type = pField->field.signature[0];
711
712 if (type == 'F' || type == 'D') {
713 double dval;
714
715 if (type == 'F')
716 dval = dvmGetFieldFloat(obj, pField->byteOffset);
717 else
718 dval = dvmGetFieldDouble(obj, pField->byteOffset);
719
720 LOGD(" %2d: '%s' '%s' af=%04x off=%d %.3f\n", i,
721 pField->field.name, pField->field.signature,
722 pField->field.accessFlags, pField->byteOffset, dval);
723 } else {
724 u8 lval;
725
726 if (type == 'J')
727 lval = dvmGetFieldLong(obj, pField->byteOffset);
728 else if (type == 'Z')
729 lval = dvmGetFieldBoolean(obj, pField->byteOffset);
730 else
731 lval = dvmGetFieldInt(obj, pField->byteOffset);
732
733 LOGD(" %2d: '%s' '%s' af=%04x off=%d 0x%08llx\n", i,
734 pField->field.name, pField->field.signature,
735 pField->field.accessFlags, pField->byteOffset, lval);
736 }
737 }
738
739 clazz = clazz->super;
740 }
741 }
742
743