/* * Create a flat array of methods that comprise the current interpreter * stack trace. Pass in the current frame ptr. * * Allocates a new array and fills it with method pointers. Break frames * are skipped, but reflection invocations are not. The caller must free * "*pArray". * * The current frame will be in element 0. * * Returns "true" on success, "false" on failure (e.g. malloc failed). */ bool dvmCreateStackTraceArray(const void* fp, const Method*** pArray, int* pLength) { const Method** array; int idx, depth; depth = dvmComputeExactFrameDepth(fp); array = (const Method**) malloc(depth * sizeof(Method*)); if (array == NULL) return false; for (idx = 0; fp != NULL; fp = SAVEAREA_FROM_FP(fp)->prevFrame) { if (!dvmIsBreakFrame(fp)) array[idx++] = SAVEAREA_FROM_FP(fp)->method; } assert(idx == depth); *pArray = array; *pLength = depth; return true; }
/* * Search the method's list of exceptions for a match. * * Returns the offset of the catch block on success, or -1 on failure. */ static int findCatchInMethod(Thread* self, const Method* method, int relPc, ClassObject* excepClass) { /* * Need to clear the exception before entry. Otherwise, dvmResolveClass * might think somebody threw an exception while it was loading a class. */ assert(!dvmCheckException(self)); assert(!dvmIsNativeMethod(method)); LOGVV("findCatchInMethod %s.%s excep=%s depth=%d\n", method->clazz->descriptor, method->name, excepClass->descriptor, dvmComputeExactFrameDepth(self->curFrame)); DvmDex* pDvmDex = method->clazz->pDvmDex; const DexCode* pCode = dvmGetMethodCode(method); DexCatchIterator iterator; if (dexFindCatchHandler(&iterator, pCode, relPc)) { for (;;) { DexCatchHandler* handler = dexCatchIteratorNext(&iterator); if (handler == NULL) { break; } if (handler->typeIdx == kDexNoIndex) { /* catch-all */ LOGV("Match on catch-all block at 0x%02x in %s.%s for %s\n", relPc, method->clazz->descriptor, method->name, excepClass->descriptor); return handler->address; } ClassObject* throwable = dvmDexGetResolvedClass(pDvmDex, handler->typeIdx); if (throwable == NULL) { /* * TODO: this behaves badly if we run off the stack * while trying to throw an exception. The problem is * that, if we're in a class loaded by a class loader, * the call to dvmResolveClass has to ask the class * loader for help resolving any previously-unresolved * classes. If this particular class loader hasn't * resolved StackOverflowError, it will call into * interpreted code, and blow up. * * We currently replace the previous exception with * the StackOverflowError, which means they won't be * catching it *unless* they explicitly catch * StackOverflowError, in which case we'll be unable * to resolve the class referred to by the "catch" * block. * * We end up getting a huge pile of warnings if we do * a simple synthetic test, because this method gets * called on every stack frame up the tree, and it * fails every time. * * This eventually bails out, effectively becoming an * uncatchable exception, so other than the flurry of * warnings it's not really a problem. Still, we could * probably handle this better. */ throwable = dvmResolveClass(method->clazz, handler->typeIdx, true); if (throwable == NULL) { /* * We couldn't find the exception they wanted in * our class files (or, perhaps, the stack blew up * while we were querying a class loader). Cough * up a warning, then move on to the next entry. * Keep the exception status clear. */ LOGW("Could not resolve class ref'ed in exception " "catch list (class index %d, exception %s)\n", handler->typeIdx, (self->exception != NULL) ? self->exception->clazz->descriptor : "(none)"); dvmClearException(self); continue; } } //LOGD("ADDR MATCH, check %s instanceof %s\n", // excepClass->descriptor, pEntry->excepClass->descriptor); if (dvmInstanceof(excepClass, throwable)) { LOGV("Match on catch block at 0x%02x in %s.%s for %s\n", relPc, method->clazz->descriptor, method->name, excepClass->descriptor); return handler->address; } } } LOGV("No matching catch block at 0x%02x in %s for %s\n", relPc, method->name, excepClass->descriptor); return -1; }