diff --git a/vm/include/interpreter_exports.h b/vm/include/interpreter_exports.h index e3a9694..01ec61d 100644 --- a/vm/include/interpreter_exports.h +++ b/vm/include/interpreter_exports.h @@ -30,6 +30,8 @@ typedef struct { FrameHandle* (*interpreter_get_last_frame) (class VM_thread *thread); FrameHandle* (*interpreter_get_prev_frame) (FrameHandle* frame); + Method_Handle (*interpreter_get_frame_method) (FrameHandle* frame); + uint8* (*interpreter_get_frame_bytecode_ptr) (FrameHandle* frame); // 'end' is not inclusive bool (*is_frame_in_native_frame) (struct FrameHandle* frame, void* begin, void* end); diff --git a/vm/interpreter/src/interp_exports.cpp b/vm/interpreter/src/interp_exports.cpp index 719aab9..2b410e7 100644 --- a/vm/interpreter/src/interp_exports.cpp +++ b/vm/interpreter/src/interp_exports.cpp @@ -95,6 +95,8 @@ extern void stack_dump(VM_thread *thread extern FrameHandle* interpreter_get_last_frame(class VM_thread *thread); extern FrameHandle* interpreter_get_prev_frame(FrameHandle* frame); +extern Method_Handle interpreter_get_frame_method(FrameHandle* frame); +extern uint8* interpreter_get_frame_bytecode_ptr(FrameHandle* frame); extern bool is_frame_in_native_frame(FrameHandle* frame, void* begin, void* end); void EXPORT JIT_init(JIT_Handle UNREF h, const char* UNREF name) { @@ -106,6 +108,8 @@ void EXPORT JIT_init(JIT_Handle UNREF h, interpreter->interpreter_get_last_frame = &interpreter_get_last_frame; interpreter->interpreter_get_prev_frame = &interpreter_get_prev_frame; + interpreter->interpreter_get_frame_method = &interpreter_get_frame_method; + interpreter->interpreter_get_frame_bytecode_ptr = &interpreter_get_frame_bytecode_ptr; interpreter->is_frame_in_native_frame = &is_frame_in_native_frame; interpreter->interpreter_ti_enumerate_thread = &interpreter_ti_enumerate_thread; #ifdef _IPF_ @@ -129,7 +133,7 @@ #endif interpreter->stack_dump = &stack_dump; #if defined (PLATFORM_NT) && defined (_DEBUG) - if (!get_boolean_property("vm.assert_dialog", false, VM_PROPERTIES)) + if (!get_boolean_property("vm.assert_dialog", TRUE, VM_PROPERTIES)) { disable_assert_dialogs(); } diff --git a/vm/interpreter/src/interpreter.cpp b/vm/interpreter/src/interpreter.cpp index 9e794ce..bfde4c4 100644 --- a/vm/interpreter/src/interpreter.cpp +++ b/vm/interpreter/src/interpreter.cpp @@ -2416,15 +2416,15 @@ stackDump(FILE * file, StackFrame& frame while(f) { Method *m = f->method; Class *c = m->get_class(); + const char* fname = NULL; int line = -2; - if ( !m->is_native() ) { - int ip = (uint8*)frame.ip - (uint8*)m->get_byte_code_addr(); - line = m->get_line_number((uint16)ip); - } + get_file_and_line(m, f->ip, false, &fname, &line); + const char* filename = fname ? fname : "NULL"; + #ifdef INTERPRETER_DEEP_DEBUG fprintf(file, "%s.%s%s (%s:%i) last bcs: (8 of %i): %s %s %s %s %s %s %s %s", c->name->bytes, m->get_name()->bytes, m->get_descriptor()->bytes, - class_get_source_file_name(c), line, f->n_last_bytecode, + filename, line, f->n_last_bytecode, opcodeNames[f->last_bytecodes[(f->n_last_bytecode-1)&7]], opcodeNames[f->last_bytecodes[(f->n_last_bytecode-2)&7]], opcodeNames[f->last_bytecodes[(f->n_last_bytecode-3)&7]], @@ -2434,9 +2434,8 @@ #ifdef INTERPRETER_DEEP_DEBUG opcodeNames[f->last_bytecodes[(f->n_last_bytecode-7)&7]], opcodeNames[f->last_bytecodes[(f->n_last_bytecode-8)&7]]); #else - const char *filename = class_get_source_file_name(c); fprintf(file, " %s.%s%s (%s:%i)\n", class_get_name(c), m->get_name()->bytes, - m->get_descriptor()->bytes, (filename != NULL ? filename : "NULL"), line); + m->get_descriptor()->bytes, filename, line); #endif f = f->prev; } @@ -2444,12 +2443,12 @@ #endif void stack_dump(VM_thread *thread) { StackFrame *frame = getLastStackFrame(thread); - stackDump(stdout, *frame); + stackDump(stderr, *frame); } void stack_dump() { StackFrame *frame = getLastStackFrame(); - stackDump(stdout, *frame); + stackDump(stderr, *frame); } static inline diff --git a/vm/interpreter/src/interpreter_ti.cpp b/vm/interpreter/src/interpreter_ti.cpp index 2b79678..fa153bf 100644 --- a/vm/interpreter/src/interpreter_ti.cpp +++ b/vm/interpreter/src/interpreter_ti.cpp @@ -519,6 +519,16 @@ FrameHandle* interpreter_get_prev_frame( return (FrameHandle*)(((StackFrame*)frame)->prev); } +Method_Handle interpreter_get_frame_method(FrameHandle* frame) +{ + return (Method_Handle)((StackFrame*)frame)->method; +} + +uint8* interpreter_get_frame_bytecode_ptr(FrameHandle* frame) +{ + return ((StackFrame*)frame)->ip; +} + bool is_frame_in_native_frame(FrameHandle* frame, void* begin, void* end) { return (frame >= begin && frame < end); diff --git a/vm/jitrino/src/vm/drl/DrlJITInterface.cpp b/vm/jitrino/src/vm/drl/DrlJITInterface.cpp index e277e33..ed5485e 100644 --- a/vm/jitrino/src/vm/drl/DrlJITInterface.cpp +++ b/vm/jitrino/src/vm/drl/DrlJITInterface.cpp @@ -86,7 +86,7 @@ #endif Jitrino::Init(jit, name); #if defined (PLATFORM_NT) && defined (_DEBUG) - if (!get_boolean_property("vm.assert_dialog", false, VM_PROPERTIES)) + if (!get_boolean_property("vm.assert_dialog", TRUE, VM_PROPERTIES)) { _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT); diff --git a/vm/vmcore/src/stack/stack_dump.cpp b/vm/vmcore/src/stack/stack_dump.cpp index f983924..bdbb481 100644 --- a/vm/vmcore/src/stack/stack_dump.cpp +++ b/vm/vmcore/src/stack/stack_dump.cpp @@ -29,6 +29,7 @@ #include "class_member.h" #include "stack_trace.h" #include "interpreter_exports.h" #include "cci.h" +#include "m2n.h" #include #ifdef PLATFORM_NT @@ -169,17 +170,10 @@ #else // PLATFORM_NT #endif } -static void st_get_java_method_info(MethodInfo* info, Method* m, void* ip, bool is_ip_past) { - info->file_name = NULL; - info->line = -1; - info->method_name = NULL; - assert(m); - if (m->get_class()->has_source_information() && m->get_class()->get_source_file_name()) { - const char* fname = m->get_class()->get_source_file_name(); - size_t flen = m->get_class()->get_source_file_name_length(); - info->file_name = (char*) STD_MALLOC(flen + 1); - strcpy(info->file_name, fname); - } +static char* construct_java_method_name(Method* m) +{ + if (!m) + return NULL; const char* mname = m->get_name()->bytes; size_t mlen = m->get_name()->len; @@ -188,15 +182,41 @@ static void st_get_java_method_info(Meth const char* descr = m->get_descriptor()->bytes; size_t dlen = m->get_descriptor()->len; - info->method_name = (char*) STD_MALLOC(mlen + clen + dlen + 2); - memcpy(info->method_name, cname, clen); - info->method_name[clen] = '.'; - memcpy(info->method_name + clen + 1, mname, mlen); - memcpy(info->method_name + clen + mlen + 1, descr, dlen); - info->method_name[clen + mlen + dlen + 1] = '\0'; - - const char* f; - get_file_and_line(m, ip, is_ip_past, &f, &info->line); + char* method_name = (char*)STD_MALLOC(mlen + clen + dlen + 2); + if (!method_name) + return NULL; + + char* ptr = method_name; + memcpy(ptr, cname, clen); + ptr += clen; + *ptr++ = '.'; + memcpy(ptr, mname, mlen); + ptr += mlen; + memcpy(ptr, descr, dlen); + ptr[dlen] = '\0'; + + return method_name; +} + +static void st_get_java_method_info(MethodInfo* info, Method* m, void* ip, bool is_ip_past) { + info->method_name = NULL; + info->file_name = NULL; + info->line = -1; + + if (!m || !method_get_class(m)) + return; + + info->method_name = construct_java_method_name(m); + const char* fname = NULL; + get_file_and_line(m, ip, is_ip_past, &fname, &info->line); + + if (fname) + { + size_t fsize = strlen(fname) + 1; + info->file_name = (char*)STD_MALLOC(fsize); + if (info->file_name) + memcpy(info->file_name, fname, fsize); + } } static void st_print_line(int count, MethodInfo* m) { @@ -205,51 +225,185 @@ static void st_print_line(int count, Met m->method_name ? m->method_name : "??", m->file_name ? m->file_name : "??", m->line); - if (m->file_name) { - STD_FREE(m->file_name); - } - if (m->method_name) { + + if (m->method_name) STD_FREE(m->method_name); + + if (m->file_name) + STD_FREE(m->file_name); +} + +void st_print_stack_jit(VM_thread* thread, + native_frame_t* frames, jint num_frames) +{ + jint frame_num = 0; + jint count = 0; + StackIterator* si = NULL; + + if (thread) + si = si_create_from_native(thread); + + while ((si && !si_is_past_end(si)) || frame_num < num_frames) + { + MethodInfo m = {NULL, NULL, 0}; + + if (frame_num < num_frames && frames[frame_num].java_depth < 0) + { + if (native_is_ip_stub(frames[frame_num].ip)) // Generated stub + { + fprintf(stderr, "\t%d: IP is %p\n", + count++, frames[frame_num].ip); + ++frame_num; + continue; + } + + // pure native frame + st_get_c_method_info(&m, frames[frame_num].ip); + st_print_line(count++, &m); + ++frame_num; + continue; + } + + // Java/JNI frame, look into stack iterator + + // If iterator is exhausted + if (si_is_past_end(si) || + (si_is_native(si) && !m2n_get_previous_frame(si_get_m2n(si)))) + break; + + if (si_is_native(si) && frame_num < num_frames) + { + // Print information from native stack trace for JNI frames + st_get_c_method_info(&m, frames[frame_num].ip); + st_print_line(count, &m); + } + else if (si_is_native(si) && frame_num >= num_frames) + { + // Print information about JNI frames from iterator + // when native stack trace is not available + Method* method = m2n_get_method(si_get_m2n(si)); + void* ip = m2n_get_ip(si_get_m2n(si)); + st_get_java_method_info(&m, method, ip, false); + st_print_line(count, &m); + } + else // !si_is_native(si) + { + // Print information about Java method from iterator + Method* method = si_get_code_chunk_info(si)->get_method(); + void* ip = (void*)si_get_ip(si); + CodeChunkInfo* cci = si_get_code_chunk_info(si); + + uint32 inlined_depth = si_get_inline_depth(si); + uint32 offset = (POINTER_SIZE_INT)ip - + (POINTER_SIZE_INT)cci->get_code_block_addr(); + + for (uint32 i = 0; i < inlined_depth; i++) + { + Method *inl_method = + cci->get_jit()->get_inlined_method(cci->get_inline_info(), + offset, i); + st_get_java_method_info(&m, inl_method, NULL, frame_num == 0); + st_print_line(count++, &m); + + if (frame_num < num_frames) + ++frame_num; // Go to the next native frame + } + + st_get_java_method_info(&m, method, ip, frame_num == 0); + st_print_line(count, &m); + } + + ++count; + si_goto_previous(si); + + if (frame_num < num_frames) + ++frame_num; // Go to the next native frame } + + if (si) + si_free(si); } -void st_print_stack(Registers* regs) { - if(interpreter_enabled()) { - interpreter.stack_dump(get_thread_ptr()); - return; +void st_print_stack_interpreter(VM_thread* thread, + native_frame_t* frames, jint num_frames) +{ + FrameHandle* frame = interpreter.interpreter_get_last_frame(thread); + jint frame_num = 0; + jint count = 0; + + while (frame || frame_num < num_frames) + { + MethodInfo m = {NULL, NULL, 0}; + + if (frame_num < num_frames && frames[frame_num].java_depth < 0) + { // pure native frame + st_get_c_method_info(&m, frames[frame_num].ip); + st_print_line(count++, &m); + ++frame_num; + continue; + } + + // Java/JNI frame, look into stack iterator + + Method* method = (Method*)interpreter.interpreter_get_frame_method(frame); + uint8* bc_ptr = interpreter.interpreter_get_frame_bytecode_ptr(frame); + + // Print information from native stack trace + // when method is not available or is native + if (frame_num < num_frames && + (!method || method_is_native(method))) + { + st_get_c_method_info(&m, frames[frame_num].ip); + st_print_line(count, &m); + } + + // Print information about method from iterator + // when is Java method or when native stack trace is not available + if (method && + (!method_is_native(method) || frame_num >= num_frames)) + { + st_get_java_method_info(&m, method, (void*)bc_ptr, false); + st_print_line(count, &m); + } + + ++count; + frame = interpreter.interpreter_get_prev_frame(frame); + + if (frame_num < num_frames) + ++frame_num; // Go to the next native frame } - jint num_frames; - native_frame_t* frames; - num_frames = walk_native_stack_registers(regs, p_TLS_vmthread, -1, NULL); - frames = (native_frame_t*) STD_ALLOCA(sizeof(native_frame_t) * num_frames); - num_frames = walk_native_stack_registers(regs, p_TLS_vmthread, num_frames, frames); - StackIterator* si = si_create_from_native(); +} + +void st_print_stack(Registers* regs) +{ + // We are trying to get native stack trace using walk_native_stack_registers + // function and get corresponding Java methods for stack trace from + // JIT/interpreter stack iterator. + // When native stack trace is not complete (for example, when + // walk_native_stack_registers cannot unwind frames in release build), + // we will use JIT/interpreter stack iterator to complete stack trace. + + VM_thread* thread = get_thread_ptr(); // Can be NULL for pure native thread + native_frame_t* frames = NULL; + + jint num_frames = + walk_native_stack_registers(regs, thread, -1, NULL); + + if (num_frames) + frames = (native_frame_t*)STD_ALLOCA(sizeof(native_frame_t)*num_frames); + + if (num_frames && frames) + walk_native_stack_registers(regs, thread, num_frames, frames); + else + num_frames = 0; // Consider native stack trace empty + fprintf(stderr, "Stack trace:\n"); - for (int i = 0; i < num_frames; i++) { - static int count = 0; - MethodInfo m; - if (frames[i].java_depth == -1 && !native_is_ip_stub(frames[i].ip)) { // Pure native method - st_get_c_method_info(&m, frames[i].ip); - } else if (frames[i].java_depth == -1) { // Generated stub - fprintf(stderr, "\t%d: IP is 0x%08X \n", ++count, (POINTER_SIZE_INT) frames[i].ip); //FIXME: IA32 ONLY - continue; - } else { // Java/JNI native method - CodeChunkInfo* cci = si_get_code_chunk_info(si); - if (!cci) { // JNI native method - st_get_c_method_info(&m, frames[i].ip); - } else { // Java method - uint32 inlined_depth = si_get_inline_depth(si); - uint32 offset = (POINTER_SIZE_INT)si_get_ip(si) - (POINTER_SIZE_INT)cci->get_code_block_addr(); - for (uint32 j = 0; j < inlined_depth; j++) { - Method *real_method = cci->get_jit()->get_inlined_method(cci->get_inline_info(), offset, j); - st_get_java_method_info(&m, real_method, frames[i].ip, 0 == i); - st_print_line(++count, &m); - } - st_get_java_method_info(&m, cci->get_method(), frames[i].ip, 0 == i); - } - si_goto_previous(si); - } - st_print_line(++count, &m); - } + + if(interpreter_enabled() && thread) + st_print_stack_interpreter(thread, frames, num_frames); + else + st_print_stack_jit(thread, frames, num_frames); + fprintf(stderr, "\n"); + fflush(stderr); } diff --git a/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp b/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp index eab4b5d..21e9b82 100644 --- a/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp +++ b/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp @@ -19,7 +19,7 @@ * @version $Revision: 1.1.2.1.4.4 $ */ -#include "clog.h" +#include "cxxlog.h" #include "method_lookup.h" #include "Environment.h" #include "exceptions.h" @@ -102,9 +102,21 @@ static void print_callstack(LPEXCEPTION_ Registers regs; nt_to_vm_context(context, ®s); st_print_stack(®s); - fflush(stderr); } + +static LONG process_crash(LPEXCEPTION_POINTERS nt_exception, const char* msg = NULL) +{ + if (get_boolean_property("vm.assert_dialog", TRUE, VM_PROPERTIES)) + return EXCEPTION_CONTINUE_SEARCH; + + print_state(nt_exception, msg); + print_callstack(nt_exception); + LOGGER_EXIT(-1); + return EXCEPTION_CONTINUE_EXECUTION; +} + + /* * Information about stack */ @@ -338,6 +350,7 @@ static LONG NTAPI vectored_exception_han // delegate "other" cases to default handler if (!in_java && code != STATUS_STACK_OVERFLOW) { + process_crash(nt_exception); context->Eip = saved_eip; return EXCEPTION_CONTINUE_SEARCH; } @@ -415,6 +428,7 @@ static LONG NTAPI vectored_exception_han } default: // unexpected hardware exception occured in java code + process_crash(nt_exception); context->Eip = saved_eip; return EXCEPTION_CONTINUE_SEARCH; }