JVMTI - 从 jvmtiFrameInfo 获取行号
JVMTI - Get line number from jvmtiFrameInfo
我有以下代码在抛出异常时获取当前堆栈帧位置的行号,但我是通过试验而不是通过规范弄清楚的。我只留下了相关代码。
int max_frame_count = 50;
jvmtiFrameInfo frames[max_frame_count];
jint count;
(*jvmti_env)->GetStackTrace(jvmti_env, thread, 0, max_frame_count, frames, &count);
for (int loop = 0; loop < count; loop++) {
jvmtiFrameInfo frame = frames[loop];
jmethodID currentMethod = frame.method;
(*jvmti_env)->GetMethodName(jvmti_env, currentMethod, &name_ptr, &signature_ptr, &generic_ptr);
(*jvmti_env)->GetLineNumberTable(jvmti_env, currentMethod, &entry_count_ptr, &table_ptr);
jint lineNumber = -1;
int lineNumberCount;
jlocation prevLocationId = -1;
if (frame.location != -1) {
for (int lineNumberLoop = entry_count_ptr - 1; lineNumberLoop >= 0; lineNumberLoop--) {
jvmtiLineNumberEntry lineNumberEntry = table_ptr[lineNumberLoop];
if (frame.location >= lineNumberEntry.start_location) {
lineNumber = lineNumberEntry.line_number;
break;
}
}
}
}
GetLineNumberTable
returns line_number
和 currentMethod
的所有行对应的 start_location
。现在我的困惑开始于此:为什么我不能将 frame.location
与 GetLineNumberTable
返回的 start_location
相匹配?有没有说明这些如何匹配?虽然我的代码似乎有效,但我无法相信这是一个始终有效的解决方案。它向后搜索大于或等于 lineNumberEntry.start_location
.
的第一个 frame.location
感谢任何提示和指点!
在 reading 之后更多关于 jlocation
上面的代码应该适用于所有情况。
jlocation values represent virtual machine bytecode indices--that is, offsets into the virtual machine code for a method.
由于一行Java可以生成多行字节码,所以lineNumberEntry.start_location
可以但不必匹配frame.location
是有道理的。 lineNumberEntry.start_location
是 java 代码行的第一个字节码指令。
例如,如果我们有以下行号 table:
- line_number: 10, start_location: 10
- line_number: 11, start_location: 18
- line_number: 12, start_location: 22
以及以下字节码:
LINENUMBER 11 L3
18: NEW java/lang/IllegalStateException
19: DUP
20: INVOKESPECIAL java/lang/IllegalStateException.<init> ()V
21: ATHROW
并且在字节码索引 21 的第 11 行 java 抛出异常,上面的代码将找到正确的行号。
你的想法是对的。要按 jlocation
查找行号,您需要找到最接近 start_location
且小于或等于 jlocation
.
的 jvmtiLineNumberEntry
其实官方的JVM TI样本也做了类似的搜索:
error = (*jvmti)->GetLineNumberTable(jvmti, finfo->method, &lineCount, &lineTable);
if ( error == JVMTI_ERROR_NONE ) {
/* Search for line */
lineNumber = lineTable[0].line_number;
for ( i = 1 ; i < lineCount ; i++ ) {
if ( finfo->location < lineTable[i].start_location ) {
break;
}
lineNumber = lineTable[i].line_number;
}
} else if ( error != JVMTI_ERROR_ABSENT_INFORMATION ) {
check_jvmti_error(jvmti, error, "Cannot get method line table");
}
for ( i = start ; i < count ; i++ ) {
if ( location < table[i].start_location ) {
HPROF_ASSERT( ((int)location) < ((int)table[i].start_location) );
break;
}
line_number = table[i].line_number;
}
我有以下代码在抛出异常时获取当前堆栈帧位置的行号,但我是通过试验而不是通过规范弄清楚的。我只留下了相关代码。
int max_frame_count = 50;
jvmtiFrameInfo frames[max_frame_count];
jint count;
(*jvmti_env)->GetStackTrace(jvmti_env, thread, 0, max_frame_count, frames, &count);
for (int loop = 0; loop < count; loop++) {
jvmtiFrameInfo frame = frames[loop];
jmethodID currentMethod = frame.method;
(*jvmti_env)->GetMethodName(jvmti_env, currentMethod, &name_ptr, &signature_ptr, &generic_ptr);
(*jvmti_env)->GetLineNumberTable(jvmti_env, currentMethod, &entry_count_ptr, &table_ptr);
jint lineNumber = -1;
int lineNumberCount;
jlocation prevLocationId = -1;
if (frame.location != -1) {
for (int lineNumberLoop = entry_count_ptr - 1; lineNumberLoop >= 0; lineNumberLoop--) {
jvmtiLineNumberEntry lineNumberEntry = table_ptr[lineNumberLoop];
if (frame.location >= lineNumberEntry.start_location) {
lineNumber = lineNumberEntry.line_number;
break;
}
}
}
}
GetLineNumberTable
returns line_number
和 currentMethod
的所有行对应的 start_location
。现在我的困惑开始于此:为什么我不能将 frame.location
与 GetLineNumberTable
返回的 start_location
相匹配?有没有说明这些如何匹配?虽然我的代码似乎有效,但我无法相信这是一个始终有效的解决方案。它向后搜索大于或等于 lineNumberEntry.start_location
.
frame.location
感谢任何提示和指点!
在 reading 之后更多关于 jlocation
上面的代码应该适用于所有情况。
jlocation values represent virtual machine bytecode indices--that is, offsets into the virtual machine code for a method.
由于一行Java可以生成多行字节码,所以lineNumberEntry.start_location
可以但不必匹配frame.location
是有道理的。 lineNumberEntry.start_location
是 java 代码行的第一个字节码指令。
例如,如果我们有以下行号 table:
- line_number: 10, start_location: 10
- line_number: 11, start_location: 18
- line_number: 12, start_location: 22
以及以下字节码:
LINENUMBER 11 L3
18: NEW java/lang/IllegalStateException
19: DUP
20: INVOKESPECIAL java/lang/IllegalStateException.<init> ()V
21: ATHROW
并且在字节码索引 21 的第 11 行 java 抛出异常,上面的代码将找到正确的行号。
你的想法是对的。要按 jlocation
查找行号,您需要找到最接近 start_location
且小于或等于 jlocation
.
jvmtiLineNumberEntry
其实官方的JVM TI样本也做了类似的搜索:
error = (*jvmti)->GetLineNumberTable(jvmti, finfo->method, &lineCount, &lineTable);
if ( error == JVMTI_ERROR_NONE ) {
/* Search for line */
lineNumber = lineTable[0].line_number;
for ( i = 1 ; i < lineCount ; i++ ) {
if ( finfo->location < lineTable[i].start_location ) {
break;
}
lineNumber = lineTable[i].line_number;
}
} else if ( error != JVMTI_ERROR_ABSENT_INFORMATION ) {
check_jvmti_error(jvmti, error, "Cannot get method line table");
}
for ( i = start ; i < count ; i++ ) {
if ( location < table[i].start_location ) {
HPROF_ASSERT( ((int)location) < ((int)table[i].start_location) );
break;
}
line_number = table[i].line_number;
}