Apply Nindent to all .c and .h files
[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 or -v 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, idt)\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;
46     long lendis;
47     int autosync = FALSE;
48     int bits = 16;
49     int eof = FALSE;
50     unsigned long prefer = 0;
51     int rn_error;
52     long offset;
53     FILE *fp;
54
55     offset = 0;
56     init_sync();
57
58     while (--argc) {
59         char *v, *vv, *p = *++argv;
60         if (*p == '-' && p[1]) {
61             p++;
62             while (*p)
63                 switch (tolower(*p)) {
64                 case 'a':      /* auto or intelligent sync */
65                 case 'i':
66                     autosync = TRUE;
67                     p++;
68                     break;
69                 case 'h':
70                     fprintf(stderr, help);
71                     return 0;
72                 case 'r':
73                 case 'v':
74                     fprintf(stderr,
75                             "NDISASM version %s compiled " __DATE__ "\n",
76                             NASM_VER);
77                     return 0;
78                 case 'u':      /* USE32 */
79                     bits = 32;
80                     p++;
81                     break;
82                 case 'b':      /* bits */
83                     v = p[1] ? p + 1 : --argc ? *++argv : NULL;
84                     if (!v) {
85                         fprintf(stderr, "%s: `-b' requires an argument\n",
86                                 pname);
87                         return 1;
88                     }
89                     if (!strcmp(v, "16"))
90                         bits = 16;
91                     else if (!strcmp(v, "32"))
92                         bits = 32;
93                     else {
94                         fprintf(stderr, "%s: argument to `-b' should"
95                                 " be `16' or `32'\n", pname);
96                     }
97                     p = "";     /* force to next argument */
98                     break;
99                 case 'o':      /* origin */
100                     v = p[1] ? p + 1 : --argc ? *++argv : NULL;
101                     if (!v) {
102                         fprintf(stderr, "%s: `-o' requires an argument\n",
103                                 pname);
104                         return 1;
105                     }
106                     offset = readnum(v, &rn_error);
107                     if (rn_error) {
108                         fprintf(stderr,
109                                 "%s: `-o' requires a numeric argument\n",
110                                 pname);
111                         return 1;
112                     }
113                     p = "";     /* force to next argument */
114                     break;
115                 case 's':      /* sync point */
116                     v = p[1] ? p + 1 : --argc ? *++argv : NULL;
117                     if (!v) {
118                         fprintf(stderr, "%s: `-s' requires an argument\n",
119                                 pname);
120                         return 1;
121                     }
122                     add_sync(readnum(v, &rn_error), 0L);
123                     if (rn_error) {
124                         fprintf(stderr,
125                                 "%s: `-s' requires a numeric argument\n",
126                                 pname);
127                         return 1;
128                     }
129                     p = "";     /* force to next argument */
130                     break;
131                 case 'e':      /* skip a header */
132                     v = p[1] ? p + 1 : --argc ? *++argv : NULL;
133                     if (!v) {
134                         fprintf(stderr, "%s: `-e' requires an argument\n",
135                                 pname);
136                         return 1;
137                     }
138                     initskip = readnum(v, &rn_error);
139                     if (rn_error) {
140                         fprintf(stderr,
141                                 "%s: `-e' requires a numeric argument\n",
142                                 pname);
143                         return 1;
144                     }
145                     p = "";     /* force to next argument */
146                     break;
147                 case 'k':      /* skip a region */
148                     v = p[1] ? p + 1 : --argc ? *++argv : NULL;
149                     if (!v) {
150                         fprintf(stderr, "%s: `-k' requires an argument\n",
151                                 pname);
152                         return 1;
153                     }
154                     vv = strchr(v, ',');
155                     if (!vv) {
156                         fprintf(stderr,
157                                 "%s: `-k' requires two numbers separated"
158                                 " by a comma\n", pname);
159                         return 1;
160                     }
161                     *vv++ = '\0';
162                     nextsync = readnum(v, &rn_error);
163                     if (rn_error) {
164                         fprintf(stderr,
165                                 "%s: `-k' requires numeric arguments\n",
166                                 pname);
167                         return 1;
168                     }
169                     synclen = readnum(vv, &rn_error);
170                     if (rn_error) {
171                         fprintf(stderr,
172                                 "%s: `-k' requires numeric arguments\n",
173                                 pname);
174                         return 1;
175                     }
176                     add_sync(nextsync, synclen);
177                     p = "";     /* force to next argument */
178                     break;
179                 case 'p':      /* preferred vendor */
180                     v = p[1] ? p + 1 : --argc ? *++argv : NULL;
181                     if (!v) {
182                         fprintf(stderr, "%s: `-p' requires an argument\n",
183                                 pname);
184                         return 1;
185                     }
186                     if (!strcmp(v, "intel")) {
187                         prefer = 0;     /* Default */
188                     } else if (!strcmp(v, "amd")) {
189                         prefer = IF_AMD | IF_3DNOW;
190                     } else if (!strcmp(v, "cyrix")) {
191                         prefer = IF_CYRIX | IF_3DNOW;
192                     } else if (!strcmp(v, "idt") || !strcmp(v, "centaur")
193                                || !strcmp(v, "winchip")) {
194                         prefer = IF_3DNOW;
195                     } else {
196                         fprintf(stderr,
197                                 "%s: unknown vendor `%s' specified with `-p'\n",
198                                 pname, v);
199                         return 1;
200                     }
201                     p = "";     /* force to next argument */
202                     break;
203                 default:       /*bf */
204                     fprintf(stderr, "%s: unrecognised option `-%c'\n",
205                             pname, *p);
206                     return 1;
207                 }
208         } else if (!filename) {
209             filename = p;
210         } else {
211             fprintf(stderr, "%s: more than one filename specified\n",
212                     pname);
213             return 1;
214         }
215     }
216
217     if (!filename) {
218         fprintf(stderr, help, pname);
219         return 0;
220     }
221
222     if (strcmp(filename, "-")) {
223         fp = fopen(filename, "rb");
224         if (!fp) {
225             fprintf(stderr, "%s: unable to open `%s': %s\n",
226                     pname, filename, strerror(errno));
227             return 1;
228         }
229     } else
230         fp = stdin;
231
232     if (initskip > 0)
233         skip(initskip, fp);
234
235     /*
236      * This main loop is really horrible, and wants rewriting with
237      * an axe. It'll stay the way it is for a while though, until I
238      * find the energy...
239      */
240
241     p = q = buffer;
242     nextsync = next_sync(offset, &synclen);
243     do {
244         unsigned long to_read = buffer + sizeof(buffer) - p;
245         if (to_read > nextsync - offset - (p - q))
246             to_read = nextsync - offset - (p - q);
247         if (to_read) {
248             lenread = fread(p, 1, to_read, fp);
249             if (lenread == 0)
250                 eof = TRUE;     /* help along systems with bad feof */
251         } else
252             lenread = 0;
253         p += lenread;
254         if ((unsigned long)offset == nextsync) {
255             if (synclen) {
256                 fprintf(stdout, "%08lX  skipping 0x%lX bytes\n", offset,
257                         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                 || (unsigned long)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             unsigned char *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(unsigned long offset, unsigned char *data,
292                        int datalen, char *insn)
293 {
294     int bytes;
295     fprintf(stdout, "%08lX  ", 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(unsigned long 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             unsigned long 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 }