ref: c00d99fba090c89e1fd9e6874b91e8aafadba8d6
parent: 25bc36bff00d311a5d3fd681ecf20b707df455a4
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Fri Jan 4 08:39:16 EST 2019
[libmach] First version of libmach Libmach is a library to abstract the details of the different object and executable formats. This is only a first version and more work is expected.
--- /dev/null
+++ b/include/scc/scc/mach.h
@@ -1,0 +1,30 @@
+typedef struct symbol Symbol;
+typedef struct object Obj;
+
+struct symbol {
+ char type;
+ char *name;
+ unsigned long long size;
+ unsigned long long value;
+};
+
+struct object {
+ int type;
+ Symbol *symtbl;
+ unsigned long nsym;
+ unsigned long cursym;
+ fpos_t pos;
+ void *data;
+};
+
+extern int archive(FILE *fp);
+extern int armember(FILE *fp, char *member);
+
+extern int artraverse(FILE *fp,
+ int (*fn)(FILE *, char *, void *),
+ void *data);
+
+extern int objtest(FILE *fp, char **name);
+extern int objopen(FILE *fp, int type, Obj *obj);
+extern int objread(FILE *fp, Obj *obj, int (*filter)(Symbol *));
+extern void objclose(Obj *obj);
--- a/src/Makefile
+++ b/src/Makefile
@@ -4,7 +4,7 @@
include $(PROJECTDIR)/scripts/rules.mk
TOOLS = cc1 cc2 ld as nm objdump
-LIBS = libscc libcoff32 libc libcrt
+LIBS = libscc libcoff32 libc libcrt libmach
DIRS = $(TOOLS) $(LIBS)
all: $(TOOLS)
--- /dev/null
+++ b/src/libmach/Makefile
@@ -1,0 +1,17 @@
+.POSIX:
+PROJECTDIR =../..
+include $(PROJECTDIR)/scripts/rules.mk
+
+TARGET = $(LIBDIR)/libmach.a
+OBJS = object.o \
+ archive.o \
+ pack.o \
+ unpack.o \
+ artraverse.o \
+ armember.o \
+ coff32.o \
+
+all: $(TARGET)
+
+$(TARGET): $(OBJS)
+ mklib -o $@ $?
--- /dev/null
+++ b/src/libmach/archive.c
@@ -1,0 +1,24 @@
+#include <stdio.h>
+#include <string.h>
+
+#include <scc/ar.h>
+#include <scc/mach.h>
+#include "libmach.h"
+
+int
+archive(FILE *fp)
+{
+ int n;
+ fpos_t pos;
+ char magic[SARMAG];
+
+ fgetpos(fp, &pos);
+
+ n = fread(magic, SARMAG, 1, fp);
+ if (n == 1 && strncmp(magic, ARMAG, SARMAG) == 0)
+ return 1;
+
+ fsetpos(fp, &pos);
+
+ return 0;
+}
--- /dev/null
+++ b/src/libmach/armember.c
@@ -1,0 +1,46 @@
+#include <stdio.h>
+#include <string.h>
+
+#include <scc/ar.h>
+#include <scc/mach.h>
+
+static char *
+getfname(struct ar_hdr *hdr, char *dst)
+{
+ char *p;
+ int i;
+
+ memcpy(dst, hdr->ar_name, SARNAM);
+ dst[SARNAM] = '\0';
+
+ for (i = SARNAM-1; i >= 0; i--) {
+ if (dst[i] != ' ' && dst[i] != '/')
+ break;
+ dst[i] = '\0';
+ }
+ return dst;
+}
+
+int
+armember(FILE *fp, char *member)
+{
+ struct ar_hdr hdr;
+ long siz;
+
+ if (fread(&hdr, sizeof(hdr), 1, fp) != 1)
+ return (feof(fp)) ? 0 : -1;
+
+ if (strncmp(hdr.ar_fmag, ARFMAG, sizeof(hdr.ar_fmag)))
+ return -1;
+
+ siz = 0;
+ sscanf(hdr.ar_size, "%10ld", &siz);
+ if (siz & 1)
+ siz++;
+ if (siz == 0)
+ return -1;
+
+ getfname(&hdr, member);
+
+ return 0;
+}
--- /dev/null
+++ b/src/libmach/artraverse.c
@@ -1,0 +1,29 @@
+#include <stdio.h>
+
+#include <scc/ar.h>
+#include <scc/mach.h>
+
+int
+artraverse(FILE *fp, int (*fn)(FILE *, char *, void *), void *data)
+{
+ int r;
+ long off;
+ fpos_t pos;
+ char name[SARNAM+1];
+
+ for (;;) {
+ fgetpos(fp, &pos);
+
+ if ((off = armember(fp, name)) < 0)
+ return -1;
+ r = !(*fn)(fp, name, data);
+ if (!r)
+ return r;
+
+ fsetpos(fp, &pos);
+ fseek(fp, off, SEEK_SET);
+
+ if (off == 0)
+ return 0;
+ }
+}
--- /dev/null
+++ b/src/libmach/coff32.c
@@ -1,0 +1,286 @@
+#include <assert.h>
+#include <ctype.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <scc/coff32/filehdr.h>
+#include <scc/coff32/scnhdr.h>
+#include <scc/coff32/syms.h>
+#include <scc/mach.h>
+
+#include "libmach.h"
+
+typedef struct coff32 Coff32;
+
+struct arch {
+ char *name;
+ unsigned char magic[2];
+ int type;
+};
+
+struct coff32 {
+ FILHDR hdr;
+ SCNHDR *scns;
+ SYMENT *ents;
+ char *strtbl;
+ unsigned long strsiz;
+};
+
+static struct arch archs[] = {
+ "coff32-i386", "\x4c\x01", OBJ(COFF32, ARCH386, LITTLE_ENDIAN),
+ "coff32-z80", "\x5a\x80", OBJ(COFF32, ARCHZ80, LITTLE_ENDIAN),
+ NULL,
+};
+
+static void
+unpack_hdr(int order, unsigned char *buf, FILHDR *hdr)
+{
+ int n;
+
+ n = unpack(order,
+ buf,
+ "sslllss",
+ &hdr->f_magic,
+ &hdr->f_nscns,
+ &hdr->f_timdat,
+ &hdr->f_symptr,
+ &hdr->f_nsyms,
+ &hdr->f_opthdr,
+ &hdr->f_flags);
+ assert(n == FILHSZ);
+}
+
+static void
+unpack_scn(int order, unsigned char *buf, SCNHDR *scn)
+{
+ int n;
+
+ n = unpack(order,
+ buf,
+ "'8llllllssl",
+ scn->s_name,
+ &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);
+ assert(n == SCNHSZ);
+}
+
+static void
+unpack_ent(int order, unsigned char *buf, SYMENT *ent)
+{
+ int n;
+ char *s;
+
+ n = unpack(order,
+ buf,
+ "'8lsscc",
+ ent->n_name,
+ &ent->n_value,
+ &ent->n_scnum,
+ &ent->n_type,
+ &ent->n_sclass,
+ &ent->n_numaux);
+ assert(n == SYMESZ);
+
+ s = ent->n_name;
+ if (!s[0] && !s[1] && !s[2] && !s[3])
+ unpack(order, "ll", buf, &ent->n_zeroes, &ent->n_offset);
+}
+
+int
+coff32probe(unsigned char *buf, char **name)
+{
+ struct arch *ap;
+
+ for (ap = archs; ap->name; ap++) {
+ if (ap->magic[0] == buf[0] && ap->magic[1] == buf[1]) {
+ if (name)
+ *name = ap->name;
+ return ap->type;
+ }
+ }
+ return -1;
+}
+
+int
+coff32open(FILE *fp, int type, Obj *obj)
+{
+ int order;
+ long i, siz;
+ FILHDR *hdr;
+ SCNHDR *scn = NULL;
+ SYMENT *ent = NULL;
+ char *str = NULL;
+ struct coff32 *coff = NULL;
+ unsigned char buf[100];
+
+ assert(FILHSZ < sizeof(buf));
+ assert(SCNHSZ < sizeof(buf));
+ assert(SYMESZ < sizeof(buf));
+
+ coff = calloc(1, sizeof(*coff));
+ if (!coff)
+ goto error;
+ hdr = &coff->hdr;
+
+ order = ORDER(type);
+ if (fgetpos(fp, &obj->pos))
+ goto error;
+ if (fread(buf, FILHSZ, 1, fp) != 1)
+ goto error;
+ unpack_hdr(order, buf, hdr);
+
+ if (hdr->f_nscns > 0) {
+ scn = calloc(hdr->f_nscns, sizeof(*scn));
+ if (!scn)
+ goto error;
+ coff->scns = scn;
+ }
+ if (hdr->f_nsyms > 0) {
+ ent = calloc(hdr->f_nsyms, sizeof(*ent));
+ if (!ent)
+ goto error;
+ coff->ents = ent;
+ }
+
+ if (fseek(fp, hdr->f_opthdr, SEEK_CUR) < 0)
+ goto error;
+ for (i = 0; i < hdr->f_nscns; i++) {
+ if (fread(buf, SCNHSZ, 1, fp) < 0)
+ goto error;
+ unpack_scn(order, buf, &scn[i]);
+ }
+
+ if (fsetpos(fp, &obj->pos))
+ return -1;
+ if (fseek(fp, hdr->f_symptr, SEEK_CUR) < 0)
+ return -1;
+ for (i = 0; i < hdr->f_nsyms; i++) {
+ if (fread(buf, SYMESZ, 1, fp) != 1)
+ goto error;
+ unpack_ent(order, buf, &ent[i]);
+ }
+
+ if (fread(buf, 4, 1, fp) != 1)
+ goto error;
+ unpack(order, buf, "l", &siz);
+ siz -= 4;
+ if (siz > 0) {
+ if (siz > SIZE_MAX)
+ goto error;
+ str = malloc(siz);
+ if (!str)
+ goto error;
+ if (fread(str, siz, 1, fp) != 1)
+ goto error;
+ coff->strtbl = str;
+ coff->strsiz = siz;
+ }
+ obj->data = coff;
+
+ return 0;
+
+error:
+ free(str);
+ free(scn);
+ free(ent);
+ free(coff);
+
+ return -1;
+}
+
+static char *
+symname(Coff32 *coff, SYMENT *ent)
+{
+ long off;
+
+ if (ent->n_zeroes != 0)
+ return ent->n_name;
+
+ off = ent->n_offset;
+ if (off >= coff->strsiz)
+ return NULL;
+ return &coff->strtbl[off];
+}
+
+static int
+typeof(Coff32 *coff, SYMENT *ent)
+{
+ int c;
+ SCNHDR *scn;
+ long flags;
+
+ switch (ent->n_scnum) {
+ case N_DEBUG:
+ c = 'N';
+ break;
+ case N_ABS:
+ c = 'a';
+ break;
+ case N_UNDEF:
+ c = (ent->n_value != 0) ? 'C' : 'U';
+ break;
+ default:
+ if (ent->n_scnum > coff->hdr.f_nscns)
+ return -1;
+ scn = &coff->scns[ent->n_scnum-1];
+ flags = scn->s_flags;
+ if (flags & STYP_TEXT)
+ c = 't';
+ else if (flags & STYP_DATA)
+ c = 'd';
+ else if (flags & STYP_BSS)
+ c = 'b';
+ else
+ c = '?';
+ break;
+ }
+
+ if (ent->n_sclass == C_EXT)
+ c = toupper(c);
+
+ return c;
+
+}
+
+int
+coff32read(Obj *obj, Symbol *sym)
+{
+ int t;
+ char *s;
+ SYMENT *ent;
+ Coff32 *coff = obj->data;
+
+ if (obj->cursym >= coff->hdr.f_nsyms)
+ return 0;
+ ent = &coff->ents[obj->cursym];
+
+ if ((t = typeof(coff, ent)) < 0)
+ return -1;
+
+ if ((s = symname(coff, ent)) == NULL)
+ return -1;
+
+ obj->cursym += ent->n_numaux + 1;
+ sym->type = t;
+ sym->name = s;
+ sym->value = ent->n_value;
+ sym->size = (sym->type == 'C') ? ent->n_value : 0;
+ return 1;
+}
+
+void
+coff32close(Obj *obj)
+{
+ struct coff32 *coff = obj->data;
+
+ free(coff->scns);
+ free(obj->data);
+}
--- /dev/null
+++ b/src/libmach/libmach.h
@@ -1,0 +1,36 @@
+#define NBYTES 20
+#define OBJ(format,arch,order) ((order) << 10 | (arch) << 5 | (format))
+#define FORMAT(t) ((t) & 0x1f)
+#define ARCH(t) (((t) >> 5) & 0x1f)
+#define ORDER(t) (((t) >> 10) & 0x1f)
+
+enum objformat {
+ COFF16,
+ COFF32,
+ ELF32,
+ ELF64,
+ NFORMATS,
+};
+
+enum objarch {
+ ARCH286,
+ ARCH386,
+ ARCHAMD64,
+ ARCHZ80,
+ ARCHARM32,
+ ARCHARM64,
+};
+
+enum order {
+ LITTLE_ENDIAN,
+ BIG_ENDIAN,
+};
+
+extern int pack(int order, unsigned char *dst, char *fmt, ...);
+extern int unpack(int order, unsigned char *src, char *fmt, ...);
+
+/* coff32.c */
+int coff32probe(unsigned char *buf, char **name);
+int coff32open(FILE *fp, int type, Obj *obj);
+int coff32read(Obj *obj, Symbol *sym);
+void coff32close(Obj *obj);
--- /dev/null
+++ b/src/libmach/object.c
@@ -1,0 +1,118 @@
+static char sccsid[] = "@(#) ./libmach/object.c";
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <scc/mach.h>
+
+#include "libmach.h"
+
+struct format {
+ int (*probe)(unsigned char *buf, char **name);
+ int (*open)(FILE *fp, int type, Obj *obj);
+ int (*read)(Obj *obj, Symbol *sym);
+ void (*close)(Obj *obj);
+};
+
+static struct format fmts[] = {
+ [COFF32] = {coff32probe, coff32open, coff32read, coff32close},
+ [NFORMATS] = {NULL},
+};
+
+int
+objtest(FILE *fp, char **name)
+{
+ int n, i;
+ int (*fn)(unsigned char *, char **);
+ fpos_t pos;
+ unsigned char buf[NBYTES];
+
+ fgetpos(fp, &pos);
+ n = fread(buf, NBYTES, 1, fp);
+ fsetpos(fp, &pos);
+
+ if (n != 1 || ferror(fp))
+ return -1;
+
+ for (i = 0; i < NFORMATS; i++) {
+ fn = fmts[i].probe;
+ if (!fn)
+ continue;
+ n = (*fn)(buf, name);
+ if (n == -1)
+ continue;
+ return n;
+ }
+
+ return -1;
+}
+
+int
+objopen(FILE *fp, int type, Obj *obj)
+{
+ struct format *op;
+
+ obj->type = type;
+ obj->symtbl = NULL;
+ obj->data = NULL;
+ obj->nsym = obj->cursym = 0;
+ op = &fmts[FORMAT(type)];
+ if ((*op->open)(fp, type, obj) < 0)
+ return -1;
+ return 0;
+}
+
+static int
+addsym(Obj *obj, Symbol *sym)
+{
+ Symbol *p, *new;
+ char *s;
+ size_t len, siz = obj->nsym * sizeof(*sym);
+
+ if (siz > SIZE_MAX - sizeof(*sym))
+ return -1;
+ siz += sizeof(*sym);
+ if ((p = realloc(obj->symtbl, siz)) == NULL)
+ return -1;
+ obj->symtbl = p;
+
+ new = &p[obj->nsym];
+ new->type = sym->type;
+ len = strlen(sym->name) + 1;
+ if ((new->name = malloc(len)) == NULL)
+ return -1;
+ memcpy(new->name, sym->name, len);
+ new->size = sym->size;
+ new->value = sym->value;
+ obj->nsym++;
+
+ return 0;
+}
+
+int
+objread(FILE *fp, Obj *obj, int (*filter)(Symbol *))
+{
+ int r;
+ Symbol sym, *p;
+ struct format *op;
+
+ op = &fmts[FORMAT(obj->type)];
+ while ((r = (*op->read)(obj, &sym)) > 0) {
+ if (filter && (*filter)(&sym))
+ continue;
+ addsym(obj, &sym);
+ }
+
+ return r;
+}
+
+void
+objclose(Obj *obj)
+{
+ struct format *op;
+
+ op = &fmts[FORMAT(obj->type)];
+ (*op->close)(obj);
+}
--- /dev/null
+++ b/src/libmach/pack.c
@@ -1,0 +1,132 @@
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <scc/mach.h>
+#include "libmach.h"
+
+static int
+lpack(unsigned char *dst, char *fmt, va_list va)
+{
+ unsigned char *bp, *cp;
+ unsigned s;
+ unsigned long l;
+ unsigned long long q;
+ int n;
+
+ bp = dst;
+ while (*fmt) {
+ switch (*fmt++) {
+ case '\'':
+ n = atoi(fmt);
+ while (isdigit(fmt))
+ fmt++;
+ cp = va_arg(va, unsigned char *);
+ while (n--)
+ *bp++ = *cp++;
+ break;
+ case 'c':
+ *bp++ = va_arg(va, unsigned);
+ break;
+ case 's':
+ s = va_arg(va, unsigned);
+ *bp++ = s;
+ *bp++ = s >> 8;
+ break;
+ case 'l':
+ l = va_arg(va, unsigned long);
+ *bp++ = l;
+ *bp++ = l >> 8;
+ *bp++ = l >> 16;
+ *bp++ = l >> 24;
+ break;
+ case 'q':
+ q = va_arg(va, unsigned long long);
+ *bp++ = q;
+ *bp++ = q >> 8;
+ *bp++ = q >> 16;
+ *bp++ = q >> 24;
+ *bp++ = q >> 32;
+ *bp++ = q >> 40;
+ *bp++ = q >> 48;
+ *bp++ = q >> 56;
+ break;
+ default:
+ va_end(va);
+ return -1;
+ }
+ }
+
+ return bp - dst;
+}
+
+static int
+bpack(unsigned char *dst, char *fmt, va_list va)
+{
+ unsigned char *bp, *cp;
+ unsigned s;
+ unsigned long l;
+ unsigned long long q;
+ int n;
+
+ bp = dst;
+ while (*fmt) {
+ switch (*fmt++) {
+ case '\'':
+ n = atoi(fmt);
+ while (isdigit(*fmt))
+ fmt++;
+ cp = va_arg(va, unsigned char *);
+ while (n--)
+ *bp++ = *cp++;
+ break;
+ case 'c':
+ *bp++ = va_arg(va, unsigned);
+ break;
+ case 's':
+ s = va_arg(va, unsigned);
+ *bp++ = s >> 8;
+ *bp++ = s;
+ break;
+ case 'l':
+ l = va_arg(va, unsigned long);
+ *bp++ = l >> 24;
+ *bp++ = l >> 16;
+ *bp++ = l >> 8;
+ *bp++ = l;
+ break;
+ case 'q':
+ q = va_arg(va, unsigned long long);
+ *bp++ = q >> 56;
+ *bp++ = q >> 48;
+ *bp++ = q >> 40;
+ *bp++ = q >> 32;
+ *bp++ = q >> 24;
+ *bp++ = q >> 16;
+ *bp++ = q >> 8;
+ *bp++ = q;
+ break;
+ default:
+ va_end(va);
+ return -1;
+ }
+ }
+
+ return bp - dst;
+}
+
+int
+pack(int order, unsigned char *dst, char *fmt, ...)
+{
+ int r;
+ int (*fn)(unsigned char *dst, char *fmt, va_list va);
+ va_list va;
+
+ va_start(va, fmt);
+ fn = (order == LITTLE_ENDIAN) ? lpack : bpack;
+ r = (*fn)(dst, fmt, va);
+ va_end(va);
+
+ return r;
+}
--- /dev/null
+++ b/src/libmach/unpack.c
@@ -1,0 +1,144 @@
+static char sccsid[] = "@(#) ./lib/scc/lunpack.c";
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <scc/mach.h>
+#include "libmach.h"
+
+static int
+lunpack(unsigned char *src, char *fmt, va_list va)
+{
+ unsigned char *bp, *cp;
+ unsigned short *sp;
+ unsigned s;
+ unsigned long *lp, l;
+ unsigned long long *qp, q;
+ int n;
+
+ bp = src;
+ while (*fmt) {
+ switch (*fmt++) {
+ case '\'':
+ n = atoi(fmt);
+ while (isdigit(*fmt))
+ fmt++;
+ cp = va_arg(va, unsigned char *);
+ while (n--)
+ *cp++ = *bp++;
+ break;
+ case 'c':
+ cp = va_arg(va, unsigned char *);
+ *cp = *bp++;
+ break;
+ case 's':
+ sp = va_arg(va, unsigned short *);
+ s = (unsigned) *bp++;
+ s |= (unsigned) *bp++ << 8;
+ *sp = s;
+ break;
+ case 'l':
+ lp = va_arg(va, unsigned long *);
+ l = (unsigned long) *bp++;
+ l |= (unsigned long) *bp++ << 8;
+ l |= (unsigned long) *bp++ << 16;
+ l |= (unsigned long) *bp++ << 24;
+ *lp = l;
+ break;
+ case 'q':
+ qp = va_arg(va, unsigned long long *);
+ q = (unsigned long long) *bp++;
+ q |= (unsigned long long) *bp++ << 8;
+ q |= (unsigned long long) *bp++ << 16;
+ q |= (unsigned long long) *bp++ << 24;
+ q |= (unsigned long long) *bp++ << 32;
+ q |= (unsigned long long) *bp++ << 40;
+ q |= (unsigned long long) *bp++ << 48;
+ q |= (unsigned long long) *bp++ << 56;
+ *qp = q;
+ break;
+ default:
+ va_end(va);
+ return -1;
+ }
+ }
+
+ return bp - src;
+}
+
+static int
+bunpack(unsigned char *src, char *fmt, va_list va)
+{
+ unsigned char *bp, *cp;
+ unsigned short *sp;
+ unsigned s;
+ unsigned long *lp, l;
+ unsigned long long *qp, q;
+ int n;
+
+ bp = src;
+ while (*fmt) {
+ switch (*fmt++) {
+ case '\'':
+ n = atoi(fmt);
+ while (isdigit(*fmt))
+ fmt++;
+ cp = va_arg(va, unsigned char *);
+ while (n--)
+ *cp++ = *bp++;
+ break;
+ case 'c':
+ cp = va_arg(va, unsigned char *);
+ *cp = *bp++;
+ break;
+ case 's':
+ sp = va_arg(va, unsigned short *);
+ s = (unsigned) *bp++ << 8;
+ s |= (unsigned) *bp++;
+ *sp = s;
+ break;
+ case 'l':
+ lp = va_arg(va, unsigned long *);
+ l = (unsigned long) *bp++ << 24;
+ l |= (unsigned long) *bp++ << 16;
+ l |= (unsigned long) *bp++ << 8;
+ l |= (unsigned long) *bp++;
+ *lp = l;
+ break;
+ case 'q':
+ qp = va_arg(va, unsigned long long *);
+ q = (unsigned long long) *bp++ << 56;
+ q |= (unsigned long long) *bp++ << 48;
+ q |= (unsigned long long) *bp++ << 40;
+ q |= (unsigned long long) *bp++ << 32;
+ q |= (unsigned long long) *bp++ << 24;
+ q |= (unsigned long long) *bp++ << 16;
+ q |= (unsigned long long) *bp++ << 8;
+ q |= (unsigned long long) *bp++;
+ *qp = q;
+ break;
+ default:
+ va_end(va);
+ return -1;
+ }
+ }
+
+ return bp - src;
+}
+
+int
+unpack(int order, unsigned char *src, char *fmt, ...)
+{
+ int r;
+ int (*fn)(unsigned char *dst, char *fmt, va_list va);
+ va_list va;
+
+ va_start(va, fmt);
+ fn = (order == LITTLE_ENDIAN) ? lunpack : bunpack;
+ r = (*fn)(src, fmt, va);
+ va_end(va);
+
+ return r;
+}
--- a/src/nm/Makefile
+++ b/src/nm/Makefile
@@ -4,17 +4,15 @@
include $(PROJECTDIR)/scripts/rules.mk
OBJS = main.o \
- coff32.o \
- formats.o \
TARGET = $(BINDIR)/nm
all: $(TARGET)
-$(TARGET): $(LIBDIR)/libscc.a
+$(TARGET): $(LIBDIR)/libscc.a $(LIBDIR)/libmach.a
$(TARGET): $(OBJS)
- $(CC) $(SCC_LDFLAGS) $(OBJS) -lscc -o $@
+ $(CC) $(SCC_LDFLAGS) $(OBJS) -lmach -lscc -o $@
dep: inc-dep
--- a/src/nm/coff32.c
+++ /dev/null
@@ -1,312 +1,0 @@
-static char sccsid[] = "@(#) ./nm/coff.c";
-
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <scc/coff32/filehdr.h>
-#include <scc/coff32/scnhdr.h>
-#include <scc/coff32/syms.h>
-#include <scc/scc.h>
-#include "nm.h"
-
-static int (*unpack)(unsigned char *, char *, ...);
-static long strtbl, symtbl, sectbl;
-static SCNHDR *sections;
-static struct symbol *syms;
-static size_t nsect, nsyms;
-
-static char
-typeof(SYMENT *ent)
-{
- SCNHDR *sec;
- int c;
- long flags;
-
- switch (ent->n_scnum) {
- case N_DEBUG:
- c = 'n';
- break;
- case N_ABS:
- c = 'a';
- break;
- case N_UNDEF:
- c = (ent->n_value != 0) ? 'C' : 'U';
- break;
- default:
- if (ent->n_scnum > nsect)
- die("nm: incorrect section index");
- sec = §ions[ent->n_scnum-1];
- flags = sec->s_flags;
- if (flags & STYP_TEXT)
- c = 't';
- else if (flags & STYP_DATA)
- c = 'd';
- else if (flags & STYP_BSS)
- c = 'b';
- else
- c = '?';
- break;
- }
-
- if (ent->n_sclass == C_EXT)
- c = toupper(c);
-
- return c;
-}
-
-static char *
-getsname(char *fname, FILE *fp, SYMENT *ent)
-{
- int c;
- size_t len;
- char *s, *err;
- fpos_t pos;
-
- if (ent->n_zeroes != 0) {
- for (len = 0; len < E_SYMNMLEN && ent->n_name[len]; ++len)
- ;
- s = xmalloc(len+1);
- s[len] = '\0';
- return memcpy(s, ent->n_name, len);
- }
-
- /* TODO: read the string table in memory before reading symbols */
- fgetpos(fp, &pos);
- fseek(fp, strtbl, SEEK_SET);
- fseek(fp, ent->n_offset, SEEK_CUR);
-
- if (ferror(fp))
- goto error;
-
- s = NULL;
- for (len = 1; (c = getc(fp)) != EOF; len++) {
- s = xrealloc(s, len);
- if ((s[len-1] = c) == '\0')
- break;
- }
- if (c == EOF)
- goto error;
- fsetpos(fp, &pos);
- return s;
-
-error:
- err = (!ferror(fp)) ?
- "EOF before reading strings" : strerror(errno);
- die("nm: %s: %s", fname, err);
-}
-
-static void
-getfsym(unsigned char *buff, SYMENT *ent)
-{
- int n;
-
- n = (*unpack)(buff,
- "'8lsscc",
- &ent->n_name,
- &ent->n_value,
- &ent->n_scnum,
- &ent->n_type,
- &ent->n_sclass,
- &ent->n_numaux);
- assert(n == SYMESZ);
-}
-
-static void
-getsymbol(char *fname, FILE *fp,
- unsigned char *buff, SYMENT *ent, struct symbol *sym)
-{
- char *nam;
-
- getfsym(buff, ent);
- nam = ent->n_name;
- if (nam[0] == 0 && nam[1] == 0 && nam[2] == 0 && nam[3] == 0) {
- long zero, offset;
-
- (*unpack)(nam, "ll", &zero, &offset);
- ent->n_zeroes = zero;
- ent->n_offset = offset;
- }
- sym->name = getsname(fname, fp, ent);
- sym->type = typeof(ent);
- sym->value = ent->n_value;
- sym->size = (sym->type == 'C') ? ent->n_value : 0;
-}
-
-static void
-getsyms(char *fname, char *member, FILE *fp, FILHDR *hdr)
-{
- size_t n, i;
- unsigned aux;
- unsigned char buff[SYMESZ];
- SYMENT ent;
-
- if (hdr->f_nsyms > SIZE_MAX)
- die("nm: %s:Too many symbols\n", member);
-
- n = hdr->f_nsyms;
- syms = xcalloc(sizeof(*syms), n);
-
- if (fseek(fp, symtbl, SEEK_SET) == EOF)
- die("nm: %s:%s", fname, strerror(errno));
-
- aux = nsyms = 0;
- for (i = 0; i < n; i++) {
- if (fread(buff, SYMESZ, 1, fp) != 1)
- break;
- if (aux > 0) {
- aux--;
- continue;
- }
- getsymbol(member, fp, buff, &ent, &syms[nsyms++]);
- aux = ent.n_numaux;
- }
- if (n != i) {
- char *err;
-
- err = (!ferror(fp)) ?
- "EOF before reading symbols" : strerror(errno);
- die("nm: %s: %s", fname, err);
- }
-}
-
-static void
-getfsec(unsigned char *buff, SCNHDR *sec)
-{
- int n;
-
- n = (*unpack)(buff,
- "'8llllllssl",
- sec->s_name,
- &sec->s_paddr,
- &sec->s_vaddr,
- &sec->s_size,
- &sec->s_scnptr,
- &sec->s_relptr,
- &sec->s_lnnoptr,
- &sec->s_nrelloc,
- &sec->s_nlnno,
- &sec->s_flags);
- assert(n == SCNHSZ);
-}
-
-static void
-getsects(char *fname, char *member, FILE *fp, FILHDR *hdr)
-{
- size_t i;
- char buff[SCNHSZ];
-
- nsect = hdr->f_nscns;
- if (nsect == 0)
- return;
-
- if (nsect > SIZE_MAX)
- die("nm: %s:Too many sections\n", member);
-
- if (fseek(fp, sectbl, SEEK_SET) == EOF)
- die("nm: %s:%s", member, strerror(errno));
-
- sections = xcalloc(sizeof(*sections), nsect);
- for (i = 0; i < nsect; i++) {
- if (fread(buff, SCNHSZ, 1, fp) != 1)
- break;
- getfsec(buff, §ions[i]);
- }
- if (i != nsect) {
- char *err;
-
- err = (!ferror(fp)) ?
- "EOF before reading sections" : strerror(errno);
- die("nm: %s: %s", fname, err);
- }
-}
-
-static void
-getfhdr(unsigned char *buff, FILHDR *hdr)
-{
- int n;
-
- n = (*unpack)(buff,
- "sslllss",
- &hdr->f_magic,
- &hdr->f_nscns,
- &hdr->f_timdat,
- &hdr->f_symptr,
- &hdr->f_nsyms,
- &hdr->f_opthdr,
- &hdr->f_flags);
- assert(n == FILHSZ);
-}
-
-static int
-nm(char *fname, char *member, FILE *fp)
-{
- unsigned char buff[FILHSZ];
- FILHDR hdr;
- long pos = ftell(fp);
-
- if (fread(buff, FILHSZ, 1, fp) != 1) {
- if (!ferror(fp))
- return 0;
- die("nm: %s: %s", fname, strerror(errno));
- }
-
- getfhdr(buff, &hdr);
- if ((hdr.f_flags & F_SYMS) != 0 || hdr.f_nsyms == 0) {
- fprintf(stderr, "nm: %s: no symbols\n", member);
- return 1;
- }
-
- /* TODO: Check overflow */
- strtbl = pos + hdr.f_symptr + hdr.f_nsyms* SYMESZ;
- symtbl = pos + hdr.f_symptr;
- sectbl = pos + FILHSZ + hdr.f_opthdr;
-
- getsects(fname, member, fp, &hdr);
- getsyms(fname, member, fp, &hdr);
- printsyms(fname, member, syms, nsyms);
-
- free(sections);
- free(syms);
- return 1;
-}
-
-static int
-probe(char *fname, char *member, FILE *fp)
-{
- int c;
- int c1, c2;
- fpos_t pos;
- unsigned short magic;
-
- fgetpos(fp, &pos);
- c1 = getc(fp);
- c2 = getc(fp);
- fsetpos(fp, &pos);
-
- if (ferror(fp))
- die("nm: %s: %s", fname, strerror(errno));
-
- if (c1 == EOF || c2 == EOF)
- return 0;
- magic = c1 | c2 << 8;
-
- switch (magic) {
- case COFF_I386MAGIC:
- case COFF_Z80MAGIC:
- unpack = lunpack;
- return 1;
- default:
- unpack = NULL;
- return 0;
- }
-}
-
-struct objfile coff32 = {
- .probe = probe,
- .nm = nm,
-};
--- a/src/nm/deps.mk
+++ b/src/nm/deps.mk
@@ -1,11 +1,5 @@
#deps
-coff32.o: $(INCDIR)/scc/scc/coff32/filehdr.h
-coff32.o: $(INCDIR)/scc/scc/coff32/scnhdr.h
-coff32.o: $(INCDIR)/scc/scc/coff32/syms.h
-coff32.o: $(INCDIR)/scc/scc/scc.h
-coff32.o: nm.h
-formats.o: nm.h
main.o: $(INCDIR)/scc/scc/ar.h
main.o: $(INCDIR)/scc/scc/arg.h
+main.o: $(INCDIR)/scc/scc/mach.h
main.o: $(INCDIR)/scc/scc/scc.h
-main.o: nm.h
--- a/src/nm/formats.c
+++ /dev/null
@@ -1,13 +1,0 @@
-static char sccsid[] = "@(#) ./nm/probe.c";
-
-#include <stdio.h>
-
-#include "nm.h"
-
-/* TODO: Autogenerate this file */
-struct objfile coff32;
-
-struct objfile *formats[] = {
- &coff32,
- NULL,
-};
--- a/src/nm/main.c
+++ b/src/nm/main.c
@@ -2,7 +2,7 @@
#include <ctype.h>
#include <errno.h>
-#include <limits.h>
+#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -11,9 +11,10 @@
#include <scc/arg.h>
#include <scc/scc.h>
#include <scc/ar.h>
-#include "nm.h"
+#include <scc/mach.h>
char *argv0;
+static int status;
static int radix = 16;
static int Pflag;
static int Aflag;
@@ -20,196 +21,168 @@
static int vflag;
static int gflag;
static int uflag;
-static int arflag;
+static char *filename, *membname;
-static int
-object(char *fname, char *member, FILE *fp)
+static void
+error(char *fmt, ...)
{
- extern struct objfile *formats[];
- struct objfile **p, *obj;
- void *data;
+ va_list va;
- for (p = formats; *p; ++p) {
- obj = *p;
- if ((*obj->probe)(fname, member, fp))
- break;
- }
- if (*p == NULL)
- return 0;
- return (*obj->nm)(fname, member, fp);
+ va_start(va, fmt);
+ fprintf(stderr, "nm: %s: ", filename);
+ if (membname)
+ fprintf(stderr, "%s: ", membname);
+ vfprintf(stderr, fmt, va);
+ putc('\n', stderr);
+ va_end(va);
+
+ status = 1;
}
-static char *
-getfname(struct ar_hdr *hdr, char *dst)
+static int
+cmp(const void *p1, const void *p2)
{
- char *p;
- int i;
+ const Symbol *s1 = p1, *s2 = p2;
- memcpy(dst, hdr->ar_name, SARNAM);
- dst[SARNAM] = '\0';
-
- for (i = SARNAM-1; i >= 0; i--) {
- if (dst[i] != ' ' && dst[i] != '/')
- break;
- dst[i] = '\0';
+ if (vflag) {
+ if (s1->value > s2->value)
+ return 1;
+ if (s1->value < s2->value)
+ return -1;
+ if (s1->type == 'U' && s2->type == 'U')
+ return 0;
+ if (s1->type == 'U')
+ return -1;
+ if (s2->type == 'U')
+ return 1;
+ return 0;
+ } else {
+ return strcmp(s1->name, s2->name);
}
- return dst;
}
static void
-ar(char *fname, FILE *fp)
+printsyms(Obj *obj)
{
- struct ar_hdr hdr;
- long pos, siz;
- char member[SARNAM+1];
+ unsigned long nsym;
+ Symbol *sym;
- arflag = 1;
- if (fseek(fp, SARMAG, SEEK_SET) == EOF)
- goto file_error;
+ if (!obj->symtbl)
+ return;
+ sym = obj->symtbl;
+ nsym = obj->nsym;
- while (fread(&hdr, sizeof(hdr), 1, fp) == 1) {
- pos = ftell(fp);
- if (strncmp(hdr.ar_fmag, ARFMAG, sizeof(hdr.ar_fmag)))
- goto corrupted;
+ qsort(sym, nsym, sizeof(*sym), cmp);
- siz = 0;
- sscanf(hdr.ar_size, "%10ld", &siz);
- if (siz == 0)
- goto corrupted;
+ for (sym = obj->symtbl; nsym--; sym++) {
+ int type = sym->type;
+ char *fmt;
- if (siz & 1)
- siz++;
- if (pos == -1 || pos > LONG_MAX - siz)
- die("nm: %s: overflow in size of archive", fname);
- pos += siz;
+ if (Aflag) {
+ fmt = (membname) ? "%s[%s]: " : "%s: ";
+ printf(fmt, filename, membname);
+ }
- getfname(&hdr, member);
- if (!object(fname, member, fp)) {
- fprintf(stderr,
- "nm: skipping member %s in archive %s\n",
- member, fname);
+ if (Pflag) {
+ printf("%s %c", sym->name, sym->type);
+ if (type != 'U') {
+ if (radix == 8)
+ fmt = " %016.16llo %lo";
+ else if (radix == 10)
+ fmt = " %016.16llu %lu";
+ else
+ fmt = " %016.16llx %lx";
+ printf(fmt, sym->value, sym->size);
+ }
+ } else {
+ if (type == 'U')
+ fmt = " ";
+ else if (radix == 8)
+ fmt = "%016.16llo";
+ else if (radix == 10)
+ fmt = "%016.16lld";
+ else
+ fmt = "%016.16llx";
+ printf(fmt, sym->value);
+ printf(" %c %s", sym->type, sym->name);
}
- if (fseek(fp, pos, SEEK_SET) == EOF)
- goto file_error;
+ putchar('\n');
}
- if (ferror(fp))
- goto file_error;
- return;
-
-corrupted:
- die("nm: %s: corrupted archive", fname);
-file_error:
- die("nm: %s: %s", fname, strerror(errno));
}
static int
-archive(char *fname, FILE *fp)
+filter(Symbol *sym)
{
- char magic[SARMAG];
- fpos_t pos;
+ int type = sym->type;
- fgetpos(fp, &pos);
- fread(magic, SARMAG, 1, fp);
- fsetpos(fp, &pos);
+ if (type == '?' || type == 'N')
+ return 1;
- if (ferror(fp))
- die("nm: %s: %s", fname, strerror(errno));
- if (strncmp(magic, ARMAG, SARMAG) != 0)
- return 0;
+ if (uflag && type != 'U')
+ return 1;
- ar(fname, fp);
- return 1;
+ if (gflag && !isupper(type))
+ return 1;
+
+ return 0;
}
static void
-printsym(char *file, char *member, struct symbol *sym)
+newobject(FILE *fp, int type)
{
- char *fmt;
- int type = sym->type;
+ Obj obj;
- if (type == '?')
- return;
+ if (objopen(fp, type, &obj) < 0)
+ goto err1;
- if (uflag && type != 'U')
- return;
+ if (objread(fp, &obj, filter) < 0)
+ goto err2;
- if (gflag && !isupper(type))
- return;
+ printsyms(&obj);
+ objclose(&obj);
+ return;
- if (Aflag)
- printf((arflag) ? "%s[%s]: " : "%s: ", file, member);
- if (Pflag) {
- printf("%s %c", sym->name, sym->type);
- if (type != 'U') {
- if (radix == 8)
- fmt = " %016.16llo %lo";
- else if (radix == 10)
- fmt = " %016.16llu %lu";
- else
- fmt = " %016.16llx %lx";
- printf(fmt, sym->value, sym->size);
- }
- } else {
- if (type == 'U')
- fmt = " ";
- else if (radix == 8)
- fmt = "%016.16llo";
- else if (radix == 10)
- fmt = "%016.16lld";
- else
- fmt = "%016.16llx";
- printf(fmt, sym->value);
- printf(" %c %s", sym->type, sym->name);
- }
- putchar('\n');
+err2:
+ objclose(&obj);
+err1:
+ error("object file corrupted");
}
static int
-cmp(const void *p1, const void *p2)
+newmember(FILE *fp, char *name, void *data)
{
- const struct symbol *s1 = p1, *s2 = p2;
+ int t;
- if (vflag) {
- if (s1->value > s2->value)
- return 1;
- if (s1->value < s2->value)
- return -1;
- if (s1->type == 'U' && s2->type == 'U')
- return 0;
- if (s1->type == 'U')
- return -1;
- if (s2->type == 'U')
- return 1;
- return 0;
- } else {
- return strcmp(s1->name, s2->name);
- }
-}
+ membname = name;
+ if ((t = objtest(fp, NULL)) != -1)
+ newobject(fp, t);
-void
-printsyms(char *file, char *member, struct symbol *syms, size_t nsyms)
-{
- qsort(syms, nsyms, sizeof(*syms), cmp);
-
- while (nsyms--)
- printsym(file, member, syms++);
+ return 0;
}
static void
-doit(char *fname)
+nm(char *fname)
{
+ int t;
FILE *fp;
- arflag = 0;
+ filename = fname;
+ membname = NULL;
- if ((fp = fopen(fname, "rb")) == NULL)
- die("nm: %s: %s", fname, strerror(errno));
+ if ((fp = fopen(fname, "rb")) == NULL) {
+ error(strerror(errno));
+ return;
+ }
- if (!object(fname, fname, fp) && !archive(fname, fp))
- die("nm: %s: File format not recognized", fname);
+ if ((t = objtest(fp, NULL)) != -1)
+ newobject(fp, t);
+ else if (archive(fp))
+ artraverse(fp, newmember, NULL);
+ else
+ error("bad format");
if (ferror(fp))
- die("nm: %s: %s", fname, strerror(errno));
+ error(strerror(errno));
fclose(fp);
}
@@ -258,15 +231,17 @@
} ARGEND
if (argc == 0) {
- doit("a.out");
+ nm("a.out");
} else {
for ( ; *argv; ++argv)
- doit(*argv);
+ nm(*argv);
}
fflush(stdout);
- if (ferror(stdout))
- die("nm: error writing in output");
+ if (ferror(stdout)) {
+ fprintf(stderr, "nm: error writing in output");
+ status = 1;
+ }
- return 0;
+ return status;
}
--- a/src/nm/nm.h
+++ /dev/null
@@ -1,14 +1,0 @@
-struct symbol {
- char *name;
- int type;
- unsigned long long value;
- unsigned long size;
-};
-
-struct objfile {
- int (*probe)(char *fname, char *member, FILE *fp);
- int (*nm)(char *fname, char *member, FILE *fp);
-};
-
-/* main.c */
-extern void printsyms(char *, char *, struct symbol *, size_t );