/* * Interactive disassembler (IDA). * Copyright (c) 1990-99 by Ilfak Guilfanov. * ALL RIGHTS RESERVED. * E-mail: ig@datarescue.com * * */ #include "h8.hpp" #include #include //---------------------------------------------------------------------- class out_h8_t : public outctx_t { out_h8_t(void) = delete; // not used public: void outreg(int r) { out_register(ph.reg_names[r]); } void out_bad_address(ea_t addr); void out_sizer(char szfl); void attach_name_comment(const op_t &x, ea_t v) const; // modifies idb! bool out_operand(const op_t &x); void out_insn(void); void out_proc_mnem(void); }; CASSERT(sizeof(out_h8_t) == sizeof(outctx_t)); DECLARE_OUT_FUNCS(out_h8_t) //---------------------------------------------------------------------- int h8_t::get_displ_outf(const op_t &x, flags_t F) { return OOF_ADDR|OOFS_IFSIGN|OOF_SIGNED | ((is_stkvar(F, x.n) || (x.szfl & disp_32) || advanced()) ? OOFW_32 : OOFW_16); } //---------------------------------------------------------------------- void out_h8_t::out_bad_address(ea_t addr) { h8_t &pm = *static_cast(procmod); const char *name = pm.find_sym(addr); if ( name != NULL && name[0] != '\0' ) { out_line(name, COLOR_IMPNAME); } else { out_tagon(COLOR_ERROR); out_btoa(addr, 16); out_tagoff(COLOR_ERROR); remember_problem(PR_NONAME, insn.ea); } } //---------------------------------------------------------------------- ea_t h8_t::trim_ea_branch(ea_t ea) const { switch ( ptype & MODE_MASK ) { case MODE_MID: case MODE_ADV: return ea & 0x00FFFFFF; case MODE_MAX: return ea; } return ea & 0x0000FFFF; } //---------------------------------------------------------------------- ea_t calc_mem(const insn_t &insn, ea_t ea) { return to_ea(insn.cs, ea); } //---------------------------------------------------------------------- ea_t calc_mem_sbr_based(const insn_t &insn, ea_t ea) { sel_t base = get_sreg(insn.ea, SBR); return (base & 0xFFFFFF00) | (ea & 0x000000FF); } //---------------------------------------------------------------------- void out_h8_t::out_sizer(char szfl) { h8_t &pm = *static_cast(procmod); if ( pm.show_sizer == -1 ) pm.show_sizer = !qgetenv("H8_NOSIZER"); if ( !pm.show_sizer ) return; if ( szfl & disp_2 ) return; int size = (szfl & disp_32) ? 32 : (szfl & disp_24) ? 24 : (szfl & disp_16) ? 16 : 8; out_symbol(':'); out_long(size, 10); } //---------------------------------------------------------------------- void out_h8_t::attach_name_comment(const op_t &x, ea_t v) const { if ( !has_cmt(F) ) { qstring qbuf; if ( get_name_expr(&qbuf, insn.ea, x.n, v, BADADDR) > 0 ) set_cmt(insn.ea, qbuf.begin(), false); } } //---------------------------------------------------------------------- static ea_t get_data_ref(ea_t ea) { ea_t to = BADADDR; xrefblk_t xb; for ( bool ok=xb.first_from(ea, XREF_DATA); ok; ok=xb.next_from() ) { if ( xb.type == dr_O ) return xb.to; } return to; } //---------------------------------------------------------------------- bool out_h8_t::out_operand(const op_t &x) { h8_t &pm = *static_cast(procmod); switch ( x.type ) { case o_void: return 0; case o_reg: outreg(x.reg); break; case o_reglist: if ( pm.is_hew_asm() ) out_symbol('('); outreg(x.reg); out_symbol('-'); outreg(x.reg+x.nregs-1); if ( pm.is_hew_asm() ) out_symbol(')'); break; case o_imm: out_symbol('#'); out_value(x, OOFS_IFSIGN|OOFW_IMM); break; case o_mem: out_symbol('@'); if ( x.memtype == mem_vec7 || x.memtype == mem_ind ) out_symbol('@'); // no break case o_near: { ea_t ea = x.memtype == mem_sbr ? calc_mem_sbr_based(insn, x.addr) : calc_mem(insn, x.addr); if ( pm.is_hew_asm() && (x.szfl & disp_24) ) out_symbol('@'); out_addr_tag(ea); if ( x.memtype == mem_sbr || !out_name_expr(x, ea, x.addr) ) { out_bad_address(x.addr); if ( x.memtype == mem_sbr ) attach_name_comment(x, ea); } if ( x.memtype != mem_vec7 ) out_sizer(x.szfl); } break; case o_phrase: out_symbol('@'); if ( x.phtype == ph_pre_dec ) out_symbol('-'); else if ( x.phtype == ph_pre_inc ) out_symbol('+'); outreg(x.phrase); if ( x.phtype == ph_post_inc ) out_symbol('+'); else if ( x.phtype == ph_post_dec ) out_symbol('-'); { ea_t ea = get_data_ref(insn.ea); if ( ea != BADADDR ) attach_name_comment(x, ea); } break; case o_displ: out_symbol('@'); out_symbol('('); { int outf = pm.get_displ_outf(x, F); out_value(x, outf); out_sizer(x.szfl); } out_symbol(','); if ( x.displtype == dt_movaop1 ) { op_t ea; memset(&ea, 0, sizeof(ea)); ea.offb = insn.Op1.offo; ea.type = insn.Op1.idxt; ea.phrase = insn.Op1.phrase; ea.phtype = insn.Op1.idxdt; ea.addr = insn.Op1.value; ea.szfl = insn.Op1.idxsz; out_operand(ea); out_symbol('.'); out_symbol(x.szfl & idx_byte ? 'b' : x.szfl & idx_word ? 'w' : 'l'); } else if ( x.displtype == dt_regidx ) { outreg(x.reg); out_symbol('.'); out_symbol(x.szfl & idx_byte ? 'b' : x.szfl & idx_word ? 'w' : 'l'); } else { outreg(x.reg); } out_symbol(')'); break; case o_pcidx: outreg(x.reg); break; default: INTERR(10096); } return 1; } //---------------------------------------------------------------------- void out_h8_t::out_proc_mnem(void) { static const char *const postfixes[] = { NULL, ".b", ".w", ".l" }; const char *postfix = postfixes[insn.auxpref]; out_mnem(8, postfix); } //---------------------------------------------------------------------- void out_h8_t::out_insn(void) { out_mnemonic(); bool showOp1 = insn.Op1.shown(); if ( showOp1 ) out_one_operand(0); if ( insn.Op2.type != o_void ) { if ( showOp1 ) { out_symbol(','); out_char(' '); } out_one_operand(1); } if ( insn.Op3.type != o_void ) { out_symbol(','); out_char(' '); out_one_operand(2); } out_immchar_cmts(); flush_outbuf(); } //-------------------------------------------------------------------------- //lint -esym(1764, ctx) could be made const //lint -esym(818, Srange) could be made const void h8_t::h8_segstart(outctx_t &ctx, segment_t *Srange) const { const char *predefined[] = { ".text", // Text section ".rdata", // Read-only data section ".data", // Data sections ".lit8", // Data sections ".lit4", // Data sections ".sdata", // Small data section, addressed through register $gp ".sbss", // Small bss section, addressed through register $gp }; if ( Srange == NULL || is_spec_segm(Srange->type) ) return; qstring sname; qstring sclas; get_segm_name(&sname, Srange); get_segm_class(&sclas, Srange); if ( !print_predefined_segname(ctx, &sname, predefined, qnumber(predefined)) ) ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s", SCOLOR_ASMDIR) "" COLSTR("%s %s", SCOLOR_AUTOCMT), sclas == "CODE" ? ".text" : ".data", ash.cmnt, sname.c_str()); } //-------------------------------------------------------------------------- void idaapi h8_segend(outctx_t &, segment_t *) { } //-------------------------------------------------------------------------- //lint -esym(1764, ctx) could be made const void h8_t::h8_assumes(outctx_t &ctx) { ea_t ea = ctx.insn_ea; segment_t *seg = getseg(ea); if ( (inf_get_outflags() & OFLG_GEN_ASSUME) == 0 || seg == NULL ) return; bool seg_started = (ea == seg->start_ea); for ( int i = ph.reg_first_sreg; i <= ph.reg_last_sreg; i++ ) { if ( i == ph.reg_code_sreg || i == ph.reg_data_sreg ) continue; sreg_range_t sra; if ( !get_sreg_range(&sra, ea, i) ) continue; bool show = sra.start_ea == ea; if ( show ) { sreg_range_t prev_sra; if ( get_prev_sreg_range(&prev_sra, ea, i) ) show = sra.val != prev_sra.val; } if ( seg_started || show ) ctx.gen_cmt_line("%-*s assume %s: %a", int(inf_get_indent()-strlen(ash.cmnt)-2), "", ph.reg_names[i], sra.val); } } //-------------------------------------------------------------------------- // Generate stack variable definition line // If this function is NULL, then the kernel will create the line itself. void h8_t::h8_gen_stkvar_def(outctx_t &ctx, const member_t *mptr, sval_t v) const { char sign = ' '; if ( v < 0 ) { v = -v; sign = '-'; } char num[MAX_NUMBUF]; btoa(num, sizeof(num), v); qstring name = get_member_name(mptr->id); if ( is_hew_asm() ) { ctx.out_printf(COLSTR("%s", SCOLOR_LOCNAME) COLSTR(": ", SCOLOR_SYMBOL) COLSTR(".assign", SCOLOR_ASMDIR) COLSTR(" %c", SCOLOR_SYMBOL) COLSTR("%s", SCOLOR_DNUM), name.c_str(), sign, num); } else { ctx.out_printf(COLSTR("%-*s", SCOLOR_LOCNAME) COLSTR("= %c", SCOLOR_SYMBOL) COLSTR("%s", SCOLOR_DNUM), inf_get_indent(), name.c_str(), sign, num); } } //-------------------------------------------------------------------------- void h8_t::h8_header(outctx_t &ctx) { ctx.gen_header(GH_PRINT_ALL); if ( ptype == P300 ) return; char procdir[MAXSTR]; qsnprintf(procdir, MAXSTR, ".h8300%s%s", is_h8sx() ? "sx" : is_h8s() ? "s" : "h", advanced() ? "" : "n"); ctx.gen_empty_line(); ctx.gen_printf(DEFAULT_INDENT, "%s", procdir); } //-------------------------------------------------------------------------- void h8_t::h8_footer(outctx_t &ctx) const { qstring nbuf = get_colored_name(inf_get_start_ea()); const char *name = nbuf.c_str(); const char *end = ash.end; if ( end == NULL ) ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s end %s",SCOLOR_AUTOCMT), ash.cmnt, name); else ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s",SCOLOR_ASMDIR) " " COLSTR("%s %s",SCOLOR_AUTOCMT), ash.end, ash.cmnt, name); }