// demand_interval: Given a PC 'pc', return an interval. Note that // 'pc' may be bogus (i.e, not even point to a text segment) and in this // case UNW_INTERVAL_NULL should be returned. UNW_INTERVAL_t demand_interval(void* pc, bool isTopFrame) { #if (HPC_UNW_LITE) void* proc_beg = NULL, *mod_beg = NULL; dylib_find_proc(pc, &proc_beg, &mod_beg); if (!proc_beg && mod_beg && !isTopFrame) { // The procedure begin could not be found but pc is valid (since // the module begin was found). proc_beg = mips_find_proc(pc, mod_beg); } if (proc_beg) { uint32_t* beg = (uint32_t*)proc_beg; // [insn_beg, insn_end) uint32_t* end = (uint32_t*)pc; return mips_build_intervals(beg, end, false/*retFirst*/, 0); } else { return UNW_INTERVAL_NULL; } #else // N.B.: calls build_intervals() if necessary return (UNW_INTERVAL_t)hpcrun_addr_to_interval(pc, NULL, NULL); #endif }
static void update_cursor_with_troll(hpcrun_unw_cursor_t* cursor, int offset) { if (ENABLED(NO_TROLLING)){ TMSG(TROLL, "Trolling disabled"); hpcrun_unw_throw(); } unsigned int tmp_ra_offset; int ret = stack_troll(cursor->sp, &tmp_ra_offset, &deep_validate_return_addr, (void *)cursor); if (ret != TROLL_INVALID) { void **next_sp = ((void **)((unsigned long) cursor->sp + tmp_ra_offset)); void *next_pc = *next_sp; void *ra_loc = (void*) next_sp; // the current base pointer is a good assumption for the caller's BP void **next_bp = (void **) cursor->bp; next_sp += 1; if ( next_sp <= cursor->sp){ TMSG(TROLL,"Something weird happened! trolling from %p" " resulted in sp not advancing", cursor->pc_unnorm); hpcrun_unw_throw(); } ip_normalized_t next_pc_norm = ip_normalized_NULL; cursor->intvl = hpcrun_addr_to_interval(((char *)next_pc) + offset, next_pc, &next_pc_norm); if (cursor->intvl) { TMSG(TROLL,"Trolling advances cursor to pc = %p, sp = %p", next_pc, next_sp); TMSG(TROLL,"TROLL SUCCESS pc = %p", cursor->pc_unnorm); cursor->pc_unnorm = next_pc; cursor->bp = next_bp; cursor->sp = next_sp; cursor->ra_loc = ra_loc; cursor->pc_norm = next_pc_norm; cursor->flags = 1; // trolling_used return; // success! } TMSG(TROLL, "No interval found for trolled pc, dropping sample," " cursor pc = %p", cursor->pc_unnorm); // fall through for error handling } else { TMSG(TROLL, "Troll failed: dropping sample, cursor pc = %p", cursor->pc_unnorm); TMSG(TROLL,"TROLL FAILURE pc = %p", cursor->pc_unnorm); // fall through for error handling } // assert(0); hpcrun_unw_throw(); }
void hpcrun_unw_init_cursor(hpcrun_unw_cursor_t* cursor, void* context) { mcontext_t *mc = GET_MCONTEXT(context); cursor->pc_unnorm = MCONTEXT_PC(mc); cursor->bp = MCONTEXT_BP(mc); cursor->sp = MCONTEXT_SP(mc); cursor->ra_loc = NULL; TMSG(UNW, "unw_init: pc=%p, ra_loc=%p, sp=%p, bp=%p", cursor->pc_unnorm, cursor->ra_loc, cursor->sp, cursor->bp); cursor->flags = 0; // trolling_used cursor->intvl = hpcrun_addr_to_interval(cursor->pc_unnorm, cursor->pc_unnorm, &cursor->pc_norm); if (!cursor->intvl) { EMSG("unw_init: cursor could NOT build an interval for initial pc = %p", cursor->pc_unnorm); cursor->pc_norm = hpcrun_normalize_ip(cursor->pc_unnorm, NULL); } if (MYDBG) { dump_ui((unwind_interval *)cursor->intvl, 0); } }
static step_state unw_step_bp(hpcrun_unw_cursor_t* cursor) { void *sp, **bp, *pc; void **next_sp, **next_bp, *next_pc; unwind_interval *uw; TMSG(UNW_STRATEGY,"Using BP step"); // current frame bp = cursor->bp; sp = cursor->sp; pc = cursor->pc_unnorm; uw = (unwind_interval *)cursor->intvl; TMSG(UNW,"step_bp: cursor { bp=%p, sp=%p, pc=%p }", bp, sp, pc); if (MYDBG) { dump_ui(uw, 0); } if (!(sp <= (void*) bp)) { TMSG(UNW," step_bp: STEP_ERROR, unwind attempted, but incoming bp(%p) was not" " >= sp(%p)", bp, sp); return STEP_ERROR; } if (DISABLED(OMP_SKIP_MSB)) { if (!((void *)bp < monitor_stack_bottom())) { TMSG(UNW," step_bp: STEP_ERROR, unwind attempted, but incoming bp(%p) was not" " between sp (%p) and monitor stack bottom (%p)", bp, sp, monitor_stack_bottom()); return STEP_ERROR; } } // bp relative next_sp = (void **)((void *)bp + uw->bp_bp_pos); next_bp = *next_sp; next_sp = (void **)((void *)bp + uw->bp_ra_pos); void* ra_loc = (void*) next_sp; next_pc = *next_sp; next_sp += 1; if ((void *)next_sp > sp) { // this condition is a weak correctness check. only // try building an interval for the return address again if it succeeds ip_normalized_t next_pc_norm = ip_normalized_NULL; uw = (unwind_interval *)hpcrun_addr_to_interval(((char *)next_pc) - 1, next_pc, &next_pc_norm); if (! uw){ if (((void *)next_sp) >= monitor_stack_bottom()) { TMSG(UNW," step_bp: STEP_STOP_WEAK, next_sp >= monitor_stack_bottom," " next_sp = %p", next_sp); return STEP_STOP_WEAK; } TMSG(UNW," step_bp: STEP_ERROR, cannot build interval for next_pc(%p)", next_pc); return STEP_ERROR; } else { cursor->pc_unnorm = next_pc; cursor->bp = next_bp; cursor->sp = next_sp; cursor->ra_loc = ra_loc; cursor->pc_norm = next_pc_norm; cursor->intvl = (splay_interval_t *)uw; TMSG(UNW," step_bp: STEP_OK, has_intvl=%d, bp=%p, sp=%p, pc=%p", cursor->intvl != NULL, next_bp, next_sp, next_pc); return STEP_OK; } } else { TMSG(UNW_STRATEGY,"BP unwind fails: bp (%p) < sp (%p)", bp, sp); return STEP_ERROR; } EMSG("FALL Through BP unwind: shouldn't happen"); return STEP_ERROR; }
static step_state unw_step_sp(hpcrun_unw_cursor_t* cursor) { TMSG(UNW_STRATEGY,"Using SP step"); // void *stack_bottom = monitor_stack_bottom(); // current frame void** bp = cursor->bp; void* sp = cursor->sp; void* pc = cursor->pc_unnorm; unwind_interval* uw = (unwind_interval *)cursor->intvl; TMSG(UNW,"step_sp: cursor { bp=%p, sp=%p, pc=%p }", bp, sp, pc); if (MYDBG) { dump_ui(uw, 0); } void** next_bp = NULL; void** next_sp = (void **)(sp + uw->sp_ra_pos); void* ra_loc = (void*) next_sp; void* next_pc = *next_sp; TMSG(UNW," step_sp: potential next cursor next_sp=%p ==> next_pc = %p", next_sp, next_pc); if (uw->bp_status == BP_UNCHANGED){ next_bp = bp; TMSG(UNW," step_sp: unwind step has BP_UNCHANGED ==> next_bp=%p", next_bp); } else { //----------------------------------------------------------- // reload the candidate value for the caller's BP from the // save area in the activation frame according to the unwind // information produced by binary analysis //----------------------------------------------------------- next_bp = (void **)(sp + uw->sp_bp_pos); TMSG(UNW," step_sp: unwind next_bp loc = %p", next_bp); next_bp = *next_bp; TMSG(UNW," step_sp: sp unwind next_bp val = %p", next_bp); } next_sp += 1; ip_normalized_t next_pc_norm = ip_normalized_NULL; cursor->intvl = hpcrun_addr_to_interval(((char *)next_pc) - 1, next_pc, &next_pc_norm); if (! cursor->intvl){ if (((void *)next_sp) >= monitor_stack_bottom()){ TMSG(UNW," step_sp: STEP_STOP_WEAK, no next interval and next_sp >= stack bottom," " so stop unwind ..."); return STEP_STOP_WEAK; } else { TMSG(UNW," sp STEP_ERROR: no next interval, step fails"); return STEP_ERROR; } } else { // sanity check to avoid infinite unwind loop if (next_sp <= cursor->sp){ TMSG(INTV_ERR,"@ pc = %p. sp unwind does not advance stack." " New sp = %p, old sp = %p", cursor->pc_unnorm, next_sp, cursor->sp); return STEP_ERROR; } unwind_interval* uw = (unwind_interval *)cursor->intvl; if ((RA_BP_FRAME == uw->ra_status) || (RA_STD_FRAME == uw->ra_status)) { // Makes sense to sanity check BP, do it //----------------------------------------------------------- // if value of BP reloaded from the save area does not point // into the stack, then it cannot possibly be useful as a frame // pointer in the caller or any of its ancesters. // // if the value in the BP register points into the stack, then // it might be useful as a frame pointer. in this case, we have // nothing to lose by assuming that our binary analysis for // unwinding might have been mistaken and that the value in // the register is the one we might want. // // 19 December 2007 - John Mellor-Crummey //----------------------------------------------------------- if (((unsigned long) next_bp < (unsigned long) sp) && ((unsigned long) bp > (unsigned long) sp)){ next_bp = bp; TMSG(UNW," step_sp: unwind bp sanity check fails." " Resetting next_bp to current bp = %p", next_bp); } } cursor->pc_unnorm = next_pc; cursor->bp = next_bp; cursor->sp = next_sp; cursor->ra_loc = ra_loc; cursor->pc_norm = next_pc_norm; } TMSG(UNW," step_sp: STEP_OK, has_intvl=%d, bp=%p, sp=%p, pc=%p", cursor->intvl != NULL, next_bp, next_sp, next_pc); return STEP_OK; }