outmacho64.c: Add PC-Relative GOT support and perform general code cleanup.
[nasm.git] / ndisasm.c
blob9234c6ee3d479b9a3d49d8a83b825fc1634302d2
1 /* ----------------------------------------------------------------------- *
2 *
3 * Copyright 1996-2009 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * ----------------------------------------------------------------------- */
35 * ndisasm.c the Netwide Disassembler main module
38 #include "compiler.h"
40 #include <stdio.h>
41 #include <stdarg.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <ctype.h>
45 #include <errno.h>
46 #include <inttypes.h>
48 #include "insns.h"
49 #include "nasm.h"
50 #include "nasmlib.h"
51 #include "sync.h"
52 #include "disasm.h"
54 #define BPL 8 /* bytes per line of hex dump */
56 static const char *help =
57 "usage: ndisasm [-a] [-i] [-h] [-r] [-u] [-b bits] [-o origin] [-s sync...]\n"
58 " [-e bytes] [-k start,bytes] [-p vendor] file\n"
59 " -a or -i activates auto (intelligent) sync\n"
60 " -u same as -b 32\n"
61 " -b 16, -b 32 or -b 64 sets the processor mode\n"
62 " -h displays this text\n"
63 " -r or -v displays the version number\n"
64 " -e skips <bytes> bytes of header\n"
65 " -k avoids disassembling <bytes> bytes from position <start>\n"
66 " -p selects the preferred vendor instruction set (intel, amd, cyrix, idt)\n";
68 static void output_ins(uint32_t, uint8_t *, int, char *);
69 static void skip(uint32_t dist, FILE * fp);
71 static void ndisasm_error(int severity, const char *fmt, ...)
73 va_list va;
75 va_start(va, fmt);
76 vfprintf(stderr, fmt, va);
78 if (severity & ERR_FATAL)
79 exit(1);
82 int main(int argc, char **argv)
84 char buffer[INSN_MAX * 2], *p, *ep, *q;
85 char outbuf[256];
86 char *pname = *argv;
87 char *filename = NULL;
88 uint32_t nextsync, synclen, initskip = 0L;
89 int lenread;
90 int32_t lendis;
91 bool autosync = false;
92 int bits = 16, b;
93 bool eof = false;
94 uint32_t prefer = 0;
95 bool rn_error;
96 int32_t offset;
97 FILE *fp;
99 tolower_init();
100 nasm_set_malloc_error(ndisasm_error);
102 offset = 0;
103 init_sync();
105 while (--argc) {
106 char *v, *vv, *p = *++argv;
107 if (*p == '-' && p[1]) {
108 p++;
109 while (*p)
110 switch (nasm_tolower(*p)) {
111 case 'a': /* auto or intelligent sync */
112 case 'i':
113 autosync = true;
114 p++;
115 break;
116 case 'h':
117 fprintf(stderr, help);
118 return 0;
119 case 'r':
120 case 'v':
121 fprintf(stderr,
122 "NDISASM version %s compiled on %s\n",
123 nasm_version, nasm_date);
124 return 0;
125 case 'u': /* -u for -b 32, -uu for -b 64 */
126 if (bits < 64)
127 bits <<= 1;
128 p++;
129 break;
130 case 'b': /* bits */
131 v = p[1] ? p + 1 : --argc ? *++argv : NULL;
132 if (!v) {
133 fprintf(stderr, "%s: `-b' requires an argument\n",
134 pname);
135 return 1;
137 b = strtoul(v, &ep, 10);
138 if (*ep || !(bits == 16 || bits == 32 || bits == 64)) {
139 fprintf(stderr, "%s: argument to `-b' should"
140 " be 16, 32 or 64\n", pname);
141 } else {
142 bits = b;
144 p = ""; /* force to next argument */
145 break;
146 case 'o': /* origin */
147 v = p[1] ? p + 1 : --argc ? *++argv : NULL;
148 if (!v) {
149 fprintf(stderr, "%s: `-o' requires an argument\n",
150 pname);
151 return 1;
153 offset = readnum(v, &rn_error);
154 if (rn_error) {
155 fprintf(stderr,
156 "%s: `-o' requires a numeric argument\n",
157 pname);
158 return 1;
160 p = ""; /* force to next argument */
161 break;
162 case 's': /* sync point */
163 v = p[1] ? p + 1 : --argc ? *++argv : NULL;
164 if (!v) {
165 fprintf(stderr, "%s: `-s' requires an argument\n",
166 pname);
167 return 1;
169 add_sync(readnum(v, &rn_error), 0L);
170 if (rn_error) {
171 fprintf(stderr,
172 "%s: `-s' requires a numeric argument\n",
173 pname);
174 return 1;
176 p = ""; /* force to next argument */
177 break;
178 case 'e': /* skip a header */
179 v = p[1] ? p + 1 : --argc ? *++argv : NULL;
180 if (!v) {
181 fprintf(stderr, "%s: `-e' requires an argument\n",
182 pname);
183 return 1;
185 initskip = readnum(v, &rn_error);
186 if (rn_error) {
187 fprintf(stderr,
188 "%s: `-e' requires a numeric argument\n",
189 pname);
190 return 1;
192 p = ""; /* force to next argument */
193 break;
194 case 'k': /* skip a region */
195 v = p[1] ? p + 1 : --argc ? *++argv : NULL;
196 if (!v) {
197 fprintf(stderr, "%s: `-k' requires an argument\n",
198 pname);
199 return 1;
201 vv = strchr(v, ',');
202 if (!vv) {
203 fprintf(stderr,
204 "%s: `-k' requires two numbers separated"
205 " by a comma\n", pname);
206 return 1;
208 *vv++ = '\0';
209 nextsync = readnum(v, &rn_error);
210 if (rn_error) {
211 fprintf(stderr,
212 "%s: `-k' requires numeric arguments\n",
213 pname);
214 return 1;
216 synclen = readnum(vv, &rn_error);
217 if (rn_error) {
218 fprintf(stderr,
219 "%s: `-k' requires numeric arguments\n",
220 pname);
221 return 1;
223 add_sync(nextsync, synclen);
224 p = ""; /* force to next argument */
225 break;
226 case 'p': /* preferred vendor */
227 v = p[1] ? p + 1 : --argc ? *++argv : NULL;
228 if (!v) {
229 fprintf(stderr, "%s: `-p' requires an argument\n",
230 pname);
231 return 1;
233 if (!strcmp(v, "intel")) {
234 prefer = 0; /* Default */
235 } else if (!strcmp(v, "amd")) {
236 prefer = IF_AMD | IF_3DNOW;
237 } else if (!strcmp(v, "cyrix")) {
238 prefer = IF_CYRIX | IF_3DNOW;
239 } else if (!strcmp(v, "idt") || !strcmp(v, "centaur")
240 || !strcmp(v, "winchip")) {
241 prefer = IF_3DNOW;
242 } else {
243 fprintf(stderr,
244 "%s: unknown vendor `%s' specified with `-p'\n",
245 pname, v);
246 return 1;
248 p = ""; /* force to next argument */
249 break;
250 default: /*bf */
251 fprintf(stderr, "%s: unrecognised option `-%c'\n",
252 pname, *p);
253 return 1;
255 } else if (!filename) {
256 filename = p;
257 } else {
258 fprintf(stderr, "%s: more than one filename specified\n",
259 pname);
260 return 1;
264 if (!filename) {
265 fprintf(stderr, help, pname);
266 return 0;
269 if (strcmp(filename, "-")) {
270 fp = fopen(filename, "rb");
271 if (!fp) {
272 fprintf(stderr, "%s: unable to open `%s': %s\n",
273 pname, filename, strerror(errno));
274 return 1;
276 } else
277 fp = stdin;
279 if (initskip > 0)
280 skip(initskip, fp);
283 * This main loop is really horrible, and wants rewriting with
284 * an axe. It'll stay the way it is for a while though, until I
285 * find the energy...
288 p = q = buffer;
289 nextsync = next_sync(offset, &synclen);
290 do {
291 uint32_t to_read = buffer + sizeof(buffer) - p;
292 if ((nextsync || synclen) &&
293 to_read > nextsync - offset - (p - q))
294 to_read = nextsync - offset - (p - q);
295 if (to_read) {
296 lenread = fread(p, 1, to_read, fp);
297 if (lenread == 0)
298 eof = true; /* help along systems with bad feof */
299 } else
300 lenread = 0;
301 p += lenread;
302 if ((nextsync || synclen) &&
303 (uint32_t)offset == nextsync) {
304 if (synclen) {
305 fprintf(stdout, "%08"PRIX32" skipping 0x%"PRIX32" bytes\n",
306 offset, synclen);
307 offset += synclen;
308 skip(synclen, fp);
310 p = q = buffer;
311 nextsync = next_sync(offset, &synclen);
313 while (p > q && (p - q >= INSN_MAX || lenread == 0)) {
314 lendis =
315 disasm((uint8_t *) q, outbuf, sizeof(outbuf), bits,
316 offset, autosync, prefer);
317 if (!lendis || lendis > (p - q)
318 || ((nextsync || synclen) &&
319 (uint32_t)lendis > nextsync - offset))
320 lendis = eatbyte((uint8_t *) q, outbuf, sizeof(outbuf), bits);
321 output_ins(offset, (uint8_t *) q, lendis, outbuf);
322 q += lendis;
323 offset += lendis;
325 if (q >= buffer + INSN_MAX) {
326 uint8_t *r = (uint8_t *) buffer, *s = (uint8_t *) q;
327 int count = p - q;
328 while (count--)
329 *r++ = *s++;
330 p -= (q - buffer);
331 q = buffer;
333 } while (lenread > 0 || !(eof || feof(fp)));
335 if (fp != stdin)
336 fclose(fp);
338 return 0;
341 static void output_ins(uint32_t offset, uint8_t *data,
342 int datalen, char *insn)
344 int bytes;
345 fprintf(stdout, "%08"PRIX32" ", offset);
347 bytes = 0;
348 while (datalen > 0 && bytes < BPL) {
349 fprintf(stdout, "%02X", *data++);
350 bytes++;
351 datalen--;
354 fprintf(stdout, "%*s%s\n", (BPL + 1 - bytes) * 2, "", insn);
356 while (datalen > 0) {
357 fprintf(stdout, " -");
358 bytes = 0;
359 while (datalen > 0 && bytes < BPL) {
360 fprintf(stdout, "%02X", *data++);
361 bytes++;
362 datalen--;
364 fprintf(stdout, "\n");
369 * Skip a certain amount of data in a file, either by seeking if
370 * possible, or if that fails then by reading and discarding.
372 static void skip(uint32_t dist, FILE * fp)
374 char buffer[256]; /* should fit on most stacks :-) */
377 * Got to be careful with fseek: at least one fseek I've tried
378 * doesn't approve of SEEK_CUR. So I'll use SEEK_SET and
379 * ftell... horrible but apparently necessary.
381 if (fseek(fp, dist + ftell(fp), SEEK_SET)) {
382 while (dist > 0) {
383 uint32_t len = (dist < sizeof(buffer) ?
384 dist : sizeof(buffer));
385 if (fread(buffer, 1, len, fp) < len) {
386 perror("fread");
387 exit(1);
389 dist -= len;