OSDN Git Service

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