Files
2021-10-31 21:20:46 +02:00

1018 lines
30 KiB
C++

/*
This module has been created by Petr Novak
*/
#include "xa.hpp"
#include <frame.hpp>
#include <segment.hpp>
#include <auto.hpp>
#include <funcs.hpp>
#include <struct.hpp>
static void create_ext_ram_seg(ea_t &v)
{
if ( (v & 0xFF0000L) >= 0x80000L ) // these are references to code
{
v = v & 0x7FFFFL;
return;
}
if ( v && getseg(v) == NULL )
{
ea_t start = v & 0xFFFF0000L;
char sname[32];
qsnprintf(sname, sizeof(sname), "RAM%02x", int((start&0xFF0000L)>>16));
add_segm(start>>4, start, start+0x10000L, sname, "DATA");
}
}
static int check_insn(
insn_t &insn,
int prev,
int itype,
optype_t op1type,
ea_t op1value,
optype_t op2type,
ea_t op2value)
{
if ( prev && decode_prev_insn(&insn, insn.ea) == BADADDR )
return 0;
switch ( itype )
{
case XA_mov:
if ( insn.itype != XA_mov && insn.itype != XA_movs )
return 0;
break;
case XA_add:
case XA_sub:
if ( insn.itype != itype && insn.itype != XA_adds )
return 0;
break;
default:
if ( insn.itype != itype )
return 0;
break;
}
if ( op1type != o_void )
{
if ( insn.Op1.type != op1type )
return 0;
if ( op1value != BADADDR )
{
switch ( op1type )
{
case o_imm:
if ( insn.Op1.value != op1value )
return 0;
break;
case o_reg:
case o_phrase:
if ( insn.Op1.reg != op1value )
return 0;
break;
default:
if ( insn.Op1.addr != op1value )
return 0;
break;
}
}
}
if ( op2type != o_void )
{
if ( insn.Op2.type != op2type )
return 0;
if ( op2value != BADADDR )
{
switch ( op2type )
{
case o_imm:
if ( insn.Op2.value != op2value )
return 0;
break;
case o_reg:
case o_phrase:
if ( insn.Op2.reg != op2value )
return 0;
break;
default:
if ( insn.Op2.addr != op2value )
return 0;
break;
}
}
}
return 1;
}
//------------------------------------------------------------------------
// Handle an operand with an immediate value:
// - mark it with FF_IMMD flag
// - for bit logical instructions specify the operand type as a number
// because such an operand is likely a plain number rather than
// an offset or of another type.
static void set_immd_bit(const insn_t &insn, const op_t &x)
{
set_immd(insn.ea);
if ( is_defarg(get_flags(insn.ea), x.n) )
return;
switch ( insn.itype )
{
case XA_and:
case XA_or:
case XA_xor:
op_num(insn.ea,x.n);
break;
}
}
//----------------------------------------------------------------------
static void attach_name_comment(const insn_t &insn, const op_t &x, ea_t v)
{
qstring qbuf;
if ( get_name_expr(&qbuf, insn.ea, x.n, v, v&0xFFFF) > 0 )
set_cmt(insn.ea, qbuf.begin(), false);
}
//----------------------------------------------------------------------
// Handle an operand. What this function usually does:
// - creates cross-references from the operand
// (the kernel deletes all xrefs before calling emu())
// - creates permanent comments
// - if possible, specifies the operand type (for example, it may
// create stack variables)
// - anything else you might need to emulate or trace
void xa_t::handle_operand(insn_t &insn, const op_t &x, bool loading)
{
flags_t F = get_flags(insn.ea);
switch ( x.type )
{
case o_reg: // no special hanlding for these types
break;
case o_imm: // an immediate number as an operand
if ( !loading )
goto BAD_LOGIC; // this can't happen!
set_immd_bit(insn, x); // handle immediate number
// if the value was converted to an offset, then create a data xref:
if ( op_adds_xrefs(F, x.n) )
insn.add_off_drefs(x, dr_O, 0);
break;
case o_displ:
if ( x.phrase != fRi )
set_immd_bit(insn, x); // handle immediate number
// if the value was converted to an offset, then create a data xref:
if ( op_adds_xrefs(F, x.n) )
insn.add_off_drefs(x, loading?dr_R:dr_W, OOF_SIGNED|OOF_ADDR);
// Handle stack variables in a form [R7] and [R7+xx]
// There is no frame pointer and all references are SP (R7) based
if ( may_create_stkvars()
&& !is_defarg(F, x.n)
&& x.indreg == rR7
&& (x.n != 1 || !check_insn(insn, 0, XA_lea, o_reg, rR7, o_void, BADADDR)) )
{
func_t *pfn = get_func(insn.ea);
if ( pfn != NULL )
{
insn_t saved = insn;
int n = x.n;
op_t fake = x;
if ( decode_insn(&insn, insn.ea+insn.size) > 0 )
{
if ( fake.dtype == dt_word )
{
QASSERT(10088, n == 0 || n == 1);
if ( saved.itype == insn.itype
&& saved.ops[n].type == insn.ops[n].type
&& saved.ops[n].phrase == insn.ops[n].phrase
&& saved.ops[n].indreg == insn.ops[n].indreg
&& saved.ops[n].addr + 2 == insn.ops[n].addr
&& saved.ops[1-n].type == insn.ops[1-n].type
&& saved.ops[1-n].reg + 1 == insn.ops[1-n].reg )
{
fake.dtype = dt_dword;
}
}
else
{ // dt_byte
if ( saved.itype == XA_mov //-V501 identical sub-expressions
&& insn.itype == XA_mov
&& n == 1
&& insn.Op2.type == o_reg
&& saved.Op1.reg == insn.Op2.reg
&& insn.Op1.type == o_mem
&& insn.Op1.addr == ES
&& decode_insn(&insn, insn.ea+insn.size) > 0
&& insn.itype == XA_mov
&& insn.Op1.type == o_reg
&& insn.Op1.dtype == dt_word
&& insn.Op2.type == o_displ
&& insn.Op2.addr + 2 == saved.Op2.addr )
{
fake.dtype = dt_dword;
fake.addr -= 2;
}
}
}
insn = saved;
if ( insn.create_stkvar(fake, fake.addr, STKVAR_VALID_SIZE) )
op_stkvar(insn.ea, x.n);
else
{
if ( fake.dtype == dt_dword )
{
fake.dtype = dt_word;
if ( insn.create_stkvar(fake, fake.addr, STKVAR_VALID_SIZE) )
{
fake.dtype = dt_dword;
insn.create_stkvar(fake, fake.addr, STKVAR_VALID_SIZE);
op_stkvar(insn.ea, x.n);
}
}
}
}
}
// fallthru
case o_phrase:
if ( x.indreg != rR7 && (x.phrase == fRi || x.phrase == fRip) ) // catch ES:offset references
{
int reg = x.indreg - rR0;
insn_t saved = insn;
if ( check_insn(insn, 1, XA_mov, o_reg, reg+rR0, o_imm, BADADDR) )
{
ea_t v = EXTRAMBASE + insn.Op2.value;
int dtype;
create_ext_ram_seg(v);
if ( !is_defarg(F, 1) )
op_offset(insn.ea, 1, REF_OFF16, v, v & 0xFFFF0000);
insn = saved;
dtype = x.dtype;
if ( dtype == dt_word )
{
int n = x.n;
if ( decode_insn(&insn, insn.ea+insn.size) > 0
&& insn.ops[n].type == o_displ
&& insn.ops[n].indreg == reg+rR0 )
{
dtype = dt_dword;
}
insn = saved;
}
insn.create_op_data(v, x.offb, dtype);
insn.add_dref(v, x.offb, loading ? dr_R : dr_W);
attach_name_comment(insn, x, v);
}
else if ( check_insn(insn, 0, XA_setb, o_bit, 0x218+reg, o_void, BADADDR) )
{
if ( check_insn(insn, 1, XA_mov, o_mem, ES, o_imm, BADADDR) )
{
ea_t v = EXTRAMBASE + (insn.Op2.value << 16);
if ( check_insn(insn, 1, XA_mov, o_reg, reg+rR0, o_imm, BADADDR)
|| check_insn(insn, 0, XA_lea, o_reg, reg+rR0, o_displ, BADADDR) )
{
int dtype;
v += insn.Op2.type == o_imm ? insn.Op2.value : insn.Op2.addr;
create_ext_ram_seg(v);
if ( !is_defarg(F, 1) )
op_offset(insn.ea, 1, REF_OFF16, v, v & 0xFFFF0000);
insn = saved;
dtype = x.dtype;
if ( dtype == dt_word )
{
int n = x.n;
if ( decode_insn(&insn, insn.ea+insn.size) > 0
&& insn.ops[n].type == o_displ
&& insn.ops[n].indreg == reg+rR0 )
{
dtype = dt_dword;
}
insn = saved;
}
insn.create_op_data(v, x.offb, dtype);
insn.add_dref(v, x.offb, loading ? dr_R : dr_W);
attach_name_comment(insn, x, v);
}
}
else if ( check_insn(insn, 0, XA_mov, o_mem, ES, o_reg, 2*reg+rR1L)
|| check_insn(insn, 0, XA_mov, o_mem, CS, o_reg, 2*reg+rR1L) )
{ // MOV.B ES/CS,R1L
int prev = 0;
ea_t v = EXTRAMBASE;
int ok = 0;
if ( check_insn(insn, 1, XA_jb, o_bit, BADADDR, o_void, BADADDR)
&& (insn.Op1.addr & 0xf) == 0xf
&& (insn.Op1.addr & 0xFFF0) == ((reg+1)<<4) )
{
prev = 1;
}
if ( check_insn(insn, prev, XA_add, o_reg, reg+rR0, o_reg, BADADDR) )
prev = 1;
else
prev = 0;
if ( check_insn(insn, prev, XA_mov, o_reg, 2*reg+rR1H, o_imm, 0) )
{
if ( check_insn(insn, 1, XA_mov, o_reg, 2*reg+rR1L, o_mem, DS) )
ok = 1;
}
else if ( check_insn(insn, 0, XA_mov, o_reg, reg+rR1, o_imm, BADADDR)
|| check_insn(insn, 0, XA_addc, o_reg, reg+rR1, o_imm, BADADDR) )
{
v += (insn.Op2.value << 16);
ok = 1;
}
if ( ok
&& (check_insn(insn, 1, XA_mov, o_reg, reg+rR0, o_imm, BADADDR)
|| check_insn(insn, 0, XA_add, o_reg, reg+rR0, o_imm, BADADDR)) )
{
int dtype;
v += insn.Op2.value;
create_ext_ram_seg(v);
if ( !is_defarg(F, 1) )
op_offset(insn.ea, 1, REF_OFF16, v, v & 0xFFFF0000);
insn = saved;
dtype = x.dtype;
if ( dtype == dt_word )
{
int n = x.n;
if ( decode_insn(&insn, insn.ea+insn.size) > 0
&& insn.ops[n].type == o_displ
&& insn.ops[n].indreg == reg+rR0 )
{
dtype = dt_dword;
}
insn = saved;
}
insn.create_op_data(v, x.offb, dtype);
insn.add_dref(v, x.offb, loading ? dr_R : dr_W);
attach_name_comment(insn, x, v);
}
}
else if ( check_insn(insn, 0, XA_mov, o_reg, reg+rR0, o_imm, BADADDR) )
{ // mov.w Rx,#xxxx
ea_t v = insn.Op2.value;
if ( check_insn(insn, 1, XA_mov, o_mem, ES, o_reg, BADADDR)
&& insn.Op1.dtype == dt_byte )
{
int reg2 = insn.Op2.reg;
if ( check_insn(insn, 1, XA_mov, o_reg, reg2, o_imm, BADADDR) )
{
int dtype;
v += EXTRAMBASE + (insn.Op2.value << 16);
create_ext_ram_seg(v);
insn = saved;
dtype = x.dtype;
if ( dtype == dt_word )
{
int n = x.n;
if ( decode_insn(&insn, insn.ea+insn.size) > 0
&& insn.ops[n].type == o_displ
&& insn.ops[n].indreg == reg+rR0 )
{
dtype = dt_dword;
}
insn = saved;
}
insn.create_op_data(v, x.offb, dtype);
insn.add_dref(v, x.offb, loading ? dr_R : dr_W);
attach_name_comment(insn, x, v);
}
}
}
}
else if ( check_insn(insn, 0, XA_mov, o_mem, ES, o_reg, BADADDR)
&& insn.Op2.dtype == dt_byte )
{ // MOV.B ES,RxL
int reg2 = (insn.Op2.reg - rR0L) >> 1;
if ( check_insn(insn, 1, XA_jb, o_bit, BADADDR, o_void, BADADDR)
&& (insn.Op1.addr & 0xf) == 0xf
&& (insn.Op1.addr & 0xFFF0) == (reg2<<4)
&& check_insn(insn, 1, XA_setb, o_bit, 0x218+reg, o_void, BADADDR) )
{
int prev = 0;
if ( check_insn(insn, 1, XA_add, o_reg, reg+rR0, o_void, BADADDR) )
prev = 1;
if ( check_insn(insn, prev, XA_mov, o_reg, reg2+rR0, o_imm, BADADDR)
|| check_insn(insn, 0, XA_addc, o_reg, reg2+rR0, o_imm, BADADDR) )
{
ea_t v = (insn.Op2.value & 0x8000) ? 0 : EXTRAMBASE;
v += (insn.Op2.value & 0xff) << 16;
if ( check_insn(insn, 1, XA_mov, o_reg, reg+rR0, o_imm, BADADDR)
|| check_insn(insn, 0, XA_add, o_reg, reg+rR0, o_imm, BADADDR) )
{
int dtype;
v += insn.Op2.value;
create_ext_ram_seg(v);
op_offset(insn.ea, 1, REF_OFF16, v, v & 0xFFFF0000);
insn = saved;
dtype = x.dtype;
if ( dtype == dt_word )
{
int n = x.n;
if ( decode_insn(&insn, insn.ea+insn.size) > 0
&& insn.ops[n].type == o_displ
&& insn.ops[n].indreg == reg+rR0 )
{
dtype = dt_dword;
}
insn = saved;
}
insn.create_op_data(v, x.offb, dtype);
insn.add_dref(v, x.offb, loading ? dr_R : dr_W);
attach_name_comment(insn, x, v);
}
}
}
}
insn = saved;
}
break;
case o_bit: // 8051 specific operand types - bits
case o_bitnot:
{
int addr = int(x.addr >> 3);
int bit = x.addr & 7;
ea_t dea;
if ( addr & 0x40 ) // SFR
{
addr += 0x3c0;
}
else if ( (x.addr & 0x20) == 0 ) // Register file
{
break;
}
attach_bit_comment(insn, addr, bit); // attach a comment if necessary
dea = map_addr(addr);
insn.create_op_data(dea, x.offb, dt_byte);
insn.add_dref(dea, x.offb, loading ? dr_R : dr_W);
}
break;
case o_mem: // an ordinary memory data reference
{
ea_t dea = map_addr(x.addr);
insn.create_op_data(dea, x);
insn.add_dref(dea, x.offb, loading ? dr_R : dr_W);
}
break;
case o_near: // a code reference
{
ea_t ea = to_ea(insn.cs, x.addr);
int iscall = has_insn_feature(insn.itype, CF_CALL);
insn.add_cref(ea, x.offb, iscall ? fl_CN : fl_JN);
if ( flow && iscall )
{
if ( !func_does_return(ea) )
flow = false;
}
}
break;
case o_far: // a code reference
{
ea_t ea = x.addr + (x.specval << 16);
int iscall = has_insn_feature(insn.itype, CF_CALL);
insn.add_cref(ea, x.offb, iscall ? fl_CF : fl_JF);
if ( flow && iscall )
{
if ( !func_does_return(ea) )
flow = false;
}
}
break;
default:
BAD_LOGIC:
warning("%a: %s,%d: bad optype %d", insn.ea, insn.get_canon_mnem(ph), x.n, x.type);
break;
}
}
//----------------------------------------------------------------------
static bool add_stkpnt(const insn_t &insn, sval_t delta)
{
func_t *pfn = get_func(insn.ea);
if ( pfn == NULL )
return false;
return add_auto_stkpnt(pfn, insn.ea+insn.size, delta);
}
//----------------------------------------------------------------------
int xa_t::emu(const insn_t &_insn)
{
insn_t insn = _insn;
uint32 Feature = insn.get_canon_feature(ph);
flow = ((Feature & CF_STOP) == 0);
// you may emulate selected instructions with a greater care:
flags_t F = get_flags(insn.ea);
switch ( insn.itype )
{
case XA_mov:
case XA_movs:
// mov R7,#xxx
if ( insn.Op1.type == o_reg && insn.Op1.reg == rR7 )
{
if ( insn.Op2.type == o_imm && !is_defarg(F, 1) )
op_offset(insn.ea, 1, REF_OFF16, INTMEMBASE + insn.Op2.value, INTMEMBASE);
}
// mov DS,#xx
if ( check_insn(insn, 0, XA_mov, o_mem, DS, o_imm, BADADDR) )
{
ea_t v = EXTRAMBASE + (insn.Op2.value << 16);
create_ext_ram_seg(v);
}
// mov ES,#xx
if ( check_insn(insn, 0, XA_mov, o_mem, ES, o_void, BADADDR) ) // MOV ES,xx
{
insn_t saved = insn;
ea_t v = 0;
if ( insn.Op2.type == o_imm )
{
v = EXTRAMBASE + (insn.Op2.value << 16);
}
else if ( insn.Op2.type == o_reg && insn.Op1.dtype == dt_byte )
{
int reg = insn.Op2.reg;
if ( check_insn(insn, 1, XA_mov, o_reg, reg, o_imm, BADADDR) )
v = EXTRAMBASE + (insn.Op2.value << 16);
}
create_ext_ram_seg(v);
if ( insn.Op2.type == o_imm && check_insn(insn, 1, XA_mov, o_reg, BADADDR, o_imm, BADADDR) && insn.Op1.dtype == dt_word )
{
v += insn.Op2.value;
if ( !is_defarg(F, 1) )
op_offset(insn.ea, 1, REF_OFF16, v, v & 0xFFFF0000);
}
insn = saved;
F = get_flags(insn.ea);
}
// mov CS,#xx
if ( check_insn(insn, 0, XA_mov, o_mem, CS, o_imm, BADADDR) ) // MOV CS,#xx
{
insn_t saved = insn;
ea_t v = (insn.Op2.value << 16);
create_ext_ram_seg(v);
if ( check_insn(insn, 1, XA_mov, o_reg, BADADDR, o_imm, BADADDR) && insn.Op1.dtype == dt_word )
{
v += insn.Op2.value;
if ( !is_defarg(F, 1) )
op_offset(insn.ea, 1, REF_OFF16, v, v & 0xFFFF0000);
}
insn = saved;
F = get_flags(insn.ea);
}
// mov Rx,#xxxx
if ( check_insn(insn, 0, XA_mov, o_reg, BADADDR, o_imm, BADADDR) && insn.Op1.dtype == dt_word )
{
insn_t saved = insn;
if ( check_insn(insn, 1, XA_mov, o_mem, ES, o_reg, BADADDR) && insn.Op1.dtype == dt_byte )
{
int regL = insn.Op2.reg - rR0L;
if ( check_insn(insn, 1, XA_mov, o_reg, regL, o_imm, BADADDR) )
{
ea_t v = EXTRAMBASE + (insn.Op2.value << 16) + saved.Op2.value;
create_ext_ram_seg(v);
insn = saved;
F = get_flags(insn.ea);
if ( !is_defarg(F, 1) )
op_offset(saved.ea, 1, REF_OFF16, v, v & 0xFFFF0000L);
}
}
insn = saved;
F = get_flags(insn.ea);
}
// mov.b R1H, #0
if ( check_insn(insn, 0, XA_mov, o_reg, BADADDR, o_imm, 0) )
{
int reg = (insn.Op1.reg - rR1H) >> 1;
insn_t saved = insn;
if ( check_insn(insn, 1, XA_mov, o_reg, 2*reg+rR1L, o_mem, DS) ) // mov rx,DS
{
if ( check_insn(insn, 1, XA_mov, o_reg, reg+rR0, o_imm, BADADDR) )
{
ea_t v = EXTRAMBASE + insn.Op2.value;
F = get_flags(insn.ea);
if ( !is_defarg(F, 1) )
op_offset(insn.ea, 1, REF_OFF16, v, EXTRAMBASE);
}
}
insn = saved;
}
break;
case XA_push:
case XA_pop:
if ( insn.Op1.type == o_phrase
&& (insn.Op1.phrase == fRlistL || insn.Op1.phrase == fRlistH) )
{
func_t *pfn = get_func(insn.ea);
int bits = 0, firstreg = 0;
for ( int bit = 7; bit >= 0; bit-- )
{
if ( insn.Op1.indreg & (1<<bit) )
{
bits++;
firstreg = bit;
}
}
if ( bits && may_trace_sp() && pfn && !get_sp_delta(pfn, insn.ea) )
add_stkpnt(insn, insn.itype == XA_push ? -2*bits : 2*bits);
if ( insn.itype == XA_push
&& bits == 2
&& (insn.Op1.indreg & (1<<(firstreg+1))) ) // dword push
{
insn_t save = insn;
if ( check_insn(insn, 1, XA_mov, o_reg, firstreg+rR1, o_imm, BADADDR) )
{
ea_t v = EXTRAMBASE + (insn.Op2.value << 16);
if ( check_insn(insn, 1, XA_mov, o_reg, firstreg+rR0, o_imm, BADADDR) )
{
v += insn.Op2.value;
create_ext_ram_seg(v);
if ( !is_defarg(F, 1) )
op_offset(insn.ea, 1, REF_OFF16, v, v & 0xFFFF0000);
}
}
insn = save;
}
}
else if ( insn.Op1.type == o_mem )
{
func_t *pfn = get_func(insn.ea);
if ( may_trace_sp() && pfn && !get_sp_delta(pfn, insn.ea) )
add_stkpnt(insn, insn.itype == XA_push ? -2 : 2);
}
else
{
warning("emu: strange push/pop instruction operand at %a", insn.ea);
}
break;
case XA_add:
case XA_sub:
case XA_adds:
if ( !may_trace_sp() )
break;
if ( insn.Op1.type == o_reg && insn.Op1.reg == rR7 )
{
if ( insn.Op2.type == o_imm )
{
func_t *pfn = get_func(insn.ea);
sval_t offset = (insn.Op2.value < 0x8000L || insn.Op2.value > 0x80000000L) ? insn.Op2.value : insn.Op2.value-0x10000L;
if ( may_trace_sp() && pfn && !get_sp_delta(pfn, insn.ea) )
add_stkpnt(insn, insn.itype == XA_sub ? -offset : offset);
}
else
{
warning("emu: add/adds/sub with R7 and non-imm operand at %a", insn.ea);
}
}
break;
case XA_lea:
if ( !may_trace_sp() )
break;
if ( insn.Op1.type == o_reg && insn.Op1.reg == rR7 )
{
if ( insn.Op2.type == o_displ && insn.Op2.indreg == rR7 )
{
func_t *pfn = get_func(insn.ea);
if ( pfn && !get_sp_delta(pfn, insn.ea) )
add_stkpnt(insn, insn.Op2.addr);
}
else
{
warning("emu: lea with R7 and unknown 2nd operand at %a", insn.ea);
}
}
break;
}
if ( Feature & CF_USE1 )
handle_operand(insn, insn.Op1, true);
if ( Feature & CF_USE2 )
handle_operand(insn, insn.Op2, true);
if ( Feature & CF_USE3 )
handle_operand(insn, insn.Op3, true);
if ( Feature & CF_JUMP )
remember_problem(PR_JUMP, insn.ea);
if ( Feature & CF_CHG1 )
handle_operand(insn, insn.Op1, false);
if ( Feature & CF_CHG2 )
handle_operand(insn, insn.Op2, false);
if ( Feature & CF_CHG3 )
handle_operand(insn, insn.Op3, false);
// if the execution flow is not stopped here, then create
// a xref to the next instruction.
// Thus we plan to analyze the next instruction.
if ( flow )
add_cref(insn.ea, insn.ea+insn.size, fl_F);
return 1; // actually the return value is unimportant, but let's it be so
}
//----------------------------------------------------------------------
// Special functions for Hisoft XA C compiler
bool xa_t::xa_create_func(func_t *pfn)
{
ea_t prologue = pfn->start_ea;
bool prologue_at_end = false;
uval_t frsize = 0;
ushort regs = 0;
insn_t insn;
if ( decode_insn(&insn, prologue) > 0 )
{
if ( insn.itype == XA_jmp || insn.itype == XA_br )
{
prologue = to_ea(insn.cs, insn.Op1.addr);
prologue_at_end = true;
}
bool more;
do
{
more = false;
if ( decode_insn(&insn, prologue) == 0 )
break;
if ( insn.itype == XA_push
&& insn.Op1.type == o_phrase
&& (insn.Op1.phrase == fRlistL || insn.Op1.phrase == fRlistH) )
{
for ( int bit = 0; bit < 8; bit++ )
{
if ( insn.Op1.indreg & (1<<bit) )
regs += 2;
}
more = true;
}
if ( insn.itype == XA_lea
&& insn.Op1.type == o_reg
&& insn.Op1.reg == rR7
&& insn.Op2.type == o_displ
&& (insn.Op2.phrase == fRid8 || insn.Op2.phrase == fRid16)
&& insn.Op2.indreg == rR7 )
{
sval_t offset = insn.Op2.addr;
if ( offset >= 0 )
{
warning("%a: positive offset %a", insn.ea, uval_t(offset));
offset -= 0x10000L;
}
frsize -= offset;
more = true;
}
if ( insn.itype == XA_sub
&& insn.Op1.type == o_reg
&& insn.Op1.reg == rR7
&& insn.Op2.type == o_imm )
{
frsize += insn.Op2.value;
more = true;
}
if ( insn.itype == XA_adds
&& insn.Op1.type == o_reg
&& insn.Op1.reg == rR7
&& insn.Op2.type == o_imm )
{
frsize -= insn.Op2.value;
more = true;
}
prologue += insn.size;
} while ( more );
}
add_frame(pfn, frsize, regs, 0);
if ( prologue_at_end )
{
decode_insn(&insn, pfn->start_ea);
add_stkpnt(insn, -frsize-regs);
}
return 1;
}
//----------------------------------------------------------------------
bool xa_t::xa_is_switch(switch_info_t *si, const insn_t &_insn)
{
bool got_value = false;
int prev;
insn_t insn = _insn;
if ( insn.Op1.type == o_phrase && insn.Op1.phrase == fRi )
{
insn_t saved = insn;
int jumpreg, datareg;
jumpreg = insn.Op1.indreg;
if ( check_insn(insn, 1, XA_movc, o_reg, jumpreg, o_phrase, fRip)
&& insn.Op2.indreg == jumpreg )
{
if ( check_insn(insn, 1, XA_add, o_reg, jumpreg, o_imm, BADADDR) )
{
si->jumps = (insn.ea & 0xFFFF0000) + insn.Op2.value;
op_offset(insn.ea, 1, REF_OFF16, si->jumps, insn.ea & 0xFFFF0000);
if ( check_insn(insn, 1, XA_asl, o_reg, jumpreg, o_imm, 1) )
{
if ( check_insn(insn, 1, XA_mov, o_reg, rR0H + 2*(jumpreg-rR0), o_imm, 0) )
{
datareg = insn.Op1.reg - 1;
prev = 0;
if ( check_insn(insn, 1, XA_nop, o_void, BADADDR, o_void, BADADDR) )
prev = 1;
if ( check_insn(insn, prev, XA_bg, o_void, BADADDR, o_void, BADADDR)
|| (check_insn(insn, 0, XA_jmp, o_void, BADADDR, o_void, BADADDR)
&& check_insn(insn, 1, XA_bl, o_void, BADADDR, o_void, BADADDR)) )
{
if ( check_insn(insn, 1, XA_cmp, o_reg, datareg, o_imm, BADADDR) )
{
si->ncases = ushort(insn.Op2.value+1);
if ( check_insn(insn, 1, XA_bcs, o_void, BADADDR, o_void, BADADDR) )
{
si->defjump = insn.Op1.addr;
if ( check_insn(insn, 1, XA_sub, o_reg, datareg, o_imm, BADADDR)
|| check_insn(insn, 0, XA_adds, o_reg, datareg, o_imm, BADADDR) )
{
if ( insn.itype == XA_sub )
{
si->lowcase = insn.Op2.value;
}
else
{
si->lowcase = -insn.Op2.value;
}
got_value = true;
si->startea = insn.ea;
}
else
{
warning("%a: no sub/add, may start with 0", insn.ea);
}
}
else
{
si->lowcase = 0;
got_value = true;
si->startea = insn.ea + insn.size;
}
}
else
{
warning("%a: no cmp", insn.ea);
}
}
else
{
warning("%a: no bg, may be signed", insn.ea);
}
}
else
{
prev = 0;
if ( check_insn(insn, 0, XA_nop, o_void, BADADDR, o_void, BADADDR) )
prev = 1;
if ( check_insn(insn, prev, XA_bg, o_void, BADADDR, o_void, BADADDR)
|| (check_insn(insn, 0, XA_jmp, o_void, BADADDR, o_void, BADADDR)
&& check_insn(insn, 1, XA_bl, o_void, BADADDR, o_void, BADADDR)) )
{
if ( check_insn(insn, 1, XA_cmp, o_reg, BADADDR, o_imm, BADADDR) )
{
datareg = insn.Op1.reg;
si->ncases = ushort(insn.Op2.value+1);
if ( check_insn(insn, 1, XA_bcs, o_void, BADADDR, o_void, BADADDR) )
{
si->defjump = insn.Op1.addr;
if ( check_insn(insn, 1, XA_sub, o_reg, datareg, o_imm, BADADDR)
|| check_insn(insn, 0, XA_adds, o_reg, datareg, o_imm, BADADDR) )
{
if ( insn.itype == XA_sub )
si->lowcase = insn.Op2.value;
else
si->lowcase = -insn.Op2.value;
got_value = true;
si->startea = insn.ea;
}
else
{
warning("no sub/add, may start with 0");
}
}
else
{
si->lowcase = 0;
got_value = true;
si->startea = insn.ea + insn.size;
}
}
else
{
warning("%a: no cmp", insn.ea);
}
}
else
{
warning("%a: no bg, may be signed", insn.ea);
}
}
}
}
}
if ( got_value )
{
if ( get_byte(si->jumps + 2*si->ncases) == 0xfe )
insn.add_cref(si->jumps + 2*si->ncases, int(saved.ea), fl_F);
}
}
return got_value;
}
//----------------------------------------------------------------------
//lint -esym(714,xa_frame_retsize)
//lint -esym(818,pfn)
int xa_t::xa_frame_retsize(const func_t *pfn)
{
return pfn->is_far() ? 2 : 4;
}
//----------------------------------------------------------------------
void xa_t::xa_stkvar_def(outctx_t &ctx, const member_t *mptr, sval_t v)
{
char sign = '+';
if ( v < 0 )
{
v = -v; sign = '-';
}
qstring name = get_member_name(mptr->id);
char vstr[MAX_NUMBUF];
btoa(vstr, sizeof(vstr), v);
ctx.out_printf(COLSTR("%-*s", SCOLOR_LOCNAME)
" "
COLSTR("set %c", SCOLOR_SYMBOL)
COLSTR("%s",SCOLOR_DNUM),
inf_get_indent()-1, name.c_str(), sign, vstr);
}
//----------------------------------------------------------------------
int xa_t::xa_align_insn(ea_t ea)
{
if ( get_byte(ea) == 0 )
return 1;
return 0;
}