1#include <ctype.h>2#include <errno.h>3#include <stdarg.h>4#include <stdint.h>5#include <stdio.h>6#include <stdlib.h>7#include <string.h>89#include <scc/ar.h>10#include <scc/arg.h>11#include <scc/mach.h>121314struct symtbl {15 Symbol **buf;16 size_t nsyms;17};1819char *argv0;20static int status, multi;21static int radix = 16;22static int Pflag;23static int Aflag;24static int vflag;25static int gflag;26static int uflag;27static int fflag;28static char *filename, *membname;2930static void31error(char *fmt, ...)32{33 va_list va;3435 va_start(va, fmt);36 fprintf(stderr, "scc-nm: %s: ", filename);37 if (membname)38 fprintf(stderr, "%s: ", membname);39 vfprintf(stderr, fmt, va);40 putc('\n', stderr);41 va_end(va);4243 status = EXIT_FAILURE;44}4546static int47cmp(const void *p1, const void *p2)48{49 Symbol **s1 = (Symbol **) p1, **s2 = (Symbol **) p2;50 Symbol *sym1 = *s1, *sym2 = *s2;5152 if (vflag) {53 if (sym1->value > sym2->value)54 return 1;55 if (sym1->value < sym2->value)56 return -1;57 if (sym1->type == 'U' && sym2->type == 'U')58 return 0;59 if (sym1->type == 'U')60 return -1;61 if (sym2->type == 'U')62 return 1;63 }6465 return strcmp(sym1->name, sym2->name);66}6768static void69printsyms(Symbol **syms, size_t nsym)70{71 size_t i;7273 if (nsym == 0) {74 error("no symbols");75 return;76 }77 qsort(syms, nsym, sizeof(syms), cmp);7879 if (!Aflag) {80 if (multi || membname)81 printf("%s:\n", (membname) ? membname : filename);82 }8384 for (i = 0; i < nsym; i++) {85 Symbol *sym = syms[i];86 int type = sym->type;87 char *fmt;8889 if (Aflag) {90 fmt = (membname) ? "%s[%s]: " : "%s: ";91 printf(fmt, filename, membname);92 }9394 if (Pflag) {95 printf("%s %c", sym->name, sym->type);96 if (type != 'U') {97 if (radix == 8)98 fmt = " %016.16llo %lo";99 else if (radix == 10)100 fmt = " %016.16llu %lu";101 else102 fmt = " %016.16llx %lx";103 printf(fmt, sym->value, sym->size);104 }105 } else {106 if (type == 'U')107 fmt = " ";108 else if (radix == 8)109 fmt = "%016.16llo";110 else if (radix == 10)111 fmt = "%016.16lld";112 else113 fmt = "%016.16llx";114 printf(fmt, sym->value);115 printf(" %c %s", sym->type, sym->name);116 }117 putchar('\n');118 }119}120121static int122newsym(Symbol *sym, struct symtbl *tbl)123{124 Symbol **p, *s;125 size_t n, size;126 int type = sym->type;127 int stype = sym->stype;128129 if (type == '?' && !fflag130 || type == 'N' && !fflag131 || (stype == SYMSECTION || stype == SYMFILE) && !fflag132 || uflag && type != 'U'133 || gflag && !isupper(type)) {134 return 0;135 }136137 n = tbl->nsyms+1;138 size = n *sizeof(*p);139 p = realloc(tbl->buf, size);140 s = malloc(sizeof(*s));141 if (!p || !s) {142 free(p);143 free(s);144 error(strerror(errno));145 return -1;146 }147148 *s = *sym;149 tbl->buf = p;150 p[tbl->nsyms++] = s;151 return 0;152}153154static void155nmobj(FILE *fp, int type)156{157 int i, err = 1;158 Obj *obj;159 Symbol sym;160 struct symtbl tbl = {NULL, 0};161162 if ((obj = newobj(type)) == NULL) {163 error(strerror(errno));164 goto err1;165 }166167 if (readobj(obj, fp) < 0)168 goto err2;169170 for (i = 0; getsym(obj, &i, &sym); i++) {171 if (newsym(&sym, &tbl) < 0)172 goto err3;173 }174175 printsyms(tbl.buf, tbl.nsyms);176 err = 0;177178err3:179 free(tbl.buf);180err2:181 delobj(obj);182err1:183 if (err)184 error("object file corrupted");185}186187static void188nmlib(FILE *fp)189{190 int t;191 long off, cur;192 char memb[SARNAM+1];193194 for (;;) {195 cur = ftell(fp);196 off = armember(fp, memb, NULL);197 switch (off) {198 case -1:199 error("library corrupted");200 if (ferror(fp))201 error(strerror(errno));202 case 0:203 return;204 default:205 membname = memb;206 if ((t = objprobe(fp, NULL)) != -1)207 nmobj(fp, t);208 membname = NULL;209 fseek(fp, cur, SEEK_SET);210 fseek(fp, off, SEEK_CUR);211 break;212 }213 }214}215216static void217nm(char *fname)218{219 int t;220 FILE *fp;221222 filename = fname;223 membname = NULL;224225 if ((fp = fopen(fname, "rb")) == NULL) {226 error(strerror(errno));227 return;228 }229230 if ((t = objprobe(fp, NULL)) != -1)231 nmobj(fp, t);232 else if (archive(fp))233 nmlib(fp);234 else235 error("bad format");236237 fclose(fp);238}239240static void241usage(void)242{243 fputs("scc-nm [-APvfagu][-t format] [file...]\n", stderr);244 exit(1);245}246247int248main(int argc, char *argv[])249{250 char *t;251252 ARGBEGIN {253 case 'P':254 Pflag = 1;255 break;256 case 'A':257 Aflag = 1;258 break;259 case 'g':260 gflag = 1;261 break;262 case 'a':263 case 'f':264 fflag = 1;265 break;266 case 'u':267 uflag = 1;268 break;269 case 'v':270 vflag = 1;271 break;272 case 't':273 t = EARGF(usage());274 if (!strcmp(t, "o"))275 radix = 8;276 else if (!strcmp(t, "d"))277 radix = 10;278 else if (!strcmp(t, "x"))279 radix = 16;280 else281 usage();282 break;283 default:284 usage();285 } ARGEND286287 if (argc == 0) {288 nm("a.out");289 } else {290 if (argc > 1)291 multi = 1;292 for ( ; *argv; ++argv)293 nm(*argv);294 }295296 if (fflush(stdout) == EOF) {297 fprintf(stderr,298 "nm: error writing in output:%s\n",299 strerror(errno));300 status = 1;301 }302303 return status;304}