OSDN Git Service

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