/**************************************************************************** * dcc project disassembler * (C) Cristina Cifuentes, Mike van Emmerik, Jeff Ledermann ****************************************************************************/ #include #include #include #include #include #include #include #include "dcc.h" #include "symtab.h" #include "disassem.h" #include "project.h" // Note: for the time being, there is no interactive disassembler // for unix using namespace std; #define POS_LAB 15 /* Position of label */ #define POS_OPC 20 /* Position of opcode */ #define POS_OPR 25 /* Position of operand */ #define WID_PTR 10 /* Width of the "xword ptr" lingo */ #define POS_OPR2 POS_OPR+WID_PTR /* Position of operand after "xword ptr" */ #define POS_CMT 54 /* Position of comment */ static const char *szFlops0C[] = { "FCHS", "FABS", "???", "???", "FTST", "FXAM", "???", "???" }; static const char *szFlops0D[] = { "FLD1", "FLDL2T","FLDL2E","FLDP1", "FLDLG2","FLDLN2","FLDZ", "???" }; static const char *szFlops0E[] = { "F2XM1", "FYL2X", "FPTAN", "FPATAN","FXTRACT","FPREM1","FDECSTP","FINCSTP" }; static const char *szFlops0F[] = { "FPREM", "FYLXP1","FSQRT", "FSINCOS","FRNDINT","FSCALE","FSIN","FCOS" }; static const char *szFlops15[] = { "???", "FUCOMPP", "???", "???", "???", "???", "???", "???" }; static const char *szFlops1C[] = { "???", "???", "FCLEX", "FINIT", "FTST", "FXAM", "???", "???" }; static const char *szFlops33[] = { "???", "FCOMPP", "???", "???", "???", "???", "???", "???" }; static const char *szFlops3C[] = { "FSTSWAX","???", "???", "???", "???", "???", "???", "???" }; static const char *szPtr[2] = { "word ptr ", "byte ptr " }; static void formatRM(ostringstream &p, const LLOperand &pm); static ostringstream &strDst(ostringstream &os, uint32_t flg, const LLOperand &pm); static char *strHex(uint32_t d); //static int checkScanned(uint32_t pcCur); //static void setProc(Function * proc); //static void dispData(uint16_t dataSeg); bool callArg(uint16_t off, char *temp); /* Check for procedure name */ //static FILE *dis_g_fp; static CIcodeRec pc; static int cb, j, numIcode, allocIcode; static map pl; static uint32_t nextInst; static bool fImpure; //static int g_lab; static Function * pProc; /* Points to current proc struct */ struct POSSTACK_ENTRY { int ic; /* An icode offset */ Function * pProc; /* A pointer to a PROCEDURE structure */ } ; static vector posStack; /* position stack */ //static uint8_t iPS; /* Index into the stack */ // These are "curses equivalent" functions. (Used to use curses for all this, // but it was too much of a distribution hassle #define printfd(x) printf(x) #define dis_newline() printf("\n") #define dis_show() // Nothing to do unless using Curses void LLInst::findJumpTargets(CIcodeRec &_pc) { if (testFlags(I) && ! testFlags(JMP_ICODE) && isJmpInst()) { /* Replace the immediate operand with an icode index */ iICODE labTgt=_pc.labelSrch(src().getImm2()); if (labTgt!=_pc.end()) { m_src.SetImmediateOp(labTgt->loc_ip); /* This icode is the target of a jump */ labTgt->ll()->setFlags(TARGET); setFlags(JMP_ICODE); /* So its not done twice */ } else { /* This jump cannot be linked to a label */ setFlags(NO_LABEL); } } } /***************************************************************************** * disassem - Prints a disassembled listing of a procedure. * pass == 1 generates output on file .a1 * pass == 2 generates output on file .a2 * pass == 3 generates output on file .b ****************************************************************************/ void Disassembler::disassem(Function * ppProc) { pProc = ppProc; /* Save the passes pProc */ createSymTables(); allocIcode = numIcode = pProc->Icode.size(); cb = allocIcode * sizeof(ICODE); if (numIcode == 0) { return; /* No Icode */ } /* Open the output file (.a1 or .a2 only) */ if (pass != 3) { auto p = (pass == 1)? asm1_name: asm2_name; m_fp.open(p,ios_base::app); if (!m_fp.is_open()) { fatalError(CANNOT_OPEN, p.c_str()); } } /* Create temporary code array */ // Mike: needs objectising! pc=pProc->Icode; if (pass == 1) { /* Bind jump offsets to labels */ //for (i = 0; i < numIcode; i++) for( ICODE &icode : pc) { LLInst *ll=icode.ll(); ll->findJumpTargets(pc); } } /* Create label array to keep track of location => label name */ pl.clear(); /* Write procedure header */ if (pass != 3) { std::string near_far=(pProc->flg & PROC_FAR)? "FAR": "NEAR"; m_fp << "\t\t"<name<<" PROC "<< near_far<<"\n"; } /* Loop over array printing each record */ nextInst = 0; for( ICODE &icode : pc) { this->dis1Line(*icode.ll(),icode.loc_ip,pass); } /* Write procedure epilogue */ if (pass != 3) { m_fp << "\n\t\t"<name<<" ENDP\n\n"; m_fp.close(); } pc.clear(); destroySymTables(); } /**************************************************************************** * dis1Line() - disassemble one line to stream fp * * i is index into Icode for this proc * * It is assumed that icode i is already scanned * ****************************************************************************/ void Disassembler::dis1Line(LLInst &inst,int loc_ip, int pass) { PROG &prog(Project::get()->prog); ostringstream oper_stream; ostringstream hex_bytes; ostringstream result_stream; ostringstream opcode_with_mods; ostringstream operands_s; oper_stream << uppercase; hex_bytes << uppercase; /* Disassembly stage 1 -- * Do not try to display NO_CODE entries or synthetic instructions, * other than JMPs, that have been introduced for def/use analysis. */ if ((option.asm1) && ( inst.testFlags(NO_CODE) || (inst.testFlags(SYNTHETIC) && (inst.getOpcode() != iJMP)))) { return; } else if (inst.testFlags(NO_CODE)) { return; } if (inst.testFlags(TARGET | CASE)) { if (pass == 3) cCode.appendCode("\n"); /* Print to c code buffer */ else m_fp<< "\n"; /* No, print to the stream */ } /* Find next instruction label and print hex bytes */ if (inst.testFlags(SYNTHETIC)) nextInst = inst.label; else { cb = (uint32_t) inst.numBytes; nextInst = inst.label + cb; /* Output hexa code in program image */ if (pass != 3) { for (j = 0; j < cb; j++) { hex_bytes << hex << setw(2) << setfill('0') << uint16_t(prog.image()[inst.label + j]); } hex_bytes << ' '; } } oper_stream << setw(POS_LAB) << left<< hex_bytes.str(); /* Check if there is a symbol here */ selectTable(Label); oper_stream << setw(5)<ll()->label, nullptr)) { break; /* Symbolic label. Done */ } } if (inst.testFlags(NO_LABEL)) { //strcpy(p + WID_PTR, strHex(pIcode->ll()->immed.op)); operands_s<name; } else if (inst.getOpcode() == iCALLF) { operands_s<<"dword ptr "; inst.strSrc(operands_s,true); } else strDst(operands_s,I, inst.src()); break; case iENTER: operands_s< 0 && j < (int)nextInst; j++) { fImpure |= BITMAP(j, BM_DATA); } } result_stream << setw(54) << left << oper_stream.str(); /* Check for user supplied comment */ selectTable(Comment); ostringstream cbuf; if (readVal(cbuf, inst.label, nullptr)) { result_stream <<"; "< 9)? "h": ""); return (buf + (buf[1] <= '9')); } /**************************************************************************** * interactDis - interactive disassembler * ****************************************************************************/ void interactDis(Function * /*initProc*/, int /*initIC*/) { printf("Sorry - interactive disasassembler option not available for Unix\n"); return; } /* Handle the floating point opcodes (icode iESC) */ void LLInst::flops(std::ostringstream &out) { //char bf[30]; uint8_t op = (uint8_t)src().getImm2(); /* Note that op is set to the escape number, e.g. esc 0x38 is FILD */ if ( not m_dst.isReg() ) { /* The mod/rm mod bits are not set to 11 (i.e. register). This is the normal floating point opcode */ out<= 0x20) && (op <= 0x27)) { /* This is the ST(i), ST form. */ out << "ST("<