Improve misc/omfdump, add misc/Makefile, use -std=c23 if possible

- Add improvements to omfdump from Bernd Böckmann.

- Add misc/Makefile with option to install omfdump and auxiliary NASM
  data files.

- Use compiler.h and friends in the misc directory.

- Use -std=c23 if the C compiler supports it.

Cc: Bernd Boeckmann <bernd-github@boeckmann.io>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin 2025-09-03 09:51:21 -07:00
parent 78abbf26df
commit 6c105cea3b
7 changed files with 663 additions and 248 deletions

1
.gitignore vendored
View file

@ -81,6 +81,7 @@ TAGS
/macros/macros.c
/misc/nasmtok.el
/misc/omfdump
/misc/Makefile
/nasm
/ndisasm
/nasm.spec

View file

@ -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:

View file

@ -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

105
misc/Makefile.in Normal file
View file

@ -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

View file

@ -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.

0
misc/nasmstab Normal file → Executable file
View file

View file

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "compiler.h"
#include "bytesex.h"
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/mman.h>
#include <sys/stat.h>
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;