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