summaryrefslogtreecommitdiff
path: root/vere/ext/nasm/misc/omfdump.c
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-10-05 21:56:51 +0700
committerpolwex <polwex@sortug.com>2025-10-05 21:56:51 +0700
commitfcedfddf00b3f994e4f4e40332ac7fc192c63244 (patch)
tree51d38e62c7bdfcc5f9a5e9435fe820c93cfc9a3d /vere/ext/nasm/misc/omfdump.c
claude is gud
Diffstat (limited to 'vere/ext/nasm/misc/omfdump.c')
-rw-r--r--vere/ext/nasm/misc/omfdump.c516
1 files changed, 516 insertions, 0 deletions
diff --git a/vere/ext/nasm/misc/omfdump.c b/vere/ext/nasm/misc/omfdump.c
new file mode 100644
index 0000000..b27e7c9
--- /dev/null
+++ b/vere/ext/nasm/misc/omfdump.c
@@ -0,0 +1,516 @@
+/*
+ * 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 <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;
+}