/* This module has been created by Petr Novak */ #include "xa.hpp" #include #include //---------------------------------------------------------------------- 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(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); }