rbtree: add rb_search_exact()
[nasm.git] / misc / omfdump.c
blobb27e7c908d7a11edec3c6d73084dd5e73d01857a
1 /*
2 * omfdump.c
4 * Very simple program to dump the contents of an OMF (OBJ) file
6 * This assumes a littleendian, unaligned-load-capable host and a
7 * C compiler which handles basic C99.
8 */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <inttypes.h>
13 #include <ctype.h>
14 #include <fcntl.h>
15 #include <unistd.h>
16 #include <stdbool.h>
17 #include <sys/mman.h>
18 #include <sys/stat.h>
20 const char *progname;
22 static const char *record_types[256] =
24 [0x80] = "THEADR",
25 [0x82] = "LHEADR",
26 [0x88] = "COMENT",
27 [0x8a] = "MODEND16",
28 [0x8b] = "MODEND32",
29 [0x8c] = "EXTDEF",
30 [0x90] = "PUBDEF16",
31 [0x91] = "PUBDEF32",
32 [0x94] = "LINNUM16",
33 [0x95] = "LINNUM32",
34 [0x96] = "LNAMES",
35 [0x98] = "SEGDEF16",
36 [0x99] = "SEGDEF32",
37 [0x9a] = "GRPDEF",
38 [0x9c] = "FIXUPP16",
39 [0x9d] = "FIXUPP32",
40 [0xa0] = "LEDATA16",
41 [0xa1] = "LEDATA32",
42 [0xa2] = "LIDATA16",
43 [0xa3] = "LIDATA32",
44 [0xb0] = "COMDEF",
45 [0xb2] = "BAKPAT16",
46 [0xb3] = "BAKPAT32",
47 [0xb4] = "LEXTDEF",
48 [0xb6] = "LPUBDEF16",
49 [0xb7] = "LPUBDEF32",
50 [0xb8] = "LCOMDEF",
51 [0xbc] = "CEXTDEF",
52 [0xc2] = "COMDAT16",
53 [0xc3] = "COMDAT32",
54 [0xc4] = "LINSYM16",
55 [0xc5] = "LINSYM32",
56 [0xc6] = "ALIAS",
57 [0xc8] = "NBKPAT16",
58 [0xc9] = "NBKPAT32",
59 [0xca] = "LLNAMES",
60 [0xcc] = "VERNUM",
61 [0xce] = "VENDEXT",
62 [0xf0] = "LIBHDR",
63 [0xf1] = "LIBEND",
66 typedef void (*dump_func)(uint8_t, const uint8_t *, size_t);
68 /* Ordered collection type */
69 struct collection {
70 size_t n; /* Elements in collection (not including 0) */
71 size_t s; /* Elements allocated (not including 0) */
72 const void **p; /* Element pointers */
75 struct collection c_names, c_lsegs, c_groups, c_extsym;
77 static void nomem(void)
79 fprintf(stderr, "%s: memory allocation error\n", progname);
80 exit(1);
83 #define INIT_SIZE 64
84 static void add_collection(struct collection *c, const void *p)
86 if (c->n >= c->s) {
87 size_t cs = c->s ? (c->s << 1) : INIT_SIZE;
88 const void **cp = realloc(c->p, cs*sizeof(const void *));
90 if (!cp)
91 nomem();
93 c->p = cp;
94 c->s = cs;
96 memset(cp + c->n, 0, (cs - c->n)*sizeof(const void *));
99 c->p[++c->n] = p;
102 static const void *get_collection(struct collection *c, size_t index)
104 if (index >= c->n)
105 return NULL;
107 return c->p[index];
110 static void hexdump_data(unsigned int offset, const uint8_t *data,
111 size_t n, size_t field)
113 unsigned int i, j;
115 for (i = 0; i < n; i += 16) {
116 printf(" %04x: ", i+offset);
117 for (j = 0; j < 16; j++) {
118 char sep = (j == 7) ? '-' : ' ';
119 if (i+j < field)
120 printf("%02x%c", data[i+j], sep);
121 else if (i+j < n)
122 printf("xx%c", sep); /* Beyond end of... */
123 else
124 printf(" "); /* No separator */
126 printf(" : ");
127 for (j = 0; j < 16; j++) {
128 if (i+j < n)
129 putchar((i+j >= field) ? 'x' :
130 isprint(data[i+j]) ? data[i+j] : '.');
132 putchar('\n');
136 static void dump_unknown(uint8_t type, const uint8_t *data, size_t n)
138 (void)type;
139 hexdump_data(0, data, n, n);
142 static void print_dostime(const uint8_t *p)
144 uint16_t da = (p[3] << 8) + p[2];
145 uint16_t ti = (p[1] << 8) + p[0];
147 printf("%04u-%02u-%02u %02u:%02u:%02u",
148 (da >> 9) + 1980, (da >> 5) & 15, da & 31,
149 (ti >> 11), (ti >> 5) & 63, (ti << 1) & 63);
152 static void dump_coment_depfile(uint8_t type, const uint8_t *data, size_t n)
154 if (n > 4 && data[4] == n-5) {
155 printf(" # ");
156 print_dostime(data);
157 printf(" %.*s\n", n-5, data+5);
160 hexdump_data(2, data, n, n);
163 static const dump_func dump_coment_class[256] = {
164 [0xe9] = dump_coment_depfile
167 static void dump_coment(uint8_t type, const uint8_t *data, size_t n)
169 uint8_t class;
170 static const char *coment_class[256] = {
171 [0x00] = "Translator",
172 [0x01] = "Copyright",
173 [0x81] = "Library specifier",
174 [0x9c] = "MS-DOS version",
175 [0x9d] = "Memory model",
176 [0x9e] = "DOSSEG",
177 [0x9f] = "Library search",
178 [0xa0] = "OMF extensions",
179 [0xa1] = "New OMF extension",
180 [0xa2] = "Link pass separator",
181 [0xa3] = "LIBMOD",
182 [0xa4] = "EXESTR",
183 [0xa6] = "INCERR",
184 [0xa7] = "NOPAD",
185 [0xa8] = "WKEXT",
186 [0xa9] = "LZEXT",
187 [0xda] = "Comment",
188 [0xdb] = "Compiler",
189 [0xdc] = "Date",
190 [0xdd] = "Timestamp",
191 [0xdf] = "User",
192 [0xe3] = "Type definition",
193 [0xe8] = "Filename",
194 [0xe9] = "Dependency file",
195 [0xff] = "Command line"
198 if (n < 2) {
199 hexdump_data(type, data, 2, n);
200 return;
203 type = data[0];
204 class = data[1];
206 printf(" [NP=%d NL=%d UD=%02X] %02X %s\n",
207 (type >> 7) & 1,
208 (type >> 6) & 1,
209 type & 0x3f,
210 class,
211 coment_class[class] ? coment_class[class] : "???");
213 if (dump_coment_class[class])
214 dump_coment_class[class](class, data+2, n-2);
215 else
216 hexdump_data(2, data+2, n-2, n-2);
219 /* Parse an index field */
220 static uint16_t get_index(const uint8_t **pp)
222 uint8_t c;
224 c = *(*pp)++;
225 if (c & 0x80) {
226 return ((c & 0x7f) << 8) + *(*pp)++;
227 } else {
228 return c;
232 static uint16_t get_16(const uint8_t **pp)
234 uint16_t v = *(const uint16_t *)(*pp);
235 (*pp) += 2;
237 return v;
240 static uint32_t get_32(const uint8_t **pp)
242 const uint32_t v = *(const uint32_t *)(*pp);
243 (*pp) += 4;
245 return v;
248 /* Returns a name as a C string in a newly allocated buffer */
249 char *lname(int index)
251 char *s;
252 const char *p = get_collection(&c_names, index);
253 size_t len;
255 if (!p)
256 return NULL;
258 len = (uint8_t)p[0];
260 s = malloc(len+1);
261 if (!s)
262 nomem();
264 memcpy(s, p+1, len);
265 s[len] = '\0';
267 return s;
270 /* LNAMES or LLNAMES */
271 static void dump_lnames(uint8_t type, const uint8_t *data, size_t n)
273 const uint8_t *p = data;
274 const uint8_t *end = data + n;
276 while (p < end) {
277 size_t l = *p+1;
278 if (l > n) {
279 add_collection(&c_names, NULL);
280 printf(" # %4u 0x%04x: \"%.*s... <%zu missing bytes>\n",
281 c_names.n, c_names.n, n-1, p+1, l-n);
282 } else {
283 add_collection(&c_names, p);
284 printf(" # %4u 0x%04x: \"%.*s\"\n",
285 c_names.n, c_names.n, l-1, p+1);
287 hexdump_data(p-data, p, l, n);
288 p += l;
289 n -= l;
293 /* SEGDEF16 or SEGDEF32 */
294 static void dump_segdef(uint8_t type, const uint8_t *data, size_t n)
296 bool big = type & 1;
297 const uint8_t *p = data;
298 const uint8_t *end = data+n;
299 uint8_t attr;
300 static const char * const alignment[8] =
301 { "ABS", "BYTE", "WORD", "PARA", "PAGE", "DWORD", "LTL", "?ALIGN" };
302 static const char * const combine[8] =
303 { "PRIVATE", "?COMMON", "PUBLIC", "?COMBINE", "?PUBLIC", "STACK", "COMMON", "?PUBLIC" };
304 uint16_t idx;
305 char *s;
307 if (p >= end)
308 return;
310 attr = *p++;
312 printf(" # %s (A%u) %s (C%u) %s%s",
313 alignment[(attr >> 5) & 7], (attr >> 5) & 7,
314 combine[(attr >> 2) & 7], (attr >> 2) & 7,
315 (attr & 0x02) ? "MAXSIZE " : "",
316 (attr & 0x01) ? "USE32" : "USE16");
318 if (((attr >> 5) & 7) == 0) {
319 /* Absolute segment */
320 if (p+3 > end)
321 goto dump;
322 printf(" AT %04x:", get_16(&p));
323 printf("%02x", *p++);
326 if (big) {
327 if (p+4 > end)
328 goto dump;
329 printf(" size 0x%08x", get_32(&p));
330 } else {
331 if (p+2 > end)
332 goto dump;
333 printf(" size 0x%04x", get_16(&p));
336 idx = get_index(&p);
337 if (p > end)
338 goto dump;
339 s = lname(idx);
340 printf(" name '%s'", s);
342 idx = get_index(&p);
343 if (p > end)
344 goto dump;
345 s = lname(idx);
346 printf(" class '%s'", s);
348 idx = get_index(&p);
349 if (p > end)
350 goto dump;
351 s = lname(idx);
352 printf(" ovl '%s'", s);
354 dump:
355 putchar('\n');
356 hexdump_data(0, data, n, n);
359 /* FIXUPP16 or FIXUPP32 */
360 static void dump_fixupp(uint8_t type, const uint8_t *data, size_t n)
362 bool big = type & 1;
363 const uint8_t *p = data;
364 const uint8_t *end = data + n;
365 static const char * const method_base[4] =
366 { "SEGDEF", "GRPDEF", "EXTDEF", "frame#" };
368 while (p < end) {
369 const uint8_t *start = p;
370 uint8_t op = *p++;
371 uint16_t index;
372 uint32_t disp;
374 if (!(op & 0x80)) {
375 /* THREAD record */
376 bool frame = !!(op & 0x40);
378 printf(" THREAD %-7s%d%s method %c%d (%s)",
379 frame ? "frame" : "target", op & 3,
380 (op & 0x20) ? " +flag5?" : "",
381 (op & 0x40) ? 'F' : 'T',
382 op & 3, method_base[op & 3]);
384 if ((op & 0x50) != 0x50) {
385 printf(" index 0x%04x", get_index(&p));
387 putchar('\n');
388 } else {
389 /* FIXUP subrecord */
390 uint8_t fix;
392 printf(" FIXUP %s-rel location %2d offset 0x%03x",
393 (op & 0x40) ? "seg" : "self",
394 (op & 0x3c) >> 2,
395 ((op & 3) << 8) + *p++);
397 fix = *p++;
398 printf("\n frame %s%d%s",
399 (fix & 0x80) ? "thread " : "F",
400 ((fix & 0x70) >> 4),
401 ((fix & 0xc0) == 0xc0) ? "?" : "");
403 if ((fix & 0xc0) == 0)
404 printf(" datum 0x%04x", get_index(&p));
406 printf("\n target %s%d",
407 (fix & 0x10) ? "thread " : "method T",
408 fix & 3);
410 if ((fix & 0x10) == 0)
411 printf(" (%s)", method_base[fix & 3]);
413 printf(" datum 0x%04x", get_index(&p));
415 if ((fix & 0x08) == 0) {
416 if (big) {
417 printf(" disp 0x%08x", get_32(&p));
418 } else {
419 printf(" disp 0x%04x", get_16(&p));
422 putchar('\n');
424 hexdump_data(start-data, start, p-start, n-(start-data));
428 static const dump_func dump_type[256] =
430 [0x88] = dump_coment,
431 [0x96] = dump_lnames,
432 [0x98] = dump_segdef,
433 [0x99] = dump_segdef,
434 [0x9c] = dump_fixupp,
435 [0x9d] = dump_fixupp,
436 [0xca] = dump_lnames,
439 int dump_omf(int fd)
441 struct stat st;
442 size_t len, n;
443 uint8_t type;
444 const uint8_t *p, *data;
446 if (fstat(fd, &st))
447 return -1;
449 len = st.st_size;
451 data = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
452 if (data == MAP_FAILED)
453 return -1;
455 p = data;
456 while (len >= 3) {
457 uint8_t csum;
458 int i;
460 type = p[0];
461 n = *(uint16_t *)(p+1);
463 printf("%02x %-10s %4zd bytes",
464 type,
465 record_types[type] ? record_types[type] : "???",
468 if (len < n+3) {
469 printf("\n (truncated, only %zd bytes left)\n", len-3);
470 break; /* Truncated */
473 p += 3; /* Header doesn't count in the length */
474 n--; /* Remove checksum byte */
476 csum = 0;
477 for (i = -3; i < (int)n; i++)
478 csum -= p[i];
480 printf(", checksum %02X", p[i]);
481 if (csum == p[i])
482 printf(" (valid)\n");
483 else
484 printf(" (actual = %02X)\n", csum);
486 if (dump_type[type])
487 dump_type[type](type, p, n);
488 else
489 dump_unknown(type, p, n);
491 p += n+1;
492 len -= (n+4);
495 munmap((void *)data, st.st_size);
496 return 0;
499 int main(int argc, char *argv[])
501 int fd;
502 int i;
504 progname = argv[0];
506 for (i = 1; i < argc; i++) {
507 fd = open(argv[i], O_RDONLY);
508 if (fd < 0 || dump_omf(fd)) {
509 perror(argv[i]);
510 return 1;
512 close(fd);
515 return 0;