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 ec4d00d..e7dea73 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/interp_stack_trace.cpp b/vm/interpreter/src/interp_stack_trace.cpp index 7640ab9..44e9905 100644 --- a/vm/interpreter/src/interp_stack_trace.cpp +++ b/vm/interpreter/src/interp_stack_trace.cpp @@ -140,6 +140,7 @@ interpreter_st_get_trace(VM_thread *p_vm if (method) { stf->method = method; stf->ip = interp_si_get_ip(si); + stf->depth = -1; stf->outdated_this = si->This; assert(stf->outdated_this || method->is_static()); stf++; diff --git a/vm/interpreter/src/interpreter.cpp b/vm/interpreter/src/interpreter.cpp index b84eb69..5db8337 100644 --- a/vm/interpreter/src/interpreter.cpp +++ b/vm/interpreter/src/interpreter.cpp @@ -2418,15 +2418,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 = (int)((uint8*)frame.ip - (uint8*)m->get_byte_code_addr()); - line = m->get_line_number((uint16)ip); - } + get_file_and_line(m, f->ip, false, -1, &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]], @@ -2436,9 +2436,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; } @@ -2446,12 +2445,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..e4b8ded 100644 --- a/vm/interpreter/src/interpreter_ti.cpp +++ b/vm/interpreter/src/interpreter_ti.cpp @@ -513,15 +513,25 @@ FrameHandle* interpreter_get_last_frame( FrameHandle* interpreter_get_prev_frame(FrameHandle* frame) { - if (frame == NULL) - return NULL; + if (frame == NULL) + return NULL; - return (FrameHandle*)(((StackFrame*)frame)->prev); + 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); + return (frame >= begin && frame < end); } ///////////////////////////////// diff --git a/vm/jitrino/src/jet/jet.cpp b/vm/jitrino/src/jet/jet.cpp index 05de246..93e755f 100644 --- a/vm/jitrino/src/jet/jet.cpp +++ b/vm/jitrino/src/jet/jet.cpp @@ -940,6 +940,17 @@ Method_Handle JIT_get_inlined_method(JIT return 0; } +/** + * Inlining is unsupported by Jitrino.JET. + * @return 0 + */ +extern "C" JITEXPORT +uint16 JIT_get_inlined_bc(JIT_Handle jit, InlineInfoPtr ptr, + uint32 offset, uint32 inline_depth) +{ + return 0; +} + extern "C" JITEXPORT Boolean JIT_can_enumerate(JIT_Handle jit, Method_Handle method, NativeCodePtr eip) diff --git a/vm/jitrino/src/vm/drl/DrlJITInterface.cpp b/vm/jitrino/src/vm/drl/DrlJITInterface.cpp index 19e09d5..5fee0c7 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/port/include/clog.h b/vm/port/include/clog.h index 9431d5d..1756468 100644 --- a/vm/port/include/clog.h +++ b/vm/port/include/clog.h @@ -26,6 +26,11 @@ #include #include "logger.h" #include "port_malloc.h" +#define LOGGER_EXIT(code) { \ + shutdown_log_system(); \ + ::exit(code); \ +} + #define DIE2(category, message) { \ const char* formatted = log_printf message; \ log4cxx_from_c(category, DIE, formatted, __FILE__, __LOG4CXX_FUNC__, __LINE__); \ diff --git a/vm/vmcore/include/dll_jit_intf.h b/vm/vmcore/include/dll_jit_intf.h index 9252f60..b7cd1dd 100644 --- a/vm/vmcore/include/dll_jit_intf.h +++ b/vm/vmcore/include/dll_jit_intf.h @@ -134,6 +134,17 @@ public: return NULL; } + uint16 + get_inlined_bc(InlineInfoPtr ptr, + uint32 offset, + uint32 inline_depth) + { + if (_get_inlined_bc != NULL) { + return _get_inlined_bc(this, ptr, offset, inline_depth); + } + return 0; + } + Boolean can_enumerate(Method_Handle method, NativeCodePtr eip @@ -331,6 +342,12 @@ private: uint32 offset, uint32 inline_depth); + uint16 + (*_get_inlined_bc)(JIT_Handle jit, + InlineInfoPtr ptr, + uint32 offset, + uint32 inline_depth); + Boolean (*_can_enumerate)(JIT_Handle jit, Method_Handle method, diff --git a/vm/vmcore/include/jit_intf_cpp.h b/vm/vmcore/include/jit_intf_cpp.h index eede66b..ca18c44 100644 --- a/vm/vmcore/include/jit_intf_cpp.h +++ b/vm/vmcore/include/jit_intf_cpp.h @@ -155,6 +155,11 @@ public: uint32 offset, uint32 inline_depth) { return NULL; } + virtual uint16 + get_inlined_bc(InlineInfoPtr ptr, + uint32 offset, + uint32 inline_depth) { return 0; } + virtual Boolean can_enumerate(Method_Handle method, NativeCodePtr eip diff --git a/vm/vmcore/include/stack_trace.h b/vm/vmcore/include/stack_trace.h index d0022e9..4554db9 100644 --- a/vm/vmcore/include/stack_trace.h +++ b/vm/vmcore/include/stack_trace.h @@ -60,6 +60,7 @@ #endif struct StackTraceFrame { Method_Handle method; NativeCodePtr ip; + int depth; // Inlined depth for inlined methods, or -1 otherwise void *outdated_this; }; @@ -134,10 +135,13 @@ VMEXPORT void st_get_trace(VM_thread *p_ * * @param[in] method - the handle of the method information to identify the source file * @param[in] ip - the instruction pointer to identify the JIT and using the JIT line number + * @param[in] depth - the inlined depth for inlined methods, starting from 0; + * (-1) for native methods and methods which were not inlined * @param[out] file - the pointer to the file reference to be filled by this function * @param[out] line - the pointer to the line number to be filled by this function */ -VMEXPORT void get_file_and_line(Method_Handle method, void *ip, bool is_ip_past, const char **file, int *line); +VMEXPORT void get_file_and_line(Method_Handle method, void *ip, bool is_ip_past, + int depth, const char **file, int *line); #ifdef __cplusplus } diff --git a/vm/vmcore/src/jit/dll_jit.cpp b/vm/vmcore/src/jit/dll_jit.cpp index 89d4b40..403924e 100644 --- a/vm/vmcore/src/jit/dll_jit.cpp +++ b/vm/vmcore/src/jit/dll_jit.cpp @@ -107,6 +107,9 @@ #define GET_OPTIONAL_FUNCTION(fn, handle GET_OPTIONAL_FUNCTION(fn, handle, "JIT_get_inlined_method"); _get_inlined_method = (Method_Handle (*)(JIT_Handle, InlineInfoPtr, uint32, uint32)) fn; + GET_OPTIONAL_FUNCTION(fn, handle, "JIT_get_inlined_bc"); + _get_inlined_bc = (uint16 (*)(JIT_Handle, InlineInfoPtr, uint32, uint32)) fn; + GET_FUNCTION(fn, handle, "JIT_unwind_stack_frame"); _unwind_stack_frame = (void (*)(JIT_Handle, Method_Handle, JitFrameContext *)) fn; diff --git a/vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.cpp b/vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.cpp index f5ba276..9c1dc56 100644 --- a/vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.cpp +++ b/vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMStack.cpp @@ -371,10 +371,11 @@ JNIEXPORT jobjectArray JNICALL Java_org_ for(unsigned i = skip; i < size; i++) { Method_Handle method = frames[i].method; NativeCodePtr ip = frames[i].ip; + int inl_depth = frames[i].depth; int lineNumber; const char* fileName; - get_file_and_line(method, ip, true, &fileName, &lineNumber); + get_file_and_line(method, ip, true, inl_depth, &fileName, &lineNumber); jstring strFileName; if (fileName != NULL) { strFileName = jenv->NewStringUTF(fileName); @@ -493,10 +494,11 @@ JNIEXPORT jobjectArray JNICALL Java_org_ for(unsigned i = 0; i < size; i++) { Method_Handle method = frames[i].method; NativeCodePtr ip = frames[i].ip; + int inl_depth = frames[i].depth; int lineNumber; const char* fileName; - get_file_and_line(method, ip, true, &fileName, &lineNumber); + get_file_and_line(method, ip, true, inl_depth, &fileName, &lineNumber); if (fileName == NULL) fileName = ""; jstring strFileName = jenv->NewStringUTF(fileName); diff --git a/vm/vmcore/src/stack/stack_dump.cpp b/vm/vmcore/src/stack/stack_dump.cpp index 0108289..b5a22c2 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,43 @@ 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, int inl_depth) +{ + 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, inl_depth, &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,53 +227,187 @@ 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(Registers* regs) { - if(interpreter_enabled()) { - interpreter.stack_dump(get_thread_ptr()); - return; - } - 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(); - 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 + +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; - } else { // Java/JNI native method + } + + // 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, -1); + st_print_line(count, &m); + } + else // !si_is_native(si) + { + // Print information about Java method from iterator 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); - // FIXME64: on 64-bit architectures method bodies can be - // potentially greater than 2GB in size - uint32 offset = (uint32)((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); - } + Method* method = cci->get_method(); + void* ip = (void*)si_get_ip(si); + + uint32 inlined_depth = si_get_inline_depth(si); + uint32 offset = (uint32)((POINTER_SIZE_INT)ip - + (POINTER_SIZE_INT)cci->get_code_block_addr()); + bool is_ip_past = (frame_num != 0); + + 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, ip, is_ip_past, i); + 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, is_ip_past, -1); + 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_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, -1); + 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 + } +} + +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"); + + if(interpreter_enabled() && thread) + st_print_stack_interpreter(thread, frames, num_frames); + else // It should be used also for threads without VM_thread structure + st_print_stack_jit(thread, frames, num_frames); + fprintf(stderr, "\n"); + fflush(stderr); } diff --git a/vm/vmcore/src/stack/stack_trace.cpp b/vm/vmcore/src/stack/stack_trace.cpp index a6b8235..b65531c 100644 --- a/vm/vmcore/src/stack/stack_trace.cpp +++ b/vm/vmcore/src/stack/stack_trace.cpp @@ -30,7 +30,8 @@ #include "cci.h" #include "class_member.h" #include "open/hythread.h" -void get_file_and_line(Method_Handle mh, void *ip, bool is_ip_past, const char **file, int *line) { +void get_file_and_line(Method_Handle mh, void *ip, bool is_ip_past, + int depth, const char **file, int *line) { Method *method = (Method*)mh; *file = class_get_source_file_name(method_get_class(method)); @@ -58,18 +59,31 @@ #if !defined(_IPF_) // appropriate callL POINTER_SIZE_INT callLength = 5; Global_Env * vm_env = VM_Global_State::loader_env; - CodeChunkInfo* jit_info = vm_env->vm_methods->find((unsigned char*)ip - callLength); - if (jit_info->get_jit()->get_bc_location_for_native( - method, - (NativeCodePtr) ((POINTER_SIZE_INT) ip - callLength), - &bcOffset) != EXE_ERROR_NONE) { - // - return; + CodeChunkInfo* cci = vm_env->vm_methods->find(ip, is_ip_past); + assert(cci); + + if (depth < 0) // Not inlined method + { + if (cci->get_jit()->get_bc_location_for_native( + method, + (NativeCodePtr)((POINTER_SIZE_INT)ip - callLength), + &bcOffset) != EXE_ERROR_NONE) { + // + return; + } } - - if (is_ip_past) { - bcOffset--; + else // Inlined method + { + InlineInfoPtr inl_info = cci->get_inline_info(); + + if (inl_info) + { + uint32 offset = (uint32) ((POINTER_SIZE_INT)ip - + (POINTER_SIZE_INT)cci->get_code_block_addr()); + bcOffset = cci->get_jit()->get_inlined_bc(inl_info, offset, depth); + } } + *line = method->get_line_number(bcOffset); #endif } @@ -99,6 +113,7 @@ bool st_get_frame(unsigned target_depth, unsigned depth = 0; while (!si_is_past_end(si)) { stf->method = si_get_method(si); + stf->depth = -1; if (stf->method) { uint32 inlined_depth = si_get_inline_depth(si); if ( (target_depth >= depth) && @@ -112,6 +127,7 @@ bool st_get_frame(unsigned target_depth, uint32 offset = (uint32)((POINTER_SIZE_INT)stf->ip - (POINTER_SIZE_INT)cci->get_code_block_addr()); stf->method = cci->get_jit()->get_inlined_method( cci->get_inline_info(), offset, target_depth - depth); + stf->depth = target_depth - depth; } si_free(si); @@ -173,7 +189,8 @@ void st_get_trace(VM_thread *p_vmthread, for (uint32 i = 0; i < inlined_depth; i++) { stf->method = jit->get_inlined_method(cci->get_inline_info(), offset, i); - stf->ip = NULL; + stf->ip = ip; + stf->depth = i; stf->outdated_this = get_this(jit, method, si); stf++; depth++; @@ -182,6 +199,7 @@ void st_get_trace(VM_thread *p_vmthread, } stf->method = method; stf->ip = ip; + stf->depth = -1; stf++; depth++; } @@ -200,7 +218,7 @@ void st_print_frame(ExpandableMemBlock* buf->AppendFormatBlock("\tat %s.%s%s", cname, mname, dname); const char *file; int line; - get_file_and_line(stf->method, stf->ip, false, &file, &line); + get_file_and_line(stf->method, stf->ip, false, stf->depth, &file, &line); if (line==-2) // Native method diff --git a/vm/vmcore/src/util/linux/signals_em64t.cpp b/vm/vmcore/src/util/linux/signals_em64t.cpp index fffbf06..f15cf70 100644 --- a/vm/vmcore/src/util/linux/signals_em64t.cpp +++ b/vm/vmcore/src/util/linux/signals_em64t.cpp @@ -67,6 +67,7 @@ #include "thread_manager.h" #include "exception_filter.h" #include "interpreter.h" +#include "stack_dump.h" // Variables used to locate the context from the signal handler static int sc_nest = -1; @@ -180,21 +181,6 @@ void addr2line (char *buf) { } } -/** - * Print out the call stack. - */ -void print_native_stack (unsigned *rbp) { - int depth = 17; - LWARN(42, "Fatal error"); - char buf[1024]; - int n = 0; - while (rbp && rbp[1] && --depth >= 0 && (nuc_mcontext.gregs[REG_RBP]; - print_native_stack(rbp); + Registers regs; + linux_ucontext_to_regs(®s, uc); + st_print_stack(®s); } void initialize_signals() diff --git a/vm/vmcore/src/util/win/em64t/nt_exception_filter.cpp b/vm/vmcore/src/util/win/em64t/nt_exception_filter.cpp index 130b5eb..4af4caa 100644 --- a/vm/vmcore/src/util/win/em64t/nt_exception_filter.cpp +++ b/vm/vmcore/src/util/win/em64t/nt_exception_filter.cpp @@ -83,22 +83,23 @@ void print_state(LPEXCEPTION_POINTERS nt fprintf(stderr, "Windows reported exception: 0x%x\n", nt_exception->ExceptionRecord->ExceptionCode); fprintf(stderr, "Registers:\n"); - fprintf(stderr, " RAX: 0x%16lx, RBX: 0x%16lx\n", + fprintf(stderr, " RAX: 0x%016I64x, RBX: 0x%016I64x\n", nt_exception->ContextRecord->Rax, nt_exception->ContextRecord->Rbx); - fprintf(stderr, " RCX: 0x%16lx, RDX: 0x%16lx\n", + fprintf(stderr, " RCX: 0x%016I64x, RDX: 0x%016I64x\n", nt_exception->ContextRecord->Rcx, nt_exception->ContextRecord->Rdx); - fprintf(stderr, " RSI: 0x%16lx, RDI: 0x%16lx\n", + fprintf(stderr, " RSI: 0x%016I64x, RDI: 0x%016I64x\n", nt_exception->ContextRecord->Rsi, nt_exception->ContextRecord->Rdi); - fprintf(stderr, " RSP: 0x%16lx, RBP: 0x%16lx\n", + fprintf(stderr, " RSP: 0x%016I64x, RBP: 0x%016I64x\n", nt_exception->ContextRecord->Rsp, nt_exception->ContextRecord->Rbp); - fprintf(stderr, " R8: 0x%16lx, R9: 0x%16lx\n", + fprintf(stderr, " R8 : 0x%016I64x, R9 : 0x%016I64x\n", nt_exception->ContextRecord->R8, nt_exception->ContextRecord->R9); - fprintf(stderr, " R10: 0x%16lx, R11P: 0x%16lx\n", + fprintf(stderr, " R10: 0x%016I64x, R11: 0x%016I64x\n", nt_exception->ContextRecord->R10, nt_exception->ContextRecord->R11); - fprintf(stderr, " RS12: 0x%16lx, R13: 0x%16lx\n", + fprintf(stderr, " R12: 0x%016I64x, R13: 0x%016I64x\n", nt_exception->ContextRecord->R12, nt_exception->ContextRecord->R13); - fprintf(stderr, " RS14: 0x%16lx, R15: 0x%16lx\n", + fprintf(stderr, " R14: 0x%016I64x, R15: 0x%016I64x\n", nt_exception->ContextRecord->R14, nt_exception->ContextRecord->R15); + fprintf(stderr, " RIP: 0x%016I64x\n", nt_exception->ContextRecord->Rip); } void* regs_get_sp(Registers* pregs) diff --git a/vm/vmcore/src/util/win/ia32_em64t/nt_exception_filter_common.cpp b/vm/vmcore/src/util/win/ia32_em64t/nt_exception_filter_common.cpp index 3ddb68f..1ce4995 100644 --- a/vm/vmcore/src/util/win/ia32_em64t/nt_exception_filter_common.cpp +++ b/vm/vmcore/src/util/win/ia32_em64t/nt_exception_filter_common.cpp @@ -47,9 +47,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 */ @@ -223,9 +235,10 @@ LONG NTAPI vectored_exception_handler_in // delegate "other" cases to default handler if (!in_java && code != STATUS_STACK_OVERFLOW) { + LONG result = process_crash(nt_exception); regs.set_ip((void*)saved_eip); vm_to_nt_context(®s, context); - return EXCEPTION_CONTINUE_SEARCH; + return result; } // if HWE occured in java code, suspension should also have been disabled @@ -300,10 +313,10 @@ LONG NTAPI vectored_exception_handler_in } default: // unexpected hardware exception occured in java code - print_callstack(nt_exception); + LONG result = process_crash(nt_exception); regs.set_ip((void*)saved_eip); vm_to_nt_context(®s, context); - return EXCEPTION_CONTINUE_SEARCH; + return result; } // we must not call potentially blocking or suspendable code