81 lines
3.1 KiB
C
81 lines
3.1 KiB
C
#include "backtrace.h"
|
|
#include "printf.h"
|
|
#include "debug.h"
|
|
#include "find_attribute.h"
|
|
#include "memory_allocator.h"
|
|
#include "native_types_allocate.h"
|
|
#include "vm_instance.h"
|
|
|
|
struct objectref * backtrace_allocate(struct vm * vm)
|
|
{
|
|
struct objectref * objectref = vm_instance_create(vm, "java/lang/Backtrace");
|
|
assert(objectref != nullptr);
|
|
assert(objectref->class_entry->instance_fields_count >= 1);
|
|
|
|
int num_entries = vm->frame_stack.ix;
|
|
struct arrayref * arrayref = prim_array_allocate(vm, (sizeof (struct backtrace_entry)), num_entries);
|
|
arrayref->class_entry = nullptr;
|
|
|
|
struct backtrace_entry * backtrace_entry = (struct backtrace_entry *)&arrayref->u32[0];
|
|
objectref->aref[0] = arrayref;
|
|
|
|
for (int i = (num_entries - 1); i >= 0; i--) {
|
|
struct frame * frame = &vm->frame_stack.frame[i];
|
|
backtrace_entry[i].class_file = frame->class_entry->class_file;
|
|
backtrace_entry[i].method_info = frame->method_info;
|
|
backtrace_entry[i].pc = frame->pc;
|
|
}
|
|
return objectref;
|
|
}
|
|
|
|
static int get_line_number(struct class_file * class_file, struct method_info * method_info, int pc)
|
|
{
|
|
int code_index = find_code_name_index(class_file);
|
|
assert(code_index != 0);
|
|
struct attribute_info * attribute = find_attribute(code_index,
|
|
method_info->attributes_count,
|
|
method_info->attributes);
|
|
assert(attribute != nullptr);
|
|
struct Code_attribute * code_attribute = attribute->code;
|
|
|
|
int linenumbertable_name_index = find_linenumbertable_name_index(class_file);
|
|
struct attribute_info * attribute_info = find_attribute(linenumbertable_name_index,
|
|
code_attribute->attributes_count,
|
|
code_attribute->attributes);
|
|
assert(attribute_info != nullptr);
|
|
int line_number_table_length = attribute_info->line_number_table->line_number_table_length;
|
|
struct line_number_table * line_number_table = attribute_info->line_number_table->line_number_table;
|
|
int line_number = 0;
|
|
for (int i = 0; i < line_number_table_length; i++) {
|
|
if (pc >= line_number_table[i].start_pc) {
|
|
line_number = line_number_table[i].line_number;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
return line_number;
|
|
}
|
|
|
|
void backtrace_print(struct objectref * objectref)
|
|
{
|
|
debugf("backtrace objectref class entry: %p\n", objectref->class_entry);
|
|
|
|
struct arrayref * arrayref = objectref->aref[0];
|
|
struct backtrace_entry * backtrace_entry = (struct backtrace_entry *)&arrayref->u32[0];
|
|
|
|
prints("backtrace:\n");
|
|
for (int i = (arrayref->length - 1); i >= 0; i--) {
|
|
struct backtrace_entry * entry = &backtrace_entry[i];
|
|
prints(" class: ");
|
|
print__class_file__class_name(entry->class_file);
|
|
prints(" method: ");
|
|
print__method_info__method_name(entry->class_file, entry->method_info);
|
|
printc('\n');
|
|
printf(" pc: %3d ", entry->pc);
|
|
int line_number = get_line_number(entry->class_file,
|
|
entry->method_info,
|
|
entry->pc);
|
|
printf(" line_number: %3d\n", line_number);
|
|
}
|
|
}
|