nm.c 5.7 KB

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