• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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->name) == 0 &&
44             strcmp(signature, pField->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     const 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[0];
99     for (i = 0; i < clazz->sfieldCount; i++, pField++) {
100         if (strcmp(fieldName, pField->name) == 0 &&
101             strcmp(signature, pField->signature) == 0)
102         {
103             return (StaticField*) 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", 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.  Does not examine interfaces.
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.  Does not examine interfaces.
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 method in an interface.  Searches superinterfaces.
546  *
547  * Returns NULL if the method can't be found.  (Does not throw an exception.)
548  */
dvmFindInterfaceMethodHierByDescriptor(const ClassObject * iface,const char * methodName,const char * descriptor)549 Method* dvmFindInterfaceMethodHierByDescriptor(const ClassObject* iface,
550     const char* methodName, const char* descriptor)
551 {
552     Method* resMethod = dvmFindVirtualMethodByDescriptor(iface,
553         methodName, descriptor);
554     if (resMethod == NULL) {
555         /* scan superinterfaces and superclass interfaces */
556         int i;
557         for (i = 0; i < iface->iftableCount; i++) {
558             resMethod = dvmFindVirtualMethodByDescriptor(iface->iftable[i].clazz,
559                 methodName, descriptor);
560             if (resMethod != NULL)
561                 break;
562         }
563     }
564     return resMethod;
565 }
566 
567 /*
568  * Find a method in an interface.  Searches superinterfaces.
569  *
570  * Returns NULL if the method can't be found.  (Does not throw an exception.)
571  */
dvmFindInterfaceMethodHier(const ClassObject * iface,const char * methodName,const DexProto * proto)572 Method* dvmFindInterfaceMethodHier(const ClassObject* iface,
573     const char* methodName, const DexProto* proto)
574 {
575     Method* resMethod = dvmFindVirtualMethod(iface, methodName, proto);
576     if (resMethod == NULL) {
577         /* scan superinterfaces and superclass interfaces */
578         int i;
579         for (i = 0; i < iface->iftableCount; i++) {
580             resMethod = dvmFindVirtualMethod(iface->iftable[i].clazz,
581                 methodName, proto);
582             if (resMethod != NULL)
583                 break;
584         }
585     }
586     return resMethod;
587 }
588 
589 /*
590  * Find a "direct" method (static, private, or "<*init>").
591  *
592  * Returns NULL if the method can't be found.  (Does not throw an exception.)
593  */
dvmFindDirectMethodByDescriptor(const ClassObject * clazz,const char * methodName,const char * descriptor)594 Method* dvmFindDirectMethodByDescriptor(const ClassObject* clazz,
595     const char* methodName, const char* descriptor)
596 {
597     return findMethodInListByDescriptor(clazz, false, false,
598             methodName, descriptor);
599 }
600 
601 /*
602  * Find a "direct" method.  If we don't find it, try the superclass.  This
603  * is only appropriate for static methods, but will work for all direct
604  * methods.
605  *
606  * Returns NULL if the method can't be found.  (Does not throw an exception.)
607  */
dvmFindDirectMethodHierByDescriptor(const ClassObject * clazz,const char * methodName,const char * descriptor)608 Method* dvmFindDirectMethodHierByDescriptor(const ClassObject* clazz,
609     const char* methodName, const char* descriptor)
610 {
611     return findMethodInListByDescriptor(clazz, false, true,
612             methodName, descriptor);
613 }
614 
615 /*
616  * Find a "direct" method (static or "<*init>").
617  *
618  * Returns NULL if the method can't be found.  (Does not throw an exception.)
619  */
dvmFindDirectMethod(const ClassObject * clazz,const char * methodName,const DexProto * proto)620 Method* dvmFindDirectMethod(const ClassObject* clazz, const char* methodName,
621     const DexProto* proto)
622 {
623     return findMethodInListByProto(clazz, METHOD_DIRECT, false, methodName,
624             proto);
625 }
626 
627 /*
628  * Find a "direct" method in a class.  If we don't find it, try the
629  * superclass.
630  *
631  * Returns NULL if the method can't be found.  (Does not throw an exception.)
632  */
dvmFindDirectMethodHier(const ClassObject * clazz,const char * methodName,const DexProto * proto)633 Method* dvmFindDirectMethodHier(const ClassObject* clazz,
634     const char* methodName, const DexProto* proto)
635 {
636     return findMethodInListByProto(clazz, METHOD_DIRECT, true, methodName,
637             proto);
638 }
639 
640 /*
641  * Find a virtual or static method in a class.  If we don't find it, try the
642  * superclass.  This is compatible with the VM spec (v2 5.4.3.3) method
643  * search order, but it stops short of scanning through interfaces (which
644  * should be done after this function completes).
645  *
646  * In most cases we know that we're looking for either a static or an
647  * instance field and there's no value in searching through both types.
648  * During verification we need to recognize and reject certain unusual
649  * situations, and we won't see them unless we walk the lists this way.
650  *
651  * Returns NULL if the method can't be found.  (Does not throw an exception.)
652  */
dvmFindMethodHier(const ClassObject * clazz,const char * methodName,const DexProto * proto)653 Method* dvmFindMethodHier(const ClassObject* clazz, const char* methodName,
654     const DexProto* proto)
655 {
656     return findMethodInListByProto(clazz, METHOD_UNKNOWN, true, methodName,
657             proto);
658 }
659 
660 
661 /*
662  * We have a method pointer for a method in "clazz", but it might be
663  * pointing to a method in a derived class.  We want to find the actual entry
664  * from the class' vtable.  If "clazz" is an interface, we have to do a
665  * little more digging.
666  *
667  * For "direct" methods (private / constructor), we just return the
668  * original Method.
669  *
670  * (This is used for reflection and JNI "call method" calls.)
671  */
dvmGetVirtualizedMethod(const ClassObject * clazz,const Method * meth)672 const Method* dvmGetVirtualizedMethod(const ClassObject* clazz,
673     const Method* meth)
674 {
675     Method* actualMeth;
676     int methodIndex;
677 
678     if (dvmIsDirectMethod(meth)) {
679         /* no vtable entry for these */
680         assert(!dvmIsStaticMethod(meth));
681         return meth;
682     }
683 
684     /*
685      * If the method was declared in an interface, we need to scan through
686      * the class' list of interfaces for it, and find the vtable index
687      * from that.
688      *
689      * TODO: use the interface cache.
690      */
691     if (dvmIsInterfaceClass(meth->clazz)) {
692         int i;
693 
694         for (i = 0; i < clazz->iftableCount; i++) {
695             if (clazz->iftable[i].clazz == meth->clazz)
696                 break;
697         }
698         if (i == clazz->iftableCount) {
699             dvmThrowIncompatibleClassChangeError(
700                 "invoking method from interface not implemented by class");
701             return NULL;
702         }
703 
704         methodIndex = clazz->iftable[i].methodIndexArray[meth->methodIndex];
705     } else {
706         methodIndex = meth->methodIndex;
707     }
708 
709     assert(methodIndex >= 0 && methodIndex < clazz->vtableCount);
710     actualMeth = clazz->vtable[methodIndex];
711 
712     /*
713      * Make sure there's code to execute.
714      */
715     if (dvmIsAbstractMethod(actualMeth)) {
716         dvmThrowAbstractMethodError(NULL);
717         return NULL;
718     }
719     assert(!dvmIsMirandaMethod(actualMeth));
720 
721     return actualMeth;
722 }
723 
724 /*
725  * Get the source file for a method.
726  */
dvmGetMethodSourceFile(const Method * meth)727 const char* dvmGetMethodSourceFile(const Method* meth)
728 {
729     /*
730      * TODO: A method's debug info can override the default source
731      * file for a class, so we should account for that possibility
732      * here.
733      */
734     return meth->clazz->sourceFile;
735 }
736 
737 /*
738  * Dump some information about an object.
739  */
dvmDumpObject(const Object * obj)740 void dvmDumpObject(const Object* obj)
741 {
742     ClassObject* clazz;
743     int i;
744 
745     if (obj == NULL || obj->clazz == NULL) {
746         LOGW("Null or malformed object not dumped");
747         return;
748     }
749 
750     clazz = obj->clazz;
751     LOGD("----- Object dump: %p (%s, %d bytes) -----",
752         obj, clazz->descriptor, (int) clazz->objectSize);
753     //printHexDump(obj, clazz->objectSize);
754     LOGD("  Fields:");
755     while (clazz != NULL) {
756         LOGD("    -- %s", clazz->descriptor);
757         for (i = 0; i < clazz->ifieldCount; i++) {
758             const InstField* pField = &clazz->ifields[i];
759             char type = pField->signature[0];
760 
761             if (type == 'F' || type == 'D') {
762                 double dval;
763 
764                 if (type == 'F')
765                     dval = dvmGetFieldFloat(obj, pField->byteOffset);
766                 else
767                     dval = dvmGetFieldDouble(obj, pField->byteOffset);
768 
769                 LOGD("    %2d: '%s' '%s' af=%04x off=%d %.3f", i,
770                     pField->name, pField->signature,
771                     pField->accessFlags, pField->byteOffset, dval);
772             } else {
773                 u8 lval;
774 
775                 if (type == 'J')
776                     lval = dvmGetFieldLong(obj, pField->byteOffset);
777                 else if (type == 'Z')
778                     lval = dvmGetFieldBoolean(obj, pField->byteOffset);
779                 else
780                     lval = dvmGetFieldInt(obj, pField->byteOffset);
781 
782                 LOGD("    %2d: '%s' '%s' af=%04x off=%d 0x%08llx", i,
783                     pField->name, pField->signature,
784                     pField->accessFlags, pField->byteOffset, lval);
785             }
786         }
787 
788         clazz = clazz->super;
789     }
790     if (dvmIsClassObject(obj)) {
791         LOGD("  Static fields:");
792         const StaticField* sfields = &((ClassObject *)obj)->sfields[0];
793         for (i = 0; i < ((ClassObject *)obj)->sfieldCount; ++i) {
794             const StaticField* pField = &sfields[i];
795             size_t byteOffset = (size_t)pField - (size_t)sfields;
796             char type = pField->signature[0];
797 
798             if (type == 'F' || type == 'D') {
799                 double dval;
800 
801                 if (type == 'F')
802                     dval = pField->value.f;
803                 else
804                     dval = pField->value.d;
805 
806                 LOGD("    %2d: '%s' '%s' af=%04x off=%zd %.3f", i,
807                      pField->name, pField->signature,
808                      pField->accessFlags, byteOffset, dval);
809             } else {
810                 u8 lval;
811 
812                 if (type == 'J')
813                     lval = pField->value.j;
814                 else if (type == 'Z')
815                     lval = pField->value.z;
816                 else
817                     lval = pField->value.i;
818 
819                 LOGD("    %2d: '%s' '%s' af=%04x off=%zd 0x%08llx", i,
820                      pField->name, pField->signature,
821                      pField->accessFlags, byteOffset, lval);
822             }
823         }
824     }
825 }
826