/* * 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(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 }