387 lines
9.3 KiB
C++
387 lines
9.3 KiB
C++
/*
|
|
* Interactive disassembler (IDA)
|
|
* Copyright (c) 1990-98 by Ilfak Guilfanov.
|
|
* E-mail: ig@datarescue.com
|
|
* PDP11 module.
|
|
* Copyright (c) 1995-2006 by Iouri Kharon.
|
|
* E-mail: yjh@styx.cabel.net
|
|
*
|
|
* ALL RIGHTS RESERVED.
|
|
*
|
|
*/
|
|
|
|
#include "pdp.hpp"
|
|
|
|
//----------------------------------------------------------------------
|
|
class out_pdp_t : public outctx_t
|
|
{
|
|
out_pdp_t(void) = delete; // not used
|
|
pdp11_t &pm() { return *static_cast<pdp11_t *>(procmod); }
|
|
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);
|
|
};
|
|
CASSERT(sizeof(out_pdp_t) == sizeof(outctx_t));
|
|
|
|
DECLARE_OUT_FUNCS(out_pdp_t)
|
|
|
|
//----------------------------------------------------------------------
|
|
bool out_pdp_t::out_operand(const op_t &x)
|
|
{
|
|
ea_t segadr;
|
|
switch ( x.type )
|
|
{
|
|
case o_void:
|
|
return 0;
|
|
case o_reg:
|
|
OutReg(x.reg);
|
|
break;
|
|
case o_fpreg:
|
|
OutReg(x.reg + 8);
|
|
break;
|
|
case o_imm: // 27
|
|
if ( x.ill_imm )
|
|
{
|
|
out_symbol('(');
|
|
OutReg(rPC);
|
|
out_symbol(')');
|
|
out_symbol('+');
|
|
}
|
|
else
|
|
{
|
|
out_symbol('#');
|
|
if ( x.dtype == dt_float || x.dtype == dt_double )
|
|
{
|
|
char str[MAXSTR];
|
|
if ( print_fpval(str, sizeof(str), &x.value, 2) )
|
|
{
|
|
char *p = str;
|
|
while ( *p == ' ' )
|
|
p++;
|
|
out_symbol('^');
|
|
out_symbol('F');
|
|
out_line(p, COLOR_NUMBER);
|
|
}
|
|
else
|
|
{
|
|
out_long(x.value, 8);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
out_value(x, OOF_SIGNED | OOFW_IMM);
|
|
}
|
|
}
|
|
break;
|
|
case o_mem: // 37/67/77
|
|
case o_near: // jcc/ [jmp/call 37/67]
|
|
case o_far:
|
|
if ( x.phrase != 0 )
|
|
{
|
|
if ( x.phrase == 077 || x.phrase == 037 )
|
|
out_symbol('@');
|
|
if ( x.phrase == 037 )
|
|
out_symbol('#');
|
|
if ( x.addr16 < pm().ml.asect_top && !is_off(F, x.n) )
|
|
{
|
|
out_value(x, OOF_ADDR | OOF_NUMBER | OOFS_NOSIGN | OOFW_16);
|
|
break;
|
|
}
|
|
}
|
|
segadr = x.type == o_far
|
|
? to_ea(x.segval, x.addr16)
|
|
: map_code_ea(insn, x.addr16, x.n);
|
|
if ( !out_name_expr(x, segadr, x.addr16) )
|
|
{
|
|
if ( x.type == o_far || x.addr16 < 0160000 )
|
|
remember_problem(PR_NONAME, insn.ea);
|
|
out_value(x, OOF_ADDR | OOF_NUMBER | OOFS_NOSIGN | OOFW_16);
|
|
}
|
|
break;
|
|
case o_number: // EMT/TRAP/MARK/SPL
|
|
out_value(x, OOF_NUMBER | OOFS_NOSIGN | OOFW_8);
|
|
break;
|
|
case o_displ: // 6x/7x (!67/!77)
|
|
if ( x.phrase >= 070 )
|
|
out_symbol('@');
|
|
out_value(x, OOF_ADDR | OOF_SIGNED | OOFW_16);
|
|
out_symbol('(');
|
|
goto endregout;
|
|
case o_phrase: // 1x/2x/3x/4x/5x (!27/!37)
|
|
switch ( x.phrase >> 3 )
|
|
{
|
|
case 1:
|
|
out_symbol('@');
|
|
OutReg(x.phrase & 7);
|
|
break;
|
|
case 3:
|
|
out_symbol('@');
|
|
// fallthrough
|
|
case 2:
|
|
out_symbol('(');
|
|
OutReg(x.phrase & 7);
|
|
out_symbol(')');
|
|
out_symbol('+');
|
|
break;
|
|
case 5:
|
|
out_symbol('@');
|
|
// fallthrough
|
|
case 4:
|
|
out_symbol('-');
|
|
out_symbol('(');
|
|
endregout:
|
|
OutReg(x.phrase & 7);
|
|
out_symbol(')');
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
warning("out: %" FMT_EA "o: bad optype %d", insn.ip, x.type);
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void out_pdp_t::out_proc_mnem(void)
|
|
{
|
|
static const char *const postfix[] = { "", "b" };
|
|
out_mnem(8, postfix[insn.bytecmd]);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void out_pdp_t::out_insn(void)
|
|
{
|
|
out_mnemonic();
|
|
if ( insn.itype == pdp_compcc )
|
|
{
|
|
uint i = 0, code, first = 0;
|
|
static const uint tabcc[8] =
|
|
{
|
|
pdp_clc, pdp_clv, pdp_clz, pdp_cln,
|
|
pdp_sec, pdp_sev, pdp_sez, pdp_sen
|
|
};
|
|
code = insn.Op1.phrase;
|
|
out_symbol('<');
|
|
if ( code >= 020 )
|
|
{
|
|
if ( (code ^= 020) == 0 )
|
|
out_line(COLSTR("nop!^O20", SCOLOR_INSN));
|
|
i = 4;
|
|
}
|
|
for ( ; code; i++, code >>= 1 )
|
|
{
|
|
if ( code & 1 )
|
|
{
|
|
if ( first++ )
|
|
out_symbol('!');
|
|
out_line(ph.instruc[tabcc[i]].name, COLOR_INSN);
|
|
}
|
|
}
|
|
out_symbol('>');
|
|
}
|
|
|
|
out_one_operand(0);
|
|
|
|
if ( insn.Op2.type != o_void )
|
|
{
|
|
out_symbol(',');
|
|
out_char(' ');
|
|
out_one_operand(1);
|
|
}
|
|
|
|
out_immchar_cmts();
|
|
flush_outbuf();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
void idaapi pdp_header(outctx_t &ctx)
|
|
{
|
|
ctx.gen_header(GH_PRINT_ALL_BUT_BYTESEX);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//lint -esym(1764, ctx) could be made const
|
|
//lint -esym(818, seg) could be made const
|
|
void pdp11_t::pdp_segstart(outctx_t &ctx, segment_t *seg)
|
|
{
|
|
if ( seg->type == SEG_IMEM )
|
|
{
|
|
ctx.flush_buf(COLSTR(".ASECT", SCOLOR_ASMDIR), DEFAULT_INDENT);
|
|
}
|
|
else
|
|
{
|
|
qstring sname;
|
|
get_visible_segm_name(&sname, seg);
|
|
ctx.out_printf(COLSTR(".PSECT %s", SCOLOR_ASMDIR), sname.c_str());
|
|
if ( seg->ovrname != 0 )
|
|
{
|
|
char bseg[MAX_NUMBUF];
|
|
char breg[MAX_NUMBUF];
|
|
btoa(bseg, sizeof(bseg), seg->ovrname & 0xFFFF, 10);
|
|
btoa(breg, sizeof(breg), seg->ovrname >> 16, 10);
|
|
ctx.out_printf(
|
|
COLSTR(" %s Overlay Segment %s, Region %s", SCOLOR_AUTOCMT),
|
|
ash.cmnt, bseg, breg);
|
|
}
|
|
ctx.flush_outbuf(0);
|
|
}
|
|
|
|
if ( (inf_get_outflags() & OFLG_GEN_ORG) != 0 )
|
|
{
|
|
size_t org = size_t(ctx.insn_ea-get_segm_base(seg));
|
|
if ( org != 0 && org != ml.asect_top && seg->comorg() )
|
|
{
|
|
ctx.out_tagon(COLOR_ASMDIR);
|
|
ctx.out_line(ash.origin);
|
|
ctx.out_line(ash.a_equ);
|
|
if ( seg->type != SEG_IMEM )
|
|
{
|
|
ctx.out_line(ash.origin);
|
|
ctx.out_char('+');
|
|
}
|
|
ctx.out_btoa(org);
|
|
ctx.out_tagoff(COLOR_ASMDIR);
|
|
ctx.flush_outbuf(DEFAULT_INDENT);
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
void pdp11_t::pdp_footer(outctx_t &ctx) const
|
|
{
|
|
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 )
|
|
{
|
|
size_t i = strlen(ash.end);
|
|
do
|
|
ctx.out_char(' ');
|
|
while ( ++i < 8 );
|
|
ctx.out_line(name.begin());
|
|
}
|
|
ctx.flush_outbuf(DEFAULT_INDENT);
|
|
}
|
|
else
|
|
{
|
|
ctx.gen_cmt_line("end of file");
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
bool pdp11_t::out_equ(outctx_t &ctx, ea_t ea) const
|
|
{
|
|
segment_t *s = getseg(ea);
|
|
char buf[MAXSTR];
|
|
if ( s != NULL )
|
|
{
|
|
if ( s->type != SEG_IMEM && !is_loaded(ea) )
|
|
{
|
|
char num[MAX_NUMBUF];
|
|
btoa(num, sizeof(num), get_item_size(ea));
|
|
nowarn_qsnprintf(buf, sizeof(buf), ash.a_bss, num);
|
|
ctx.flush_buf(buf);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
void pdp11_t::pdp_data(outctx_t &ctx, bool analyze_only) const
|
|
{
|
|
char buf[MAXSTR];
|
|
ushort v[5];
|
|
ea_t endea;
|
|
ushort i, j;
|
|
|
|
ea_t ea = ctx.insn_ea;
|
|
if ( out_equ(ctx, ea) )
|
|
return;
|
|
|
|
i = 0;
|
|
flags_t F = ctx.F;
|
|
if ( !is_unknown(F) )
|
|
{
|
|
if ( is_word(F) && get_radix(F,0) == 16 )
|
|
i = 2;
|
|
else if ( is_dword(F) )
|
|
i = 4;
|
|
else if ( is_qword(F) )
|
|
i = 8;
|
|
else if ( is_tbyte(F) )
|
|
i = 10;
|
|
if ( i == 0 )
|
|
{
|
|
ctx.out_data(analyze_only);
|
|
return;
|
|
}
|
|
|
|
int radix = get_radix(F, 0);
|
|
endea = get_item_end(ea);
|
|
for ( ; ea < endea; ea += i )
|
|
{
|
|
memset(v, 0, sizeof(v));
|
|
if ( get_bytes(v, i, ea) != i || r50_to_asc(buf, v, i/2) != 0 )
|
|
{
|
|
ctx.out_keyword(".word ");
|
|
for ( j = 0; j < i/2; j++ )
|
|
{
|
|
if ( j )
|
|
ctx.out_symbol(',');
|
|
btoa(buf, sizeof(buf), v[j], radix);
|
|
ctx.out_line(buf, COLOR_NUMBER);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ctx.out_keyword(".rad50 ");
|
|
ctx.out_tagon(COLOR_CHAR);
|
|
ctx.out_char('/');
|
|
ctx.out_line(buf);
|
|
ctx.out_char('/');
|
|
ctx.out_tagoff(COLOR_CHAR);
|
|
}
|
|
if ( ctx.flush_outbuf() )
|
|
return; // too many lines
|
|
}
|
|
return;
|
|
}
|
|
// unknown
|
|
if ( !is_loaded(ea) )
|
|
{
|
|
ctx.flush_buf(COLSTR(".blkb", SCOLOR_KEYWORD));
|
|
}
|
|
else
|
|
{
|
|
uchar c = get_byte(ea);
|
|
|
|
char cbuf[MAX_NUMBUF];
|
|
btoa(cbuf, sizeof(cbuf), c);
|
|
ctx.out_printf(COLSTR(".byte ", SCOLOR_KEYWORD)
|
|
COLSTR("%4s ", SCOLOR_DNUM)
|
|
COLSTR("%s %c", SCOLOR_AUTOCMT),
|
|
cbuf,
|
|
ash.cmnt,
|
|
c >= ' ' ? c : ' ');
|
|
if ( !(ea & 1) && (i = get_word(ea)) != 0 )
|
|
{
|
|
ctx.out_tagon(COLOR_AUTOCMT);
|
|
ctx.out_char(' ');
|
|
b2a32(buf, sizeof(buf), i, 2, 0);
|
|
ctx.out_line(buf);
|
|
ctx.out_char(' ');
|
|
ushort w = i;
|
|
r50_to_asc(buf, &w, 1);
|
|
ctx.out_line(buf);
|
|
ctx.out_tagoff(COLOR_AUTOCMT);
|
|
}
|
|
ctx.flush_outbuf();
|
|
} // undefined
|
|
}
|