home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / dosdisas.zip / dccsrcoo.zip / disassem.cpp < prev    next >
C/C++ Source or Header  |  1997-09-10  |  52KB  |  1,709 lines

  1. /****************************************************************************
  2.  *$Log:    disassem.c,v $
  3.  * Revision 2.20  94/03/14  08:40:05  cifuente
  4.  * flags type was changed to flags32 (to compile under Turbo C).
  5.  * 
  6.  * Revision 2.18  94/02/22  15:15:32  cifuente
  7.  * Changed a few flags.
  8.  * 
  9.  * Revision 2.17  93/12/14  14:03:58  cifuente
  10.  * ic.ll.immed.proc has one extra level of indirection.
  11.  * 
  12.  * Revision 2.16  93/11/18  11:24:26  emmerik
  13.  * When interactive disassembler brought up for unparsable instruction,
  14.  * display starts on the line with the problem
  15.  * Attempts to cope with unscanned icodes now
  16.  * 
  17.  * Revision 2.15  93/11/15  16:53:19  emmerik
  18.  * process_JMP checks to see if the jump is in range before determining
  19.  * whether a target has a  label
  20.  * 
  21.  * Revision 2.14  93/11/02  15:18:52  emmerik
  22.  * Implemented floating point instructions for the iESC icode. Widened the
  23.  * operand field to fit "qword ptr " etc.
  24.  * 
  25.  * Revision 2.13  93/10/28  15:27:24  cifuente
  26.  * Implicit source operand dx:ax when IM_SRC flag is set
  27.  * 
  28.  * Revision 2.12  93/10/25  10:53:32  cifuente
  29.  * New SYNTHETIC instructions for d/u analysis.
  30.  * 
  31.  * Revision 2.11  93/10/20  14:38:23  cifuente
  32.  * New level of indirection for icode array (Icode.icode[])
  33.  * 
  34.  * Revision 2.10  93/10/01  14:34:22  emmerik
  35.  * Added the code segment (CS) in the interactive disassembler's title
  36.  * 
  37.  * Revision 2.9  93/10/01  08:58:48  cifuente
  38.  * boolT type - for compilation under unix SVR4.2
  39.  * 
  40.  * Revision 2.8  93/09/29  13:50:12  cifuente
  41.  * iCBW is llIcode (0)
  42.  * 
  43.  * Revision 2.7  93/09/29  10:43:53  cifuente
  44.  * LOW_LEVEL and HIGH_LEVEL icode definitions.  Increases llIcode indirection
  45.  * by 2 levels.
  46.  * 
  47.  * Revision 2.6  93/09/24  11:07:21  emmerik
  48.  * Commented out unused dis1LineOp();
  49.  * added createSymTable() and destroySymTable() to disassem()
  50.  * 
  51.  * Revision 2.5  93/09/20  11:49:50  cifuente
  52.  * Changed tabs to spaces
  53.  * 
  54.  * Revision 2.4  93/09/17  08:35:59  cifuente
  55.  * Attempted to make independant of icodes; unfinished
  56.  * 
  57.  * Revision 2.3  93/08/23  12:15:00  cifuente
  58.  * Interactive mode with curses
  59.  * 
  60.  * Revision 2.1  93/03/30  14:50:36  cifuente
  61.  * Compiled with gcc.
  62.  * 
  63.  *          RevComp project disassembler
  64.  ****************************************************************************/
  65.  
  66. #include "dcc.h"
  67. #include "symtab.h"
  68. #include <stdio.h>
  69. #include <string.h>
  70. #ifdef __BORLAND__
  71. #include <alloc.h>
  72. #else
  73. #include <malloc.h>        /* For free() */
  74. #endif
  75. #ifdef _CONSOLE
  76. #include <windows.h>    /* For console mode routines */
  77. #endif
  78. #include "disassem.h"
  79. // Note: for the time being, there is no interactive disassembler
  80. // for unix
  81. #ifndef __UNIX__
  82. #include <conio.h>    // getch() etc
  83. #endif
  84.  
  85.  
  86. #ifndef max
  87. #define max(a,b)  (((a) > (b)) ? (a) : (b))
  88. #endif
  89.  
  90. #define POS_LAB     15              /* Position of label */
  91. #define POS_OPC     20              /* Position of opcode */
  92. #define POS_OPR     25              /* Position of operand */
  93. #define    WID_PTR        10                /* Width of the "xword ptr" lingo */
  94. #define POS_OPR2    POS_OPR+WID_PTR /* Position of operand after "xword ptr" */
  95. #define POS_CMT     54              /* Position of comment */
  96.  
  97.  
  98. #define DELTA_ICODE 160              /* Number of icodes to realloc by each time */
  99.  
  100. static char *szOps[] =
  101. {
  102. "CBW",  "AAA",      "AAD",      "AAM",      "AAS",      "ADC",  "ADD",  "AND",
  103. "BOUND","CALL",     "CALL",     "CLC",      "CLD",      "CLI",  "CMC",  "CMP",
  104. "CMPS", "REPNE CMPS","REPE CMPS","DAA",     "DAS",      "DEC",  "DIV",  "ENTER",
  105. "ESC",  "HLT",      "IDIV",     "IMUL",     "IN",       "INC",  "INS",  "REP INS",
  106. "INT",  "IRET",     "JB",       "JBE",      "JAE",      "JA",   "JE",   "JNE",
  107. "JL",   "JGE",      "JLE",      "JG",       "JS",       "JNS",  "JO",   "JNO",
  108. "JP",   "JNP",      "JCXZ",     "JMP",      "JMP",      "LAHF", "LDS",  "LEA",
  109. "LEAVE","LES",      "LOCK",     "LODS",     "REP LODS", "LOOP", "LOOPE","LOOPNE",
  110. "MOV",  "MOVS",     "REP MOVS", "MUL",      "NEG",      "NOT",  "OR",   "OUT",
  111. "OUTS", "REP OUTS", "POP",      "POPA",     "POPF",     "PUSH", "PUSHA","PUSHF",
  112. "RCL",  "RCR",      "ROL",      "ROR",      "RET",      "RETF", "SAHF", "SAR",
  113. "SHL",  "SHR",      "SBB",      "SCAS",     "REPNE SCAS","REPE SCAS",   "CWD",  "STC",
  114. "STD",  "STI",      "STOS",     "REP STOS", "SUB",      "TEST", "WAIT", "XCHG",
  115. "XLAT", "XOR",      "INTO",     "NOP",        "REPNE",    "REPE",    "MOD"
  116. };
  117.  
  118. /* The following opcodes are for mod != 3 */
  119. static char *szFlops1[] =
  120. {
  121. /* 0        1        2       3        4        5        6        7  */
  122. "FADD",  "FMUL",  "FCOM", "FCOMP", "FSUB",  "FSUBR", "FDIV",  "FDIVR",  /* 00 */
  123. "FLD",   "???",   "FST",  "???",   "FLDENV","FLDCW", "FSTENV","FSTSW",  /* 08 */
  124. "FIADD", "FIMUL", "FICOM","FICOMP","FISUB", "FISUBR","FIDIV", "FIDIVR", /* 10 */
  125. "FILD",  "???",   "FIST", "FISTP", "???",   "???",   "???",   "FSTP",   /* 18 */
  126. "FADD",  "FMUL",  "FCOM", "FCOMP", "FSUB",  "FSUBR", "FDIV",  "FDIVR",  /* 20 */
  127. "FLD",   "FLD",   "FST",  "FSTP",  "FRESTOR","???",  "FSAVE", "FSTSW",  /* 28 */
  128. "FIADD", "FIMUL", "FICOM","FICOMP","FISUB", "FISUBR","FIDIV", "FIDIVR", /* 30 */
  129. "FILD",  "???",   "FIST", "FISTP", "FBLD",  "???",   "FBSTP", "FISTP"   /* 38 */
  130. };
  131.  
  132. /* The following opcodes are for mod == 3 */
  133. static char *szFlops2[] =
  134. {
  135. /* 0        1        2       3        4        5        6        7  */
  136. "FADD",  "FMUL",  "FCOM", "FCOMP", "FSUB",  "FSUBR", "FDIV",  "FDIVR",  /* 00 */
  137. "FLD",   "FXCH",  "FNOP", "???",   "",      "",      "",      "",       /* 08 */
  138. "FIADD", "FIMUL", "FICOM","FICOMP","FISUB", "",      "FIDIV", "FIDIVR", /* 10 */
  139. "FILD",  "???",   "FIST", "FISTP", "???",   "???",   "???",   "FSTP",   /* 18 */
  140. "FADD",  "FMUL",  "FCOM", "FCOMP", "FSUB",  "FSUBR", "FDIV",  "FDIVR",  /* 20 */
  141. "FFREE", "FSTP",  "FST",  "???",   "FUCOM", "FUCOMP","???",   "???",    /* 28 */
  142. "FADDP", "FMULP", "FICOM","",      "FSUBRP","FISUBR","FDIVRP","FDIVP",  /* 30 */
  143. "FILD",  "???",   "FIST", "FISTP", "",      "???",   "FBSTP", "FISTP"   /* 38 */
  144. };
  145.  
  146. static char *szFlops0C[] =
  147. {
  148. "FCHS",  "FABS",  "???",   "???",   "FTST", "FXAM",  "???",   "???"
  149. };
  150.  
  151. static char *szFlops0D[] =
  152. {
  153. "FLD1",  "FLDL2T","FLDL2E","FLDP1", "FLDLG2","FLDLN2","FLDZ", "???"
  154. };
  155.  
  156. static char *szFlops0E[] =
  157. {
  158. "F2XM1", "FYL2X", "FPTAN", "FPATAN","FXTRACT","FPREM1","FDECSTP","FINCSTP"
  159. };
  160.  
  161. static char *szFlops0F[] =
  162. {
  163. "FPREM", "FYLXP1","FSQRT", "FSINCOS","FRNDINT","FSCALE","FSIN","FCOS"
  164. };
  165.  
  166. static char *szFlops15[] =
  167. {
  168. "???",  "FUCOMPP",  "???", "???", "???", "???",  "???",   "???"
  169. };
  170.  
  171. static char *szFlops1C[] =
  172. {
  173. "???",  "???",  "FCLEX", "FINIT", "FTST", "FXAM",  "???",   "???"
  174. };
  175.  
  176. static char *szFlops33[] =
  177. {
  178. "???",  "FCOMPP",  "???", "???", "???", "???",  "???",   "???"
  179. };
  180.  
  181. static char *szFlops3C[] =
  182. {
  183. "FSTSWAX","???",  "???", "???", "???", "???",  "???",   "???"
  184. };
  185.  
  186.  
  187. static char *szIndex[8] = {"bx+si", "bx+di", "bp+si", "bp+di", "si", "di","bp","bx" };
  188. static char *szBreg[8]  = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" };
  189. static char *szWreg[12] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
  190.                             "es", "cs", "ss", "ds" };
  191. static char *szPtr[2]   = { " word ptr ", " byte ptr " };
  192.  
  193.  
  194. static void  dis1Line  (Int i, boolT fWin, char attr, Int pass);
  195.        void  dis1LineOp(Int i, boolT fWin, char attr, word *len, PPROC pProc);
  196. static void  formatRM(char *p, flags32 flg, PMEM pm);
  197. static char *strDst(flags32 flg, PMEM pm);
  198. static char *strSrc(PICODE pc);
  199. static char *strHex(dword d);
  200. static Int   checkScanned(dword pcCur);
  201. static void  setProc(PPROC proc);
  202. static void  dispData(word dataSeg);
  203. static void  flops(PICODE pi);
  204.        boolT callArg(word off, char *temp);  /* Check for procedure name */
  205.  
  206. static  FILE   *fp;
  207. static  PICODE  pc;
  208. static  char    buf[200], *p;
  209. static  Int     cb, j, numIcode, allocIcode, eop, *pl;
  210. static  dword   nextInst;
  211. static  boolT    fImpure;
  212. static  Int     lab, prevPass;
  213. static  PPROC   pProc;          /* Points to current proc struct */
  214.  
  215. typedef struct _POSSTACK
  216. {
  217.     Int     ic;                 /* An icode offset */
  218.     PPROC   pProc;              /* A pointer to a PROCEDURE structure */
  219. } POSSTACK;
  220.  
  221. static  POSSTACK *posStack;     /* Pointer to the position stack */
  222. byte              iPS;          /* Index into the stack */
  223.  
  224. static  char    cbuf[256];      /* Has to be 256 for wgetstr() to work */
  225.  
  226. // These are "curses equivalent" functions. (Used to use curses for all this,
  227. // but it was too much of a distribution hassle
  228.  
  229. #if _CONSOLE
  230. HANDLE    hConsole;        /* All 32 bit console style routines need this handle */
  231. #endif
  232.  
  233. void attrSet(char attrib)
  234. {
  235. #ifdef _CONSOLE
  236.     switch (attrib)
  237.     {
  238.         case A_NORMAL:
  239.             SetConsoleTextAttribute(hConsole,
  240.                 FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
  241.             break;
  242.         case A_REVERSE:
  243.             SetConsoleTextAttribute(hConsole,
  244.                 BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
  245.             break;
  246.         case A_BOLD:
  247.             SetConsoleTextAttribute(hConsole,
  248.                 FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED |
  249.                 FOREGROUND_INTENSITY);
  250.             break;
  251.     }
  252. #else
  253.     /* Set the attribute, using VT100 codes */
  254.     switch (attrib)
  255.     {
  256.         case A_NORMAL:
  257.             printf("\033[0m");
  258.             break;
  259.         case A_REVERSE:
  260.             printf("\033[7m");
  261.             break;
  262.         case A_BOLD:
  263.             printf("\033[1m");
  264.             break;
  265.     }
  266. #endif
  267. }
  268.  
  269. #ifdef _CONSOLE
  270. void initConsole()
  271. {
  272.     hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
  273. }
  274. #endif
  275.  
  276. void erase(void)
  277. {
  278. #ifdef _CONSOLE
  279.    COORD coordScreen = { 0, 0 };    /* here's where we'll home the
  280.                                        cursor */
  281.    DWORD cCharsWritten;
  282.    CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */
  283.    DWORD dwConSize;                 /* number of character cells in
  284.                                        the current buffer */
  285.  
  286.    /* get the number of character cells in the current buffer */
  287.    GetConsoleScreenBufferInfo( hConsole, &csbi );
  288.    dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
  289.  
  290.    /* fill the entire screen with blanks */
  291.    FillConsoleOutputCharacter( hConsole, (TCHAR) ' ',
  292.       dwConSize, coordScreen, &cCharsWritten );
  293.  
  294.    /* get the current text attribute */
  295. //   GetConsoleScreenBufferInfo( hConsole, &csbi );
  296.  
  297.    /* now set the buffer's attributes accordingly */
  298.    FillConsoleOutputAttribute( hConsole, csbi.wAttributes,
  299.       dwConSize, coordScreen, &cCharsWritten );
  300.  
  301.    /* put the cursor at (0, 0) */
  302.    SetConsoleCursorPosition( hConsole, coordScreen );
  303.  
  304. #else
  305.     // Assume that ANSI is supported
  306.     printf("\033[2J");
  307. #endif
  308. }
  309.  
  310. void move(int r, int c)
  311. {
  312. #ifdef _CONSOLE
  313.    COORD pos;
  314.     pos.X = c;
  315.     pos.Y = r;
  316.     SetConsoleCursorPosition( hConsole, pos );
  317. #else
  318.     printf("\033[%d;%dH", r+1, c+1);
  319. #endif
  320. }
  321.  
  322. #define printfd(x) printf(x)
  323. #define dis_newline() printf("\n")
  324. #define dis_show()                    // Nothing to do unless using Curses
  325.  
  326.  
  327. /*****************************************************************************
  328.  * disassem - Prints a disassembled listing of a procedure.
  329.  *              pass == 1 generates output on file .a1
  330.  *              pass == 2 generates output on file .a2
  331.  *              pass == 3 generates output on file .b
  332.  ****************************************************************************/
  333. void disassem(Int pass, PPROC ppProc)
  334. {
  335.     Int         i;
  336.  
  337.     pProc = ppProc;             /* Save the passes pProc */
  338.     if (pass != prevPass)
  339.     {
  340.         prevPass = pass;
  341.         lab = 0;     /* Restart label numbers */
  342.     }
  343.     createSymTables();
  344.     allocIcode = numIcode = pProc->Icode.GetNumIcodes();
  345.     if ((cb = allocIcode * sizeof(ICODE)) == 0)
  346.     {
  347.         return;  /* No Icode */
  348.     }
  349.  
  350.     /* Open the output file (.a1 or .a2 only) */
  351.     if (pass != 3)
  352.     {
  353.         p = (pass == 1)? asm1_name: asm2_name;
  354.         fp = fopen(p, "a+");
  355.         if (!fp)
  356.         {
  357.             fatalError(CANNOT_OPEN, p);
  358.         }
  359.     }
  360.  
  361.     /* Create temporary code array */
  362.     // Mike: needs objectising!
  363.     pc = (PICODE)memcpy(allocMem(cb), pProc->Icode.GetFirstIcode(), (size_t)cb);
  364.  
  365.     if (pass == 1)
  366.     {
  367.         /* Bind jump offsets to labels */
  368.         for (i = 0; i < numIcode; i++)
  369.         {
  370.             if ((pc[i].ic.ll.flg & I) && !(pc[i].ic.ll.flg & JMP_ICODE) &&
  371.                 JmpInst(pc[i].ic.ll.opcode))
  372.             {
  373.                 /* Replace the immediate operand with an icode index */
  374.                 if (labelSrch(pc, numIcode, pc[i].ic.ll.immed.op,
  375.                     (Int *)&pc[i].ic.ll.immed.op))
  376.                 {
  377.                     /* This icode is the target of a jump */
  378.                     pc[pc[i].ic.ll.immed.op].ic.ll.flg |= TARGET;
  379.                     pc[i].ic.ll.flg |= JMP_ICODE;   /* So its not done twice */
  380.                 }
  381.                 else
  382.                 {
  383.                     /* This jump cannot be linked to a label */
  384.                     pc[i].ic.ll.flg |= NO_LABEL;
  385.                 }
  386.             }
  387.         }
  388.     }
  389.  
  390.     /* Create label array to keep track of location => label name */
  391.     pl = (Int*)memset(allocMem(numIcode * sizeof(Int)), 0,
  392.         (size_t)(numIcode * sizeof(Int)));
  393.  
  394.     /* Write procedure header */
  395.     if (pass != 3)
  396.         fprintf(fp, "\t\t%s  PROC  %s\n", pProc->name, 
  397.             (pProc->flg & PROC_FAR)? "FAR": "NEAR");
  398.     
  399.     /* Loop over array printing each record */
  400.     for (i = nextInst = 0; i < numIcode; i++)
  401.     {
  402.         dis1Line(i, FALSE, 0, pass);
  403.     }
  404.  
  405.     /* Write procedure epilogue */
  406.     if (pass != 3)
  407.     {
  408.         fprintf(fp, "\n\t\t%s  ENDP\n\n", pProc->name);
  409.         fclose(fp);
  410.     }
  411.  
  412.     free(pc);
  413.     free(pl);
  414.     destroySymTables();
  415. }
  416.  
  417. /****************************************************************************
  418.  * dis1Line() - disassemble one line to stream fp                           *                                   *
  419.  * i is index into Icode for this proc                                      *
  420.  * It is assumed that icode i is already scanned                            *
  421.  ****************************************************************************/
  422. static void
  423. dis1Line(Int i, boolT fWindow, char attr, Int pass)
  424. {
  425.     PICODE pIcode = &pc[i];
  426.  
  427.     /* Disassembly stage 1 --
  428.      * Do not try to display NO_CODE entries or synthetic instructions,
  429.      * other than JMPs, that have been introduced for def/use analysis. */
  430.     if ((option.asm1) && 
  431.         ((pIcode->ic.ll.flg & NO_CODE) ||
  432.          ((pIcode->ic.ll.flg & SYNTHETIC) && (pIcode->ic.ll.opcode != iJMP))))
  433.     {
  434.         return;
  435.     }
  436.     else if (pIcode->ic.ll.flg & NO_CODE)
  437.     {
  438.         return;
  439.     }
  440.  
  441.     /* p points to the current position in buf[] */
  442.     p = (char*)memset(buf, ' ', sizeof(buf));
  443.  
  444.     if (pIcode->ic.ll.flg & (TARGET | CASE))
  445.     {
  446.         if (fWindow)                        /* Printing to disassem window? */
  447.             dis_newline();                    /* Yes */
  448.         else if (pass == 3)                    
  449.             appendStrTab (&cCode.code, "\n"); /* No, print to c code buffer */
  450.         else
  451.             fprintf(fp, "\n");              /* No, print to the stream */ 
  452.     } 
  453.  
  454.     /* Find next instruction label and print hex bytes */
  455.     if (pIcode->ic.ll.flg & SYNTHETIC)
  456.         nextInst = pIcode->ic.ll.label;
  457.     else
  458.     {
  459.         cb = (dword) pIcode->ic.ll.numBytes;
  460.         nextInst = pIcode->ic.ll.label + cb;
  461.  
  462.         /* Output hexa code in program image */
  463.         if (pass != 3)
  464.         {
  465.             for (j = 0; j < cb; j++, p += 2)
  466.                 sprintf(p, "%02X", prog.Image[pIcode->ic.ll.label + j]);
  467.             *p = ' ';
  468.         }
  469.     }
  470.  
  471.     /* Check if there is a symbol here */
  472.     selectTable(Label);
  473.     if (readVal(&buf[POS_LAB], pIcode->ic.ll.label, 0))
  474.     {
  475.         buf[strlen(buf)] = ':';             /* Also removes the null */
  476.     }
  477.  
  478.     else if (pIcode->ic.ll.flg & TARGET)    /* Symbols override Lnn labels */
  479.     {   /* Print label */
  480.         if (! pl[i])
  481.         {
  482.             pl[i] = ++lab;
  483.         }
  484.         if (pass == 3)
  485.             sprintf(buf, "L%ld", pl[i]);
  486.         else    
  487.             sprintf(&buf[15], "L%ld", pl[i]);
  488.         buf[strlen(buf)] = ':';             /* Also removes the null */
  489.     }
  490.  
  491.     if (pIcode->ic.ll.opcode == iSIGNEX && (pIcode->ic.ll.flg & B))
  492.     {
  493.         pIcode->ic.ll.opcode = iCBW;
  494.     }
  495.  
  496.     if (pass == 3)
  497.     {
  498.         strcpy (&buf[8], szOps[pIcode->ic.ll.opcode]);
  499.         buf[eop = strlen(buf)] = ' ';
  500.         p = buf + 8 + (POS_OPR - POS_OPC);
  501.     }
  502.     else
  503.     {
  504.         strcpy(&buf[POS_OPC], szOps[pIcode->ic.ll.opcode]);
  505.         buf[eop = strlen(buf)] = ' ';
  506.         p = buf + POS_OPR;
  507.     }
  508.  
  509.     switch (pIcode->ic.ll.opcode)
  510.     {
  511.     case iADD:  case iADC:  case iSUB:  case iSBB:  case iAND:  case iOR:
  512.     case iXOR:  case iTEST: case iCMP:  case iMOV:  case iLEA:  case iXCHG:
  513.         strcpy(p, strDst(pIcode->ic.ll.flg, &pIcode->ic.ll.dst));
  514.         strcat(p, strSrc(pIcode));
  515.         break;
  516.  
  517.     case iESC:
  518.         flops(pIcode);
  519.         break;
  520.  
  521.     case iSAR:  case iSHL:  case iSHR:  case iRCL:  case iRCR:  case iROL:
  522.     case iROR:
  523.         strcpy(p, strDst(pIcode->ic.ll.flg | I, &pIcode->ic.ll.dst));
  524.         strcat(p, (pIcode->ic.ll.flg & I)? strSrc(pIcode): ", cl");
  525.         break;
  526.  
  527.     case iINC:  case iDEC:  case iNEG:  case iNOT:  case iPOP:
  528.         strcpy(p, strDst(pIcode->ic.ll.flg | I, &pIcode->ic.ll.dst));
  529.         break;
  530.  
  531.     case iPUSH:
  532.         if (pIcode->ic.ll.flg & I)
  533.         {
  534.             strcpy(p + WID_PTR, strHex(pIcode->ic.ll.immed.op));
  535.         }
  536.         else
  537.         {
  538.             strcpy(p, strDst(pIcode->ic.ll.flg | I, &pIcode->ic.ll.dst));
  539.         }
  540.         break;
  541.  
  542.     case iDIV:  case iIDIV:  case iMUL: case iIMUL: case iMOD:
  543.         if (pIcode->ic.ll.flg & I)
  544.         {
  545.             strcat(strcpy(p, strDst(pIcode->ic.ll.flg, &pIcode->ic.ll.dst)),
  546.                     ", ");
  547.             formatRM(p + strlen(p), pIcode->ic.ll.flg, &pIcode->ic.ll.src);
  548.             strcat(p, strSrc(pIcode));
  549.         }
  550.         else    
  551.             strcpy(p, strDst(pIcode->ic.ll.flg | I, &pIcode->ic.ll.src));
  552.         break;
  553.  
  554.     case iLDS:  case iLES:  case iBOUND:
  555.         strcpy(p, strDst(pIcode->ic.ll.flg, &pIcode->ic.ll.dst));
  556.         strcat(strcat(p, ", dword ptr"), strSrc(pIcode)+1);
  557.         break;
  558.  
  559.     case iJB:  case iJBE:  case iJAE:  case iJA:
  560.     case iJL:  case iJLE:  case iJGE:  case iJG: 
  561.     case iJE:  case iJNE:  case iJS:   case iJNS:
  562.     case iJO:  case iJNO:  case iJP:   case iJNP:
  563.     case iJCXZ:case iLOOP: case iLOOPE:case iLOOPNE:
  564.     case iJMP: case iJMPF:
  565.  
  566.         /* Check if there is a symbol here */
  567.         selectTable(Label);
  568.         if ((pIcode->ic.ll.immed.op < (dword)numIcode) &&  /* Ensure in range */
  569.             readVal(p+WID_PTR, pc[pIcode->ic.ll.immed.op].ic.ll.label, 0))
  570.         {
  571.             break;                          /* Symbolic label. Done */
  572.         }
  573.  
  574.         if (pIcode->ic.ll.flg & NO_LABEL)
  575.         {
  576.             strcpy(p + WID_PTR, strHex(pIcode->ic.ll.immed.op));
  577.         }
  578.         else if (pIcode->ic.ll.flg & I)
  579.         {
  580.             j = pIcode->ic.ll.immed.op;
  581.             if (! pl[j])       /* Forward jump */
  582.             {
  583.                 pl[j] = ++lab;
  584.             }
  585.             if (pIcode->ic.ll.opcode == iJMPF)
  586.             {
  587.                 sprintf(p, " far ptr L%ld", pl[j]);
  588.             }
  589.             else
  590.             {
  591.                 sprintf(p + WID_PTR, "L%ld", pl[j]);
  592.             }
  593.         }           
  594.         else if (pIcode->ic.ll.opcode == iJMPF)
  595.         {
  596.             strcat(strcpy(p-1, "dword ptr"), strSrc(pIcode)+1);
  597.         }
  598.         else
  599.         {
  600.             strcpy(p, strDst(I, &pIcode->ic.ll.src));
  601.         }
  602.         break;
  603.  
  604.     case iCALL: case iCALLF:
  605.         if (pIcode->ic.ll.flg & I)
  606.         {
  607.             sprintf(p, "%s ptr %s", 
  608.                 (pIcode->ic.ll.opcode == iCALL) ?" near":"  far",
  609.                 (pIcode->ic.ll.immed.proc.proc)->name);
  610.         }
  611.         else if (pIcode->ic.ll.opcode == iCALLF)
  612.         {
  613.             strcat(strcpy(p, "dword ptr"),strSrc(pIcode)+1);
  614.         }
  615.         else
  616.         {
  617.             strcpy(p, strDst(I, &pIcode->ic.ll.src));
  618.         }
  619.         break;
  620.  
  621.     case iENTER:
  622.         strcat(strcpy(p + WID_PTR, strHex(pIcode->ic.ll.dst.off)), ", ");
  623.         strcat(p, strHex(pIcode->ic.ll.immed.op));
  624.         break;
  625.  
  626.     case iRET:  case iRETF:  case iINT:
  627.         if (pIcode->ic.ll.flg & I)
  628.         {
  629.             strcpy(p + WID_PTR, strHex(pIcode->ic.ll.immed.op));
  630.         }
  631.         else
  632.         {
  633.             buf[eop] = '\0';
  634.         }
  635.         break;
  636.  
  637.     case iCMPS:  case iREPNE_CMPS:  case iREPE_CMPS:
  638.     case iSCAS:  case iREPNE_SCAS:  case iREPE_SCAS:
  639.     case iSTOS:  case iREP_STOS:
  640.     case iLODS:  case iREP_LODS:
  641.     case iMOVS:  case iREP_MOVS:
  642.     case iINS:   case iREP_INS:
  643.     case iOUTS:  case iREP_OUTS:
  644.         if (pIcode->ic.ll.src.segOver)
  645.         {
  646.             (pIcode->ic.ll.opcode == iOUTS || pIcode->ic.ll.opcode == iREP_OUTS)
  647.                 ? strcat(strcpy(p+WID_PTR,"dx, "), szPtr[pIcode->ic.ll.flg & B])
  648.                 : strcpy(&buf[eop+1], szPtr[pIcode->ic.ll.flg & B]);
  649.             if (pIcode->ic.ll.opcode == iLODS || 
  650.                 pIcode->ic.ll.opcode == iREP_LODS || 
  651.                 pIcode->ic.ll.opcode == iOUTS || 
  652.                 pIcode->ic.ll.opcode == iREP_OUTS)
  653.             {
  654.                 strcat(p, szWreg[pIcode->ic.ll.src.segOver-rAX]);
  655.             }
  656.             else
  657.             {
  658.                 strcat(strcat(p, "es:[di], "),
  659.                     szWreg[pIcode->ic.ll.src.segOver - rAX]);
  660.             }
  661.             strcat(p, ":[si]");
  662.         }
  663.         else    strcpy(&buf[eop], (pIcode->ic.ll.flg & B)? "B": "W");
  664.         break;
  665.  
  666.     case iXLAT:
  667.         if (pIcode->ic.ll.src.segOver)
  668.         {
  669.             strcpy(&buf[eop+1], szPtr[1]);
  670.             strcat(strcat(p, szWreg[pIcode->ic.ll.src.segOver-rAX]), ":[bx]");
  671.         }
  672.         else    buf[eop] = '\0';
  673.         break;
  674.  
  675.     case iIN:
  676.         strcpy(p+WID_PTR, (pIcode->ic.ll.flg & B)?"al, ": "ax, ");
  677.         strcat(p+WID_PTR, (pIcode->ic.ll.flg & I)? strHex(pIcode->ic.ll.immed.op): "dx");
  678.         break;
  679.  
  680.     case iOUT:
  681.         strcpy(p+WID_PTR, (pIcode->ic.ll.flg & I)? strHex(pIcode->ic.ll.immed.op): "dx");
  682.         strcat(p+WID_PTR, (pIcode->ic.ll.flg & B)?", al": ", ax");
  683.         break;
  684.  
  685.     default:
  686.         buf[eop] = '\0';
  687.         break;
  688.     }
  689.  
  690.     /* Comments */
  691.     if (pIcode->ic.ll.flg & SYNTHETIC)
  692.     {
  693.         fImpure = FALSE;
  694.     }
  695.     else
  696.     {
  697.         for (j = pIcode->ic.ll.label, fImpure = 0; j > 0 && j < (Int)nextInst; 
  698.              j++)
  699.         {
  700.             fImpure |= BITMAP(j, BM_DATA);
  701.         }
  702.     }
  703.  
  704.  
  705.     /* Check for user supplied comment */
  706.     selectTable(Comment);
  707.     if (readVal(cbuf, pIcode->ic.ll.label, 0))
  708.     {
  709.         buf[strlen(buf)] = ' ';             /* Removes the null */
  710.         buf[POS_CMT] = ';';
  711.         strcpy(buf+POS_CMT+1, cbuf);
  712.     }
  713.  
  714.     else if (fImpure || (pIcode->ic.ll.flg & (SWITCH | CASE | SEG_IMMED | 
  715.                 IMPURE | SYNTHETIC | TERMINATES)))
  716.     {
  717.         buf[strlen(buf)] = ' ';
  718.         buf[POS_CMT] = '\0';
  719.         if (pIcode->ic.ll.flg & CASE)
  720.         {
  721.             sprintf(buf+POS_CMT, ";Case l%ld", pIcode->ic.ll.caseTbl.numEntries);
  722.         }
  723.         if (pIcode->ic.ll.flg & SWITCH)
  724.         {
  725.             strcat(buf, ";Switch ");
  726.         }
  727.         if (fImpure)
  728.         {
  729.             strcat(buf, ";Accessed as data ");
  730.         }
  731.         if (pIcode->ic.ll.flg & IMPURE)
  732.         {
  733.             strcat(buf, ";Impure operand ");
  734.         }
  735.         if (pIcode->ic.ll.flg & SEG_IMMED)
  736.         {
  737.             strcat(buf, ";Segment constant");
  738.         }
  739.         if (pIcode->ic.ll.flg & TERMINATES)
  740.         {
  741.             strcat(buf, ";Exit to DOS");
  742.         }
  743.     }
  744.  
  745.     /* Comment on iINT icodes */
  746.     if (pIcode->ic.ll.opcode == iINT)
  747.         writeIntComment (pIcode, buf);    
  748.  
  749.     /* Display output line */
  750.     if (! (pIcode->ic.ll.flg & SYNTHETIC))
  751.     {
  752.         if (fWindow)
  753.         {
  754.             word off;
  755.             char szOffset[6];
  756.  
  757.             off = (word)(pIcode->ic.ll.label - ((dword)pProc->state.r[rCS] << 4));
  758.             attrSet(attr);
  759.             
  760.             sprintf(szOffset, "%04X ", off);
  761.             printfd(szOffset);
  762.             printfd(buf);
  763.             dis_newline();
  764.             attrSet(A_NORMAL);
  765.         }
  766.         else if (pass == 3)        /* output to .b code buffer */ 
  767.             appendStrTab (&cCode.code, "%s\n", buf);
  768.         else                    /* output to .a1 or .a2 file */
  769.             fprintf (fp, "%03ld %06lX %s\n", i, pIcode->ic.ll.label, buf);
  770.     }
  771.     else        /* SYNTHETIC instruction */
  772.     {
  773.         strcat (buf, ";Synthetic inst");
  774.         if (fWindow)
  775.         {
  776.             printfd("     ");
  777.             printfd(buf);
  778.             dis_newline();
  779.         }
  780.         else if (pass == 3)        /* output to .b code buffer */
  781.         {
  782.             appendStrTab (&cCode.code, "%s\n", buf);
  783.         }
  784.         else                    /* output to .a1 or .a2 file */
  785.         {
  786.             fprintf (fp, "%03ld        %s\n", i, buf);
  787.         }
  788.     }
  789. }
  790.  
  791.  
  792.  
  793. /****************************************************************************
  794.  * formatRM
  795.  ***************************************************************************/
  796. static void formatRM(char *p, flags32 flg, PMEM pm)
  797. {
  798.     char    seg[4];
  799.  
  800.     if (pm->segOver)
  801.     {
  802.         strcat(strcpy(seg, szWreg[pm->segOver - rAX]), ":");
  803.     }
  804.     else    *seg = '\0';
  805.  
  806.     if (pm->regi == 0)
  807.     {
  808.         sprintf(p,"%s[%s]", seg, strHex((dword)pm->off));
  809.     }
  810.  
  811.     else if (pm->regi == (INDEXBASE - 1))
  812.     {
  813.         strcpy (p, "tmp");
  814.     }
  815.  
  816.     else if (pm->regi < INDEXBASE)
  817.     {
  818.         strcpy(p, (flg & B)? szBreg[pm->regi - rAL]: szWreg[pm->regi - rAX]);
  819.     }
  820.     
  821.     else if (pm->off)
  822.     {
  823.         if (pm->off < 0)
  824.         {
  825.             sprintf(p,"%s[%s-%s]", seg, szIndex[pm->regi - INDEXBASE],
  826.                      strHex((dword)(- pm->off)));
  827.         }
  828.         else
  829.         {
  830.             sprintf(p,"%s[%s+%s]", seg, szIndex[pm->regi - INDEXBASE],
  831.                      strHex((dword)pm->off));
  832.         }
  833.     }
  834.     else    sprintf(p,"%s[%s]", seg, szIndex[pm->regi - INDEXBASE]);
  835. }
  836.  
  837.  
  838. /*****************************************************************************
  839.  * strDst
  840.  ****************************************************************************/
  841. static char *strDst(flags32 flg, PMEM pm)
  842. {
  843.     static char buf[30];
  844.  
  845.     /* Immediates to memory require size descriptor */
  846.     if ((flg & I) && (pm->regi == 0 || pm->regi >= INDEXBASE))
  847.     {
  848.         memcpy(buf, szPtr[flg & B], WID_PTR);
  849.     }
  850.     else
  851.     {
  852.         memset(buf, ' ', WID_PTR);
  853.     }
  854.  
  855.     formatRM(buf + WID_PTR, flg, pm);
  856.     return buf;
  857. }
  858.  
  859.  
  860. /****************************************************************************
  861.  * strSrc                                                                   *
  862.  ****************************************************************************/
  863. static char *strSrc(PICODE pc)
  864. {
  865.     static char buf[30] = {", "};
  866.  
  867.     if (pc->ic.ll.flg & I)
  868.         strcpy(buf + 2, strHex(pc->ic.ll.immed.op));
  869.     else if (pc->ic.ll.flg & IM_SRC)        /* level 2 */
  870.         strcpy (buf + 2, "dx:ax");
  871.     else
  872.         formatRM(buf + 2, pc->ic.ll.flg, &pc->ic.ll.src);
  873.  
  874.     return buf;
  875. }
  876.  
  877.  
  878. /****************************************************************************
  879.  * strHex                                                                   *
  880.  ****************************************************************************/
  881. static char *strHex(dword d)
  882. {
  883.     static char buf[10];
  884.  
  885.     d &= 0xFFFF;
  886.     sprintf(buf, "0%lX%s", d, (d > 9)? "h": "");
  887.     return (buf + (buf[1] <= '9'));
  888. }
  889.  
  890.  
  891.  
  892.  
  893.  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
  894.  
  895. <           Interactive Disassembler and Associated Routines                >
  896.  
  897.  \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  898.  
  899.  
  900.  
  901. dword   pcTop;                  /* Image offset of top line */
  902. Int     icTop;                  /* Icode index  of top line */
  903. dword   pcCur;                  /* Image offset of cursor */
  904. dword    oldPcCur;                /* As above, before latest command */
  905. Int     icCur;                  /* Icode index  of cursor */
  906. dword   pcBot;                  /* Image offset of bottom line */
  907. Int     icBot;                  /* Icode index  of bottom line */
  908. dword   pcLast;                 /* Image offset of last instr in proc */
  909. int     NSCROLL;                /* Number of limes to scroll. Pseudo constant */
  910.  
  911. /* Paint the title line */
  912. void dispTitle(void)
  913. {
  914.     char buf[80];
  915.  
  916.     move(0, 0);                    /* Must move before setting attributes */
  917.     attrSet(A_BOLD);
  918.     sprintf(buf, "Proc %s at %06lX (%04X:%04X): %d bytes of parameters ",
  919.         pProc->name, pProc->Icode.GetFirstIcode()->ic.ll.label,
  920.         pProc->state.r[rCS],
  921.         (word)(pProc->Icode.GetFirstIcode()->ic.ll.label - ((dword)(pProc->state.r[rCS]) << 4)),
  922.         pProc->cbParam);
  923.     printfd(buf);
  924.     if (pProc->flg & PROC_ISLIB) printfd(" LIBRARY");
  925.     attrSet(A_NORMAL);
  926. }
  927.  
  928.  
  929. /****************************************************************************
  930. *           updateScr - update the screen                                    *
  931.  ****************************************************************************/
  932. /* bNew is true if must recalculate the top line */
  933. void
  934. updateScr(boolT bNew)
  935. {
  936.     int y, x;
  937.     Int i, ic;
  938.  
  939.     bNew |= (pcCur > pcBot) || (pcCur < pcTop);
  940.     if (bNew)
  941.     {
  942.         /* We need to redo the screen completely */
  943.         erase();
  944.         dispTitle();
  945.         icTop = icCur;
  946.         for (x=0; x < NSCROLL; x++)
  947.         {
  948.             if (icTop && pc[icTop-1].ic.ll.label + 
  949.                 (dword)pc[icTop-1].ic.ll.numBytes == pc[icTop].ic.ll.label)
  950.             {
  951.                 /* Then this instruction is contiguous with the current */
  952.                 icTop--;
  953.             }
  954.             else break;
  955.         }
  956.         pcTop = pc[icTop].ic.ll.label;
  957.     }
  958.     else
  959.     {
  960.         dispTitle();
  961.     }
  962.  
  963.     move(1, 0);
  964.     nextInst = pcTop;
  965.     for (y=1, ic=icTop; y < LINES-1; ic++, y++)
  966.     {
  967.         if ((ic >= numIcode) || (nextInst != pc[ic].ic.ll.label))
  968.         {
  969.             if (labelSrch(pc, numIcode, nextInst, &i))
  970.             {
  971.                 ic = i;
  972.             }
  973.             else 
  974.             {
  975.                 pcLast = pc[ic-1].ic.ll.label;    /* Remember end of proc */
  976.                 break;                      /* Must be past last */
  977.             }
  978.         }
  979.  
  980.         /* Save pc of current line. Last assignment will be pc of bott line */
  981.         pcBot = nextInst;
  982.         icBot = ic;
  983.  
  984.         // Only have to repaint if screen is new, or repainting formerly highlighted
  985.         // line, or newly highlighted line
  986.         if (bNew || (pcCur == nextInst) || (oldPcCur == nextInst))
  987.             dis1Line(ic, TRUE, (char)((pcCur == nextInst) ? A_REVERSE : A_NORMAL), 0);
  988.  
  989.         if (ic == numIcode-1)
  990.         {
  991.             switch (pc[ic].ic.ll.opcode)
  992.             {
  993.                 case iJMP:  case iJMPF:
  994.                 case iRET:  case iRETF:
  995.                 case iIRET:
  996.                 break;
  997.  
  998.                 default:
  999.                 /* We have other than a break of control flow instruction
  1000.                     at the end of the proc. Parse more instructions to
  1001.                     complete the basic block
  1002.                 */
  1003.                 if ((ic = checkScanned(nextInst)) == -1)
  1004.                 {
  1005.                     /* Some error. */
  1006.                     pcLast = pcCur;    /* Remember end of proc */
  1007.                     break;             /* Must be past last */
  1008.                 }
  1009.  
  1010.             }
  1011.         }
  1012.     }
  1013.     dis_show();            /* Make it happen */
  1014. }
  1015.  
  1016. #if 0
  1017. /* An opcode based version of updateScr() */
  1018. /****************************************************************************
  1019. *           updateScrOp - update the screen                                  *
  1020.  ****************************************************************************/
  1021. /* bNew is true if must recalculate the top line */
  1022. void
  1023. updateScrOp(boolT bNew)
  1024. {
  1025.     int y, x;
  1026.     dword pc;
  1027.     word len;
  1028.  
  1029.     dispTitle();
  1030.     if (bNew || (pcCur > pcBot) || (pcCur < pcTop))
  1031.     {
  1032.         /* We need to redo the screen completely */
  1033.         pcTop = pcCur;
  1034.     }
  1035.  
  1036.     move(1, 0);
  1037.     for (y=1, pc = pcTop; y < LINES-1;)
  1038.     {
  1039.         /* Save pc of current line. Last assignment will be pc of bott line */
  1040.         pcBot = pc;
  1041.  
  1042.         dis1LineOp(pc, TRUE, (pcCur == pc) ? A_REVERSE : A_NORMAL, &len,
  1043.             pProc);
  1044.         pc += len;
  1045.         getyx(stdscr, y, x);
  1046.     }
  1047.  
  1048.     refresh();
  1049. }
  1050.  
  1051. #endif
  1052.  
  1053. void pushPosStack(void)
  1054. {
  1055.     /* Push the current position on the position stack */
  1056.     posStack[iPS].ic = icCur;
  1057.     posStack[iPS++].pProc = pProc;
  1058. }
  1059.  
  1060. void popPosStack(void)
  1061. {
  1062.     /* Push the current position on the position stack */
  1063.     /* Note: relies on the byte wraparound. Beware! */
  1064.     if ((Int)(posStack[--iPS].pProc) != -1)
  1065.     {
  1066.         if (posStack[iPS].pProc != pProc)
  1067.         {
  1068.             setProc(posStack[iPS].pProc);
  1069.         }
  1070.         icCur = posStack[iPS].ic;
  1071.         pcCur = pc[icCur].ic.ll.label;
  1072.     }
  1073.     else iPS++;                             /* Stack empty.. don't pop */
  1074. }
  1075.  
  1076.  
  1077. /* Check to see if there is an icode for given image offset.
  1078.     Scan it if necessary, adjusting the allocation of pc[] and pl[]
  1079.     if necessary. Returns -1 if an error, otherwise the icode offset
  1080. */
  1081. static Int
  1082. checkScanned(dword pcCur)
  1083. {
  1084.     Int i;
  1085.  
  1086.     /* First we check if the current icode is in range */
  1087.     /* A sanity check first */
  1088.     if (pcCur >= (dword)prog.cbImage)
  1089.     {
  1090.         /* Couldn't be! */
  1091.         return -1;
  1092.     }
  1093.  
  1094.     if (!labelSrch(pc, numIcode, pcCur, &i))
  1095.     {
  1096.         /* This icode does not exist yet. Tack it on the end of the existing */
  1097.         if (numIcode >= allocIcode)
  1098.         {
  1099.             allocIcode = numIcode + DELTA_ICODE;      /* Make space for this one, and a few more */
  1100.             pc = (PICODE)reallocVar(pc, allocIcode * sizeof(ICODE));
  1101.             /* It is important to clear the new icodes, to ensure that the type
  1102.                 is set to NOT_SCANNED */
  1103.             memset(&pc[numIcode], 0, (size_t)(allocIcode-numIcode)*sizeof(ICODE));
  1104.             pl = (Int*)reallocVar(pl, allocIcode * sizeof(Int));
  1105.             memset(&pl[numIcode], 0, (size_t)(allocIcode-numIcode)*sizeof(Int));
  1106.         }
  1107.         i = numIcode++;
  1108.     }
  1109.  
  1110.     if (pc[i].type == NOT_SCANNED)
  1111.     {
  1112.         /* This is a new icode not even scanned yet. Scan it now */
  1113.         /* Ignore most errors... at this stage */
  1114.         if (scan(pcCur, &pc[i]) == IP_OUT_OF_RANGE)
  1115.         {
  1116.             /* Something went wrong... just forget it */
  1117.             return -1;
  1118.         }
  1119.     }
  1120.  
  1121.     return i;
  1122. }
  1123.  
  1124.  
  1125.  
  1126.  
  1127.  
  1128. /* Set up to use the procedure proc */
  1129. /* This includes some important initialisations, allocations, etc that are
  1130.     normally done in disassem() */
  1131. static void
  1132. setProc(PPROC proc)
  1133. {
  1134.     Int i;
  1135.  
  1136.     pProc = proc;                           /* Keep in a static */
  1137.  
  1138.     /* Free old arrays, if any */
  1139.     if (pc) free(pc);
  1140.     if (pl) free(pl);
  1141.  
  1142.  
  1143.     /* Create temporary code array */
  1144.     numIcode = pProc->Icode.GetNumIcodes();
  1145.     cb = numIcode * sizeof(ICODE);
  1146.     // Mike: needs objectising
  1147.     pc = (PICODE)memcpy(allocMem(cb), pProc->Icode.GetFirstIcode(), (size_t)cb);
  1148.  
  1149.     /* Create label array to keep track of location => label name */
  1150.     pl = (Int*)memset(allocMem(numIcode * sizeof(Int)), 0,
  1151.         (size_t)(numIcode * sizeof(Int)));
  1152.  
  1153.     /* Bind jump offsets to labels */
  1154.     for (i = 0; i < numIcode; i++)
  1155.     {
  1156.         if ((pc[i].ic.ll.flg & I) && !(pc[i].ic.ll.flg & JMP_ICODE) &&
  1157.             JmpInst(pc[i].ic.ll.opcode))
  1158.         {
  1159.             /* Immediate jump instructions. Make dest an icode index */
  1160.             if (labelSrch(pc, numIcode, pc[i].ic.ll.immed.op, 
  1161.                           (Int *)&pc[i].ic.ll.immed.op))
  1162.             {
  1163.                 /* This icode is the target of a jump */
  1164.                 pc[pc[i].ic.ll.immed.op].ic.ll.flg |= TARGET;
  1165.                 pc[i].ic.ll.flg |= JMP_ICODE;   /* So its not done twice */
  1166.             }
  1167.             else
  1168.             {
  1169.                 /* This jump cannot be linked to a label */
  1170.                 pc[i].ic.ll.flg |= NO_LABEL;
  1171.             }
  1172.         }
  1173.     }
  1174.  
  1175.     /* Window initially scrolled with entry point on top */
  1176.     pcCur = pcTop = pProc->procEntry;
  1177.     labelSrch(pc, numIcode, pcCur, &icCur);
  1178.     /* pcLast is set properly in updateScr(), at least for now */
  1179.     pcLast = (dword)-1;
  1180.  
  1181. }
  1182.  
  1183. /****************************************************************************
  1184.  *          interactDis - interactive disassembler                          *
  1185.  ****************************************************************************/
  1186. void interactDis(PPROC initProc, Int initIC)
  1187. {
  1188.  
  1189.  
  1190. #ifdef __UNIX__
  1191.     printf("Sorry - interactive disasassembler option not available for Unix\n");
  1192.     return;
  1193. #else
  1194.     boolT   fInteract;
  1195.     int        nEsc = 0;        /* This cycles 0 1 2 for Esc [ X under Unix */
  1196.                             /* and 0 1 for NULL X under Dos */
  1197.     int     ch;
  1198.     Int     i;
  1199.     pProc = initProc;                       /* Keep copy of init proc */
  1200.     NSCROLL = max(3, LINES >> 3);           /* Number of lines to scroll */
  1201.  
  1202.     /* Allocate the position stack */
  1203.     posStack = (POSSTACK*)allocMem(256 * sizeof(POSSTACK));
  1204.     iPS = 0;
  1205.     memset(posStack, -1, 256 * sizeof(POSSTACK));
  1206.  
  1207.  
  1208.     /* Initialise the console interface, if required */
  1209.     initConsole();
  1210.  
  1211.     /* Initially, work on the given proc */
  1212.     setProc(initProc);
  1213.     if (initIC)
  1214.     {
  1215.         icCur = initIC;
  1216.         pcCur = pc[icCur].ic.ll.label;
  1217.     }
  1218.  
  1219.     /* Initialise the symbol table */
  1220.     createSymTables();
  1221.  
  1222.     strcpy(cbuf, "label");                  /* Provide a default label string */
  1223.  
  1224.     updateScr(TRUE);
  1225.  
  1226.     fInteract = TRUE;
  1227.     while (fInteract)
  1228.     {
  1229.         ch = ::_getch();            // Mike: need a Unix equivalent of getch()!
  1230. #ifdef __MSDOS__
  1231.         if (nEsc)
  1232.         {
  1233.             ch += EXT;        /* Got the NULL before, so this is extended */
  1234.             nEsc = 0;
  1235.         }
  1236.         else if (ch == 0)
  1237.         {
  1238.             nEsc = 1;        /* Got one escape (actually, NULL) char */
  1239.             break;
  1240.         }
  1241. #endif
  1242. #ifdef __UNIX__
  1243.         switch (nEsc)
  1244.         {
  1245.             case 1:            /* Already got one escape */
  1246.                 if (ch == '[')
  1247.                 {
  1248.                     nEsc++;        /* Got 2 chars in the escape sequence */
  1249.                     break;
  1250.                 }
  1251.                 else
  1252.                 {
  1253.                     /* Escape something else. Ignore */
  1254.                     nEsc = 0;
  1255.                 }
  1256.                 break;
  1257.             case 2:
  1258.                 /* Already got Esc [ ... */
  1259.                 ch += EXT;        /* Make it an extended key */
  1260.                 nEsc = 0;        /* Reset the escape state */
  1261.                 break;
  1262.             case 0:
  1263.                 /* No escapes... yet */
  1264.                 if (ch == 0x1B)
  1265.                 {
  1266.                     nEsc++;        /* That's one escape... */
  1267.                     break;
  1268.                 }
  1269.         }
  1270. #endif
  1271.  
  1272. // For consoles, we get a 0xE0 then KEY_DOWN for the normal down arrow character.
  1273. // We simply ignore the 0xE0; this has the effect that the numeric keypad keys
  1274. // work as well (regardless of numlock state).
  1275.         oldPcCur = pcCur;
  1276.         switch (ch)
  1277.         {
  1278.             case KEY_DOWN:
  1279.  
  1280.                 if (pcCur >= pcLast) continue;  /* Ignore it */
  1281.                 pcCur += pc[icCur].ic.ll.numBytes;
  1282.                 labelSrch(pc, numIcode, pcCur, &icCur);
  1283.                 if (pcCur >= pcBot)
  1284.                 {
  1285.                     int j;
  1286.  
  1287.                     /* We have gone past the bottom line. Scroll a few lines */
  1288.                     for (j=0; j < NSCROLL; j++)
  1289.                     {
  1290.                         if (pcTop >= pcLast)
  1291.                         {
  1292.                             break;
  1293.                         }
  1294.                         pcTop += pc[icTop].ic.ll.numBytes;
  1295.                         if (labelSrch(pc, numIcode, pcTop, &i))
  1296.                             icTop = i;
  1297.                         else break;         /* Some problem... no more scroll */
  1298.                     }
  1299.                 }
  1300.                 updateScr(FALSE);
  1301.                 break;
  1302.  
  1303.             case KEY_UP:
  1304.                 /* First simply try the prev icode */
  1305.                 if ((icCur == 0) ||
  1306.                     pc[--icCur].ic.ll.label + (dword)pc[icCur].ic.ll.numBytes != pcCur)
  1307.                 {
  1308.                     for (i = 0; i < numIcode; i++)
  1309.                     {
  1310.                         if (pc[i].ic.ll.label + (dword)pc[i].ic.ll.numBytes == pcCur)
  1311.                         {
  1312.                             break;          /* This is the one! */
  1313.                         }
  1314.                     }
  1315.                     if (pc[i].ic.ll.label + pc[i].ic.ll.numBytes != pcCur)
  1316.                         break;              /* Not found. Sorry! */
  1317.                     icCur = i;
  1318.                 }
  1319.                 pcCur = pc[icCur].ic.ll.label;
  1320.                 updateScr(FALSE);
  1321.                 break;
  1322.  
  1323.  
  1324.             case '2':        /* Think up a better key... */
  1325.                 /* As for right arrow, but considers source operand first */
  1326.                 if  (pc[icCur].ic.ll.src.off != 0)
  1327.                 {
  1328.                     pushPosStack();
  1329.                     pcCur = pc[icCur].ic.ll.src.off;
  1330.                     if (!labelSrch(pc, numIcode, pcCur, &icCur))
  1331.                         break;
  1332.                     updateScr(FALSE);
  1333.                 }
  1334.                 /* Fall through to KEY_RIGHT processing */
  1335.  
  1336.             case KEY_RIGHT:
  1337.                 if (pc[icCur].ic.ll.flg & I)
  1338.                 {
  1339.                     if ((pc[icCur].ic.ll.opcode >= iJB) &&
  1340.                         (pc[icCur].ic.ll.opcode <= iJMPF))
  1341.                     {
  1342.                         /* An immediate jump op. Jump to it */
  1343.                         pushPosStack();
  1344.                         if (pc[icCur].ic.ll.flg & JMP_ICODE)
  1345.                         {
  1346.                             /* immed.op is an icode offset */
  1347.                             icCur = pc[icCur].ic.ll.immed.op;
  1348.                             pcCur = pc[icCur].ic.ll.label;
  1349.                         }
  1350.                         else
  1351.                         {
  1352.                             /* immed.op is still an image offset.
  1353.                                 Quite likely we need to scan */
  1354.                             pcCur = pc[icCur].ic.ll.immed.op;
  1355.                             if ((icCur = checkScanned(pcCur)) == -1)
  1356.                                 break;
  1357.                         }
  1358.                     }
  1359.                     else if ((pc[icCur].ic.ll.opcode == iCALL) ||
  1360.                              (pc[icCur].ic.ll.opcode == iCALLF))
  1361.                     {
  1362.                         /* The dest is a pointer to a proc struct */
  1363.                         // First check that the procedure has icodes (e.g. may be
  1364.                         // a library function, or just not disassembled yet)
  1365.                         PPROC pp = (PPROC)pc[icCur].ic.ll.immed.op;
  1366.                         if (pp->Icode.GetFirstIcode() != NULL)
  1367.                         {
  1368.                             pushPosStack();
  1369.                             setProc(pp);
  1370.                         }
  1371.                     }
  1372.                     else
  1373.                     {
  1374.                         /* Other immediate */
  1375.                         pushPosStack();
  1376.                         pcCur = pc[icCur].ic.ll.immed.op;
  1377.                         dispData(pProc->state.r[rDS]);
  1378.                         break;
  1379.                     }
  1380.                 }
  1381.                 else if (pc[icCur].ic.ll.dst.off != 0)
  1382.                 {
  1383.                     pushPosStack();
  1384.                     pcCur = pc[icCur].ic.ll.dst.off;
  1385.                     if (!labelSrch(pc, numIcode, pcCur, &icCur))
  1386.                     {
  1387.                         dispData(pProc->state.r[rDS]);
  1388.                         break;
  1389.                     }
  1390.                 }
  1391.                 else if (pc[icCur].ic.ll.src.off != 0)
  1392.                 {
  1393.                     pushPosStack();
  1394.                     pcCur = pc[icCur].ic.ll.src.off;
  1395.                     if (!labelSrch(pc, numIcode, pcCur, &icCur))
  1396.                     {
  1397.                         dispData(pProc->state.r[rDS]);
  1398.                         break;
  1399.                     }
  1400.                 }
  1401.                 updateScr(TRUE);
  1402.                 break;
  1403.  
  1404.             case KEY_LEFT:
  1405.                 popPosStack();
  1406.                 pcCur = pc[icCur].ic.ll.label;
  1407.                 updateScr(TRUE);
  1408.                 break;
  1409.                 
  1410.  
  1411.             case KEY_NPAGE:
  1412.                 pcCur = pcTop = pcBot;      /* Put bottom line at top now */
  1413.                 icCur = icTop = icBot;
  1414.                 updateScr(FALSE);
  1415.                 break;
  1416.  
  1417.             case KEY_PPAGE:
  1418.                 pcTop -= (LINES-2) * 2; /* Average of 2 bytes per inst */
  1419.                 for (i = 0; i < numIcode; i++)
  1420.                 {
  1421.                     if  ((pc[i].ic.ll.label <= pcTop) &&
  1422.                          (pc[i].ic.ll.label + (dword)pc[i].ic.ll.numBytes >= pcTop))
  1423.                     {
  1424.                         break;          /* This is the spot! */
  1425.                     }
  1426.                 }
  1427.                 if (i >= numIcode)
  1428.                 {
  1429.                     /* Something went wrong. Goto to first icode */
  1430.                     i = 0;
  1431.                 }
  1432.                 icCur = icTop = i;
  1433.                 pcCur = pcTop = pc[i].ic.ll.label;
  1434.                 updateScr(FALSE);
  1435.                 break;
  1436.  
  1437.             case 'l':                       /* Add a symbolic label here */
  1438.             {
  1439.                 char    *pStr;
  1440.  
  1441.                 move(LINES, 0);
  1442.                 printf("Enter symbol: ");
  1443.                 gets(cbuf);         /* Get a string to buf */
  1444.                 move (LINES, 0);
  1445.                 printf("%50c", ' ');
  1446.  
  1447.                 if (strlen(cbuf) >= SYMLEN)
  1448.                 {
  1449.                     /* Name too ling. Truncate */
  1450.                     cbuf[SYMLEN-1] = '\0';
  1451.                 }
  1452.                 pStr = addStrTbl(cbuf);     /* Add to the string table */
  1453.  
  1454.                 selectTable(Label);         /* Select the label table */
  1455.                 /* Add the symbol to both value- and symbol- hashed tables */
  1456.                 enterSym(pStr, pcCur, pProc, TRUE);
  1457.  
  1458.                 if (icCur == 0)
  1459.                 {
  1460.                     /* We are at the first icode of a function.
  1461.                         Assume it is the entry point, and rename the function */
  1462.                     strcpy(pProc->name, cbuf);
  1463.                 }
  1464.  
  1465.                 updateScr(FALSE);
  1466.                 break;
  1467.             }
  1468.  
  1469.             case ';':
  1470.             {
  1471.                 char    *pStr;
  1472.                 word w;
  1473.  
  1474.                 if (findVal(pcCur, 0, &w))
  1475.                 {
  1476.                     readVal(cbuf, pcCur, 0);/* Make it the default string */
  1477.                     deleteVal(pcCur, 0, FALSE);
  1478.                 }
  1479.                 else
  1480.                 {
  1481.                     cbuf[0] = '\0';             /* Remove prev string */
  1482.                 }
  1483.  
  1484.                 /* Enter a comment here, from a window */
  1485.                 move(LINES, 0);
  1486.                 printf("Enter comment: ");
  1487.                 gets(cbuf);                    /* Get a string to buf */
  1488.                 move(LINES, 0);
  1489.                 printf("%50c", ' ');
  1490.  
  1491.                 pStr = addStrTbl(cbuf);     /* Add to the string table */
  1492.  
  1493.                 selectTable(Comment);
  1494.                 enterSym(pStr, pcCur, pProc, FALSE);/* Add the symbol */
  1495.  
  1496.                 updateScr(FALSE);
  1497.                 break;
  1498.             }
  1499.                 
  1500.  
  1501.             case 'X' & 0x1F:                /* Control X; can't use Alt with Unix */
  1502.                 fInteract = FALSE;          /* Exit interactive mode */
  1503.                 attrSet(A_NORMAL);            /* Normal attributes */
  1504.                 break;
  1505.         }
  1506.     }
  1507.  
  1508.     free(posStack);
  1509.     destroySymTables();
  1510. #endif            // #ifdef unix
  1511. }
  1512.  
  1513.  
  1514. /****************************************************************************
  1515.  *          Display the current image position as data                      *
  1516.  ****************************************************************************/
  1517. static void
  1518. dispData(word dataSeg)
  1519. {
  1520.     int y, c, i;
  1521.     Int pc, pcStart;
  1522.     Int off = (Int)dataSeg << 4;
  1523.     char szOffset[6], szByte[4];
  1524.  
  1525.     if (pcCur >= (dword)prog.cbImage)
  1526.     {
  1527.         /* We're at an invalid address. Use 0x100 instead */
  1528.         pcCur = 0;
  1529.     }
  1530.     erase();
  1531.     dispTitle();
  1532.  
  1533.     pcStart = pc = pcCur;           /* pc at start of line */
  1534.     for (y=1; y < LINES-1; y++)
  1535.     {
  1536.         move (y, 1);
  1537.         sprintf(szOffset, "%04lX ", pc);
  1538.         printfd(szOffset);
  1539.         for (i=0; i < 16; i++)
  1540.         {
  1541.             sprintf(szByte, "%02X ", prog.Image[pc++ + off]);
  1542.             printfd(szByte);
  1543.             if ((pc + off) > prog.cbImage) break;
  1544.         }
  1545.         pc = pcStart;
  1546.         for (i=0; i < 16; i++)
  1547.         {
  1548.             c = prog.Image[pc++ + off];
  1549.             if ((c < 0x20) || (c > 0x7E))
  1550.             {
  1551.                 c = '.';
  1552.             }
  1553.             szByte[0] = (char)c;
  1554.             szByte[1] = '\0';
  1555.             printfd(szByte);
  1556.             if ((pc + off) > prog.cbImage) break;
  1557.         }
  1558.         dis_newline();
  1559.         pcStart = pc;
  1560.  
  1561.         if ((pc + off) > prog.cbImage) break;
  1562.  
  1563. /*       getyx(stdscr, y, x);    */
  1564.     }
  1565.  
  1566. }
  1567.  
  1568.  
  1569. boolT callArg(word off, char *sym)
  1570. {
  1571.     dword   imageOff;
  1572.     PPROC   p, pPrev;
  1573.  
  1574.     imageOff = off + ((dword)pProc->state.r[rCS] << 4);
  1575.     /* Search procedure list for one with appropriate entry point */
  1576.     for (p = pProcList; p && p->procEntry != imageOff; p = p->next)
  1577.     {
  1578.         pPrev = p;
  1579.     }
  1580.  
  1581.     if (p == 0)
  1582.     {
  1583.         /* No existing proc entry */
  1584.         LibCheck(p);
  1585.         if (p->flg & PROC_ISLIB)
  1586.         {
  1587.             /* No entry for this proc, but it is a library function.
  1588.                 Create an entry for it */
  1589.             p = (PPROC)memset(allocStruc(PROCEDURE), 0, sizeof(PROCEDURE));
  1590.             pPrev->next = p;
  1591.             p->procEntry = imageOff;
  1592.         }
  1593.     }
  1594.  
  1595.     if (p)
  1596.     {
  1597.         /* We have a proc entry for this procedure. Copy the name */
  1598.         strcpy(sym, p->name);
  1599.         return TRUE;
  1600.     }
  1601.  
  1602.     return FALSE;
  1603.  
  1604. }
  1605.  
  1606. /* Handle the floating point opcodes (icode iESC) */
  1607. static void flops(PICODE pIcode)
  1608. {
  1609.     char bf[30];
  1610.     byte op = (byte)pIcode->ic.ll.immed.op;
  1611.  
  1612.     /* Note that op is set to the escape number, e.g.
  1613.         esc 0x38 is FILD */
  1614.  
  1615.     if ((pIcode->ic.ll.dst.regi == 0) || (pIcode->ic.ll.dst.regi >= INDEXBASE))
  1616.     {
  1617.         /* The mod/rm mod bits are not set to 11 (i.e. register).
  1618.            This is the normal floating point opcode */
  1619.         strcpy(&buf[POS_OPC], szFlops1[op]);
  1620.         buf[strlen(buf)] = ' ';
  1621.  
  1622.         if ((op == 0x29) || (op == 0x1F))
  1623.         {
  1624.             strcpy(bf, "tbyte ptr ");
  1625.         }
  1626.         else switch (op & 0x30)
  1627.         {
  1628.             case 0x00:
  1629.             case 0x10:
  1630.                 strcpy(bf, "dword ptr ");
  1631.                 break;
  1632.             case 0x20:
  1633.                 strcpy(bf, "qword ptr ");
  1634.                 break;
  1635.             case 0x30:
  1636.                 switch (op)
  1637.                 {
  1638.                     case 0x3C:       /* FBLD */
  1639.                     case 0x3E:       /* FBSTP */
  1640.                         strcpy(bf, "tbyte ptr ");
  1641.                         break;
  1642.                     case 0x3D:       /* FILD 64 bit */
  1643.                     case 0x3F:       /* FISTP 64 bit */
  1644.                         strcpy(bf, "qword ptr ");
  1645.                         break;
  1646.  
  1647.                     default:
  1648.                         strcpy(bf, "word  ptr ");
  1649.                         break;
  1650.                 }
  1651.         }
  1652.  
  1653.         formatRM(bf + 10, pIcode->ic.ll.flg, &pIcode->ic.ll.dst);
  1654.         strcpy(p, bf);
  1655.     }
  1656.     else
  1657.     {
  1658.         /* The mod/rm mod bits are set to 11 (i.e. register).
  1659.            Could be specials (0x0C-0x0F, etc), or the st(i) versions of
  1660.            normal opcodes. Because the opcodes are slightly different for
  1661.            this case (e.g. op=04 means FSUB if reg != 3, but FSUBR for
  1662.            reg == 3), a separate table is used (szFlops2). */
  1663.         switch (op)
  1664.         {
  1665.             case 0x0C:
  1666.                 strcpy(&buf[POS_OPC], szFlops0C[pIcode->ic.ll.dst.regi - rAX]);
  1667.                 break;
  1668.             case 0x0D:
  1669.                 strcpy(&buf[POS_OPC], szFlops0D[pIcode->ic.ll.dst.regi - rAX]);
  1670.                 break;
  1671.             case 0x0E:
  1672.                 strcpy(&buf[POS_OPC], szFlops0E[pIcode->ic.ll.dst.regi - rAX]);
  1673.                 break;
  1674.             case 0x0F:
  1675.                 strcpy(&buf[POS_OPC], szFlops0F[pIcode->ic.ll.dst.regi - rAX]);
  1676.                 break;
  1677.             case 0x15:
  1678.                 strcpy(&buf[POS_OPC], szFlops15[pIcode->ic.ll.dst.regi - rAX]);
  1679.                 break;
  1680.             case 0x1C:
  1681.                 strcpy(&buf[POS_OPC], szFlops1C[pIcode->ic.ll.dst.regi - rAX]);
  1682.                 break;
  1683.             case 0x33:
  1684.                 strcpy(&buf[POS_OPC], szFlops33[pIcode->ic.ll.dst.regi - rAX]);
  1685.                 break;
  1686.             case 0x3C:
  1687.                 strcpy(&buf[POS_OPC], szFlops3C[pIcode->ic.ll.dst.regi - rAX]);
  1688.                 break;
  1689.             default:
  1690.                 strcpy(&buf[POS_OPC], szFlops2[op]);
  1691.                 buf[strlen(buf)] = ' ';
  1692.                 if ((op >= 0x20) && (op <= 0x27))
  1693.                 {
  1694.                     /* This is the ST(i), ST form. */
  1695.                     sprintf(&buf[POS_OPR2], "ST(%d),ST", pIcode->ic.ll.dst.regi - rAX);
  1696.                 }
  1697.                 else 
  1698.                 {
  1699.                     /* ST, ST(i) */
  1700.                     sprintf(&buf[POS_OPR2], "ST,ST(%d)", pIcode->ic.ll.dst.regi - rAX);
  1701.                 }
  1702.  
  1703.                 break;
  1704.         }
  1705.     }
  1706. }
  1707.  
  1708.  
  1709.