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 = §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 = '?';
+
+ 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, §ions[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 );