]> pd.if.org Git - mmurtl/blob - mscode16/dumprun/dumprun.c
autocommit for file dated 1994-12-31 12:23:54
[mmurtl] / mscode16 / dumprun / dumprun.c
1 /* Dumprun.c  Dumps the contents of a MMURTL Run file (DLL or Device Driver*/\r
2 \r
3 \r
4 #define U32 unsigned long\r
5 #define S32 long\r
6 #define U16 unsigned int\r
7 #define S16 int\r
8 #define U8 unsigned char\r
9 #define S8 char\r
10 \r
11 #define TRUE 1\r
12 #define FALSE 1\r
13 \r
14 #include <ctype.h>\r
15 #include <stdio.h>\r
16 #include <string.h>\r
17 #include <stdlib.h>\r
18 #include "runfile.h"\r
19 \r
20 /* disassembler data */\r
21 \r
22 #include "uproto.h"\r
23 \r
24 int seg_size = 32;              /* set to 32 for /3 option */\r
25 int fRaw = 0;                   /* dump raw byte too? */\r
26 int nRaw;\r
27 U8 RawBuf[10];\r
28 \r
29 S32  addrIn;\r
30 U32 fEOF = 0;\r
31 \r
32 /*  The Intel 386 Software Writers Guide provides a table that uses the\r
33 following codes to assist in manual disassembly of 386 code. The\r
34 letters below are the same as the codes in the manual.  The % (vertical\r
35 bar is an escape character - like in c - to signify expansion of the codes is\r
36 required when the string is being outut.\r
37 */\r
38 \r
39 char *opmap1[] = {\r
40 /* 0 */\r
41   "ADD %Eb,%Gb", "ADD %Ev,%Gv",  "ADD %Gb,%Eb", "ADD %Gv,%Ev",\r
42   "ADD AL,%Ib",  "ADD %eAX,%Iv", "PUSH ES",     "POP ES",\r
43   "OR %Eb,%Gb",  "OR %Ev,%Gv",   "OR %Gb,%Eb",  "OR %Gv,%Ev",\r
44   "OR AL,%Ib",   "OR %eAX,%Iv",  "PUSH CS",     "%2 ",\r
45 /* 1 */\r
46   "ADC %Eb,%Gb", "ADC %Ev,%Gv",  "ADC %Gb,%Eb", "ADC %Gv,%Ev",\r
47   "ADC AL,%Ib",  "ADC %eAX,%Iv", "PUSH SS",     "POP SS",\r
48   "SBB %Eb,%Gb", "SBB %Ev,%Gv",  "SBB %Gb,%Eb", "SBB %Gv,%Ev",\r
49   "SBB AL,%Ib",  "SBB %eAX,%Iv", "PUSH DS",     "POP DS",\r
50 /* 2 */\r
51   "AND %Eb,%Gb", "AND %Ev,%Gv",  "AND %Gb,%Eb", "AND %Gv,%Ev",\r
52   "AND AL,%Ib",  "AND %eAX,%Iv", "%pE",         "DAA",\r
53   "SUB %Eb,%Gb", "SUB %Ev,%Gv",  "SUB %Gb,%Eb", "SUB %Gv,%Ev",\r
54   "SUB AL,%Ib",  "SUB %eAX,%Iv", "%pC",         "DAS",\r
55 /* 3 */\r
56   "XOR %Eb,%Gb", "XOR %Ev,%Gv",  "XOR %Gb,%Eb", "XOR %Gv,%Ev",\r
57   "XOR AL,%Ib",  "XOR %eAX,%Iv", "%pS",         "AAA",\r
58   "CMP %Eb,%Gb", "CMP %Ev,%Gv",  "CMP %Gb,%Eb", "CMP %Gv,%Ev",\r
59   "CMP AL,%Ib",  "CMP %eAX,%Iv", "%pD",         "AAS",\r
60 /* 4 */\r
61   "INC %eAX",    "INC %eCX",     "INC %eDX",    "INC %eBX",\r
62   "INC %eSP",    "INC %eBP",     "INC %eSI",    "INC %eDI",\r
63   "DEC %eAX",    "DEC %eCX",     "DEC %eDX",    "DEC %eBX",\r
64   "DEC %eSP",    "DEC %eBP",     "DEC %eSI",    "DEC %eDI",\r
65 /* 5 */\r
66   "PUSH %eAX",   "PUSH %eCX",    "PUSH %eDX",   "PUSH %eBX",\r
67   "PUSH %eSP",   "PUSH %eBP",    "PUSH %eSI",   "PUSH %eDI",\r
68   "POP %eAX",    "POP %eCX",     "POP %eDX",    "POP %eBX",\r
69   "POP %eSP",    "POP %eBP",     "POP %eSI",    "POP %eDI",\r
70 /* 6 */\r
71   "PUSHA",       "POPA",         "BOUND %Gv,%Ma", "ARPL %Ew,%Rw",\r
72   "%pF",         "%pG",          "%so",           "%sa",\r
73   "PUSH %Iv",    "IMUL %Gv=%Ev*%Iv", "PUSH %Ib",  "IMUL %Gv=%Ev*%Ib",\r
74   "INSB %Yb,DX", "INS%ew %Yv,DX", "OUTSB DX,%Xb", "OUTS%ew DX,%Xv",\r
75 /* 7 */\r
76   "JO %Jb",      "JNO %Jb",       "JC %Jb",       "JNC %Jb",\r
77   "JZ %Jb",      "JNZ %Jb",       "JBE %Jb",      "JNBE %Jb",\r
78   "JS %Jb",      "JNS %Jb",       "JPE %Jb",      "JPO %Jb",\r
79   "JL %Jb",      "JGE %Jb",       "JLE %Jb",      "JG %Jb",\r
80 /* 8 */\r
81   "%g1 %Eb,%Ib",  "%g1 %Ev,%Iv",  "MOV AL,%Ib",   "%g1 %Ev,%Ib",\r
82   "TEST %Eb,%Gb", "TEST %Ev,%Gv", "XCHG %Eb,%Gb", "XCHG %Ev,%Gv",\r
83   "MOV %Eb,%Gb",  "MOV %Ev,%Gv",  "MOV %Gb,%Eb",  "MOV %Gv,%Ev",\r
84   "MOV %Ew,%Sw",  "LEA %Gv,%M ",  "MOV %Sw,%Ew",  "POP %Ev",\r
85 /* 9 */\r
86   "NOP",            "XCHG %eAX,%eCX", "XCHG %eAX,%eDX", "XCHG %eAX,%eBX",\r
87   "XCHG %eAX,%eSP", "XCHG %eAX,%eBP", "XCHG %eAX,%eSI", "XCHG %eAX,%eDI",\r
88   "CBW",            "CDW",            "CALL %Ap",       "FWAIT",\r
89   "PUSH %eflags",   "POP %eflags",    "SAHF",           "LAHF",\r
90 /* a */\r
91   "MOV AL,%Ov",     "MOV %eAX,%Ov",     "MOV %Ov,al",    "MOV %Ov,%eAX",\r
92   "MOVSB %Xb,%Yb",  "MOVS%ew %Xv,%Yv",  "CMPSB %Xb,%Yb", "CMPS%ew %Xv,%Yv",\r
93   "TEST AL,%Ib",    "TEST %eAX,%Iv",    "STOSB %Yb,AL",  "STOS%ew %Yv,%eAX",\r
94   "LODSB AL,%Xb",   "LODS%ew %eAX,%Xv", "SCASB AL,%Xb",  "SCAS%ew %eAX,%Xv",\r
95 /* b */\r
96   "MOV AL,%Ib",   "MOV CL,%Ib",   "MOV DL,%Ib",   "MOV BL,%Ib",\r
97   "MOV AH,%Ib",   "MOV CH,%Ib",   "MOV DH,%Ib",   "MOV BH,%Ib",\r
98   "MOV %eAX,%Iv", "MOV %eCX,%Iv", "MOV %eDX,%Iv", "MOV %eBX,%Iv",\r
99   "MOV %eSP,%Iv", "MOV %eBP,%Iv", "MOV %eSI,%Iv", "MOV %eDI,%Iv",\r
100 /* c */\r
101   "%g2 %Eb,%Ib",   "%g2 %Ev,%Ib",  "RET %Iw",      "RET",\r
102   "LES %Gv,%Mp",   "LDS %Gv,%Mp",  "MOV %Eb,%Ib",  "MOV %Ev,%Iv",\r
103   "ENTER %Iw,%Ib", "LEAVE",        "RETF %Iw",     "RETF",\r
104   "INT 3",         "INT %Ib",      "INTO",         "IRET",\r
105 /* d */\r
106   "%g2 %Eb,1", "%g2 %Ev,1", "%g2 %Eb,cl", "%g2 %Ev,cl",\r
107   "AAM", "AAD", 0, "XLAT",\r
108 \r
109 /*\r
110   "ESC 0,%Ib", "ESC 1,%Ib", "ESC 2,%Ib", "ESC 3,%Ib",\r
111   "ESC 4,%Ib", "ESC 5,%Ib", "ESC 6,%Ib", "ESC 7,%Ib",\r
112 */\r
113 \r
114   "%f0", "%f1", "%f2", "%f3",\r
115   "%f4", "%f5", "%f6", "%f7",\r
116 \r
117 \r
118 /* e */\r
119   "LOOPNE %Jb", "LOOPE %Jb", "LOOP %Jb", "JCXZ %Jb",\r
120   "IN AL,%Ib", "IN %eAX,%Ib", "OUT %Ib,AL", "OUT %Ib,%eAX",\r
121   "CALL %Jv", "JMP %Jv", "JMP %Ap", "JMP %Jb",\r
122   "IN AL,DX", "IN %eAX,DX", "OUT DX,AL", "OUT DX,%eAX",\r
123 /* f */\r
124   "LOCK%p ", 0, "REPNE%p ", "REP(e)%p ",\r
125   "HLT", "CMC", "%g3", "%g0",\r
126   "CLC", "STC", "CLI", "STI",\r
127   "CLD", "STD", "%g4", "%g5"\r
128   };\r
129 \r
130 char *SecOp00[] = {\r
131 /* 0 */\r
132   "%g6", "%g7", "LAR %Gv,%Ew", "LSL %Gv,%Ew", 0, 0, "CLTS", 0,\r
133   0, 0, 0, 0, 0, 0, 0, 0 };\r
134 \r
135 char *SecOp20[] = {\r
136 /* 2 */\r
137   "MOV %Rd,%Cd", "MOV %Rd,%Dd", "MOV %Cd,%Rd", "MOV %Dd,%Rd",\r
138   "MOV %Rd,%Td", 0, "MOV %Td,%Rd", 0,\r
139   0, 0, 0, 0, 0, 0, 0, 0};\r
140 \r
141 char *SecOp80[] = {\r
142   "JO %Jv", "JNO %Jv", "JC %Jv",  "JNC %Jv",            /*RAB  Rev JNC /JC */\r
143   "JZ %Jv", "JNZ %Jv", "JBE %Jv", "JNBE %Jv",\r
144   "JS %Jv", "JNS %Jv", "JPE %Jv", "JPO %Jv",\r
145   "JL %Jv", "JGE %Jv", "JLE %Jv", "JG %Jv",\r
146 /* 9 */\r
147   "SETO %Eb", "SETNO %Eb", "SETNC %Eb", "SETC %Eb",\r
148   "SETZ %Eb", "SETNZ %Eb", "SETBE %Eb", "SETNBE %Eb",\r
149   "SETS %Eb", "SETNS %Eb", "SETP %Eb", "SETNP %Eb",\r
150   "SETL %Eb", "SETGE %Eb", "SETLE %Eb", "SETG %Eb",\r
151 /* a */\r
152   "PUSH FS",          "POP FS",          0,          "BT %Ev,%Gv",\r
153   "SHLD %Ev,%Gv,%Ib", "SHLD %Ev,%Gv,cl", 0,           0,\r
154   "PUSH GS",          "POP GS",          0,          "BTS %Ev,%Gv",\r
155   "SHRD %Ev,%Gv,%Ib", "SHRD %Ev,%Gv,cl", 0,          "IMUL %Gv,%Ev",\r
156 \r
157 /* b */\r
158   0,             0,            "LSS %Mp",       "BTR %Ev,%Gv",\r
159   "LFS %Mp",    "LGS %Mp",     "MOVZX %Gv,%Eb", "MOVZX %Gv,%Ew",\r
160   0,             0,            "%g8 %Ev,%Ib",   "BTC %Ev,%Gv",\r
161   "BSF %Gv,%Ev", "BSR%Gv,%Ev", "MOVSX %Gv,%Eb", "MOVSX %Gv,%Ew",\r
162   };\r
163 \r
164 /* NOTE: Second byte of 2 byte OpCodes are Invalid if Over 0xBF */\r
165 \r
166 \r
167 char *groups[9][8] = {   /* group 0 is group 3 for %Ev set */\r
168   { "TEST %Ev,%Iv", "TEST %Ev,%Iv,", "NOT %Ev", "NEG %Ev",\r
169     "MUL %eAX,%Ev", "IMUL %eAX,%Ev", "DIV %eAX,%Ev", "IDIV %eAX,%Ev" },\r
170   { "ADD", "OR", "ADC", "SBB", "AND", "SUB", "XOR", "CMP" },\r
171   { "ROL", "ROR", "RCL", "RCR", "SHL", "SHR", "SHL", "SAR" },\r
172   { "TEST %Eb,%Ib", "TEST %Eb,%Ib,", "NOT %Eb", "NEG %Eb",\r
173     "MUL AL,%Eb", "IMUL AL,%Eb", "DIV AL,%Eb", "IDIV AL,%Eb" },\r
174   { "INC %Eb", "DEC %Eb", 0, 0, 0, 0, 0, 0 },\r
175   { "INC %Ev", "DEC %Ev", "CALL %Ev", "CALL %Ep",\r
176     "JMP %Ev", "JMP %Ep", "PUSH %Ev", 0 },\r
177   { "SLDT %Ew", "STR %Ew", "LLDT %Ew", "LTR %Ew",\r
178     "VERR %Ew", "VERW %Ew", 0, 0 },\r
179   { "SGDT %Ms", "SIDT %Ms", "LGDT %Ms", "LIDT %Ms",\r
180     "SMSW %Ew", 0, "LMSW %Ew", 0 },\r
181   { 0, 0, 0, 0, "BT", "BTS", "BTR", "BTC" }\r
182   };\r
183 \r
184         /* for display */\r
185 char *seg_names[]= {"ES","CS","SS","DS","FS","GS"};\r
186 char *breg_names[]={"AL","CL","DL","BL","AH","CH","DH","BH" };\r
187 char *wreg_names[]={"AX","CX","DX","BX","SP","BP","SI","DI" };\r
188 char *dreg_names[]={"EAX","ECX","EDX","EBX","ESP","EBP","ESI","EDI" };\r
189 \r
190 S16 prefix;\r
191 U8 modrmv;\r
192 S8 fmodrmv;\r
193 U8 sibv;\r
194 S8 fsibv;\r
195 S16 opsize;\r
196 S16 addrsize;\r
197 \r
198 \r
199 /* Run file data */\r
200 \r
201 char *pCode, *pData, *pStack;   /* Ptrs in User mem to load to */\r
202 long sCode,   sData,  sStack;   /* Size of segments */\r
203 unsigned long oCode, oData;             /* Offset in file to Code & Data */\r
204 unsigned long offCode, offData; /* Virtual Offset for Code & Data Segs */\r
205 unsigned long nCDFIX, oCDFIX,\r
206                           nCCFIX, oCCFIX,\r
207                           nDDFIX, oDDFIX,\r
208                           nDCFIX, oDCFIX;\r
209 \r
210 char *pStart;\r
211 \r
212 struct tagtype tag;\r
213 \r
214 FILE *run_fh   = 0;             /* Current .RUN, .DLL, or .DDR (output) */\r
215 FILE *out_fh   = 0;             /* Output file */\r
216 \r
217 char runname[40];\r
218 char outname[40];\r
219 \r
220 char fUASM = 0;\r
221 char fDumpData = 0;\r
222 char fOutFile = 0;\r
223 \r
224 /*********************************************\r
225   Dumps all bytes pointed to to stream with\r
226   offset printed in front of each line.\r
227 */\r
228 \r
229 void Dump(long cb)\r
230 {\r
231 U32 i, val, addr;\r
232 U16 j;\r
233 unsigned char buff[17];\r
234 unsigned char line[78]; /* Addr xx xx xx xx... ASCII */\r
235 \r
236         addr = 0;\r
237 \r
238         while (cb) {\r
239                 if (cb > 15)\r
240                         j=16;\r
241                 else\r
242                         j = cb;\r
243 \r
244                 sprintf(line, "%08lX   ", addr);        /* print current offset */\r
245 \r
246                 fread (buff, 1, j, run_fh);             /* Read j bytes from stream */\r
247 \r
248                 for (i=0; i<j; i++) {\r
249                         val = buff[i];\r
250                         sprintf(&line[11 + (i*3)], "%02lX ", val);\r
251                         if (buff[i] < 0x20)\r
252                                 buff[i] = 0x2E;\r
253                         if (buff[i] > 0x7F)\r
254                                 buff[i] = 0x2E;\r
255                         line[i+61] = buff[i];   /* printed char */\r
256                 }\r
257                 line[59] = 0x20;\r
258                 line[60] = 0x20;\r
259                 line[i+61] = 0;\r
260 \r
261                 fprintf(out_fh, "%s\r\n", line);        /* put in chars */\r
262 \r
263                 addr += j;\r
264                 cb -=j;\r
265         }\r
266         return;\r
267 }\r
268 \r
269 \r
270 \r
271 /*****************************************************\r
272 Gets a byte to disassemble saving the raw bytes that\r
273 make it up in RawBuf[nRaw].\r
274 ******************************************************/\r
275 \r
276 U8 getbyte(void)\r
277 {\r
278 S32 i;\r
279 U8 b;\r
280 \r
281 i=fgetc(run_fh);\r
282 if (i==EOF) fEOF = 1;\r
283 b = i & 0xff;\r
284 if (fRaw)\r
285         RawBuf[nRaw++] = b;\r
286 addrIn++;\r
287 return b;\r
288 }\r
289 \r
290 \r
291 /*************************************************/\r
292 /* Get Mod/RM field byte for current instruction */\r
293 \r
294 U8 modrm(void)\r
295 {\r
296   if (!fmodrmv) {\r
297     modrmv = getbyte();\r
298     fmodrmv = 1;\r
299     }\r
300   return modrmv;\r
301 }\r
302 \r
303 \r
304 /*************************************************/\r
305 /* Get 'scale-index-base' byte for current instruction */\r
306 \r
307 U8 sib(void)\r
308 {\r
309   if (!fsibv) {\r
310     sibv = getbyte();\r
311     fsibv = 1;\r
312     }\r
313   return sibv;\r
314 }\r
315 \r
316 /**********************************************************/\r
317 /* Macros to shift or mask a byte so bit type data such as\r
318    reg or mod can be pulled out of certain instruction\r
319    bytes.\r
320 */\r
321 \r
322 #define mod(a)  (((a)>>6)&7)\r
323 #define reg(a)  (((a)>>3)&7)\r
324 #define rm(a)   ((a)&7)\r
325 #define ss(a)   (((a)>>6)&7)\r
326 #define indx(a) (((a)>>3)&7)\r
327 #define base(a) ((a)&7)\r
328 \r
329 /*------------------------------------------------------------------------*/\r
330 \r
331 /**************************************\r
332 * Write a decimal number to a file fout\r
333 ***************************************/\r
334 \r
335 void put_num(U32 value, FILE *fout)\r
336 {\r
337 S8   stack[10];\r
338 register U16 i;\r
339 \r
340         if(value & 0x80000000) {\r
341                 fputc('-', fout);\r
342                 value = -value; }\r
343         i = 0;\r
344         do\r
345                 stack[i++] = (value % 10) + '0';\r
346         while(value /= 10);\r
347         while(i) {\r
348                 fputc(stack[--i], fout);\r
349                 }\r
350 }\r
351 \r
352 /**************************************\r
353   Write a Hex byte to a file fout.\r
354 ***************************************/\r
355 \r
356 void put_hexb(U8 value, FILE *fout)\r
357 {\r
358 S8  stack[10];\r
359 U16 i, j;\r
360 \r
361         i = 0; j = 2;\r
362         do {\r
363                 stack[i] = (value % 16) + '0';\r
364                 if (stack[i] > 0x39)\r
365             stack[i] += 7;\r
366                 i++;\r
367                 }\r
368         while(value /= 16);\r
369         while (i < j--) {                       /* zero pad front end to width */\r
370                 fputc('0', fout);\r
371                 }\r
372         while(i) {\r
373                 fputc(stack[--i], fout);\r
374                 }\r
375 }\r
376 \r
377 /**************************************\r
378   Write a Hex number to a file fout.\r
379 ***************************************/\r
380 \r
381 void put_hexw(U16 value, FILE *fout)\r
382 {\r
383 S8  stack[10];\r
384 U16 i, j;\r
385 \r
386         i = 0;\r
387         j = 4;\r
388         do {\r
389                 stack[i] = (value % 16) + '0';\r
390                 if (stack[i] > 0x39)\r
391             stack[i] += 7;\r
392                 i++;\r
393                 }\r
394         while(value /= 16);\r
395         while (i < j--) {                       /* zero pad front end to width */\r
396                 fputc('0', fout);\r
397                 }\r
398         while(i) {\r
399                 fputc(stack[--i], fout);\r
400                 }\r
401 }\r
402 \r
403 /**************************************\r
404   Write a hex dword to a file fout.\r
405 ***************************************/\r
406 \r
407 void put_hexd(U32 value, FILE *fout)\r
408 {\r
409 S8  stack[10];\r
410 U16 i, j;\r
411 \r
412         i = 0;\r
413         j = 8;\r
414         do {\r
415                 stack[i] = (value % 16) + '0';\r
416                 if (stack[i] > 0x39)\r
417             stack[i] += 7;\r
418                 i++;\r
419                 }\r
420         while(value /= 16);\r
421         while (i < j--) {                       /* zero pad front end to width */\r
422                 fputc('0', fout);\r
423                 }\r
424         while(i) {\r
425                 fputc(stack[--i], fout);\r
426                 }\r
427 }\r
428 \r
429 /*------------------------------------------------------------------------*/\r
430 /* determines how many bytes left in the instruction from the\r
431   letter in the table (which is passed in here).  "v" is a variable\r
432   number based on current segment size of code descriptor.\r
433 */\r
434 \r
435 int bytes(char c)\r
436 {\r
437   switch (c)\r
438   {\r
439     case 'b':\r
440       return 1;\r
441     case 'w':\r
442       return 2;\r
443     case 'd':\r
444       return 4;\r
445     case 'v':\r
446       if (opsize == 32)\r
447         return 4;\r
448       else\r
449         return 2;\r
450   }\r
451   return 0;\r
452 }\r
453 \r
454 /**************************************************************\r
455 Get the correct number of bytes for immediate data from the\r
456 code stream and output it as hex.\r
457 ***************************************************************/\r
458 \r
459 void ohex(char c, int extend, int optional, int defsize)\r
460 {\r
461 int n, s, i, j;\r
462 S32 delta;\r
463 unsigned char buf[6];\r
464 char *name;\r
465 \r
466   n=0;\r
467   s=0;\r
468 \r
469   switch (c)\r
470   {\r
471     case 'a':\r
472       break;\r
473     case 'b':   /* byte */\r
474       n = 1;\r
475       break;\r
476     case 'w':   /* word */\r
477       n = 2;\r
478       break;\r
479     case 'd':   /* dword */\r
480       n = 4;\r
481       break;\r
482     case 's':   /* fword */\r
483       n = 6;\r
484       break;\r
485     case 'c':\r
486     case 'v':\r
487       if (defsize == 32)\r
488         n = 4;\r
489       else\r
490         n = 2;\r
491       break;\r
492     case 'p':   /* 32 or 48 bit pointer */\r
493       if (defsize == 32)\r
494         n = 6;\r
495       else\r
496         n = 4;\r
497       s = 1;\r
498       break;\r
499   }\r
500 \r
501   for (i=0; i<n; i++)\r
502     buf[i] = getbyte();\r
503 \r
504   /* sign extend the value into a U32 */\r
505 \r
506   for (; i<extend; i++)\r
507     buf[i] = (buf[i-1] & 0x80) ? 0xff : 0;\r
508 \r
509   if (s)                /* outputs the segment value of FAR pointer */\r
510   {\r
511 \r
512         fprintf(out_fh,"%02X%02X",buf[n-1],buf[n-2]);\r
513 /*\r
514     put_hexb(buf[n-1], out_fh);\r
515     put_hexb(buf[n-2], out_fh);\r
516 */\r
517     n -= 2;\r
518   }\r
519 \r
520   if (extend > n)\r
521   {\r
522     if (!optional)\r
523         fprintf(out_fh,"+");\r
524         n = 4;\r
525   }\r
526   switch (n)\r
527   {\r
528     case 1: {\r
529                         fprintf(out_fh,"%02X",buf[0]);\r
530 /*              put_hexb(buf[0], out_fh); */\r
531                 break;\r
532                 }\r
533     case 2:     {\r
534                         fprintf(out_fh,"%02X%02X",buf[1],buf[0]);\r
535 /*              put_hexb(buf[1], out_fh);\r
536                 put_hexb(buf[0], out_fh);\r
537 */\r
538                 break;\r
539                 }\r
540     case 4:     {\r
541                         fprintf(out_fh,"%02X%02X%02X%02X",buf[3],buf[2],buf[1],buf[0]);\r
542 /*\r
543                 put_hexb(buf[3], out_fh);\r
544                 put_hexb(buf[2], out_fh);\r
545                 put_hexb(buf[1], out_fh);\r
546                 put_hexb(buf[0], out_fh);\r
547 */\r
548                 break;\r
549                 }\r
550   }\r
551 }\r
552 \r
553 /*------------------------------------------------------------------------*/\r
554 \r
555 void reg_name(U8 which, char size)\r
556 {\r
557   if (size == 'F')\r
558   {\r
559     fprintf(out_fh, "st(%d)",which);\r
560 \r
561     return;\r
562   }\r
563   if (((size == 'v') && (opsize == 32)) || (size == 'd'))\r
564   {\r
565     fprintf(out_fh,"E");\r
566   }\r
567   if (size == 'b')\r
568   {\r
569     fprintf(out_fh, "%s", breg_names[which]);\r
570   }\r
571   else\r
572   {\r
573     fprintf(out_fh, "%s", wreg_names[which]);\r
574   }\r
575 }\r
576 \r
577 /******************************************************************\r
578    This takes in a two chars that represent part of the op code and\r
579    puts out the proper text to match what the letter represents.\r
580    c is the first char after the dollar sign and t is next one. See\r
581    opcode1[] strings for what the chars mean.\r
582 *******************************************************************/\r
583 \r
584 void escape(char c, char t)\r
585 {\r
586   U32 v;\r
587   S32  delta, vofs, tmp;\r
588   S8 vofsb;\r
589   S16 vofsw;\r
590   char *name;\r
591   int extend;\r
592   U8 b2, w;\r
593 \r
594   extend = (addrsize == 32) ? 4 : 2;\r
595 \r
596   switch (c)\r
597   {\r
598     case 'A':                             /* Direct Address */\r
599             ohex(t, extend, 0, addrsize);\r
600             break;\r
601     case 'C':                             /* Reg of R/M picks control reg */\r
602                 fprintf(out_fh, "CR%d",reg(modrm()));\r
603             break;\r
604     case 'D':                             /* Reg of R/M pick debug reg */\r
605                 fprintf(out_fh, "DR%d",modrm());\r
606                 break;\r
607     case 'E':                             /* R/M picks operand */\r
608                 do_modrm(t);\r
609                 break;\r
610     case 'G':                             /* Reg of R/M picks general reg */\r
611                 if (t == 'F')\r
612                 reg_name(rm(modrm()), t);\r
613                 else\r
614                 reg_name(reg(modrm()), t);\r
615                 break;\r
616     case 'I':                             /* Immediate data */\r
617                 ohex(t, 0, 0, opsize);\r
618                 break;\r
619     case 'J':                             /* Relative IP offset */\r
620                 switch (bytes(t))\r
621                 {\r
622         case 1:\r
623           vofsb = getbyte();            /* must remian signed! */\r
624           vofs = vofsb;\r
625           break;\r
626         case 2:\r
627           vofsb = getbyte();        /*Must be Signed bytes/Words */\r
628           vofsw = getbyte()<<8;\r
629           vofs = vofsw + vofsb;\r
630           break;\r
631         case 4:\r
632           vofs = getbyte();\r
633           tmp = getbyte();\r
634           vofs |= tmp << 8;\r
635           tmp = getbyte();\r
636           vofs |= tmp << 16;\r
637           tmp = getbyte();\r
638           vofs |= tmp << 24;\r
639           break;\r
640                 }\r
641                 delta = addrIn + vofs;\r
642             fprintf(out_fh, "%08lX", delta);\r
643                 break;\r
644     case 'M':                             /* R/M picks memory */\r
645                 do_modrm(t);\r
646                 break;\r
647         case 'O':                             /* NO R/M, Offset only */\r
648                 expand_out("%p:[");\r
649                 ohex(t, extend, 0, addrsize);\r
650                 fprintf(out_fh,"]");\r
651                 break;\r
652     case 'R':                             /* Mod of R/M pick REG only */\r
653                 do_modrm(t);\r
654                 break;\r
655     case 'S':                             /* Reg of R/M picks seg reg */\r
656             fprintf(out_fh, "%s", seg_names[reg(modrm())]);\r
657                 break;\r
658     case 'T':                             /* Reg of R/M picks test reg */\r
659                 fprintf(out_fh, "TR%d",modrm());\r
660                 break;\r
661     case 'X':                             /* DS:ESI */\r
662                 fprintf(out_fh,"DS:[");\r
663                 if (addrsize == 32)\r
664                 fprintf(out_fh,"E");\r
665                 fprintf(out_fh,"SI]");\r
666                 break;\r
667         case 'Y':                             /* ES:EDI */\r
668                 fprintf(out_fh,"ES:[");\r
669                 if (addrsize == 32)\r
670                         fprintf(out_fh,"E");\r
671                 fprintf(out_fh,"DI]");\r
672                 break;\r
673     case '2':                             /* Prefix of 2 byte opcode */\r
674                 b2 = getbyte();\r
675                 if (b2 < 0x10)\r
676                         expand_out(SecOp00[b2]);\r
677                 else if ((b2 > 0x1F) && (b2 < 0x30))\r
678                         expand_out(SecOp20[b2-0x20]);\r
679                 else if ((b2 > 0x7F) && (b2 < 0xC0))\r
680                         expand_out(SecOp80[b2-0x80]);\r
681                 else\r
682                     fprintf(out_fh, "<invalid>");\r
683                 break;\r
684         case 'e':                 /* If "USE32" t is part of reg name */\r
685                 if (opsize == 32)\r
686                 {\r
687                         if (t == 'w')     /* put out "d" if t is "w" on USE32 segs*/\r
688                                 fprintf(out_fh,"D");\r
689                         else\r
690                         {\r
691                           fprintf(out_fh,"E");  /* put out "E" if not t <> "w" then put t */\r
692                           fputc(t, out_fh);\r
693                         }\r
694                 }\r
695                 else {\r
696                         fputc(t, out_fh);    /* when USE16 just put out esc char */\r
697                 }\r
698                 break;\r
699     case 'f':                /* floating point */\r
700             fprintf(out_fh,"<Float Op>");\r
701 \r
702 /*              floating_point(t-'0');  */\r
703 \r
704                 break;\r
705     case 'g':                             /* do R/M group 'n' */\r
706                 expand_out(groups[t-'0'][reg(modrm())]);\r
707                 break;\r
708     case 'p':                             /* Segment prefix */\r
709                 switch (t)\r
710                 {\r
711                 case 'C':                         /* CS */\r
712                 case 'D':                         /* DS */\r
713                 case 'E':                         /* ES */\r
714                 case 'F':                         /* FS */\r
715                 case 'G':                         /* GS */\r
716                 case 'S':                         /* SS */\r
717                   prefix = t;\r
718           expand_out(opmap1[getbyte()]);\r
719           break;\r
720                 case ':':\r
721           if (prefix) {\r
722                 fputc(prefix, out_fh);\r
723                 fprintf(out_fh,"S:");\r
724           }\r
725           break;\r
726         case ' ':\r
727           expand_out(opmap1[getbyte()]);\r
728           break;\r
729                 }\r
730                 break;\r
731     case 's':                                                           /* Size override */\r
732                 switch (t)\r
733             {\r
734         case 'a':\r
735                         addrsize = 48 - addrsize;               /* a is address */\r
736                         expand_out(opmap1[getbyte()]);\r
737                         break;\r
738                 case 'o':                                                       /* o is operand */\r
739                   opsize = 48 - opsize;\r
740                   expand_out(opmap1[getbyte()]);\r
741                   break;\r
742             }\r
743             break;\r
744   }\r
745 }\r
746 \r
747 \r
748 /******************************************\r
749 This expands and outputs the instruction\r
750 string passed in if it find the escape\r
751 character (vertical bar).\r
752 ******************************************/\r
753 \r
754 void expand_out(char *s)\r
755 {\r
756   int i;\r
757   char c;\r
758 \r
759   if (s == 0)                   /* if NULL pointer, then it's BAD */\r
760   {\r
761     fprintf(out_fh,"<invalid>");\r
762   }\r
763   while ((c = *s++) != 0)       /* put next char in c */\r
764   {\r
765     if (c == '%')               /* if c is % then ESCAPE */\r
766     {\r
767       c = *s++;                 /* get letter representing value */\r
768       escape(c, *s++);\r
769     }\r
770     else\r
771       if (c == ' ')             /* if space, put TAB in string */\r
772                 fprintf(out_fh," ");\r
773       else {\r
774                 fputc(c, out_fh);            /* else put out the char found! */\r
775                 }\r
776   }\r
777 }\r
778 \r
779 \r
780 /* outputs 'scale-index-base' instructions */\r
781 \r
782 void do_sib(int m)\r
783 {\r
784   int s, i, b;\r
785   s = ss(sib());\r
786   i = indx(sib());\r
787   b = base(sib());\r
788   switch (b)\r
789   {\r
790     case 0: expand_out("%p:[EAX"); break;\r
791     case 1: expand_out("%p:[ECX"); break;\r
792     case 2: expand_out("%p:[EDX"); break;\r
793     case 3: expand_out("%p:[EBX"); break;\r
794     case 4: expand_out("%p:[ESP"); break;\r
795     case 5:\r
796       if (m == 0)\r
797       {\r
798         expand_out("%p:[");\r
799         ohex('d', 4, 0, addrsize);\r
800       }\r
801       else\r
802         expand_out("%p:[EBP");\r
803       break;\r
804     case 6: expand_out("%p:[ESI"); break;\r
805     case 7: expand_out("%p:[EDI"); break;\r
806   }\r
807   switch (i)\r
808   {\r
809     case 0: fprintf(out_fh,"+EAX"); break;\r
810     case 1: fprintf(out_fh,"+ECX"); break;\r
811     case 2: fprintf(out_fh,"+EDX"); break;\r
812     case 3: fprintf(out_fh,"+EBX"); break;\r
813     case 4: break;\r
814     case 5: fprintf(out_fh,"+EBP"); break;\r
815     case 6: fprintf(out_fh,"+ESI"); break;\r
816     case 7: fprintf(out_fh,"+EDI"); break;\r
817   }\r
818   if (i != 4)\r
819     switch (s)\r
820     {\r
821       case 0: break;\r
822       case 1: fprintf(out_fh,"*2"); break;\r
823       case 2: fprintf(out_fh,"*4"); break;\r
824       case 3: fprintf(out_fh,"*8"); break;\r
825 \r
826     }\r
827 }\r
828 /*------------------------------------------------------------------------*/\r
829 void do_modrm(char t)\r
830 {\r
831   int m;\r
832   int r;\r
833   int extend;\r
834 \r
835   m =  mod(modrm());\r
836   r = rm(modrm());\r
837   extend = (addrsize == 32) ? 4 : 2;\r
838 \r
839   if (m == 3)\r
840   {\r
841     reg_name(r, t);\r
842     return;\r
843   }\r
844   if ((m == 0) && (r == 5) && (addrsize == 32))\r
845   {\r
846     expand_out("%p:[");\r
847     ohex('d', extend, 0, addrsize);\r
848     fprintf(out_fh,"]");\r
849     return;\r
850   }\r
851   if ((m == 0) && (r == 6) && (addrsize == 16))\r
852   {\r
853     expand_out("%p:[");\r
854     ohex('w', extend, 0, addrsize);\r
855     fprintf(out_fh,"]");\r
856     return;\r
857   }\r
858   if ((addrsize != 32) || (r != 4))\r
859     expand_out("%p:[");\r
860   if (addrsize == 16)\r
861   {\r
862     switch (r)\r
863     {\r
864       case 0: fprintf(out_fh,"BX+SI"); break;\r
865       case 1: fprintf(out_fh,"BX+DI"); break;\r
866       case 2: fprintf(out_fh,"BP+SI"); break;\r
867       case 3: fprintf(out_fh,"BP+DI"); break;\r
868       case 4: fprintf(out_fh,"SI"); break;\r
869       case 5: fprintf(out_fh,"DI"); break;\r
870       case 6: fprintf(out_fh,"BP"); break;\r
871       case 7: fprintf(out_fh,"BX"); break;\r
872     }\r
873   }\r
874   else\r
875   {\r
876     switch (r)\r
877     {\r
878       case 0: fprintf(out_fh,"EAX"); break;\r
879       case 1: fprintf(out_fh,"ECX"); break;\r
880       case 2: fprintf(out_fh,"EDX"); break;\r
881       case 3: fprintf(out_fh,"EBX"); break;\r
882       case 4: do_sib(m); break;\r
883       case 5: fprintf(out_fh,"EBP"); break;\r
884       case 6: fprintf(out_fh,"ESI"); break;\r
885       case 7: fprintf(out_fh,"EDI"); break;\r
886     }\r
887   }\r
888   switch (m)\r
889   {\r
890     case 1:\r
891       ohex('b', extend, 0, addrsize);  /* was 1 */\r
892       break;\r
893     case 2:\r
894       fprintf(out_fh,"+");\r
895       ohex('v', extend, 0, addrsize);  /* was 1 */\r
896       break;\r
897   }\r
898   fprintf(out_fh,"]");\r
899 }\r
900 \r
901 /***********************************************\r
902   This disassembles one instruction each time it\r
903   is called.\r
904 ************************************************/\r
905 \r
906 U32 disassemble(void)\r
907 {\r
908   int    i;\r
909   char   *cmp, *brp;\r
910   U8     *wp;\r
911   U32    delta;\r
912   char   *name, *lname;\r
913 \r
914   prefix = 0;\r
915   fmodrmv = 0;\r
916   fsibv = 0;\r
917   nRaw = 0;\r
918   opsize = addrsize = seg_size;\r
919 \r
920   fprintf(out_fh, "%08lX   ", addrIn);\r
921 \r
922   expand_out(opmap1[getbyte()]);        /* decode instruction and output */\r
923 \r
924   if (fRaw) {\r
925      i = 0;\r
926          fprintf(out_fh, "            ");\r
927          while (nRaw--) {\r
928                 put_hexb(RawBuf[i++], out_fh);\r
929                 fprintf(out_fh, " ");\r
930          }\r
931   }\r
932 \r
933   fprintf(out_fh, "\r\n");\r
934   return addrIn;\r
935 }\r
936 \r
937 \r
938 /************************************************\r
939 * Write part of an instruction to the file "fi"\r
940 *************************************************/\r
941 \r
942 void put_str(char *ptr, FILE *fi)\r
943 {\r
944         while(*ptr)\r
945                 fputc(*ptr++, fi);\r
946 }\r
947 \r
948 /*******************************************\r
949 * Report a non-recoverable error\r
950 ********************************************/\r
951 \r
952 void fatal_error(char *string)\r
953 {\r
954         put_str(string, stderr);\r
955         put_str("Disassembly aborted\r\n", stderr);\r
956 \r
957         exit(-1);\r
958 }\r
959 \r
960 /*********************************************************\r
961   This reads and dumps a RUN file with complete tag field\r
962   descriptions and data.\r
963 *********************************************************/\r
964 \r
965 void DumpRunFile(FILE *fh)\r
966 {\r
967 int ii;\r
968 long i, dret, nPages, nobj;\r
969 char fDone, filetype, junk;\r
970 \r
971         addrIn = 0;     /* Default Address */\r
972         offCode = 0;    /* Default virtual code */\r
973         fDone = 0;\r
974         while (!fDone) {\r
975                 tag.id = 0;\r
976                 fprintf(out_fh, "\r\nFile LFA: %ld\r\n", ftell(fh));\r
977                 nobj = fread (&tag, 1, 5, fh);\r
978                 if (nobj) {\r
979                         ii = tag.id;\r
980                         fprintf(out_fh, "Tage Value  (hex): %02X\r\n", ii);\r
981                         fprintf(out_fh, "Tage Length (dec): %ld\r\n", tag.len);\r
982                 }\r
983                 else\r
984                         fDone = TRUE;\r
985                 switch (tag.id) {\r
986                         case IDTAG:\r
987                                 nobj = fread (&filetype, 1, 1, fh);\r
988                                 if (filetype == 1)\r
989                                         fprintf(out_fh, "File type: STANDARD RUN FILE\r\n");\r
990                                 else if (filetype == 2)\r
991                                         fprintf(out_fh, "File type: DYNAMIC LINK LIBRAY\r\n");\r
992                                 else if (filetype == 3)\r
993                                         fprintf(out_fh, "File type: DEVICE DRIVER\r\n");\r
994                                 else {\r
995                                         fprintf(out_fh, "File type: UNKNOWN (ID=%d)\r\n",filetype);\r
996                                         fDone = 1;\r
997                                 }\r
998                                 break;\r
999                         case SEGTAG:\r
1000                                 fprintf(out_fh, "Segment Sizes:\r\n");\r
1001                                 nobj = fread (&sStack, 1, 4, fh);\r
1002                                 if (nobj) nobj = fread (&sCode, 1, 4, fh);\r
1003                                 if (nobj) nobj = fread (&sData, 1, 4, fh);\r
1004                                 fprintf(out_fh, "  Stack   %ld\r\n", sStack);\r
1005                                 fprintf(out_fh, "  Code    %ld\r\n", sCode);\r
1006                                 fprintf(out_fh, "  Data    %ld\r\n", sData);\r
1007                                 break;\r
1008                         case DOFFTAG:\r
1009                                 nobj = fread (&offData, 1, 4, fh);\r
1010                                 fprintf(out_fh, "Virtual Data Offset: %08lXh\r\n", offData);\r
1011                                 break;\r
1012                         case COFFTAG:\r
1013                                 nobj = fread (&offCode, 1, 4, fh);\r
1014                                 fprintf(out_fh, "Virtual Code Offset: %08lXh\r\n", offCode);\r
1015                                 addrIn = offCode;       /* Virtual Address */\r
1016                                 break;\r
1017                         case STRTTAG:\r
1018                                 nobj = fread (&pStart, 1, 4, fh);\r
1019                                 fprintf(out_fh, "Start Address: %08lXh\r\n", pStart);\r
1020                                 break;\r
1021                         case CODETAG:\r
1022                                 fprintf(out_fh, "Code Segment Contents...\r\n");\r
1023                                 if (fUASM) {\r
1024                                         while ((disassemble() - offCode)  < tag.len);\r
1025                                  }\r
1026                                  else\r
1027                                         while (tag.len--)\r
1028                                                 nobj = fread (&junk, 1, 1, fh);\r
1029                                 break;\r
1030                         case DATATAG:\r
1031                                 fprintf(out_fh, "Data Segment Contents...\r\n");\r
1032                                 if (fDumpData) {\r
1033                                         Dump(tag.len);\r
1034                                 }\r
1035                                 else {\r
1036                                         while (tag.len--)\r
1037                                                 nobj = fread (&junk, 1, 1, fh);\r
1038                                 }\r
1039                                 break;\r
1040                         case CDFIXTAG:\r
1041                                 fprintf(out_fh, "CD Fixups - Refs to Data at CSeg offsets:\r\n");\r
1042                                 while ((tag.len) && (nobj)) {\r
1043                                         nobj = fread (&i, 1, 4, fh);\r
1044                                         tag.len-=4;\r
1045                                         fprintf(out_fh, "  Offset- %08lXh\r\n", i);\r
1046                                 }\r
1047                                 break;\r
1048                         case CCFIXTAG:\r
1049                                 fprintf(out_fh, "CC Fixups - Refs to Code at CSeg offsets:\r\n");\r
1050                                 while ((tag.len) && (nobj)) {\r
1051                                         nobj = fread (&i, 1, 4, fh);\r
1052                                         tag.len-=4;\r
1053                                         fprintf(out_fh, "  Offset- %08lXh\r\n", i);\r
1054                                 }\r
1055                                 break;\r
1056                         case DDFIXTAG:\r
1057                                 fprintf(out_fh, "DD Fixups - Refs to Data at DSeg offsets:\r\n");\r
1058                                 while ((tag.len) && (nobj)) {\r
1059                                         nobj = fread (&i, 1, 4, fh);\r
1060                                         tag.len-=4;\r
1061                                         fprintf(out_fh, "  Offset- %08lXh\r\n", i);\r
1062                                 }\r
1063                                 break;\r
1064                         case DCFIXTAG:\r
1065                                 fprintf(out_fh, "DD Fixups - Refs to Code at DSeg offsets:\r\n");\r
1066                                 while ((tag.len) && (nobj)) {\r
1067                                         nobj = fread (&i, 1, 4, fh);\r
1068                                         tag.len-=4;\r
1069                                         fprintf(out_fh, "  Offset- %08lXh\r\n", i);\r
1070                                 }\r
1071                                 break;\r
1072                         case ENDTAG:\r
1073                                 nobj = fread (&i, 1, 4, fh);\r
1074                                 fprintf(out_fh, "END Tag Value: %ld\r\n", i);\r
1075                                 fDone = TRUE;\r
1076                                 break;\r
1077                         default:\r
1078                                 while ((tag.len--) && (nobj))\r
1079                                         nobj = fread (&junk, 1, 1, fh);\r
1080                                 break;\r
1081                 }\r
1082         }\r
1083 }\r
1084 \r
1085 /***************************\r
1086 * Main program DUMPRUNFILE\r
1087 ****************************/\r
1088 \r
1089 void main(S16 argc, S8   *argv[])\r
1090 {\r
1091 S8   *ptr, *pname;\r
1092 S16 i, j, fdone;\r
1093 \r
1094         out_fh = 0;             /* default the list file */\r
1095 \r
1096         for(i=1; i < argc; ++i) {\r
1097                 ptr = argv[i];\r
1098                 if (*ptr == '/') {\r
1099                   ptr++;\r
1100                   switch(*ptr) {\r
1101                         case 'U' :                      /* UnAssemble Code */\r
1102                         case 'u' :\r
1103                                 fUASM = 1;\r
1104                                 break;\r
1105                         case 'D' :                      /* Dump Symbols */\r
1106                         case 'd' :\r
1107                                 fDumpData = 1;\r
1108                                 break;\r
1109                         case 'O' :                      /* Output Hex code with Unassembly */\r
1110                         case 'o' :\r
1111                                 fRaw = 1;\r
1112                                 break;\r
1113                         default:\r
1114                                 printf("Invalid option/swtich \n");\r
1115                                 if (run_fh)\r
1116                                         fclose(run_fh);\r
1117                                 exit(1);\r
1118                                 break;\r
1119                   }\r
1120                 }\r
1121                 else {\r
1122                         if(!run_fh) {\r
1123                                 strncpy(runname, argv[i], 39);\r
1124                                 run_fh = fopen(argv[i], "rb");\r
1125                         }\r
1126                         else if (!out_fh) {\r
1127                                 strncpy(outname, argv[i], 39);\r
1128                                 if(!(out_fh = fopen(argv[i], "w"))) {\r
1129                                   printf("Can't open OUTPUT file\n");\r
1130                                   exit(1);\r
1131                                 }\r
1132                                 fOutFile = 1;\r
1133                         }\r
1134                         else {\r
1135                                 printf("Too many options\n"); /* Too many parameters */\r
1136                                 exit(1);\r
1137                         }\r
1138             }\r
1139         }\r
1140 \r
1141 /* Input file not explicitly named errors out */\r
1142 \r
1143         if (!run_fh) {\r
1144                 printf("Usage: DumpRun  runfile  outputfile /U /D \r\n");\r
1145                 printf("/U = Unassemble Code segment\r\n");\r
1146                 printf("/O = Output code in hex with Unassembly (must use /U)\r\n");\r
1147                 printf("/D = Dump data segment contents in hex format\r\n");\r
1148                 printf("If outputfile isn't specifiled output is sent to screenr\r\n");\r
1149                 printf("Can't open RUNFILE.\n"); /* Can't open file */\r
1150                 exit(1);\r
1151         }\r
1152 \r
1153 /* Output file not explicitly named is set to stdout */\r
1154 \r
1155         if (!out_fh)\r
1156                 out_fh = stdout;\r
1157 \r
1158 \r
1159 if (fOutFile) {\r
1160         printf("DumpRunFile Ver x1.0 (c) R.A. Burgess 1993, 1994\r\n");\r
1161         printf("Dump being sent to file: %s \r\n\r\n", outname);\r
1162 }\r
1163 \r
1164 fprintf(out_fh, "DumpRunFile Ver x1.0 (c) R.A. Burgess 1993, 1994\r\n\r\n");\r
1165 \r
1166 DumpRunFile(run_fh);\r
1167 if (run_fh)\r
1168         fclose(run_fh);\r
1169 if (fOutFile)\r
1170         fclose(out_fh);\r
1171 exit(0);\r
1172 \r
1173 }\r
1174 \r
1175 /*********************** End of Module *****************/\r