Commit 863fb7ad authored by Lubomir Bulej's avatar Lubomir Bulej
Browse files

Don't query thread id during debugging to avoid JVM crashes

Calling the thread.getId() function through JNI seems to cause JVM
crashes when runtime debugging is enabled, so we avoid it for now.
parent 71c2d9df
......@@ -120,10 +120,6 @@ static volatile bool jvm_is_initialized;
rdoutput (AGENT_NAME " [%s]: ", __safe_name ((info)->name)); \
rdoutput (args);
#define rdatiprefix(info, args...) \
rdoutput (AGENT_NAME " [%s, %" PRId64 "]: ", __safe_name ((info)->name), (info)->id); \
rdoutput (args);
#define rdaprintf(args...) \
rdexec { \
rdaprefix (args); \
......@@ -134,11 +130,6 @@ static volatile bool jvm_is_initialized;
rdatprefix (info, args); \
}
#define rdatiprintf(info, args...) \
rdexec { \
rdatiprefix (info, args); \
}
// ****************************************************************************
// CLASS FILE LOAD
......@@ -346,55 +337,13 @@ __force_classes (
}
}
static jlong
__thread_id (JNIEnv * jni) {
assert (jni != NULL && jvm_is_started);
static jclass thread_class;
if (thread_class == NULL) {
jclass thread_class_local = (*jni)->FindClass (jni, "java/lang/Thread");
if (thread_class_local == NULL) {
return -1;
}
thread_class = (jclass) (*jni)->NewGlobalRef (jni, thread_class_local);
if (thread_class == NULL) {
return -1;
}
}
//
static jmethodID m_currentThread;
if (m_currentThread == NULL) {
m_currentThread = (*jni)->GetStaticMethodID (jni, thread_class, "currentThread", "()Ljava/lang/Thread;");
if (m_currentThread == NULL) {
return -1;
}
}
jobject thread = (*jni)->CallStaticObjectMethod (jni, thread_class, m_currentThread);
//
static jmethodID m_getId;
if (m_getId == NULL) {
m_getId = (*jni)->GetMethodID (jni, thread_class, "getId", "()J");
if (m_getId == NULL) {
return -1;
}
}
return (thread != NULL) ? (*jni)->CallLongMethod (jni, thread, m_getId) : -1;
}
static char *
__thread_name (jvmtiEnv * jvmti, JNIEnv * jni) {
assert (jvmti != NULL && jvm_is_initialized);
jvmtiThreadInfo info;
jvmtiError error = (*jvmti)->GetThreadInfo (jvmti, NULL, &info);
jvmtiError error = (*jvmti)->GetThreadInfo (jvmti, NULL /* current */, &info);
check_jvmti_error (jvmti, error, "failed to get current thread info");
//
......@@ -411,11 +360,10 @@ __thread_name (jvmtiEnv * jvmti, JNIEnv * jni) {
struct thread_info {
jlong id;
char * name;
};
#define INIT_THREAD_INFO { .id = -1, .name = NULL }
#define INIT_THREAD_INFO { .name = NULL }
static void
......@@ -423,10 +371,6 @@ __thread_info_init (jvmtiEnv * jvmti, JNIEnv * jni, struct thread_info * info) {
if (jvmti != NULL && jvm_is_initialized) {
info->name = __thread_name (jvmti, jni);
}
if (jni != NULL && jvm_is_started) {
info->id = __thread_id (jni);
}
}
......@@ -509,7 +453,7 @@ jvmti_callback_class_file_load (
rdexec {
__thread_info_init (jvmti, jni, &info);
rdatiprefix (
rdatprefix (
&info, "processing %s of classloader %" PRId64 " (%ld bytes)\n",
__safe (class_name), classloader_tag, (long) class_byte_count
);
......@@ -519,7 +463,7 @@ jvmti_callback_class_file_load (
// Avoid instrumenting the bypass check class.
//
if (class_name != NULL && strcmp (class_name, BPC_CLASS_NAME) == 0) {
rdatiprintf (&info, "ignored %s (bypass check class)\n", class_name);
rdatprintf (&info, "ignored %s (bypass check class)\n", class_name);
goto __release_thread_info;
}
......@@ -530,10 +474,10 @@ jvmti_callback_class_file_load (
//
if (agent_config.force_superclass || agent_config.force_interfaces) {
if (jni != NULL) {
rdatiprintf (&info, "forcing lookup of dependent classes for %s\n", __safe (class_name));
rdatprintf (&info, "forcing lookup of dependent classes for %s\n", __safe (class_name));
__force_classes (jni, class_name, class_bytes, class_byte_count);
} else {
rdatiprintf (&info, "VM still primordial, skipping lookup of dependent classes for %s\n", __safe (class_name));
rdatprintf (&info, "VM still primordial, skipping lookup of dependent classes for %s\n", __safe (class_name));
}
}
......@@ -560,12 +504,12 @@ jvmti_callback_class_file_load (
*new_class_byte_count = class_def.class_byte_count;
*new_class_bytes = jvm_class_bytes;
rdatiprintf (
rdatprintf (
&info, "redefined %s (%ld bytes)\n",
__safe (class_name), (long) class_def.class_byte_count
);
} else {
rdatiprintf (&info, "loaded %s (unmodified)\n", __safe (class_name));
rdatprintf (&info, "loaded %s (unmodified)\n", __safe (class_name));
}
__release_thread_info:
......@@ -590,7 +534,7 @@ jvmti_callback_vm_init (jvmtiEnv * jvmti, JNIEnv * jni, jthread UNUSED (thread))
struct thread_info info = INIT_THREAD_INFO;
rdexec {
__thread_info_init (jvmti, jni, &info);
rdatiprefix (&info, "vm_init (the VM has been initialized)\n");
rdatprefix (&info, "vm_init (the VM has been initialized)\n");
}
//
......@@ -600,10 +544,10 @@ jvmti_callback_vm_init (jvmtiEnv * jvmti, JNIEnv * jni, jthread UNUSED (thread))
//
jvmtiClassDefinition * bpc_classdef;
if (agent_config.bypass_mode == BYPASS_MODE_DYNAMIC) {
rdatiprintf (&info, "redefining BypassCheck for dynamic bypass\n");
rdatprintf (&info, "redefining BypassCheck for dynamic bypass\n");
bpc_classdef = &dynamic_BypassCheck_classdef;
} else {
rdatiprintf (&info, "redefining BypassCheck to disable bypass\n");
rdatprintf (&info, "redefining BypassCheck to disable bypass\n");
bpc_classdef = &never_BypassCheck_classdef;
}
......@@ -641,7 +585,7 @@ jvmti_callback_vm_death (jvmtiEnv * jvmti, JNIEnv * jni) {
rdexec {
struct thread_info info = INIT_THREAD_INFO;
__thread_info_init (jvmti, jni, &info);
rdatiprefix (&info, "vm_death (the VM is shutting down)\n");
rdatprefix (&info, "vm_death (the VM is shutting down)\n");
__thread_info_done (jvmti, &info);
}
......
......@@ -66,8 +66,8 @@
* and information about a given thread. The arguments
* are processed using printf(2).
*/
#define common_rdatiprefix(agent_name, info, args...) \
rdoutput (agent_name " [%s, %" PRId64 "]: ", __safe_name ((info)->name), (int64_t) (info)->id); \
#define common_rdatprefix(agent_name, info, args...) \
rdoutput (agent_name " [%s]: ", __safe_name ((info)->name)); \
rdoutput (args);
......@@ -91,8 +91,7 @@
rdoutput (args);
#define rdatprefix(info, args...) \
rdoutput (AGENT_NAME " [%s]: ", __safe_name ((info)->name)); \
rdoutput (args);
common_rdatprefix(AGENT_NAME, info, args);
/**
......@@ -100,10 +99,6 @@
* and information about a given thread. The arguments
* are processed using printf(2).
*/
#define rdatiprefix(info, args...) \
rdoutput (AGENT_NAME " [%s, %" PRId64 "]: ", __safe_name ((info)->name), (info)->id); \
rdoutput (args);
#define rdaprintf(args...) \
rdexec { \
rdaprefix (args); \
......@@ -114,11 +109,6 @@
rdatprefix (info, args); \
}
#define rdatiprintf(info, args...) \
rdexec { \
rdatiprefix (info, args); \
}
// ****************************************************************************
// RUNTIME DEBUGGING MACROS FOR DiSL MODULE
......@@ -153,12 +143,12 @@
disl_rdaprefix (args); \
}
#define disl_rdatiprefix(info, args...) \
common_rdatiprefix ("DISL", info, args);
#define disl_rdatprefix(info, args...) \
common_rdatprefix ("DISL", info, args);
#define disl_rdatiprintf(info, args...) \
#define disl_rdatprintf(info, args...) \
disl_rdexec { \
disl_rdatiprefix (info, args); \
disl_rdatprefix (info, args); \
}
#endif // _DEBUG_H
......@@ -395,54 +395,12 @@ __force_classes (
}
}
static jlong
__thread_id (JNIEnv * jni) {
assert (jni != NULL && jvm_is_started);
static jclass thread_class;
if (thread_class == NULL) {
jclass thread_class_local = (*jni)->FindClass (jni, "java/lang/Thread");
if (thread_class_local == NULL) {
return -1;
}
thread_class = (jclass) (*jni)->NewGlobalRef (jni, thread_class_local);
if (thread_class == NULL) {
return -1;
}
}
//
static jmethodID m_currentThread;
if (m_currentThread == NULL) {
m_currentThread = (*jni)->GetStaticMethodID (jni, thread_class, "currentThread", "()Ljava/lang/Thread;");
if (m_currentThread == NULL) {
return -1;
}
}
jobject thread = (*jni)->CallStaticObjectMethod (jni, thread_class, m_currentThread);
//
static jmethodID m_getId;
if (m_getId == NULL) {
m_getId = (*jni)->GetMethodID (jni, thread_class, "getId", "()J");
if (m_getId == NULL) {
return -1;
}
}
return (thread != NULL) ? (*jni)->CallLongMethod (jni, thread, m_getId) : -1;
}
static char *
__thread_name (jvmtiEnv * jvmti, JNIEnv * jni) {
assert (jvmti != NULL && jvm_is_initialized);
jvmtiThreadInfo info;
jvmtiError error = (*jvmti)->GetThreadInfo (jvmti, NULL, &info);
jvmtiError error = (*jvmti)->GetThreadInfo (jvmti, NULL /* current */, &info);
check_jvmti_error (jvmti, error, "failed to get current thread info");
//
......@@ -458,21 +416,16 @@ __thread_name (jvmtiEnv * jvmti, JNIEnv * jni) {
}
struct thread_info {
jlong id;
char * name;
};
#define INIT_THREAD_INFO { .id = -1, .name = NULL }
#define INIT_THREAD_INFO { .name = NULL }
static void
__thread_info_init (jvmtiEnv * jvmti, JNIEnv * jni, struct thread_info * info) {
if (jvmti != NULL && jvm_is_initialized) {
info->name = __thread_name (jvmti, jni);
}
if (jni != NULL && jvm_is_started) {
info->id = __thread_id (jni);
}
}
static void
......@@ -511,7 +464,7 @@ disl_jvmti_callback_class_file_load (
disl_rdexec {
__thread_info_init (jvmti, jni, &info);
disl_rdatiprefix (
disl_rdatprefix (
&info, "processing %s of classloader %" PRId64 " (%ld bytes)\n",
__safe (class_name), (int64_t) classloader_tag, (long) class_byte_count
);
......@@ -521,7 +474,7 @@ disl_jvmti_callback_class_file_load (
// Avoid instrumenting the bypass check class.
//
if (class_name != NULL && strcmp (class_name, BPC_CLASS_NAME) == 0) {
disl_rdatiprintf (&info, "ignored %s (bypass check class)\n", class_name);
disl_rdatprintf (&info, "ignored %s (bypass check class)\n", class_name);
goto __release_thread_info;
}
......@@ -532,10 +485,10 @@ disl_jvmti_callback_class_file_load (
//
if (agent_config->force_superclass || agent_config->force_interfaces) {
if (jni != NULL) {
disl_rdatiprintf (&info, "forcing lookup of dependent classes for %s\n", __safe (class_name));
disl_rdatprintf (&info, "forcing lookup of dependent classes for %s\n", __safe (class_name));
__force_classes (jni, class_name, class_bytes, class_byte_count);
} else {
disl_rdatiprintf (&info, "VM still primordial, skipping lookup of dependent classes for %s\n", __safe (class_name));
disl_rdatprintf (&info, "VM still primordial, skipping lookup of dependent classes for %s\n", __safe (class_name));
}
}
......@@ -562,12 +515,12 @@ disl_jvmti_callback_class_file_load (
*new_class_byte_count = class_def.class_byte_count;
*new_class_bytes = jvm_class_bytes;
disl_rdatiprintf (
disl_rdatprintf (
&info, "redefined %s (%d bytes)\n",
__safe (class_name), class_def.class_byte_count
);
} else {
disl_rdatiprintf (&info, "loaded %s (unmodified)\n", __safe (class_name));
disl_rdatprintf (&info, "loaded %s (unmodified)\n", __safe (class_name));
}
__release_thread_info:
......@@ -592,7 +545,7 @@ disl_jvmti_callback_vm_init (jvmtiEnv * jvmti, JNIEnv * jni, jthread UNUSED (thr
struct thread_info info = INIT_THREAD_INFO;
disl_rdexec {
__thread_info_init (jvmti, jni, &info);
disl_rdatiprefix (&info, "vm_init (the VM has been initialized)\n");
disl_rdatprefix (&info, "vm_init (the VM has been initialized)\n");
}
//
......@@ -602,10 +555,10 @@ disl_jvmti_callback_vm_init (jvmtiEnv * jvmti, JNIEnv * jni, jthread UNUSED (thr
//
jvmtiClassDefinition * bpc_classdef;
if (agent_config->bypass_mode == BYPASS_MODE_DYNAMIC) {
disl_rdatiprintf (&info, "redefining BypassCheck for dynamic bypass\n");
disl_rdatprintf (&info, "redefining BypassCheck for dynamic bypass\n");
bpc_classdef = &dynamic_BypassCheck_classdef;
} else {
disl_rdatiprintf (&info, "redefining BypassCheck to disable bypass\n");
disl_rdatprintf (&info, "redefining BypassCheck to disable bypass\n");
bpc_classdef = &never_BypassCheck_classdef;
}
......@@ -641,7 +594,7 @@ disl_jvmti_callback_vm_death (jvmtiEnv * jvmti, JNIEnv * jni) {
disl_rdexec {
struct thread_info info = INIT_THREAD_INFO;
__thread_info_init (jvmti, jni, &info);
disl_rdatiprefix (&info, "vm_death (the VM is shutting down)\n");
disl_rdatprefix (&info, "vm_death (the VM is shutting down)\n");
__thread_info_done (jvmti, &info);
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment