scc

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

commit ff1e3fe0e05d8b64072dba845a2d9f27889d28e1
parent 83f81da6c14c9890ff0852122228a9bb332b817d
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Fri,  4 Jan 2019 13:39:16 +0000

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

Diffstat:
Ainclude/scc/scc/mach.h | 30++++++++++++++++++++++++++++++
Msrc/Makefile | 2+-
Asrc/libmach/Makefile | 17+++++++++++++++++
Asrc/libmach/archive.c | 24++++++++++++++++++++++++
Asrc/libmach/armember.c | 46++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libmach/artraverse.c | 29+++++++++++++++++++++++++++++
Asrc/libmach/coff32.c | 286+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libmach/libmach.h | 36++++++++++++++++++++++++++++++++++++
Asrc/libmach/object.c | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libmach/pack.c | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libmach/unpack.c | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/nm/Makefile | 6++----
Dsrc/nm/coff32.c | 312-------------------------------------------------------------------------------
Msrc/nm/deps.mk | 8+-------
Dsrc/nm/formats.c | 13-------------
Msrc/nm/main.c | 281++++++++++++++++++++++++++++++++++++-------------------------------------------
Dsrc/nm/nm.h | 14--------------
17 files changed, 994 insertions(+), 504 deletions(-)

diff --git a/include/scc/scc/mach.h b/include/scc/scc/mach.h @@ -0,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); diff --git a/src/Makefile b/src/Makefile @@ -4,7 +4,7 @@ PROJECTDIR = .. 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) diff --git a/src/libmach/Makefile b/src/libmach/Makefile @@ -0,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 $@ $? diff --git a/src/libmach/archive.c b/src/libmach/archive.c @@ -0,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; +} diff --git a/src/libmach/armember.c b/src/libmach/armember.c @@ -0,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; +} diff --git a/src/libmach/artraverse.c b/src/libmach/artraverse.c @@ -0,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; + } +} diff --git a/src/libmach/coff32.c b/src/libmach/coff32.c @@ -0,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); +} diff --git a/src/libmach/libmach.h b/src/libmach/libmach.h @@ -0,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); diff --git a/src/libmach/object.c b/src/libmach/object.c @@ -0,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); +} diff --git a/src/libmach/pack.c b/src/libmach/pack.c @@ -0,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; +} diff --git a/src/libmach/unpack.c b/src/libmach/unpack.c @@ -0,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; +} diff --git a/src/nm/Makefile b/src/nm/Makefile @@ -4,17 +4,15 @@ PROJECTDIR = ../.. 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 diff --git a/src/nm/coff32.c b/src/nm/coff32.c @@ -1,312 +0,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 = &sections[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, &sections[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, -}; diff --git 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 diff --git a/src/nm/formats.c b/src/nm/formats.c @@ -1,13 +0,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, -}; diff --git a/src/nm/main.c b/src/nm/main.c @@ -2,7 +2,7 @@ static char sccsid[] = "@(#) ./nm/main.c"; #include <ctype.h> #include <errno.h> -#include <limits.h> +#include <stdarg.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -11,205 +11,178 @@ static char sccsid[] = "@(#) ./nm/main.c"; #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; 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; - - 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_list va; + + 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]; - - arflag = 1; - if (fseek(fp, SARMAG, SEEK_SET) == EOF) - goto file_error; - - while (fread(&hdr, sizeof(hdr), 1, fp) == 1) { - pos = ftell(fp); - if (strncmp(hdr.ar_fmag, ARFMAG, sizeof(hdr.ar_fmag))) - goto corrupted; - - siz = 0; - sscanf(hdr.ar_size, "%10ld", &siz); - if (siz == 0) - goto corrupted; - - if (siz & 1) - siz++; - if (pos == -1 || pos > LONG_MAX - siz) - die("nm: %s: overflow in size of archive", fname); - pos += siz; - - getfname(&hdr, member); - if (!object(fname, member, fp)) { - fprintf(stderr, - "nm: skipping member %s in archive %s\n", - member, fname); - } - if (fseek(fp, pos, SEEK_SET) == EOF) - goto file_error; - } - if (ferror(fp)) - goto file_error; - return; + unsigned long nsym; + Symbol *sym; -corrupted: - die("nm: %s: corrupted archive", fname); -file_error: - die("nm: %s: %s", fname, strerror(errno)); -} + if (!obj->symtbl) + return; + sym = obj->symtbl; + nsym = obj->nsym; -static int -archive(char *fname, FILE *fp) -{ - char magic[SARMAG]; - fpos_t pos; + qsort(sym, nsym, sizeof(*sym), cmp); - fgetpos(fp, &pos); - fread(magic, SARMAG, 1, fp); - fsetpos(fp, &pos); + for (sym = obj->symtbl; nsym--; sym++) { + int type = sym->type; + char *fmt; - if (ferror(fp)) - die("nm: %s: %s", fname, strerror(errno)); - if (strncmp(magic, ARMAG, SARMAG) != 0) - return 0; + if (Aflag) { + fmt = (membname) ? "%s[%s]: " : "%s: "; + printf(fmt, filename, membname); + } - ar(fname, fp); - return 1; + 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'); + } } -static void -printsym(char *file, char *member, struct symbol *sym) +static int +filter(Symbol *sym) { - char *fmt; int type = sym->type; - if (type == '?') - return; + if (type == '?' || type == 'N') + return 1; if (uflag && type != 'U') - return; + return 1; if (gflag && !isupper(type)) - return; + return 1; - 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'); + return 0; } -static int -cmp(const void *p1, const void *p2) +static void +newobject(FILE *fp, int type) { - const struct symbol *s1 = p1, *s2 = p2; + Obj obj; - 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); - } + if (objopen(fp, type, &obj) < 0) + goto err1; + + if (objread(fp, &obj, filter) < 0) + goto err2; + + printsyms(&obj); + objclose(&obj); + return; + +err2: + objclose(&obj); +err1: + error("object file corrupted"); } -void -printsyms(char *file, char *member, struct symbol *syms, size_t nsyms) +static int +newmember(FILE *fp, char *name, void *data) { - qsort(syms, nsyms, sizeof(*syms), cmp); + int t; - while (nsyms--) - printsym(file, member, syms++); + membname = name; + if ((t = objtest(fp, NULL)) != -1) + newobject(fp, t); + + 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 @@ main(int argc, char *argv[]) } 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; } diff --git a/src/nm/nm.h b/src/nm/nm.h @@ -1,14 +0,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 );