update to ida 7.6, add builds
This commit is contained in:
487
idasdk76/module/xa/out.cpp
Normal file
487
idasdk76/module/xa/out.cpp
Normal file
@@ -0,0 +1,487 @@
|
||||
/*
|
||||
This module has been created by Petr Novak
|
||||
*/
|
||||
|
||||
#include "xa.hpp"
|
||||
#include <fpro.h>
|
||||
#include <diskio.hpp>
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_xa_t : public outctx_t
|
||||
{
|
||||
out_xa_t(void) = delete; // not used
|
||||
public:
|
||||
void OutReg(int rgnum)
|
||||
{
|
||||
out_register(ph.reg_names[rgnum]);
|
||||
}
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
void out_proc_mnem(void);
|
||||
|
||||
void do_out_equ(const char *name, uchar off);
|
||||
int out_equ(void);
|
||||
};
|
||||
CASSERT(sizeof(out_xa_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS(out_xa_t)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
AS_PRINTF(1, 0) static void vlog(const char *format, va_list va)
|
||||
{
|
||||
static FILE *fp = NULL;
|
||||
if ( fp == NULL )
|
||||
fp = fopenWT("debug_log");
|
||||
qvfprintf(fp, format, va);
|
||||
qflush(fp);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
AS_PRINTF(1, 2) inline void log(const char *format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
vlog(format, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
#define AT COLSTR("@", SCOLOR_SYMBOL)
|
||||
#define PLUS COLSTR("+", SCOLOR_SYMBOL)
|
||||
|
||||
static const char *const phrases[] =
|
||||
{
|
||||
AT COLSTR("A", SCOLOR_REG) PLUS COLSTR("DPTR", SCOLOR_REG),
|
||||
AT COLSTR("A", SCOLOR_REG) PLUS COLSTR("PC", SCOLOR_REG)
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// generate the text representation of an operand
|
||||
|
||||
bool out_xa_t::out_operand(const op_t &x)
|
||||
{
|
||||
uval_t v = 0;
|
||||
int dir, bit;
|
||||
qstring qbuf;
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_reg:
|
||||
OutReg(x.reg);
|
||||
break;
|
||||
|
||||
case o_phrase:
|
||||
switch ( x.phrase )
|
||||
{
|
||||
case fAdptr:
|
||||
case fApc:
|
||||
out_colored_register_line(phrases[x.phrase]);
|
||||
break;
|
||||
case fRi:
|
||||
out_symbol('[');
|
||||
OutReg(x.indreg);
|
||||
out_symbol(']');
|
||||
break;
|
||||
case fRip:
|
||||
out_symbol('[');
|
||||
OutReg(x.indreg);
|
||||
out_symbol('+');
|
||||
out_symbol(']');
|
||||
break;
|
||||
case fRii:
|
||||
out_symbol('[');
|
||||
out_symbol('[');
|
||||
OutReg(x.indreg);
|
||||
out_symbol(']');
|
||||
out_symbol(']');
|
||||
break;
|
||||
case fRipi:
|
||||
out_symbol('[');
|
||||
out_symbol('[');
|
||||
OutReg(x.indreg);
|
||||
out_symbol('+');
|
||||
out_symbol(']');
|
||||
out_symbol(']');
|
||||
break;
|
||||
case fRlistL:
|
||||
case fRlistH:
|
||||
v = x.indreg;
|
||||
dir = (x.dtype == dt_byte) ? rR0L : rR0;
|
||||
if ( x.phrase == fRlistH )
|
||||
dir += 8;
|
||||
for ( bit = 0; bit < 8; bit++,dir++,v >>= 1 )
|
||||
{
|
||||
if ( v&1 )
|
||||
{
|
||||
OutReg(dir);
|
||||
if ( v & 0xfe )
|
||||
out_symbol(',');
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case o_displ:
|
||||
if ( insn.itype != XA_lea )
|
||||
out_symbol('[');
|
||||
OutReg(x.indreg);
|
||||
if ( x.indreg == rR7 || x.phrase != fRi )
|
||||
out_value(x, OOF_ADDR | OOFS_NEEDSIGN | OOF_SIGNED | OOFW_16);
|
||||
if ( insn.itype != XA_lea )
|
||||
out_symbol(']');
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
out_symbol('#');
|
||||
out_value(x, OOFS_IFSIGN | /* OOF_SIGNED | */ OOFW_IMM);
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
case o_near:
|
||||
case o_far:
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_mem:
|
||||
v = map_addr(x.addr);
|
||||
break;
|
||||
case o_near:
|
||||
v = to_ea(insn.cs, x.addr);
|
||||
break;
|
||||
case o_far:
|
||||
v = x.addr + (x.specval<<16);
|
||||
break;
|
||||
}
|
||||
if ( get_name_expr(&qbuf, insn.ea+x.offb, x.n, v, x.addr & 0xFFFF) <= 0 )
|
||||
{
|
||||
if ( x.type == o_far )
|
||||
{
|
||||
// print the segment part
|
||||
out_long(x.specval, 16);
|
||||
out_symbol(':');
|
||||
}
|
||||
// now print the offset
|
||||
out_value(x, OOF_ADDR | OOF_NUMBER | OOFS_NOSIGN | OOFW_32);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
break;
|
||||
}
|
||||
|
||||
// we want to output SFR register names always in COLOR_REG,
|
||||
// so remove the color tags and output it manually:
|
||||
|
||||
if ( x.type == o_mem && x.addr >= 0x400 )
|
||||
{
|
||||
tag_remove(&qbuf);
|
||||
out_register(qbuf.begin());
|
||||
break;
|
||||
}
|
||||
out_line(qbuf.begin());
|
||||
break;
|
||||
|
||||
case o_void:
|
||||
return 0;
|
||||
|
||||
case o_bitnot:
|
||||
out_symbol('/');
|
||||
// fallthrough
|
||||
case o_bit:
|
||||
dir = int(x.addr >> 3);
|
||||
bit = x.addr & 7;
|
||||
if ( dir & 0x40 ) // SFR
|
||||
{
|
||||
dir += 0x3c0;
|
||||
}
|
||||
else if ( (dir & 0x20) == 0 ) // Register file
|
||||
{
|
||||
dir = int(x.addr >> 4);
|
||||
bit = x.addr & 15;
|
||||
OutReg(rR0+dir);
|
||||
out_symbol(ash.uflag & UAS_NOBIT ? '_' : '.');
|
||||
if ( bit > 9 )
|
||||
{
|
||||
out_symbol('1');
|
||||
bit -= 10;
|
||||
}
|
||||
out_symbol(char('0'+bit));
|
||||
break;
|
||||
}
|
||||
if ( ash.uflag & UAS_PBIT )
|
||||
{
|
||||
xa_t &pm = *static_cast<xa_t *>(procmod);
|
||||
const predefined_t *predef = pm.GetPredefinedBits(dir, bit);
|
||||
if ( predef != NULL )
|
||||
{
|
||||
out_line(predef->name, COLOR_REG);
|
||||
break;
|
||||
}
|
||||
}
|
||||
{
|
||||
v = map_addr(dir);
|
||||
bool ok = get_name_expr(&qbuf, insn.ea+x.offb, x.n, v, dir) > 0;
|
||||
if ( ok && strchr(qbuf.begin(), '+') == NULL )
|
||||
{
|
||||
|
||||
// we want to output the bit names always in COLOR_REG,
|
||||
// so remove the color tags and output it manually:
|
||||
|
||||
if ( dir < 0x80 )
|
||||
{
|
||||
out_line(qbuf.begin());
|
||||
}
|
||||
else
|
||||
{
|
||||
tag_remove(&qbuf);
|
||||
out_register(qbuf.begin());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
out_long(dir, 16);
|
||||
}
|
||||
out_symbol(ash.uflag & UAS_NOBIT ? '_' : '.');
|
||||
out_symbol(char('0'+bit));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("out: %a: bad optype %d", insn.ea, x.type);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_xa_t::out_proc_mnem(void)
|
||||
{
|
||||
if ( insn.Op1.type != o_void )
|
||||
{
|
||||
switch ( insn.Op1.dtype )
|
||||
{
|
||||
case dt_byte:
|
||||
out_mnem(8,".b");
|
||||
break;
|
||||
case dt_word:
|
||||
out_mnem(8,".w");
|
||||
break;
|
||||
case dt_dword:
|
||||
out_mnem(8,".d");
|
||||
break;
|
||||
default:
|
||||
out_mnem();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
out_mnem(); // output instruction mnemonics
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// generate a text representation of an instruction
|
||||
// the information about the instruction is in the insn structure
|
||||
|
||||
void out_xa_t::out_insn(void)
|
||||
{
|
||||
out_mnemonic();
|
||||
out_one_operand(0); // output the first operand
|
||||
|
||||
if ( insn.Op2.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(1); // output the second operand
|
||||
}
|
||||
|
||||
if ( insn.Op3.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(2); // output the third operand
|
||||
}
|
||||
|
||||
|
||||
// output a character representation of the immediate values
|
||||
// embedded in the instruction as comments
|
||||
out_immchar_cmts();
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// generate start of the disassembly
|
||||
|
||||
void xa_t::xa_header(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_header(GH_PRINT_ALL_BUT_BYTESEX);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// generate start of a segment
|
||||
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
//lint -esym(818, Sarea) could be made const
|
||||
void xa_t::xa_segstart(outctx_t &ctx, segment_t *Sarea)
|
||||
{
|
||||
qstring sname;
|
||||
get_visible_segm_name(&sname, Sarea);
|
||||
|
||||
if ( ash.uflag & UAS_SECT )
|
||||
{
|
||||
if ( Sarea->type == SEG_IMEM )
|
||||
ctx.flush_buf(".RSECT", DEFAULT_INDENT);
|
||||
else
|
||||
ctx.gen_printf(0, COLSTR("%s: .section", SCOLOR_ASMDIR), sname.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ash.uflag & UAS_NOSEG )
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s.segment %s", SCOLOR_AUTOCMT),
|
||||
ash.cmnt, sname.c_str());
|
||||
else
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR("segment %s",SCOLOR_ASMDIR), sname.c_str());
|
||||
if ( ash.uflag & UAS_SELSG )
|
||||
ctx.flush_buf(sname.c_str(), DEFAULT_INDENT);
|
||||
if ( ash.uflag & UAS_CDSEG )
|
||||
ctx.flush_buf(Sarea->type == SEG_IMEM
|
||||
? COLSTR("DSEG", SCOLOR_ASMDIR)
|
||||
: COLSTR("CSEG", SCOLOR_ASMDIR),
|
||||
DEFAULT_INDENT);
|
||||
// XSEG - eXternal memory
|
||||
}
|
||||
if ( (inf_get_outflags() & OFLG_GEN_ORG) != 0 )
|
||||
{
|
||||
adiff_t org = ctx.insn_ea - get_segm_base(Sarea);
|
||||
if ( org != 0 )
|
||||
{
|
||||
char buf[MAX_NUMBUF];
|
||||
btoa(buf, sizeof(buf), org);
|
||||
ctx.gen_cmt_line("%s %s", ash.origin, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// generate end of the disassembly
|
||||
|
||||
void xa_t::xa_footer(outctx_t &ctx)
|
||||
{
|
||||
if ( ash.end != NULL )
|
||||
{
|
||||
ctx.gen_empty_line();
|
||||
ctx.out_line(ash.end, COLOR_ASMDIR);
|
||||
qstring name;
|
||||
if ( get_colored_name(&name, inf_get_start_ea()) > 0 )
|
||||
{
|
||||
ctx.out_char(' ');
|
||||
if ( ash.uflag & UAS_NOENS )
|
||||
ctx.out_line(ash.cmnt);
|
||||
ctx.out_line(name.begin());
|
||||
}
|
||||
ctx.flush_outbuf(DEFAULT_INDENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.gen_cmt_line("end of file");
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// output one "equ" directive
|
||||
|
||||
void out_xa_t::do_out_equ(const char *name, uchar off)
|
||||
{
|
||||
if ( (ash.uflag & UAS_PSAM) != 0 )
|
||||
{
|
||||
out_line(ash.a_equ, COLOR_KEYWORD);
|
||||
out_char(' ');
|
||||
out_line(name);
|
||||
out_symbol(',');
|
||||
}
|
||||
else
|
||||
{
|
||||
out_line(name);
|
||||
if ( ash.uflag & UAS_EQCLN )
|
||||
out_symbol(':');
|
||||
out_char(' ');
|
||||
out_line(ash.a_equ, COLOR_KEYWORD);
|
||||
out_char(' ');
|
||||
}
|
||||
out_long(off, 16);
|
||||
clr_gen_label();
|
||||
out_tagoff(COLOR_SYMBOL);
|
||||
flush_outbuf(0);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// output "equ" directive(s) if necessary
|
||||
int out_xa_t::out_equ(void)
|
||||
{
|
||||
ea_t ea = insn.ea;
|
||||
segment_t *s = getseg(ea);
|
||||
if ( s != NULL && s->type == SEG_IMEM && ash.a_equ != NULL )
|
||||
{
|
||||
qstring name;
|
||||
if ( get_visible_name(&name, ea) > 0
|
||||
&& ((ash.uflag & UAS_PBYTNODEF) == 0 || !xa_t::IsPredefined(name.begin())) )
|
||||
{
|
||||
get_colored_name(&name, ea);
|
||||
uchar off = uchar(ea - get_segm_base(s));
|
||||
do_out_equ(name.begin(), off);
|
||||
if ( (ash.uflag & UAS_AUBIT) == 0 && (off & 0xF8) == off )
|
||||
{
|
||||
qstring tmp;
|
||||
out_tagon(COLOR_SYMBOL);
|
||||
out_char(ash.uflag & UAS_NOBIT ? '_' : '.');
|
||||
tmp.swap(outbuf);
|
||||
for ( int i=0; i < 8; i++,off++ )
|
||||
{
|
||||
qstring full = tmp;
|
||||
full.append('0' + i);
|
||||
do_out_equ(full.begin(), off);
|
||||
}
|
||||
gen_empty_line();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
clr_gen_label();
|
||||
flush_buf("");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if ( (ash.uflag & UAS_NODS) != 0 )
|
||||
{
|
||||
if ( !is_loaded(ea) && s->type == SEG_CODE )
|
||||
{
|
||||
adiff_t org = ea - get_segm_base(s) + get_item_size(ea);
|
||||
char buf[MAX_NUMBUF];
|
||||
btoa(buf, sizeof(buf), org);
|
||||
gen_printf(DEFAULT_INDENT, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// generate a data representation
|
||||
// usually all the job is handled by the kernel's standard procedure,
|
||||
// out_data()
|
||||
// But 8051 has its own quirks (namely, "equ" directives) and out_data()
|
||||
// can't handle them. So we output "equ" ourselves and pass everything
|
||||
// else to out_data()
|
||||
// Again, let's repeat: usually the data items are output by the kernel
|
||||
// function out_data(). You have to override it only if the processor
|
||||
// has special features and the data itesm should be displayed in a
|
||||
// special way.
|
||||
|
||||
void xa_t::xa_data(outctx_t &ctx, bool analyze_only)
|
||||
{
|
||||
// the kernel's standard routine which outputs the data knows nothing
|
||||
// about "equ" directives. So we do the following:
|
||||
// - try to output an "equ" directive
|
||||
// - if we succeed, then ok
|
||||
// - otherwise let the standard data output routine, out_data()
|
||||
// do all the job
|
||||
|
||||
out_xa_t *p = (out_xa_t *)&ctx;
|
||||
if ( !p->out_equ() )
|
||||
ctx.out_data(analyze_only);
|
||||
}
|
||||
Reference in New Issue
Block a user