static int HeuristicTraceBack( address *p_prev_sp, address *start, address *execution, address *frame, address *stack ) { mad_disasm_data dd; int word_size; long sp_adjust; long bp_adjust; long saved_bp_loc = 0; long bp_to_ra_offset = 0; // int found_inc_bp; int found_mov_bp_sp; int found_push_bp; char *jmplabel; address return_addr_location; address bp_value; address sp_value; address saved_return_location; int found_call; int i; InitCache( *start, 100 ); sp_value = *stack; bp_value = *frame; DbgAddr = *execution; DisAsm( &dd ); if( dd.ins.type == DI_X86_retf || dd.ins.type == DI_X86_retf2 ) { *execution = GetFarAddr( &sp_value ); found_call = 1; } else if( dd.ins.type == DI_X86_ret || dd.ins.type == DI_X86_ret2 ) { execution->mach.offset = GetAnOffset( &sp_value ); found_call = 1; } else { // Check for ADD SP,n right after current ip and adjust SP if its there // because it must be popping parms if( dd.ins.type == DI_X86_add3 && ConstOp( dd.ins.op[OP_2] ) && IsSPReg( dd.ins.op[OP_1] ) ){ sp_value.mach.offset += dd.ins.op[ OP_2 ].value.s._32[I64LO32]; } // Run through code from the known symbol until and collect prolog info word_size = Is32BitSegment ? 4 : 2; sp_adjust = 0; bp_adjust = 0; // found_inc_bp = 0; found_mov_bp_sp = 0; found_push_bp = 0; DbgAddr = *start; while( DbgAddr.mach.offset != execution->mach.offset ) { DisAsm( &dd ); switch( dd.ins.type ) { case DI_INVALID: return( 0 ); case DI_X86_call3: jmplabel = ToSegStr( dd.ins.op[ OP_1 ].value.s._32[I64LO32], dd.ins.op[ OP_1 ].extra, 0 ); if( IdentifyFunc( jmplabel, &sp_adjust ) ) continue; break; case DI_X86_call: jmplabel = JmpLabel( dd.ins.op[ OP_1 ].value.s._32[I64LO32], 0 ); if( IdentifyFunc( jmplabel, &sp_adjust ) ) continue; break; case DI_X86_enter: sp_adjust -= word_size; // push bp found_push_bp = 1; bp_to_ra_offset = sp_adjust; // mov bp,sp found_mov_bp_sp = 1; saved_bp_loc = 0; // 0[bp] sp_adjust -= dd.ins.op[ OP_1 ].value.s._32[I64LO32]; // sub sp,n break; case DI_X86_inc2: if( IsBPReg( dd.ins.op[ OP_1 ] ) ) { // found_inc_bp = 1; continue; } break; case DI_X86_mov: if( IsBPReg( dd.ins.op[ OP_1 ] ) && IsSPReg( dd.ins.op[ OP_2 ] ) ) { found_mov_bp_sp = 1; bp_to_ra_offset = sp_adjust; saved_bp_loc -= sp_adjust; } continue; case DI_X86_nop: continue; case DI_X86_pop: case DI_X86_pop2: case DI_X86_pop3d: case DI_X86_pop3e: case DI_X86_pop3s: case DI_X86_pop4f: case DI_X86_pop4g: sp_adjust += word_size; continue; case DI_X86_push: case DI_X86_push2: case DI_X86_push3: case DI_X86_push4f: case DI_X86_push4g: case DI_X86_push5: sp_adjust -= word_size; if( IsBPReg( dd.ins.op[ OP_1 ] ) ) { saved_bp_loc = sp_adjust; found_push_bp = 1; } continue; case DI_X86_sub: dd.ins.op[ OP_2 ].value.s._32[I64LO32] = -dd.ins.op[ OP_2 ].value.s._32[I64LO32]; /* fall through */ case DI_X86_add: if( !ConstOp( dd.ins.op[ OP_2 ] ) ) break; if( IsSPReg( dd.ins.op[ OP_1 ] ) ) { sp_adjust += dd.ins.op[ OP_2 ].value.s._32[I64LO32]; continue; } else if( IsBPReg( dd.ins.op[ OP_1 ] ) ) { bp_adjust += dd.ins.op[ OP_2 ].value.s._32[I64LO32]; continue; } break; default: break; } break; } // find the address of the return address (return_addr_location) if( found_mov_bp_sp ) { return_addr_location = bp_value; return_addr_location.mach.offset -= bp_adjust; GetBPFromStack( &return_addr_location, &bp_value ); return_addr_location.mach.offset -= bp_to_ra_offset; } else { if( found_push_bp ) { return_addr_location = sp_value; return_addr_location.mach.offset += saved_bp_loc - sp_adjust; GetBPFromStack( &return_addr_location, &bp_value ); } return_addr_location = sp_value; return_addr_location.mach.offset -= sp_adjust; } found_call = 0; if( found_mov_bp_sp ) { found_call = FindCall( execution, &return_addr_location ); if( !found_call ) { return_addr_location = sp_value; return_addr_location.mach.offset -= sp_adjust; } } if( !found_call ) { saved_return_location = return_addr_location; // limit the search to 512*word_size (W2K can cause us to search 4Gb!) for( i = 0; return_addr_location.mach.offset >= p_prev_sp->mach.offset && i < 512; ++i ) { found_call = FindCall( execution, &return_addr_location ); if( found_call ) break; return_addr_location.mach.offset -= word_size; } if( !found_call ) { return_addr_location = saved_return_location; for( i = 0; i < 10; ++i ) { return_addr_location.mach.offset += word_size; found_call = FindCall( execution, &return_addr_location ); if( found_call ) { break; } } } } } *stack = DbgAddr; *frame = bp_value; return( found_call ); }
void FormatIns( char *buf, instruction *curr_ins, form_option format ) /*********************************************************************/ { const char *name; int len; operand *op; int i; int seg_override; bool prefix; char tmp_buff[ 80 ]; char *ptr; if( curr_ins->opcode == I_INVALID ) { strcpy( buf, "?????" ); return; } CurrIns = *curr_ins; prefix = false; for( i = 0; i <= 3; ++i ) { if( CurrIns.pref & PrefixTab[ i ] ) { strcpy( tmp_buff, InsName[ PrefixName[ i ] ] ); PadBlanks( tmp_buff ); if( format & FORM_NAME_UPPER ) { ZapUpper( tmp_buff ); } strcat( buf, tmp_buff ); prefix = true; } } seg_override = NULL_REG; if( CurrIns.pref & PREF_xS ) { seg_override = CurrIns.seg_used; FixStringIns( &CurrIns ); } if( CurrIns.opcode < FIRST_WTK_INS ) { name = InsName[ CurrIns.opcode ]; } else { name = GetWtkInsName( CurrIns.opcode - FIRST_WTK_INS ); } strcpy( tmp_buff, name ); #ifdef O2A if( DO_UNIX ) { ToUnixInsName( tmp_buff, &CurrIns ); } #endif if( format & FORM_NAME_UPPER ) { ZapUpper( tmp_buff ); } strcat( buf, tmp_buff ); PadBlanks( buf ); if( prefix ) { /* if a prefix like 'lock', need space after name */ strcat( buf, " " ); } tmp_buff[ 0 ] = '\0'; #ifdef O2A if( !DO_UNIX ) { #endif if( CurrIns.opcode == I_CALL_FAR || CurrIns.opcode == I_JMP_FAR ) { if( CurrIns.modifier == MOD_NONE ) { if( format & FORM_ASSEMBLER ) { strcpy( tmp_buff, "far ptr " ); } else { strcpy( tmp_buff, "far " ); } } } else if( CurrIns.opcode == I_CALL || ( IsJumpIns( CurrIns.opcode ) && CurrIns.ins_size != 2 ) ) { if( CurrIns.modifier == MOD_NONE ) { if( format & FORM_ASSEMBLER ) { strcpy( tmp_buff, "near ptr " ); } } } if( format & FORM_NAME_UPPER ) { ZapUpper( tmp_buff ); } strcat( buf, tmp_buff ); #ifdef O2A } else if( CurrIns.num_oper >= 2 ) { // swap operands operand tmp; int last; last = CurrIns.num_oper - 1; tmp = CurrIns.op[ OP_1 ]; CurrIns.op[ OP_1 ] = CurrIns.op[ last ]; CurrIns.op[ last ] = tmp; if( CurrIns.mem_ref_op == 0 ) { CurrIns.mem_ref_op = last; } else if( CurrIns.mem_ref_op == last ) { CurrIns.mem_ref_op = 0; } } #endif for( i = 0; i < CurrIns.num_oper; ++i ) { if( i > 0 ) { len = strlen( buf ); buf[ len ] = ','; buf[ len + 1 ] = '\0'; } op = &CurrIns.op[ i ]; if( CurrIns.mem_ref_op == i ) { if( #ifdef O2A !DO_UNIX && #endif CurrIns.modifier != MOD_NONE ) { strcpy( tmp_buff, ModifierTab[ CurrIns.modifier ] ); if( format & FORM_NAME_UPPER ) { ZapUpper( tmp_buff ); } strcat( buf, tmp_buff ); } if( seg_override != NULL_REG ) { DumpOverride( tmp_buff, seg_override ); if( format & FORM_REG_UPPER ) ZapUpper( tmp_buff ); strcat( buf, tmp_buff ); } } switch( op->mode ) { case ADDR_REG: ptr = tmp_buff; #ifdef O2A if( DO_UNIX ) { *ptr++ = '%'; } #endif strcpy( ptr, X86RegisterName[ op->base ] ); if( format & FORM_REG_UPPER ) ZapUpper( ptr ); strcat( buf, tmp_buff ); break; case ADDR_CONST: #ifdef O2A if( DO_UNIX ) { strcat( buf, "$" ); } #endif if( op->size == 0 ) { len = strlen( buf ); ltoa( op->disp, &buf[ len ], 10 ); } else { strcat( buf, ToStr( op->disp, 2 * op->size, op->offset ) ); } break; case ADDR_LABEL: #ifdef O2A if( !DO_UNIX && ( format & FORM_ASSEMBLER && IsJumpIns( CurrIns.opcode ) ) ) { if( CurrIns.ins_size == 2 ) { if( format & FORM_NAME_UPPER ) { strcat( buf, "SHORT " ); } else { strcat( buf, "short " ); } } } #endif strcat( buf, JmpLabel( op->disp, op->offset ) ); break; case ADDR_ABS: strcat( buf, ToBrStr( op->disp, op->offset ) ); break; case ADDR_BASE: case ADDR_INDEX: case ADDR_BASE_INDEX: if( #ifdef O2A DO_UNIX || #endif ( format & FORM_INDEX_IN ) == 0 ) { if( op->size != 0 ) { strcat( buf, ToIndex( op->disp, op->offset ) ); } } len = strlen( buf ); buf[ len ] = START_INDEX; FormIndex( op, tmp_buff ); if( format & FORM_REG_UPPER ) { ZapUpper( tmp_buff ); } strcpy( &buf[ len + 1 ], tmp_buff ); if( #ifdef O2A !DO_UNIX && #endif ( format & FORM_INDEX_IN ) ) { if( op->size != 0 ) { name = ToIndex( op->disp, op->offset ); if( *name != '+' && *name != '-' ) { strcat( buf, "+" ); } strcat( buf, name ); } } len = strlen( buf ); buf[ len ] = END_INDEX; buf[ len + 1 ] = '\0'; break; case ADDR_SEG_OFFSET: /* modifier or seg override */ strcat( buf, ToSegStr( op->disp, (op+1)->disp, op->offset ) ); break; case ADDR_ES_DI: case ADDR_ES_EDI: /* we have an overridden string instruction */ ptr = DumpOverride( tmp_buff, ES_REG ); *ptr++ = START_INDEX; strcpy( ptr, X86RegisterName[ op->mode == ADDR_ES_DI ? DI_REG : EDI_REG ] ); ptr += strlen( ptr ); *ptr++ = END_INDEX; *ptr = '\0'; if( format & FORM_REG_UPPER ) ZapUpper( tmp_buff ); strcat( buf, tmp_buff ); break; case ADDR_WTK: { char * tmpstr; wop_type tmptype = (wop_type)op->size; if( tmptype == WST || tmptype == ANY_SINGLE ) { tmpstr = "ws"; } else { tmpstr = "wd"; } strcat( buf, tmpstr ); itoa( (int)op->disp, &buf[ strlen( buf ) ], 10 ); } break; case ADDR_WTK_OPCODE: strcat( buf, InsName[ op->disp ] ); break; } } if( CurrIns.pref & EMU_INTERRUPT ) { strcat( buf, "; int " ); strcat( buf, ToStr( CurrIns.op[ OP_3 ].disp, 2, -1 ) ); } }