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

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
}