Home | History | Annotate | Download | only in interp
      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  * We assume the thread list lock is currently 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      * The "currentPc" is updated whenever we execute an instruction that
   1196      * might throw an exception.  Show it here.
   1197      */
   1198     if (framePtr != NULL && !dvmIsBreakFrame(framePtr)) {
   1199         saveArea = SAVEAREA_FROM_FP(framePtr);
   1200 
   1201         if (saveArea->xtra.currentPc != NULL)
   1202             currentPc = saveArea->xtra.currentPc;
   1203     }
   1204 
   1205     while (framePtr != NULL) {
   1206         saveArea = SAVEAREA_FROM_FP(framePtr);
   1207         method = saveArea->method;
   1208 
   1209         if (dvmIsBreakFrame(framePtr)) {
   1210             //dvmPrintDebugMessage(target, "  (break frame)\n");
   1211         } else {
   1212             int relPc;
   1213 
   1214             if (currentPc != NULL)
   1215                 relPc = currentPc - saveArea->method->insns;
   1216             else
   1217                 relPc = -1;
   1218 
   1219             char* className = dvmDescriptorToDot(method->clazz->descriptor);
   1220             if (dvmIsNativeMethod(method))
   1221                 dvmPrintDebugMessage(target,
   1222                     "  at %s.%s(Native Method)\n", className, method->name);
   1223             else {
   1224                 dvmPrintDebugMessage(target,
   1225                     "  at %s.%s(%s:%s%d)\n",
   1226                     className, method->name, dvmGetMethodSourceFile(method),
   1227                     (relPc >= 0 && first) ? "~" : "",
   1228                     relPc < 0 ? -1 : dvmLineNumFromPC(method, relPc));
   1229             }
   1230             free(className);
   1231 
   1232             if (first) {
   1233                 /*
   1234                  * Decorate WAIT and MONITOR threads with some detail on
   1235                  * the first frame.
   1236                  *
   1237                  * warning: wait status not stable, even in suspend
   1238                  */
   1239                 if (thread->status == THREAD_WAIT ||
   1240                     thread->status == THREAD_TIMED_WAIT)
   1241                 {
   1242                     Monitor* mon = thread->waitMonitor;
   1243                     Object* obj = dvmGetMonitorObject(mon);
   1244                     if (obj != NULL) {
   1245                         className = dvmDescriptorToDot(obj->clazz->descriptor);
   1246                         dvmPrintDebugMessage(target,
   1247                             "  - waiting on <%p> (a %s)\n", obj, className);
   1248                         free(className);
   1249                     }
   1250                 } else if (thread->status == THREAD_MONITOR) {
   1251                     Object* obj;
   1252                     Thread* owner;
   1253                     if (extractMonitorEnterObject(thread, &obj, &owner)) {
   1254                         className = dvmDescriptorToDot(obj->clazz->descriptor);
   1255                         if (owner != NULL) {
   1256                             char* threadName = dvmGetThreadName(owner);
   1257                             dvmPrintDebugMessage(target,
   1258                                 "  - waiting to lock <%p> (a %s) held by threadid=%d (%s)\n",
   1259                                 obj, className, owner->threadId, threadName);
   1260                             free(threadName);
   1261                         } else {
   1262                             dvmPrintDebugMessage(target,
   1263                                 "  - waiting to lock <%p> (a %s) held by ???\n",
   1264                                 obj, className);
   1265                         }
   1266                         free(className);
   1267                     }
   1268                 }
   1269             }
   1270         }
   1271 
   1272         /*
   1273          * Get saved PC for previous frame.  There's no savedPc in a "break"
   1274          * frame, because that represents native or interpreted code
   1275          * invoked by the VM.  The saved PC is sitting in the "PC register",
   1276          * a local variable on the native stack.
   1277          */
   1278         currentPc = saveArea->savedPc;
   1279 
   1280         first = false;
   1281 
   1282         if (saveArea->prevFrame != NULL && saveArea->prevFrame <= framePtr) {
   1283             LOGW("Warning: loop in stack trace at frame %d (%p -> %p)\n",
   1284                 checkCount, framePtr, saveArea->prevFrame);
   1285             break;
   1286         }
   1287         framePtr = saveArea->prevFrame;
   1288 
   1289         checkCount++;
   1290         if (checkCount > 300) {
   1291             dvmPrintDebugMessage(target,
   1292                 "  ***** printed %d frames, not showing any more\n",
   1293                 checkCount);
   1294             break;
   1295         }
   1296     }
   1297     dvmPrintDebugMessage(target, "\n");
   1298 }
   1299 
   1300 
   1301 /*
   1302  * Dump the stack for the specified thread.
   1303  */
   1304 void dvmDumpThreadStack(const DebugOutputTarget* target, Thread* thread)
   1305 {
   1306     dumpFrames(target, thread->curFrame, thread);
   1307 }
   1308 
   1309 /*
   1310  * Dump the stack for the specified thread, which is still running.
   1311  *
   1312  * This is very dangerous, because stack frames are being pushed on and
   1313  * popped off, and if the thread exits we'll be looking at freed memory.
   1314  * The plan here is to take a snapshot of the stack and then dump that
   1315  * to try to minimize the chances of catching it mid-update.  This should
   1316  * work reasonably well on a single-CPU system.
   1317  *
   1318  * There is a small chance that calling here will crash the VM.
   1319  */
   1320 void dvmDumpRunningThreadStack(const DebugOutputTarget* target, Thread* thread)
   1321 {
   1322     StackSaveArea* saveArea;
   1323     const u1* origStack;
   1324     u1* stackCopy = NULL;
   1325     int origSize, fpOffset;
   1326     void* fp;
   1327     int depthLimit = 200;
   1328 
   1329     if (thread == NULL || thread->curFrame == NULL) {
   1330         dvmPrintDebugMessage(target,
   1331             "DumpRunning: Thread at %p has no curFrame (threadid=%d)\n",
   1332             thread, (thread != NULL) ? thread->threadId : 0);
   1333         return;
   1334     }
   1335 
   1336     /* wait for a full quantum */
   1337     sched_yield();
   1338 
   1339     /* copy the info we need, then the stack itself */
   1340     origSize = thread->interpStackSize;
   1341     origStack = (const u1*) thread->interpStackStart - origSize;
   1342     stackCopy = (u1*) malloc(origSize);
   1343     fpOffset = (u1*) thread->curFrame - origStack;
   1344     memcpy(stackCopy, origStack, origSize);
   1345 
   1346     /*
   1347      * Run through the stack and rewrite the "prev" pointers.
   1348      */
   1349     //LOGI("DR: fpOff=%d (from %p %p)\n",fpOffset, origStack, thread->curFrame);
   1350     fp = stackCopy + fpOffset;
   1351     while (true) {
   1352         int prevOffset;
   1353 
   1354         if (depthLimit-- < 0) {
   1355             /* we're probably screwed */
   1356             dvmPrintDebugMessage(target, "DumpRunning: depth limit hit\n");
   1357             dvmAbort();
   1358         }
   1359         saveArea = SAVEAREA_FROM_FP(fp);
   1360         if (saveArea->prevFrame == NULL)
   1361             break;
   1362 
   1363         prevOffset = (u1*) saveArea->prevFrame - origStack;
   1364         if (prevOffset < 0 || prevOffset > origSize) {
   1365             dvmPrintDebugMessage(target,
   1366                 "DumpRunning: bad offset found: %d (from %p %p)\n",
   1367                 prevOffset, origStack, saveArea->prevFrame);
   1368             saveArea->prevFrame = NULL;
   1369             break;
   1370         }
   1371 
   1372         saveArea->prevFrame = stackCopy + prevOffset;
   1373         fp = saveArea->prevFrame;
   1374     }
   1375 
   1376     /*
   1377      * We still need to pass the Thread for some monitor wait stuff.
   1378      */
   1379     dumpFrames(target, stackCopy + fpOffset, thread);
   1380     free(stackCopy);
   1381 }
   1382