shithub: scc

Download patch

ref: 8e8710e0cbdc6f1aae24dfaecdbe04325c039a47
parent: f96febf13f98bd4a810267cb6a6f0e26507f41ae
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Mon Mar 12 07:53:45 EDT 2018

[nm] Implement coff symbol listing

--- a/inc/coff32/filehdr.h
+++ b/inc/coff32/filehdr.h
@@ -18,5 +18,8 @@
 #define F_EXEC   (1 << 1)
 #define F_LMNO   (1 << 2)
 #define F_SYMS   (1 << 3)
+#define F_AR16WR (1 << 4)
+#define F_AR32WR (1 << 5)
+#define F_A32WR  (1 << 6)
 
 #define COFF_Z80MAGIC     0x805a
--- a/inc/coff32/scnhdr.h
+++ b/inc/coff32/scnhdr.h
@@ -26,11 +26,9 @@
 #define STYP_PAD         (1 << 3)
 #define STYP_COPY        (1 << 4)
 #define STYP_TEXT        (1 << 5)
-#define S_SHRSEG         (1 << 6)
-#define STYP_DATA        (1 << 7)
-#define STYP_BSS         (1 << 8)
-#define S_NEWFCN         (1 << 9)
-#define STYP_INFO        (1 << 10)
+#define STYP_DATA        (1 << 6)
+#define STYP_BSS         (1 << 7)
+#define STYP_INFO        (1 << 9)
 #define STYP_OVER        (1 << 11)
 #define STYP_LIB         (1 << 12)
 #define STYP_MERGE       (1 << 13)
--- a/inc/coff32/syms.h
+++ b/inc/coff32/syms.h
@@ -1,6 +1,8 @@
 
 /* This file is inspired in the book "Understanding and using COFF" */
 
+#define E_SYMNMLEN   8
+
 struct syment {
 	union {
 		char _n_name[8];          /* symbol name */
@@ -8,7 +10,6 @@
 			long _n_zeroes;  /* if _n_name[0-3] == 0 */
 			long _n_offset;  /* offset into string table */
 		} _n_n;
-		char _n_ptr[2];          /* allows for overlaying */
 	} _n;
 	long n_value;                    /* value of symbol */
 	short n_scnum;                   /* section number */
@@ -17,8 +18,10 @@
 	char n_numaux;                   /* number of aux. entries */
 };
 
+#define SYMENT  struct syment
+#define SYMESZ  18
+
 #define n_name       _n._n_name
-#define n_nptr       _n._n_nptr[1]
 #define n_zeroes     _n._n_n._n_zeroes
 #define n_offset     _n._n_n._n_offset
 
@@ -26,6 +29,7 @@
 #define N_DEBUG      -2
 #define N_ABS        -1
 #define N_UNDEF       0
+#define N_SCNUM(x)   ((x) > 0)
 
 /* basic types */
 #define T_NULL        0
--- a/inc/scc.h
+++ b/inc/scc.h
@@ -37,3 +37,5 @@
 extern int casecmp(const char *s1, const char *s2);
 extern int lpack(unsigned char *dst, char *fmt, ...);
 extern int lunpack(unsigned char *src, char *fmt, ...);
+extern int bpack(unsigned char *dst, char *fmt, ...);
+extern int bunpack(unsigned char *src, char *fmt, ...);
--- a/nm/Makefile
+++ b/nm/Makefile
@@ -5,12 +5,16 @@
 include $(PROJECTDIR)/rules.mk
 include $(LIBDIR)/libdep.mk
 
-OBJ       = main.o coff.o formats.o
+OBJ       = main.o coff32.o formats.o
 
 all: nm
 
 main.o: $(INCDIR)/scc.h $(INCDIR)/ar.h $(INCDIR)/arg.h nm.h
-coff.o: nm.h
+coff32.o: nm.h
+coff32.o: ../inc/coff32/filehdr.h
+coff32.o: ../inc/coff32/scnhdr.h
+coff32.o: ../inc/coff32/syms.h
+coff32.o: ../inc/scc.h
 formats.o: nm.h
 
 nm: $(OBJ) $(LIBDIR)/libscc.a
