| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518 |
- /*
- * omfdump.c
- *
- * Very simple program to dump the contents of an OMF (OBJ) file
- *
- * This assumes a littleendian, unaligned-load-capable host and a
- * C compiler which handles basic C99.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <inttypes.h>
- #include <ctype.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <stdbool.h>
- #include <string.h>
- #include <sys/mman.h>
- #include <sys/stat.h>
- const char *progname;
- static const char *record_types[256] =
- {
- [0x80] = "THEADR",
- [0x82] = "LHEADR",
- [0x88] = "COMENT",
- [0x8a] = "MODEND16",
- [0x8b] = "MODEND32",
- [0x8c] = "EXTDEF",
- [0x90] = "PUBDEF16",
- [0x91] = "PUBDEF32",
- [0x94] = "LINNUM16",
- [0x95] = "LINNUM32",
- [0x96] = "LNAMES",
- [0x98] = "SEGDEF16",
- [0x99] = "SEGDEF32",
- [0x9a] = "GRPDEF",
- [0x9c] = "FIXUPP16",
- [0x9d] = "FIXUPP32",
- [0xa0] = "LEDATA16",
- [0xa1] = "LEDATA32",
- [0xa2] = "LIDATA16",
- [0xa3] = "LIDATA32",
- [0xb0] = "COMDEF",
- [0xb2] = "BAKPAT16",
- [0xb3] = "BAKPAT32",
- [0xb4] = "LEXTDEF",
- [0xb6] = "LPUBDEF16",
- [0xb7] = "LPUBDEF32",
- [0xb8] = "LCOMDEF",
- [0xbc] = "CEXTDEF",
- [0xc2] = "COMDAT16",
- [0xc3] = "COMDAT32",
- [0xc4] = "LINSYM16",
- [0xc5] = "LINSYM32",
- [0xc6] = "ALIAS",
- [0xc8] = "NBKPAT16",
- [0xc9] = "NBKPAT32",
- [0xca] = "LLNAMES",
- [0xcc] = "VERNUM",
- [0xce] = "VENDEXT",
- [0xf0] = "LIBHDR",
- [0xf1] = "LIBEND",
- };
- typedef void (*dump_func)(uint8_t, const uint8_t *, size_t);
- /* Ordered collection type */
- struct collection {
- size_t n; /* Elements in collection (not including 0) */
- size_t s; /* Elements allocated (not including 0) */
- const void **p; /* Element pointers */
- };
- struct collection c_names, c_lsegs, c_groups, c_extsym;
- static void nomem(void)
- {
- fprintf(stderr, "%s: memory allocation error\n", progname);
- exit(1);
- }
- #define INIT_SIZE 64
- static void add_collection(struct collection *c, const void *p)
- {
- if (c->n >= c->s) {
- size_t cs = c->s ? (c->s << 1) : INIT_SIZE;
- const void **cp = realloc(c->p, cs*sizeof(const void *));
- if (!cp)
- nomem();
- c->p = cp;
- c->s = cs;
- memset(cp + c->n, 0, (cs - c->n)*sizeof(const void *));
- }
- c->p[++c->n] = p;
- }
- static const void *get_collection(struct collection *c, size_t index)
- {
- if (index >= c->n)
- return NULL;
- return c->p[index];
- }
- static void hexdump_data(unsigned int offset, const uint8_t *data,
- size_t n, size_t field)
- {
- unsigned int i, j;
- for (i = 0; i < n; i += 16) {
- printf(" %04x: ", i+offset);
- for (j = 0; j < 16; j++) {
- char sep = (j == 7) ? '-' : ' ';
- if (i+j < field)
- printf("%02x%c", data[i+j], sep);
- else if (i+j < n)
- printf("xx%c", sep); /* Beyond end of... */
- else
- printf(" "); /* No separator */
- }
- printf(" : ");
- for (j = 0; j < 16; j++) {
- if (i+j < n)
- putchar((i+j >= field) ? 'x' :
- isprint(data[i+j]) ? data[i+j] : '.');
- }
- putchar('\n');
- }
- }
- static void dump_unknown(uint8_t type, const uint8_t *data, size_t n)
- {
- (void)type;
- hexdump_data(0, data, n, n);
- }
- static void print_dostime(const uint8_t *p)
- {
- uint16_t da = (p[3] << 8) + p[2];
- uint16_t ti = (p[1] << 8) + p[0];
- printf("%04u-%02u-%02u %02u:%02u:%02u",
- (da >> 9) + 1980, (da >> 5) & 15, da & 31,
- (ti >> 11), (ti >> 5) & 63, (ti << 1) & 63);
- }
- static void dump_coment_depfile(uint8_t type, const uint8_t *data, size_t n)
- {
- if (n > 4 && data[4] == n-5) {
- printf(" # ");
- print_dostime(data);
- printf(" %.*s\n", n-5, data+5);
- }
- hexdump_data(2, data, n, n);
- }
- static const dump_func dump_coment_class[256] = {
- [0xe9] = dump_coment_depfile
- };
- static void dump_coment(uint8_t type, const uint8_t *data, size_t n)
- {
- uint8_t class;
- static const char *coment_class[256] = {
- [0x00] = "Translator",
- [0x01] = "Copyright",
- [0x81] = "Library specifier",
- [0x9c] = "MS-DOS version",
- [0x9d] = "Memory model",
- [0x9e] = "DOSSEG",
- [0x9f] = "Library search",
- [0xa0] = "OMF extensions",
- [0xa1] = "New OMF extension",
- [0xa2] = "Link pass separator",
- [0xa3] = "LIBMOD",
- [0xa4] = "EXESTR",
- [0xa6] = "INCERR",
- [0xa7] = "NOPAD",
- [0xa8] = "WKEXT",
- [0xa9] = "LZEXT",
- [0xda] = "Comment",
- [0xdb] = "Compiler",
- [0xdc] = "Date",
- [0xdd] = "Timestamp",
- [0xdf] = "User",
- [0xe3] = "Type definition",
- [0xe8] = "Filename",
- [0xe9] = "Dependency file",
- [0xff] = "Command line"
- };
- if (n < 2) {
- hexdump_data(type, data, 2, n);
- return;
- }
- type = data[0];
- class = data[1];
- printf(" [NP=%d NL=%d UD=%02X] %02X %s\n",
- (type >> 7) & 1,
- (type >> 6) & 1,
- type & 0x3f,
- class,
- coment_class[class] ? coment_class[class] : "???");
- if (dump_coment_class[class])
- dump_coment_class[class](class, data+2, n-2);
- else
- hexdump_data(2, data+2, n-2, n-2);
- }
- /* Parse an index field */
- static uint16_t get_index(const uint8_t **pp)
- {
- uint8_t c;
- c = *(*pp)++;
- if (c & 0x80) {
- return ((c & 0x7f) << 8) + *(*pp)++;
- } else {
- return c;
- }
- }
- static uint16_t get_16(const uint8_t **pp)
- {
- uint16_t v = *(const uint16_t *)(*pp);
- (*pp) += 2;
- return v;
- }
- static uint32_t get_32(const uint8_t **pp)
- {
- const uint32_t v = *(const uint32_t *)(*pp);
- (*pp) += 4;
- return v;
- }
- /* Returns a name as a C string in a newly allocated buffer */
- char *lname(int index)
- {
- char *s;
- const char *p = get_collection(&c_names, index);
- size_t len;
- if (!p)
- return NULL;
- len = (uint8_t)p[0];
- s = malloc(len+1);
- if (!s)
- nomem();
- memcpy(s, p+1, len);
- s[len] = '\0';
- return s;
- }
- /* LNAMES or LLNAMES */
- static void dump_lnames(uint8_t type, const uint8_t *data, size_t n)
- {
- const uint8_t *p = data;
- const uint8_t *end = data + n;
- while (p < end) {
- size_t l = *p+1;
- if (l > n) {
- add_collection(&c_names, NULL);
- printf(" # %4u 0x%04x: \"%.*s... <%zu missing bytes>\n",
- c_names.n, c_names.n, n-1, p+1, l-n);
- } else {
- add_collection(&c_names, p);
- printf(" # %4u 0x%04x: \"%.*s\"\n",
- c_names.n, c_names.n, l-1, p+1);
- }
- hexdump_data(p-data, p, l, n);
- p += l;
- n -= l;
- }
- }
- /* SEGDEF16 or SEGDEF32 */
- static void dump_segdef(uint8_t type, const uint8_t *data, size_t n)
- {
- bool big = type & 1;
- const uint8_t *p = data;
- const uint8_t *end = data+n;
- uint8_t attr;
- static const char * const alignment[8] =
- { "ABS", "BYTE", "WORD", "PARA", "PAGE", "DWORD", "LTL", "?ALIGN" };
- static const char * const combine[8] =
- { "PRIVATE", "?COMMON", "PUBLIC", "?COMBINE", "?PUBLIC", "STACK", "COMMON", "?PUBLIC" };
- uint16_t idx;
- char *s;
- if (p >= end)
- return;
- attr = *p++;
- printf(" # %s (A%u) %s (C%u) %s%s",
- alignment[(attr >> 5) & 7], (attr >> 5) & 7,
- combine[(attr >> 2) & 7], (attr >> 2) & 7,
- (attr & 0x02) ? "MAXSIZE " : "",
- (attr & 0x01) ? "USE32" : "USE16");
- if (((attr >> 5) & 7) == 0) {
- /* Absolute segment */
- if (p+3 > end)
- goto dump;
- printf(" AT %04x:", get_16(&p));
- printf("%02x", *p++);
- }
- if (big) {
- if (p+4 > end)
- goto dump;
- printf(" size 0x%08x", get_32(&p));
- } else {
- if (p+2 > end)
- goto dump;
- printf(" size 0x%04x", get_16(&p));
- }
- idx = get_index(&p);
- if (p > end)
- goto dump;
- s = lname(idx);
- printf(" name '%s'", s);
- idx = get_index(&p);
- if (p > end)
- goto dump;
- s = lname(idx);
- printf(" class '%s'", s);
- idx = get_index(&p);
- if (p > end)
- goto dump;
- s = lname(idx);
- printf(" ovl '%s'", s);
- dump:
- putchar('\n');
- hexdump_data(0, data, n, n);
- }
- /* FIXUPP16 or FIXUPP32 */
- static void dump_fixupp(uint8_t type, const uint8_t *data, size_t n)
- {
- bool big = type & 1;
- const uint8_t *p = data;
- const uint8_t *end = data + n;
- static const char * const method_base[4] =
- { "SEGDEF", "GRPDEF", "EXTDEF", "frame#" };
- while (p < end) {
- const uint8_t *start = p;
- uint8_t op = *p++;
- uint16_t index;
- uint32_t disp;
- if (!(op & 0x80)) {
- /* THREAD record */
- bool frame = !!(op & 0x40);
- printf(" THREAD %-7s%d%s method %c%d (%s)",
- frame ? "frame" : "target", op & 3,
- (op & 0x20) ? " +flag5?" : "",
- (op & 0x40) ? 'F' : 'T',
- op & 3, method_base[op & 3]);
- if ((op & 0x50) != 0x50) {
- printf(" index 0x%04x", get_index(&p));
- }
- putchar('\n');
- } else {
- /* FIXUP subrecord */
- uint8_t fix;
- printf(" FIXUP %s-rel location %2d offset 0x%03x",
- (op & 0x40) ? "seg" : "self",
- (op & 0x3c) >> 2,
- ((op & 3) << 8) + *p++);
- fix = *p++;
- printf("\n frame %s%d%s",
- (fix & 0x80) ? "thread " : "F",
- ((fix & 0x70) >> 4),
- ((fix & 0xc0) == 0xc0) ? "?" : "");
- if ((fix & 0xc0) == 0)
- printf(" datum 0x%04x", get_index(&p));
- printf("\n target %s%d",
- (fix & 0x10) ? "thread " : "method T",
- fix & 3);
- if ((fix & 0x10) == 0)
- printf(" (%s)", method_base[fix & 3]);
- printf(" datum 0x%04x", get_index(&p));
- if ((fix & 0x08) == 0) {
- if (big) {
- printf(" disp 0x%08x", get_32(&p));
- } else {
- printf(" disp 0x%04x", get_16(&p));
- }
- }
- putchar('\n');
- }
- hexdump_data(start-data, start, p-start, n-(start-data));
- }
- }
- static const dump_func dump_type[256] =
- {
- [0x88] = dump_coment,
- [0x96] = dump_lnames,
- [0x98] = dump_segdef,
- [0x99] = dump_segdef,
- [0x9c] = dump_fixupp,
- [0x9d] = dump_fixupp,
- [0xca] = dump_lnames,
- };
- int dump_omf(int fd)
- {
- struct stat st;
- size_t len, n;
- uint8_t type;
- const uint8_t *p, *data;
- if (fstat(fd, &st))
- return -1;
- len = st.st_size;
- data = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
- if (data == MAP_FAILED)
- return -1;
- p = data;
- while (len >= 3) {
- uint8_t csum;
- int i;
- type = p[0];
- n = *(uint16_t *)(p+1);
- printf("%02x %-10s %4zd bytes",
- type,
- record_types[type] ? record_types[type] : "???",
- n);
- if (len < n+3) {
- printf("\n (truncated, only %zd bytes left)\n", len-3);
- break; /* Truncated */
- }
- p += 3; /* Header doesn't count in the length */
- n--; /* Remove checksum byte */
- csum = 0;
- for (i = -3; i < (int)n; i++)
- csum -= p[i];
- printf(", checksum %02X", p[i]);
- if (csum == p[i])
- printf(" (valid)\n");
- else
- printf(" (actual = %02X)\n", csum);
- if (dump_type[type])
- dump_type[type](type, p, n);
- else
- dump_unknown(type, p, n);
- p += n+1;
- len -= (n+4);
- }
- munmap((void *)data, st.st_size);
- return 0;
- }
- int main(int argc, char *argv[])
- {
- int fd;
- int i;
- progname = argv[0];
- for (i = 1; i < argc; i++) {
- fd = open(argv[i], O_RDONLY);
- if (fd < 0 || dump_omf(fd)) {
- perror(argv[i]);
- return 1;
- }
- close(fd);
- }
- return 0;
- }
|