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