• 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  * Stacks and their uses (e.g. native --> interpreted method calls).
19  *
20  * See the majestic ASCII art in Stack.h.
21  */
22 #include "Dalvik.h"
23 #include "jni.h"
24 
25 #include <stdlib.h>
26 #include <stdarg.h>
27 
28 #ifdef HAVE_ANDROID_OS
29 #include <corkscrew/backtrace.h>
30 #endif
31 
32 /*
33  * Initialize the interpreter stack in a new thread.
34  *
35  * Currently this doesn't do much, since we don't need to zero out the
36  * stack (and we really don't want to if it was created with mmap).
37  */
dvmInitInterpStack(Thread * thread,int stackSize)38 bool dvmInitInterpStack(Thread* thread, int stackSize)
39 {
40     assert(thread->interpStackStart != NULL);
41 
42     assert(thread->interpSave.curFrame == NULL);
43 
44     return true;
45 }
46 
47 /*
48  * We're calling an interpreted method from an internal VM function or
49  * via reflection.
50  *
51  * Push a frame for an interpreted method onto the stack.  This is only
52  * used when calling into interpreted code from native code.  (The
53  * interpreter does its own stack frame manipulation for interp-->interp
54  * calls.)
55  *
56  * The size we need to reserve is the sum of parameters, local variables,
57  * saved goodies, and outbound parameters.
58  *
59  * We start by inserting a "break" frame, which ensures that the interpreter
60  * hands control back to us after the function we call returns or an
61  * uncaught exception is thrown.
62  */
dvmPushInterpFrame(Thread * self,const Method * method)63 static bool dvmPushInterpFrame(Thread* self, const Method* method)
64 {
65     StackSaveArea* saveBlock;
66     StackSaveArea* breakSaveBlock;
67     int stackReq;
68     u1* stackPtr;
69 
70     assert(!dvmIsNativeMethod(method));
71     assert(!dvmIsAbstractMethod(method));
72 
73     stackReq = method->registersSize * 4        // params + locals
74                 + sizeof(StackSaveArea) * 2     // break frame + regular frame
75                 + method->outsSize * 4;         // args to other methods
76 
77     if (self->interpSave.curFrame != NULL)
78         stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame);
79     else
80         stackPtr = self->interpStackStart;
81 
82     if (stackPtr - stackReq < self->interpStackEnd) {
83         /* not enough space */
84         ALOGW("Stack overflow on call to interp "
85              "(req=%d top=%p cur=%p size=%d %s.%s)",
86             stackReq, self->interpStackStart, self->interpSave.curFrame,
87             self->interpStackSize, method->clazz->descriptor, method->name);
88         dvmHandleStackOverflow(self, method);
89         assert(dvmCheckException(self));
90         return false;
91     }
92 
93     /*
94      * Shift the stack pointer down, leaving space for the function's
95      * args/registers and save area.
96      */
97     stackPtr -= sizeof(StackSaveArea);
98     breakSaveBlock = (StackSaveArea*)stackPtr;
99     stackPtr -= method->registersSize * 4 + sizeof(StackSaveArea);
100     saveBlock = (StackSaveArea*) stackPtr;
101 
102 #if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
103     /* debug -- memset the new stack, unless we want valgrind's help */
104     memset(stackPtr - (method->outsSize*4), 0xaf, stackReq);
105 #endif
106 #ifdef EASY_GDB
107     breakSaveBlock->prevSave =
108        (StackSaveArea*)FP_FROM_SAVEAREA(self->interpSave.curFrame);
109     saveBlock->prevSave = breakSaveBlock;
110 #endif
111 
112     breakSaveBlock->prevFrame = self->interpSave.curFrame;
113     breakSaveBlock->savedPc = NULL;             // not required
114     breakSaveBlock->xtra.localRefCookie = 0;    // not required
115     breakSaveBlock->method = NULL;
116     saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock);
117     saveBlock->savedPc = NULL;                  // not required
118     saveBlock->xtra.currentPc = NULL;           // not required?
119     saveBlock->method = method;
120 
121     LOGVV("PUSH frame: old=%p new=%p (size=%d)",
122         self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock),
123         (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
124 
125     self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock);
126 
127     return true;
128 }
129 
130 /*
131  * We're calling a JNI native method from an internal VM fuction or
132  * via reflection.  This is also used to create the "fake" native-method
133  * frames at the top of the interpreted stack.
134  *
135  * This actually pushes two frames; the first is a "break" frame.
136  *
137  * The top frame has additional space for JNI local reference tracking.
138  */
dvmPushJNIFrame(Thread * self,const Method * method)139 bool dvmPushJNIFrame(Thread* self, const Method* method)
140 {
141     StackSaveArea* saveBlock;
142     StackSaveArea* breakSaveBlock;
143     int stackReq;
144     u1* stackPtr;
145 
146     assert(dvmIsNativeMethod(method));
147 
148     stackReq = method->registersSize * 4        // params only
149                 + sizeof(StackSaveArea) * 2;    // break frame + regular frame
150 
151     if (self->interpSave.curFrame != NULL)
152         stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame);
153     else
154         stackPtr = self->interpStackStart;
155 
156     if (stackPtr - stackReq < self->interpStackEnd) {
157         /* not enough space */
158         ALOGW("Stack overflow on call to native "
159              "(req=%d top=%p cur=%p size=%d '%s')",
160             stackReq, self->interpStackStart, self->interpSave.curFrame,
161             self->interpStackSize, method->name);
162         dvmHandleStackOverflow(self, method);
163         assert(dvmCheckException(self));
164         return false;
165     }
166 
167     /*
168      * Shift the stack pointer down, leaving space for just the stack save
169      * area for the break frame, then shift down farther for the full frame.
170      * We leave space for the method args, which are copied in later.
171      */
172     stackPtr -= sizeof(StackSaveArea);
173     breakSaveBlock = (StackSaveArea*)stackPtr;
174     stackPtr -= method->registersSize * 4 + sizeof(StackSaveArea);
175     saveBlock = (StackSaveArea*) stackPtr;
176 
177 #if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
178     /* debug -- memset the new stack */
179     memset(stackPtr, 0xaf, stackReq);
180 #endif
181 #ifdef EASY_GDB
182     if (self->interpSave.curFrame == NULL)
183         breakSaveBlock->prevSave = NULL;
184     else {
185         void* fp = FP_FROM_SAVEAREA(self->interpSave.curFrame);
186         breakSaveBlock->prevSave = (StackSaveArea*)fp;
187     }
188     saveBlock->prevSave = breakSaveBlock;
189 #endif
190 
191     breakSaveBlock->prevFrame = self->interpSave.curFrame;
192     breakSaveBlock->savedPc = NULL;             // not required
193     breakSaveBlock->xtra.localRefCookie = 0;    // not required
194     breakSaveBlock->method = NULL;
195     saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock);
196     saveBlock->savedPc = NULL;                  // not required
197     saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
198     saveBlock->method = method;
199 
200     LOGVV("PUSH JNI frame: old=%p new=%p (size=%d)",
201         self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock),
202         (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
203 
204     self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock);
205 
206     return true;
207 }
208 
209 /*
210  * This is used by the JNI PushLocalFrame call.  We push a new frame onto
211  * the stack that has no ins, outs, or locals, and no break frame above it.
212  * It's strictly used for tracking JNI local refs, and will be popped off
213  * by dvmPopFrame if it's not removed explicitly.
214  */
dvmPushLocalFrame(Thread * self,const Method * method)215 bool dvmPushLocalFrame(Thread* self, const Method* method)
216 {
217     StackSaveArea* saveBlock;
218     int stackReq;
219     u1* stackPtr;
220 
221     assert(dvmIsNativeMethod(method));
222 
223     stackReq = sizeof(StackSaveArea);       // regular frame
224 
225     assert(self->interpSave.curFrame != NULL);
226     stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame);
227 
228     if (stackPtr - stackReq < self->interpStackEnd) {
229         /* not enough space; let JNI throw the exception */
230         ALOGW("Stack overflow on PushLocal "
231              "(req=%d top=%p cur=%p size=%d '%s')",
232             stackReq, self->interpStackStart, self->interpSave.curFrame,
233             self->interpStackSize, method->name);
234         dvmHandleStackOverflow(self, method);
235         assert(dvmCheckException(self));
236         return false;
237     }
238 
239     /*
240      * Shift the stack pointer down, leaving space for just the stack save
241      * area for the break frame, then shift down farther for the full frame.
242      */
243     stackPtr -= sizeof(StackSaveArea);
244     saveBlock = (StackSaveArea*) stackPtr;
245 
246 #if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
247     /* debug -- memset the new stack */
248     memset(stackPtr, 0xaf, stackReq);
249 #endif
250 #ifdef EASY_GDB
251     saveBlock->prevSave =
252         (StackSaveArea*)FP_FROM_SAVEAREA(self->interpSave.curFrame);
253 #endif
254 
255     saveBlock->prevFrame = self->interpSave.curFrame;
256     saveBlock->savedPc = NULL;                  // not required
257     saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
258     saveBlock->method = method;
259 
260     LOGVV("PUSH JNI local frame: old=%p new=%p (size=%d)",
261         self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock),
262         (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
263 
264     self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock);
265 
266     return true;
267 }
268 
269 /*
270  * Pop one frame pushed on by JNI PushLocalFrame.
271  *
272  * If we've gone too far, the previous frame is either a break frame or
273  * an interpreted frame.  Either way, the method pointer won't match.
274  */
dvmPopLocalFrame(Thread * self)275 bool dvmPopLocalFrame(Thread* self)
276 {
277     StackSaveArea* saveBlock = SAVEAREA_FROM_FP(self->interpSave.curFrame);
278 
279     assert(!dvmIsBreakFrame((u4*)self->interpSave.curFrame));
280     if (saveBlock->method != SAVEAREA_FROM_FP(saveBlock->prevFrame)->method) {
281         /*
282          * The previous frame doesn't have the same method pointer -- we've
283          * been asked to pop too much.
284          */
285         assert(dvmIsBreakFrame((u4*)saveBlock->prevFrame) ||
286                !dvmIsNativeMethod(
287                        SAVEAREA_FROM_FP(saveBlock->prevFrame)->method));
288         return false;
289     }
290 
291     LOGVV("POP JNI local frame: removing %s, now %s",
292         saveBlock->method->name,
293         SAVEAREA_FROM_FP(saveBlock->prevFrame)->method->name);
294     dvmPopJniLocals(self, saveBlock);
295     self->interpSave.curFrame = saveBlock->prevFrame;
296 
297     return true;
298 }
299 
300 /*
301  * Pop a frame we added.  There should be one method frame and one break
302  * frame.
303  *
304  * If JNI Push/PopLocalFrame calls were mismatched, we might end up
305  * popping multiple method frames before we find the break.
306  *
307  * Returns "false" if there was no frame to pop.
308  */
dvmPopFrame(Thread * self)309 static bool dvmPopFrame(Thread* self)
310 {
311     StackSaveArea* saveBlock;
312 
313     if (self->interpSave.curFrame == NULL)
314         return false;
315 
316     saveBlock = SAVEAREA_FROM_FP(self->interpSave.curFrame);
317     assert(!dvmIsBreakFrame((u4*)self->interpSave.curFrame));
318 
319     /*
320      * Remove everything up to the break frame.  If this was a call into
321      * native code, pop the JNI local references table.
322      */
323     while (saveBlock->prevFrame != NULL && saveBlock->method != NULL) {
324         /* probably a native->native JNI call */
325 
326         if (dvmIsNativeMethod(saveBlock->method)) {
327             LOGVV("Popping JNI stack frame for %s.%s%s",
328                 saveBlock->method->clazz->descriptor,
329                 saveBlock->method->name,
330                 (SAVEAREA_FROM_FP(saveBlock->prevFrame)->method == NULL) ?
331                 "" : " (JNI local)");
332             dvmPopJniLocals(self, saveBlock);
333         }
334 
335         saveBlock = SAVEAREA_FROM_FP(saveBlock->prevFrame);
336     }
337     if (saveBlock->method != NULL) {
338         ALOGE("PopFrame missed the break");
339         assert(false);
340         dvmAbort();     // stack trashed -- nowhere to go in this thread
341     }
342 
343     LOGVV("POP frame: cur=%p new=%p",
344         self->interpSave.curFrame, saveBlock->prevFrame);
345 
346     self->interpSave.curFrame = saveBlock->prevFrame;
347     return true;
348 }
349 
350 /*
351  * Common code for dvmCallMethodV/A and dvmInvokeMethod.
352  *
353  * Pushes a call frame on, advancing self->interpSave.curFrame.
354  */
callPrep(Thread * self,const Method * method,Object * obj,bool checkAccess)355 static ClassObject* callPrep(Thread* self, const Method* method, Object* obj,
356     bool checkAccess)
357 {
358     ClassObject* clazz;
359 
360 #ifndef NDEBUG
361     if (self->status != THREAD_RUNNING) {
362         ALOGW("threadid=%d: status=%d on call to %s.%s -",
363             self->threadId, self->status,
364             method->clazz->descriptor, method->name);
365     }
366 #endif
367 
368     assert(self != NULL);
369     assert(method != NULL);
370 
371     if (obj != NULL)
372         clazz = obj->clazz;
373     else
374         clazz = method->clazz;
375 
376     IF_LOGVV() {
377         char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
378         LOGVV("thread=%d native code calling %s.%s %s", self->threadId,
379             clazz->descriptor, method->name, desc);
380         free(desc);
381     }
382 
383     if (checkAccess) {
384         /* needed for java.lang.reflect.Method.invoke */
385         if (!dvmCheckMethodAccess(dvmGetCaller2Class(self->interpSave.curFrame),
386                 method))
387         {
388             /* note this throws IAException, not IAError */
389             dvmThrowIllegalAccessException("access to method denied");
390             return NULL;
391         }
392     }
393 
394     /*
395      * Push a call frame on.  If there isn't enough room for ins, locals,
396      * outs, and the saved state, it will throw an exception.
397      *
398      * This updates self->interpSave.curFrame.
399      */
400     if (dvmIsNativeMethod(method)) {
401         /* native code calling native code the hard way */
402         if (!dvmPushJNIFrame(self, method)) {
403             assert(dvmCheckException(self));
404             return NULL;
405         }
406     } else {
407         /* native code calling interpreted code */
408         if (!dvmPushInterpFrame(self, method)) {
409             assert(dvmCheckException(self));
410             return NULL;
411         }
412     }
413 
414     return clazz;
415 }
416 
417 /*
418  * Issue a method call.
419  *
420  * Pass in NULL for "obj" on calls to static methods.
421  *
422  * (Note this can't be inlined because it takes a variable number of args.)
423  */
dvmCallMethod(Thread * self,const Method * method,Object * obj,JValue * pResult,...)424 void dvmCallMethod(Thread* self, const Method* method, Object* obj,
425     JValue* pResult, ...)
426 {
427     va_list args;
428     va_start(args, pResult);
429     dvmCallMethodV(self, method, obj, false, pResult, args);
430     va_end(args);
431 }
432 
433 /*
434  * Issue a method call with a variable number of arguments.  We process
435  * the contents of "args" by scanning the method signature.
436  *
437  * Pass in NULL for "obj" on calls to static methods.
438  *
439  * We don't need to take the class as an argument because, in Dalvik,
440  * we don't need to worry about static synchronized methods.
441  */
dvmCallMethodV(Thread * self,const Method * method,Object * obj,bool fromJni,JValue * pResult,va_list args)442 void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
443     bool fromJni, JValue* pResult, va_list args)
444 {
445     const char* desc = &(method->shorty[1]); // [0] is the return type.
446     int verifyCount = 0;
447     ClassObject* clazz;
448     u4* ins;
449 
450     clazz = callPrep(self, method, obj, false);
451     if (clazz == NULL)
452         return;
453 
454     /* "ins" for new frame start at frame pointer plus locals */
455     ins = ((u4*)self->interpSave.curFrame) +
456            (method->registersSize - method->insSize);
457 
458     //ALOGD("  FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);
459 
460     /* put "this" pointer into in0 if appropriate */
461     if (!dvmIsStaticMethod(method)) {
462 #ifdef WITH_EXTRA_OBJECT_VALIDATION
463         assert(obj != NULL && dvmIsHeapAddress(obj));
464 #endif
465         *ins++ = (u4) obj;
466         verifyCount++;
467     }
468 
469     while (*desc != '\0') {
470         switch (*(desc++)) {
471             case 'D': case 'J': {
472                 u8 val = va_arg(args, u8);
473                 memcpy(ins, &val, 8);       // EABI prevents direct store
474                 ins += 2;
475                 verifyCount += 2;
476                 break;
477             }
478             case 'F': {
479                 /* floats were normalized to doubles; convert back */
480                 float f = (float) va_arg(args, double);
481                 *ins++ = dvmFloatToU4(f);
482                 verifyCount++;
483                 break;
484             }
485             case 'L': {     /* 'shorty' descr uses L for all refs, incl array */
486                 void* arg = va_arg(args, void*);
487                 assert(obj == NULL || dvmIsHeapAddress(obj));
488                 jobject argObj = reinterpret_cast<jobject>(arg);
489                 if (fromJni)
490                     *ins++ = (u4) dvmDecodeIndirectRef(self, argObj);
491                 else
492                     *ins++ = (u4) argObj;
493                 verifyCount++;
494                 break;
495             }
496             default: {
497                 /* Z B C S I -- all passed as 32-bit integers */
498                 *ins++ = va_arg(args, u4);
499                 verifyCount++;
500                 break;
501             }
502         }
503     }
504 
505 #ifndef NDEBUG
506     if (verifyCount != method->insSize) {
507         ALOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
508             method->insSize, clazz->descriptor, method->name);
509         assert(false);
510         goto bail;
511     }
512 #endif
513 
514     //dvmDumpThreadStack(dvmThreadSelf());
515 
516     if (dvmIsNativeMethod(method)) {
517         TRACE_METHOD_ENTER(self, method);
518         /*
519          * Because we leave no space for local variables, "curFrame" points
520          * directly at the method arguments.
521          */
522         (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult,
523                               method, self);
524         TRACE_METHOD_EXIT(self, method);
525     } else {
526         dvmInterpret(self, method, pResult);
527     }
528 
529 #ifndef NDEBUG
530 bail:
531 #endif
532     dvmPopFrame(self);
533 }
534 
535 /*
536  * Issue a method call with arguments provided in an array.  We process
537  * the contents of "args" by scanning the method signature.
538  *
539  * The values were likely placed into an uninitialized jvalue array using
540  * the field specifiers, which means that sub-32-bit fields (e.g. short,
541  * boolean) may not have 32 or 64 bits of valid data.  This is different
542  * from the varargs invocation where the C compiler does a widening
543  * conversion when calling a function.  As a result, we have to be a
544  * little more precise when pulling stuff out.
545  *
546  * "args" may be NULL if the method has no arguments.
547  */
dvmCallMethodA(Thread * self,const Method * method,Object * obj,bool fromJni,JValue * pResult,const jvalue * args)548 void dvmCallMethodA(Thread* self, const Method* method, Object* obj,
549     bool fromJni, JValue* pResult, const jvalue* args)
550 {
551     const char* desc = &(method->shorty[1]); // [0] is the return type.
552     int verifyCount = 0;
553     ClassObject* clazz;
554     u4* ins;
555 
556     clazz = callPrep(self, method, obj, false);
557     if (clazz == NULL)
558         return;
559 
560     /* "ins" for new frame start at frame pointer plus locals */
561     ins = ((u4*)self->interpSave.curFrame) +
562         (method->registersSize - method->insSize);
563 
564     /* put "this" pointer into in0 if appropriate */
565     if (!dvmIsStaticMethod(method)) {
566         assert(obj != NULL);
567         *ins++ = (u4) obj;              /* obj is a "real" ref */
568         verifyCount++;
569     }
570 
571     while (*desc != '\0') {
572         switch (*desc++) {
573         case 'D':                       /* 64-bit quantity; have to use */
574         case 'J':                       /*  memcpy() in case of mis-alignment */
575             memcpy(ins, &args->j, 8);
576             ins += 2;
577             verifyCount++;              /* this needs an extra push */
578             break;
579         case 'L':                       /* includes array refs */
580             if (fromJni)
581                 *ins++ = (u4) dvmDecodeIndirectRef(self, args->l);
582             else
583                 *ins++ = (u4) args->l;
584             break;
585         case 'F':
586         case 'I':
587             *ins++ = args->i;           /* full 32 bits */
588             break;
589         case 'S':
590             *ins++ = args->s;           /* 16 bits, sign-extended */
591             break;
592         case 'C':
593             *ins++ = args->c;           /* 16 bits, unsigned */
594             break;
595         case 'B':
596             *ins++ = args->b;           /* 8 bits, sign-extended */
597             break;
598         case 'Z':
599             *ins++ = args->z;           /* 8 bits, zero or non-zero */
600             break;
601         default:
602             ALOGE("Invalid char %c in short signature of %s.%s",
603                 *(desc-1), clazz->descriptor, method->name);
604             assert(false);
605             goto bail;
606         }
607 
608         verifyCount++;
609         args++;
610     }
611 
612 #ifndef NDEBUG
613     if (verifyCount != method->insSize) {
614         ALOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
615             method->insSize, clazz->descriptor, method->name);
616         assert(false);
617         goto bail;
618     }
619 #endif
620 
621     if (dvmIsNativeMethod(method)) {
622         TRACE_METHOD_ENTER(self, method);
623         /*
624          * Because we leave no space for local variables, "curFrame" points
625          * directly at the method arguments.
626          */
627         (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult,
628                               method, self);
629         TRACE_METHOD_EXIT(self, method);
630     } else {
631         dvmInterpret(self, method, pResult);
632     }
633 
634 bail:
635     dvmPopFrame(self);
636 }
637 
throwArgumentTypeMismatch(int argIndex,ClassObject * expected,DataObject * arg)638 static void throwArgumentTypeMismatch(int argIndex, ClassObject* expected, DataObject* arg) {
639     std::string expectedClassName(dvmHumanReadableDescriptor(expected->descriptor));
640     std::string actualClassName = dvmHumanReadableType(arg);
641     dvmThrowExceptionFmt(gDvm.exIllegalArgumentException, "argument %d should have type %s, got %s",
642             argIndex + 1, expectedClassName.c_str(), actualClassName.c_str());
643 }
644 
645 /*
646  * Invoke a method, using the specified arguments and return type, through
647  * one of the reflection interfaces.  Could be a virtual or direct method
648  * (including constructors).  Used for reflection.
649  *
650  * Deals with boxing/unboxing primitives and performs widening conversions.
651  *
652  * "invokeObj" will be null for a static method.
653  *
654  * If the invocation returns with an exception raised, we have to wrap it.
655  */
dvmInvokeMethod(Object * obj,const Method * method,ArrayObject * argList,ArrayObject * params,ClassObject * returnType,bool noAccessCheck)656 Object* dvmInvokeMethod(Object* obj, const Method* method,
657     ArrayObject* argList, ArrayObject* params, ClassObject* returnType,
658     bool noAccessCheck)
659 {
660     ClassObject* clazz;
661     Object* retObj = NULL;
662     Thread* self = dvmThreadSelf();
663     s4* ins;
664     int verifyCount, argListLength;
665     JValue retval;
666     bool needPop = false;
667 
668     /* verify arg count */
669     if (argList != NULL)
670         argListLength = argList->length;
671     else
672         argListLength = 0;
673     if (argListLength != (int) params->length) {
674         dvmThrowExceptionFmt(gDvm.exIllegalArgumentException,
675             "wrong number of arguments; expected %d, got %d",
676             params->length, argListLength);
677         return NULL;
678     }
679 
680     clazz = callPrep(self, method, obj, !noAccessCheck);
681     if (clazz == NULL)
682         return NULL;
683     needPop = true;
684 
685     /* "ins" for new frame start at frame pointer plus locals */
686     ins = ((s4*)self->interpSave.curFrame) +
687         (method->registersSize - method->insSize);
688     verifyCount = 0;
689 
690     //ALOGD("  FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);
691 
692     /* put "this" pointer into in0 if appropriate */
693     if (!dvmIsStaticMethod(method)) {
694         assert(obj != NULL);
695         *ins++ = (s4) obj;
696         verifyCount++;
697     }
698 
699     /*
700      * Copy the args onto the stack.  Primitive types are converted when
701      * necessary, and object types are verified.
702      */
703     DataObject** args = (DataObject**)(void*)argList->contents;
704     ClassObject** types = (ClassObject**)(void*)params->contents;
705     for (int i = 0; i < argListLength; i++) {
706         int width = dvmConvertArgument(*args++, *types++, ins);
707         if (width < 0) {
708             dvmPopFrame(self);      // throw wants to pull PC out of stack
709             needPop = false;
710             throwArgumentTypeMismatch(i, *(types-1), *(args-1));
711             goto bail;
712         }
713 
714         ins += width;
715         verifyCount += width;
716     }
717 
718 #ifndef NDEBUG
719     if (verifyCount != method->insSize) {
720         ALOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
721             method->insSize, clazz->descriptor, method->name);
722         assert(false);
723         goto bail;
724     }
725 #endif
726 
727     if (dvmIsNativeMethod(method)) {
728         TRACE_METHOD_ENTER(self, method);
729         /*
730          * Because we leave no space for local variables, "curFrame" points
731          * directly at the method arguments.
732          */
733         (*method->nativeFunc)((u4*)self->interpSave.curFrame, &retval,
734                               method, self);
735         TRACE_METHOD_EXIT(self, method);
736     } else {
737         dvmInterpret(self, method, &retval);
738     }
739 
740     /*
741      * Pop the frame immediately.  The "wrap" calls below can cause
742      * allocations, and we don't want the GC to walk the now-dead frame.
743      */
744     dvmPopFrame(self);
745     needPop = false;
746 
747     /*
748      * If an exception is raised, wrap and replace.  This is necessary
749      * because the invoked method could have thrown a checked exception
750      * that the caller wasn't prepared for.
751      *
752      * We might be able to do this up in the interpreted code, but that will
753      * leave us with a shortened stack trace in the top-level exception.
754      */
755     if (dvmCheckException(self)) {
756         dvmWrapException("Ljava/lang/reflect/InvocationTargetException;");
757     } else {
758         /*
759          * If this isn't a void method or constructor, convert the return type
760          * to an appropriate object.
761          *
762          * We don't do this when an exception is raised because the value
763          * in "retval" is undefined.
764          */
765         if (returnType != NULL) {
766             retObj = (Object*)dvmBoxPrimitive(retval, returnType);
767             dvmReleaseTrackedAlloc(retObj, NULL);
768         }
769     }
770 
771 bail:
772     if (needPop) {
773         dvmPopFrame(self);
774     }
775     return retObj;
776 }
777 
778 struct LineNumFromPcContext {
779     u4 address;
780     u4 lineNum;
781 };
782 
lineNumForPcCb(void * cnxt,u4 address,u4 lineNum)783 static int lineNumForPcCb(void *cnxt, u4 address, u4 lineNum)
784 {
785     LineNumFromPcContext *pContext = (LineNumFromPcContext *)cnxt;
786 
787     // We know that this callback will be called in
788     // ascending address order, so keep going until we find
789     // a match or we've just gone past it.
790 
791     if (address > pContext->address) {
792         // The line number from the previous positions callback
793         // wil be the final result.
794         return 1;
795     }
796 
797     pContext->lineNum = lineNum;
798 
799     return (address == pContext->address) ? 1 : 0;
800 }
801 
802 /*
803  * Determine the source file line number based on the program counter.
804  * "pc" is an offset, in 16-bit units, from the start of the method's code.
805  *
806  * Returns -1 if no match was found (possibly because the source files were
807  * compiled without "-g", so no line number information is present).
808  * Returns -2 for native methods (as expected in exception traces).
809  */
dvmLineNumFromPC(const Method * method,u4 relPc)810 int dvmLineNumFromPC(const Method* method, u4 relPc)
811 {
812     const DexCode* pDexCode = dvmGetMethodCode(method);
813 
814     if (pDexCode == NULL) {
815         if (dvmIsNativeMethod(method) && !dvmIsAbstractMethod(method))
816             return -2;
817         return -1;      /* can happen for abstract method stub */
818     }
819 
820     LineNumFromPcContext context;
821     memset(&context, 0, sizeof(context));
822     context.address = relPc;
823     // A method with no line number info should return -1
824     context.lineNum = -1;
825 
826     dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile, pDexCode,
827             method->clazz->descriptor,
828             method->prototype.protoIdx,
829             method->accessFlags,
830             lineNumForPcCb, NULL, &context);
831 
832     return context.lineNum;
833 }
834 
835 /*
836  * Compute the frame depth.
837  *
838  * Excludes "break" frames.
839  */
dvmComputeExactFrameDepth(const void * fp)840 int dvmComputeExactFrameDepth(const void* fp)
841 {
842     int count = 0;
843 
844     for ( ; fp != NULL; fp = SAVEAREA_FROM_FP(fp)->prevFrame) {
845         if (!dvmIsBreakFrame((u4*)fp))
846             count++;
847     }
848 
849     return count;
850 }
851 
852 /*
853  * Compute the "vague" frame depth, which is just a pointer subtraction.
854  * The result is NOT an overly generous assessment of the number of
855  * frames; the only meaningful use is to compare against the result of
856  * an earlier invocation.
857  *
858  * Useful for implementing single-step debugger modes, which may need to
859  * call this for every instruction.
860  */
dvmComputeVagueFrameDepth(Thread * thread,const void * fp)861 int dvmComputeVagueFrameDepth(Thread* thread, const void* fp)
862 {
863     const u1* interpStackStart = thread->interpStackStart;
864 
865     assert((u1*) fp >= interpStackStart - thread->interpStackSize);
866     assert((u1*) fp < interpStackStart);
867     return interpStackStart - (u1*) fp;
868 }
869 
870 /*
871  * Get the calling frame.  Pass in the current fp.
872  *
873  * Skip "break" frames and reflection invoke frames.
874  */
dvmGetCallerFP(const void * curFrame)875 void* dvmGetCallerFP(const void* curFrame)
876 {
877     void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
878     StackSaveArea* saveArea;
879 
880 retry:
881     if (dvmIsBreakFrame((u4*)caller)) {
882         /* pop up one more */
883         caller = SAVEAREA_FROM_FP(caller)->prevFrame;
884         if (caller == NULL)
885             return NULL;        /* hit the top */
886 
887         /*
888          * If we got here by java.lang.reflect.Method.invoke(), we don't
889          * want to return Method's class loader.  Shift up one and try
890          * again.
891          */
892         saveArea = SAVEAREA_FROM_FP(caller);
893         if (dvmIsReflectionMethod(saveArea->method)) {
894             caller = saveArea->prevFrame;
895             assert(caller != NULL);
896             goto retry;
897         }
898     }
899 
900     return caller;
901 }
902 
903 /*
904  * Get the caller's class.  Pass in the current fp.
905  *
906  * This is used by e.g. java.lang.Class.
907  */
dvmGetCallerClass(const void * curFrame)908 ClassObject* dvmGetCallerClass(const void* curFrame)
909 {
910     void* caller;
911 
912     caller = dvmGetCallerFP(curFrame);
913     if (caller == NULL)
914         return NULL;
915 
916     return SAVEAREA_FROM_FP(caller)->method->clazz;
917 }
918 
919 /*
920  * Get the caller's caller's class.  Pass in the current fp.
921  *
922  * This is used by e.g. java.lang.Class, which wants to know about the
923  * class loader of the method that called it.
924  */
dvmGetCaller2Class(const void * curFrame)925 ClassObject* dvmGetCaller2Class(const void* curFrame)
926 {
927     void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
928     void* callerCaller;
929 
930     /* at the top? */
931     if (dvmIsBreakFrame((u4*)caller) &&
932         SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
933         return NULL;
934 
935     /* go one more */
936     callerCaller = dvmGetCallerFP(caller);
937     if (callerCaller == NULL)
938         return NULL;
939 
940     return SAVEAREA_FROM_FP(callerCaller)->method->clazz;
941 }
942 
943 /*
944  * Get the caller's caller's caller's class.  Pass in the current fp.
945  *
946  * This is used by e.g. java.lang.Class, which wants to know about the
947  * class loader of the method that called it.
948  */
dvmGetCaller3Class(const void * curFrame)949 ClassObject* dvmGetCaller3Class(const void* curFrame)
950 {
951     void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
952     int i;
953 
954     /* at the top? */
955     if (dvmIsBreakFrame((u4*)caller) &&
956         SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
957         return NULL;
958 
959     /* Walk up two frames if possible. */
960     for (i = 0; i < 2; i++) {
961         caller = dvmGetCallerFP(caller);
962         if (caller == NULL)
963             return NULL;
964     }
965 
966     return SAVEAREA_FROM_FP(caller)->method->clazz;
967 }
968 
969 /*
970  * Fill a flat array of methods that comprise the current interpreter
971  * stack trace.  Pass in the current frame ptr.  Break frames are
972  * skipped, but reflection invocations are not.
973  *
974  * The current frame will be in element 0.
975  */
dvmFillStackTraceArray(const void * fp,const Method ** array,size_t length)976 void dvmFillStackTraceArray(const void* fp, const Method** array, size_t length)
977 {
978     assert(fp != NULL);
979     assert(array != NULL);
980     size_t i = 0;
981     while (fp != NULL) {
982         if (!dvmIsBreakFrame((u4*)fp)) {
983             assert(i < length);
984             array[i++] = SAVEAREA_FROM_FP(fp)->method;
985         }
986         fp = SAVEAREA_FROM_FP(fp)->prevFrame;
987     }
988 }
989 
990 /*
991  * Open up the reserved area and throw an exception.  The reserved area
992  * should only be needed to create and initialize the exception itself.
993  *
994  * If we already opened it and we're continuing to overflow, abort the VM.
995  *
996  * We have to leave the "reserved" area open until the "catch" handler has
997  * finished doing its processing.  This is because the catch handler may
998  * need to resolve classes, which requires calling into the class loader if
999  * the classes aren't already in the "initiating loader" list.
1000  */
dvmHandleStackOverflow(Thread * self,const Method * method)1001 void dvmHandleStackOverflow(Thread* self, const Method* method)
1002 {
1003     /*
1004      * Can we make the reserved area available?
1005      */
1006     if (self->stackOverflowed) {
1007         /*
1008          * Already did, nothing to do but bail.
1009          */
1010         ALOGE("DalvikVM: double-overflow of stack in threadid=%d; aborting",
1011             self->threadId);
1012         dvmDumpThread(self, false);
1013         dvmAbort();
1014     }
1015 
1016     /* open it up to the full range */
1017     ALOGI("threadid=%d: stack overflow on call to %s.%s:%s",
1018         self->threadId,
1019         method->clazz->descriptor, method->name, method->shorty);
1020     StackSaveArea* saveArea = SAVEAREA_FROM_FP(self->interpSave.curFrame);
1021     ALOGI("  method requires %d+%d+%d=%d bytes, fp is %p (%d left)",
1022         method->registersSize * 4, sizeof(StackSaveArea), method->outsSize * 4,
1023         (method->registersSize + method->outsSize) * 4 + sizeof(StackSaveArea),
1024         saveArea, (u1*) saveArea - self->interpStackEnd);
1025     ALOGI("  expanding stack end (%p to %p)", self->interpStackEnd,
1026         self->interpStackStart - self->interpStackSize);
1027     //dvmDumpThread(self, false);
1028     self->interpStackEnd = self->interpStackStart - self->interpStackSize;
1029     self->stackOverflowed = true;
1030 
1031     /*
1032      * If we were trying to throw an exception when the stack overflowed,
1033      * we will blow up when doing the class lookup on StackOverflowError
1034      * because of the pending exception.  So, we clear it and make it
1035      * the cause of the SOE.
1036      */
1037     Object* excep = dvmGetException(self);
1038     if (excep != NULL) {
1039         ALOGW("Stack overflow while throwing exception");
1040         dvmClearException(self);
1041     }
1042     dvmThrowChainedException(gDvm.exStackOverflowError, NULL, excep);
1043 }
1044 
1045 /*
1046  * Reduce the available stack size.  By this point we should have finished
1047  * our overflow processing.
1048  */
dvmCleanupStackOverflow(Thread * self,const Object * exception)1049 void dvmCleanupStackOverflow(Thread* self, const Object* exception)
1050 {
1051     const u1* newStackEnd;
1052 
1053     assert(self->stackOverflowed);
1054 
1055     if (exception->clazz != gDvm.exStackOverflowError) {
1056         /* exception caused during SOE, not the SOE itself */
1057         return;
1058     }
1059 
1060     newStackEnd = (self->interpStackStart - self->interpStackSize)
1061         + STACK_OVERFLOW_RESERVE;
1062     if ((u1*)self->interpSave.curFrame <= newStackEnd) {
1063         ALOGE("Can't shrink stack: curFrame is in reserved area (%p %p)",
1064             self->interpStackEnd, self->interpSave.curFrame);
1065         dvmDumpThread(self, false);
1066         dvmAbort();
1067     }
1068 
1069     self->interpStackEnd = newStackEnd;
1070     self->stackOverflowed = false;
1071 
1072     ALOGI("Shrank stack (to %p, curFrame is %p)", self->interpStackEnd,
1073         self->interpSave.curFrame);
1074 }
1075 
1076 
1077 /*
1078  * Extract the object that is the target of a monitor-enter instruction
1079  * in the top stack frame of "thread".
1080  *
1081  * The other thread might be alive, so this has to work carefully.
1082  *
1083  * The thread list lock must be held.
1084  *
1085  * Returns "true" if we successfully recover the object.  "*pOwner" will
1086  * be NULL if we can't determine the owner for some reason (e.g. race
1087  * condition on ownership transfer).
1088  */
extractMonitorEnterObject(Thread * thread,Object ** pLockObj,Thread ** pOwner)1089 static bool extractMonitorEnterObject(Thread* thread, Object** pLockObj,
1090     Thread** pOwner)
1091 {
1092     void* framePtr = thread->interpSave.curFrame;
1093 
1094     if (framePtr == NULL || dvmIsBreakFrame((u4*)framePtr))
1095         return false;
1096 
1097     const StackSaveArea* saveArea = SAVEAREA_FROM_FP(framePtr);
1098     const Method* method = saveArea->method;
1099     const u2* currentPc = saveArea->xtra.currentPc;
1100 
1101     /* check Method* */
1102     if (!dvmLinearAllocContains(method, sizeof(Method))) {
1103         ALOGD("ExtrMon: method %p not valid", method);
1104         return false;
1105     }
1106 
1107     /* check currentPc */
1108     u4 insnsSize = dvmGetMethodInsnsSize(method);
1109     if (currentPc < method->insns ||
1110         currentPc >= method->insns + insnsSize)
1111     {
1112         ALOGD("ExtrMon: insns %p not valid (%p - %p)",
1113             currentPc, method->insns, method->insns + insnsSize);
1114         return false;
1115     }
1116 
1117     /* check the instruction */
1118     if ((*currentPc & 0xff) != OP_MONITOR_ENTER) {
1119         ALOGD("ExtrMon: insn at %p is not monitor-enter (0x%02x)",
1120             currentPc, *currentPc & 0xff);
1121         return false;
1122     }
1123 
1124     /* get and check the register index */
1125     unsigned int reg = *currentPc >> 8;
1126     if (reg >= method->registersSize) {
1127         ALOGD("ExtrMon: invalid register %d (max %d)",
1128             reg, method->registersSize);
1129         return false;
1130     }
1131 
1132     /* get and check the object in that register */
1133     u4* fp = (u4*) framePtr;
1134     Object* obj = (Object*) fp[reg];
1135     if (obj != NULL && !dvmIsHeapAddress(obj)) {
1136         ALOGD("ExtrMon: invalid object %p at %p[%d]", obj, fp, reg);
1137         return false;
1138     }
1139     *pLockObj = obj;
1140 
1141     /*
1142      * Try to determine the object's lock holder; it's okay if this fails.
1143      *
1144      * We're assuming the thread list lock is already held by this thread.
1145      * If it's not, we may be living dangerously if we have to scan through
1146      * the thread list to find a match.  (The VM will generally be in a
1147      * suspended state when executing here, so this is a minor concern
1148      * unless we're dumping while threads are running, in which case there's
1149      * a good chance of stuff blowing up anyway.)
1150      */
1151     *pOwner = dvmGetObjectLockHolder(obj);
1152 
1153     return true;
1154 }
1155 
printWaitMessage(const DebugOutputTarget * target,const char * detail,Object * obj,Thread * thread)1156 static void printWaitMessage(const DebugOutputTarget* target, const char* detail, Object* obj,
1157         Thread* thread)
1158 {
1159     std::string msg(StringPrintf("  - waiting %s <%p> ", detail, obj));
1160 
1161     if (obj->clazz != gDvm.classJavaLangClass) {
1162         // I(16573)   - waiting on <0xf5feda38> (a java.util.LinkedList)
1163         // I(16573)   - waiting on <0xf5ed54f8> (a java.lang.Class<java.lang.ref.ReferenceQueue>)
1164         msg += "(a " + dvmHumanReadableType(obj) + ")";
1165     }
1166 
1167     if (thread != NULL) {
1168         std::string threadName(dvmGetThreadName(thread));
1169         StringAppendF(&msg, " held by tid=%d (%s)", thread->threadId, threadName.c_str());
1170     }
1171 
1172     dvmPrintDebugMessage(target, "%s\n", msg.c_str());
1173 }
1174 
1175 /*
1176  * Dump stack frames, starting from the specified frame and moving down.
1177  *
1178  * Each frame holds a pointer to the currently executing method, and the
1179  * saved program counter from the caller ("previous" frame).  This means
1180  * we don't have the PC for the current method on the stack, which is
1181  * pretty reasonable since it's in the "PC register" for the VM.  Because
1182  * exceptions need to show the correct line number we actually *do* have
1183  * an updated version in the fame's "xtra.currentPc", but it's unreliable.
1184  *
1185  * Note "framePtr" could be NULL in rare circumstances.
1186  */
dumpFrames(const DebugOutputTarget * target,void * framePtr,Thread * thread)1187 static void dumpFrames(const DebugOutputTarget* target, void* framePtr,
1188     Thread* thread)
1189 {
1190     const StackSaveArea* saveArea;
1191     const Method* method;
1192     int checkCount = 0;
1193     const u2* currentPc = NULL;
1194     bool first = true;
1195 
1196     /*
1197      * We call functions that require us to be holding the thread list lock.
1198      * It's probable that the caller has already done so, but it's not
1199      * guaranteed.  If it's not locked, lock it now.
1200      */
1201     bool needThreadUnlock = dvmTryLockThreadList();
1202 
1203     /*
1204      * The "currentPc" is updated whenever we execute an instruction that
1205      * might throw an exception.  Show it here.
1206      */
1207     if (framePtr != NULL && !dvmIsBreakFrame((u4*)framePtr)) {
1208         saveArea = SAVEAREA_FROM_FP(framePtr);
1209 
1210         if (saveArea->xtra.currentPc != NULL)
1211             currentPc = saveArea->xtra.currentPc;
1212     }
1213 
1214     while (framePtr != NULL) {
1215         saveArea = SAVEAREA_FROM_FP(framePtr);
1216         method = saveArea->method;
1217 
1218         if (dvmIsBreakFrame((u4*)framePtr)) {
1219             //dvmPrintDebugMessage(target, "  (break frame)\n");
1220         } else {
1221             int relPc;
1222 
1223             if (currentPc != NULL)
1224                 relPc = currentPc - saveArea->method->insns;
1225             else
1226                 relPc = -1;
1227 
1228             std::string methodName(dvmHumanReadableMethod(method, false));
1229             if (dvmIsNativeMethod(method)) {
1230                 dvmPrintDebugMessage(target, "  at %s(Native Method)\n",
1231                         methodName.c_str());
1232             } else {
1233                 dvmPrintDebugMessage(target, "  at %s(%s:%s%d)\n",
1234                         methodName.c_str(), dvmGetMethodSourceFile(method),
1235                         (relPc >= 0 && first) ? "~" : "",
1236                         relPc < 0 ? -1 : dvmLineNumFromPC(method, relPc));
1237             }
1238 
1239             if (first) {
1240                 /*
1241                  * Decorate WAIT and MONITOR threads with some detail on
1242                  * the first frame.
1243                  *
1244                  * warning: wait status not stable, even in suspend
1245                  */
1246                 if (thread->status == THREAD_WAIT ||
1247                     thread->status == THREAD_TIMED_WAIT)
1248                 {
1249                     Monitor* mon = thread->waitMonitor;
1250                     Object* obj = dvmGetMonitorObject(mon);
1251                     if (obj != NULL) {
1252                         Thread* joinThread = NULL;
1253                         if (obj->clazz == gDvm.classJavaLangVMThread) {
1254                             joinThread = dvmGetThreadFromThreadObject(obj);
1255                         }
1256                         if (joinThread == NULL) {
1257                             joinThread = dvmGetObjectLockHolder(obj);
1258                         }
1259                         printWaitMessage(target, "on", obj, joinThread);
1260                     }
1261                 } else if (thread->status == THREAD_MONITOR) {
1262                     Object* obj;
1263                     Thread* owner;
1264                     if (extractMonitorEnterObject(thread, &obj, &owner)) {
1265                         printWaitMessage(target, "to lock", obj, owner);
1266                     }
1267                 }
1268             }
1269         }
1270 
1271         /*
1272          * Get saved PC for previous frame.  There's no savedPc in a "break"
1273          * frame, because that represents native or interpreted code
1274          * invoked by the VM.  The saved PC is sitting in the "PC register",
1275          * a local variable on the native stack.
1276          */
1277         currentPc = saveArea->savedPc;
1278 
1279         first = false;
1280 
1281         if (saveArea->prevFrame != NULL && saveArea->prevFrame <= framePtr) {
1282             ALOGW("Warning: loop in stack trace at frame %d (%p -> %p)",
1283                 checkCount, framePtr, saveArea->prevFrame);
1284             break;
1285         }
1286         framePtr = saveArea->prevFrame;
1287 
1288         checkCount++;
1289         if (checkCount > 300) {
1290             dvmPrintDebugMessage(target,
1291                 "  ***** printed %d frames, not showing any more\n",
1292                 checkCount);
1293             break;
1294         }
1295     }
1296 
1297     if (needThreadUnlock) {
1298         dvmUnlockThreadList();
1299     }
1300 }
1301 
1302 
1303 /*
1304  * Dump the stack for the specified thread.
1305  */
dvmDumpThreadStack(const DebugOutputTarget * target,Thread * thread)1306 void dvmDumpThreadStack(const DebugOutputTarget* target, Thread* thread)
1307 {
1308     dumpFrames(target, thread->interpSave.curFrame, thread);
1309 }
1310 
1311 /*
1312  * Dump the stack for the specified thread, which is still running.
1313  *
1314  * This is very dangerous, because stack frames are being pushed on and
1315  * popped off, and if the thread exits we'll be looking at freed memory.
1316  * The plan here is to take a snapshot of the stack and then dump that
1317  * to try to minimize the chances of catching it mid-update.  This should
1318  * work reasonably well on a single-CPU system.
1319  *
1320  * There is a small chance that calling here will crash the VM.
1321  */
dvmDumpRunningThreadStack(const DebugOutputTarget * target,Thread * thread)1322 void dvmDumpRunningThreadStack(const DebugOutputTarget* target, Thread* thread)
1323 {
1324     StackSaveArea* saveArea;
1325     const u1* origStack;
1326     u1* stackCopy = NULL;
1327     int origSize, fpOffset;
1328     void* fp;
1329     int depthLimit = 200;
1330 
1331     if (thread == NULL || thread->interpSave.curFrame == NULL) {
1332         dvmPrintDebugMessage(target,
1333             "DumpRunning: Thread at %p has no curFrame (threadid=%d)\n",
1334             thread, (thread != NULL) ? thread->threadId : 0);
1335         return;
1336     }
1337 
1338     /* wait for a full quantum */
1339     sched_yield();
1340 
1341     /* copy the info we need, then the stack itself */
1342     origSize = thread->interpStackSize;
1343     origStack = (const u1*) thread->interpStackStart - origSize;
1344     stackCopy = (u1*) malloc(origSize);
1345     fpOffset = (u1*) thread->interpSave.curFrame - origStack;
1346     memcpy(stackCopy, origStack, origSize);
1347 
1348     /*
1349      * Run through the stack and rewrite the "prev" pointers.
1350      */
1351     //ALOGI("DR: fpOff=%d (from %p %p)",fpOffset, origStack,
1352     //     thread->interpSave.curFrame);
1353     fp = stackCopy + fpOffset;
1354     while (true) {
1355         int prevOffset;
1356 
1357         if (depthLimit-- < 0) {
1358             /* we're probably screwed */
1359             dvmPrintDebugMessage(target, "DumpRunning: depth limit hit\n");
1360             dvmAbort();
1361         }
1362         saveArea = SAVEAREA_FROM_FP(fp);
1363         if (saveArea->prevFrame == NULL)
1364             break;
1365 
1366         prevOffset = (u1*) saveArea->prevFrame - origStack;
1367         if (prevOffset < 0 || prevOffset > origSize) {
1368             dvmPrintDebugMessage(target,
1369                 "DumpRunning: bad offset found: %d (from %p %p)\n",
1370                 prevOffset, origStack, saveArea->prevFrame);
1371             saveArea->prevFrame = NULL;
1372             break;
1373         }
1374 
1375         saveArea->prevFrame = (u4*)(stackCopy + prevOffset);
1376         fp = saveArea->prevFrame;
1377     }
1378 
1379     /*
1380      * We still need to pass the Thread for some monitor wait stuff.
1381      */
1382     dumpFrames(target, stackCopy + fpOffset, thread);
1383     free(stackCopy);
1384 }
1385 
1386 /*
1387  * Dump the native stack for the specified thread.
1388  */
dvmDumpNativeStack(const DebugOutputTarget * target,pid_t tid)1389 void dvmDumpNativeStack(const DebugOutputTarget* target, pid_t tid)
1390 {
1391 #ifdef HAVE_ANDROID_OS
1392     const size_t MAX_DEPTH = 32;
1393     backtrace_frame_t backtrace[MAX_DEPTH];
1394     ssize_t frames = unwind_backtrace_thread(tid, backtrace, 0, MAX_DEPTH);
1395     if (frames > 0) {
1396         backtrace_symbol_t backtrace_symbols[MAX_DEPTH];
1397         get_backtrace_symbols(backtrace, frames, backtrace_symbols);
1398 
1399         for (size_t i = 0; i < size_t(frames); i++) {
1400             char line[MAX_BACKTRACE_LINE_LENGTH];
1401             format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i],
1402                     line, MAX_BACKTRACE_LINE_LENGTH);
1403             dvmPrintDebugMessage(target, "  %s\n", line);
1404         }
1405 
1406         free_backtrace_symbols(backtrace_symbols, frames);
1407     } else {
1408         dvmPrintDebugMessage(target, "  (native backtrace unavailable)\n");
1409     }
1410 #endif
1411 }
1412