nm.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /*
  2. * nm.c -- drive nm
  3. */
  4. #include <u.h>
  5. #include <libc.h>
  6. #include <ar.h>
  7. #include <bio.h>
  8. #include <mach.h>
  9. enum{
  10. CHUNK = 256 /* must be power of 2 */
  11. };
  12. char *errs; /* exit status */
  13. char *filename; /* current file */
  14. char symname[]="__.SYMDEF"; /* table of contents file name */
  15. int multifile; /* processing multiple files */
  16. int aflag;
  17. int gflag;
  18. int hflag;
  19. int nflag;
  20. int sflag;
  21. int uflag;
  22. int Tflag;
  23. Sym **fnames; /* file path translation table */
  24. Sym **symptr;
  25. int nsym;
  26. Biobuf bout;
  27. int cmp(void*, void*);
  28. void error(char*, ...);
  29. void execsyms(int);
  30. void psym(Sym*, void*);
  31. void printsyms(Sym**, long);
  32. void doar(Biobuf*);
  33. void dofile(Biobuf*);
  34. void zenter(Sym*);
  35. void
  36. usage(void)
  37. {
  38. fprint(2, "usage: nm [-aghnsTu] file ...\n");
  39. exits("usage");
  40. }
  41. void
  42. main(int argc, char *argv[])
  43. {
  44. int i;
  45. Biobuf *bin;
  46. Binit(&bout, 1, OWRITE);
  47. argv0 = argv[0];
  48. ARGBEGIN {
  49. default: usage();
  50. case 'a': aflag = 1; break;
  51. case 'g': gflag = 1; break;
  52. case 'h': hflag = 1; break;
  53. case 'n': nflag = 1; break;
  54. case 's': sflag = 1; break;
  55. case 'u': uflag = 1; break;
  56. case 'T': Tflag = 1; break;
  57. } ARGEND
  58. if (argc == 0)
  59. usage();
  60. if (argc > 1)
  61. multifile++;
  62. for(i=0; i<argc; i++){
  63. filename = argv[i];
  64. bin = Bopen(filename, OREAD);
  65. if(bin == 0){
  66. error("cannot open %s", filename);
  67. continue;
  68. }
  69. if (isar(bin))
  70. doar(bin);
  71. else{
  72. Bseek(bin, 0, 0);
  73. dofile(bin);
  74. }
  75. Bterm(bin);
  76. }
  77. exits(errs);
  78. }
  79. /*
  80. * read an archive file,
  81. * processing the symbols for each intermediate file in it.
  82. */
  83. void
  84. doar(Biobuf *bp)
  85. {
  86. int offset, size, obj;
  87. char membername[SARNAME];
  88. multifile = 1;
  89. for (offset = Boffset(bp);;offset += size) {
  90. size = nextar(bp, offset, membername);
  91. if (size < 0) {
  92. error("phase error on ar header %ld", offset);
  93. return;
  94. }
  95. if (size == 0)
  96. return;
  97. if (strcmp(membername, symname) == 0)
  98. continue;
  99. obj = objtype(bp, 0);
  100. if (obj < 0) {
  101. error("inconsistent file %s in %s",
  102. membername, filename);
  103. return;
  104. }
  105. if (!readar(bp, obj, offset+size, 1)) {
  106. error("invalid symbol reference in file %s",
  107. membername);
  108. return;
  109. }
  110. filename = membername;
  111. nsym=0;
  112. objtraverse(psym, 0);
  113. printsyms(symptr, nsym);
  114. }
  115. }
  116. /*
  117. * process symbols in a file
  118. */
  119. void
  120. dofile(Biobuf *bp)
  121. {
  122. int obj;
  123. obj = objtype(bp, 0);
  124. if (obj < 0)
  125. execsyms(Bfildes(bp));
  126. else
  127. if (readobj(bp, obj)) {
  128. nsym = 0;
  129. objtraverse(psym, 0);
  130. printsyms(symptr, nsym);
  131. }
  132. }
  133. /*
  134. * comparison routine for sorting the symbol table
  135. * this screws up on 'z' records when aflag == 1
  136. */
  137. int
  138. cmp(void *vs, void *vt)
  139. {
  140. Sym **s, **t;
  141. s = vs;
  142. t = vt;
  143. if(nflag)
  144. if((*s)->value < (*t)->value)
  145. return -1;
  146. else
  147. return (*s)->value > (*t)->value;
  148. return strcmp((*s)->name, (*t)->name);
  149. }
  150. /*
  151. * enter a symbol in the table of filename elements
  152. */
  153. void
  154. zenter(Sym *s)
  155. {
  156. static int maxf = 0;
  157. if (s->value > maxf) {
  158. maxf = (s->value+CHUNK-1) &~ (CHUNK-1);
  159. fnames = realloc(fnames, (maxf+1)*sizeof(*fnames));
  160. if(fnames == 0) {
  161. error("out of memory", argv0);
  162. exits("memory");
  163. }
  164. }
  165. fnames[s->value] = s;
  166. }
  167. /*
  168. * get the symbol table from an executable file, if it has one
  169. */
  170. void
  171. execsyms(int fd)
  172. {
  173. Fhdr f;
  174. Sym *s;
  175. long n;
  176. seek(fd, 0, 0);
  177. if (crackhdr(fd, &f) == 0) {
  178. error("Can't read header for %s", filename);
  179. return;
  180. }
  181. if (syminit(fd, &f) < 0)
  182. return;
  183. s = symbase(&n);
  184. nsym = 0;
  185. while(n--)
  186. psym(s++, 0);
  187. printsyms(symptr, nsym);
  188. }
  189. void
  190. psym(Sym *s, void* p)
  191. {
  192. USED(p);
  193. switch(s->type) {
  194. case 'T':
  195. case 'L':
  196. case 'D':
  197. case 'B':
  198. if (uflag)
  199. return;
  200. if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
  201. return;
  202. break;
  203. case 'b':
  204. case 'd':
  205. case 'l':
  206. case 't':
  207. if (uflag || gflag)
  208. return;
  209. if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
  210. return;
  211. break;
  212. case 'U':
  213. if (gflag)
  214. return;
  215. break;
  216. case 'Z':
  217. if (!aflag)
  218. return;
  219. break;
  220. case 'm':
  221. case 'f': /* we only see a 'z' when the following is true*/
  222. if(!aflag || uflag || gflag)
  223. return;
  224. if (strcmp(s->name, ".frame"))
  225. zenter(s);
  226. break;
  227. case 'a':
  228. case 'p':
  229. case 'z':
  230. default:
  231. if(!aflag || uflag || gflag)
  232. return;
  233. break;
  234. }
  235. symptr = realloc(symptr, (nsym+1)*sizeof(Sym*));
  236. if (symptr == 0) {
  237. error("out of memory");
  238. exits("memory");
  239. }
  240. symptr[nsym++] = s;
  241. }
  242. void
  243. printsyms(Sym **symptr, long nsym)
  244. {
  245. int i, wid;
  246. Sym *s;
  247. char *cp;
  248. char path[512];
  249. if(!sflag)
  250. qsort(symptr, nsym, sizeof(*symptr), cmp);
  251. wid = 0;
  252. for (i=0; i<nsym; i++) {
  253. s = symptr[i];
  254. if (s->value && wid == 0)
  255. wid = 8;
  256. else if (s->value >= 0x100000000LL && wid == 8)
  257. wid = 16;
  258. }
  259. for (i=0; i<nsym; i++) {
  260. s = symptr[i];
  261. if (multifile && !hflag)
  262. Bprint(&bout, "%s:", filename);
  263. if (s->type == 'z') {
  264. fileelem(fnames, (uchar *) s->name, path, 512);
  265. cp = path;
  266. } else
  267. cp = s->name;
  268. if (Tflag)
  269. Bprint(&bout, "%8ux ", s->sig);
  270. if (s->value || s->type == 'a' || s->type == 'p')
  271. Bprint(&bout, "%*llux ", wid, s->value);
  272. else
  273. Bprint(&bout, "%*s ", wid, "");
  274. Bprint(&bout, "%c %s\n", s->type, cp);
  275. }
  276. }
  277. void
  278. error(char *fmt, ...)
  279. {
  280. Fmt f;
  281. char buf[128];
  282. va_list arg;
  283. fmtfdinit(&f, 2, buf, sizeof buf);
  284. fmtprint(&f, "%s: ", argv0);
  285. va_start(arg, fmt);
  286. fmtvprint(&f, fmt, arg);
  287. va_end(arg);
  288. fmtprint(&f, "\n");
  289. fmtfdflush(&f);
  290. errs = "errors";
  291. }