summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--vm/CheckJni.c3
-rw-r--r--vm/Dvm.mk1
-rw-r--r--vm/Globals.h1
-rw-r--r--vm/Init.c13
-rw-r--r--vm/Native.c111
-rw-r--r--vm/Native.h8
-rw-r--r--vm/arch/x86-atom/Call386ABI.S2
-rw-r--r--vm/interp/Interp.c2
-rw-r--r--vm/mterp/c/gotoTargets.c22
-rw-r--r--vm/mterp/out/InterpC-allstubs.c22
-rw-r--r--vm/mterp/out/InterpC-portdbg.c22
-rw-r--r--vm/mterp/out/InterpC-portstd.c22
-rw-r--r--vm/mterp/out/InterpC-x86-atom.c22
-rw-r--r--vm/mterp/out/InterpC-x86.c22
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 { \
diff --git a/vm/Dvm.mk b/vm/Dvm.mk
index 862637519..ba580d05b 100644
--- a/vm/Dvm.mk
+++ b/vm/Dvm.mk
@@ -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;
diff --git a/vm/Init.c b/vm/Init.c
index d900f2513..d73bec789 100644
--- a/vm/Init.c
+++ b/vm/Init.c
@@ -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