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