unwind_interval * process_lea(xed_decoded_inst_t *xptr, const xed_inst_t *xi, interval_arg_t *iarg) { highwatermark_t *hw_tmp = &(iarg->highwatermark); unwind_interval *next = iarg->current; const xed_operand_t *op0 = xed_inst_operand(xi, 0); xed_operand_enum_t op0_name = xed_operand_name(op0); if ((op0_name == XED_OPERAND_REG0)) { xed_reg_enum_t regname = xed_decoded_inst_get_reg(xptr, op0_name); if (x86_isReg_BP(regname)) { //======================================================================= // action: clobbering the base pointer; begin a new SP_RELATIVE interval // note: we don't check that BP is BP_SAVED; we might have to //======================================================================= next = new_ui(iarg->ins + xed_decoded_inst_get_length(xptr), RA_SP_RELATIVE, iarg->current->sp_ra_pos, iarg->current->bp_ra_pos, BP_HOSED, iarg->current->sp_bp_pos, iarg->current->bp_bp_pos, iarg->current); if (HW_TEST_STATE(hw_tmp->state, HW_BP_SAVED, HW_BP_OVERWRITTEN) && (hw_tmp->uwi->sp_ra_pos == next->sp_ra_pos)) { hw_tmp->uwi = next; hw_tmp->state = HW_NEW_STATE(hw_tmp->state, HW_BP_OVERWRITTEN); } } } return next; }
void reset_to_canonical_interval(xed_decoded_inst_t *xptr, unwind_interval **next, bool irdebug, interval_arg_t *iarg, mem_alloc m_alloc) { unwind_interval *current = iarg->current; unwind_interval *first = iarg->first; unwind_interval *hw_uwi = iarg->highwatermark.uwi; // if the return is not the last instruction in the interval, // set up an interval for code after the return if (iarg->ins + xed_decoded_inst_get_length(xptr) < iarg->end){ if (iarg->bp_frames_found) { // look for first bp frame first = find_first_bp_frame(first); set_ui_canonical(first, iarg->canonical_interval); iarg->canonical_interval = first; } else if (iarg->canonical_interval) { if (hw_uwi && UWI_RECIPE(hw_uwi)->bp_status != BP_UNCHANGED) if ((UWI_RECIPE(iarg->canonical_interval)->bp_status == BP_UNCHANGED) || ((UWI_RECIPE(iarg->canonical_interval)->bp_status == BP_SAVED) && (UWI_RECIPE(hw_uwi)->bp_status == BP_HOSED))) { set_ui_canonical(hw_uwi, iarg->canonical_interval); iarg->canonical_interval = hw_uwi; } first = iarg->canonical_interval; } else { // look for first nondecreasing with no jmp first = find_first_non_decr(first, hw_uwi); set_ui_canonical(first, iarg->canonical_interval); iarg->canonical_interval = first; } { ra_loc ra_status = UWI_RECIPE(first)->ra_status; bp_loc bp_status = (UWI_RECIPE(current)->bp_status == BP_HOSED) ? BP_HOSED : UWI_RECIPE(first)->bp_status; #ifndef FIX_INTERVALS_AT_RETURN if ((UWI_RECIPE(current)->ra_status != ra_status) || (UWI_RECIPE(current)->bp_status != bp_status) || (UWI_RECIPE(current)->sp_ra_pos != UWI_RECIPE(first)->sp_ra_pos) || (UWI_RECIPE(current)->bp_ra_pos != UWI_RECIPE(first)->bp_ra_pos) || (UWI_RECIPE(current)->bp_bp_pos != UWI_RECIPE(first)->bp_bp_pos) || (UWI_RECIPE(current)->sp_bp_pos != UWI_RECIPE(first)->sp_bp_pos)) #endif { *next = new_ui(iarg->ins + xed_decoded_inst_get_length(xptr), ra_status, UWI_RECIPE(first)->sp_ra_pos, UWI_RECIPE(first)->bp_ra_pos, bp_status, UWI_RECIPE(first)->sp_bp_pos, UWI_RECIPE(first)->bp_bp_pos, current, m_alloc); set_ui_restored_canonical(*next, UWI_RECIPE(iarg->canonical_interval)->prev_canonical); if (UWI_RECIPE(first)->bp_status != BP_HOSED && bp_status == BP_HOSED) { set_ui_canonical(*next, iarg->canonical_interval); iarg->canonical_interval = *next; } return; } } } *next = current; }
unwind_interval * process_leave(xed_decoded_inst_t *xptr, const xed_inst_t *xi, interval_arg_t *iarg) { unwind_interval *next; next = new_ui(iarg->ins + xed_decoded_inst_get_length(xptr), RA_SP_RELATIVE, 0, 0, BP_UNCHANGED, 0, 0, iarg->current); return next; }
unwind_interval * process_and(xed_decoded_inst_t *xptr, const xed_inst_t *xi, interval_arg_t *iarg, mem_alloc m_alloc) { unwind_interval *next = iarg->current; const xed_operand_t* op0 = xed_inst_operand(xi,0); xed_operand_enum_t op0_name = xed_operand_name(op0); if (op0_name == XED_OPERAND_REG0) { xed_reg_enum_t reg0 = xed_decoded_inst_get_reg(xptr, op0_name); if (x86_isReg_SP(reg0) && UWI_RECIPE(iarg->current)->bp_status != BP_UNCHANGED) { //----------------------------------------------------------------------- // we are adjusting the stack pointer via 'and' instruction //----------------------------------------------------------------------- next = new_ui(iarg->ins + xed_decoded_inst_get_length(xptr), RA_BP_FRAME, UWI_RECIPE(iarg->current)->sp_ra_pos, UWI_RECIPE(iarg->current)->bp_ra_pos, UWI_RECIPE(iarg->current)->bp_status, UWI_RECIPE(iarg->current)->sp_bp_pos, UWI_RECIPE(iarg->current)->bp_bp_pos, iarg->current, m_alloc); } } return next; }
unwind_interval * process_addsub(xed_decoded_inst_t *xptr, const xed_inst_t *xi, interval_arg_t *iarg) { highwatermark_t *hw_tmp = &(iarg->highwatermark); unwind_interval *next = iarg->current; const xed_operand_t* op0 = xed_inst_operand(xi,0); const xed_operand_t* op1 = xed_inst_operand(xi,1); xed_operand_enum_t op0_name = xed_operand_name(op0); if (op0_name == XED_OPERAND_REG0) { xed_reg_enum_t reg0 = xed_decoded_inst_get_reg(xptr, op0_name); if (x86_isReg_SP(reg0)) { //----------------------------------------------------------------------- // we are adjusting the stack pointer //----------------------------------------------------------------------- if (xed_operand_name(op1) == XED_OPERAND_IMM0) { int sign = (iclass_eq(xptr, XED_ICLASS_ADD)) ? -1 : 1; long immedv = sign * xed_decoded_inst_get_signed_immediate(xptr); ra_loc istatus = iarg->current->ra_status; if ((istatus == RA_STD_FRAME) && (immedv > 0) && (hw_tmp->state & HW_SP_DECREMENTED)) { //------------------------------------------------------------------- // if we are in a standard frame and we see a second subtract, // it is time to convert interval to a BP frame to minimize // the chance we get the wrong offset for the return address // in a routine that manipulates SP frequently (as in // leapfrog_mod_leapfrog_ in the SPEC CPU2006 benchmark // 459.GemsFDTD, when compiled with PGI 7.0.3 with high levels // of optimization). // // 9 December 2007 -- John Mellor-Crummey //------------------------------------------------------------------- } next = new_ui(iarg->ins + xed_decoded_inst_get_length(xptr), istatus, iarg->current->sp_ra_pos + immedv, iarg->current->bp_ra_pos, iarg->current->bp_status, iarg->current->sp_bp_pos + immedv, iarg->current->bp_bp_pos, iarg->current); if (immedv > 0) { if (HW_TEST_STATE(hw_tmp->state, 0, HW_SP_DECREMENTED)) { //----------------------------------------------------------------- // set the highwatermark and canonical interval upon seeing // the FIRST subtract from SP; take no action on subsequent // subtracts. // // test case: main in SPEC CPU2006 benchmark 470.lbm // contains multiple subtracts from SP when compiled with // PGI 7.0.3 with high levels of optimization. the first // subtract from SP is to set up the frame; subsequent ones // are to reserve space for arguments passed to functions. // // 9 December 2007 -- John Mellor-Crummey //----------------------------------------------------------------- hw_tmp->uwi = next; hw_tmp->succ_inst_ptr = iarg->ins + xed_decoded_inst_get_length(xptr); hw_tmp->state = HW_NEW_STATE(hw_tmp->state, HW_SP_DECREMENTED); iarg->canonical_interval = next; } } } else { if (iarg->current->ra_status != RA_BP_FRAME){ //------------------------------------------------------------------- // no immediate in add/subtract from stack pointer; switch to // BP_FRAME // // 9 December 2007 -- John Mellor-Crummey //------------------------------------------------------------------- next = new_ui(iarg->ins + xed_decoded_inst_get_length(xptr), RA_BP_FRAME, iarg->current->sp_ra_pos, iarg->current->bp_ra_pos, iarg->current->bp_status, iarg->current->sp_bp_pos, iarg->current->bp_bp_pos, iarg->current); iarg->bp_frames_found = true; } } } } return next; }