ref: f35fcff7b5fef0b95079c09445b5e60659dc271e
dir: /nm/main.c/
static char sccsid[] = "@(#) ./nm/main.c"; #include <ctype.h> #include <errno.h> #include <limits.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "../inc/arg.h" #include "../inc/scc.h" #include "../inc/ar.h" #include "nm.h" char *argv0; static int radix = 16; static int Pflag; static int Aflag; static int vflag; static int gflag; static int uflag; static int arflag; static int object(char *fname, char *member, FILE *fp) { 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); } 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; } static void ar(char *fname, FILE *fp) { 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; corrupted: die("nm: %s: corrupted archive", fname); file_error: die("nm: %s: %s", fname, strerror(errno)); } static int archive(char *fname, FILE *fp) { char magic[SARMAG]; fpos_t pos; fgetpos(fp, &pos); fread(magic, SARMAG, 1, fp); fsetpos(fp, &pos); if (ferror(fp)) die("nm: %s: %s", fname, strerror(errno)); if (strncmp(magic, ARMAG, SARMAG) != 0) return 0; ar(fname, fp); return 1; } static void printsym(char *file, char *member, struct symbol *sym) { char *fmt; int type = sym->type; if (type == '?') return; if (uflag && type != 'U') return; if (gflag && !isupper(type)) 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'); } static int cmp(const void *p1, const void *p2) { const struct symbol *s1 = p1, *s2 = p2; 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); } } void printsyms(char *file, char *member, struct symbol *syms, size_t nsyms) { qsort(syms, nsyms, sizeof(*syms), cmp); while (nsyms--) printsym(file, member, syms++); } static void doit(char *fname) { FILE *fp; arflag = 0; if ((fp = fopen(fname, "rb")) == NULL) die("nm: %s: %s", fname, strerror(errno)); if (!object(fname, fname, fp) && !archive(fname, fp)) die("nm: %s: File format not recognized", fname); if (ferror(fp)) die("nm: %s: %s", fname, strerror(errno)); fclose(fp); } static void usage(void) { fputs("nm [-APv][ -g| -u][-t format] [file...]\n", stderr); exit(1); } int main(int argc, char *argv[]) { char *t; ARGBEGIN { case 'P': Pflag = 1; break; case 'A': Aflag = 1; break; case 'g': gflag = 1; break; case 'u': uflag = 1; break; case 'v': vflag = 1; break; case 't': t = EARGF(usage()); if (!strcmp(t, "o")) radix = 8; else if (!strcmp(t, "d")) radix = 10; else if (!strcmp(t, "x")) radix = 16; else usage(); break; default: usage(); } ARGEND if (argc == 0) { doit("a.out"); } else { for ( ; *argv; ++argv) doit(*argv); } fflush(stdout); if (ferror(stdout)) die("nm: error writing in output"); return 0; }