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