diff options
| -rw-r--r-- | vm/CheckJni.c | 3 | ||||
| -rw-r--r-- | vm/Dvm.mk | 1 | ||||
| -rw-r--r-- | vm/Globals.h | 1 | ||||
| -rw-r--r-- | vm/Init.c | 13 | ||||
| -rw-r--r-- | vm/Native.c | 111 | ||||
| -rw-r--r-- | vm/Native.h | 8 | ||||
| -rw-r--r-- | vm/arch/x86-atom/Call386ABI.S | 2 | ||||
| -rw-r--r-- | vm/interp/Interp.c | 2 | ||||
| -rw-r--r-- | vm/mterp/c/gotoTargets.c | 22 | ||||
| -rw-r--r-- | vm/mterp/out/InterpC-allstubs.c | 22 | ||||
| -rw-r--r-- | vm/mterp/out/InterpC-portdbg.c | 22 | ||||
| -rw-r--r-- | vm/mterp/out/InterpC-portstd.c | 22 | ||||
| -rw-r--r-- | vm/mterp/out/InterpC-x86-atom.c | 22 | ||||
| -rw-r--r-- | vm/mterp/out/InterpC-x86.c | 22 |
14 files changed, 252 insertions, 21 deletions
diff --git a/vm/CheckJni.c b/vm/CheckJni.c index 3c87eaf99..f4c761e8f 100644 --- a/vm/CheckJni.c +++ b/vm/CheckJni.c @@ -257,7 +257,8 @@ void dvmCheckCallJNIMethod_staticNoRef(const u4* args, JValue* pResult, checkMethodArgsV(_env, _methid, _args, __FUNCTION__) /* - * Print trace message when both "checkJNI" and "verbose:jni" are enabled. + * Prints trace messages when a native method calls a JNI function such as + * NewByteArray. Enabled if both "-Xcheck:jni" and "-verbose:jni" are enabled. */ #define JNI_TRACE(_entry, _hasmeth) \ do { \ @@ -32,6 +32,7 @@ LOCAL_CFLAGS += -Wall -Wextra -Wno-unused-parameter # Optional features. These may impact the size or performance of the VM. # LOCAL_CFLAGS += -DWITH_PROFILER -DWITH_DEBUGGER +#LOCAL_CFLAGS += -DWITH_JNI_TRACE # 0=full cache, 1/2=reduced, 3=no cache LOCAL_CFLAGS += -DDVM_RESOLVER_CACHE=0 diff --git a/vm/Globals.h b/vm/Globals.h index 1c9ca7af9..5817cd037 100644 --- a/vm/Globals.h +++ b/vm/Globals.h @@ -104,6 +104,7 @@ struct DvmGlobals { void (*abortHook)(void); int jniGrefLimit; // 0 means no limit + char* jniTrace; bool reduceSignals; bool noQuitHandler; bool verifyDexChecksum; @@ -111,6 +111,9 @@ static void dvmUsage(const char* progName) dvmFprintf(stderr, " -Xjnigreflimit:N (must be multiple of 100, >= 200)\n"); dvmFprintf(stderr, " -Xjniopts:{warnonly,forcecopy}\n"); +#if defined(WITH_JNI_TRACE) + dvmFprintf(stderr, " -Xjnitrace:substring (eg NativeClass or nativeMethod)\n"); +#endif dvmFprintf(stderr, " -Xdeadlockpredict:{off,warn,err,abort}\n"); dvmFprintf(stderr, " -Xstacktracefile:<filename>\n"); dvmFprintf(stderr, " -Xgc:[no]precise\n"); @@ -176,6 +179,9 @@ static void dvmUsage(const char* progName) #ifdef WITH_JNI_STACK_CHECK " jni_stack_check" #endif +#ifdef WITH_JNI_TRACE + " jni_trace" +#endif #ifdef EASY_GDB " easy_gdb" #endif @@ -886,6 +892,11 @@ static int dvmProcessOptions(int argc, const char* const argv[], } gDvm.jniGrefLimit = lim; +#if defined(WITH_JNI_TRACE) + } else if (strncmp(argv[i], "-Xjnitrace:", 11) == 0) { + gDvm.jniTrace = strdup(argv[i] + 11); +#endif + } else if (strcmp(argv[i], "-Xlog-stdio") == 0) { gDvm.logStdio = true; @@ -1609,6 +1620,8 @@ void dvmShutdown(void) dvmJdwpShutdown(gDvm.jdwpState); free(gDvm.jdwpHost); gDvm.jdwpHost = NULL; + free(gDvm.jniTrace); + gDvm.jniTrace = NULL; free(gDvm.stackTraceFile); gDvm.stackTraceFile = NULL; diff --git a/vm/Native.c b/vm/Native.c index bca45cc62..479fd52e6 100644 --- a/vm/Native.c +++ b/vm/Native.c @@ -815,3 +815,114 @@ static void* lookupSharedLibMethod(const Method* method) return (void*) dvmHashForeach(gDvm.nativeLibs, findMethodInLib, (void*) method); } + + +static void appendValue(char type, const JValue value, char* buf, size_t n, + bool appendComma) +{ + size_t len = strlen(buf); + if (len >= n - 32) { // 32 should be longer than anything we could append. + buf[len - 1] = '.'; + buf[len - 2] = '.'; + buf[len - 3] = '.'; + return; + } + char* p = buf + len; + switch (type) { + case 'B': + if (value.b >= 0 && value.b < 10) { + sprintf(p, "%d", value.b); + } else { + sprintf(p, "0x%x (%d)", value.b, value.b); + } + break; + case 'C': + if (value.c < 0x7f && value.c >= ' ') { + sprintf(p, "U+%x ('%c')", value.c, value.c); + } else { + sprintf(p, "U+%x", value.c); + } + break; + case 'D': + sprintf(p, "%g", value.d); + break; + case 'F': + sprintf(p, "%g", value.f); + break; + case 'I': + sprintf(p, "%d", value.i); + break; + case 'L': + sprintf(p, "0x%x", value.i); + break; + case 'J': + sprintf(p, "%lld", value.j); + break; + case 'S': + sprintf(p, "%d", value.s); + break; + case 'V': + strcpy(p, "void"); + break; + case 'Z': + strcpy(p, value.z ? "true" : "false"); + break; + default: + sprintf(p, "unknown type '%c'", type); + break; + } + + if (appendComma) { + strcat(p, ", "); + } +} + +#define LOGI_NATIVE(...) LOG(LOG_INFO, LOG_TAG "-native", __VA_ARGS__) + +void dvmLogNativeMethodEntry(const Method* method, u4* fp) +{ + char thisString[32] = { 0 }; + u4* sp = &fp[method->registersSize - method->insSize]; + if (!dvmIsStaticMethod(method)) { + sprintf(thisString, "this=0x%08x ", *sp++); + } + + char argsString[128]= { 0 }; + const char* desc = &method->shorty[1]; + while (*desc != '\0') { + char argType = *desc++; + JValue value; + if (argType == 'D' || argType == 'J') { + value.j = dvmGetArgLong(sp, 0); + sp += 2; + } else { + value.i = *sp++; + } + appendValue(argType, value, argsString, sizeof(argsString), + *desc != '\0'); + } + + char* signature = dexProtoCopyMethodDescriptor(&method->prototype); + LOGI_NATIVE("-> %s.%s%s %s(%s)", method->clazz->descriptor, method->name, + signature, thisString, argsString); + free(signature); +} + +void dvmLogNativeMethodExit(const Method* method, Thread* self, + const JValue returnValue) +{ + char* signature = dexProtoCopyMethodDescriptor(&method->prototype); + if (dvmCheckException(self)) { + Object* exception = dvmGetException(self); + LOGI_NATIVE("<- %s.%s%s threw %s", method->clazz->descriptor, + method->name, signature, exception->clazz->descriptor); + } else { + char returnValueString[128] = { 0 }; + char returnType = method->shorty[0]; + appendValue(returnType, returnValue, + returnValueString, sizeof(returnValueString), false); + LOGI_NATIVE("<- %s.%s%s returned %s", method->clazz->descriptor, + method->name, signature, returnValueString); + } + free(signature); +} diff --git a/vm/Native.h b/vm/Native.h index 5b54fc7cb..2887fbdd4 100644 --- a/vm/Native.h +++ b/vm/Native.h @@ -105,4 +105,12 @@ INLINE s8 dvmGetArgLong(const u4* args, int elem) #endif } +/* + * Used to implement -Xjnitrace. + */ +struct Thread; +void dvmLogNativeMethodEntry(const Method* method, u4* newFp); +void dvmLogNativeMethodExit(const Method* method, struct Thread* self, + const JValue retval); + #endif /*_DALVIK_NATIVE*/ diff --git a/vm/arch/x86-atom/Call386ABI.S b/vm/arch/x86-atom/Call386ABI.S index 1146c2d10..db1541e25 100644 --- a/vm/arch/x86-atom/Call386ABI.S +++ b/vm/arch/x86-atom/Call386ABI.S @@ -16,7 +16,7 @@ /* * File: CallABI.S * - * Code: facitliates call to native code C and C++ routines. + * Code: facilitates call to native code C and C++ routines. * */ diff --git a/vm/interp/Interp.c b/vm/interp/Interp.c index e75c91c70..daaf0c0da 100644 --- a/vm/interp/Interp.c +++ b/vm/interp/Interp.c @@ -706,8 +706,8 @@ void dvmDumpRegs(const Method* method, const u4* framePtr, bool inOnly) break; } const char* name = ""; - int j; #if 0 // "locals" structure has changed -- need to rewrite this + int j; DexFile* pDexFile = method->clazz->pDexFile; const DexCode* pDexCode = dvmGetMethodCode(method); int localsSize = dexGetLocalsSize(pDexFile, pDexCode); diff --git a/vm/mterp/c/gotoTargets.c b/vm/mterp/c/gotoTargets.c index c6c118bab..589f974fa 100644 --- a/vm/mterp/c/gotoTargets.c +++ b/vm/mterp/c/gotoTargets.c @@ -507,7 +507,6 @@ GOTO_TARGET(invokeSuperQuick, bool methodCallRange) GOTO_TARGET_END - /* * General handling for return-void, return, and return-wide. Put the * return value in "retval" before jumping here. @@ -735,6 +734,7 @@ GOTO_TARGET(exceptionThrown) GOTO_TARGET_END + /* * General handling for invoke-{virtual,super,direct,static,interface}, * including "quick" variants. @@ -917,8 +917,18 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall, TRACE_METHOD_ENTER(self, methodToCall); #endif - ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor, - methodToCall->name, methodToCall->shorty); +#if defined(WITH_JNI_TRACE) + bool trace = gDvm.jniTrace && + strstr(methodToCall->clazz->descriptor, gDvm.jniTrace); + if (trace) { + dvmLogNativeMethodEntry(methodToCall, newFp); + } + else +#endif + { + ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor, + methodToCall->name, methodToCall->shorty); + } #if defined(WITH_JIT) /* Allow the Jit to end any pending trace building */ @@ -946,6 +956,12 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall, dvmPopJniLocals(self, newSaveArea); self->curFrame = fp; +#if defined(WITH_JNI_TRACE) + if (trace) { + dvmLogNativeMethodExit(methodToCall, self, retval); + } +#endif + /* * If the native code threw an exception, or interpreted code * invoked by the native call threw one and nobody has cleared diff --git a/vm/mterp/out/InterpC-allstubs.c b/vm/mterp/out/InterpC-allstubs.c index 39cd6ba6e..8f7f4ecc9 100644 --- a/vm/mterp/out/InterpC-allstubs.c +++ b/vm/mterp/out/InterpC-allstubs.c @@ -3641,7 +3641,6 @@ GOTO_TARGET(invokeSuperQuick, bool methodCallRange) GOTO_TARGET_END - /* * General handling for return-void, return, and return-wide. Put the * return value in "retval" before jumping here. @@ -3869,6 +3868,7 @@ GOTO_TARGET(exceptionThrown) GOTO_TARGET_END + /* * General handling for invoke-{virtual,super,direct,static,interface}, * including "quick" variants. @@ -4051,8 +4051,18 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall, TRACE_METHOD_ENTER(self, methodToCall); #endif - ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor, - methodToCall->name, methodToCall->shorty); +#if defined(WITH_JNI_TRACE) + bool trace = gDvm.jniTrace && + strstr(methodToCall->clazz->descriptor, gDvm.jniTrace); + if (trace) { + dvmLogNativeMethodEntry(methodToCall, newFp); + } + else +#endif + { + ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor, + methodToCall->name, methodToCall->shorty); + } #if defined(WITH_JIT) /* Allow the Jit to end any pending trace building */ @@ -4080,6 +4090,12 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall, dvmPopJniLocals(self, newSaveArea); self->curFrame = fp; +#if defined(WITH_JNI_TRACE) + if (trace) { + dvmLogNativeMethodExit(methodToCall, self, retval); + } +#endif + /* * If the native code threw an exception, or interpreted code * invoked by the native call threw one and nobody has cleared diff --git a/vm/mterp/out/InterpC-portdbg.c b/vm/mterp/out/InterpC-portdbg.c index 9468b24f7..92b97b0ab 100644 --- a/vm/mterp/out/InterpC-portdbg.c +++ b/vm/mterp/out/InterpC-portdbg.c @@ -3925,7 +3925,6 @@ GOTO_TARGET(invokeSuperQuick, bool methodCallRange) GOTO_TARGET_END - /* * General handling for return-void, return, and return-wide. Put the * return value in "retval" before jumping here. @@ -4153,6 +4152,7 @@ GOTO_TARGET(exceptionThrown) GOTO_TARGET_END + /* * General handling for invoke-{virtual,super,direct,static,interface}, * including "quick" variants. @@ -4335,8 +4335,18 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall, TRACE_METHOD_ENTER(self, methodToCall); #endif - ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor, - methodToCall->name, methodToCall->shorty); +#if defined(WITH_JNI_TRACE) + bool trace = gDvm.jniTrace && + strstr(methodToCall->clazz->descriptor, gDvm.jniTrace); + if (trace) { + dvmLogNativeMethodEntry(methodToCall, newFp); + } + else +#endif + { + ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor, + methodToCall->name, methodToCall->shorty); + } #if defined(WITH_JIT) /* Allow the Jit to end any pending trace building */ @@ -4364,6 +4374,12 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall, dvmPopJniLocals(self, newSaveArea); self->curFrame = fp; +#if defined(WITH_JNI_TRACE) + if (trace) { + dvmLogNativeMethodExit(methodToCall, self, retval); + } +#endif + /* * If the native code threw an exception, or interpreted code * invoked by the native call threw one and nobody has cleared diff --git a/vm/mterp/out/InterpC-portstd.c b/vm/mterp/out/InterpC-portstd.c index 5b0d45b00..9be8a8e16 100644 --- a/vm/mterp/out/InterpC-portstd.c +++ b/vm/mterp/out/InterpC-portstd.c @@ -3664,7 +3664,6 @@ GOTO_TARGET(invokeSuperQuick, bool methodCallRange) GOTO_TARGET_END - /* * General handling for return-void, return, and return-wide. Put the * return value in "retval" before jumping here. @@ -3892,6 +3891,7 @@ GOTO_TARGET(exceptionThrown) GOTO_TARGET_END + /* * General handling for invoke-{virtual,super,direct,static,interface}, * including "quick" variants. @@ -4074,8 +4074,18 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall, TRACE_METHOD_ENTER(self, methodToCall); #endif - ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor, - methodToCall->name, methodToCall->shorty); +#if defined(WITH_JNI_TRACE) + bool trace = gDvm.jniTrace && + strstr(methodToCall->clazz->descriptor, gDvm.jniTrace); + if (trace) { + dvmLogNativeMethodEntry(methodToCall, newFp); + } + else +#endif + { + ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor, + methodToCall->name, methodToCall->shorty); + } #if defined(WITH_JIT) /* Allow the Jit to end any pending trace building */ @@ -4103,6 +4113,12 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall, dvmPopJniLocals(self, newSaveArea); self->curFrame = fp; +#if defined(WITH_JNI_TRACE) + if (trace) { + dvmLogNativeMethodExit(methodToCall, self, retval); + } +#endif + /* * If the native code threw an exception, or interpreted code * invoked by the native call threw one and nobody has cleared diff --git a/vm/mterp/out/InterpC-x86-atom.c b/vm/mterp/out/InterpC-x86-atom.c index 7da241c70..13d05cc22 100644 --- a/vm/mterp/out/InterpC-x86-atom.c +++ b/vm/mterp/out/InterpC-x86-atom.c @@ -1835,7 +1835,6 @@ GOTO_TARGET(invokeSuperQuick, bool methodCallRange) GOTO_TARGET_END - /* * General handling for return-void, return, and return-wide. Put the * return value in "retval" before jumping here. @@ -2063,6 +2062,7 @@ GOTO_TARGET(exceptionThrown) GOTO_TARGET_END + /* * General handling for invoke-{virtual,super,direct,static,interface}, * including "quick" variants. @@ -2245,8 +2245,18 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall, TRACE_METHOD_ENTER(self, methodToCall); #endif - ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor, - methodToCall->name, methodToCall->shorty); +#if defined(WITH_JNI_TRACE) + bool trace = gDvm.jniTrace && + strstr(methodToCall->clazz->descriptor, gDvm.jniTrace); + if (trace) { + dvmLogNativeMethodEntry(methodToCall, newFp); + } + else +#endif + { + ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor, + methodToCall->name, methodToCall->shorty); + } #if defined(WITH_JIT) /* Allow the Jit to end any pending trace building */ @@ -2274,6 +2284,12 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall, dvmPopJniLocals(self, newSaveArea); self->curFrame = fp; +#if defined(WITH_JNI_TRACE) + if (trace) { + dvmLogNativeMethodExit(methodToCall, self, retval); + } +#endif + /* * If the native code threw an exception, or interpreted code * invoked by the native call threw one and nobody has cleared diff --git a/vm/mterp/out/InterpC-x86.c b/vm/mterp/out/InterpC-x86.c index 86fe9729e..142d7c9f0 100644 --- a/vm/mterp/out/InterpC-x86.c +++ b/vm/mterp/out/InterpC-x86.c @@ -1804,7 +1804,6 @@ GOTO_TARGET(invokeSuperQuick, bool methodCallRange) GOTO_TARGET_END - /* * General handling for return-void, return, and return-wide. Put the * return value in "retval" before jumping here. @@ -2032,6 +2031,7 @@ GOTO_TARGET(exceptionThrown) GOTO_TARGET_END + /* * General handling for invoke-{virtual,super,direct,static,interface}, * including "quick" variants. @@ -2214,8 +2214,18 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall, TRACE_METHOD_ENTER(self, methodToCall); #endif - ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor, - methodToCall->name, methodToCall->shorty); +#if defined(WITH_JNI_TRACE) + bool trace = gDvm.jniTrace && + strstr(methodToCall->clazz->descriptor, gDvm.jniTrace); + if (trace) { + dvmLogNativeMethodEntry(methodToCall, newFp); + } + else +#endif + { + ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor, + methodToCall->name, methodToCall->shorty); + } #if defined(WITH_JIT) /* Allow the Jit to end any pending trace building */ @@ -2243,6 +2253,12 @@ GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall, dvmPopJniLocals(self, newSaveArea); self->curFrame = fp; +#if defined(WITH_JNI_TRACE) + if (trace) { + dvmLogNativeMethodExit(methodToCall, self, retval); + } +#endif + /* * If the native code threw an exception, or interpreted code * invoked by the native call threw one and nobody has cleared |
