/* * Dump stack frames, starting from the specified frame and moving down. * * Each frame holds a pointer to the currently executing method, and the * saved program counter from the caller ("previous" frame). This means * we don't have the PC for the current method on the stack, which is * pretty reasonable since it's in the "PC register" for the VM. Because * exceptions need to show the correct line number we actually *do* have * an updated version in the fame's "xtra.currentPc", but it's unreliable. * * Note "framePtr" could be NULL in rare circumstances. */ static void dumpFrames(const DebugOutputTarget* target, void* framePtr, Thread* thread) { const StackSaveArea* saveArea; const Method* method; int checkCount = 0; const u2* currentPc = NULL; bool first = true; /* * We call functions that require us to be holding the thread list lock. * It's probable that the caller has already done so, but it's not * guaranteed. If it's not locked, lock it now. */ bool needThreadUnlock = dvmTryLockThreadList(); /* * The "currentPc" is updated whenever we execute an instruction that * might throw an exception. Show it here. */ if (framePtr != NULL && !dvmIsBreakFrame((u4*)framePtr)) { saveArea = SAVEAREA_FROM_FP(framePtr); if (saveArea->xtra.currentPc != NULL) currentPc = saveArea->xtra.currentPc; } while (framePtr != NULL) { saveArea = SAVEAREA_FROM_FP(framePtr); method = saveArea->method; if (dvmIsBreakFrame((u4*)framePtr)) { //dvmPrintDebugMessage(target, " (break frame)\n"); } else { int relPc; if (currentPc != NULL) relPc = currentPc - saveArea->method->insns; else relPc = -1; std::string methodName(dvmHumanReadableMethod(method, false)); if (dvmIsNativeMethod(method)) { dvmPrintDebugMessage(target, " at %s(Native Method)\n", methodName.c_str()); } else { dvmPrintDebugMessage(target, " at %s(%s:%s%d)\n", methodName.c_str(), dvmGetMethodSourceFile(method), (relPc >= 0 && first) ? "~" : "", relPc < 0 ? -1 : dvmLineNumFromPC(method, relPc)); } if (first) { /* * Decorate WAIT and MONITOR threads with some detail on * the first frame. * * warning: wait status not stable, even in suspend */ if (thread->status == THREAD_WAIT || thread->status == THREAD_TIMED_WAIT) { Monitor* mon = thread->waitMonitor; Object* obj = dvmGetMonitorObject(mon); if (obj != NULL) { Thread* joinThread = NULL; if (obj->clazz == gDvm.classJavaLangVMThread) { joinThread = dvmGetThreadFromThreadObject(obj); } if (joinThread == NULL) { joinThread = dvmGetObjectLockHolder(obj); } printWaitMessage(target, "on", obj, joinThread); } } else if (thread->status == THREAD_MONITOR) { Object* obj; Thread* owner; if (extractMonitorEnterObject(thread, &obj, &owner)) { printWaitMessage(target, "to lock", obj, owner); } } } } /* * Get saved PC for previous frame. There's no savedPc in a "break" * frame, because that represents native or interpreted code * invoked by the VM. The saved PC is sitting in the "PC register", * a local variable on the native stack. */ currentPc = saveArea->savedPc; first = false; if (saveArea->prevFrame != NULL && saveArea->prevFrame <= framePtr) { ALOGW("Warning: loop in stack trace at frame %d (%p -> %p)", checkCount, framePtr, saveArea->prevFrame); break; } framePtr = saveArea->prevFrame; checkCount++; if (checkCount > 300) { dvmPrintDebugMessage(target, " ***** printed %d frames, not showing any more\n", checkCount); break; } } if (needThreadUnlock) { dvmUnlockThreadList(); } }
/* * Dump stack frames, starting from the specified frame and moving down. * * Each frame holds a pointer to the currently executing method, and the * saved program counter from the caller ("previous" frame). This means * we don't have the PC for the current method on the stack, which is * pretty reasonable since it's in the "PC register" for the VM. Because * exceptions need to show the correct line number we actually *do* have * an updated version in the fame's "xtra.currentPc", but it's unreliable. * * Note "framePtr" could be NULL in rare circumstances. */ static void dumpFrames(const DebugOutputTarget* target, void* framePtr, Thread* thread) { const StackSaveArea* saveArea; const Method* method; int checkCount = 0; const u2* currentPc = NULL; bool first = true; /* * The "currentPc" is updated whenever we execute an instruction that * might throw an exception. Show it here. */ if (framePtr != NULL && !dvmIsBreakFrame(framePtr)) { saveArea = SAVEAREA_FROM_FP(framePtr); if (saveArea->xtra.currentPc != NULL) currentPc = saveArea->xtra.currentPc; } while (framePtr != NULL) { saveArea = SAVEAREA_FROM_FP(framePtr); method = saveArea->method; if (dvmIsBreakFrame(framePtr)) { //dvmPrintDebugMessage(target, " (break frame)\n"); } else { int relPc; if (currentPc != NULL) relPc = currentPc - saveArea->method->insns; else relPc = -1; char* className = dvmDescriptorToDot(method->clazz->descriptor); if (dvmIsNativeMethod(method)) dvmPrintDebugMessage(target, " at %s.%s(Native Method)\n", className, method->name); else { dvmPrintDebugMessage(target, " at %s.%s(%s:%s%d)\n", className, method->name, dvmGetMethodSourceFile(method), (relPc >= 0 && first) ? "~" : "", relPc < 0 ? -1 : dvmLineNumFromPC(method, relPc)); } free(className); if (first) { /* * Decorate WAIT and MONITOR threads with some detail on * the first frame. * * warning: wait status not stable, even in suspend */ if (thread->status == THREAD_WAIT || thread->status == THREAD_TIMED_WAIT) { Monitor* mon = thread->waitMonitor; Object* obj = dvmGetMonitorObject(mon); if (obj != NULL) { className = dvmDescriptorToDot(obj->clazz->descriptor); dvmPrintDebugMessage(target, " - waiting on <%p> (a %s)\n", obj, className); free(className); } } else if (thread->status == THREAD_MONITOR) { Object* obj; Thread* owner; if (extractMonitorEnterObject(thread, &obj, &owner)) { className = dvmDescriptorToDot(obj->clazz->descriptor); if (owner != NULL) { char* threadName = dvmGetThreadName(owner); dvmPrintDebugMessage(target, " - waiting to lock <%p> (a %s) held by threadid=%d (%s)\n", obj, className, owner->threadId, threadName); free(threadName); } else { dvmPrintDebugMessage(target, " - waiting to lock <%p> (a %s) held by ???\n", obj, className); } free(className); } } } } /* * Get saved PC for previous frame. There's no savedPc in a "break" * frame, because that represents native or interpreted code * invoked by the VM. The saved PC is sitting in the "PC register", * a local variable on the native stack. */ currentPc = saveArea->savedPc; first = false; if (saveArea->prevFrame != NULL && saveArea->prevFrame <= framePtr) { LOGW("Warning: loop in stack trace at frame %d (%p -> %p)\n", checkCount, framePtr, saveArea->prevFrame); break; } framePtr = saveArea->prevFrame; checkCount++; if (checkCount > 300) { dvmPrintDebugMessage(target, " ***** printed %d frames, not showing any more\n", checkCount); break; } } dvmPrintDebugMessage(target, "\n"); }