Index: vm/port/src/encoder/ia32_em64t/dec_base.cpp =================================================================== --- vm/port/src/encoder/ia32_em64t/dec_base.cpp (revision 619840) +++ vm/port/src/encoder/ia32_em64t/dec_base.cpp (working copy) @@ -74,7 +74,7 @@ if (is_prefix(bytes)) { // More than 4 prefixes together ? - assert(false); +// assert(false); return 0; } @@ -96,7 +96,7 @@ } } if (!found) { - assert(false); +// assert(false); return 0; } tmp.size = (unsigned)(bytes-(const unsigned char*)addr); @@ -167,7 +167,7 @@ } return true; case OpcodeByteKind_cw: - assert(false); // not an error, but not expected in current env +// assert(false); // not an error, but not expected in current env break; case OpcodeByteKind_cd: { @@ -231,11 +231,11 @@ return true; } case OpcodeByteKind_ZeroOpcodeByte: // cant be here - assert(false); +// assert(false); break; default: // unknown kind ? how comes ? - assert(false); +// assert(false); break; } return false; Index: vm/port/src/encoder/ia32_em64t/enc_tabl.cpp =================================================================== --- vm/port/src/encoder/ia32_em64t/enc_tabl.cpp (revision 619840) +++ vm/port/src/encoder/ia32_em64t/enc_tabl.cpp (working copy) @@ -470,7 +470,7 @@ BEGIN_OPCODES() {OpcodeInfo::all, {0xE8, cd}, {rel32}, U }, {OpcodeInfo::ia32, {0xFF, _2}, {r_m32}, U }, - {OpcodeInfo::em64t, {REX_W, 0xFF, _2}, {r_m64}, U }, + {OpcodeInfo::em64t, {0xFF, _2}, {r_m64}, U }, END_OPCODES() END_MNEMONIC() Index: vm/port/src/lil/ia32/pim/stack_iterator_ia32.cpp =================================================================== --- vm/port/src/lil/ia32/pim/stack_iterator_ia32.cpp (revision 619840) +++ vm/port/src/lil/ia32/pim/stack_iterator_ia32.cpp (working copy) @@ -115,7 +115,6 @@ si->c.p_esi = &m2nfl->esi; si->c.p_ebx = &m2nfl->ebx; si->c.p_ebp = &m2nfl->ebp; - si->c.p_eip = &m2nfl->eip; } } Index: vm/vmcore/include/ncai_internal.h =================================================================== --- vm/vmcore/include/ncai_internal.h (revision 619840) +++ vm/vmcore/include/ncai_internal.h (working copy) @@ -28,9 +28,6 @@ extern NcaiRegisterTableItem g_ncai_reg_table[]; -int walk_native_stack(hythread_t thread, - VM_thread* pthread, int max_depth, ncaiFrameInfo* frame_info); - void clean_all_modules(ncaiModule* pmodules); void ncai_library_load_callback(const char* name); void ncai_library_unload_callback(const char* name); Index: vm/vmcore/include/native_stack.h =================================================================== --- vm/vmcore/include/native_stack.h (revision 619840) +++ vm/vmcore/include/native_stack.h (working copy) @@ -38,26 +38,33 @@ void* stack; } native_frame_t; +typedef struct WalkContext { + native_module_t* modules; + bool clean_modules; + native_segment_t stack; +} WalkContext; + // If frame_array is NULL, only returns real frame count -int walk_native_stack_registers(Registers* pregs, +int walk_native_stack_registers(WalkContext* context, Registers* pregs, VM_thread* pthread, int max_depth, native_frame_t* frame_array); +bool native_init_walk_context(WalkContext* context, native_module_t* modules, Registers* regs); +void native_clean_walk_context(WalkContext* context); + ////////////////////////////////////////////////////////////////////////////// // Interchange between platform-dependent and general functions -void native_get_frame_info(Registers* regs, void** ip, void** bp, void** sp); -bool native_unwind_bp_based_frame(void* frame, void** ip, void** bp, void** sp); -void native_get_ip_bp_from_si_jit_context(StackIterator* si, void** ip, void** bp); -void native_get_sp_from_si_jit_context(StackIterator* si, void** sp); -bool native_is_out_of_stack(void* value); -bool native_is_frame_valid(native_module_t* modules, void* bp, void* sp); -int native_test_unwind_special(native_module_t* modules, void* sp); -bool native_unwind_special(native_module_t* modules, - void* stack, void** ip, void** sp, void** bp, bool is_last); -void native_unwind_interrupted_frame(jvmti_thread_t thread, void** p_ip, void** p_bp, void** p_sp); -bool native_is_ip_in_modules(native_module_t* modules, void* ip); + +bool native_unwind_stack_frame(WalkContext* context, Registers* regs); +void native_get_regs_from_jit_context(JitFrameContext* jfc, Registers* regs); +bool native_get_stack_range(WalkContext* context, Registers* regs, native_segment_t* seg); +bool native_is_frame_exists(WalkContext* context, Registers* regs); +bool native_unwind_special(WalkContext* context, Registers* regs); +bool native_is_in_code(WalkContext* context, void* ip); +bool native_is_in_stack(WalkContext* context, void* sp); bool native_is_ip_stub(void* ip); char* native_get_stub_name(void* ip, char* buf, size_t buflen); +void native_fill_frame_info(Registers* regs, native_frame_t* frame, jint jdepth); #ifdef __cplusplus Index: vm/vmcore/include/vm_core_types.h =================================================================== --- vm/vmcore/include/vm_core_types.h (revision 619840) +++ vm/vmcore/include/vm_core_types.h (working copy) @@ -69,9 +69,11 @@ uint64 *bsp; uint64 ip; - void reset_ip() { ip = 0; } + void reset_ip() { ip = 0; } void* get_ip() { return (void*)ip; } - void set_ip(void* src_ip) { ip = (uint64)src_ip; } + void set_ip(void* src_ip) { ip = (uint64)src_ip; } + void* get_sp() { return (void*)bsp; } + void set_sp(void* src_sp) { } }; //Registers #else // !_IPF_ @@ -101,9 +103,11 @@ uint32 eflags; - void reset_ip() { rip = 0; } + void reset_ip() { rip = 0; } void* get_ip() { return (void*)rip; } - void set_ip(void* src_ip) { rip = (uint64)src_ip; } + void set_ip(void* src_ip) { rip = (uint64)src_ip; } + void* get_sp() { return (void*)rsp; } + void set_sp(void* src_sp) { rsp = (uint64)src_sp; } }; //Registers #else // ! _EM64T_ @@ -120,9 +124,11 @@ uint32 eip; uint32 eflags; - void reset_ip() { eip = 0; } + void reset_ip() { eip = 0; } void* get_ip() { return (void*)eip; } - void set_ip(void* src_ip) { eip = (uint32)src_ip; } + void set_ip(void* src_ip) { eip = (uint32)src_ip; } + void* get_sp() { return (void*)esp; } + void set_sp(void* src_sp) { esp = (uint32)src_sp; } }; //Registers #endif // _EM64T_ Index: vm/vmcore/src/stack/stack_dump.cpp =================================================================== --- vm/vmcore/src/stack/stack_dump.cpp (revision 619840) +++ vm/vmcore/src/stack/stack_dump.cpp (working copy) @@ -474,26 +474,31 @@ // walk_native_stack_registers cannot unwind frames in release build), // we will use JIT/interpreter stack iterator to complete stack trace. - jint num_frames = - walk_native_stack_registers(regs, thread, -1, NULL); + 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 = (native_frame_t*)STD_ALLOCA(sizeof(native_frame_t)*num_frames); - if (num_frames && frames) - walk_native_stack_registers(regs, thread, num_frames, frames); - else - num_frames = 0; // Consider native stack trace empty + 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"); + 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); + 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); + fprintf(stderr, "\n"); + fflush(stderr); + } if (thread) set_unwindable(unwindable); Index: vm/vmcore/src/ncai/ncai_stack.cpp =================================================================== --- vm/vmcore/src/ncai/ncai_stack.cpp (revision 619840) +++ vm/vmcore/src/ncai/ncai_stack.cpp (working copy) @@ -153,8 +153,14 @@ vm_thread = jthread_get_vm_thread(thread); } - *pcount = walk_native_stack_registers(®s, + WalkContext context; + if (!native_init_walk_context(&context, NULL, ®s)) + return NCAI_ERROR_INTERNAL; + + *pcount = walk_native_stack_registers(&context, ®s, vm_thread, max_depth, frame_array); + native_clean_walk_context(&context); + return NCAI_ERROR_NONE; } Index: vm/vmcore/src/util/em64t/base/native_stack_em64t.cpp =================================================================== --- vm/vmcore/src/util/em64t/base/native_stack_em64t.cpp (revision 619840) +++ vm/vmcore/src/util/em64t/base/native_stack_em64t.cpp (working copy) @@ -20,175 +20,141 @@ */ #include "method_lookup.h" +#include "dec_base.h" +#include "native_modules.h" #include "native_stack.h" -void native_get_frame_info(Registers* regs, void** ip, void** bp, void** sp) + +bool native_is_frame_exists(WalkContext* context, Registers* regs) { - *ip = (void*)regs->rip; - *bp = (void*)regs->rbp; - *sp = (void*)regs->rsp; + // 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_bp_based_frame(void* frame, void** ip, void** bp, void** sp) +bool native_unwind_stack_frame(WalkContext* context, Registers* regs) { - void** frame_ptr = (void**)frame; + void** frame = (void**)regs->rbp; - *ip = frame_ptr[1]; - *bp = frame_ptr[0]; + void* rbp = frame[0]; + void* rip = frame[1]; +// void* rsp = (void*)(frame + 2); + void* rsp = &frame[2]; - *sp = (void*)((POINTER_SIZE_INT)frame + 2*sizeof(void*)); - return (*bp != NULL && *ip != NULL); -} + 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; + } -void native_get_ip_bp_from_si_jit_context(StackIterator* si, void** ip, void** bp) -{ - JitFrameContext* jfc = si_get_jit_context(si); - *ip = (void*)*jfc->p_rip; - *bp = (void*)*jfc->p_rbp; + return false; } -void native_get_sp_from_si_jit_context(StackIterator* si, void** sp) +void native_get_regs_from_jit_context(JitFrameContext* jfc, Registers* regs) { - *sp = (void*)si_get_jit_context(si)->rsp; + regs->rip = *jfc->p_rip; + regs->rbp = *jfc->p_rbp; + regs->rsp = jfc->rsp; } -bool native_is_out_of_stack(void* value) +static bool fill_regs_from_sp(WalkContext* context, Registers* regs, void** sp) { - // FIXME: Invalid criterion - return (value < (void*)0x10000) || (value > (void*)0x800000000000); + 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; } -bool native_is_frame_valid(native_module_t* modules, void* bp, void* sp) +static unsigned native_dec_instr(WalkContext* context, void* addr, void** target) { - // Check for frame layout and stack values - if ((bp < sp) || native_is_out_of_stack(bp)) - return false; // Invalid frame + Inst inst; - void** dw_ptr = (void**)bp; - void* ret_ip = *(dw_ptr + 1); // Return address for frame + if (!native_is_in_code(context, addr)) + return 0; - // Check return address for meaning - if (!native_is_ip_in_modules(modules, ret_ip) && !native_is_ip_stub(ret_ip)) - return false; + unsigned len = DecoderBase::decode(addr, &inst); - return true; -} + if (len == 0 || + inst.mn != Mnemonic_CALL || + inst.argc != 1) + return 0; -// Searches for correct return address in the stack -// Returns stack address pointing to return address -static void** native_search_special_frame(native_module_t* modules, void* sp) -{ -// Max search depth for return address -#define MAX_SPECIAL_DEPTH 0x100 + if (target && inst.operands[0].is_imm()) + *target = (void*)((uint64)addr + (uint64)len + inst.operands[0].imm()); - POINTER_SIZE_INT sp_begin = (POINTER_SIZE_INT)sp; - for (POINTER_SIZE_INT sp_int = sp_begin; - sp_int < sp_begin + MAX_SPECIAL_DEPTH; - sp_int += 8) // 8 is granularity of stack - { - void** sp_pointer = (void**)sp_int; - - if (native_is_ip_in_modules(modules, *sp_pointer)) - return sp_pointer; - } - - return NULL; + return len; } -// Tests if stack contains non-BP-based frames on top -int native_test_unwind_special(native_module_t* modules, void* sp) +static bool native_check_caller(WalkContext* context, Registers* regs, void** sp) { -#define MAX_SPECIAL_COUNT 16 - -#if (!defined PLATFORM_POSIX) - return -1; // Because we cannot identify executable code on Windows -#endif - - if (modules == NULL) - return false; - - int count = 0; - void** sp_pointer = (void**)sp; - - do + 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 (native_is_ip_stub(sp_pointer[-1])) - break; // We've found JNI stub + if (!target) + return true; - // We've reached Java without native stub - if (vm_identify_eip(sp_pointer[-1]) == VM_TYPE_JAVA) - break; + native_module_t* cur_module = + find_native_module(context->modules, regs->get_ip()); + native_module_t* found_module = + find_native_module(context->modules, target); - void** next_sp = native_search_special_frame(modules, sp_pointer); + return (cur_module == found_module); + } - if (next_sp == NULL) - break; // We cannot unwind anymore + return false; +} - if (count > 0 && // Check BP-frame for upper frames - sp_pointer[-2] >= sp_pointer && // Correct frame layout - sp_pointer[-2] == next_sp - 1 && // is RBP saved correctly - next_sp[-1] >= next_sp + 1) // Correct next frame layout - { - break; - } - sp_pointer = next_sp + 1; +// Max search depth for return address +#define MAX_SPECIAL_DEPTH 0x900 +#define NATIVE_STRICT_UNWINDING 1 - } while (++count <= MAX_SPECIAL_COUNT); - - return count; -} - -bool native_unwind_special(native_module_t* modules, - void* stack, void** ip, void** sp, void** bp, bool is_last) +bool native_unwind_special(WalkContext* context, Registers* regs) { - if (modules == NULL) + 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) { - *ip = NULL; - return false; - } + if (!native_is_in_code(context, *cur_sp)) + continue; - void** found = NULL; - - POINTER_SIZE_INT sp_begin = (POINTER_SIZE_INT)stack; - for (POINTER_SIZE_INT sp_int = sp_begin; - sp_int < sp_begin + MAX_SPECIAL_DEPTH; - sp_int += 8) // 8 is granularity of stack - { - void** sp_pointer = (void**)sp_int; - - if (native_is_ip_in_modules(modules, *sp_pointer)) - { - found = sp_pointer; - break; - } +#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 } - if (!found) - { - *ip = NULL; - return false; - } - - *ip = *found; - *sp = found + 1; - - if (is_last && !native_is_ip_stub(*ip)) - *bp = found[-1]; - else - *bp = *sp; - - return true; + return false; } -void native_unwind_interrupted_frame(jvmti_thread_t thread, void** p_ip, void** p_bp, void** p_sp) +void native_fill_frame_info(Registers* regs, native_frame_t* frame, jint jdepth) { - if (!thread) { + frame->java_depth = jdepth; + + if (!regs) return; - } - Registers* pregs = (Registers*)(thread->jvmti_saved_exception_registers); - *p_ip = (void*)pregs->rip; - *p_bp = (void*)pregs->rbp; - *p_sp = (void*)pregs->rsp; + + frame->ip = (void*)regs->rip; + frame->frame = (void*)regs->rbp; + frame->stack = (void*)regs->rsp; } Index: vm/vmcore/src/util/linux/native_stack_os.cpp =================================================================== --- vm/vmcore/src/util/linux/native_stack_os.cpp (revision 0) +++ vm/vmcore/src/util/linux/native_stack_os.cpp (revision 0) @@ -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; +*/ +} Index: vm/vmcore/src/util/native_stack.cpp =================================================================== --- vm/vmcore/src/util/native_stack.cpp (revision 619840) +++ vm/vmcore/src/util/native_stack.cpp (working copy) @@ -33,52 +33,9 @@ #include "native_stack.h" - -// Global lock used for locking module list access -static Lock_Manager g_list_lock; - - ////////////////////////////////////////////////////////////////////////////// /// Helper functions -static bool get_modules(native_module_t** pmodules) -{ - assert(pmodules); - - if (*pmodules != NULL) - return true; - - int mod_count; - native_module_t* mod_list = NULL; - - LMAutoUnlock aulock(&g_list_lock); - - bool result = get_all_native_modules(&mod_list, &mod_count); - - if (!result) - return false; - - *pmodules = mod_list; - return true; -} - -bool native_is_ip_in_modules(native_module_t* modules, void* ip) -{ - for (native_module_t* module = 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; -} - static DynamicCode* native_find_stub(void* ip) { for (DynamicCode *dcList = compile_get_dynamic_code_list(); @@ -111,6 +68,12 @@ 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 @@ -131,54 +94,108 @@ ////////////////////////////////////////////////////////////////////////////// // -static int walk_native_stack_jit(Registers* pregs, VM_thread* pthread, +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 (!get_all_native_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) + clear_native_modules(&context->modules); + return false; + } + + return true; +} + +void native_clean_walk_context(WalkContext* context) +{ + if (!context) + return; + + if (context->modules && context->clean_modules) + { + clear_native_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(Registers* pregs, +static int walk_native_stack_pure( + WalkContext* context, Registers* pregs, int max_depth, native_frame_t* frame_array); -static int walk_native_stack_interpreter(Registers* pregs, VM_thread* pthread, +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(Registers* pregs, +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(pregs, max_depth, frame_array); + return walk_native_stack_pure(context, pregs, max_depth, frame_array); if (interpreter_enabled()) - return walk_native_stack_interpreter(pregs, pthread, max_depth, frame_array); + return walk_native_stack_interpreter(context, pregs, + pthread, max_depth, frame_array); - return walk_native_stack_jit(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(Registers* pregs, VM_thread* pthread, +static int walk_native_stack_jit( + WalkContext* context, + Registers* pregs, VM_thread* pthread, int max_depth, native_frame_t* frame_array) { - // These vars store current frame context for each iteration - void *ip, *bp, *sp; - // To translate platform-dependant info; we will use ip from here - native_get_frame_info(pregs, &ip, &bp, &sp); + // 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(ip); + 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; - native_module_t* modules = NULL; if (code_type == VM_TYPE_JAVA) { // We must add dummy M2N frame to start SI iteration - assert(pthread); + if (!pthread) + return 0; + is_java = true; M2nFrame* lm2n = m2n_get_last_frame(pthread); - if (!m2n_is_suspended_frame(lm2n) || m2n_get_ip(lm2n) != ip) + 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, pregs); + m2n_push_suspended_frame(pthread, ®s); flag_dummy_frame = true; } } @@ -206,12 +223,8 @@ if (frame_array) { // If frames requested, store current frame - frame_array[frame_count].java_depth = - is_java ? java_depth : -1; - - frame_array[frame_count].ip = ip; - frame_array[frame_count].frame = bp; - frame_array[frame_count].stack = sp; + native_fill_frame_info(®s, &frame_array[frame_count], + is_java ? java_depth : -1); } ++frame_count; @@ -221,7 +234,8 @@ if (is_java) //code_type == VM_TYPE_JAVA { // Go to previous frame using StackIterator cci = si_get_code_chunk_info(si); - assert(cci); // Java method should contain cci + if (!cci) // Java method should contain cci + break; // if (inline_index < 0) we have new si // (inline_index < inline_count) we must process inline @@ -246,22 +260,22 @@ inline_index = -1; // Go to previous stack frame from StackIterator si_goto_previous(si); - native_get_ip_bp_from_si_jit_context(si, &ip, &bp);//??? - native_get_sp_from_si_jit_context(si, &sp); + native_get_regs_from_jit_context(si_get_jit_context(si), ®s); } - code_type = vm_identify_eip(ip); + 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(ip); + is_stub = native_is_ip_stub(regs.get_ip()); if (is_stub) { // Native stub, previous frame is Java frame - assert(si_is_native(si)); + if (!si_is_native(si)) + break; if (si_get_method(si)) // Frame represents JNI frame { @@ -278,60 +292,38 @@ // Ge to previous stack frame from StackIterator si_goto_previous(si); // Let's get context from si - native_get_ip_bp_from_si_jit_context(si, &ip, &bp); - native_get_sp_from_si_jit_context(si, &sp); + native_get_regs_from_jit_context(si_get_jit_context(si), ®s); } else { - if (!modules && !get_modules(&modules)) - break; + Registers tmp_regs = regs; - if (native_is_frame_valid(modules, bp, sp)) - { // Simply bp-based frame, let's unwind it - void *tmp_ip, *tmp_bp, *tmp_sp; - native_unwind_bp_based_frame(bp, &tmp_ip, &tmp_bp, &tmp_sp); - - VMBreakPoints* vm_breaks = VM_Global_State::loader_env->TI->vm_brpt; - vm_breaks->lock(); - - if (native_is_ip_in_breakpoint_handler(tmp_ip)) - { - native_unwind_interrupted_frame(&pthread->jvmti_thread, &ip, &bp, &sp); - flag_breakpoint = true; - } - else - { - ip = tmp_ip; - bp = tmp_bp; - sp = tmp_sp; - } - - vm_breaks->unlock(); + if (native_is_frame_exists(context, &tmp_regs)) + { // Stack frame (x86) + if (!native_unwind_stack_frame(context, &tmp_regs)) + break; } else - { // Is not bp-based frame - if (frame_count == 1) - { // For first frame, test special unwinding possibility - special_count = native_test_unwind_special(modules, sp); - if (special_count <= 0) - ip = NULL; - } + { // Stack frame does not exist, try using heuristics + if (!native_unwind_special(context, &tmp_regs)) + break; + } - if (frame_count <= special_count) - { // Specially unwind first native frames - bool res = native_unwind_special(modules, - sp, &ip, &sp, &bp, - frame_count == special_count); + VMBreakPoints* vm_breaks = VM_Global_State::loader_env->TI->vm_brpt; + vm_breaks->lock(); - if (!res) - break; // Unwinding failed - } - else - break; // There is another invalid frame in the stack + 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(ip); + 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) @@ -355,18 +347,16 @@ } -static int walk_native_stack_pure(Registers* pregs, +static int walk_native_stack_pure( + WalkContext* context, Registers* pregs, int max_depth, native_frame_t* frame_array) { - // These vars store current frame context for each iteration - void *ip, *bp, *sp; - // To translate platform-dependant info; we will use ip from here - native_get_frame_info(pregs, &ip, &bp, &sp); - assert(vm_identify_eip(ip) != VM_TYPE_JAVA); + // Register context for current frame + Registers regs = *pregs; + if (vm_identify_eip(regs.get_ip()) == VM_TYPE_JAVA) + return 0; int frame_count = 0; - int special_count = 0; - native_module_t* modules = NULL; while (1) { @@ -375,40 +365,22 @@ if (frame_array) { // If frames requested, store current frame - frame_array[frame_count].java_depth = -1; - frame_array[frame_count].ip = ip; - frame_array[frame_count].frame = bp; - frame_array[frame_count].stack = sp; + native_fill_frame_info(®s, &frame_array[frame_count], -1); } ++frame_count; - if (!modules && !get_modules(&modules)) - break; - - // Simply bp-based frame, let's unwind it - if (native_is_frame_valid(modules, bp, sp)) - { + 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 - native_unwind_bp_based_frame(bp, &ip, &bp, &sp); + if (!native_unwind_stack_frame(context, ®s)) + break; } else - { // Wrong frame - if (frame_count == 1) - { // For first frame, test special unwinding possibility - special_count = native_test_unwind_special(modules, sp); - if (special_count <= 0) - break; - } - - if (frame_count <= special_count) - { // Specially unwind first native frames - native_unwind_special(modules, sp, &ip, &sp, &bp, - frame_count == special_count); - } - else // There is another invalid frame in the stack + { // Stack frame does not exist, try using heuristics + if (!native_unwind_special(context, ®s)) break; } } @@ -417,13 +389,13 @@ } -static int walk_native_stack_interpreter(Registers* pregs, VM_thread* pthread, +static int walk_native_stack_interpreter( + WalkContext* context, + Registers* pregs, VM_thread* pthread, int max_depth, native_frame_t* frame_array) { - // These vars store current frame context for each iteration - void *ip, *bp, *sp; - // To translate platform-dependant info; we will use ip from here - native_get_frame_info(pregs, &ip, &bp, &sp); + // Register context for current frame + Registers regs = *pregs; assert(pthread); FrameHandle* last_frame = interpreter.interpreter_get_last_frame(pthread); @@ -431,8 +403,6 @@ int frame_count = 0; jint java_depth = 0; - int special_count = 0; - native_module_t* modules = NULL; while (1) { @@ -441,60 +411,37 @@ if (frame_array) { // If frames requested, store current frame - frame_array[frame_count].java_depth = -1; - frame_array[frame_count].ip = ip; - frame_array[frame_count].frame = bp; - frame_array[frame_count].stack = sp; + native_fill_frame_info(®s, &frame_array[frame_count], -1); } ++frame_count; // Store previous value to identify frame range later - void* prev_sp = sp; + void* prev_sp = regs.get_sp(); + Registers tmp_regs = regs; - if (!modules && !get_modules(&modules)) - break; + 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; + } - if (native_is_frame_valid(modules, bp, sp)) - { // Simply bp-based frame, let's unwind it - void *tmp_ip, *tmp_bp, *tmp_sp; - native_unwind_bp_based_frame(bp, &tmp_ip, &tmp_bp, &tmp_sp); + VMBreakPoints* vm_breaks = VM_Global_State::loader_env->TI->vm_brpt; + vm_breaks->lock(); - VMBreakPoints* vm_breaks = VM_Global_State::loader_env->TI->vm_brpt; - vm_breaks->lock(); - - if (native_is_ip_in_breakpoint_handler(tmp_ip)) - { - native_unwind_interrupted_frame(&pthread->jvmti_thread, &ip, &bp, &sp); - } - else - { - ip = tmp_ip; - bp = tmp_bp; - sp = tmp_sp; - } - - vm_breaks->unlock(); - } + if (native_is_ip_in_breakpoint_handler(tmp_regs.get_ip())) + regs = *pthread->jvmti_thread.jvmti_saved_exception_registers; else - { // Is not bp-based frame - if (frame_count == 1) - { // For first frame, test special unwinding possibility - special_count = native_test_unwind_special(modules, sp); - if (special_count <= 0) - break; - } + regs = tmp_regs; - if (frame_count <= special_count) - { // Specially unwind first native frames - native_unwind_special(modules, sp, &ip, &sp, &bp, - frame_count == special_count); - } - else - break; // There is another invalid frame in the stack - } + vm_breaks->unlock(); - bool is_java = interpreter.is_frame_in_native_frame(frame, prev_sp, sp); + bool is_java = interpreter.is_frame_in_native_frame(frame, prev_sp, regs.get_sp()); if (is_java) { Index: vm/vmcore/src/util/win/native_stack_os.cpp =================================================================== --- vm/vmcore/src/util/win/native_stack_os.cpp (revision 0) +++ vm/vmcore/src/util/win/native_stack_os.cpp (revision 0) @@ -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; +} Index: vm/vmcore/src/util/ia32/base/native_stack_ia32.cpp =================================================================== --- vm/vmcore/src/util/ia32/base/native_stack_ia32.cpp (revision 619840) +++ vm/vmcore/src/util/ia32/base/native_stack_ia32.cpp (working copy) @@ -20,176 +20,141 @@ */ #include "method_lookup.h" +#include "dec_base.h" +#include "native_modules.h" #include "native_stack.h" -void native_get_frame_info(Registers* regs, void** ip, void** bp, void** sp) -{ - *ip = (void*)regs->eip; - *bp = (void*)regs->ebp; - *sp = (void*)regs->esp; -} -bool native_unwind_bp_based_frame(void* frame, void** ip, void** bp, void** sp) +bool native_is_frame_exists(WalkContext* context, Registers* regs) { - void** frame_ptr = (void**)frame; + // Check for frame layout and stack values + if ((regs->ebp < regs->esp) || !native_is_in_stack(context, (void*)regs->ebp)) + return false; // Invalid frame - *ip = frame_ptr[1]; - *bp = frame_ptr[0]; - // FIXME - wrong value, we cannot get sp anyhow - *sp = (void*)((POINTER_SIZE_INT)frame + 2*sizeof(void*)); + void** frame_ptr = (void**)regs->ebp; + void* eip = frame_ptr[1]; // Return address - return (*bp != NULL && *ip != NULL); + // Check return address for meaning + return (native_is_in_code(context, eip) || native_is_ip_stub(eip)); } -void native_get_ip_bp_from_si_jit_context(StackIterator* si, void** ip, void** bp) +bool native_unwind_stack_frame(WalkContext* context, Registers* regs) { - JitFrameContext* jfc = si_get_jit_context(si); - *ip = (void*)*jfc->p_eip; - *bp = (void*)*jfc->p_ebp; -} + void** frame = (void**)regs->ebp; -void native_get_sp_from_si_jit_context(StackIterator* si, void** sp) -{ - *sp = (void*)si_get_jit_context(si)->esp; + 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; } -bool native_is_out_of_stack(void* value) +void native_get_regs_from_jit_context(JitFrameContext* jfc, Registers* regs) { - // FIXME: Invalid criterion - return (value < (void*)0x10000) || (value > (void*)0xC0000000); + regs->eip = *jfc->p_eip; + regs->ebp = *jfc->p_ebp; + regs->esp = jfc->esp; } -bool native_is_frame_valid(native_module_t* modules, void* bp, void* sp) +static bool fill_regs_from_sp(WalkContext* context, Registers* regs, void** sp) { - // Check for frame layout and stack values - if ((bp < sp) || native_is_out_of_stack(bp)) - return false; // Invalid frame - - void** dw_ptr = (void**)bp; - void* ret_ip = *(dw_ptr + 1); // Return address for frame - - // Check return address for meaning - if (!native_is_ip_in_modules(modules, ret_ip) && !native_is_ip_stub(ret_ip)) - return false; - + 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; } -// Searches for correct return address in the stack -// Returns stack address pointing to return address -static void** native_search_special_frame(native_module_t* modules, void* sp) +static unsigned native_dec_instr(WalkContext* context, void* addr, void** target) { -// Max search depth for return address -#define MAX_SPECIAL_DEPTH 0x40 + Inst inst; - POINTER_SIZE_INT sp_begin = (POINTER_SIZE_INT)sp; - for (POINTER_SIZE_INT sp_int = sp_begin; - sp_int < sp_begin + MAX_SPECIAL_DEPTH; - sp_int +=2) // 2 is minimum stack item for ia32 - { - void** sp_pointer = (void**)sp_int; + if (!native_is_in_code(context, addr)) + return 0; - if (native_is_ip_in_modules(modules, *sp_pointer)) - return sp_pointer; - } + uint32 len = DecoderBase::decode(addr, &inst); - return NULL; -} + if (len == 0 || + inst.mn != Mnemonic_CALL || + inst.argc != 1) + return 0; -// Tests if stack contains non-BP-based frames on top -int native_test_unwind_special(native_module_t* modules, void* sp) -{ -#define MAX_SPECIAL_COUNT 16 + if (target && inst.operands[0].is_imm()) + *target = (void*)((uint32)addr + len + inst.operands[0].imm()); -#if (!defined PLATFORM_POSIX) - return -1; // Because we cannot identify executable code on Windows -#endif + return len; +} - if (modules == NULL) - return false; - - int count = 0; - void** sp_pointer = (void**)sp; - - do +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 (native_is_ip_stub(sp_pointer[-1])) - break; // We've found JNI stub + if (!target) + return true; - // We've reached Java without native stub - if (vm_identify_eip(sp_pointer[-1]) == VM_TYPE_JAVA) - break; + native_module_t* cur_module = + find_native_module(context->modules, regs->get_ip()); + native_module_t* found_module = + find_native_module(context->modules, target); - void** next_sp = native_search_special_frame(modules, sp_pointer); + return (cur_module == found_module); + } - if (next_sp == NULL) - break; // We cannot unwind anymore + return false; +} - if (count > 0 && // Check BP-frame for upper frames - sp_pointer[-2] >= sp_pointer && // Correct frame layout - sp_pointer[-2] == next_sp - 1 && // is BP saved correctly - next_sp[-1] >= next_sp + 1) // Correct next frame layout - { - break; - } - sp_pointer = next_sp + 1; +// Max search depth for return address +#define MAX_SPECIAL_DEPTH 0x400 +#define NATIVE_STRICT_UNWINDING 1 - } while (++count <= MAX_SPECIAL_COUNT); - - return count; -} - -// Tries to unwind non-BP-based frame -bool native_unwind_special(native_module_t* modules, - void* stack, void** ip, void** sp, void** bp, bool is_last) +bool native_unwind_special(WalkContext* context, Registers* regs) { - if (modules == NULL) + 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) { - *ip = NULL; - return false; - } + if (!native_is_in_code(context, *cur_sp)) + continue; - void** found = NULL; - - POINTER_SIZE_INT sp_begin = (POINTER_SIZE_INT)stack; - for (POINTER_SIZE_INT sp_int = sp_begin; - sp_int < sp_begin + MAX_SPECIAL_DEPTH; - sp_int +=2) // 2 is minimum stack item for ia32 - { - void** sp_pointer = (void**)sp_int; - - if (native_is_ip_in_modules(modules, *sp_pointer)) - { - found = sp_pointer; - break; - } +#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 } - if (!found) - { - *ip = NULL; - return false; - } - - *ip = *found; - *sp = found + 1; - - if (is_last && !native_is_ip_stub(*ip)) - *bp = found[-1]; - else - *bp = *sp; - - return true; + return false; } -void native_unwind_interrupted_frame(jvmti_thread_t thread, void** p_ip, void** p_bp, void** p_sp) +void native_fill_frame_info(Registers* regs, native_frame_t* frame, jint jdepth) { - if (!thread) { + frame->java_depth = jdepth; + + if (!regs) return; - } - Registers* pregs = (Registers*)(thread->jvmti_saved_exception_registers); - *p_ip = (void*)pregs->eip; - *p_bp = (void*)pregs->ebp; - *p_sp = (void*)pregs->esp; + + frame->ip = (void*)regs->eip; + frame->frame = (void*)regs->ebp; + frame->stack = (void*)regs->esp; } Index: vm/vmcore/src/util/ipf/base/native_stack_ipf.cpp =================================================================== --- vm/vmcore/src/util/ipf/base/native_stack_ipf.cpp (revision 619840) +++ vm/vmcore/src/util/ipf/base/native_stack_ipf.cpp (working copy) @@ -21,55 +21,26 @@ #include "native_stack.h" -void native_get_frame_info(Registers* regs, void** ip, void** bp, void** sp) -{ - // FIXME: not implemented -} -bool native_unwind_bp_based_frame(void* frame, void** ip, void** bp, void** sp) +bool native_is_frame_exists(WalkContext* UNREF context, Registers* UNREF regs) { - return false; // Not implemented + return false; } -void native_get_ip_bp_from_si_jit_context(StackIterator* si, void** ip, void** bp) -{ // Not implemented -} - -void native_get_sp_from_si_jit_context(StackIterator* si, void** sp) -{ // Not implemented -} - -bool native_is_out_of_stack(void* value) +bool native_unwind_stack_frame(WalkContext* UNREF context, Registers* UNREF regs) { - return true; // Not implemented + return false; } -bool native_is_frame_valid(native_module_t* modules, void* bp, void* sp) +void native_get_regs_from_jit_context(JitFrameContext* UNREF jfc, Registers* UNREF regs) { - return false; // Not implemented } -int native_test_unwind_special(native_module_t* modules, void* sp) +bool native_unwind_special(WalkContext* UNREF context, Registers* UNREF regs) { - return false; // Not implemented + return false; } -bool native_unwind_special(native_module_t* modules, - void* stack, void** ip, void** sp, void** bp, bool is_last) +void native_fill_frame_info(Registers* UNREF regs, native_frame_t* UNREF frame, jint UNREF jdepth) { - return false; // Not implemented } - -void native_unwind_interrupted_frame(jvmti_thread_t thread, void** p_ip, void** p_bp, void** p_sp) -{ // Not implemented yet - *p_ip = NULL; - *p_bp = NULL; - *p_sp = NULL; -} - -void si_set_callbak(StackIterator* si, NativeCodePtr* callback) { - // FIXME: not implemented - assert(0); - abort(); -} -