int VariableFrame( addr_off off ) { axp_pdata pdata; unsigned_32 ins; address a; if( GetPData( off, &pdata ) != MS_OK ) return( 0 ); if( pdata.pro_end_addr.u._32[0] == pdata.beg_addr.u._32[0] ) { return( 0 ); } memset( &a, 0, sizeof( a ) ); a.mach.offset = pdata.pro_end_addr.u._32[0] - sizeof( ins ); MCReadMem( a, sizeof( ins ), &ins ); return( ins == INS_MOV_SP_FP ); }
mad_status DIGENTRY MICallUpStackLevel( mad_call_up_data *cud, const address *start, unsigned rtn_characteristics, long return_disp, const mad_registers *in, address *execution, address *frame, address *stack, mad_registers **out ) { axp_pdata pdata; mad_disasm_data dd; mad_status ms; address curr; addr_off prev_ra_off; addr_off prev_sp_off; addr_off prev_fp_off; addr_off frame_size; addr_off frame_start; return_disp = return_disp; start = start; rtn_characteristics = rtn_characteristics; in = in; *out = NULL; if( cud->ra == 0 ) return( MS_FAIL ); if( cud->sp == 0 ) return( MS_FAIL ); ms = GetPData( execution->mach.offset, &pdata ); if( ms != MS_OK ) return( ms ); frame_size = 0; frame_start = cud->sp; prev_ra_off = NO_OFF; prev_sp_off = NO_OFF; prev_fp_off = NO_OFF; curr = *execution; curr.mach.offset = pdata.beg_addr.u._32[0]; if( curr.mach.offset == 0 ) return( MS_FAIL ); for( ;; ) { if( curr.mach.offset >= execution->mach.offset ) break; if( curr.mach.offset >= pdata.pro_end_addr.u._32[0] ) break; ms = DisasmOne( &dd, &curr, 0 ); if( ms != MS_OK ) return( ms ); if( curr.mach.offset == (pdata.beg_addr.u._32[0] + sizeof( unsigned_32 )) ) { if( dd.ins.type != DI_AXP_LDA ) return( MS_FAIL ); frame_size = -dd.ins.op[1].value; } switch( dd.ins.type ) { case DI_AXP_STQ: switch( dd.ins.op[0].base ) { case DR_AXP_ra: case DR_AXP_r26: prev_ra_off = dd.ins.op[1].value; break; case DR_AXP_sp: case DR_AXP_r30: prev_sp_off = dd.ins.op[1].value; break; case DR_AXP_fp: case DR_AXP_r15: prev_fp_off = dd.ins.op[1].value; break; } break; case DI_AXP_BIS: if( dd.ins.op[0].type == DO_REG && dd.ins.op[1].type == DO_REG && dd.ins.op[2].type == DO_REG && dd.ins.op[0].base == DR_AXP_r31 /* zero */ && dd.ins.op[1].base == DR_AXP_r30 /* sp */ && dd.ins.op[2].base == DR_AXP_r15 /* fp */ ) { /* variable frame routine, and we've done all the prolog */ frame_start = cud->fp; } break; } } if( frame_start == 0 ) return( MS_FAIL ); if( prev_sp_off != NO_OFF ) { if( !GetAnOffset( frame_start + prev_sp_off, &cud->sp ) ) return( MS_FAIL ); } else { cud->sp = frame_start + frame_size; } if( prev_fp_off != NO_OFF ) { if( !GetAnOffset( frame_start + prev_fp_off, &cud->fp ) ) return( MS_FAIL ); } if( prev_ra_off != NO_OFF ) { if( !GetAnOffset( frame_start + prev_ra_off, &cud->ra ) ) return( MS_FAIL ); } stack->mach.offset = cud->sp; execution->mach.offset = cud->ra; if( VariableFrame( execution->mach.offset ) ) { frame->mach.offset = cud->fp; } else { frame->mach.offset = cud->sp; } return( MS_OK ); }