--- a/nm/coff.c
+++ /dev/null
@@ -1,21 +1,0 @@
-
-static char sccsid[] = "@(#) ./nm/coff.c";
-
-#include <stdio.h>
-
-#include "nm.h"
-
-static void
-nm(char *fname, FILE *fp)
-{
-}
-
-static int
-probe(FILE *fp)
-{
-}
-
-struct objfile coff = {
-	.probe = probe,
-	.nm = nm,
-};
--- /dev/null
+++ b/nm/coff32.c
@@ -1,0 +1,308 @@
+
+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 "../inc/coff32/filehdr.h"
+#include "../inc/coff32/scnhdr.h"
+#include "../inc/coff32/syms.h"
+#include "../inc/scc.h"
+#include "nm.h"
+
+static int (*unpack)(unsigned char *, char *, ...);
+static long stringtbl;
+static SCNHDR *sections;
+static struct symbol *syms;
+static size_t nsect, nsyms;
+
+static char
+typeof(SYMENT *ent)
+{
+	SCNHDR *sec;
+	int c;
+	long flags;
+	char **bp;
+
+	switch (ent->n_scnum) {
+	case N_DEBUG:
+		c = '?';
+		break;
+	case N_ABS:
+		c = 'A';
+		break;
+	case N_UNDEF:
+		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 = '?';
+
+		if (ent->n_sclass == C_EXT)
+			c = toupper(c);
+
+		break;
+	}
+	return c;
+}
+
+static char *
+getsname(FILE *fp, SYMENT *ent)
+{
+	int c;
+	size_t len;
+	char *s;
+	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);
+	}
+
+	
+	fgetpos(fp, &pos);
+	fseek(fp, stringtbl, SEEK_SET);
+	fseek(fp, ent->n_offset, SEEK_CUR);
+
+	if (ferror(fp))
+		goto error;
+
+	s = xmalloc(1);
+	for (len = 0; (c = getc(fp)) != '\0'; len++) {
+		if (c == EOF)
+			goto error;
+		s = xrealloc(s, len+1);
+		s[len] = c;
+	}
+	s[len] = '\0';
+	fsetpos(fp, &pos);
+	return s;
+
+error:
+	fprintf(stderr,
+	        "nm::%s\n",
+	        (ferror(fp)) ? strerror(errno) : "broken string table");
+	exit(1);
+}
+
+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(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(fp, ent);
+	sym->type = typeof(ent);
+	sym->value = ent->n_value;
+}
+
+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, hdr->f_symptr, SEEK_SET) == EOF)
+		die("nm:%s:%s", member, 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(fp, buff, &ent, &syms[nsyms++]);
+		aux = ent.n_numaux;
+	}
+	if (n != i) {
+		die("nm:%s:%s",
+		    member,
+		    (ferror(fp)) ? strerror(errno) : "EOF before reading symbols");
+	}
+}
+
+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, FILHSZ + hdr->f_opthdr, 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) {
+		fprintf(stderr,
+			"nm:%s:%s\n",
+		        member,
+			(ferror(fp)) ? strerror(errno) : "EOF before reading sections");
+		exit(1);
+	}
+}
+
+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 void
+nm(char *fname, char *member, FILE *fp)
+{
+	unsigned char buff[FILHSZ];
+	FILHDR hdr;
+	unsigned magic;
+
+	if (fread(buff, FILHSZ, 1, fp) != 1)
+		return;
+
+	magic = buff[0] | buff[1] << 8;
+
+	switch (magic) {
+	case COFF_Z80MAGIC:
+		unpack = lunpack;
+		break;
+	default:
+		abort();
+	}
+
+	getfhdr(buff, &hdr);
+	if ((hdr.f_flags & F_SYMS) != 0 || hdr.f_nsyms == 0) {
+		fprintf(stderr, "nm: %s: no symbols\n", member);
+		return;
+	}
+
+	stringtbl = hdr.f_symptr + hdr.f_nsyms* SYMESZ;
+
+	getsects(fname, member, fp, &hdr);
+	getsyms(fname, member, fp, &hdr);
+	printsyms(fname, member, syms, nsyms);
+
+	free(sections);
+	free(syms);
+}
+
+static int
+probe(FILE *fp)
+{
+	int c;
+	int c1, c2;
+	fpos_t pos;
+	static unsigned short magic;
+
+	fgetpos(fp, &pos);
+	c1 = getc(fp);
+	c2 = getc(fp);
+	fsetpos(fp, &pos);
+
+	if (c1 == EOF || c2 == EOF)
+		return 0;
+	magic = c1 | c2 << 8;
+
+	switch (magic) {
+	case COFF_Z80MAGIC:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+struct objfile coff32 = {
+	.probe = probe,
+	.nm = nm,
+};
--- a/nm/formats.c
+++ b/nm/formats.c
@@ -5,11 +5,10 @@
 
 #include "nm.h"
 
-struct objfile coff;
-
 /* TODO: Autogenerate this file */
+struct objfile coff32;
 
 struct objfile *formats[] = {
-	&coff,
+	&coff32,
 	NULL,
 };
--- a/nm/main.c
+++ b/nm/main.c
@@ -23,16 +23,20 @@
 static int arflag;
 
 int
-object(char *fname, FILE *fp)
+object(char *fname, char *member, FILE *fp)
 {
-	extern struct objfile formats[];
-	struct objfile *p;
+	extern struct objfile *formats[];
+	struct objfile **p, *obj;
+	void *data;
 
-	for (p = formats; p->probe && (*p->probe)(fp); ++p)
-		;
-	if (!p->probe)
+	for (p = formats; *p; ++p) {
+		obj = *p;
+		if ((*obj->probe)(fp))
+			break;
+	}
+	if (*p == NULL)
 		return 0;
-	(*p->nm)(fname, fp);
+	(*obj->nm)(fname, member, fp);
 	return 1;
 }
 
@@ -65,7 +69,7 @@
 
 	while (fread(&hdr, sizeof(hdr), 1, fp) == 1) {
 		pos = ftell(fp);
-		if (strncmp(hdr.ar_fmag, ARFMAG, strlen(ARFMAG)))
+		if (strncmp(hdr.ar_fmag, ARFMAG, SARMAG))
 			goto corrupted;
 
 		siz = 0;
@@ -84,7 +88,7 @@
 		pos += siz;
 
 		getfname(&hdr, member);
-		if (!object(member, fp)) {
+		if (!object(member, member, fp)) {
 			fprintf(stderr,
 			        "nm: skipping member %s in archive %s\n",
 			        member, fname);
@@ -108,22 +112,23 @@
 	fread(magic, SARMAG, 1, fp);
 	fsetpos(fp, &pos);
 
-	if (ferror(fp)) {
-		perror("nm");
-		exit(1);
-	}
+	if (ferror(fp))
+		return 0;
 	if (strncmp(magic, ARMAG, SARMAG) != 0)
 		return 0;
+
 	ar(fname, fp);
 	return 1;
 }
 
-void
+static void
 print(char *file, char *member, struct symbol *sym)
 {
 	char *fmt;
 	int type = sym->type;
 
+	if (type == '?')
+		return;
 	if (uflag && type != 'U')
 		return;
 	if (gflag && type != 'A' && type != 'B' && type != 'D')
@@ -140,7 +145,7 @@
 				fmt = "%llu %llu";
 			else
 				fmt = "%llx %llx";
-			printf(fmt, sym->off, sym->size);
+			printf(fmt, sym->value, sym->size);
 		}
 	} else {
 		if (type == 'U')
@@ -151,7 +156,7 @@
 			fmt = "%016.16lld";
 		else
 			fmt = "%016.16llx";
-		printf(fmt, sym->off);
+		printf(fmt, sym->value);
 		printf(" %c %s", sym->type, sym->name);
 	}
 	putchar('\n');
@@ -163,7 +168,7 @@
 	const struct symbol *s1 = p1, *s2 = p2;
 
 	if (vflag)
-		return s1->off - s2->off;
+		return s1->value - s2->value;
 	else
 		return strcmp(s1->name, s2->name);
 }
@@ -188,7 +193,7 @@
 		exit(1);
 	}
 
-	if (!object(fname, fp) && !archive(fname, fp))
+	if (!object(fname, fname, fp) && !archive(fname, fp))
 		fprintf(stderr, "nm: %s: File format not recognized\n", fname);
 
 	if (ferror(fp) || fclose(fp) == EOF) {
--- a/nm/nm.h
+++ b/nm/nm.h
@@ -2,14 +2,14 @@
 struct symbol {
 	char *name;
 	int type;
-	unsigned long long off;
+	unsigned long long value;
 	unsigned long size;
 };
 
 struct objfile {
 	int (*probe)(FILE *fp);
-	void (*nm)(char *fname, FILE *fp);
+	void (*nm)(char *fname, char *member, FILE *fp);
 };
 
 /* main.c */
-extern void print(char *file, char *member, struct symbol *sym);
+extern void printsyms(char *, char *, struct symbol *, size_t );