JVMTI - 从 jvmtiFrameInformation 获取行号



我有以下代码在抛出有效的异常时获取当前堆栈帧位置的行号,但我通过实验而不是通过规范来弄清楚。我只留下了相关的代码。

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返回所有currentMethod行的line_number和相应的start_location。现在我的困惑开始了:为什么我不能将frame.locationGetLineNumberTable返回的start_location相匹配?是否有任何规范这些如何匹配?虽然我的代码似乎有效,但我无法相信这是一个始终有效的解决方案。它向后搜索大于或等于lineNumberEntry.start_location的第一个frame.location

感谢您的任何提示和指点!

你的想法是对的。要按jlocation查找行号,您需要找到start_location最接近且小于或等于jlocationjvmtiLineNumberEntry

实际上,官方的 JVM TI 示例也进行了类似的搜索:

堆跟踪器.c

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");
}

hprof_util.c

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;
}

在阅读了有关jlocation的更多信息后,上面的代码应该适用于所有情况。

jlocation 值表示虚拟机字节码索引,即偏移到方法的虚拟机代码中。

由于一行Java可以生成多行字节代码,因此lineNumberEntry.start_location可以但不必匹配frame.location是有道理的。lineNumberEntry.start_location是 java 代码行的第一个字节码指令。

例如,如果我们有以下行号表:

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 处的 java 行 11 上抛出,上面的代码将找到正确的行号。

相关内容

  • 没有找到相关文章

最新更新