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