diff --git a/.gitignore b/.gitignore index 97d7d87c2..de653e382 100644 --- a/.gitignore +++ b/.gitignore @@ -81,6 +81,7 @@ TAGS /macros/macros.c /misc/nasmtok.el /misc/omfdump +/misc/Makefile /nasm /ndisasm /nasm.spec diff --git a/Makefile.in b/Makefile.in index 4bf1bd299..6c308f23b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -88,7 +88,7 @@ endif .SUFFIXES: .SUFFIXES: $(X) .$(O) .$(A) .xml .1 .c .i .s .txt .time -.PHONY: all doc install clean distclean cleaner spotless test +.PHONY: all doc misc install clean distclean cleaner spotless test .PHONY: install_doc everything install_everything strip perlreq dist tags TAGS .PHONY: nothing manpages nsis @@ -208,7 +208,7 @@ LIBOBJ = $(LIBOBJ_W) $(LIBOBJ_NW) $(ZLIB) ALLOBJ_W = $(NASM) $(LIBOBJ_W) ALLOBJ = $(PROGOBJ) $(LIBOBJ) SUBDIRS = stdlib nasmlib include config output asm disasm x86 \ - common zlib macros + common zlib macros misc XSUBDIRS = test doc nsis win DEPDIRS = . $(SUBDIRS) #-- End File Lists --# @@ -463,11 +463,12 @@ distclean: clean done $(RM_F) test/*.$(O) $(RM_F) *.dep - -sh autoconf/clean.sh || sh '$(srcdir)'/autoconf/clean.sh + -$(SHELL) autoconf/clean.sh || $(SHELL) '$(srcdir)'/autoconf/clean.sh cleaner: $(RM_F) $(PERLREQ_CL) *.1 nasm.spec $(MAKE) -C doc clean + $(MAKE) -C misc clean $(MAKE) distclean $(RM_F) */*.time @@ -493,9 +494,15 @@ cscope: doc: doc/warnings.src doc/perlbreq.src $(MAKE) -C doc all -doc_install install_doc: +doc_install install_doc install-doc: $(MAKE) -C doc install +misc: + $(MAKE) -C misc all + +misc_install install_misc install-misc: + $(MAKE) -C misc install + # Dummy target to prevent accidental invocation of the default "all" target nothing: diff --git a/configure.ac b/configure.ac index 346082f9a..a5886ea68 100644 --- a/configure.ac +++ b/configure.ac @@ -20,9 +20,10 @@ PA_CROSS_COMPILE dnl Enable any available C extensions PA_PROG_CC AC_USE_SYSTEM_EXTENSIONS -PA_ADD_CPPFLAGS([-std=c17], [], [], -[PA_ADD_CPPFLAGS([-std=c11], [], [], - [PA_ADD_CPPFLAGS([-std=c99])])]) +PA_ADD_CPPFLAGS([-std=c23], [], [], +[PA_ADD_CPPFLAGS([-std=c17], [], [], + [PA_ADD_CPPFLAGS([-std=c11], [], [], + [PA_ADD_CPPFLAGS([-std=c99])])])]) dnl Options for debugging and profiling PA_OPTION_DEBUG @@ -377,5 +378,5 @@ dnl PA_CHECK_BAD_STDC_INLINE PA_C_TYPEOF -AC_CONFIG_FILES([Makefile doc/Makefile test/Makefile]) +AC_CONFIG_FILES([Makefile doc/Makefile misc/Makefile test/Makefile]) AC_OUTPUT diff --git a/misc/Makefile.in b/misc/Makefile.in new file mode 100644 index 000000000..72628522a --- /dev/null +++ b/misc/Makefile.in @@ -0,0 +1,105 @@ +# +# Makefile for various extra NASM programs and files +# + +@SET_MAKE@ + +top_srcdir = @top_srcdir@ +srcdir = @srcdir@ +top_objdir = @top_builddir@ +objdir = @builddir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +mandir = @mandir@ +docdir = @docdir@ +htmldir = @htmldir@ +infodir = @infodir@ +datarootdir = @datarootdir@ + +datadir = $(datarootdir)/nasm + +CC = @CC@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +BUILD_CFLAGS = $(CPPFLAGS) $(CFLAGS) @DEFS@ +INTERNAL_CFLAGS = -I$(srcdir) -I$(objdir) \ + -I$(top_srcdir) -I$(top_objdir) \ + -I$(top_srcdir)/include -I$(top_objdir)/include \ + -I$(top_srcdir)/config -I$(top_objdir)/config +ALL_CFLAGS = $(BUILD_CFLAGS) $(INTERNAL_CFLAGS) +LDFLAGS = @LDFLAGS@ +ALL_LDFLAGS = $(ALL_CFLAGS) $(LDFLAGS) +LIBS = @LIBS@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +PERL = perl +RUNPERL = $(PERL) -I$(top_srcdir)/perllib -I$(srcdir) + +MKDIR_P = @MKDIR_P@ +RM_F = rm -f +RM_RF = rm -rf +CP_F = cp -f +CP_UF = cp -uf + +PROGS = omfdump$(X) +GENDATA = nasmtok.el +SRCDATA = README \ + c16.mac c32.mac exebin.mac exebin2.mac \ + myC32.mac scitech.mac \ + nasmstab + +# Binary suffixes +O = @OBJEXT@ +X = @EXEEXT@ +A = @LIBEXT@ + +# Don't delete intermediate files +.SECONDARY: + +# Delete files on error +.DELETE_ON_ERROR: + +.SUFFIXES: +.SUFFIXES: .$(O) .$(A) $(X) .c .i .s + +all: $(PROGS) $(GENDATA) + +.c.$(O): + $(CC) $(ALL_CFLAGS) -c -o $@ $< + +.c.s: + $(CC) $(ALL_CFLAGS) -S -o $@ $< + +.c.i: + $(CC) $(ALL_CFLAGS) -E -o $@ $< + +omfdump$(X): omfdump.$(O) + $(CC) $(ALL_LDFLAGS) -o $@ $< $(LIBS) + +nasmtok.el: + $(MAKE) -C .. + +install-prog: $(PROGS) + $(MKDIR_P) $(DESTDIR)$(bindir) + $(INSTALL_PROGRAM) $(PROGS) $(DESTDIR)$(bindir)/ + +DATAFILES = $(GENDATA) $(SRCDATA:%=$(srcdir)/%) + +install-data: $(DATAFILES) + $(MKDIR_P) $(DESTDIR)$(datadir) + $(INSTALL_DATA) $(DATAFILES) $(DESTDIR)$(datadir)/ + +install: install-prog install-data + +clean: + -$(RM_F) *.$(O) *.$(A) $(PROGS) $(GENDATA) + +spotless: clean + +Makefile: Makefile.in ../config.status + $(SHELL) ../config.status diff --git a/misc/README b/misc/README index f39ba4d2d..577aacfec 100644 --- a/misc/README +++ b/misc/README @@ -1,2 +1,2 @@ -There are various helpful bits and pieces for NASM, -including but not limited to Simon photograph =) +There are various helpful bits and pieces for NASM. Many of these are +contributed by users, and may be out of date. Patches are accepted. diff --git a/misc/nasmstab b/misc/nasmstab old mode 100644 new mode 100755 diff --git a/misc/omfdump.c b/misc/omfdump.c index 8afdcd95a..34b88d068 100644 --- a/misc/omfdump.c +++ b/misc/omfdump.c @@ -5,29 +5,38 @@ * * This assumes a littleendian, unaligned-load-capable host and a * C compiler which handles basic C99. + * + * Copyright (c) 1996-2010, the NASM Authors + * Copyright (c) 2023, Bernd Boeckmann + * + * see LICENCE file for licensing terms */ -#include -#include -#include -#include +#include "compiler.h" +#include "bytesex.h" + #include -#include -#include -#include -#include -#include + +typedef struct { + uint16_t name_idx; + uint16_t class_idx; + uint16_t ovl_idx; +} segdef_t; + +typedef struct { + uint16_t name_idx; +} grpdef_t; const char *progname; -static const char *record_types[256] = -{ +static const char *record_types[256] = { [0x80] = "THEADR", [0x82] = "LHEADR", [0x88] = "COMENT", [0x8a] = "MODEND16", [0x8b] = "MODEND32", [0x8c] = "EXTDEF", + [0x8e] = "TYPDEF", [0x90] = "PUBDEF16", [0x91] = "PUBDEF32", [0x94] = "LINNUM16", @@ -68,44 +77,77 @@ 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 */ + size_t n; /* Elements in collection (not including 0) */ + size_t s; /* Elements allocated (not including 0) */ + void const **p; /* Element pointers */ }; struct collection c_names, c_lsegs, c_groups, c_extsym; -static void nomem(void) +static void *nulldie(void *ptr) { + if (likely(ptr)) + return ptr; + fprintf(stderr, "%s: memory allocation error\n", progname); exit(1); + abort(); /* This should never happen */ +} + +static void *xmalloc(size_t size) +{ + return nulldie(malloc(size)); +} + +static void *xrealloc(void *ptr, size_t size) +{ + return nulldie(realloc(ptr, size)); +} + +/* Make sure there is enough space for at least one additional element */ +static void *expand_buffer(void *buf, size_t *bufsizep, size_t datasize, + size_t elemsize) +{ + size_t bufsize = *bufsizep; + + if (likely(bufsize < datasize)) + return buf; + + if (bufsize < BUFSIZ) + bufsize = BUFSIZ; + else + bufsize <<= 1; + + if (bufsize <= datasize) + bufsize = datasize+1; + + buf = xrealloc(buf, bufsize * elemsize); + *bufsizep = bufsize; + + return buf; } -#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; + c->p = expand_buffer(c->p, &c->s, c->n, sizeof(const void *)); + c->p[c->n++] = p; } -static const void *get_collection(struct collection *c, size_t index) +static const void *get_collection(struct collection *c, size_t index, + const void *invalid) { - if (index >= c->n) - return NULL; + if (index == 0 || index > c->n) + return invalid; - return c->p[index]; + return c->p[index - 1]; +} + +static uint8_t *copy_name(size_t len, const uint8_t *data) +{ + uint8_t *r = xmalloc(len + 1); + memcpy(r, data, len); + r[len] = '\0'; + return r; } static void hexdump_data(unsigned int offset, const uint8_t *data, @@ -114,23 +156,23 @@ static void hexdump_data(unsigned int offset, const uint8_t *data, unsigned int i, j; for (i = 0; i < n; i += 16) { - printf(" %04x: ", i+offset); - for (j = 0; j < 16; j++) { + 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... */ + 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'); + 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'); } } @@ -152,10 +194,12 @@ static void print_dostime(const uint8_t *p) static void dump_coment_depfile(uint8_t type, const uint8_t *data, size_t n) { - if (n > 4 && data[4] == n-5) { + (void)type; + + if (n > 4 && data[4] == n - 5) { printf(" # "); print_dostime(data); - printf(" %.*s\n", n-5, data+5); + printf(" %.*s\n", (int)(n - 5), data + 5); } hexdump_data(2, data, n, n); @@ -169,52 +213,51 @@ 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", + [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" + [0xe9] = "Dependency file", + [0xff] = "Command line" }; if (n < 2) { - hexdump_data(type, data, 2, n); - return; + hexdump_data(type, data, 2, n); + return; } - type = data[0]; + 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] : "???"); + (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); + dump_coment_class[class] (class, data + 2, n - 2); else - hexdump_data(2, data+2, n-2, n-2); + hexdump_data(2, data + 2, n - 2, n - 2); } /* Parse an index field */ @@ -232,7 +275,7 @@ static uint16_t get_index(const uint8_t **pp) static uint16_t get_16(const uint8_t **pp) { - uint16_t v = *(const uint16_t *)(*pp); + uint16_t v = getu16(*pp); (*pp) += 2; return v; @@ -240,32 +283,39 @@ static uint16_t get_16(const uint8_t **pp) static uint32_t get_32(const uint8_t **pp) { - const uint32_t v = *(const uint32_t *)(*pp); + const uint32_t v = getu32(*pp); (*pp) += 4; return v; } -/* Returns a name as a C string in a newly allocated buffer */ -char *lname(int index) +/* Returns a name as a constant, persistent C string */ +static const char *lname(int index) { - char *s; - const char *p = get_collection(&c_names, index); - size_t len; + return get_collection(&c_names, index, ""); +} - if (!p) - return NULL; +static const char *segment_name(uint16_t segment_idx) +{ + const segdef_t *seg; + seg = get_collection(&c_lsegs, segment_idx, NULL); + if (!seg) + return ""; + return lname(seg->name_idx); +} - len = (uint8_t)p[0]; +static const char *group_name(uint16_t group_idx) +{ + const grpdef_t *grp; + grp = get_collection(&c_groups, group_idx, NULL); + if (!grp) + return ""; + return lname(grp->name_idx); +} - s = malloc(len+1); - if (!s) - nomem(); - - memcpy(s, p+1, len); - s[len] = '\0'; - - return s; +static const char *external_name(uint16_t idx) +{ + return get_collection(&c_extsym, idx, ""); } /* LNAMES or LLNAMES */ @@ -273,21 +323,25 @@ 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; + uint8_t *s; + + (void)type; while (p < end) { - size_t l = *p+1; + size_t l = *p; 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); + s = copy_name(n, p+1); + add_collection(&c_names, s); + printf(" # %4zu 0x%04zx: \"%.*s... <%zu missing bytes>\n", + c_names.n, c_names.n, (int)(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); + s = copy_name(l, p+1); + add_collection(&c_names, s); + printf(" [%04zx] '%s'\n", c_names.n, s); } - hexdump_data(p-data, p, l, n); - p += l; - n -= l; + hexdump_data(p - data, p, l + 1, n); + p += l + 1; + n -= l + 1; } } @@ -296,81 +350,195 @@ 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; + 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; + 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" }; + const char *s; + + segdef_t *seg = xmalloc(sizeof(segdef_t)); if (p >= end) - return; + 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"); + 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++); + /* 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)); + if (p + 4 > end) + goto dump; + printf(" size %08x", get_32(&p)); } else { - if (p+2 > end) - goto dump; - printf(" size 0x%04x", get_16(&p)); + if (p + 2 > end) + goto dump; + printf(" size %04x", get_16(&p)); + } + puts(""); + + seg->name_idx = get_index(&p); + if (p > end) + goto dump; + s = lname(seg->name_idx); + printf(" name '%s'", s); + + seg->class_idx = get_index(&p); + if (p > end) + goto dump; + s = lname(seg->class_idx); + if (*s) { + printf(", class '%s'", s); } - idx = get_index(&p); + seg->ovl_idx = get_index(&p); if (p > end) - goto dump; - s = lname(idx); - printf(" name '%s'", s); + goto dump; + s = lname(seg->ovl_idx); + if (*s) { /* s points to empty string if no overlay is given */ + printf(", ovl '%s'", s); + } - idx = get_index(&p); - if (p > end) - goto dump; - s = lname(idx); - printf(" class '%s'", s); + add_collection(&c_lsegs, seg); - idx = get_index(&p); - if (p > end) - goto dump; - s = lname(idx); - printf(" ovl '%s'", s); - -dump: + dump: putchar('\n'); hexdump_data(0, data, n, n); } +static void dump_grpdef(uint8_t type, const uint8_t *data, size_t n) +{ + const uint8_t *p = data; + const uint8_t *end = data + n; + const char *s; + uint16_t name_idx; + grpdef_t *grp; + + (void)type; + + grp = xmalloc(sizeof(grpdef_t)); + + name_idx = get_index(&p); + grp->name_idx = name_idx; + + if (p > end) + goto dump; + + add_collection(&c_groups, grp); + + s = lname(name_idx); + printf(" name '%s'\n", s); + + while (p < end) { + if (*p == 0xff) { /* segment */ + p++; + printf(" segment '%s'\n", segment_name(get_index(&p))); + } else if (*p == 0xfe) { + p++; + name_idx = get_index(&p); + s = lname(name_idx); + printf(" external '%s'\n", s); + } else + goto dump; + } + + dump: + hexdump_data(0, data, n, n); +} + +static const char *const method_base[16] = { + "SEGDEF", "GRPDEF", "EXTDEF", "frame#", + "SEGDEF", "GRPDEF", "EXTDEF", "unsupported", + "SEGDEF", "GRPDEF", "EXTDEF", "frame#", + "prev. LEDATA SEG index", "TARGET index", "invalid", "unsupported" +}; + +static const char *location_descr[16] = { + "low-order byte", "16-bit offset", "16-bit segment", "32-bit far ptr", + "hi-order byte", "16-bit ldr-resolved offset", "reserved", "reserved", + "unknown", "32-bit offset", "unknown", "48-bit ptr", "unknown", + "32-bit ldr-resolved offset", "unknown", "unknown" +}; + +/* helper routine used in fixup and modend dumps */ +static void dump_fixdat(bool big, const uint8_t **data) +{ + const uint8_t *p = *data; + + uint8_t fix; + uint16_t idx; + + fix = *p++; + + /* frame decoding */ + printf("\n frame %s%d%s", + (fix & 0x80) ? "thread " : "method F", + ((fix & 0x70) >> 4), ((fix & 0xc0) == 0xc0) ? "?" : ""); + if ((fix & 0x80) == 0) + printf(" (%s)", method_base[((fix >> 4) & 7) + 8]); + if ((fix & 0xc0) == 0) { + idx = get_index(&p); + printf(" index %04x", idx); + if ((fix >> 4) == 0) { + printf(" '%s'", segment_name(idx)); + } else if ((fix >> 4) == 1) { + printf(" '%s'", group_name(idx)); + } else if ((fix >> 4) == 2) { + printf(" '%s'", external_name(idx)); + } + } + + /* target decoding */ + printf("\n target %s%d", + (fix & 0x08) ? "thread " : "method T", fix & 7); + if ((fix & 0x08) == 0) + printf(" (%s)", method_base[(fix & 7)]); + if ((fix & 0x08) == 0) { + idx = get_index(&p); + printf(" index %04x", idx); + if ((fix & 3) == 0) { + printf(" '%s'", segment_name(idx)); + } else if ((fix & 3) == 1) { + printf(" '%s'", group_name(idx)); + } else if ((fix & 3) == 2) { + printf(" '%s'", external_name(idx)); + } + } + if ((fix & 0x04) == 0) { + if (big) { + printf(" disp %08x", get_32(&p)); + } else { + printf(" disp %04x", get_16(&p)); + } + } + putchar('\n'); + + *data = p; +} + /* 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 */ @@ -380,137 +548,270 @@ static void dump_fixupp(uint8_t type, const uint8_t *data, size_t n) frame ? "frame" : "target", op & 3, (op & 0x20) ? " +flag5?" : "", (op & 0x40) ? 'F' : 'T', - op & 3, method_base[op & 3]); + ((op & 0x1c) >> 2), + method_base[((op & 0x40) >> 3) | ((op & 0x1c) >> 2)]); if ((op & 0x50) != 0x50) { - printf(" index 0x%04x", get_index(&p)); + printf(" index %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", + printf(" FIXUP %s-relative, type %d (%s)\n" + " record offset %04x", + (op & 0x40) ? "segment" : "self", (op & 0x3c) >> 2, - ((op & 3) << 8) + *p++); + location_descr[(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'); + dump_fixdat(big, &p); } - hexdump_data(start-data, start, p-start, n-(start-data)); + hexdump_data(start - data, start, p - start, n - (start - data)); } } -static const dump_func dump_type[256] = +static void dump_ledata(uint8_t type, const uint8_t *data, size_t n) { + bool big = type & 1; + const uint8_t *p = data; + const segdef_t *seg = get_collection(&c_lsegs, get_index(&p), NULL); + const char *seg_name = "(null)"; + size_t data_len; + + if (seg != NULL) + seg_name = lname(seg->name_idx); + + printf(" segment '%s', ", seg_name); + + if (big) { + printf("offset %08x\n", get_32(&p)); + } else { + printf("offset %04x\n", get_16(&p)); + } + + data_len = n - (p - data); + hexdump_data(0, p, data_len, data_len); +} + +static void dump_pubdef(uint8_t type, const uint8_t *data, size_t n) +{ + static int pub_names_count; + bool big = type & 1; + const uint8_t *p = data; + const uint8_t *end = data + n; + uint16_t grp_idx; + uint16_t seg_idx; + uint16_t type_idx; + int name_len; + + grp_idx = get_index(&p); + if (p > end) + goto dump; + + seg_idx = get_index(&p); + if (p > end) + goto dump; + + if (grp_idx == 0 && seg_idx == 0) { + printf(" frame %04x", get_16(&p)); + } else { + printf(" "); + if (seg_idx) { + printf(" segment '%s'", segment_name(seg_idx)); + } + if (grp_idx) { + printf(" group '%s'", group_name(grp_idx)); + } + } + puts(""); + + while (p < end) { + pub_names_count++; + + name_len = *p++; + printf(" [%04x] public name '%.*s' ", pub_names_count, name_len, p); + p += name_len; + + if (big) { + printf("offset %08x", get_32(&p)); + } else { + printf("offset %04x", get_16(&p)); + } + type_idx = get_index(&p); + if (type_idx) { + printf(", type %d", type_idx); + } + puts(""); + } + + dump: + hexdump_data(0, data, n, n); +} + +static void dump_extdef(uint8_t type, const uint8_t *data, size_t n) +{ + static int ext_names_count; + const uint8_t *p = data; + const uint8_t *end = data + n; + uint16_t type_idx; + int name_len; + uint8_t *name; + + (void)type; + + while (p < end) { + ext_names_count++; + name_len = *p++; + name = copy_name(name_len, p); + add_collection(&c_extsym, name); + p += name_len; + printf(" [%04x] external name '%s'", ext_names_count, name); + type_idx = get_index(&p); + if (type_idx) { + printf(", type %d", type_idx); + } + puts(""); + } + + hexdump_data(0, data, n, n); +} + +static void dump_modend(uint8_t type, const uint8_t *data, size_t n) +{ + const uint8_t *p = data; + + if (*p & 0x80) + printf(" main module\n"); + if (*p & 0x40) { + printf(" start address:"); + p++; + dump_fixdat(type & 1, &p); + } + hexdump_data(0, data, n, n); +} + +static const dump_func dump_type[256] = { [0x88] = dump_coment, + [0x8a] = dump_modend, + [0x8c] = dump_extdef, + [0x90] = dump_pubdef, + [0x91] = dump_pubdef, [0x96] = dump_lnames, [0x98] = dump_segdef, [0x99] = dump_segdef, + [0x9a] = dump_grpdef, [0x9c] = dump_fixupp, [0x9d] = dump_fixupp, + [0xa0] = dump_ledata, + [0xa1] = dump_ledata, [0xca] = dump_lnames, }; -int dump_omf(int fd) +static uint8_t *read_file(FILE *f, size_t *sz) +{ + uint8_t *buf = NULL; + size_t bufsize = 0; + size_t bytes; + size_t size = 0; + + if (fseek(f, 0, SEEK_END)) { + /* Try to get the size of the file to preallocate buffer */ + bufsize = ftell(f); + if (bufsize) + buf = xmalloc(bufsize); + } + rewind(f); + + do { + buf = expand_buffer(buf, &bufsize, size, 1); + bytes = fread(buf + size, 1, bufsize - size, f); + if (ferror(f)) { + free(buf); + *sz = 0; + return NULL; + } + + size += bytes; + } while (bytes && !feof(f)); + + *sz = size; + if (size != bufsize) + buf = xrealloc(buf, size); + + return buf; +} + +static int dump_omf(FILE *f) { - 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; + data = read_file(f, &len); + if (!data) + return -1; p = data; - while (len >= 3) { - uint8_t csum; - int i; + while (len >= 3 && *p != 0x1a) { + uint8_t csum; + int i; - type = p[0]; - n = *(uint16_t *)(p+1); + type = p[0]; + n = *(uint16_t *) (p + 1); - printf("%02x %-10s %4zd bytes", - type, - record_types[type] ? record_types[type] : "???", - n); + 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 */ - } + 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 */ + 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]; + 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); + 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); + if (dump_type[type]) + dump_type[type] (type, p, n); + else + dump_unknown(type, p, n); - p += n+1; - len -= (n+4); + p += n + 1; + len -= (n + 4); } - munmap((void *)data, st.st_size); + free((void *)data); return 0; } int main(int argc, char *argv[]) { - int fd; + FILE *f; int i; progname = argv[0]; + if (argc < 2) { + fputs("omfdump - dump contents of object module files to stdout\n" + "Usage: omfdump file...\n", stdout); + return 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); + f = fopen(argv[i], "rb"); + if (!f || dump_omf(f)) { + perror(argv[i]); + return 1; + } + fclose(f); } return 0;