NASM 0.98p3.5
[platform/upstream/nasm.git] / ndisasm.c
1 /* ndisasm.c   the Netwide Disassembler main module
2  *
3  * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4  * Julian Hall. All rights reserved. The software is
5  * redistributable under the licence given in the file "Licence"
6  * distributed in the NASM archive.
7  */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <errno.h>
14
15 #include "insns.h"
16 #include "nasm.h"
17 #include "nasmlib.h"
18 #include "sync.h"
19 #include "disasm.h"
20
21 #define BPL 8                          /* bytes per line of hex dump */
22
23 static const char *help =
24 "usage: ndisasm [-a] [-i] [-h] [-r] [-u] [-b bits] [-o origin] [-s sync...]\n"
25 "               [-e bytes] [-k start,bytes] [-p vendor] file\n"
26 "   -a or -i activates auto (intelligent) sync\n"
27 "   -u sets USE32 (32-bit mode)\n"
28 "   -b 16 or -b 32 sets number of bits too\n"
29 "   -h displays this text\n"
30 "   -r displays the version number\n"
31 "   -e skips <bytes> bytes of header\n"
32 "   -k avoids disassembling <bytes> bytes from position <start>\n"
33 "   -p selects the preferred vendor instruction set (intel, amd, cyrix)\n";
34
35 static void output_ins (unsigned long, unsigned char *, int, char *);
36 static void skip (unsigned long dist, FILE *fp);
37
38 int main(int argc, char **argv) 
39 {
40     unsigned char buffer[INSN_MAX * 2], *p, *q;
41     char outbuf[256];
42     char *pname = *argv;
43     char *filename = NULL;
44     unsigned long nextsync, synclen, initskip = 0L;
45     int lenread, lendis;
46     int autosync = FALSE;
47     int bits = 16;
48     int eof = FALSE;
49     unsigned long prefer = 0;
50     int rn_error;
51     long offset;
52     FILE *fp;
53
54     offset = 0;
55     init_sync();
56
57     while (--argc) {
58         char *v, *vv, *p = *++argv;
59         if (*p == '-' && p[1]) {
60             p++;
61             while (*p) switch (tolower(*p)) {
62               case 'a':                /* auto or intelligent sync */
63               case 'i':
64                 autosync = TRUE;
65                 p++;
66                 break;
67               case 'h':
68                 fprintf(stderr, help);
69                 return 0;
70               case 'r':
71                 fprintf(stderr, "NDISASM version " NASM_VER "\n");
72                 return 0;
73               case 'u':                /* USE32 */
74                 bits = 32;
75                 p++;
76                 break;
77               case 'b':                /* bits */
78                 v = p[1] ? p+1 : --argc ? *++argv : NULL;
79                 if (!v) {
80                     fprintf(stderr, "%s: `-b' requires an argument\n", pname);
81                     return 1;
82                 }
83                 if (!strcmp(v, "16"))
84                     bits = 16;
85                 else if (!strcmp(v, "32"))
86                     bits = 32;
87                 else {
88                     fprintf(stderr, "%s: argument to `-b' should"
89                             " be `16' or `32'\n", pname);
90                 }
91                 p = "";                /* force to next argument */
92                 break;
93               case 'o':                /* origin */
94                 v = p[1] ? p+1 : --argc ? *++argv : NULL;
95                 if (!v) {
96                     fprintf(stderr, "%s: `-o' requires an argument\n", pname);
97                     return 1;
98                 }
99                 offset = readnum (v, &rn_error);
100                 if (rn_error) {
101                     fprintf(stderr, "%s: `-o' requires a numeric argument\n",
102                             pname);
103                     return 1;
104                 }
105                 p = "";                /* force to next argument */
106                 break;
107               case 's':                /* sync point */
108                 v = p[1] ? p+1 : --argc ? *++argv : NULL;
109                 if (!v) {
110                     fprintf(stderr, "%s: `-s' requires an argument\n", pname);
111                     return 1;
112                 }
113                 add_sync (readnum (v, &rn_error), 0L);
114                 if (rn_error) {
115                     fprintf(stderr, "%s: `-s' requires a numeric argument\n",
116                             pname);
117                     return 1;
118                 }
119                 p = "";                /* force to next argument */
120                 break;
121               case 'e':                /* skip a header */
122                 v = p[1] ? p+1 : --argc ? *++argv : NULL;
123                 if (!v) {
124                     fprintf(stderr, "%s: `-e' requires an argument\n", pname);
125                     return 1;
126                 }
127                 initskip = readnum (v, &rn_error);
128                 if (rn_error) {
129                     fprintf(stderr, "%s: `-e' requires a numeric argument\n",
130                             pname);
131                     return 1;
132                 }
133                 p = "";                /* force to next argument */
134                 break;
135               case 'k':                /* skip a region */
136                 v = p[1] ? p+1 : --argc ? *++argv : NULL;
137                 if (!v) {
138                     fprintf(stderr, "%s: `-k' requires an argument\n", pname);
139                     return 1;
140                 }
141                 vv = strchr(v, ',');
142                 if (!vv) {
143                     fprintf(stderr, "%s: `-k' requires two numbers separated"
144                             " by a comma\n", pname);
145                     return 1;
146                 }
147                 *vv++ = '\0';
148                 nextsync = readnum (v, &rn_error);
149                 if (rn_error) {
150                     fprintf(stderr, "%s: `-k' requires numeric arguments\n",
151                             pname);
152                     return 1;
153                 }
154                 synclen = readnum (vv, &rn_error);
155                 if (rn_error) {
156                     fprintf(stderr, "%s: `-k' requires numeric arguments\n",
157                             pname);
158                     return 1;
159                 }
160                 add_sync (nextsync, synclen);
161                 p = "";                /* force to next argument */
162                 break;
163             case 'p':                  /* preferred vendor */
164                 v = p[1] ? p+1 : --argc ? *++argv : NULL;
165                 if (!v) {
166                     fprintf(stderr, "%s: `-p' requires an argument\n", pname);
167                     return 1;
168                 }
169                 if ( !strcmp(v, "intel") ) {
170                   prefer = 0;   /* Default */
171                 } else if ( !strcmp(v, "amd") ) {
172                   prefer = IF_AMD|IF_3DNOW;
173                 } else if ( !strcmp(v, "cyrix") ) {
174                   prefer = IF_CYRIX|IF_3DNOW;
175                 } else {
176                   fprintf(stderr, "%s: unknown vendor `%s' specified with `-p'\n", pname, v);
177                   return 1;
178                 }
179                 p = "";                /* force to next argument */
180                 break;
181             }
182         } else if (!filename) {
183             filename = p;
184         } else {
185             fprintf(stderr, "%s: more than one filename specified\n", pname);
186             return 1;
187         }
188     }
189
190     if (!filename) {
191         fprintf(stderr, help, pname);
192         return 0;
193     }
194
195     if (strcmp(filename, "-")) {
196         fp = fopen(filename, "rb");
197         if (!fp) {
198             fprintf(stderr, "%s: unable to open `%s': %s\n",
199                     pname, filename, strerror(errno));
200             return 1;
201         }
202     } else
203         fp = stdin;
204
205     if (initskip > 0)
206         skip (initskip, fp);
207
208     /*
209      * This main loop is really horrible, and wants rewriting with
210      * an axe. It'll stay the way it is for a while though, until I
211      * find the energy...
212      */
213
214     p = q = buffer;
215     nextsync = next_sync (offset, &synclen);
216     do {
217         unsigned long to_read = buffer+sizeof(buffer)-p;
218         if (to_read > nextsync-offset-(p-q))
219             to_read = nextsync-offset-(p-q);
220         if (to_read) {
221             lenread = fread (p, 1, to_read, fp);
222             if (lenread == 0)
223                 eof = TRUE;            /* help along systems with bad feof */
224         } else
225             lenread = 0;
226         p += lenread;
227         if (offset == nextsync) {
228             if (synclen) {
229                 printf("%08lX  skipping 0x%lX bytes\n", offset, synclen);
230                 offset += synclen;
231                 skip (synclen, fp);
232             }
233             p = q = buffer;
234             nextsync = next_sync (offset, &synclen);
235         }
236         while (p > q && (p - q >= INSN_MAX || lenread == 0)) {
237             lendis = disasm (q, outbuf, bits, offset, autosync, prefer);
238             if (!lendis || lendis > (p - q) ||
239                 lendis > nextsync-offset)
240                 lendis = eatbyte (q, outbuf);
241             output_ins (offset, q, lendis, outbuf);
242             q += lendis;
243             offset += lendis;
244         }
245         if (q >= buffer+INSN_MAX) {
246             unsigned char *r = buffer, *s = q;
247             int count = p - q;
248             while (count--)
249                 *r++ = *s++;
250             p -= (q - buffer);
251             q = buffer;
252         }
253     } while (lenread > 0 || !(eof || feof(fp)));
254
255     if (fp != stdin)
256         fclose (fp);
257
258     return 0;
259 }
260
261 static void output_ins (unsigned long offset, unsigned char *data,
262                         int datalen, char *insn) 
263 {
264     int bytes;
265     printf("%08lX  ", offset);
266
267     bytes = 0;
268     while (datalen > 0 && bytes < BPL) {
269         printf("%02X", *data++);
270         bytes++;
271         datalen--;
272     }
273
274     printf("%*s%s\n", (BPL+1-bytes)*2, "", insn);
275
276     while (datalen > 0) {
277         printf("         -");
278         bytes = 0;
279         while (datalen > 0 && bytes < BPL) {
280             printf("%02X", *data++);
281             bytes++;
282             datalen--;
283         }
284         printf("\n");
285     }
286 }
287
288 /*
289  * Skip a certain amount of data in a file, either by seeking if
290  * possible, or if that fails then by reading and discarding.
291  */
292 static void skip (unsigned long dist, FILE *fp) 
293 {
294     char buffer[256];                  /* should fit on most stacks :-) */
295
296     /*
297      * Got to be careful with fseek: at least one fseek I've tried
298      * doesn't approve of SEEK_CUR. So I'll use SEEK_SET and
299      * ftell... horrible but apparently necessary.
300      */
301     if (fseek (fp, dist+ftell(fp), SEEK_SET)) {
302         while (dist > 0) {
303             unsigned long len = (dist < sizeof(buffer) ?
304                                  dist : sizeof(buffer));
305             if (fread (buffer, 1, len, fp) < len) {
306                 perror("fread");
307                 exit(1);
308             }
309             dist -= len;
310         }
311     }
312 }