commit 7cde34f9285a940a998c32f70e523783b98aa15c
parent a99a218615a40203e5a9b10f233deb8e79235a3d
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Sat, 18 Jan 2025 23:56:03 +0100
objdump: Add new version of objdump
This is a more advanced version of objdump that what we used to
have. The old version was only dumping data, and while this version
is still a work in progress it mimics very well the behaviour of
GNU objdump, giving very useful debug information. Currently only
coff32 is supported, but elf64 is expected to happen soon.
Diffstat:
6 files changed, 580 insertions(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
@@ -9,7 +9,7 @@ dirs
/deps
/src/cmd/scc-addr2line
/src/cmd/scc-objcopy
-/src/cmd/scc-objdump
+/src/cmd/scc-objdump/scc-objdump
/src/cmd/scc-size
/src/cmd/scc-strip
/src/cmd/scc-ar
diff --git a/src/cmd/Makefile b/src/cmd/Makefile
@@ -5,6 +5,7 @@ DIRS =\
scc-as\
scc-cc\
scc-make\
+ scc-objdump\
PROJECTDIR = ../..
include $(PROJECTDIR)/scripts/rules.mk
diff --git a/src/cmd/scc-objdump/Makefile b/src/cmd/scc-objdump/Makefile
@@ -0,0 +1,17 @@
+.POSIX:
+
+PROJECTDIR = ../../..
+include $(PROJECTDIR)/scripts/rules.mk
+
+OBJS =\
+ main.o\
+ coff32.o\
+
+TARGET = scc-objdump
+MORE_LDLIBS = -lmach -lscc
+
+all: $(TARGET)
+
+scc-objdump: $(OBJS) $(LIBMACH) $(LIBSCC)
+ $(CC) $(PROJ_LDFLAGS) $(OBJS) $(PROJ_LDLIBS) -o $@
+ cp $@ $(BINDIR)
diff --git a/src/cmd/scc-objdump/coff32.c b/src/cmd/scc-objdump/coff32.c
@@ -0,0 +1,165 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <scc/mach.h>
+#include <scc/coff32.h>
+
+#include "objdump.h"
+
+void
+coff32syms(Obj *obj)
+{
+ long i;
+ struct coff32 *coff = obj->data;
+ FILHDR *hdr = &coff->hdr;
+
+ for (i = 0; i < hdr->f_nsyms; i++) {
+ SYMENT *ent;
+ AUXENT *aux;
+ Entry *ep = &coff->ents[i];
+
+ aux = &ep->u.aux;
+ switch (ep->type) {
+ case SYM_ENT:
+ ent = &ep->u.sym;
+ printf("[%4ld](sec %2d)(ty %4x)(scl %3d) (nx %d) 0x%04lX %s\n",
+ i,
+ ent->n_scnum,
+ ent->n_type,
+ ent->n_sclass,
+ ent->n_numaux,
+ ent->n_value,
+ coff32str(coff, ent));
+ break;
+ case SYM_AUX_UNK:
+ puts("AUX");
+ break;
+ case SYM_AUX_SYM:
+ printf("AUX tagndx %ld lnno %d size 0x%x lnnoptr %ld endndx %ld tv %d\n",
+ aux->x_tagndx,
+ aux->x_lnno,
+ aux->x_size,
+ aux->x_lnnoptr,
+ aux->x_endndx,
+ aux->x_tvndx);
+ break;
+ case SYM_AUX_FILE:
+ printf("File %s\n", coff32str(coff, aux));
+ break;
+ case SYM_AUX_SCN:
+ printf("AUX scnlen 0x%lx nreloc %d nlnno %d chk %lu ass %d comdat %d\n",
+ aux->x_scnlen,
+ aux->x_nreloc,
+ aux->x_nlinno,
+ aux->x_checksum,
+ aux->x_associated,
+ aux->x_comdat);
+ break;
+ case SYM_AUX_FUN:
+ printf("AUX tagndx %ld fsize 0x%lx lnnoptr %ld endndx %ld tv %d\n",
+ aux->x_fsize,
+ aux->x_tagndx,
+ aux->x_lnnoptr,
+ aux->x_endndx,
+ aux->x_tvndx);
+ break;
+ case SYM_AUX_ARY:
+ break;
+ abort();
+ }
+ }
+}
+
+void
+coff32scns(Obj *obj)
+{
+ int i;
+ SCNHDR *scn;
+ struct coff32 *coff = obj->data;
+ FILHDR *hdr = &coff->hdr;
+
+ for (i = 0; i < hdr->f_nscns; i++) {
+ scn = &coff->scns[i];
+ printf("\nscnhdr: %d\n"
+ "\tname: %s\n"
+ "\ts_paddr: 0x%04lx\n"
+ "\ts_vaddr: 0x%04lx\n"
+ "\ts_size: 0x%04lx\n"
+ "\ts_scnptr: %ld\n"
+ "\ts_relptr: %ld\n"
+ "\ts_lnnoptr: %ld\n"
+ "\ts_nrelloc: %u\n"
+ "\ts_nlnno: %u\n"
+ "\ts_flags: %#lx\n",
+ i,
+ coff32str(coff, scn),
+ scn->s_paddr,
+ scn->s_vaddr,
+ scn->s_size,
+ scn->s_scnptr,
+ scn->s_relptr,
+ scn->s_lnnoptr,
+ scn->s_nrelloc,
+ scn->s_nlnno,
+ scn->s_flags);
+ }
+}
+
+unsigned
+coff32fhdr(Obj *obj, unsigned long long *start)
+{
+ unsigned flags, r;
+ struct coff32 *coff = obj->data;
+ FILHDR *hdr = &coff->hdr;
+ AOUTHDR *aout = &coff->aout;
+
+ if (pflag) {
+ printf("FILEHDR:\n"
+ "\tf_magic: %#x\n"
+ "\tf_nscns: %u\n"
+ "\tf_timdat: %ld\n"
+ "\tf_symptr: %ld\n"
+ "\tf_nsyms: %ld\n"
+ "\tf_opthdr: %u\n"
+ "\tf_flags: 0x%04x\n\n",
+ hdr->f_magic,
+ hdr->f_nscns,
+ hdr->f_timdat,
+ hdr->f_symptr,
+ hdr->f_nsyms,
+ hdr->f_opthdr,
+ hdr->f_flags);
+ }
+
+ if (pflag && hdr->f_opthdr > 0) {
+ printf("AOUTHDR:\n"
+ "\tmagic: %x\n"
+ "\tvstamp: %x\n"
+ "\ttsize: %04lx\n"
+ "\tdsize: %04lx\n"
+ "\tbsize: %04lx\n"
+ "\tentry: %04lx\n"
+ "\ttext_start: %04lx\n"
+ "\tdata_start: %04lx\n\n",
+ aout->magic,
+ aout->vstamp,
+ aout->tsize,
+ aout->dsize,
+ aout->bsize,
+ aout->entry,
+ aout->text_start,
+ aout->data_start);
+ *start = aout->entry;
+ }
+
+ r = 0;
+ flags = hdr->f_flags;
+ setflag(&r, (flags & F_RELFLG) == 0, HAS_RELOC);
+ setflag(&r, (flags & F_LMNO) == 0, HAS_LINENO);
+ setflag(&r, (flags & F_LSYMS) == 0, HAS_LOCALS);
+ setflag(&r, hdr->f_nsyms > 0, HAS_SYMS);
+ setflag(&r, flags & F_EXEC, EXEC_P);
+ setflag(&r, flags & F_EXEC, D_PAGED);
+
+ return r;
+}
diff --git a/src/cmd/scc-objdump/main.c b/src/cmd/scc-objdump/main.c
@@ -0,0 +1,362 @@
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <scc/ar.h>
+#include <scc/arg.h>
+#include <scc/scc.h>
+#include <scc/mach.h>
+
+#include "objdump.h"
+
+int tflag, fflag, hflag, pflag, aflag, rflag;
+char *argv0;
+
+static int status;
+static char *filename, *membname;
+
+void
+error(char *fmt, ...)
+{
+ va_list va;
+
+ va_start(va, fmt);
+ fprintf(stderr, "objdump: %s: ", filename);
+ if (membname)
+ fprintf(stderr, "%s: ", membname);
+ vfprintf(stderr, fmt, va);
+ putc('\n', stderr);
+ va_end(va);
+
+ status = EXIT_FAILURE;
+}
+
+void
+setflag(unsigned *r, int cond, int flag)
+{
+ if (cond)
+ *r |= 1 << flag;
+}
+
+static void
+printfileflags(unsigned flags)
+{
+ int first, i;
+ static const char *text[] = {
+ [HAS_RELOC] = "HAS_RELOC",
+ [EXEC_P] = "EXEC_P",
+ [HAS_LINENO] = "HAS_LINENO",
+ [HAS_DEBUG] = "HAS_DEBUG",
+ [HAS_SYMS] = "HAS_SYMS",
+ [HAS_LOCALS] = "HAS_LOCALS",
+ [D_PAGED] = "D_PAGED",
+ };
+
+ first = 1;
+ for (i = 0; i < NR_FILE_FLAGS; i++) {
+ if (flags & 1) {
+ if (!first)
+ fputs(", ", stdout);
+ first = 0;
+ fputs(text[i], stdout);
+ }
+ flags >>= 1;
+ }
+
+ putchar('\n');
+}
+
+static void
+dumpfhdr(Obj *obj, char *fmt)
+{
+ unsigned f;
+ unsigned long long start = 0;
+
+ printf("architecture: %s, flags: 0x%08x\n",
+ strchr(fmt, '-') + 1,
+ obj->type);
+
+ switch (FORMAT(obj->type)) {
+ case COFF32:
+ f = coff32fhdr(obj, &start);
+ break;
+ default:
+ error("unknown fhdr binary format");
+ return;
+ }
+
+ printfileflags(f);
+ printf("start address 0x%08llx\n", start);
+}
+
+static void
+printsecflags(unsigned flags)
+{
+ int first, i;
+ static const char *text[] = {
+ [SEC_HAS_CONTENTS] = "CONTENTS",
+ [SEC_ALLOC] = "ALLOC",
+ [SEC_LOAD] = "LOAD",
+ [SEC_RELOC] = "RELOC",
+ [SEC_READONLY] = "READONLY",
+ [SEC_CODE] = "CODE",
+ [SEC_DATA] = "DATA",
+ [SEC_DEBUGGING] = "DEBUGGING",
+ };
+
+ first = 1;
+ fputs(" ", stdout);
+ for (i = 0; i < NR_SEC_FLAGS; i++) {
+ if (flags & 1) {
+ if (!first)
+ fputs(", ", stdout);
+ first = 0;
+ fputs(text[i], stdout);
+ }
+ flags >>= 1;
+ }
+
+ putchar('\n');
+}
+
+static int
+logb2(unsigned val)
+{
+ int n;
+
+ for (n = 0; (val & 1) == 0; n++)
+ val >>= 1;
+ return n;
+}
+
+static void
+dumpscns(Obj *obj)
+{
+ int i, debug;
+ unsigned f, flags;
+ Section sec;
+
+ puts("Sections:");
+ puts("Idx Name Size VMA LMA File off Algn");
+ for (i = 0; getsec(obj, &i, &sec); i++) {
+ printf("%3d %-13s %08llx %08llx %08llx %08llx 2**%d\n",
+ sec.index,
+ sec.name,
+ sec.size,
+ sec.base,
+ sec.load,
+ sec.offset,
+ logb2(sec.align));
+
+ f = 0;
+ flags = sec.flags;
+ debug = sec.type == 'N';
+ setflag(&f, flags & SALLOC, SEC_ALLOC);
+ setflag(&f, flags & SLOAD, SEC_LOAD);
+ setflag(&f, (flags & SRELOC) && sec.nreloc > 0, SEC_RELOC);
+ setflag(&f, (flags & SWRITE) == 0 && !debug, SEC_READONLY);
+ setflag(&f, flags & SEXEC, SEC_CODE);
+ setflag(&f, (flags & (SEXEC|SLOAD)) == SLOAD, SEC_DATA);
+ setflag(&f, debug, SEC_DEBUGGING);
+ setflag(&f, sec.size > 0, SEC_HAS_CONTENTS);
+ printsecflags(f);
+ }
+
+ if (!pflag)
+ return;
+
+ switch (FORMAT(obj->type)) {
+ case COFF32:
+ coff32scns(obj);
+ break;
+ default:
+ error("unknown fhdr binary format");
+ }
+}
+
+static void
+dumpsyms(Obj *obj)
+{
+ puts("SYMBOL TABLE:");
+ switch (FORMAT(obj->type)) {
+ case COFF32:
+ coff32syms(obj);
+ break;
+ default:
+ error("unknown symbol binary format");
+ }
+}
+
+static void
+dumpobj(FILE *fp, int type, char *fmt)
+{
+ Obj *obj;
+
+ printf("\n%s", filename);
+ if (membname)
+ printf("(%s)", membname);
+ printf(":\tfile format %s\n", fmt);
+
+ if ((obj = newobj(type)) == NULL) {
+ error("failed object allocation");
+ return;
+ }
+
+ if (readobj(obj, fp) < 0) {
+ error("object file corrupted");
+ goto err;
+ }
+
+ if (fflag)
+ dumpfhdr(obj, fmt);
+ if (hflag)
+ dumpscns(obj);
+ if (tflag)
+ dumpsyms(obj);
+
+err:
+ delobj(obj);
+}
+
+static void
+dumprights(unsigned r)
+{
+ putchar((r & 4) ? 'r' : '-');
+ putchar((r & 2) ? 'w' : '-');
+ putchar((r & 1) ? 'x' : '-');
+}
+
+static void
+dumpar(char *fname, struct ar_hdr *hdr, char *fmt)
+{
+ time_t t;
+ int n;
+ struct tm *tm;
+ char buf[60];
+ unsigned long mode;
+
+ printf("%s: file format %s\n", fname, fmt);
+
+ mode = strtol(hdr->ar_mode, NULL, 8);
+ dumprights((mode >> 6) & 7);
+ dumprights((mode >> 3) & 7);
+ dumprights(mode & 7);
+
+ t = fromepoch(atoll(hdr->ar_date));
+ strftime(buf, sizeof(buf), "%c", gmtime(&t));
+ printf(" %d/%d %lld %s %s\n\n",
+ atoi(hdr->ar_uid),
+ atoi(hdr->ar_gid),
+ atoll(hdr->ar_size),
+ buf,
+ fname);
+}
+
+static void
+dumplib(FILE *fp)
+{
+ int t;
+ char *fmt;
+ long off, cur;
+ struct ar_hdr hdr;
+ char memb[SARNAM+1];
+
+ for (;;) {
+ cur = ftell(fp);
+
+ off = armember(fp, memb, &hdr);
+ switch (off) {
+ case -1:
+ error("library corrupted");
+ if (ferror(fp))
+ error(strerror(errno));
+ case 0:
+ return;
+ default:
+ membname = memb;
+ if ((t = objprobe(fp, &fmt)) != -1) {
+ if (aflag)
+ dumpar(memb, &hdr, fmt);
+ dumpobj(fp, t, fmt);
+ }
+ membname = NULL;
+ fseek(fp, cur, SEEK_SET);
+ fseek(fp, off, SEEK_CUR);
+ break;
+ }
+ }
+}
+
+static void
+objdump(char *fname)
+{
+ int t;
+ char *fmt;
+ FILE *fp;
+
+ membname = NULL;
+ filename = fname;
+ if ((fp = fopen(fname, "rb")) == NULL) {
+ error(strerror(errno));
+ return;
+ }
+
+ if ((t = objprobe(fp, &fmt)) != -1)
+ dumpobj(fp, t, fmt);
+ else if (archive(fp))
+ dumplib(fp);
+ else
+ error("bad format");
+
+ fclose(fp);
+}
+
+static void
+usage(void)
+{
+ fputs("usage: objdump [-afhpt] file...\n", stderr);
+ exit(EXIT_FAILURE);
+}
+
+int
+main(int argc, char *argv[])
+{
+ ARGBEGIN {
+ case 'a':
+ aflag = 1;
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 'h':
+ hflag = 1;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ default:
+ usage();
+ } ARGEND
+
+ if (argc == 0) {
+ objdump("a.out");
+ } else {
+ for ( ; *argv; ++argv)
+ objdump(*argv);
+ }
+
+ if (fflush(stdout)) {
+ fprintf(stderr,
+ "size: error writing in output:%s\n",
+ strerror(errno));
+ status = 1;
+ }
+
+ return status;
+}
diff --git a/src/cmd/scc-objdump/objdump.h b/src/cmd/scc-objdump/objdump.h
@@ -0,0 +1,34 @@
+enum file_flags {
+ HAS_RELOC,
+ EXEC_P,
+ HAS_LINENO,
+ HAS_DEBUG,
+ HAS_SYMS,
+ HAS_LOCALS,
+ D_PAGED,
+ NR_FILE_FLAGS,
+};
+
+enum sec_flags {
+ SEC_HAS_CONTENTS,
+ SEC_ALLOC,
+ SEC_LOAD,
+ SEC_RELOC,
+ SEC_READONLY,
+ SEC_CODE,
+ SEC_DATA,
+ SEC_DEBUGGING,
+ NR_SEC_FLAGS,
+};
+
+/* coff32.c */
+extern void coff32syms(Obj *);
+extern void coff32scns(Obj *);
+extern unsigned coff32fhdr(Obj *, unsigned long long *);
+
+/* main.c */
+extern void error(char *, ...);
+extern void setflag(unsigned *, int, int);
+
+/* globals */
+extern int pflag;