I have the following code to get the line numbers at the current stack frame locations when an exception is thrown that works but I figured it out by experimenting rather than through a specification. I only left the relevant code.
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 the line_number
and the corresponding start_location
for all lines of currentMethod
. Now here is where my confusion starts: Why can't I match frame.location
to a start_location
returned by GetLineNumberTable
? Is there any specification how these match? While my code seems to work, I can't belief that this is a solution that always works. It searches backwards for the first frame.location
that is greater or equal to lineNumberEntry.start_location
.
Thanks for any hints and pointers!
Your idea is right. To find a line number by jlocation
, you need to find jvmtiLineNumberEntry
with the closest start_location
which is less or equal jlocation
.
Actually, the official JVM TI samples do a similar search:
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;
}