8341295: Add some useful debugging APIs to the debug agent
Reviewed-by: amenkov, sspitsyn
This commit is contained in:
parent
a3e23572d5
commit
33e4bfdf91
@ -1652,6 +1652,185 @@ setAgentPropertyValue(JNIEnv *env, char *propertyName, char* propertyValue)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// APIs that can be called when debugging the debug agent
|
||||
|
||||
#define check_jvmti_status(err, msg) \
|
||||
if (err != JVMTI_ERROR_NONE) { \
|
||||
EXIT_ERROR(err, msg); \
|
||||
}
|
||||
|
||||
char*
|
||||
translateThreadState(jint flags) {
|
||||
char str[15 * 20];
|
||||
str[0] = '\0';
|
||||
|
||||
if (flags & JVMTI_THREAD_STATE_ALIVE) {
|
||||
strcat(str, " ALIVE");
|
||||
}
|
||||
if (flags & JVMTI_THREAD_STATE_TERMINATED) {
|
||||
strcat(str, " TERMINATED");
|
||||
}
|
||||
if (flags & JVMTI_THREAD_STATE_RUNNABLE) {
|
||||
strcat(str, " RUNNABLE");
|
||||
}
|
||||
if (flags & JVMTI_THREAD_STATE_WAITING) {
|
||||
strcat(str, " WAITING");
|
||||
}
|
||||
if (flags & JVMTI_THREAD_STATE_WAITING_INDEFINITELY) {
|
||||
strcat(str, " WAITING_INDEFINITELY");
|
||||
}
|
||||
if (flags & JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT) {
|
||||
strcat(str, " WAITING_WITH_TIMEOUT");
|
||||
}
|
||||
if (flags & JVMTI_THREAD_STATE_SLEEPING) {
|
||||
strcat(str, " SLEEPING");
|
||||
}
|
||||
if (flags & JVMTI_THREAD_STATE_IN_OBJECT_WAIT) {
|
||||
strcat(str, " IN_OBJECT_WAIT");
|
||||
}
|
||||
if (flags & JVMTI_THREAD_STATE_PARKED) {
|
||||
strcat(str, " PARKED");
|
||||
}
|
||||
if (flags & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER) {
|
||||
strcat(str, " BLOCKED_ON_MONITOR_ENTER");
|
||||
}
|
||||
if (flags & JVMTI_THREAD_STATE_SUSPENDED) {
|
||||
strcat(str, " SUSPENDED");
|
||||
}
|
||||
if (flags & JVMTI_THREAD_STATE_INTERRUPTED) {
|
||||
strcat(str, " INTERRUPTED");
|
||||
}
|
||||
if (flags & JVMTI_THREAD_STATE_IN_NATIVE) {
|
||||
strcat(str, " IN_NATIVE");
|
||||
}
|
||||
|
||||
if (strlen(str) == 0) {
|
||||
strcpy(str, "<none>");
|
||||
}
|
||||
|
||||
char* tstate = (char*)jvmtiAllocate((int)strlen(str) + 1);
|
||||
strcpy(tstate, str);
|
||||
|
||||
return tstate;
|
||||
}
|
||||
|
||||
char*
|
||||
getThreadName(jthread thread) {
|
||||
jvmtiThreadInfo thr_info;
|
||||
jvmtiError err;
|
||||
|
||||
memset(&thr_info, 0, sizeof(thr_info));
|
||||
err = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo)
|
||||
(gdata->jvmti, thread, &thr_info);
|
||||
if (err == JVMTI_ERROR_WRONG_PHASE || err == JVMTI_ERROR_THREAD_NOT_ALIVE) {
|
||||
return NULL; // VM or target thread completed its work
|
||||
}
|
||||
check_jvmti_status(err, "getThreadName: error in JVMTI GetThreadInfo call");
|
||||
|
||||
char* tname = thr_info.name;
|
||||
if (tname == NULL) {
|
||||
const char* UNNAMED_STR = "<Unnamed thread>";
|
||||
size_t UNNAMED_LEN = strlen(UNNAMED_STR);
|
||||
tname = (char*)jvmtiAllocate((int)UNNAMED_LEN + 1);
|
||||
strcpy(tname, UNNAMED_STR);
|
||||
}
|
||||
return tname;
|
||||
}
|
||||
|
||||
char*
|
||||
getMethodName(jmethodID method) {
|
||||
char* mname = NULL;
|
||||
jvmtiError err;
|
||||
|
||||
err = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodName)
|
||||
(gdata->jvmti, method, &mname, NULL, NULL);
|
||||
check_jvmti_status(err, "getMethodName: error in JVMTI GetMethodName call");
|
||||
|
||||
return mname;
|
||||
}
|
||||
|
||||
static char*
|
||||
get_method_class_name(jmethodID method) {
|
||||
jclass klass = NULL;
|
||||
char* cname = NULL;
|
||||
char* result = NULL;
|
||||
jvmtiError err;
|
||||
|
||||
err = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodDeclaringClass)
|
||||
(gdata->jvmti, method, &klass);
|
||||
check_jvmti_status(err, "get_method_class_name: error in JVMTI GetMethodDeclaringClass");
|
||||
|
||||
err = JVMTI_FUNC_PTR(gdata->jvmti,GetClassSignature)
|
||||
(gdata->jvmti, klass, &cname, NULL);
|
||||
check_jvmti_status(err, "get_method_class_name: error in JVMTI GetClassSignature");
|
||||
|
||||
size_t len = strlen(cname) - 2; // get rid of leading 'L' and trailing ';'
|
||||
result = (char*)jvmtiAllocate((int)len + 1);
|
||||
strncpy(result, cname + 1, len); // skip leading 'L'
|
||||
result[len] = '\0';
|
||||
jvmtiDeallocate((void*)cname);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
print_method(jmethodID method, jint depth) {
|
||||
char* cname = NULL;
|
||||
char* mname = NULL;
|
||||
char* msign = NULL;
|
||||
jvmtiError err;
|
||||
|
||||
cname = get_method_class_name(method);
|
||||
|
||||
err = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodName)
|
||||
(gdata->jvmti, method, &mname, &msign, NULL);
|
||||
check_jvmti_status(err, "print_method: error in JVMTI GetMethodName");
|
||||
|
||||
tty_message("%2d: %s: %s%s", depth, cname, mname, msign);
|
||||
jvmtiDeallocate((void*)cname);
|
||||
jvmtiDeallocate((void*)mname);
|
||||
jvmtiDeallocate((void*)msign);
|
||||
}
|
||||
|
||||
#define MAX_FRAME_COUNT_PRINT_STACK_TRACE 200
|
||||
|
||||
void
|
||||
printStackTrace(jthread thread) {
|
||||
jvmtiFrameInfo frames[MAX_FRAME_COUNT_PRINT_STACK_TRACE];
|
||||
char* tname = getThreadName(thread);
|
||||
jint count = 0;
|
||||
|
||||
jvmtiError err = JVMTI_FUNC_PTR(gdata->jvmti,GetStackTrace)
|
||||
(gdata->jvmti, thread, 0, MAX_FRAME_COUNT_PRINT_STACK_TRACE, frames, &count);
|
||||
check_jvmti_status(err, "printStackTrace: error in JVMTI GetStackTrace");
|
||||
|
||||
tty_message("JVMTI Stack Trace for thread %s: frame count: %d", tname, count);
|
||||
for (int depth = 0; depth < count; depth++) {
|
||||
print_method(frames[depth].method, depth);
|
||||
}
|
||||
jvmtiDeallocate((void*)tname);
|
||||
}
|
||||
|
||||
void
|
||||
printThreadInfo(jthread thread) {
|
||||
jvmtiThreadInfo thread_info;
|
||||
jint thread_state;
|
||||
jvmtiError err;
|
||||
err = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo)
|
||||
(gdata->jvmti, thread, &thread_info);
|
||||
check_jvmti_status(err, "Error in GetThreadInfo");
|
||||
err = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadState)
|
||||
(gdata->jvmti, thread, &thread_state);
|
||||
check_jvmti_status(err, "Error in GetThreadState");
|
||||
const char* state = translateThreadState(thread_state);
|
||||
tty_message("Thread: %p, name: %s, state(%x): %s, attrs: %s %s",
|
||||
thread, thread_info.name, thread_state, state,
|
||||
(isVThread(thread) ? "virtual": "platform"),
|
||||
(thread_info.is_daemon ? "daemon": ""));
|
||||
}
|
||||
|
||||
#endif /* DEBUG*/
|
||||
|
||||
/**
|
||||
* Return property value as JDWP allocated string in UTF8 encoding
|
||||
*/
|
||||
|
@ -386,6 +386,15 @@ jvmtiError allNestedClasses(jclass clazz, jclass **ppnested, jint *pcount);
|
||||
|
||||
void setAgentPropertyValue(JNIEnv *env, char *propertyName, char* propertyValue);
|
||||
|
||||
#ifdef DEBUG
|
||||
// APIs that can be called when debugging the debug agent
|
||||
char* translateThreadState(jint flags);
|
||||
char* getThreadName(jthread thread);
|
||||
char* getMethodName(jmethodID method);
|
||||
void printStackTrace(jthread thread);
|
||||
void printThreadInfo(jthread thread);
|
||||
#endif
|
||||
|
||||
void *jvmtiAllocate(jint numBytes);
|
||||
void jvmtiDeallocate(void *buffer);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user