【问题标题】:JVMTI - Get line number from jvmtiFrameInfoJVMTI - 从 jvmtiFrameInfo 获取行号
【发布时间】:2020-06-07 15:35:03
【问题描述】:

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

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

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

感谢任何提示和指点!

【问题讨论】:

    标签: java jvm java-native-interface jvmti


    【解决方案1】:

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

    其实官方的JVM TI示例也做了类似的搜索:

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

    【讨论】:

      【解决方案2】:

      reading 之后更多关于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
      

      并且异常在java第11行字节码索引21处抛出,上面的代码会找到正确的行号。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多