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.
22 static const char *record_types
[256] =
66 typedef void (*dump_func
)(uint8_t, const uint8_t *, size_t);
68 /* Ordered collection type */
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
);
84 static void add_collection(struct collection
*c
, const void *p
)
87 size_t cs
= c
->s
? (c
->s
<< 1) : INIT_SIZE
;
88 const void **cp
= realloc(c
->p
, cs
*sizeof(const void *));
96 memset(cp
+ c
->n
, 0, (cs
- c
->n
)*sizeof(const void *));
102 static const void *get_collection(struct collection
*c
, size_t index
)
110 static void hexdump_data(unsigned int offset
, const uint8_t *data
,
111 size_t n
, size_t field
)
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) ? '-' : ' ';
120 printf("%02x%c", data
[i
+j
], sep
);
122 printf("xx%c", sep
); /* Beyond end of... */
124 printf(" "); /* No separator */
127 for (j
= 0; j
< 16; j
++) {
129 putchar((i
+j
>= field
) ? 'x' :
130 isprint(data
[i
+j
]) ? data
[i
+j
] : '.');
136 static void dump_unknown(uint8_t type
, const uint8_t *data
, size_t n
)
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) {
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
)
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",
177 [0x9f] = "Library search",
178 [0xa0] = "OMF extensions",
179 [0xa1] = "New OMF extension",
180 [0xa2] = "Link pass separator",
190 [0xdd] = "Timestamp",
192 [0xe3] = "Type definition",
194 [0xe9] = "Dependency file",
195 [0xff] = "Command line"
199 hexdump_data(type
, data
, 2, n
);
206 printf(" [NP=%d NL=%d UD=%02X] %02X %s\n",
211 coment_class
[class] ? coment_class
[class] : "???");
213 if (dump_coment_class
[class])
214 dump_coment_class
[class](class, data
+2, n
-2);
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
)
226 return ((c
& 0x7f) << 8) + *(*pp
)++;
232 static uint16_t get_16(const uint8_t **pp
)
234 uint16_t v
= *(const uint16_t *)(*pp
);
240 static uint32_t get_32(const uint8_t **pp
)
242 const uint32_t v
= *(const uint32_t *)(*pp
);
248 /* Returns a name as a C string in a newly allocated buffer */
249 char *lname(int index
)
252 const char *p
= get_collection(&c_names
, index
);
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
;
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
);
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
);
293 /* SEGDEF16 or SEGDEF32 */
294 static void dump_segdef(uint8_t type
, const uint8_t *data
, size_t n
)
297 const uint8_t *p
= data
;
298 const uint8_t *end
= data
+n
;
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" };
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 */
322 printf(" AT %04x:", get_16(&p
));
323 printf("%02x", *p
++);
329 printf(" size 0x%08x", get_32(&p
));
333 printf(" size 0x%04x", get_16(&p
));
340 printf(" name '%s'", s
);
346 printf(" class '%s'", s
);
352 printf(" ovl '%s'", s
);
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
)
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#" };
369 const uint8_t *start
= p
;
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
));
389 /* FIXUP subrecord */
392 printf(" FIXUP %s-rel location %2d offset 0x%03x",
393 (op
& 0x40) ? "seg" : "self",
395 ((op
& 3) << 8) + *p
++);
398 printf("\n frame %s%d%s",
399 (fix
& 0x80) ? "thread " : "F",
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",
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) {
417 printf(" disp 0x%08x", get_32(&p
));
419 printf(" disp 0x%04x", get_16(&p
));
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
,
444 const uint8_t *p
, *data
;
451 data
= mmap(NULL
, len
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
452 if (data
== MAP_FAILED
)
461 n
= *(uint16_t *)(p
+1);
463 printf("%02x %-10s %4zd bytes",
465 record_types
[type
] ? record_types
[type
] : "???",
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 */
477 for (i
= -3; i
< (int)n
; i
++)
480 printf(", checksum %02X", p
[i
]);
482 printf(" (valid)\n");
484 printf(" (actual = %02X)\n", csum
);
487 dump_type
[type
](type
, p
, n
);
489 dump_unknown(type
, p
, n
);
495 munmap((void *)data
, st
.st_size
);
499 int main(int argc
, char *argv
[])
506 for (i
= 1; i
< argc
; i
++) {
507 fd
= open(argv
[i
], O_RDONLY
);
508 if (fd
< 0 || dump_omf(fd
)) {