From 12197c4f945e348e9f5b664986d3a7e88501d2de Mon Sep 17 00:00:00 2001 From: Ilya Berezhniuk Date: Fri, 29 Feb 2008 00:43:50 +0300 Subject: [PATCH] --move-- Moving to PORT: memory access, stack dump, signal helpers, native stack, GDB crash handler renamed: vm/port/include/native_modules.h -> vm/port/include/port_modules.h renamed: vm/vmcore/src/util/em64t/base/native_stack_em64t.cpp -> vm/port/src/crash_handler/em64t/native_unwind_arch.cpp renamed: vm/vmcore/src/util/em64t/base/signals_arch.cpp -> vm/port/src/crash_handler/em64t/reg_state.cpp renamed: vm/vmcore/src/util/ia32/base/native_stack_ia32.cpp -> vm/port/src/crash_handler/ia32/native_unwind_arch.cpp renamed: vm/vmcore/src/util/ia32/base/signals_arch.cpp -> vm/port/src/crash_handler/ia32/reg_state.cpp renamed: vm/vmcore/include/stack_dump.h -> vm/port/src/crash_handler/include/stack_dump.h renamed: vm/vmcore/src/util/ipf/base/native_stack_ipf.cpp -> vm/port/src/crash_handler/ipf/native_unwind_arch.cpp renamed: vm/vmcore/src/util/ipf/base/signals_arch.cpp -> vm/port/src/crash_handler/ipf/reg_state.cpp renamed: vm/vmcore/src/util/linux/crash_handler.cpp -> vm/port/src/crash_handler/linux/gdb_crash_handler.cpp renamed: vm/vmcore/src/util/linux/include/crash_handler.h -> vm/port/src/crash_handler/linux/include/gdb_crash_handler.h renamed: vm/vmcore/src/util/linux/native_stack_os.cpp -> vm/port/src/crash_handler/linux/native_unwind_os.cpp renamed: vm/vmcore/src/util/linux/stack_dump_platf.cpp -> vm/port/src/crash_handler/linux/stack_dump_os.cpp renamed: vm/vmcore/src/stack/stack_dump.cpp -> vm/port/src/crash_handler/stack_dump.cpp renamed: vm/vmcore/src/util/win/native_stack_os.cpp -> vm/port/src/crash_handler/win/native_unwind_os.cpp renamed: vm/vmcore/src/util/win/stack_dump_platf.cpp -> vm/port/src/crash_handler/win/stack_dump_os.cpp renamed: vm/vmcore/src/ncai/utils/ncai_memory_linux.cpp -> vm/port/src/memaccess/linux/memaccess.cpp renamed: vm/vmcore/src/ncai/utils/ncai_memory_win.cpp -> vm/port/src/memaccess/win/memaccess.cpp renamed: vm/vmcore/src/util/win/em64t/exception_handlers.asm -> vm/port/src/signals/win/signals_em64t.asm renamed: vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp -> vm/port/src/signals/win/signals_ia32.cpp renamed: vm/vmcore/src/util/native_stack.cpp -> vm/vmcore/src/stack/native_stack.cpp --- vm/port/include/native_modules.h | 92 ---- vm/port/include/port_modules.h | 92 ++++ .../src/crash_handler/em64t/native_unwind_arch.cpp | 160 ++++++ vm/port/src/crash_handler/em64t/reg_state.cpp | 41 ++ .../src/crash_handler/ia32/native_unwind_arch.cpp | 160 ++++++ vm/port/src/crash_handler/ia32/reg_state.cpp | 29 ++ vm/port/src/crash_handler/include/stack_dump.h | 85 ++++ .../src/crash_handler/ipf/native_unwind_arch.cpp | 46 ++ vm/port/src/crash_handler/ipf/reg_state.cpp | 46 ++ .../src/crash_handler/linux/gdb_crash_handler.cpp | 112 +++++ .../linux/include/gdb_crash_handler.h | 53 ++ .../src/crash_handler/linux/native_unwind_os.cpp | 87 ++++ vm/port/src/crash_handler/linux/stack_dump_os.cpp | 266 ++++++++++ vm/port/src/crash_handler/stack_dump.cpp | 512 ++++++++++++++++++++ vm/port/src/crash_handler/win/native_unwind_os.cpp | 53 ++ vm/port/src/crash_handler/win/stack_dump_os.cpp | 273 +++++++++++ vm/port/src/memaccess/linux/memaccess.cpp | 287 +++++++++++ vm/port/src/memaccess/win/memaccess.cpp | 49 ++ vm/port/src/signals/win/signals_em64t.asm | 27 + vm/port/src/signals/win/signals_ia32.cpp | 37 ++ vm/vmcore/include/stack_dump.h | 85 ---- vm/vmcore/src/ncai/utils/ncai_memory_linux.cpp | 287 ----------- vm/vmcore/src/ncai/utils/ncai_memory_win.cpp | 49 -- vm/vmcore/src/stack/native_stack.cpp | 468 ++++++++++++++++++ vm/vmcore/src/stack/stack_dump.cpp | 512 -------------------- .../src/util/em64t/base/native_stack_em64t.cpp | 160 ------ vm/vmcore/src/util/em64t/base/signals_arch.cpp | 41 -- vm/vmcore/src/util/ia32/base/native_stack_ia32.cpp | 160 ------ vm/vmcore/src/util/ia32/base/signals_arch.cpp | 29 -- vm/vmcore/src/util/ipf/base/native_stack_ipf.cpp | 46 -- vm/vmcore/src/util/ipf/base/signals_arch.cpp | 46 -- vm/vmcore/src/util/linux/crash_handler.cpp | 112 ----- vm/vmcore/src/util/linux/include/crash_handler.h | 53 -- vm/vmcore/src/util/linux/native_stack_os.cpp | 87 ---- vm/vmcore/src/util/linux/stack_dump_platf.cpp | 266 ---------- vm/vmcore/src/util/native_stack.cpp | 468 ------------------ .../src/util/win/em64t/exception_handlers.asm | 27 - .../src/util/win/ia32/nt_exception_filter.cpp | 37 -- vm/vmcore/src/util/win/native_stack_os.cpp | 53 -- vm/vmcore/src/util/win/stack_dump_platf.cpp | 273 ----------- 40 files changed, 2883 insertions(+), 2883 deletions(-) delete mode 100644 vm/port/include/native_modules.h create mode 100644 vm/port/include/port_modules.h create mode 100644 vm/port/src/crash_handler/em64t/native_unwind_arch.cpp create mode 100644 vm/port/src/crash_handler/em64t/reg_state.cpp create mode 100644 vm/port/src/crash_handler/ia32/native_unwind_arch.cpp create mode 100644 vm/port/src/crash_handler/ia32/reg_state.cpp create mode 100644 vm/port/src/crash_handler/include/stack_dump.h create mode 100644 vm/port/src/crash_handler/ipf/native_unwind_arch.cpp create mode 100644 vm/port/src/crash_handler/ipf/reg_state.cpp create mode 100644 vm/port/src/crash_handler/linux/gdb_crash_handler.cpp create mode 100644 vm/port/src/crash_handler/linux/include/gdb_crash_handler.h create mode 100644 vm/port/src/crash_handler/linux/native_unwind_os.cpp create mode 100644 vm/port/src/crash_handler/linux/stack_dump_os.cpp create mode 100644 vm/port/src/crash_handler/stack_dump.cpp create mode 100644 vm/port/src/crash_handler/win/native_unwind_os.cpp create mode 100644 vm/port/src/crash_handler/win/stack_dump_os.cpp create mode 100644 vm/port/src/memaccess/linux/memaccess.cpp create mode 100644 vm/port/src/memaccess/win/memaccess.cpp create mode 100644 vm/port/src/signals/win/signals_em64t.asm create mode 100644 vm/port/src/signals/win/signals_ia32.cpp delete mode 100644 vm/vmcore/include/stack_dump.h delete mode 100644 vm/vmcore/src/ncai/utils/ncai_memory_linux.cpp delete mode 100644 vm/vmcore/src/ncai/utils/ncai_memory_win.cpp create mode 100644 vm/vmcore/src/stack/native_stack.cpp delete mode 100644 vm/vmcore/src/stack/stack_dump.cpp delete mode 100644 vm/vmcore/src/util/em64t/base/native_stack_em64t.cpp delete mode 100644 vm/vmcore/src/util/em64t/base/signals_arch.cpp delete mode 100644 vm/vmcore/src/util/ia32/base/native_stack_ia32.cpp delete mode 100644 vm/vmcore/src/util/ia32/base/signals_arch.cpp delete mode 100644 vm/vmcore/src/util/ipf/base/native_stack_ipf.cpp delete mode 100644 vm/vmcore/src/util/ipf/base/signals_arch.cpp delete mode 100644 vm/vmcore/src/util/linux/crash_handler.cpp delete mode 100644 vm/vmcore/src/util/linux/include/crash_handler.h delete mode 100644 vm/vmcore/src/util/linux/native_stack_os.cpp delete mode 100644 vm/vmcore/src/util/linux/stack_dump_platf.cpp delete mode 100644 vm/vmcore/src/util/native_stack.cpp delete mode 100644 vm/vmcore/src/util/win/em64t/exception_handlers.asm delete mode 100644 vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp delete mode 100644 vm/vmcore/src/util/win/native_stack_os.cpp delete mode 100644 vm/vmcore/src/util/win/stack_dump_platf.cpp diff --git a/vm/port/include/native_modules.h b/vm/port/include/native_modules.h deleted file mode 100644 index 2b382f0..0000000 --- a/vm/port/include/native_modules.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Ilya Berezhniuk - * @version $Revision: 1.1.2.1 $ - */ - -#ifndef _NATIVE_MODULES_H_ -#define _NATIVE_MODULES_H_ - -#include -#include -#include "open/types.h" - - -typedef enum { - SEGMENT_TYPE_UNKNOWN, - SEGMENT_TYPE_CODE, - SEGMENT_TYPE_DATA -} native_seg_type_t; - -typedef struct { - native_seg_type_t type; - void* base; - size_t size; -} native_segment_t; - -typedef struct native_module_t native_module_t; - -struct native_module_t { - char* filename; - size_t seg_count; - native_module_t* next; - native_segment_t segments[1]; -}; - - -#ifdef __cplusplus -extern "C" { -#endif - - -/** -* Returns the list of modules loaded to the current process. -* Module includes one or more segments of type native_segment_t. -* @param list_ptr - an address of modules list pointer to fill -* @param count_ptr - count of modules in the returned list -* @return TRUE if OK; FALSE if error occured. -*/ -Boolean port_get_all_modules(native_module_t** list_ptr, int* count_ptr); - -/** -* Dumps the list of modules loaded to the current process.. -* @param modules - pointer to the list of modules to dump. -* @param out - stream for printing the dump. -*/ -void port_dump_modules(native_module_t* modules, FILE *out); - -/** -* Clears the list of modules passed, writes NULL to the poiner. -* @param modules - pointer to the list of modules to clear. -*/ -void port_clear_modules(native_module_t** list_ptr); - -/** -* Searches for the specific address in the list of modules. -* @param modules - pointer to the list of modules to inspect. -* @param code_ptr - the address to look for. -* @return native_module_t pointer if OK; otherwise, NULL. -*/ -native_module_t* port_find_module(native_module_t* modules, void* code_ptr); - - -#ifdef __cplusplus -} -#endif - -#endif // _NATIVE_MODULES_H_ diff --git a/vm/port/include/port_modules.h b/vm/port/include/port_modules.h new file mode 100644 index 0000000..2b382f0 --- /dev/null +++ b/vm/port/include/port_modules.h @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya Berezhniuk + * @version $Revision: 1.1.2.1 $ + */ + +#ifndef _NATIVE_MODULES_H_ +#define _NATIVE_MODULES_H_ + +#include +#include +#include "open/types.h" + + +typedef enum { + SEGMENT_TYPE_UNKNOWN, + SEGMENT_TYPE_CODE, + SEGMENT_TYPE_DATA +} native_seg_type_t; + +typedef struct { + native_seg_type_t type; + void* base; + size_t size; +} native_segment_t; + +typedef struct native_module_t native_module_t; + +struct native_module_t { + char* filename; + size_t seg_count; + native_module_t* next; + native_segment_t segments[1]; +}; + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** +* Returns the list of modules loaded to the current process. +* Module includes one or more segments of type native_segment_t. +* @param list_ptr - an address of modules list pointer to fill +* @param count_ptr - count of modules in the returned list +* @return TRUE if OK; FALSE if error occured. +*/ +Boolean port_get_all_modules(native_module_t** list_ptr, int* count_ptr); + +/** +* Dumps the list of modules loaded to the current process.. +* @param modules - pointer to the list of modules to dump. +* @param out - stream for printing the dump. +*/ +void port_dump_modules(native_module_t* modules, FILE *out); + +/** +* Clears the list of modules passed, writes NULL to the poiner. +* @param modules - pointer to the list of modules to clear. +*/ +void port_clear_modules(native_module_t** list_ptr); + +/** +* Searches for the specific address in the list of modules. +* @param modules - pointer to the list of modules to inspect. +* @param code_ptr - the address to look for. +* @return native_module_t pointer if OK; otherwise, NULL. +*/ +native_module_t* port_find_module(native_module_t* modules, void* code_ptr); + + +#ifdef __cplusplus +} +#endif + +#endif // _NATIVE_MODULES_H_ diff --git a/vm/port/src/crash_handler/em64t/native_unwind_arch.cpp b/vm/port/src/crash_handler/em64t/native_unwind_arch.cpp new file mode 100644 index 0000000..c8f139c --- /dev/null +++ b/vm/port/src/crash_handler/em64t/native_unwind_arch.cpp @@ -0,0 +1,160 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya Berezhniuk + * @version $Revision: 1.1.2.1 $ + */ + +#include "method_lookup.h" +#include "dec_base.h" +#include "native_modules.h" +#include "native_stack.h" + + +bool native_is_frame_exists(WalkContext* context, Registers* regs) +{ + // Check for frame layout and stack values + if ((regs->rbp < regs->rsp) || !native_is_in_stack(context, (void*)regs->rbp)) + return false; // Invalid frame + + void** frame_ptr = (void**)regs->rbp; + void* rip = frame_ptr[1]; // Return address + + // Check return address for meaning + return (native_is_in_code(context, rip) || native_is_ip_stub(rip)); +} + +bool native_unwind_stack_frame(WalkContext* context, Registers* regs) +{ + void** frame = (void**)regs->rbp; + + void* rbp = frame[0]; + void* rip = frame[1]; +// void* rsp = (void*)(frame + 2); + void* rsp = &frame[2]; + + + if (native_is_in_stack(context, rsp) && + (native_is_in_code(context, rip) || native_is_ip_stub(rip))) + { + regs->rbp = (uint64)rbp; + regs->rsp = (uint64)rsp; + regs->rip = (uint64)rip; + return true; + } + + return false; +} + +void native_get_regs_from_jit_context(JitFrameContext* jfc, Registers* regs) +{ + regs->rip = *jfc->p_rip; + regs->rbp = *jfc->p_rbp; + regs->rsp = jfc->rsp; +} + +static bool fill_regs_from_sp(WalkContext* context, Registers* regs, void** sp) +{ + regs->rsp = (uint64)(sp + 1); + regs->rip = (uint64)*sp; + regs->rbp = native_is_in_stack(context, sp[-1]) ? (uint64)sp[-1] : regs->rsp; + return true; +} + +static unsigned native_dec_instr(WalkContext* context, void* addr, void** target) +{ + Inst inst; + + if (!native_is_in_code(context, addr)) + return 0; + + unsigned len = DecoderBase::decode(addr, &inst); + + if (len == 0 || + inst.mn != Mnemonic_CALL || + inst.argc != 1) + return 0; + + if (target && inst.operands[0].is_imm()) + *target = (void*)((uint64)addr + (uint64)len + inst.operands[0].imm()); + + return len; +} + +static bool native_check_caller(WalkContext* context, Registers* regs, void** sp) +{ + void* target = NULL; + char* ptr = (char*)*sp; + + if (native_dec_instr(context, ptr - 2, &target) == 2 || // CALL r/m64 w/o SIB w/o disp + native_dec_instr(context, ptr - 3, &target) == 3 || // CALL r/m64 w/ SIB w/o disp + native_dec_instr(context, ptr - 4, &target) == 4 || // CALL r/m64 w/ SIB w/ disp8 + native_dec_instr(context, ptr - 5, &target) == 5 || // CALL rel32 + native_dec_instr(context, ptr - 6, &target) == 6 || // CALL r/m64 w/o SIB w/ disp32 + native_dec_instr(context, ptr - 7, &target) == 7 || // CALL r/m64 w/ SIB w/ disp32 + native_dec_instr(context, ptr - 8, &target) == 8) // CALL r/m64 w/ SIB w/ disp32 + Seg prefix + { + if (!target) + return true; + + native_module_t* cur_module = + port_find_module(context->modules, regs->get_ip()); + native_module_t* found_module = + port_find_module(context->modules, target); + + return (cur_module == found_module); + } + + return false; +} + + +// Max search depth for return address +#define MAX_SPECIAL_DEPTH 0x900 +#define NATIVE_STRICT_UNWINDING 1 + +bool native_unwind_special(WalkContext* context, Registers* regs) +{ + for (void** cur_sp = (void**)regs->rsp; + (char*)cur_sp < ((char*)regs->rsp + MAX_SPECIAL_DEPTH) && native_is_in_stack(context, cur_sp); + ++cur_sp) + { + if (!native_is_in_code(context, *cur_sp)) + continue; + +#if (!NATIVE_STRICT_UNWINDING) + return fill_regs_from_sp(context, regs, cur_sp); +#else + if (native_check_caller(context, regs, cur_sp)) + return fill_regs_from_sp(context, regs, cur_sp); +#endif + } + + return false; +} + +void native_fill_frame_info(Registers* regs, native_frame_t* frame, jint jdepth) +{ + frame->java_depth = jdepth; + + if (!regs) + return; + + frame->ip = (void*)regs->rip; + frame->frame = (void*)regs->rbp; + frame->stack = (void*)regs->rsp; +} diff --git a/vm/port/src/crash_handler/em64t/reg_state.cpp b/vm/port/src/crash_handler/em64t/reg_state.cpp new file mode 100644 index 0000000..b79c436 --- /dev/null +++ b/vm/port/src/crash_handler/em64t/reg_state.cpp @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "vm_core_types.h" + +void print_reg_state(Registers* regs) +{ + fprintf(stderr, "Registers:\n"); + fprintf(stderr, " RAX: 0x%"W_PI_FMT", RBX: 0x%"W_PI_FMT"\n", + regs->rax, regs->rbx); + fprintf(stderr, " RCX: 0x%"W_PI_FMT", RDX: 0x%"W_PI_FMT"\n", + regs->rcx, regs->rdx); + fprintf(stderr, " RSI: 0x%"W_PI_FMT", RDI: 0x%"W_PI_FMT"\n", + regs->rsi, regs->rdi); + fprintf(stderr, " RSP: 0x%"W_PI_FMT", RBP: 0x%"W_PI_FMT"\n", + regs->rsp, regs->rbp); + fprintf(stderr, " R8 : 0x%"W_PI_FMT", R9 : 0x%"W_PI_FMT"\n", + regs->r8, regs->r9); + fprintf(stderr, " R10: 0x%"W_PI_FMT", R11: 0x%"W_PI_FMT"\n", + regs->r10, regs->r11); + fprintf(stderr, " R12: 0x%"W_PI_FMT", R13: 0x%"W_PI_FMT"\n", + regs->r12, regs->r13); + fprintf(stderr, " R14: 0x%"W_PI_FMT", R15: 0x%"W_PI_FMT"\n", + regs->r14, regs->r15); + fprintf(stderr, " RIP: 0x%"W_PI_FMT"\n", regs->rip); +} diff --git a/vm/port/src/crash_handler/ia32/native_unwind_arch.cpp b/vm/port/src/crash_handler/ia32/native_unwind_arch.cpp new file mode 100644 index 0000000..cbfc211 --- /dev/null +++ b/vm/port/src/crash_handler/ia32/native_unwind_arch.cpp @@ -0,0 +1,160 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya Berezhniuk + * @version $Revision: 1.1.2.1 $ + */ + +#include "method_lookup.h" +#include "dec_base.h" +#include "native_modules.h" +#include "native_stack.h" + + +bool native_is_frame_exists(WalkContext* context, Registers* regs) +{ + // Check for frame layout and stack values + if ((regs->ebp < regs->esp) || !native_is_in_stack(context, (void*)regs->ebp)) + return false; // Invalid frame + + void** frame_ptr = (void**)regs->ebp; + void* eip = frame_ptr[1]; // Return address + + // Check return address for meaning + return (native_is_in_code(context, eip) || native_is_ip_stub(eip)); +} + +bool native_unwind_stack_frame(WalkContext* context, Registers* regs) +{ + void** frame = (void**)regs->ebp; + + void* ebp = frame[0]; + void* eip = frame[1]; +// void* esp = (void*)(frame + 2); + void* esp = &frame[2]; + + + if (native_is_in_stack(context, esp) && + (native_is_in_code(context, eip) || native_is_ip_stub(eip))) + { + regs->ebp = (uint32)ebp; + regs->esp = (uint32)esp; + regs->eip = (uint32)eip; + return true; + } + + return false; +} + +void native_get_regs_from_jit_context(JitFrameContext* jfc, Registers* regs) +{ + regs->eip = *jfc->p_eip; + regs->ebp = *jfc->p_ebp; + regs->esp = jfc->esp; +} + +static bool fill_regs_from_sp(WalkContext* context, Registers* regs, void** sp) +{ + regs->esp = (uint32)(sp + 1); + regs->eip = (uint32)*sp; + regs->ebp = native_is_in_stack(context, sp[-1]) ? (uint32)sp[-1] : regs->esp; + return true; +} + +static unsigned native_dec_instr(WalkContext* context, void* addr, void** target) +{ + Inst inst; + + if (!native_is_in_code(context, addr)) + return 0; + + uint32 len = DecoderBase::decode(addr, &inst); + + if (len == 0 || + inst.mn != Mnemonic_CALL || + inst.argc != 1) + return 0; + + if (target && inst.operands[0].is_imm()) + *target = (void*)((uint32)addr + len + inst.operands[0].imm()); + + return len; +} + +static bool native_check_caller(WalkContext* context, Registers* regs, void** sp) +{ + void* target = NULL; + char* ptr = (char*)*sp; + + if (native_dec_instr(context, ptr - 2, &target) == 2 || // CALL r/m32 w/o SIB w/o disp + native_dec_instr(context, ptr - 3, &target) == 3 || // CALL r/m32 w/ SIB w/o disp + native_dec_instr(context, ptr - 4, &target) == 4 || // CALL r/m32 w/ SIB w/ disp8 + native_dec_instr(context, ptr - 5, &target) == 5 || // CALL rel32 + native_dec_instr(context, ptr - 6, &target) == 6 || // CALL r/m32 w/o SIB w/ disp32 + native_dec_instr(context, ptr - 7, &target) == 7 || // CALL r/m32 w/ SIB w/ disp32 + native_dec_instr(context, ptr - 8, &target) == 8) // CALL r/m32 w/ SIB w/ disp32 + Seg prefix + { + if (!target) + return true; + + native_module_t* cur_module = + port_find_module(context->modules, regs->get_ip()); + native_module_t* found_module = + port_find_module(context->modules, target); + + return (cur_module == found_module); + } + + return false; +} + + +// Max search depth for return address +#define MAX_SPECIAL_DEPTH 0x400 +#define NATIVE_STRICT_UNWINDING 1 + +bool native_unwind_special(WalkContext* context, Registers* regs) +{ + for (void** cur_sp = (void**)regs->esp; + (char*)cur_sp < ((char*)regs->esp + MAX_SPECIAL_DEPTH) && native_is_in_stack(context, cur_sp); + ++cur_sp) + { + if (!native_is_in_code(context, *cur_sp)) + continue; + +#if (!NATIVE_STRICT_UNWINDING) + return fill_regs_from_sp(context, regs, cur_sp); +#else + if (native_check_caller(context, regs, cur_sp)) + return fill_regs_from_sp(context, regs, cur_sp); +#endif + } + + return false; +} + +void native_fill_frame_info(Registers* regs, native_frame_t* frame, jint jdepth) +{ + frame->java_depth = jdepth; + + if (!regs) + return; + + frame->ip = (void*)regs->eip; + frame->frame = (void*)regs->ebp; + frame->stack = (void*)regs->esp; +} diff --git a/vm/port/src/crash_handler/ia32/reg_state.cpp b/vm/port/src/crash_handler/ia32/reg_state.cpp new file mode 100644 index 0000000..0ac5a4c --- /dev/null +++ b/vm/port/src/crash_handler/ia32/reg_state.cpp @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "vm_core_types.h" + +void print_reg_state(Registers* regs) +{ + fprintf(stderr, "Registers:\n"); + fprintf(stderr, " EAX: 0x%"W_PI_FMT", EBX: 0x%"W_PI_FMT", ECX: 0x%"W_PI_FMT", EDX: 0x%"W_PI_FMT"\n", + regs->eax, regs->ebx, regs->ecx, regs->edx); + fprintf(stderr, " ESI: 0x%"W_PI_FMT", EDI: 0x%"W_PI_FMT", ESP: 0x%"W_PI_FMT", EBP: 0x%"W_PI_FMT"\n", + regs->esi, regs->edi, regs->esp, regs->ebp); + fprintf(stderr, " EIP: 0x%"W_PI_FMT"\n", regs->eip); +} diff --git a/vm/port/src/crash_handler/include/stack_dump.h b/vm/port/src/crash_handler/include/stack_dump.h new file mode 100644 index 0000000..8126316 --- /dev/null +++ b/vm/port/src/crash_handler/include/stack_dump.h @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Vladimir Nenashev + * @version $Revision$ + */ + + +#ifndef __STACK_DUMP_H_ +#define __STACK_DUMP_H_ + +#include "open/hythread_ext.h" +#include "vm_core_types.h" +#include "jni.h" +#include "native_modules.h" + + +#ifdef _DEBUG +#define SD_UPDATE_MODULES +#endif + +#ifdef SD_UPDATE_MODULES +#define sd_update_modules() sd_update_modules() +#else +#define sd_update_modules() +#endif + +#ifdef PLATFORM_POSIX +#include +#define strcmp_case strcasecmp +#else // Win +#include +#define strcmp_case _stricmp +#endif + +#include "platform_lowlevel.h" + +#define SD_MNAME_LENGTH 2048 + +// Symbolic method info: method name, source file name and a line number of an instruction within the method +struct MethodInfo { + char method_name[SD_MNAME_LENGTH]; + char file_name[_MAX_PATH]; + int line; +}; + + +/** + * Prints a stack trace using given register context for current thread + */ +void sd_print_stack(Registers* regs); + +/** + * Updates modules list for crash reporting + */ +#ifdef SD_UPDATE_MODULES +void sd_update_modules(); +#endif + +// platform-dependent functions +bool sd_initialize(hymutex_t** p_lock); +void sd_parse_module_info(native_module_t* module, void* ip); +void sd_get_c_method_info(MethodInfo* info, native_module_t* module, void* ip); +int sd_get_cur_tid(); +void sd_init_crash_handler(); +void sd_print_cwdcmdenv(); + +// general functions to call from platform-dependent code +const char* sd_get_module_type(const char* short_name); + +#endif //!__STACK_DUMP_H_ diff --git a/vm/port/src/crash_handler/ipf/native_unwind_arch.cpp b/vm/port/src/crash_handler/ipf/native_unwind_arch.cpp new file mode 100644 index 0000000..e91c555 --- /dev/null +++ b/vm/port/src/crash_handler/ipf/native_unwind_arch.cpp @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya Berezhniuk + * @version $Revision: 1.1.2.1 $ + */ + +#include "native_stack.h" + + +bool native_is_frame_exists(WalkContext* UNREF context, Registers* UNREF regs) +{ + return false; +} + +bool native_unwind_stack_frame(WalkContext* UNREF context, Registers* UNREF regs) +{ + return false; +} + +void native_get_regs_from_jit_context(JitFrameContext* UNREF jfc, Registers* UNREF regs) +{ +} + +bool native_unwind_special(WalkContext* UNREF context, Registers* UNREF regs) +{ + return false; +} + +void native_fill_frame_info(Registers* UNREF regs, native_frame_t* UNREF frame, jint UNREF jdepth) +{ +} diff --git a/vm/port/src/crash_handler/ipf/reg_state.cpp b/vm/port/src/crash_handler/ipf/reg_state.cpp new file mode 100644 index 0000000..149cb94 --- /dev/null +++ b/vm/port/src/crash_handler/ipf/reg_state.cpp @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "vm_core_types.h" + +void print_reg_state(Registers* regs) +{ + fprintf(stderr, "Registers:"); + + for (int gn = 0; gn < 8; gn++) + { + fprintf(stderr, "\n GR %2d-%2d:", gn*4, (gn+1)*4 - 1); + for (int gc = 0; gc < 4; gc++) + fprintf(stderr, " 0x%"W_PI_FMT, regs->gr[gn*4 + gc]); + } + + for (int bn = 0; bn < 2; bn++) + { + fprintf(stderr, "\n BR %2d-%2d:", bn*4, (bn+1)*4 - 1); + for (int bc = 0; bc < 4; bc++) + fprintf(stderr, " 0x%"W_PI_FMT, regs->br[bn*4 + bc]); + } + + fprintf(stderr, "\n"); + fprintf(stderr, " preds: 0x%"W_PI_FMT"\n", regs->preds); + fprintf(stderr, " nats: 0x%"W_PI_FMT"\n", regs->nats); + fprintf(stderr, " pfs: 0x%"W_PI_FMT"\n", regs->pfs); + fprintf(stderr, " bsp: 0x%"W_PI_FMT"\n", (POINTER_SIZE_INT)regs->bsp); + fprintf(stderr, " *bsp: 0x%"W_PI_FMT"\n", regs->bsp ? (*regs->bsp) : 0); + fprintf(stderr, " ip: 0x%"W_PI_FMT"\n", regs->ip); +} diff --git a/vm/port/src/crash_handler/linux/gdb_crash_handler.cpp b/vm/port/src/crash_handler/linux/gdb_crash_handler.cpp new file mode 100644 index 0000000..16b0bf1 --- /dev/null +++ b/vm/port/src/crash_handler/linux/gdb_crash_handler.cpp @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Intel, Evgueni Brevnov + * @version $Revision: 1.1.2.1.4.3 $ + */ + +#include +#include +#include +#include + +#include "vm_core_types.h" +#include "environment.h" +#include "port_sysinfo.h" +#include "platform_lowlevel.h" +#include "exception_filter.h" +#include "port_thread.h" + +#include "crash_handler.h" + +static char* g_executable = NULL;// Executable file name +static sem_t g_sem_started; // Prevent forking debugger more than once +static bool g_prepared = false; // Flag is set if gdb crash handler is prepared +static bool g_enabled = false; // vm.crash_handler value is stored here + + +#if defined (__INTEL_COMPILER) +#pragma warning ( push ) +#pragma warning (disable:869) +#endif + + +bool is_gdb_crash_handler_enabled() +{ + return (g_prepared && g_enabled); +} + +bool gdb_crash_handler(Registers* regs) +{ + if (!g_prepared || !g_enabled || + !g_executable || + 0 != sem_trywait(&g_sem_started)) // gdb was already started + return false; + + // Print register info + print_reg_state(regs); + + static const int tid_len = 10; + char tid[tid_len]; + snprintf(tid, tid_len, "%d", gettid()); + + if (fork() == 0) + { + fprintf(stderr, "----------------------------------------\n" + "gdb %s %s\n" + "----------------------------------------\n" + , g_executable, tid); + fflush(stderr); + + execlp("gdb", "gdb", g_executable, tid, NULL); + perror("Can't run gdb"); + } + else + { + // give gdb chance to start before the default handler kills the app + sleep(10); + } +} +#if defined (__INTEL_COMPILER) +#pragma warning ( pop ) +#endif + +static int get_executable_name() +{ + if (port_executable_name(&g_executable) != 0) + return -1; + + return g_executable ? 0 : -1; +} + + +void init_gdb_crash_handler() +{ + if (sem_init(&g_sem_started, 0, 1) != 0 || + get_executable_name() != 0) + { + g_prepared = false; + return; + } + + if (!VM_Global_State::loader_env) + g_enabled = true; + else + g_enabled = get_boolean_property("vm.crash_handler", FALSE, VM_PROPERTIES); + + g_prepared = true; +} diff --git a/vm/port/src/crash_handler/linux/include/gdb_crash_handler.h b/vm/port/src/crash_handler/linux/include/gdb_crash_handler.h new file mode 100644 index 0000000..333b646 --- /dev/null +++ b/vm/port/src/crash_handler/linux/include/gdb_crash_handler.h @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Intel, Evgueni Brevnov + * @version $Revision: 1.1.2.1.4.3 $ + */ + +#ifndef _CRASH_HANDLER_H +#define _CRASH_HANDLER_H + +#include "vm_core_types.h" + +/** + * \file + * Provides definition needed to install gdb crash handler. + */ + +/** + * Checks if gdb crash handler is enabled and prepared. + * + * @return true if gdb crash handler is enabled and ready for use. + */ +bool is_gdb_crash_handler_enabled(); + +/** + * Initializes the static state needed for gdb crash handler. + * + * @return 0 on success or negative value on failure + */ +void init_gdb_crash_handler(); + +/** + * Invokes gdb. + * + * @return true on success or false on failure + */ +bool gdb_crash_handler(Registers* regs); + +#endif // _CRASH_HANDLER_H diff --git a/vm/port/src/crash_handler/linux/native_unwind_os.cpp b/vm/port/src/crash_handler/linux/native_unwind_os.cpp new file mode 100644 index 0000000..5af1425 --- /dev/null +++ b/vm/port/src/crash_handler/linux/native_unwind_os.cpp @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include "native_modules.h" +#include "native_stack.h" + + +bool native_is_in_code(WalkContext* context, void* ip) +{ + if (!ip) + return false; + + for (native_module_t* module = context->modules; module; module = module->next) + { + for (size_t i = 0; i < module->seg_count; i++) + { + char* base = (char*)module->segments[i].base; + + if (ip >= base && + ip < (base + module->segments[i].size)) + return true; + } + } + + return false; +} + +bool native_get_stack_range(WalkContext* context, Registers* regs, native_segment_t* seg) +{ + int err; + pthread_attr_t pthread_attr; + + pthread_t thread = pthread_self(); + void* sp = regs->get_sp(); + + if (pthread_attr_init(&pthread_attr) != 0) + return false; + +#if defined(FREEBSD) + err = pthread_attr_get_np(thread, &pthread_attr); +#else + err = pthread_getattr_np(thread, &pthread_attr); +#endif + + if (err != 0) + return false; + + if (pthread_attr_getstack(&pthread_attr, &seg->base, &seg->size)) + return false; + + pthread_attr_destroy(&pthread_attr); + return true; + +/* for (native_module_t* module = context->modules; module; module = module->next) + { + for (size_t i = 0; i < module->seg_count; i++) + { + char* base = (char*)module->segments[i].base; + + if (sp >= base && + sp < (base + module->segments[i].size)) + { + *seg = module->segments[i]; + return true; + } + } + } + + return false; +*/ +} diff --git a/vm/port/src/crash_handler/linux/stack_dump_os.cpp b/vm/port/src/crash_handler/linux/stack_dump_os.cpp new file mode 100644 index 0000000..1bfd0c6 --- /dev/null +++ b/vm/port/src/crash_handler/linux/stack_dump_os.cpp @@ -0,0 +1,266 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "open/hythread_ext.h" +#include "native_stack.h" +#include "port_filepath.h" +#include "port_dso.h" +#include "port_thread.h" +#include "stack_dump.h" + + +static hymutex_t g_lock; +static const char* g_curdir = NULL; +static const char* g_cmdline = NULL; + + +bool sd_initialize(hymutex_t** p_lock) +{ + static int initialized = 0; + + if (!initialized) + { + IDATA err = hymutex_create(&g_lock, APR_THREAD_MUTEX_NESTED); + + if (err != APR_SUCCESS) + return false; + + initialized = true; + } + + if (p_lock) + *p_lock = &g_lock; + + return true; +} + + +static bool sd_is_predefined_name(const char* name) +{ + if (*name != '[') + return false; + + return true; +// return (!strcmp(name, "[heap]") || +// !strcmp(name, "[stack]") || +// !strcmp(name, "[vdso]")); +} + +static inline native_segment_t* sd_find_segment(native_module_t* module, void* ip) +{ + for (size_t i = 0; i < module->seg_count; i++) + { + if (module->segments[i].base <= ip && + (char*)module->segments[i].base + module->segments[i].size > ip) + return &module->segments[i]; + } + + assert(0); + return NULL; +} + +void sd_parse_module_info(native_module_t* module, void* ip) +{ + fprintf(stderr, "\nCrashed module:\n"); + + if (!module) + { // Unknown address + fprintf(stderr, "Unknown address 0x%"W_PI_FMT"\n", + (POINTER_SIZE_INT)ip); + return; + } + + native_segment_t* segment = sd_find_segment(module, ip); + + if (!module->filename) + { + fprintf(stderr, "Unknown memory region 0x%"W_PI_FMT":0x%"W_PI_FMT"%s\n", + (size_t)segment->base, (size_t)segment->base + segment->size, + (segment->type == SEGMENT_TYPE_CODE) ? "" : " without execution rights"); + return; + } + + if (sd_is_predefined_name(module->filename)) + { // Special memory region + fprintf(stderr, "%s memory region 0x%"W_PI_FMT":0x%"W_PI_FMT"%s\n", + module->filename, + (size_t)segment->base, (size_t)segment->base + segment->size, + (segment->type == SEGMENT_TYPE_CODE) ? "" : " without execution rights"); + return; + } + + // Common shared module + const char* short_name = port_filepath_basename(module->filename); + const char* module_type = sd_get_module_type(short_name); + + fprintf(stderr, "%s\n(%s)\n", module->filename, module_type); +} + + +void sd_get_c_method_info(MethodInfo* info, native_module_t* module, void* ip) +{ + *info->method_name = 0; + *info->file_name = 0; + info->line = -1; + + if (!module || !module->filename) + return; + + POINTER_SIZE_INT offset = (POINTER_SIZE_INT)ip; + + if (strstr(module->filename, PORT_DSO_EXT) != NULL) // Shared object + { // IP for addr2line should be an offset within shared library + native_segment_t* seg = sd_find_segment(module, ip); + offset -= (POINTER_SIZE_INT)seg->base; + } + + int po[2]; + pipe(po); + + char ip_str[20]; + sprintf(ip_str, "0x%"PI_FMT"x\n", offset); + + if (!fork()) + { + close(po[0]); + dup2(po[1], 1); + execlp("addr2line", "addr2line", "-f", "-s", "-e", module->filename, "-C", ip_str, NULL); + //fprintf(stderr, "Warning: Cannot run addr2line. No symbolic information will be available\n"); + printf("??\n??:0\n"); // Emulate addr2line output + exit(-1); + } + else + { + close(po[1]); + char buf[sizeof(info->method_name) + sizeof(info->file_name)]; + int status; + wait(&status); + int count = read(po[0], buf, sizeof(buf) - 1); + close(po[0]); + + if (count < 0) + { + fprintf(stderr, "read() failed during addr2line execution\n"); + return; + } + + while (isspace(buf[count-1])) + count--; + + buf[count] = '\0'; + int i = 0; + + for (; i < count; i++) + { + if (buf[i] == '\n') + { // Function name is limited by '\n' + buf[i] = '\0'; + strncpy(info->method_name, buf, sizeof(info->method_name)); + break; + } + } + + if (i == count) + return; + + char* fn = buf + i + 1; + + for (; i < count && buf[i] != ':'; i++); // File name and line number are separated by ':' + + if (i == count) + return; + + buf[i] = '\0'; + strncpy(info->file_name, fn, sizeof(info->file_name)); + + info->line = atoi(buf + i + 1); // Line number + + if (info->line == 0) + info->line = -1; + } +} + +int sd_get_cur_tid() +{ + return gettid(); +} + +void sd_init_crash_handler() +{ + // Get current directory + char buf[PATH_MAX + 1]; + char* cwd = getcwd(buf, sizeof(buf)); + + if (cwd) + { + cwd = (char*)STD_MALLOC(strlen(cwd) + 1); + g_curdir = cwd; + if (cwd) + strcpy(cwd, buf); + } + + // Get command line + sprintf(buf, "/proc/%d/cmdline", getpid()); + int file = open(buf, O_RDONLY); + + if (file > 0) + { + size_t size = 0; + char rdbuf[256]; + ssize_t rd; + do + { + rd = read(file, rdbuf, sizeof(rdbuf)); + size += (rd > 0) ? rd : 0; + } while (rd == sizeof(rdbuf)); + + if (size) + { + char* cmd = (char*)STD_MALLOC(size + 1); + g_cmdline = cmd; + if (cmd) + { + cmd[size + 1] = '\0'; + lseek(file, 0, SEEK_SET); + read(file, cmd, size); + } + } + close(file); + } +} + +void sd_print_cwdcmdenv() +{ + fprintf(stderr, "\nWorking directory:\n%s\n", g_curdir ? g_curdir : "'null'"); + + fprintf(stderr, "\nCommand line:\n"); + for (const char* ptr = g_cmdline; *ptr; ptr += strlen(ptr) + 1) + fprintf(stderr, "%s ", ptr); + fprintf(stderr, "\n"); + + fprintf(stderr, "\nEnvironment variables:\n"); + for (char** env = environ; *env; ++env) + fprintf(stderr, "%s\n", *env); +} diff --git a/vm/port/src/crash_handler/stack_dump.cpp b/vm/port/src/crash_handler/stack_dump.cpp new file mode 100644 index 0000000..948a988 --- /dev/null +++ b/vm/port/src/crash_handler/stack_dump.cpp @@ -0,0 +1,512 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Vladimir Nenashev + * @version $Revision$ + */ + +#include +#include "vm_threads.h" +#include "port_malloc.h" +#include "port_dso.h" +#include "jit_intf_cpp.h" +#include "Class.h" +#include "class_member.h" +#include "exceptions.h" +#include "stack_trace.h" +#include "interpreter_exports.h" +#include "cci.h" +#include "m2n.h" +#include "native_stack.h" +#include "native_modules.h" +#include "natives_support.h" +#include "exception_filter.h" + +#include "stack_dump.h" + + +static native_module_t* g_modules = NULL; + +// Is called to fill modules list (should be called under lock) +static void sd_fill_modules() +{ + if (g_modules) + return; + + int count; + bool res = port_get_all_modules(&g_modules, &count); + assert(res && g_modules && count); +} + +#ifdef SD_UPDATE_MODULES +// Is called to update modules info +void sd_update_modules() +{ + hymutex_t* sd_lock; + bool res = sd_initialize(&sd_lock); + + if (!res) + return; + + hymutex_lock(sd_lock); + + if (g_modules) + port_clear_modules(&g_modules); + + int count; + res = port_get_all_modules(&g_modules, &count); + assert(res && g_modules && count); + + hymutex_unlock(sd_lock); +} +#endif // SD_UPDATE_MODULES + + +static char* sd_construct_java_method_name(Method* m, char* buf) +{ + if (!m || !buf) + { + *buf = 0; + return NULL; + } + + char* ptr = buf; + + const char* err_str = "<--Truncated: too long name"; + size_t err_len = strlen(err_str); + + size_t remain = SD_MNAME_LENGTH - 1; + const char* cname = m->get_class()->get_name()->bytes; + size_t clen = m->get_class()->get_name()->len; + const char* mname = m->get_name()->bytes; + size_t mlen = m->get_name()->len; + const char* descr = m->get_descriptor()->bytes; + size_t dlen = m->get_descriptor()->len; + + if (clen + 1 > remain) + { + size_t len = remain - err_len; + memcpy(ptr, cname, len); + strcpy(ptr + len, err_str); + return buf; + } + + memcpy(ptr, cname, clen); + ptr += clen; + *ptr++ = '.'; + remain -= clen + 1; + + if (mlen > remain) + { + if (remain > err_len) + memcpy(ptr, mname, remain - err_len); + + strcpy(ptr + remain - err_len, err_str); + return buf; + } + + memcpy(ptr, mname, mlen); + ptr += mlen; + remain -= mlen; + + if (dlen > remain) + { + if (remain > err_len) + memcpy(ptr, descr, remain - err_len); + + strcpy(ptr + remain - err_len, err_str); + return buf; + } + + strcpy(ptr, descr); + return buf; +} + +static void sd_get_java_method_info(MethodInfo* info, Method* m, void* ip, + bool is_ip_past, int inl_depth) +{ + *info->method_name = 0; + *info->file_name = 0; + info->line = -1; + + if (!m || !method_get_class(m)) + return; + + if (!sd_construct_java_method_name(m, info->method_name)) + return; + + const char* fname = NULL; + get_file_and_line(m, ip, is_ip_past, inl_depth, &fname, &info->line); + + if (fname) + { + if (strlen(fname) >= sizeof(info->file_name)) + { + memcpy(info->file_name, fname, sizeof(info->file_name)); + info->file_name[sizeof(info->file_name) - 1] = 0; + } + else + strcpy(info->file_name, fname); + } +} + +static void sd_print_line(int count, MethodInfo* m) { + + fprintf(stderr, "%3d: %s (%s:%d)\n", + count, + *m->method_name ? m->method_name : "??", + *m->file_name ? m->file_name : "??", + m->line); +} + + +static void sd_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; + void* cur_ip = frames[frame_num].ip; + + if (frame_num < num_frames && frames[frame_num].java_depth < 0) + { + if (native_is_ip_stub(cur_ip)) // Generated stub + { + char buf[81]; + char* stub_name = + native_get_stub_name(cur_ip, buf, sizeof(buf)); + + fprintf(stderr, "%3d: 0x%"W_PI_FMT": stub '%s'\n", + count++, (POINTER_SIZE_INT)cur_ip, + stub_name ? stub_name : "??"); + ++frame_num; + continue; + } + + // pure native frame + native_module_t* module = port_find_module(g_modules, cur_ip); + sd_get_c_method_info(&m, module, cur_ip); + sd_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 + native_module_t* module = port_find_module(g_modules, cur_ip); + sd_get_c_method_info(&m, module, cur_ip); + sd_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)); + sd_get_java_method_info(&m, method, ip, false, -1); + sd_print_line(count, &m); + } + else // !si_is_native(si) + { + // Print information about Java method from iterator + CodeChunkInfo* cci = si_get_code_chunk_info(si); + 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); + + if (inlined_depth) + { + for (uint32 i = inlined_depth; i > 0; i--) + { + Method* inl_method = cci->get_jit()->get_inlined_method( + cci->get_inline_info(), offset, i); + + sd_get_java_method_info(&m, inl_method, ip, is_ip_past, i); + sd_print_line(count++, &m); + + if (frame_num < num_frames) + ++frame_num; // Go to the next native frame + } + } + + sd_get_java_method_info(&m, method, ip, is_ip_past, -1); + sd_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); +} + +static void sd_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; + + if (frame_num < num_frames && frames[frame_num].java_depth < 0) + { // pure native frame + native_module_t* module = port_find_module(g_modules, frames[frame_num].ip); + sd_get_c_method_info(&m, module, frames[frame_num].ip); + sd_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))) + { + native_module_t* module = port_find_module(g_modules, frames[frame_num].ip); + sd_get_c_method_info(&m, module, frames[frame_num].ip); + sd_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)) + { + sd_get_java_method_info(&m, method, (void*)bc_ptr, false, -1); + sd_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 + } +} + +const char* sd_get_module_type(const char* short_name) +{ + char name[256]; + + if (strlen(short_name) > 255) + return "Too long short name"; + + strcpy(name, short_name); + char* dot = strchr(name, '.'); + + // Strip suffix/extension + if (dot) + *dot = 0; + + // Strip prefix + char* nameptr = name; + + if (!memcmp(short_name, PORT_DSO_PREFIX, strlen(PORT_DSO_PREFIX))) + nameptr += strlen(PORT_DSO_PREFIX); + + char* vm_modules[] = {"java", "em", "encoder", "gc_gen", "gc_gen_uncomp", "gc_cc", + "harmonyvm", "hythr", "interpreter", "jitrino", "vmi"}; + + for (size_t i = 0; i < sizeof(vm_modules)/sizeof(vm_modules[0]); i++) + { + if (!strcmp_case(name, vm_modules[i])) + return "VM native code"; + } + + if (natives_is_library_loaded_slow(short_name)) + return "JNI native library"; + + return "Unknown/system native module"; +} + + +static void sd_print_module_info(Registers* regs) +{ +#ifdef SD_UPDATE_MODULES + sd_fill_modules(); // Fill modules table if needed +#endif + + native_module_t* module = port_find_module(g_modules, (void*)regs->get_ip()); + sd_parse_module_info(module, (void*)regs->get_ip()); +} + +static void sd_print_modules() +{ + fprintf(stderr, "\nLoaded modules:\n\n"); + port_dump_modules(g_modules, stderr); +} + + +static void sd_print_threads_info(VM_thread* cur_thread) +{ + if (!cur_thread) + fprintf(stderr, "\nCurrent thread is not attached to VM, ID: %d\n", sd_get_cur_tid()); + + fprintf(stderr, "\nVM attached threads:\n\n"); + + hythread_iterator_t it = hythread_iterator_create(NULL); + int count = (int)hythread_iterator_size (it); + + for (int i = 0; i < count; i++) + { + hythread_t thread = hythread_iterator_next(&it); + VM_thread* vm_thread = jthread_get_vm_thread(thread); + + if (!vm_thread) + continue; + + jthread java_thread = jthread_get_java_thread(thread); + JNIEnv* jni_env = vm_thread->jni_env; + + if (cur_thread && java_thread) + { + jclass cl = GetObjectClass(jni_env, java_thread); + jmethodID id = jni_env->GetMethodID(cl, "getName","()Ljava/lang/String;"); + jstring name = jni_env->CallObjectMethod(java_thread, id); + char* java_name = (char*)jni_env->GetStringUTFChars(name, NULL); + + fprintf(stderr, "%s[%p] '%s'\n", + (cur_thread && vm_thread == cur_thread) ? "--->" : " ", + thread->os_handle, java_name); + + jni_env->ReleaseStringUTFChars(name, java_name); + } + else + { + fprintf(stderr, "%s[%p]\n", + (cur_thread && vm_thread == cur_thread) ? "--->" : " ", + thread->os_handle); + } + } + + hythread_iterator_release(&it); +} + + +void sd_print_stack(Registers* regs) +{ + hymutex_t* sd_lock; + int disable_count; + bool unwindable; + + VM_thread* thread = get_thread_ptr(); // Can be NULL for pure native thread + + // Enable suspend to allow working with threads + if (thread) + disable_count = hythread_reset_suspend_disable(); + + // Acquire global lock to print threads list and stop other crashed threads + hythread_global_lock(); + + if (!sd_initialize(&sd_lock)) + return; + + hymutex_lock(sd_lock); + if (thread) + unwindable = set_unwindable(false); // To call Java code + + // Print register info + print_reg_state(regs); + + // Print crashed modile info + sd_print_module_info(regs); + + // Print program environment info + sd_print_cwdcmdenv(); + + // Print the whole list of modules + sd_print_modules(); + + native_frame_t* frames = NULL; + + // Print threads info + sd_print_threads_info(thread); + + // 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. + + WalkContext context; + + if (native_init_walk_context(&context, g_modules, regs)) + { + jint num_frames = + walk_native_stack_registers(&context, 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(&context, regs, thread, num_frames, frames); + else + num_frames = 0; // Consider native stack trace empty + + fprintf(stderr, "\nStack trace:\n"); + + if (interpreter_enabled() && thread) + sd_print_stack_interpreter(thread, frames, num_frames); + else // It should be used also for threads without VM_thread structure + sd_print_stack_jit(thread, frames, num_frames); + + fprintf(stderr, "\n"); + fflush(stderr); + } + + if (thread) + set_unwindable(unwindable); + + // Do not unlock to prevent other threads from printing crash stack + //hymutex_unlock(sd_lock); + + hythread_global_unlock(); + if (thread) + hythread_set_suspend_disable(disable_count); +} diff --git a/vm/port/src/crash_handler/win/native_unwind_os.cpp b/vm/port/src/crash_handler/win/native_unwind_os.cpp new file mode 100644 index 0000000..3c32489 --- /dev/null +++ b/vm/port/src/crash_handler/win/native_unwind_os.cpp @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "native_modules.h" +#include "native_stack.h" + + +bool native_is_in_code(WalkContext* context, void* ip) +{ + if (!ip) + return false; + + MEMORY_BASIC_INFORMATION mem_info; + + if (VirtualQuery(ip, &mem_info, sizeof(mem_info)) == 0) + return false; + + if (mem_info.State != MEM_COMMIT) + return false; + + return ((mem_info.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | + PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) != 0); +} + +bool native_get_stack_range(WalkContext* context, Registers* regs, native_segment_t* seg) +{ + MEMORY_BASIC_INFORMATION mem_info; + + if (VirtualQuery(regs->get_sp(), &mem_info, sizeof(mem_info)) == 0) + return false; + + if (mem_info.State != MEM_COMMIT) + return false; + + seg->base = mem_info.BaseAddress; + seg->size = mem_info.RegionSize; + return true; +} diff --git a/vm/port/src/crash_handler/win/stack_dump_os.cpp b/vm/port/src/crash_handler/win/stack_dump_os.cpp new file mode 100644 index 0000000..4005c1d --- /dev/null +++ b/vm/port/src/crash_handler/win/stack_dump_os.cpp @@ -0,0 +1,273 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "open/hythread_ext.h" +#include "native_stack.h" +#include "stack_dump.h" +#include "port_filepath.h" + +#ifndef NO_DBGHELP +#include +#pragma comment(linker, "/defaultlib:dbghelp.lib") +#endif + + +static hymutex_t g_lock; +static const char* g_curdir = NULL; +static const char* g_cmdline = NULL; +static const char* g_environ = NULL; + +#ifndef NO_DBGHELP +typedef BOOL (WINAPI *SymFromAddr_type) + (IN HANDLE hProcess, + IN DWORD64 Address, + OUT PDWORD64 Displacement, + IN OUT PSYMBOL_INFO Symbol ); +typedef BOOL (WINAPI *SymGetLineFromAddr64_type) + (IN HANDLE hProcess, + IN DWORD64 qwAddr, + OUT PDWORD pdwDisplacement, + OUT PIMAGEHLP_LINE64 Line64); + +typedef BOOL (WINAPI *SymGetLineFromAddr_type) + (IN HANDLE hProcess, + IN DWORD dwAddr, + OUT PDWORD pdwDisplacement, + OUT PIMAGEHLP_LINE Line ); + +static SymFromAddr_type g_SymFromAddr = NULL; +static SymGetLineFromAddr64_type g_SymGetLineFromAddr64 = NULL; +static SymGetLineFromAddr_type g_SymGetLineFromAddr = NULL; +#endif // #ifndef NO_DBGHELP + + +bool sd_initialize(hymutex_t** p_lock) +{ + static int initialized = 0; + + if (!initialized) + { + IDATA err = hymutex_create(&g_lock, APR_THREAD_MUTEX_NESTED); + + if (err != APR_SUCCESS) + return false; + +#ifndef NO_DBGHELP +// Preventive initialization does not work +// if (!SymInitialize(GetCurrentProcess(), NULL, TRUE)) +// return false; + + HMODULE hdbghelp = ::LoadLibrary("dbghelp"); + + if (hdbghelp) + { + SymSetOptions(SYMOPT_LOAD_LINES); + g_SymFromAddr = (SymFromAddr_type)::GetProcAddress(hdbghelp, "SymFromAddr"); + g_SymGetLineFromAddr64 = (SymGetLineFromAddr64_type)::GetProcAddress(hdbghelp, "SymGetLineFromAddr64"); + g_SymGetLineFromAddr = (SymGetLineFromAddr_type)::GetProcAddress(hdbghelp, "SymGetLineFromAddr"); + } +#endif // #ifndef NO_DBGHELP + + initialized = true; + } + + if (p_lock) + *p_lock = &g_lock; + + return true; +} + + +static const char* sd_get_region_access_info(MEMORY_BASIC_INFORMATION* pinfo) +{ + if ((pinfo->State & MEM_COMMIT) == 0) + return "not committed"; + + if ((pinfo->Protect & PAGE_GUARD) != 0) + return "guard page occured"; + + if ((pinfo->Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | + PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY | + PAGE_READWRITE | PAGE_READONLY)) != 0) + return ""; + + if ((pinfo->Protect & (PAGE_READWRITE | PAGE_READONLY)) != 0) + return "without execution rights"; + + return "without read rights";; +} + +void sd_parse_module_info(native_module_t* module, void* ip) +{ + fprintf(stderr, "\nCrashed module:\n"); + + if (module) + { + native_segment_t* segment = module->segments; + + assert(module->filename); + + if (!module->filename) + { // We should not reach this code + fprintf(stderr, "Unknown memory region 0x%"W_PI_FMT":0x%"W_PI_FMT"%s\n", + (size_t)segment->base, (size_t)segment->base + segment->size, + (segment->type == SEGMENT_TYPE_CODE) ? "" : " without execution rights"); + return; + } + + // Common shared module + const char* short_name = port_filepath_basename(module->filename); + const char* module_type = sd_get_module_type(short_name); + fprintf(stderr, "%s\n(%s)\n", module->filename, module_type); + return; + } + + // module == NULL + size_t start_addr, end_addr, region_size; + MEMORY_BASIC_INFORMATION mem_info; + + VirtualQuery(ip, &mem_info, sizeof(mem_info)); + start_addr = (size_t)mem_info.BaseAddress; + region_size = (size_t)mem_info.RegionSize; + end_addr = start_addr + region_size; + + fprintf(stderr, "Memory region 0x%"W_PI_FMT":0x%"W_PI_FMT" %s\n", + start_addr, end_addr, sd_get_region_access_info(&mem_info)); +} + + +void sd_get_c_method_info(MethodInfo* info, native_module_t* UNREF module, void* ip) +{ + *info->method_name = 0; + *info->file_name = 0; + info->line = -1; + +#ifndef NO_DBGHELP + + if (!SymInitialize(GetCurrentProcess(), NULL, TRUE)) + return; + + BYTE smBuf[sizeof(SYMBOL_INFO) + SD_MNAME_LENGTH - 1]; + PSYMBOL_INFO pSymb = (PSYMBOL_INFO)smBuf; + pSymb->SizeOfStruct = sizeof(SYMBOL_INFO); + pSymb->MaxNameLen = SD_MNAME_LENGTH; + DWORD64 funcDispl; + + if (g_SymFromAddr && + g_SymFromAddr(GetCurrentProcess(), (DWORD64)(POINTER_SIZE_INT)ip, &funcDispl, pSymb)) + { + strcpy(info->method_name, pSymb->Name); + } + + if (g_SymGetLineFromAddr64) + { + DWORD offset; + IMAGEHLP_LINE64 lineinfo; + lineinfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + + if (g_SymGetLineFromAddr64(GetCurrentProcess(), + (DWORD64)(POINTER_SIZE_INT)ip, + &offset, &lineinfo)) + { + info->line = lineinfo.LineNumber; + strncpy(info->file_name, lineinfo.FileName, sizeof(info->file_name)); + return; + } + } + + if (g_SymGetLineFromAddr) + { + DWORD offset; + IMAGEHLP_LINE lineinfo; + lineinfo.SizeOfStruct = sizeof(IMAGEHLP_LINE); + + if (g_SymGetLineFromAddr(GetCurrentProcess(), + (DWORD)(POINTER_SIZE_INT)ip, + &offset, &lineinfo)) + { + info->line = lineinfo.LineNumber; + strncpy(info->file_name, lineinfo.FileName, sizeof(info->file_name)); + } + } + +#endif // #ifndef NO_DBGHELP +} + +int sd_get_cur_tid() +{ + return GetCurrentThreadId(); +} + +void sd_init_crash_handler() +{ + // Get current directory + DWORD required = GetCurrentDirectory(0, NULL); + char* ptr = (char*)STD_MALLOC(required); + + if (ptr) + { + GetCurrentDirectory(required, ptr); + g_curdir = ptr; + } + + // Get command line + LPTSTR cmdline = GetCommandLine(); + ptr = (char*)STD_MALLOC(strlen(cmdline) + 1); + strcpy(ptr, cmdline); + g_cmdline = ptr; + + // Get environment + LPVOID env_block = GetEnvironmentStrings(); + + if (!env_block) + return; + + size_t total_len = 1; + ptr = (char*)env_block; + + while (*ptr) + { + total_len += strlen(ptr) + 1; + ptr += strlen(ptr) + 1; + } + + ptr = (char*)STD_MALLOC(total_len); + + if (ptr) + { + memcpy(ptr, env_block, total_len); + g_environ = ptr; + } + + FreeEnvironmentStrings((char*)env_block); +} + +void sd_print_cwdcmdenv() +{ + fprintf(stderr, "\nWorking directory:\n%s\n", g_curdir ? g_curdir : "'null'"); + fprintf(stderr, "\nCommand line:\n%s\n", g_cmdline); + + fprintf(stderr, "\nEnvironment variables:\n"); + + const char* penv = (char*)g_environ; + + while (*penv) + { + fprintf(stderr, "%s\n", penv); + penv += strlen(penv) + 1; + } +} diff --git a/vm/port/src/memaccess/linux/memaccess.cpp b/vm/port/src/memaccess/linux/memaccess.cpp new file mode 100644 index 0000000..ec98839 --- /dev/null +++ b/vm/port/src/memaccess/linux/memaccess.cpp @@ -0,0 +1,287 @@ +/** + * @author Ilya Berezhniuk + * @version $Revision$ + */ +#include +#include + +#include "port_vmem.h" +#ifdef _IA32_ +#include "encoder.h" +#include "jit_intf_cpp.h" +#endif // #ifdef _IA32_ +#include "nogc.h" +#include "dump.h" +#include "ncai_direct.h" +#include "ncai_internal.h" + + +typedef void* (__cdecl *get_return_address_stub_type)(); + + +#ifdef _IA32_ + +static get_return_address_stub_type gen_get_return_address_stub() +{ + static get_return_address_stub_type addr = NULL; + + if (addr) + return addr; + + const int stub_size = 0x04; + char *stub = (char *)malloc_fixed_code_for_jit(stub_size, DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_COLD, CAA_Allocate); +#ifdef _DEBUG + memset(stub, 0xcc /*int 3*/, stub_size); +#endif + char *ss = stub; + + M_Base_Opnd m1(esp_reg, 0); + ss = mov(ss, eax_opnd, m1); + ss = ret(ss); + + addr = (get_return_address_stub_type)stub; + assert(ss - stub <= stub_size); + + /* + The following code will be generated: + + mov eax,dword ptr [esp] + ret + */ + + DUMP_STUB(stub, "get_return_address", ss - stub); + + return addr; +} +#endif // #ifdef _IA32_ + + +ncaiError ncai_read_memory_internal(void* addr, size_t size, void* buf, bool UNUSED calc_pass = false) +{ +#ifndef _IA32_ + // SIGSEGV processing is not implemented for EM64T/IPF + memcpy(buf, addr, size); + return NCAI_ERROR_NONE; +#else // #ifndef _IA32_ + +static void* read_memory_1st_label = NULL; +static void* read_memory_2nd_label = NULL; + + char dummy_str[3]; + + if (calc_pass) + { + addr = dummy_str; + buf = dummy_str; + *dummy_str = 'a'; // To avoid warnings + size = 1; + } + + jvmti_thread_t jvmti_thread = &p_TLS_vmthread->jvmti_thread; + + unsigned char* src_ptr = (unsigned char*)addr; + unsigned char* dest_ptr = (unsigned char*)buf; + + jvmti_thread->violation_flag = 1; + jvmti_thread->violation_restart_address = read_memory_1st_label; + + size_t i; + for (i = 0; i < size; i++) + { + *dest_ptr = *src_ptr; + + void* label = (gen_get_return_address_stub())(); + read_memory_1st_label = label; + + if (jvmti_thread->violation_flag == 0) + break; + + ++src_ptr; + ++dest_ptr; + } + + if (jvmti_thread->violation_flag == 0 || calc_pass) + { + if (!calc_pass) + { + size_t* page_sizes = port_vmem_page_sizes(); + size_t page_size = page_sizes[0]; + + POINTER_SIZE_INT start = + ((POINTER_SIZE_INT)addr + i) & ~(page_size - 1); + POINTER_SIZE_INT pastend = + ((POINTER_SIZE_INT)addr + size + page_size - 1) & ~(page_size - 1); + + int result = mprotect((void*)start, pastend - start, + PROT_READ | PROT_WRITE | PROT_EXEC); + + if (result == EAGAIN) + { + timespec delay = {0, 10}; + nanosleep(&delay, NULL); + result = mprotect((void*)start, pastend - start, + PROT_READ | PROT_WRITE | PROT_EXEC); + } + + if (result != 0) + return NCAI_ERROR_ACCESS_DENIED; + } + + if (calc_pass) + ++size; + + jvmti_thread->violation_flag = 1; + jvmti_thread->violation_restart_address = read_memory_2nd_label; + + for (; i < size; i++) + { + *dest_ptr++ = *src_ptr++; + + void* label = (gen_get_return_address_stub())(); + read_memory_2nd_label = label; + + if (jvmti_thread->violation_flag == 0) + return NCAI_ERROR_ACCESS_DENIED; + } + } + + jvmti_thread->violation_flag = 0; + return NCAI_ERROR_NONE; +#endif // #ifndef _IA32_ +} + + +ncaiError ncai_read_memory(void* addr, size_t size, void* buf) +{ + if (!buf || !addr) + return NCAI_ERROR_NULL_POINTER; + + if (size == 0) + return NCAI_ERROR_ILLEGAL_ARGUMENT; + + if (p_TLS_vmthread == NULL) + return NCAI_ERROR_INTERNAL; + + if (ncai_read_memory_internal(NULL, 0, NULL, true) != NCAI_ERROR_NONE) + return NCAI_ERROR_INTERNAL; + + return ncai_read_memory_internal(addr, size, buf, false); +} + + +static ncaiError ncai_write_memory_internal(void* addr, size_t size, void* buf, bool UNUSED calc_pass = false) +{ +#ifndef _IA32_ + // SIGSEGV processing is not implemented for EM64T/IPF + memcpy(addr, buf, size); + return NCAI_ERROR_NONE; +#else // #ifndef _IA32_ + +static void* write_memory_1st_label = NULL; +static void* write_memory_2nd_label = NULL; + + char dummy_str[3]; + + if (calc_pass) + { + addr = dummy_str; + buf = dummy_str; + *dummy_str = 'a'; // To avoid warnings + size = 1; + } + + jvmti_thread_t jvmti_thread = &p_TLS_vmthread->jvmti_thread; + + unsigned char* src_ptr = (unsigned char*)buf; + unsigned char* dest_ptr = (unsigned char*)addr; + + jvmti_thread->violation_flag = 1; + jvmti_thread->violation_restart_address = write_memory_1st_label; + + size_t i; + for (i = 0; i < size; i++) + { + *dest_ptr = *src_ptr; + + void* label = (gen_get_return_address_stub())(); + write_memory_1st_label = label; + + if (jvmti_thread->violation_flag == 0) + break; + + ++src_ptr; + ++dest_ptr; + } + + if (jvmti_thread->violation_flag == 0 || calc_pass) + { + if (!calc_pass) + { + size_t* page_sizes = port_vmem_page_sizes(); + size_t page_size = page_sizes[0]; + + POINTER_SIZE_INT start = + ((POINTER_SIZE_INT)addr + i) & ~(page_size - 1); + POINTER_SIZE_INT pastend = + ((POINTER_SIZE_INT)addr + size + page_size - 1) & ~(page_size - 1); + + int result = mprotect((void*)start, pastend - start, + PROT_READ | PROT_WRITE | PROT_EXEC); + + if (result == EAGAIN) + { + timespec delay = {0, 10}; + nanosleep(&delay, NULL); + result = mprotect((void*)start, pastend - start, + PROT_READ | PROT_WRITE | PROT_EXEC); + } + + if (result != 0) + return NCAI_ERROR_ACCESS_DENIED; + } + + if (calc_pass) + ++size; + + jvmti_thread->violation_flag = 1; + jvmti_thread->violation_restart_address = write_memory_2nd_label; + + for (; i < size; i++) + { + *dest_ptr++ = *src_ptr++; + + void* label = (gen_get_return_address_stub())(); + write_memory_2nd_label = label; + + if (jvmti_thread->violation_flag == 0) + return NCAI_ERROR_ACCESS_DENIED; + } + } + +#ifdef _IPF_ + asm volatile ("mf" ::: "memory"); +#else + __asm__("mfence"); +#endif + + jvmti_thread->violation_flag = 0; + return NCAI_ERROR_NONE; +#endif // #ifndef _IA32_ +} + +ncaiError ncai_write_memory(void* addr, size_t size, void* buf) +{ + if (!buf || !addr) + return NCAI_ERROR_NULL_POINTER; + + if (size == 0) + return NCAI_ERROR_ILLEGAL_ARGUMENT; + + if (p_TLS_vmthread == NULL) + return NCAI_ERROR_INTERNAL; + + if (ncai_write_memory_internal(NULL, 0, NULL, true) != NCAI_ERROR_NONE) + return NCAI_ERROR_INTERNAL; + + return ncai_write_memory_internal(addr, size, buf, false); +} diff --git a/vm/port/src/memaccess/win/memaccess.cpp b/vm/port/src/memaccess/win/memaccess.cpp new file mode 100644 index 0000000..1c72ef6 --- /dev/null +++ b/vm/port/src/memaccess/win/memaccess.cpp @@ -0,0 +1,49 @@ +/** + * @author Ilya Berezhniuk + * @version $Revision$ + */ +#include "ncai_direct.h" +#include "ncai_internal.h" + + +ncaiError ncai_read_memory(void* addr, size_t size, void* buf) +{ + if (!buf || !addr) + return NCAI_ERROR_NULL_POINTER; + + if (size == 0) + return NCAI_ERROR_ILLEGAL_ARGUMENT; + + SIZE_T bytes_read; + + BOOL result = ReadProcessMemory(GetCurrentProcess(), + addr, buf, size, &bytes_read); + assert(bytes_read == size); + + if (!result) + return NCAI_ERROR_ACCESS_DENIED; + + return NCAI_ERROR_NONE; +} + +ncaiError ncai_write_memory(void* addr, size_t size, void* buf) +{ + if (!buf || !addr) + return NCAI_ERROR_NULL_POINTER; + + if (size == 0) + return NCAI_ERROR_ILLEGAL_ARGUMENT; + + SIZE_T bytes_written; + + BOOL result = WriteProcessMemory(GetCurrentProcess(), + addr, buf, size, &bytes_written); + assert(bytes_written == size); + + if (!result) + return NCAI_ERROR_ACCESS_DENIED; + + FlushInstructionCache(GetCurrentProcess(), addr, size); + + return NCAI_ERROR_NONE; +} diff --git a/vm/port/src/signals/win/signals_em64t.asm b/vm/port/src/signals/win/signals_em64t.asm new file mode 100644 index 0000000..b54aa4f --- /dev/null +++ b/vm/port/src/signals/win/signals_em64t.asm @@ -0,0 +1,27 @@ +PUBLIC vectored_exception_handler +EXTRN vectored_exception_handler_internal:PROC + +_TEXT SEGMENT + +vectored_exception_handler PROC + +; LONG NTAPI vectored_exception_handler(LPEXCEPTION_POINTERS nt_exception) +; Args: +; rcx - nt_exception +; rdx - none +; r8 - none +; r9 - none + + pushfq + cld + sub rsp, 32 ; allocate stack for 4 registers + call vectored_exception_handler_internal + add rsp, 32 + popfq + ret + +vectored_exception_handler ENDP + +_TEXT ENDS + +END diff --git a/vm/port/src/signals/win/signals_ia32.cpp b/vm/port/src/signals/win/signals_ia32.cpp new file mode 100644 index 0000000..feef001 --- /dev/null +++ b/vm/port/src/signals/win/signals_ia32.cpp @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "platform_lowlevel.h" +#include "exceptions_jit.h" +#include "exception_filter.h" + + +LONG __declspec(naked) NTAPI vectored_exception_handler(LPEXCEPTION_POINTERS nt_exception) +{ + __asm { + push ebp + mov ebp,esp + pushfd + cld + mov eax, [ebp + 8] + push eax + call vectored_exception_handler_internal + popfd + pop ebp + ret 4 + } +} diff --git a/vm/vmcore/include/stack_dump.h b/vm/vmcore/include/stack_dump.h deleted file mode 100644 index 8126316..0000000 --- a/vm/vmcore/include/stack_dump.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Vladimir Nenashev - * @version $Revision$ - */ - - -#ifndef __STACK_DUMP_H_ -#define __STACK_DUMP_H_ - -#include "open/hythread_ext.h" -#include "vm_core_types.h" -#include "jni.h" -#include "native_modules.h" - - -#ifdef _DEBUG -#define SD_UPDATE_MODULES -#endif - -#ifdef SD_UPDATE_MODULES -#define sd_update_modules() sd_update_modules() -#else -#define sd_update_modules() -#endif - -#ifdef PLATFORM_POSIX -#include -#define strcmp_case strcasecmp -#else // Win -#include -#define strcmp_case _stricmp -#endif - -#include "platform_lowlevel.h" - -#define SD_MNAME_LENGTH 2048 - -// Symbolic method info: method name, source file name and a line number of an instruction within the method -struct MethodInfo { - char method_name[SD_MNAME_LENGTH]; - char file_name[_MAX_PATH]; - int line; -}; - - -/** - * Prints a stack trace using given register context for current thread - */ -void sd_print_stack(Registers* regs); - -/** - * Updates modules list for crash reporting - */ -#ifdef SD_UPDATE_MODULES -void sd_update_modules(); -#endif - -// platform-dependent functions -bool sd_initialize(hymutex_t** p_lock); -void sd_parse_module_info(native_module_t* module, void* ip); -void sd_get_c_method_info(MethodInfo* info, native_module_t* module, void* ip); -int sd_get_cur_tid(); -void sd_init_crash_handler(); -void sd_print_cwdcmdenv(); - -// general functions to call from platform-dependent code -const char* sd_get_module_type(const char* short_name); - -#endif //!__STACK_DUMP_H_ diff --git a/vm/vmcore/src/ncai/utils/ncai_memory_linux.cpp b/vm/vmcore/src/ncai/utils/ncai_memory_linux.cpp deleted file mode 100644 index ec98839..0000000 --- a/vm/vmcore/src/ncai/utils/ncai_memory_linux.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/** - * @author Ilya Berezhniuk - * @version $Revision$ - */ -#include -#include - -#include "port_vmem.h" -#ifdef _IA32_ -#include "encoder.h" -#include "jit_intf_cpp.h" -#endif // #ifdef _IA32_ -#include "nogc.h" -#include "dump.h" -#include "ncai_direct.h" -#include "ncai_internal.h" - - -typedef void* (__cdecl *get_return_address_stub_type)(); - - -#ifdef _IA32_ - -static get_return_address_stub_type gen_get_return_address_stub() -{ - static get_return_address_stub_type addr = NULL; - - if (addr) - return addr; - - const int stub_size = 0x04; - char *stub = (char *)malloc_fixed_code_for_jit(stub_size, DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_COLD, CAA_Allocate); -#ifdef _DEBUG - memset(stub, 0xcc /*int 3*/, stub_size); -#endif - char *ss = stub; - - M_Base_Opnd m1(esp_reg, 0); - ss = mov(ss, eax_opnd, m1); - ss = ret(ss); - - addr = (get_return_address_stub_type)stub; - assert(ss - stub <= stub_size); - - /* - The following code will be generated: - - mov eax,dword ptr [esp] - ret - */ - - DUMP_STUB(stub, "get_return_address", ss - stub); - - return addr; -} -#endif // #ifdef _IA32_ - - -ncaiError ncai_read_memory_internal(void* addr, size_t size, void* buf, bool UNUSED calc_pass = false) -{ -#ifndef _IA32_ - // SIGSEGV processing is not implemented for EM64T/IPF - memcpy(buf, addr, size); - return NCAI_ERROR_NONE; -#else // #ifndef _IA32_ - -static void* read_memory_1st_label = NULL; -static void* read_memory_2nd_label = NULL; - - char dummy_str[3]; - - if (calc_pass) - { - addr = dummy_str; - buf = dummy_str; - *dummy_str = 'a'; // To avoid warnings - size = 1; - } - - jvmti_thread_t jvmti_thread = &p_TLS_vmthread->jvmti_thread; - - unsigned char* src_ptr = (unsigned char*)addr; - unsigned char* dest_ptr = (unsigned char*)buf; - - jvmti_thread->violation_flag = 1; - jvmti_thread->violation_restart_address = read_memory_1st_label; - - size_t i; - for (i = 0; i < size; i++) - { - *dest_ptr = *src_ptr; - - void* label = (gen_get_return_address_stub())(); - read_memory_1st_label = label; - - if (jvmti_thread->violation_flag == 0) - break; - - ++src_ptr; - ++dest_ptr; - } - - if (jvmti_thread->violation_flag == 0 || calc_pass) - { - if (!calc_pass) - { - size_t* page_sizes = port_vmem_page_sizes(); - size_t page_size = page_sizes[0]; - - POINTER_SIZE_INT start = - ((POINTER_SIZE_INT)addr + i) & ~(page_size - 1); - POINTER_SIZE_INT pastend = - ((POINTER_SIZE_INT)addr + size + page_size - 1) & ~(page_size - 1); - - int result = mprotect((void*)start, pastend - start, - PROT_READ | PROT_WRITE | PROT_EXEC); - - if (result == EAGAIN) - { - timespec delay = {0, 10}; - nanosleep(&delay, NULL); - result = mprotect((void*)start, pastend - start, - PROT_READ | PROT_WRITE | PROT_EXEC); - } - - if (result != 0) - return NCAI_ERROR_ACCESS_DENIED; - } - - if (calc_pass) - ++size; - - jvmti_thread->violation_flag = 1; - jvmti_thread->violation_restart_address = read_memory_2nd_label; - - for (; i < size; i++) - { - *dest_ptr++ = *src_ptr++; - - void* label = (gen_get_return_address_stub())(); - read_memory_2nd_label = label; - - if (jvmti_thread->violation_flag == 0) - return NCAI_ERROR_ACCESS_DENIED; - } - } - - jvmti_thread->violation_flag = 0; - return NCAI_ERROR_NONE; -#endif // #ifndef _IA32_ -} - - -ncaiError ncai_read_memory(void* addr, size_t size, void* buf) -{ - if (!buf || !addr) - return NCAI_ERROR_NULL_POINTER; - - if (size == 0) - return NCAI_ERROR_ILLEGAL_ARGUMENT; - - if (p_TLS_vmthread == NULL) - return NCAI_ERROR_INTERNAL; - - if (ncai_read_memory_internal(NULL, 0, NULL, true) != NCAI_ERROR_NONE) - return NCAI_ERROR_INTERNAL; - - return ncai_read_memory_internal(addr, size, buf, false); -} - - -static ncaiError ncai_write_memory_internal(void* addr, size_t size, void* buf, bool UNUSED calc_pass = false) -{ -#ifndef _IA32_ - // SIGSEGV processing is not implemented for EM64T/IPF - memcpy(addr, buf, size); - return NCAI_ERROR_NONE; -#else // #ifndef _IA32_ - -static void* write_memory_1st_label = NULL; -static void* write_memory_2nd_label = NULL; - - char dummy_str[3]; - - if (calc_pass) - { - addr = dummy_str; - buf = dummy_str; - *dummy_str = 'a'; // To avoid warnings - size = 1; - } - - jvmti_thread_t jvmti_thread = &p_TLS_vmthread->jvmti_thread; - - unsigned char* src_ptr = (unsigned char*)buf; - unsigned char* dest_ptr = (unsigned char*)addr; - - jvmti_thread->violation_flag = 1; - jvmti_thread->violation_restart_address = write_memory_1st_label; - - size_t i; - for (i = 0; i < size; i++) - { - *dest_ptr = *src_ptr; - - void* label = (gen_get_return_address_stub())(); - write_memory_1st_label = label; - - if (jvmti_thread->violation_flag == 0) - break; - - ++src_ptr; - ++dest_ptr; - } - - if (jvmti_thread->violation_flag == 0 || calc_pass) - { - if (!calc_pass) - { - size_t* page_sizes = port_vmem_page_sizes(); - size_t page_size = page_sizes[0]; - - POINTER_SIZE_INT start = - ((POINTER_SIZE_INT)addr + i) & ~(page_size - 1); - POINTER_SIZE_INT pastend = - ((POINTER_SIZE_INT)addr + size + page_size - 1) & ~(page_size - 1); - - int result = mprotect((void*)start, pastend - start, - PROT_READ | PROT_WRITE | PROT_EXEC); - - if (result == EAGAIN) - { - timespec delay = {0, 10}; - nanosleep(&delay, NULL); - result = mprotect((void*)start, pastend - start, - PROT_READ | PROT_WRITE | PROT_EXEC); - } - - if (result != 0) - return NCAI_ERROR_ACCESS_DENIED; - } - - if (calc_pass) - ++size; - - jvmti_thread->violation_flag = 1; - jvmti_thread->violation_restart_address = write_memory_2nd_label; - - for (; i < size; i++) - { - *dest_ptr++ = *src_ptr++; - - void* label = (gen_get_return_address_stub())(); - write_memory_2nd_label = label; - - if (jvmti_thread->violation_flag == 0) - return NCAI_ERROR_ACCESS_DENIED; - } - } - -#ifdef _IPF_ - asm volatile ("mf" ::: "memory"); -#else - __asm__("mfence"); -#endif - - jvmti_thread->violation_flag = 0; - return NCAI_ERROR_NONE; -#endif // #ifndef _IA32_ -} - -ncaiError ncai_write_memory(void* addr, size_t size, void* buf) -{ - if (!buf || !addr) - return NCAI_ERROR_NULL_POINTER; - - if (size == 0) - return NCAI_ERROR_ILLEGAL_ARGUMENT; - - if (p_TLS_vmthread == NULL) - return NCAI_ERROR_INTERNAL; - - if (ncai_write_memory_internal(NULL, 0, NULL, true) != NCAI_ERROR_NONE) - return NCAI_ERROR_INTERNAL; - - return ncai_write_memory_internal(addr, size, buf, false); -} diff --git a/vm/vmcore/src/ncai/utils/ncai_memory_win.cpp b/vm/vmcore/src/ncai/utils/ncai_memory_win.cpp deleted file mode 100644 index 1c72ef6..0000000 --- a/vm/vmcore/src/ncai/utils/ncai_memory_win.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/** - * @author Ilya Berezhniuk - * @version $Revision$ - */ -#include "ncai_direct.h" -#include "ncai_internal.h" - - -ncaiError ncai_read_memory(void* addr, size_t size, void* buf) -{ - if (!buf || !addr) - return NCAI_ERROR_NULL_POINTER; - - if (size == 0) - return NCAI_ERROR_ILLEGAL_ARGUMENT; - - SIZE_T bytes_read; - - BOOL result = ReadProcessMemory(GetCurrentProcess(), - addr, buf, size, &bytes_read); - assert(bytes_read == size); - - if (!result) - return NCAI_ERROR_ACCESS_DENIED; - - return NCAI_ERROR_NONE; -} - -ncaiError ncai_write_memory(void* addr, size_t size, void* buf) -{ - if (!buf || !addr) - return NCAI_ERROR_NULL_POINTER; - - if (size == 0) - return NCAI_ERROR_ILLEGAL_ARGUMENT; - - SIZE_T bytes_written; - - BOOL result = WriteProcessMemory(GetCurrentProcess(), - addr, buf, size, &bytes_written); - assert(bytes_written == size); - - if (!result) - return NCAI_ERROR_ACCESS_DENIED; - - FlushInstructionCache(GetCurrentProcess(), addr, size); - - return NCAI_ERROR_NONE; -} diff --git a/vm/vmcore/src/stack/native_stack.cpp b/vm/vmcore/src/stack/native_stack.cpp new file mode 100644 index 0000000..25ee12e --- /dev/null +++ b/vm/vmcore/src/stack/native_stack.cpp @@ -0,0 +1,468 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya Berezhniuk + * @version $Revision: 1.1.2.1 $ + */ + +#include +#include "lock_manager.h" +#include "method_lookup.h" +#include "m2n.h" +#include "stack_trace.h" +#include "interpreter.h" +#include "interpreter_exports.h" +#include "compile.h" +#include "jvmti_break_intf.h" +#include "environment.h" +#include "native_modules.h" +#include "native_stack.h" + + +////////////////////////////////////////////////////////////////////////////// +/// Helper functions + +static DynamicCode* native_find_stub(void* ip) +{ + for (DynamicCode *dcList = compile_get_dynamic_code_list(); + NULL != dcList; dcList = dcList->next) + { + if (ip >= dcList->address && + ip < (void*)((POINTER_SIZE_INT)dcList->address + dcList->length)) + return dcList; + } + + return NULL; +} + +char* native_get_stub_name(void* ip, char* buf, size_t buflen) +{ + // Synchronizing access to dynamic code list + LMAutoUnlock dcll(VM_Global_State::loader_env->p_dclist_lock); + + if (!buf || buflen == 0) + return NULL; + + DynamicCode* code = native_find_stub(ip); + + if (!code || !code->name) + return NULL; + + strncpy(buf, code->name, buflen); + buf[buflen - 1] = '\0'; + + return buf; +} + +bool native_is_in_stack(WalkContext* context, void* sp) +{ + return (sp >= context->stack.base && + sp < (char*)context->stack.base + context->stack.size); +} + +bool native_is_ip_stub(void* ip) +{ + // Synchronizing access to dynamic code list + LMAutoUnlock dcll(VM_Global_State::loader_env->p_dclist_lock); + + return (native_find_stub(ip) != NULL); +} + +/* +Now the technique for calling C handler from a signal/exception context +guarantees that all needed return addresses are present in stack, so +there is no need in special processing +static bool native_is_ip_in_breakpoint_handler(void* ip) +{ + return (ip >= &process_native_breakpoint_event && + ip < &jvmti_jit_breakpoint_handler); +}*/ +/// Helper functions +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// +// + +bool native_init_walk_context(WalkContext* context, native_module_t* modules, Registers* regs) +{ + if (!context) + return false; + + if (!modules) + { + int mod_count; + native_module_t* mod_list = NULL; + + if (!port_get_all_modules(&mod_list, &mod_count)) + return false; + + context->clean_modules = true; + context->modules = mod_list; + } + else + { + context->clean_modules = false; + context->modules = modules; + } + + if (!native_get_stack_range(context, regs, &context->stack)) + { + if (context->clean_modules) + port_clear_modules(&context->modules); + return false; + } + + return true; +} + +void native_clean_walk_context(WalkContext* context) +{ + if (!context) + return; + + if (context->modules && context->clean_modules) + { + port_clear_modules(&context->modules); + } + + context->modules = NULL; +} + + +static int walk_native_stack_jit( + WalkContext* context, + Registers* pregs, VM_thread* pthread, + int max_depth, native_frame_t* frame_array); +static int walk_native_stack_pure( + WalkContext* context, Registers* pregs, + int max_depth, native_frame_t* frame_array); +static int walk_native_stack_interpreter( + WalkContext* context, + Registers* pregs, VM_thread* pthread, + int max_depth, native_frame_t* frame_array); + +int walk_native_stack_registers(WalkContext* context, Registers* pregs, + VM_thread* pthread, int max_depth, native_frame_t* frame_array) +{ + if (pthread == NULL) // Pure native thread + return walk_native_stack_pure(context, pregs, max_depth, frame_array); + + if (interpreter_enabled()) + return walk_native_stack_interpreter(context, pregs, + pthread, max_depth, frame_array); + + return walk_native_stack_jit(context, pregs, pthread, max_depth, frame_array); + return 0; +} + + +static int walk_native_stack_jit( + WalkContext* context, + Registers* pregs, VM_thread* pthread, + int max_depth, native_frame_t* frame_array) +{ + // Register context for current frame + Registers regs = *pregs; + + int frame_count = 0; + + // Search for method containing corresponding address + VM_Code_Type code_type = vm_identify_eip(regs.get_ip()); + bool flag_dummy_frame = false; + jint java_depth = 0; + StackIterator* si = NULL; + bool is_java = false; + + if (code_type == VM_TYPE_JAVA) + { // We must add dummy M2N frame to start SI iteration + if (!pthread) + return 0; + + is_java = true; + + M2nFrame* lm2n = m2n_get_last_frame(pthread); + + if (!m2n_is_suspended_frame(lm2n) || m2n_get_ip(lm2n) != regs.get_ip()) + { // We should not push frame if it was pushed by breakpoint handler + m2n_push_suspended_frame(pthread, ®s); + flag_dummy_frame = true; + } + } + + si = si_create_from_native(pthread); + + if (is_java || + // Frame was pushed already by breakpoint handler + (si_is_native(si) && si_get_m2n(si) && m2n_is_suspended_frame(si_get_m2n(si)))) + { + si_goto_previous(si); + } + + jint inline_index = -1; + jint inline_count; + CodeChunkInfo* cci = NULL; + bool is_stub = false; + int special_count = 0; + bool flag_breakpoint = false; + + while (1) + { + if (frame_array != NULL && frame_count >= max_depth) + break; + + if (frame_array) + { // If frames requested, store current frame + native_fill_frame_info(®s, &frame_array[frame_count], + is_java ? java_depth : -1); + } + + ++frame_count; + +///////////////////////// +// vv Java vv + if (is_java) //code_type == VM_TYPE_JAVA + { // Go to previous frame using StackIterator + cci = si_get_code_chunk_info(si); + if (!cci) // Java method should contain cci + break; + + // if (inline_index < 0) we have new si + // (inline_index < inline_count) we must process inline + // (inline_index == inline_count) we must process si itself + if (inline_index < 0) + { + inline_count = si_get_inline_depth(si); + inline_index = 0; + } + + ++java_depth; + + if (inline_index < inline_count) + { // Process inlined method + // We don't need to update context, + // because context is equal for + // all inlined methods + ++inline_index; + } + else + { + inline_index = -1; + // Go to previous stack frame from StackIterator + si_goto_previous(si); + native_get_regs_from_jit_context(si_get_jit_context(si), ®s); + } + + code_type = vm_identify_eip(regs.get_ip()); + is_java = (code_type == VM_TYPE_JAVA); + continue; + } +// ^^ Java ^^ +///////////////////////// +// vv Native vv + is_stub = native_is_ip_stub(regs.get_ip()); + + if (is_stub) + { // Native stub, previous frame is Java frame + if (!si_is_native(si)) + break; + + if (si_get_method(si)) // Frame represents JNI frame + { + // Mark first frame (JNI stub) as Java frame + if (frame_array && frame_count == 1) + frame_array[frame_count - 1].java_depth = java_depth; + + if (frame_array && frame_count > 1) + frame_array[frame_count - 2].java_depth = java_depth; + + ++java_depth; + } + + // Ge to previous stack frame from StackIterator + si_goto_previous(si); + // Let's get context from si + native_get_regs_from_jit_context(si_get_jit_context(si), ®s); + } + else + { + Registers tmp_regs = regs; + + if (native_is_frame_exists(context, &tmp_regs)) + { // Stack frame (x86) + if (!native_unwind_stack_frame(context, &tmp_regs)) + break; + } + else + { // Stack frame does not exist, try using heuristics + if (!native_unwind_special(context, &tmp_regs)) + break; + } + + VMBreakPoints* vm_breaks = VM_Global_State::loader_env->TI->vm_brpt; + vm_breaks->lock(); +/* +Now the technique for calling C handler from a signal/exception context +guarantees that all needed return addresses are present in stack, so +there is no need in special processing + if (native_is_ip_in_breakpoint_handler(tmp_regs.get_ip())) + { + regs = *pthread->jvmti_thread.jvmti_saved_exception_registers; + flag_breakpoint = true; + } + else*/ + regs = tmp_regs; + + vm_breaks->unlock(); + } + + code_type = vm_identify_eip(regs.get_ip()); + is_java = (code_type == VM_TYPE_JAVA); + + // If we've reached Java without native stub (or breakpoint handler frame) + if (is_java && !is_stub && !flag_breakpoint) + break; // then stop processing + flag_breakpoint = false; +// ^^ Native ^^ +///////////////////////// + } + + if (flag_dummy_frame) + { // Delete previously added dummy frame + M2nFrame* plm2n = m2n_get_last_frame(pthread); + m2n_set_last_frame(pthread, m2n_get_previous_frame(plm2n)); + STD_FREE(plm2n); + } + + si_free(si); + + return frame_count; +} + + +static int walk_native_stack_pure( + WalkContext* context, Registers* pregs, + int max_depth, native_frame_t* frame_array) +{ + // Register context for current frame + Registers regs = *pregs; + if (vm_identify_eip(regs.get_ip()) == VM_TYPE_JAVA) + return 0; + + int frame_count = 0; + + while (1) + { + if (frame_array != NULL && frame_count >= max_depth) + break; + + if (frame_array) + { // If frames requested, store current frame + native_fill_frame_info(®s, &frame_array[frame_count], -1); + } + + ++frame_count; + + if (native_is_frame_exists(context, ®s)) + { // Stack frame (x86) + // Here must be special processing for breakpoint handler frames + // But it requires VM_thread structure attached to thread + // TODO: Investigate possibility + if (!native_unwind_stack_frame(context, ®s)) + break; + } + else + { // Stack frame does not exist, try using heuristics + if (!native_unwind_special(context, ®s)) + break; + } + } + + return frame_count; +} + + +static int walk_native_stack_interpreter( + WalkContext* context, + Registers* pregs, VM_thread* pthread, + int max_depth, native_frame_t* frame_array) +{ + // Register context for current frame + Registers regs = *pregs; + + assert(pthread); + FrameHandle* last_frame = interpreter.interpreter_get_last_frame(pthread); + FrameHandle* frame = last_frame; + + int frame_count = 0; + jint java_depth = 0; + + while (1) + { + if (frame_array != NULL && frame_count >= max_depth) + break; + + if (frame_array) + { // If frames requested, store current frame + native_fill_frame_info(®s, &frame_array[frame_count], -1); + } + + ++frame_count; + + // Store previous value to identify frame range later + void* prev_sp = regs.get_sp(); + Registers tmp_regs = regs; + + if (native_is_frame_exists(context, &tmp_regs)) + { // Stack frame (x86) + if (!native_unwind_stack_frame(context, &tmp_regs)) + break; + } + else + { // Stack frame does not exist, try using heuristics + if (!native_unwind_special(context, &tmp_regs)) + break; + } + + VMBreakPoints* vm_breaks = VM_Global_State::loader_env->TI->vm_brpt; + vm_breaks->lock(); +/* +Now the technique for calling C handler from a signal/exception context +guarantees that all needed return addresses are present in stack, so +there is no need in special processing + if (native_is_ip_in_breakpoint_handler(tmp_regs.get_ip())) + regs = *pthread->jvmti_thread.jvmti_saved_exception_registers; + else*/ + regs = tmp_regs; + + vm_breaks->unlock(); + + bool is_java = interpreter.is_frame_in_native_frame(frame, prev_sp, regs.get_sp()); + + if (is_java) + { + // Set Java frame number + if (frame_array && frame_count > 1) + frame_array[frame_count - 2].java_depth = java_depth++; + + // Go to previous frame + frame = interpreter.interpreter_get_prev_frame(frame); + } + } + + return frame_count; +} diff --git a/vm/vmcore/src/stack/stack_dump.cpp b/vm/vmcore/src/stack/stack_dump.cpp deleted file mode 100644 index 948a988..0000000 --- a/vm/vmcore/src/stack/stack_dump.cpp +++ /dev/null @@ -1,512 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Vladimir Nenashev - * @version $Revision$ - */ - -#include -#include "vm_threads.h" -#include "port_malloc.h" -#include "port_dso.h" -#include "jit_intf_cpp.h" -#include "Class.h" -#include "class_member.h" -#include "exceptions.h" -#include "stack_trace.h" -#include "interpreter_exports.h" -#include "cci.h" -#include "m2n.h" -#include "native_stack.h" -#include "native_modules.h" -#include "natives_support.h" -#include "exception_filter.h" - -#include "stack_dump.h" - - -static native_module_t* g_modules = NULL; - -// Is called to fill modules list (should be called under lock) -static void sd_fill_modules() -{ - if (g_modules) - return; - - int count; - bool res = port_get_all_modules(&g_modules, &count); - assert(res && g_modules && count); -} - -#ifdef SD_UPDATE_MODULES -// Is called to update modules info -void sd_update_modules() -{ - hymutex_t* sd_lock; - bool res = sd_initialize(&sd_lock); - - if (!res) - return; - - hymutex_lock(sd_lock); - - if (g_modules) - port_clear_modules(&g_modules); - - int count; - res = port_get_all_modules(&g_modules, &count); - assert(res && g_modules && count); - - hymutex_unlock(sd_lock); -} -#endif // SD_UPDATE_MODULES - - -static char* sd_construct_java_method_name(Method* m, char* buf) -{ - if (!m || !buf) - { - *buf = 0; - return NULL; - } - - char* ptr = buf; - - const char* err_str = "<--Truncated: too long name"; - size_t err_len = strlen(err_str); - - size_t remain = SD_MNAME_LENGTH - 1; - const char* cname = m->get_class()->get_name()->bytes; - size_t clen = m->get_class()->get_name()->len; - const char* mname = m->get_name()->bytes; - size_t mlen = m->get_name()->len; - const char* descr = m->get_descriptor()->bytes; - size_t dlen = m->get_descriptor()->len; - - if (clen + 1 > remain) - { - size_t len = remain - err_len; - memcpy(ptr, cname, len); - strcpy(ptr + len, err_str); - return buf; - } - - memcpy(ptr, cname, clen); - ptr += clen; - *ptr++ = '.'; - remain -= clen + 1; - - if (mlen > remain) - { - if (remain > err_len) - memcpy(ptr, mname, remain - err_len); - - strcpy(ptr + remain - err_len, err_str); - return buf; - } - - memcpy(ptr, mname, mlen); - ptr += mlen; - remain -= mlen; - - if (dlen > remain) - { - if (remain > err_len) - memcpy(ptr, descr, remain - err_len); - - strcpy(ptr + remain - err_len, err_str); - return buf; - } - - strcpy(ptr, descr); - return buf; -} - -static void sd_get_java_method_info(MethodInfo* info, Method* m, void* ip, - bool is_ip_past, int inl_depth) -{ - *info->method_name = 0; - *info->file_name = 0; - info->line = -1; - - if (!m || !method_get_class(m)) - return; - - if (!sd_construct_java_method_name(m, info->method_name)) - return; - - const char* fname = NULL; - get_file_and_line(m, ip, is_ip_past, inl_depth, &fname, &info->line); - - if (fname) - { - if (strlen(fname) >= sizeof(info->file_name)) - { - memcpy(info->file_name, fname, sizeof(info->file_name)); - info->file_name[sizeof(info->file_name) - 1] = 0; - } - else - strcpy(info->file_name, fname); - } -} - -static void sd_print_line(int count, MethodInfo* m) { - - fprintf(stderr, "%3d: %s (%s:%d)\n", - count, - *m->method_name ? m->method_name : "??", - *m->file_name ? m->file_name : "??", - m->line); -} - - -static void sd_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; - void* cur_ip = frames[frame_num].ip; - - if (frame_num < num_frames && frames[frame_num].java_depth < 0) - { - if (native_is_ip_stub(cur_ip)) // Generated stub - { - char buf[81]; - char* stub_name = - native_get_stub_name(cur_ip, buf, sizeof(buf)); - - fprintf(stderr, "%3d: 0x%"W_PI_FMT": stub '%s'\n", - count++, (POINTER_SIZE_INT)cur_ip, - stub_name ? stub_name : "??"); - ++frame_num; - continue; - } - - // pure native frame - native_module_t* module = port_find_module(g_modules, cur_ip); - sd_get_c_method_info(&m, module, cur_ip); - sd_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 - native_module_t* module = port_find_module(g_modules, cur_ip); - sd_get_c_method_info(&m, module, cur_ip); - sd_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)); - sd_get_java_method_info(&m, method, ip, false, -1); - sd_print_line(count, &m); - } - else // !si_is_native(si) - { - // Print information about Java method from iterator - CodeChunkInfo* cci = si_get_code_chunk_info(si); - 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); - - if (inlined_depth) - { - for (uint32 i = inlined_depth; i > 0; i--) - { - Method* inl_method = cci->get_jit()->get_inlined_method( - cci->get_inline_info(), offset, i); - - sd_get_java_method_info(&m, inl_method, ip, is_ip_past, i); - sd_print_line(count++, &m); - - if (frame_num < num_frames) - ++frame_num; // Go to the next native frame - } - } - - sd_get_java_method_info(&m, method, ip, is_ip_past, -1); - sd_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); -} - -static void sd_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; - - if (frame_num < num_frames && frames[frame_num].java_depth < 0) - { // pure native frame - native_module_t* module = port_find_module(g_modules, frames[frame_num].ip); - sd_get_c_method_info(&m, module, frames[frame_num].ip); - sd_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))) - { - native_module_t* module = port_find_module(g_modules, frames[frame_num].ip); - sd_get_c_method_info(&m, module, frames[frame_num].ip); - sd_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)) - { - sd_get_java_method_info(&m, method, (void*)bc_ptr, false, -1); - sd_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 - } -} - -const char* sd_get_module_type(const char* short_name) -{ - char name[256]; - - if (strlen(short_name) > 255) - return "Too long short name"; - - strcpy(name, short_name); - char* dot = strchr(name, '.'); - - // Strip suffix/extension - if (dot) - *dot = 0; - - // Strip prefix - char* nameptr = name; - - if (!memcmp(short_name, PORT_DSO_PREFIX, strlen(PORT_DSO_PREFIX))) - nameptr += strlen(PORT_DSO_PREFIX); - - char* vm_modules[] = {"java", "em", "encoder", "gc_gen", "gc_gen_uncomp", "gc_cc", - "harmonyvm", "hythr", "interpreter", "jitrino", "vmi"}; - - for (size_t i = 0; i < sizeof(vm_modules)/sizeof(vm_modules[0]); i++) - { - if (!strcmp_case(name, vm_modules[i])) - return "VM native code"; - } - - if (natives_is_library_loaded_slow(short_name)) - return "JNI native library"; - - return "Unknown/system native module"; -} - - -static void sd_print_module_info(Registers* regs) -{ -#ifdef SD_UPDATE_MODULES - sd_fill_modules(); // Fill modules table if needed -#endif - - native_module_t* module = port_find_module(g_modules, (void*)regs->get_ip()); - sd_parse_module_info(module, (void*)regs->get_ip()); -} - -static void sd_print_modules() -{ - fprintf(stderr, "\nLoaded modules:\n\n"); - port_dump_modules(g_modules, stderr); -} - - -static void sd_print_threads_info(VM_thread* cur_thread) -{ - if (!cur_thread) - fprintf(stderr, "\nCurrent thread is not attached to VM, ID: %d\n", sd_get_cur_tid()); - - fprintf(stderr, "\nVM attached threads:\n\n"); - - hythread_iterator_t it = hythread_iterator_create(NULL); - int count = (int)hythread_iterator_size (it); - - for (int i = 0; i < count; i++) - { - hythread_t thread = hythread_iterator_next(&it); - VM_thread* vm_thread = jthread_get_vm_thread(thread); - - if (!vm_thread) - continue; - - jthread java_thread = jthread_get_java_thread(thread); - JNIEnv* jni_env = vm_thread->jni_env; - - if (cur_thread && java_thread) - { - jclass cl = GetObjectClass(jni_env, java_thread); - jmethodID id = jni_env->GetMethodID(cl, "getName","()Ljava/lang/String;"); - jstring name = jni_env->CallObjectMethod(java_thread, id); - char* java_name = (char*)jni_env->GetStringUTFChars(name, NULL); - - fprintf(stderr, "%s[%p] '%s'\n", - (cur_thread && vm_thread == cur_thread) ? "--->" : " ", - thread->os_handle, java_name); - - jni_env->ReleaseStringUTFChars(name, java_name); - } - else - { - fprintf(stderr, "%s[%p]\n", - (cur_thread && vm_thread == cur_thread) ? "--->" : " ", - thread->os_handle); - } - } - - hythread_iterator_release(&it); -} - - -void sd_print_stack(Registers* regs) -{ - hymutex_t* sd_lock; - int disable_count; - bool unwindable; - - VM_thread* thread = get_thread_ptr(); // Can be NULL for pure native thread - - // Enable suspend to allow working with threads - if (thread) - disable_count = hythread_reset_suspend_disable(); - - // Acquire global lock to print threads list and stop other crashed threads - hythread_global_lock(); - - if (!sd_initialize(&sd_lock)) - return; - - hymutex_lock(sd_lock); - if (thread) - unwindable = set_unwindable(false); // To call Java code - - // Print register info - print_reg_state(regs); - - // Print crashed modile info - sd_print_module_info(regs); - - // Print program environment info - sd_print_cwdcmdenv(); - - // Print the whole list of modules - sd_print_modules(); - - native_frame_t* frames = NULL; - - // Print threads info - sd_print_threads_info(thread); - - // 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. - - WalkContext context; - - if (native_init_walk_context(&context, g_modules, regs)) - { - jint num_frames = - walk_native_stack_registers(&context, 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(&context, regs, thread, num_frames, frames); - else - num_frames = 0; // Consider native stack trace empty - - fprintf(stderr, "\nStack trace:\n"); - - if (interpreter_enabled() && thread) - sd_print_stack_interpreter(thread, frames, num_frames); - else // It should be used also for threads without VM_thread structure - sd_print_stack_jit(thread, frames, num_frames); - - fprintf(stderr, "\n"); - fflush(stderr); - } - - if (thread) - set_unwindable(unwindable); - - // Do not unlock to prevent other threads from printing crash stack - //hymutex_unlock(sd_lock); - - hythread_global_unlock(); - if (thread) - hythread_set_suspend_disable(disable_count); -} diff --git a/vm/vmcore/src/util/em64t/base/native_stack_em64t.cpp b/vm/vmcore/src/util/em64t/base/native_stack_em64t.cpp deleted file mode 100644 index c8f139c..0000000 --- a/vm/vmcore/src/util/em64t/base/native_stack_em64t.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Ilya Berezhniuk - * @version $Revision: 1.1.2.1 $ - */ - -#include "method_lookup.h" -#include "dec_base.h" -#include "native_modules.h" -#include "native_stack.h" - - -bool native_is_frame_exists(WalkContext* context, Registers* regs) -{ - // Check for frame layout and stack values - if ((regs->rbp < regs->rsp) || !native_is_in_stack(context, (void*)regs->rbp)) - return false; // Invalid frame - - void** frame_ptr = (void**)regs->rbp; - void* rip = frame_ptr[1]; // Return address - - // Check return address for meaning - return (native_is_in_code(context, rip) || native_is_ip_stub(rip)); -} - -bool native_unwind_stack_frame(WalkContext* context, Registers* regs) -{ - void** frame = (void**)regs->rbp; - - void* rbp = frame[0]; - void* rip = frame[1]; -// void* rsp = (void*)(frame + 2); - void* rsp = &frame[2]; - - - if (native_is_in_stack(context, rsp) && - (native_is_in_code(context, rip) || native_is_ip_stub(rip))) - { - regs->rbp = (uint64)rbp; - regs->rsp = (uint64)rsp; - regs->rip = (uint64)rip; - return true; - } - - return false; -} - -void native_get_regs_from_jit_context(JitFrameContext* jfc, Registers* regs) -{ - regs->rip = *jfc->p_rip; - regs->rbp = *jfc->p_rbp; - regs->rsp = jfc->rsp; -} - -static bool fill_regs_from_sp(WalkContext* context, Registers* regs, void** sp) -{ - regs->rsp = (uint64)(sp + 1); - regs->rip = (uint64)*sp; - regs->rbp = native_is_in_stack(context, sp[-1]) ? (uint64)sp[-1] : regs->rsp; - return true; -} - -static unsigned native_dec_instr(WalkContext* context, void* addr, void** target) -{ - Inst inst; - - if (!native_is_in_code(context, addr)) - return 0; - - unsigned len = DecoderBase::decode(addr, &inst); - - if (len == 0 || - inst.mn != Mnemonic_CALL || - inst.argc != 1) - return 0; - - if (target && inst.operands[0].is_imm()) - *target = (void*)((uint64)addr + (uint64)len + inst.operands[0].imm()); - - return len; -} - -static bool native_check_caller(WalkContext* context, Registers* regs, void** sp) -{ - void* target = NULL; - char* ptr = (char*)*sp; - - if (native_dec_instr(context, ptr - 2, &target) == 2 || // CALL r/m64 w/o SIB w/o disp - native_dec_instr(context, ptr - 3, &target) == 3 || // CALL r/m64 w/ SIB w/o disp - native_dec_instr(context, ptr - 4, &target) == 4 || // CALL r/m64 w/ SIB w/ disp8 - native_dec_instr(context, ptr - 5, &target) == 5 || // CALL rel32 - native_dec_instr(context, ptr - 6, &target) == 6 || // CALL r/m64 w/o SIB w/ disp32 - native_dec_instr(context, ptr - 7, &target) == 7 || // CALL r/m64 w/ SIB w/ disp32 - native_dec_instr(context, ptr - 8, &target) == 8) // CALL r/m64 w/ SIB w/ disp32 + Seg prefix - { - if (!target) - return true; - - native_module_t* cur_module = - port_find_module(context->modules, regs->get_ip()); - native_module_t* found_module = - port_find_module(context->modules, target); - - return (cur_module == found_module); - } - - return false; -} - - -// Max search depth for return address -#define MAX_SPECIAL_DEPTH 0x900 -#define NATIVE_STRICT_UNWINDING 1 - -bool native_unwind_special(WalkContext* context, Registers* regs) -{ - for (void** cur_sp = (void**)regs->rsp; - (char*)cur_sp < ((char*)regs->rsp + MAX_SPECIAL_DEPTH) && native_is_in_stack(context, cur_sp); - ++cur_sp) - { - if (!native_is_in_code(context, *cur_sp)) - continue; - -#if (!NATIVE_STRICT_UNWINDING) - return fill_regs_from_sp(context, regs, cur_sp); -#else - if (native_check_caller(context, regs, cur_sp)) - return fill_regs_from_sp(context, regs, cur_sp); -#endif - } - - return false; -} - -void native_fill_frame_info(Registers* regs, native_frame_t* frame, jint jdepth) -{ - frame->java_depth = jdepth; - - if (!regs) - return; - - frame->ip = (void*)regs->rip; - frame->frame = (void*)regs->rbp; - frame->stack = (void*)regs->rsp; -} diff --git a/vm/vmcore/src/util/em64t/base/signals_arch.cpp b/vm/vmcore/src/util/em64t/base/signals_arch.cpp deleted file mode 100644 index b79c436..0000000 --- a/vm/vmcore/src/util/em64t/base/signals_arch.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "vm_core_types.h" - -void print_reg_state(Registers* regs) -{ - fprintf(stderr, "Registers:\n"); - fprintf(stderr, " RAX: 0x%"W_PI_FMT", RBX: 0x%"W_PI_FMT"\n", - regs->rax, regs->rbx); - fprintf(stderr, " RCX: 0x%"W_PI_FMT", RDX: 0x%"W_PI_FMT"\n", - regs->rcx, regs->rdx); - fprintf(stderr, " RSI: 0x%"W_PI_FMT", RDI: 0x%"W_PI_FMT"\n", - regs->rsi, regs->rdi); - fprintf(stderr, " RSP: 0x%"W_PI_FMT", RBP: 0x%"W_PI_FMT"\n", - regs->rsp, regs->rbp); - fprintf(stderr, " R8 : 0x%"W_PI_FMT", R9 : 0x%"W_PI_FMT"\n", - regs->r8, regs->r9); - fprintf(stderr, " R10: 0x%"W_PI_FMT", R11: 0x%"W_PI_FMT"\n", - regs->r10, regs->r11); - fprintf(stderr, " R12: 0x%"W_PI_FMT", R13: 0x%"W_PI_FMT"\n", - regs->r12, regs->r13); - fprintf(stderr, " R14: 0x%"W_PI_FMT", R15: 0x%"W_PI_FMT"\n", - regs->r14, regs->r15); - fprintf(stderr, " RIP: 0x%"W_PI_FMT"\n", regs->rip); -} diff --git a/vm/vmcore/src/util/ia32/base/native_stack_ia32.cpp b/vm/vmcore/src/util/ia32/base/native_stack_ia32.cpp deleted file mode 100644 index cbfc211..0000000 --- a/vm/vmcore/src/util/ia32/base/native_stack_ia32.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Ilya Berezhniuk - * @version $Revision: 1.1.2.1 $ - */ - -#include "method_lookup.h" -#include "dec_base.h" -#include "native_modules.h" -#include "native_stack.h" - - -bool native_is_frame_exists(WalkContext* context, Registers* regs) -{ - // Check for frame layout and stack values - if ((regs->ebp < regs->esp) || !native_is_in_stack(context, (void*)regs->ebp)) - return false; // Invalid frame - - void** frame_ptr = (void**)regs->ebp; - void* eip = frame_ptr[1]; // Return address - - // Check return address for meaning - return (native_is_in_code(context, eip) || native_is_ip_stub(eip)); -} - -bool native_unwind_stack_frame(WalkContext* context, Registers* regs) -{ - void** frame = (void**)regs->ebp; - - void* ebp = frame[0]; - void* eip = frame[1]; -// void* esp = (void*)(frame + 2); - void* esp = &frame[2]; - - - if (native_is_in_stack(context, esp) && - (native_is_in_code(context, eip) || native_is_ip_stub(eip))) - { - regs->ebp = (uint32)ebp; - regs->esp = (uint32)esp; - regs->eip = (uint32)eip; - return true; - } - - return false; -} - -void native_get_regs_from_jit_context(JitFrameContext* jfc, Registers* regs) -{ - regs->eip = *jfc->p_eip; - regs->ebp = *jfc->p_ebp; - regs->esp = jfc->esp; -} - -static bool fill_regs_from_sp(WalkContext* context, Registers* regs, void** sp) -{ - regs->esp = (uint32)(sp + 1); - regs->eip = (uint32)*sp; - regs->ebp = native_is_in_stack(context, sp[-1]) ? (uint32)sp[-1] : regs->esp; - return true; -} - -static unsigned native_dec_instr(WalkContext* context, void* addr, void** target) -{ - Inst inst; - - if (!native_is_in_code(context, addr)) - return 0; - - uint32 len = DecoderBase::decode(addr, &inst); - - if (len == 0 || - inst.mn != Mnemonic_CALL || - inst.argc != 1) - return 0; - - if (target && inst.operands[0].is_imm()) - *target = (void*)((uint32)addr + len + inst.operands[0].imm()); - - return len; -} - -static bool native_check_caller(WalkContext* context, Registers* regs, void** sp) -{ - void* target = NULL; - char* ptr = (char*)*sp; - - if (native_dec_instr(context, ptr - 2, &target) == 2 || // CALL r/m32 w/o SIB w/o disp - native_dec_instr(context, ptr - 3, &target) == 3 || // CALL r/m32 w/ SIB w/o disp - native_dec_instr(context, ptr - 4, &target) == 4 || // CALL r/m32 w/ SIB w/ disp8 - native_dec_instr(context, ptr - 5, &target) == 5 || // CALL rel32 - native_dec_instr(context, ptr - 6, &target) == 6 || // CALL r/m32 w/o SIB w/ disp32 - native_dec_instr(context, ptr - 7, &target) == 7 || // CALL r/m32 w/ SIB w/ disp32 - native_dec_instr(context, ptr - 8, &target) == 8) // CALL r/m32 w/ SIB w/ disp32 + Seg prefix - { - if (!target) - return true; - - native_module_t* cur_module = - port_find_module(context->modules, regs->get_ip()); - native_module_t* found_module = - port_find_module(context->modules, target); - - return (cur_module == found_module); - } - - return false; -} - - -// Max search depth for return address -#define MAX_SPECIAL_DEPTH 0x400 -#define NATIVE_STRICT_UNWINDING 1 - -bool native_unwind_special(WalkContext* context, Registers* regs) -{ - for (void** cur_sp = (void**)regs->esp; - (char*)cur_sp < ((char*)regs->esp + MAX_SPECIAL_DEPTH) && native_is_in_stack(context, cur_sp); - ++cur_sp) - { - if (!native_is_in_code(context, *cur_sp)) - continue; - -#if (!NATIVE_STRICT_UNWINDING) - return fill_regs_from_sp(context, regs, cur_sp); -#else - if (native_check_caller(context, regs, cur_sp)) - return fill_regs_from_sp(context, regs, cur_sp); -#endif - } - - return false; -} - -void native_fill_frame_info(Registers* regs, native_frame_t* frame, jint jdepth) -{ - frame->java_depth = jdepth; - - if (!regs) - return; - - frame->ip = (void*)regs->eip; - frame->frame = (void*)regs->ebp; - frame->stack = (void*)regs->esp; -} diff --git a/vm/vmcore/src/util/ia32/base/signals_arch.cpp b/vm/vmcore/src/util/ia32/base/signals_arch.cpp deleted file mode 100644 index 0ac5a4c..0000000 --- a/vm/vmcore/src/util/ia32/base/signals_arch.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "vm_core_types.h" - -void print_reg_state(Registers* regs) -{ - fprintf(stderr, "Registers:\n"); - fprintf(stderr, " EAX: 0x%"W_PI_FMT", EBX: 0x%"W_PI_FMT", ECX: 0x%"W_PI_FMT", EDX: 0x%"W_PI_FMT"\n", - regs->eax, regs->ebx, regs->ecx, regs->edx); - fprintf(stderr, " ESI: 0x%"W_PI_FMT", EDI: 0x%"W_PI_FMT", ESP: 0x%"W_PI_FMT", EBP: 0x%"W_PI_FMT"\n", - regs->esi, regs->edi, regs->esp, regs->ebp); - fprintf(stderr, " EIP: 0x%"W_PI_FMT"\n", regs->eip); -} diff --git a/vm/vmcore/src/util/ipf/base/native_stack_ipf.cpp b/vm/vmcore/src/util/ipf/base/native_stack_ipf.cpp deleted file mode 100644 index e91c555..0000000 --- a/vm/vmcore/src/util/ipf/base/native_stack_ipf.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Ilya Berezhniuk - * @version $Revision: 1.1.2.1 $ - */ - -#include "native_stack.h" - - -bool native_is_frame_exists(WalkContext* UNREF context, Registers* UNREF regs) -{ - return false; -} - -bool native_unwind_stack_frame(WalkContext* UNREF context, Registers* UNREF regs) -{ - return false; -} - -void native_get_regs_from_jit_context(JitFrameContext* UNREF jfc, Registers* UNREF regs) -{ -} - -bool native_unwind_special(WalkContext* UNREF context, Registers* UNREF regs) -{ - return false; -} - -void native_fill_frame_info(Registers* UNREF regs, native_frame_t* UNREF frame, jint UNREF jdepth) -{ -} diff --git a/vm/vmcore/src/util/ipf/base/signals_arch.cpp b/vm/vmcore/src/util/ipf/base/signals_arch.cpp deleted file mode 100644 index 149cb94..0000000 --- a/vm/vmcore/src/util/ipf/base/signals_arch.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "vm_core_types.h" - -void print_reg_state(Registers* regs) -{ - fprintf(stderr, "Registers:"); - - for (int gn = 0; gn < 8; gn++) - { - fprintf(stderr, "\n GR %2d-%2d:", gn*4, (gn+1)*4 - 1); - for (int gc = 0; gc < 4; gc++) - fprintf(stderr, " 0x%"W_PI_FMT, regs->gr[gn*4 + gc]); - } - - for (int bn = 0; bn < 2; bn++) - { - fprintf(stderr, "\n BR %2d-%2d:", bn*4, (bn+1)*4 - 1); - for (int bc = 0; bc < 4; bc++) - fprintf(stderr, " 0x%"W_PI_FMT, regs->br[bn*4 + bc]); - } - - fprintf(stderr, "\n"); - fprintf(stderr, " preds: 0x%"W_PI_FMT"\n", regs->preds); - fprintf(stderr, " nats: 0x%"W_PI_FMT"\n", regs->nats); - fprintf(stderr, " pfs: 0x%"W_PI_FMT"\n", regs->pfs); - fprintf(stderr, " bsp: 0x%"W_PI_FMT"\n", (POINTER_SIZE_INT)regs->bsp); - fprintf(stderr, " *bsp: 0x%"W_PI_FMT"\n", regs->bsp ? (*regs->bsp) : 0); - fprintf(stderr, " ip: 0x%"W_PI_FMT"\n", regs->ip); -} diff --git a/vm/vmcore/src/util/linux/crash_handler.cpp b/vm/vmcore/src/util/linux/crash_handler.cpp deleted file mode 100644 index 16b0bf1..0000000 --- a/vm/vmcore/src/util/linux/crash_handler.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Intel, Evgueni Brevnov - * @version $Revision: 1.1.2.1.4.3 $ - */ - -#include -#include -#include -#include - -#include "vm_core_types.h" -#include "environment.h" -#include "port_sysinfo.h" -#include "platform_lowlevel.h" -#include "exception_filter.h" -#include "port_thread.h" - -#include "crash_handler.h" - -static char* g_executable = NULL;// Executable file name -static sem_t g_sem_started; // Prevent forking debugger more than once -static bool g_prepared = false; // Flag is set if gdb crash handler is prepared -static bool g_enabled = false; // vm.crash_handler value is stored here - - -#if defined (__INTEL_COMPILER) -#pragma warning ( push ) -#pragma warning (disable:869) -#endif - - -bool is_gdb_crash_handler_enabled() -{ - return (g_prepared && g_enabled); -} - -bool gdb_crash_handler(Registers* regs) -{ - if (!g_prepared || !g_enabled || - !g_executable || - 0 != sem_trywait(&g_sem_started)) // gdb was already started - return false; - - // Print register info - print_reg_state(regs); - - static const int tid_len = 10; - char tid[tid_len]; - snprintf(tid, tid_len, "%d", gettid()); - - if (fork() == 0) - { - fprintf(stderr, "----------------------------------------\n" - "gdb %s %s\n" - "----------------------------------------\n" - , g_executable, tid); - fflush(stderr); - - execlp("gdb", "gdb", g_executable, tid, NULL); - perror("Can't run gdb"); - } - else - { - // give gdb chance to start before the default handler kills the app - sleep(10); - } -} -#if defined (__INTEL_COMPILER) -#pragma warning ( pop ) -#endif - -static int get_executable_name() -{ - if (port_executable_name(&g_executable) != 0) - return -1; - - return g_executable ? 0 : -1; -} - - -void init_gdb_crash_handler() -{ - if (sem_init(&g_sem_started, 0, 1) != 0 || - get_executable_name() != 0) - { - g_prepared = false; - return; - } - - if (!VM_Global_State::loader_env) - g_enabled = true; - else - g_enabled = get_boolean_property("vm.crash_handler", FALSE, VM_PROPERTIES); - - g_prepared = true; -} diff --git a/vm/vmcore/src/util/linux/include/crash_handler.h b/vm/vmcore/src/util/linux/include/crash_handler.h deleted file mode 100644 index 333b646..0000000 --- a/vm/vmcore/src/util/linux/include/crash_handler.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Intel, Evgueni Brevnov - * @version $Revision: 1.1.2.1.4.3 $ - */ - -#ifndef _CRASH_HANDLER_H -#define _CRASH_HANDLER_H - -#include "vm_core_types.h" - -/** - * \file - * Provides definition needed to install gdb crash handler. - */ - -/** - * Checks if gdb crash handler is enabled and prepared. - * - * @return true if gdb crash handler is enabled and ready for use. - */ -bool is_gdb_crash_handler_enabled(); - -/** - * Initializes the static state needed for gdb crash handler. - * - * @return 0 on success or negative value on failure - */ -void init_gdb_crash_handler(); - -/** - * Invokes gdb. - * - * @return true on success or false on failure - */ -bool gdb_crash_handler(Registers* regs); - -#endif // _CRASH_HANDLER_H diff --git a/vm/vmcore/src/util/linux/native_stack_os.cpp b/vm/vmcore/src/util/linux/native_stack_os.cpp deleted file mode 100644 index 5af1425..0000000 --- a/vm/vmcore/src/util/linux/native_stack_os.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include -#include "native_modules.h" -#include "native_stack.h" - - -bool native_is_in_code(WalkContext* context, void* ip) -{ - if (!ip) - return false; - - for (native_module_t* module = context->modules; module; module = module->next) - { - for (size_t i = 0; i < module->seg_count; i++) - { - char* base = (char*)module->segments[i].base; - - if (ip >= base && - ip < (base + module->segments[i].size)) - return true; - } - } - - return false; -} - -bool native_get_stack_range(WalkContext* context, Registers* regs, native_segment_t* seg) -{ - int err; - pthread_attr_t pthread_attr; - - pthread_t thread = pthread_self(); - void* sp = regs->get_sp(); - - if (pthread_attr_init(&pthread_attr) != 0) - return false; - -#if defined(FREEBSD) - err = pthread_attr_get_np(thread, &pthread_attr); -#else - err = pthread_getattr_np(thread, &pthread_attr); -#endif - - if (err != 0) - return false; - - if (pthread_attr_getstack(&pthread_attr, &seg->base, &seg->size)) - return false; - - pthread_attr_destroy(&pthread_attr); - return true; - -/* for (native_module_t* module = context->modules; module; module = module->next) - { - for (size_t i = 0; i < module->seg_count; i++) - { - char* base = (char*)module->segments[i].base; - - if (sp >= base && - sp < (base + module->segments[i].size)) - { - *seg = module->segments[i]; - return true; - } - } - } - - return false; -*/ -} diff --git a/vm/vmcore/src/util/linux/stack_dump_platf.cpp b/vm/vmcore/src/util/linux/stack_dump_platf.cpp deleted file mode 100644 index 1bfd0c6..0000000 --- a/vm/vmcore/src/util/linux/stack_dump_platf.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "open/hythread_ext.h" -#include "native_stack.h" -#include "port_filepath.h" -#include "port_dso.h" -#include "port_thread.h" -#include "stack_dump.h" - - -static hymutex_t g_lock; -static const char* g_curdir = NULL; -static const char* g_cmdline = NULL; - - -bool sd_initialize(hymutex_t** p_lock) -{ - static int initialized = 0; - - if (!initialized) - { - IDATA err = hymutex_create(&g_lock, APR_THREAD_MUTEX_NESTED); - - if (err != APR_SUCCESS) - return false; - - initialized = true; - } - - if (p_lock) - *p_lock = &g_lock; - - return true; -} - - -static bool sd_is_predefined_name(const char* name) -{ - if (*name != '[') - return false; - - return true; -// return (!strcmp(name, "[heap]") || -// !strcmp(name, "[stack]") || -// !strcmp(name, "[vdso]")); -} - -static inline native_segment_t* sd_find_segment(native_module_t* module, void* ip) -{ - for (size_t i = 0; i < module->seg_count; i++) - { - if (module->segments[i].base <= ip && - (char*)module->segments[i].base + module->segments[i].size > ip) - return &module->segments[i]; - } - - assert(0); - return NULL; -} - -void sd_parse_module_info(native_module_t* module, void* ip) -{ - fprintf(stderr, "\nCrashed module:\n"); - - if (!module) - { // Unknown address - fprintf(stderr, "Unknown address 0x%"W_PI_FMT"\n", - (POINTER_SIZE_INT)ip); - return; - } - - native_segment_t* segment = sd_find_segment(module, ip); - - if (!module->filename) - { - fprintf(stderr, "Unknown memory region 0x%"W_PI_FMT":0x%"W_PI_FMT"%s\n", - (size_t)segment->base, (size_t)segment->base + segment->size, - (segment->type == SEGMENT_TYPE_CODE) ? "" : " without execution rights"); - return; - } - - if (sd_is_predefined_name(module->filename)) - { // Special memory region - fprintf(stderr, "%s memory region 0x%"W_PI_FMT":0x%"W_PI_FMT"%s\n", - module->filename, - (size_t)segment->base, (size_t)segment->base + segment->size, - (segment->type == SEGMENT_TYPE_CODE) ? "" : " without execution rights"); - return; - } - - // Common shared module - const char* short_name = port_filepath_basename(module->filename); - const char* module_type = sd_get_module_type(short_name); - - fprintf(stderr, "%s\n(%s)\n", module->filename, module_type); -} - - -void sd_get_c_method_info(MethodInfo* info, native_module_t* module, void* ip) -{ - *info->method_name = 0; - *info->file_name = 0; - info->line = -1; - - if (!module || !module->filename) - return; - - POINTER_SIZE_INT offset = (POINTER_SIZE_INT)ip; - - if (strstr(module->filename, PORT_DSO_EXT) != NULL) // Shared object - { // IP for addr2line should be an offset within shared library - native_segment_t* seg = sd_find_segment(module, ip); - offset -= (POINTER_SIZE_INT)seg->base; - } - - int po[2]; - pipe(po); - - char ip_str[20]; - sprintf(ip_str, "0x%"PI_FMT"x\n", offset); - - if (!fork()) - { - close(po[0]); - dup2(po[1], 1); - execlp("addr2line", "addr2line", "-f", "-s", "-e", module->filename, "-C", ip_str, NULL); - //fprintf(stderr, "Warning: Cannot run addr2line. No symbolic information will be available\n"); - printf("??\n??:0\n"); // Emulate addr2line output - exit(-1); - } - else - { - close(po[1]); - char buf[sizeof(info->method_name) + sizeof(info->file_name)]; - int status; - wait(&status); - int count = read(po[0], buf, sizeof(buf) - 1); - close(po[0]); - - if (count < 0) - { - fprintf(stderr, "read() failed during addr2line execution\n"); - return; - } - - while (isspace(buf[count-1])) - count--; - - buf[count] = '\0'; - int i = 0; - - for (; i < count; i++) - { - if (buf[i] == '\n') - { // Function name is limited by '\n' - buf[i] = '\0'; - strncpy(info->method_name, buf, sizeof(info->method_name)); - break; - } - } - - if (i == count) - return; - - char* fn = buf + i + 1; - - for (; i < count && buf[i] != ':'; i++); // File name and line number are separated by ':' - - if (i == count) - return; - - buf[i] = '\0'; - strncpy(info->file_name, fn, sizeof(info->file_name)); - - info->line = atoi(buf + i + 1); // Line number - - if (info->line == 0) - info->line = -1; - } -} - -int sd_get_cur_tid() -{ - return gettid(); -} - -void sd_init_crash_handler() -{ - // Get current directory - char buf[PATH_MAX + 1]; - char* cwd = getcwd(buf, sizeof(buf)); - - if (cwd) - { - cwd = (char*)STD_MALLOC(strlen(cwd) + 1); - g_curdir = cwd; - if (cwd) - strcpy(cwd, buf); - } - - // Get command line - sprintf(buf, "/proc/%d/cmdline", getpid()); - int file = open(buf, O_RDONLY); - - if (file > 0) - { - size_t size = 0; - char rdbuf[256]; - ssize_t rd; - do - { - rd = read(file, rdbuf, sizeof(rdbuf)); - size += (rd > 0) ? rd : 0; - } while (rd == sizeof(rdbuf)); - - if (size) - { - char* cmd = (char*)STD_MALLOC(size + 1); - g_cmdline = cmd; - if (cmd) - { - cmd[size + 1] = '\0'; - lseek(file, 0, SEEK_SET); - read(file, cmd, size); - } - } - close(file); - } -} - -void sd_print_cwdcmdenv() -{ - fprintf(stderr, "\nWorking directory:\n%s\n", g_curdir ? g_curdir : "'null'"); - - fprintf(stderr, "\nCommand line:\n"); - for (const char* ptr = g_cmdline; *ptr; ptr += strlen(ptr) + 1) - fprintf(stderr, "%s ", ptr); - fprintf(stderr, "\n"); - - fprintf(stderr, "\nEnvironment variables:\n"); - for (char** env = environ; *env; ++env) - fprintf(stderr, "%s\n", *env); -} diff --git a/vm/vmcore/src/util/native_stack.cpp b/vm/vmcore/src/util/native_stack.cpp deleted file mode 100644 index 25ee12e..0000000 --- a/vm/vmcore/src/util/native_stack.cpp +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Ilya Berezhniuk - * @version $Revision: 1.1.2.1 $ - */ - -#include -#include "lock_manager.h" -#include "method_lookup.h" -#include "m2n.h" -#include "stack_trace.h" -#include "interpreter.h" -#include "interpreter_exports.h" -#include "compile.h" -#include "jvmti_break_intf.h" -#include "environment.h" -#include "native_modules.h" -#include "native_stack.h" - - -////////////////////////////////////////////////////////////////////////////// -/// Helper functions - -static DynamicCode* native_find_stub(void* ip) -{ - for (DynamicCode *dcList = compile_get_dynamic_code_list(); - NULL != dcList; dcList = dcList->next) - { - if (ip >= dcList->address && - ip < (void*)((POINTER_SIZE_INT)dcList->address + dcList->length)) - return dcList; - } - - return NULL; -} - -char* native_get_stub_name(void* ip, char* buf, size_t buflen) -{ - // Synchronizing access to dynamic code list - LMAutoUnlock dcll(VM_Global_State::loader_env->p_dclist_lock); - - if (!buf || buflen == 0) - return NULL; - - DynamicCode* code = native_find_stub(ip); - - if (!code || !code->name) - return NULL; - - strncpy(buf, code->name, buflen); - buf[buflen - 1] = '\0'; - - return buf; -} - -bool native_is_in_stack(WalkContext* context, void* sp) -{ - return (sp >= context->stack.base && - sp < (char*)context->stack.base + context->stack.size); -} - -bool native_is_ip_stub(void* ip) -{ - // Synchronizing access to dynamic code list - LMAutoUnlock dcll(VM_Global_State::loader_env->p_dclist_lock); - - return (native_find_stub(ip) != NULL); -} - -/* -Now the technique for calling C handler from a signal/exception context -guarantees that all needed return addresses are present in stack, so -there is no need in special processing -static bool native_is_ip_in_breakpoint_handler(void* ip) -{ - return (ip >= &process_native_breakpoint_event && - ip < &jvmti_jit_breakpoint_handler); -}*/ -/// Helper functions -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// -// - -bool native_init_walk_context(WalkContext* context, native_module_t* modules, Registers* regs) -{ - if (!context) - return false; - - if (!modules) - { - int mod_count; - native_module_t* mod_list = NULL; - - if (!port_get_all_modules(&mod_list, &mod_count)) - return false; - - context->clean_modules = true; - context->modules = mod_list; - } - else - { - context->clean_modules = false; - context->modules = modules; - } - - if (!native_get_stack_range(context, regs, &context->stack)) - { - if (context->clean_modules) - port_clear_modules(&context->modules); - return false; - } - - return true; -} - -void native_clean_walk_context(WalkContext* context) -{ - if (!context) - return; - - if (context->modules && context->clean_modules) - { - port_clear_modules(&context->modules); - } - - context->modules = NULL; -} - - -static int walk_native_stack_jit( - WalkContext* context, - Registers* pregs, VM_thread* pthread, - int max_depth, native_frame_t* frame_array); -static int walk_native_stack_pure( - WalkContext* context, Registers* pregs, - int max_depth, native_frame_t* frame_array); -static int walk_native_stack_interpreter( - WalkContext* context, - Registers* pregs, VM_thread* pthread, - int max_depth, native_frame_t* frame_array); - -int walk_native_stack_registers(WalkContext* context, Registers* pregs, - VM_thread* pthread, int max_depth, native_frame_t* frame_array) -{ - if (pthread == NULL) // Pure native thread - return walk_native_stack_pure(context, pregs, max_depth, frame_array); - - if (interpreter_enabled()) - return walk_native_stack_interpreter(context, pregs, - pthread, max_depth, frame_array); - - return walk_native_stack_jit(context, pregs, pthread, max_depth, frame_array); - return 0; -} - - -static int walk_native_stack_jit( - WalkContext* context, - Registers* pregs, VM_thread* pthread, - int max_depth, native_frame_t* frame_array) -{ - // Register context for current frame - Registers regs = *pregs; - - int frame_count = 0; - - // Search for method containing corresponding address - VM_Code_Type code_type = vm_identify_eip(regs.get_ip()); - bool flag_dummy_frame = false; - jint java_depth = 0; - StackIterator* si = NULL; - bool is_java = false; - - if (code_type == VM_TYPE_JAVA) - { // We must add dummy M2N frame to start SI iteration - if (!pthread) - return 0; - - is_java = true; - - M2nFrame* lm2n = m2n_get_last_frame(pthread); - - if (!m2n_is_suspended_frame(lm2n) || m2n_get_ip(lm2n) != regs.get_ip()) - { // We should not push frame if it was pushed by breakpoint handler - m2n_push_suspended_frame(pthread, ®s); - flag_dummy_frame = true; - } - } - - si = si_create_from_native(pthread); - - if (is_java || - // Frame was pushed already by breakpoint handler - (si_is_native(si) && si_get_m2n(si) && m2n_is_suspended_frame(si_get_m2n(si)))) - { - si_goto_previous(si); - } - - jint inline_index = -1; - jint inline_count; - CodeChunkInfo* cci = NULL; - bool is_stub = false; - int special_count = 0; - bool flag_breakpoint = false; - - while (1) - { - if (frame_array != NULL && frame_count >= max_depth) - break; - - if (frame_array) - { // If frames requested, store current frame - native_fill_frame_info(®s, &frame_array[frame_count], - is_java ? java_depth : -1); - } - - ++frame_count; - -///////////////////////// -// vv Java vv - if (is_java) //code_type == VM_TYPE_JAVA - { // Go to previous frame using StackIterator - cci = si_get_code_chunk_info(si); - if (!cci) // Java method should contain cci - break; - - // if (inline_index < 0) we have new si - // (inline_index < inline_count) we must process inline - // (inline_index == inline_count) we must process si itself - if (inline_index < 0) - { - inline_count = si_get_inline_depth(si); - inline_index = 0; - } - - ++java_depth; - - if (inline_index < inline_count) - { // Process inlined method - // We don't need to update context, - // because context is equal for - // all inlined methods - ++inline_index; - } - else - { - inline_index = -1; - // Go to previous stack frame from StackIterator - si_goto_previous(si); - native_get_regs_from_jit_context(si_get_jit_context(si), ®s); - } - - code_type = vm_identify_eip(regs.get_ip()); - is_java = (code_type == VM_TYPE_JAVA); - continue; - } -// ^^ Java ^^ -///////////////////////// -// vv Native vv - is_stub = native_is_ip_stub(regs.get_ip()); - - if (is_stub) - { // Native stub, previous frame is Java frame - if (!si_is_native(si)) - break; - - if (si_get_method(si)) // Frame represents JNI frame - { - // Mark first frame (JNI stub) as Java frame - if (frame_array && frame_count == 1) - frame_array[frame_count - 1].java_depth = java_depth; - - if (frame_array && frame_count > 1) - frame_array[frame_count - 2].java_depth = java_depth; - - ++java_depth; - } - - // Ge to previous stack frame from StackIterator - si_goto_previous(si); - // Let's get context from si - native_get_regs_from_jit_context(si_get_jit_context(si), ®s); - } - else - { - Registers tmp_regs = regs; - - if (native_is_frame_exists(context, &tmp_regs)) - { // Stack frame (x86) - if (!native_unwind_stack_frame(context, &tmp_regs)) - break; - } - else - { // Stack frame does not exist, try using heuristics - if (!native_unwind_special(context, &tmp_regs)) - break; - } - - VMBreakPoints* vm_breaks = VM_Global_State::loader_env->TI->vm_brpt; - vm_breaks->lock(); -/* -Now the technique for calling C handler from a signal/exception context -guarantees that all needed return addresses are present in stack, so -there is no need in special processing - if (native_is_ip_in_breakpoint_handler(tmp_regs.get_ip())) - { - regs = *pthread->jvmti_thread.jvmti_saved_exception_registers; - flag_breakpoint = true; - } - else*/ - regs = tmp_regs; - - vm_breaks->unlock(); - } - - code_type = vm_identify_eip(regs.get_ip()); - is_java = (code_type == VM_TYPE_JAVA); - - // If we've reached Java without native stub (or breakpoint handler frame) - if (is_java && !is_stub && !flag_breakpoint) - break; // then stop processing - flag_breakpoint = false; -// ^^ Native ^^ -///////////////////////// - } - - if (flag_dummy_frame) - { // Delete previously added dummy frame - M2nFrame* plm2n = m2n_get_last_frame(pthread); - m2n_set_last_frame(pthread, m2n_get_previous_frame(plm2n)); - STD_FREE(plm2n); - } - - si_free(si); - - return frame_count; -} - - -static int walk_native_stack_pure( - WalkContext* context, Registers* pregs, - int max_depth, native_frame_t* frame_array) -{ - // Register context for current frame - Registers regs = *pregs; - if (vm_identify_eip(regs.get_ip()) == VM_TYPE_JAVA) - return 0; - - int frame_count = 0; - - while (1) - { - if (frame_array != NULL && frame_count >= max_depth) - break; - - if (frame_array) - { // If frames requested, store current frame - native_fill_frame_info(®s, &frame_array[frame_count], -1); - } - - ++frame_count; - - if (native_is_frame_exists(context, ®s)) - { // Stack frame (x86) - // Here must be special processing for breakpoint handler frames - // But it requires VM_thread structure attached to thread - // TODO: Investigate possibility - if (!native_unwind_stack_frame(context, ®s)) - break; - } - else - { // Stack frame does not exist, try using heuristics - if (!native_unwind_special(context, ®s)) - break; - } - } - - return frame_count; -} - - -static int walk_native_stack_interpreter( - WalkContext* context, - Registers* pregs, VM_thread* pthread, - int max_depth, native_frame_t* frame_array) -{ - // Register context for current frame - Registers regs = *pregs; - - assert(pthread); - FrameHandle* last_frame = interpreter.interpreter_get_last_frame(pthread); - FrameHandle* frame = last_frame; - - int frame_count = 0; - jint java_depth = 0; - - while (1) - { - if (frame_array != NULL && frame_count >= max_depth) - break; - - if (frame_array) - { // If frames requested, store current frame - native_fill_frame_info(®s, &frame_array[frame_count], -1); - } - - ++frame_count; - - // Store previous value to identify frame range later - void* prev_sp = regs.get_sp(); - Registers tmp_regs = regs; - - if (native_is_frame_exists(context, &tmp_regs)) - { // Stack frame (x86) - if (!native_unwind_stack_frame(context, &tmp_regs)) - break; - } - else - { // Stack frame does not exist, try using heuristics - if (!native_unwind_special(context, &tmp_regs)) - break; - } - - VMBreakPoints* vm_breaks = VM_Global_State::loader_env->TI->vm_brpt; - vm_breaks->lock(); -/* -Now the technique for calling C handler from a signal/exception context -guarantees that all needed return addresses are present in stack, so -there is no need in special processing - if (native_is_ip_in_breakpoint_handler(tmp_regs.get_ip())) - regs = *pthread->jvmti_thread.jvmti_saved_exception_registers; - else*/ - regs = tmp_regs; - - vm_breaks->unlock(); - - bool is_java = interpreter.is_frame_in_native_frame(frame, prev_sp, regs.get_sp()); - - if (is_java) - { - // Set Java frame number - if (frame_array && frame_count > 1) - frame_array[frame_count - 2].java_depth = java_depth++; - - // Go to previous frame - frame = interpreter.interpreter_get_prev_frame(frame); - } - } - - return frame_count; -} diff --git a/vm/vmcore/src/util/win/em64t/exception_handlers.asm b/vm/vmcore/src/util/win/em64t/exception_handlers.asm deleted file mode 100644 index b54aa4f..0000000 --- a/vm/vmcore/src/util/win/em64t/exception_handlers.asm +++ /dev/null @@ -1,27 +0,0 @@ -PUBLIC vectored_exception_handler -EXTRN vectored_exception_handler_internal:PROC - -_TEXT SEGMENT - -vectored_exception_handler PROC - -; LONG NTAPI vectored_exception_handler(LPEXCEPTION_POINTERS nt_exception) -; Args: -; rcx - nt_exception -; rdx - none -; r8 - none -; r9 - none - - pushfq - cld - sub rsp, 32 ; allocate stack for 4 registers - call vectored_exception_handler_internal - add rsp, 32 - popfq - ret - -vectored_exception_handler ENDP - -_TEXT ENDS - -END diff --git a/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp b/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp deleted file mode 100644 index feef001..0000000 --- a/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "platform_lowlevel.h" -#include "exceptions_jit.h" -#include "exception_filter.h" - - -LONG __declspec(naked) NTAPI vectored_exception_handler(LPEXCEPTION_POINTERS nt_exception) -{ - __asm { - push ebp - mov ebp,esp - pushfd - cld - mov eax, [ebp + 8] - push eax - call vectored_exception_handler_internal - popfd - pop ebp - ret 4 - } -} diff --git a/vm/vmcore/src/util/win/native_stack_os.cpp b/vm/vmcore/src/util/win/native_stack_os.cpp deleted file mode 100644 index 3c32489..0000000 --- a/vm/vmcore/src/util/win/native_stack_os.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include "native_modules.h" -#include "native_stack.h" - - -bool native_is_in_code(WalkContext* context, void* ip) -{ - if (!ip) - return false; - - MEMORY_BASIC_INFORMATION mem_info; - - if (VirtualQuery(ip, &mem_info, sizeof(mem_info)) == 0) - return false; - - if (mem_info.State != MEM_COMMIT) - return false; - - return ((mem_info.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | - PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) != 0); -} - -bool native_get_stack_range(WalkContext* context, Registers* regs, native_segment_t* seg) -{ - MEMORY_BASIC_INFORMATION mem_info; - - if (VirtualQuery(regs->get_sp(), &mem_info, sizeof(mem_info)) == 0) - return false; - - if (mem_info.State != MEM_COMMIT) - return false; - - seg->base = mem_info.BaseAddress; - seg->size = mem_info.RegionSize; - return true; -} diff --git a/vm/vmcore/src/util/win/stack_dump_platf.cpp b/vm/vmcore/src/util/win/stack_dump_platf.cpp deleted file mode 100644 index 4005c1d..0000000 --- a/vm/vmcore/src/util/win/stack_dump_platf.cpp +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "open/hythread_ext.h" -#include "native_stack.h" -#include "stack_dump.h" -#include "port_filepath.h" - -#ifndef NO_DBGHELP -#include -#pragma comment(linker, "/defaultlib:dbghelp.lib") -#endif - - -static hymutex_t g_lock; -static const char* g_curdir = NULL; -static const char* g_cmdline = NULL; -static const char* g_environ = NULL; - -#ifndef NO_DBGHELP -typedef BOOL (WINAPI *SymFromAddr_type) - (IN HANDLE hProcess, - IN DWORD64 Address, - OUT PDWORD64 Displacement, - IN OUT PSYMBOL_INFO Symbol ); -typedef BOOL (WINAPI *SymGetLineFromAddr64_type) - (IN HANDLE hProcess, - IN DWORD64 qwAddr, - OUT PDWORD pdwDisplacement, - OUT PIMAGEHLP_LINE64 Line64); - -typedef BOOL (WINAPI *SymGetLineFromAddr_type) - (IN HANDLE hProcess, - IN DWORD dwAddr, - OUT PDWORD pdwDisplacement, - OUT PIMAGEHLP_LINE Line ); - -static SymFromAddr_type g_SymFromAddr = NULL; -static SymGetLineFromAddr64_type g_SymGetLineFromAddr64 = NULL; -static SymGetLineFromAddr_type g_SymGetLineFromAddr = NULL; -#endif // #ifndef NO_DBGHELP - - -bool sd_initialize(hymutex_t** p_lock) -{ - static int initialized = 0; - - if (!initialized) - { - IDATA err = hymutex_create(&g_lock, APR_THREAD_MUTEX_NESTED); - - if (err != APR_SUCCESS) - return false; - -#ifndef NO_DBGHELP -// Preventive initialization does not work -// if (!SymInitialize(GetCurrentProcess(), NULL, TRUE)) -// return false; - - HMODULE hdbghelp = ::LoadLibrary("dbghelp"); - - if (hdbghelp) - { - SymSetOptions(SYMOPT_LOAD_LINES); - g_SymFromAddr = (SymFromAddr_type)::GetProcAddress(hdbghelp, "SymFromAddr"); - g_SymGetLineFromAddr64 = (SymGetLineFromAddr64_type)::GetProcAddress(hdbghelp, "SymGetLineFromAddr64"); - g_SymGetLineFromAddr = (SymGetLineFromAddr_type)::GetProcAddress(hdbghelp, "SymGetLineFromAddr"); - } -#endif // #ifndef NO_DBGHELP - - initialized = true; - } - - if (p_lock) - *p_lock = &g_lock; - - return true; -} - - -static const char* sd_get_region_access_info(MEMORY_BASIC_INFORMATION* pinfo) -{ - if ((pinfo->State & MEM_COMMIT) == 0) - return "not committed"; - - if ((pinfo->Protect & PAGE_GUARD) != 0) - return "guard page occured"; - - if ((pinfo->Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | - PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY | - PAGE_READWRITE | PAGE_READONLY)) != 0) - return ""; - - if ((pinfo->Protect & (PAGE_READWRITE | PAGE_READONLY)) != 0) - return "without execution rights"; - - return "without read rights";; -} - -void sd_parse_module_info(native_module_t* module, void* ip) -{ - fprintf(stderr, "\nCrashed module:\n"); - - if (module) - { - native_segment_t* segment = module->segments; - - assert(module->filename); - - if (!module->filename) - { // We should not reach this code - fprintf(stderr, "Unknown memory region 0x%"W_PI_FMT":0x%"W_PI_FMT"%s\n", - (size_t)segment->base, (size_t)segment->base + segment->size, - (segment->type == SEGMENT_TYPE_CODE) ? "" : " without execution rights"); - return; - } - - // Common shared module - const char* short_name = port_filepath_basename(module->filename); - const char* module_type = sd_get_module_type(short_name); - fprintf(stderr, "%s\n(%s)\n", module->filename, module_type); - return; - } - - // module == NULL - size_t start_addr, end_addr, region_size; - MEMORY_BASIC_INFORMATION mem_info; - - VirtualQuery(ip, &mem_info, sizeof(mem_info)); - start_addr = (size_t)mem_info.BaseAddress; - region_size = (size_t)mem_info.RegionSize; - end_addr = start_addr + region_size; - - fprintf(stderr, "Memory region 0x%"W_PI_FMT":0x%"W_PI_FMT" %s\n", - start_addr, end_addr, sd_get_region_access_info(&mem_info)); -} - - -void sd_get_c_method_info(MethodInfo* info, native_module_t* UNREF module, void* ip) -{ - *info->method_name = 0; - *info->file_name = 0; - info->line = -1; - -#ifndef NO_DBGHELP - - if (!SymInitialize(GetCurrentProcess(), NULL, TRUE)) - return; - - BYTE smBuf[sizeof(SYMBOL_INFO) + SD_MNAME_LENGTH - 1]; - PSYMBOL_INFO pSymb = (PSYMBOL_INFO)smBuf; - pSymb->SizeOfStruct = sizeof(SYMBOL_INFO); - pSymb->MaxNameLen = SD_MNAME_LENGTH; - DWORD64 funcDispl; - - if (g_SymFromAddr && - g_SymFromAddr(GetCurrentProcess(), (DWORD64)(POINTER_SIZE_INT)ip, &funcDispl, pSymb)) - { - strcpy(info->method_name, pSymb->Name); - } - - if (g_SymGetLineFromAddr64) - { - DWORD offset; - IMAGEHLP_LINE64 lineinfo; - lineinfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - - if (g_SymGetLineFromAddr64(GetCurrentProcess(), - (DWORD64)(POINTER_SIZE_INT)ip, - &offset, &lineinfo)) - { - info->line = lineinfo.LineNumber; - strncpy(info->file_name, lineinfo.FileName, sizeof(info->file_name)); - return; - } - } - - if (g_SymGetLineFromAddr) - { - DWORD offset; - IMAGEHLP_LINE lineinfo; - lineinfo.SizeOfStruct = sizeof(IMAGEHLP_LINE); - - if (g_SymGetLineFromAddr(GetCurrentProcess(), - (DWORD)(POINTER_SIZE_INT)ip, - &offset, &lineinfo)) - { - info->line = lineinfo.LineNumber; - strncpy(info->file_name, lineinfo.FileName, sizeof(info->file_name)); - } - } - -#endif // #ifndef NO_DBGHELP -} - -int sd_get_cur_tid() -{ - return GetCurrentThreadId(); -} - -void sd_init_crash_handler() -{ - // Get current directory - DWORD required = GetCurrentDirectory(0, NULL); - char* ptr = (char*)STD_MALLOC(required); - - if (ptr) - { - GetCurrentDirectory(required, ptr); - g_curdir = ptr; - } - - // Get command line - LPTSTR cmdline = GetCommandLine(); - ptr = (char*)STD_MALLOC(strlen(cmdline) + 1); - strcpy(ptr, cmdline); - g_cmdline = ptr; - - // Get environment - LPVOID env_block = GetEnvironmentStrings(); - - if (!env_block) - return; - - size_t total_len = 1; - ptr = (char*)env_block; - - while (*ptr) - { - total_len += strlen(ptr) + 1; - ptr += strlen(ptr) + 1; - } - - ptr = (char*)STD_MALLOC(total_len); - - if (ptr) - { - memcpy(ptr, env_block, total_len); - g_environ = ptr; - } - - FreeEnvironmentStrings((char*)env_block); -} - -void sd_print_cwdcmdenv() -{ - fprintf(stderr, "\nWorking directory:\n%s\n", g_curdir ? g_curdir : "'null'"); - fprintf(stderr, "\nCommand line:\n%s\n", g_cmdline); - - fprintf(stderr, "\nEnvironment variables:\n"); - - const char* penv = (char*)g_environ; - - while (*penv) - { - fprintf(stderr, "%s\n", penv); - penv += strlen(penv) + 1; - } -} -- 1.5.0.3