scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | LICENSE

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:
M.gitignore | 2+-
Msrc/cmd/Makefile | 1+
Asrc/cmd/scc-objdump/Makefile | 17+++++++++++++++++
Asrc/cmd/scc-objdump/coff32.c | 165+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/cmd/scc-objdump/main.c | 362+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/cmd/scc-objdump/objdump.h | 34++++++++++++++++++++++++++++++++++
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;