Backtrace is now printed using the VM stack walker. One advantage of this is that it can recognize JIT, trampoline, VM native and JNI frames. JIT frames have different format than native frames - return address is misplaced so the stamdard backtrace() doesn't work with jit frames involved.
Example "mixed" trace: Native and JAVA stack trace: [<08069cd0>] vm native : java/lang/VMClassLoader.getPrimitiveClass(Native Method) [<a7c91aed>] jit : java/lang/Object.clone(Object.java:314) [<a7c9bb34>] jit : java/lang/String.toCharArray(String.java:1631) [<a7c9ba86>] jit : java/io/PrintStream.<clinit>(PrintStream.java:70) [<0806591d>] native : vm_class_init+13f (/home/tomek/projects/jato/jato/vm/class.c:443) [<08069802>] native : <unknown> [<a7c9b985>] jit : java/lang/VMSystem.makeStandardOutputStream(VMSystem.java:197) [<a7c8bfda>] jit : java/lang/System.<clinit>(System.java:86) [<0806591d>] native : vm_class_init+13f (/home/tomek/projects/jato/jato/vm/class.c:443) [<08061f41>] native : <unknown> [<a7c8bedc>] trampoline : java/lang/System.loadLibrary(System.java:591) [<a7c8bf2e>] jit : TestJNI.main(TestJNI.java:23) [<0806894a>] native : main+2b2 (/home/tomek/projects/jato/jato/vm/jato.c:737) Compared with the old backtrace for the same situation: Native stack trace: [<08069cd0>] <unknown> [<a7c91aee>] <unknown> [<0846a900>] <unknown> [<08998e10>] <unknown> [<0896d658>] <unknown> [<08069803>] vm_object_alloc+19 (/home/tomek/projects/jato/jato/vm/object.c:43) [<a7c9b986>] <unknown> [<083010f8>] <unknown> [<082bdaf0>] <unknown> Signed-off-by: Tomek Grabiec <tgrab...@gmail.com> --- arch/x86/backtrace.c | 57 +++++++++++++++++++++++++++++++++++++++---- include/vm/stack-trace.h | 2 + test/vm/Makefile | 5 +++- test/vm/stack-trace-stub.c | 28 +++++++++++++++++++++ vm/stack-trace.c | 53 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 138 insertions(+), 7 deletions(-) diff --git a/arch/x86/backtrace.c b/arch/x86/backtrace.c index 9fd28b4..842ce7a 100644 --- a/arch/x86/backtrace.c +++ b/arch/x86/backtrace.c @@ -34,6 +34,11 @@ #include <stdlib.h> #include <string.h> +#include "vm/die.h" +#include "vm/class.h" +#include "vm/method.h" +#include "vm/stack-trace.h" + /* get REG_EIP from ucontext.h */ #include <ucontext.h> @@ -108,7 +113,7 @@ static bool show_exe_function(void *addr) symbol_start = bfd_asymbol_value(symbol); symbol_offset = (unsigned long) addr - symbol_start; - printf(" [<%08lx>] %s+%llx (%s:%i)\n", (unsigned long) addr, + printf("%s+%llx (%s:%i)\n", function_name, (long long) symbol_offset, filename, line); ret = true; @@ -129,7 +134,7 @@ static void show_function(void *addr) if (show_exe_function(addr)) return; - printf(" [<%08lx> <unknown>]\n", (unsigned long) addr); + printf("<unknown>\n"); } /* Must be inline so this does not change the backtrace. */ @@ -143,13 +148,44 @@ static inline void __show_stack_trace(unsigned long start, unsigned long caller) array[1] = (void *) caller; printf("Native stack trace:\n"); - for (i = start; i < size; i++) + for (i = start; i < size; i++) { + printf(" [<%08lx>] ", (unsigned long) array[i]); show_function(array[i]); + } +} + +static void show_mixed_stack_trace(struct stack_trace_elem *elem) +{ + printf("Native and JAVA stack trace:\n"); + do { + printf(" [<%08lx>] %-10s : ", elem->addr, + stack_trace_elem_type_name(elem->type)); + + if (elem->type != STACK_TRACE_ELEM_TYPE_OTHER) { + print_java_stack_trace_elem(elem); + printf("\n"); + + printf("%-27s"," "); + if (!show_exe_function((void *) elem->addr)) + printf("\r"); + + continue; + } + + show_function((void *) elem->addr); + } while (stack_trace_elem_next(elem) == 0); } void print_trace(void) { - __show_stack_trace(0, 0); + struct stack_trace_elem elem; + + init_stack_trace_elem_current(&elem); + + /* Skip init_stack_trace_elem_current() */ + stack_trace_elem_next(&elem); + + show_mixed_stack_trace(&elem); } static unsigned long get_greg(gregset_t gregs, int reg) @@ -160,6 +196,8 @@ static unsigned long get_greg(gregset_t gregs, int reg) #ifndef CONFIG_X86_64 #define IP_REG REG_EIP +#define BP_REG REG_EBP + #define IP_REG_NAME "EIP" static void show_registers(gregset_t gregs) @@ -187,6 +225,8 @@ static void show_registers(gregset_t gregs) #else #define IP_REG REG_RIP +#define BP_REG REG_RBP + #define IP_REG_NAME "RIP" static void show_registers(gregset_t gregs) @@ -233,9 +273,10 @@ static void show_registers(gregset_t gregs) void print_backtrace_and_die(int sig, siginfo_t *info, void *secret) { ucontext_t *uc = secret; - unsigned long eip, addr; + unsigned long eip, ebp, addr; eip = uc->uc_mcontext.gregs[IP_REG]; + ebp = uc->uc_mcontext.gregs[BP_REG]; addr = (unsigned long) info->si_addr; switch (sig) { @@ -248,6 +289,10 @@ void print_backtrace_and_die(int sig, siginfo_t *info, void *secret) break; }; show_registers(uc->uc_mcontext.gregs); - __show_stack_trace(1, eip); + + struct stack_trace_elem elem; + init_stack_trace_elem(&elem, eip, (void *) ebp); + show_mixed_stack_trace(&elem); + exit(1); } diff --git a/include/vm/stack-trace.h b/include/vm/stack-trace.h index ea070db..7a6cb1f 100644 --- a/include/vm/stack-trace.h +++ b/include/vm/stack-trace.h @@ -143,6 +143,8 @@ int stack_trace_elem_next(struct stack_trace_elem *elem); int stack_trace_elem_next_java(struct stack_trace_elem *elem); int skip_frames_from_class(struct stack_trace_elem *elem, struct vm_class *class); int get_java_stack_trace_depth(struct stack_trace_elem *elem); +void print_java_stack_trace_elem(struct stack_trace_elem *elem); +const char *stack_trace_elem_type_name(enum stack_trace_elem_type type); struct compilation_unit *stack_trace_elem_get_cu(struct stack_trace_elem *elem); struct vm_object *get_java_stack_trace(void); struct vm_object *native_vmthrowable_fill_in_stack_trace(struct vm_object *); diff --git a/test/vm/Makefile b/test/vm/Makefile index d0434d5..b29df2a 100644 --- a/test/vm/Makefile +++ b/test/vm/Makefile @@ -15,7 +15,8 @@ TOPLEVEL_OBJS := \ vm/stack.o \ vm/types.o \ vm/zalloc.o \ - test/libharness/libharness.o + test/libharness/libharness.o \ + test/vm/stack-trace-stub.o TEST_OBJS := \ bitset-test.o \ @@ -28,4 +29,6 @@ TEST_OBJS := \ string-test.o \ types-test.o +CFLAGS += -I ../../arch/mmix/include + include ../../scripts/build/test.mk diff --git a/test/vm/stack-trace-stub.c b/test/vm/stack-trace-stub.c index 4159d4a..37ebc5d 100644 --- a/test/vm/stack-trace-stub.c +++ b/test/vm/stack-trace-stub.c @@ -9,3 +9,31 @@ int vm_enter_jni(void *caller_frame, unsigned long call_site_addr, void vm_leave_jni(void) { } + +void init_stack_trace_elem(struct stack_trace_elem *elem, unsigned long addr, + void *frame) +{ +} + +void init_stack_trace_elem_current(struct stack_trace_elem *elem) +{ +} + +int stack_trace_elem_next(struct stack_trace_elem *elem) +{ + return -1; +} + +int stack_trace_elem_next_java(struct stack_trace_elem *elem) +{ + return -1; +} + +void print_java_stack_trace_elem(struct stack_trace_elem *elem) +{ +} + +const char *stack_trace_elem_type_name(enum stack_trace_elem_type type) +{ + return NULL; +} diff --git a/vm/stack-trace.c b/vm/stack-trace.c index 81ca7aa..1c3418f 100644 --- a/vm/stack-trace.c +++ b/vm/stack-trace.c @@ -423,6 +423,44 @@ static struct vm_object *get_intermediate_stack_trace(void) return array; } +void print_java_stack_trace_elem(struct stack_trace_elem *elem) +{ + struct compilation_unit *cu; + unsigned long bc_offset; + + cu = stack_trace_elem_get_cu(elem); + + struct vm_method *vmm = cu->method; + printf("%s.%s", vmm->class->name, vmm->name); + + if (vm_method_is_native(vmm)) { + printf("(Native Method)"); + return; + } + + if (!vmm->class->source_file_name) { + printf("(Unknown Source)"); + return; + } + + printf("(%s", vmm->class->source_file_name); + + if (elem->type == STACK_TRACE_ELEM_TYPE_TRAMPOLINE) + bc_offset = 0; + else { + bc_offset = native_ptr_to_bytecode_offset(cu, + (unsigned char*)elem->addr); + if (bc_offset == BC_OFFSET_UNKNOWN) + goto out; + } + + int line_no = bytecode_offset_to_line_no(vmm, bc_offset); + printf(":%d", line_no); + + out: + printf(")"); +} + /** * new_stack_trace_element - creates new instance of * java.lang.StackTraceElement for given method and bytecode @@ -784,3 +822,18 @@ struct vm_object *vm_alloc_stack_overflow_error(void) return obj; } + +static char *stack_trace_elem_type_names[] = { + [STACK_TRACE_ELEM_TYPE_JIT] = "jit", + [STACK_TRACE_ELEM_TYPE_VM_NATIVE] = "vm native", + [STACK_TRACE_ELEM_TYPE_JNI] = "jni", + [STACK_TRACE_ELEM_TYPE_OTHER] = "native", + [STACK_TRACE_ELEM_TYPE_TRAMPOLINE] = "trampoline", +}; + +const char *stack_trace_elem_type_name(enum stack_trace_elem_type type) +{ + assert(type >= 0 && type < ARRAY_LEN(stack_trace_elem_type_names)); + + return stack_trace_elem_type_names[type]; +} -- 1.6.0.6 ------------------------------------------------------------------------------ _______________________________________________ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel