nm.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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. }
  156. return strcmp((*s)->name, (*t)->name);
  157. }
  158. /*
  159. * enter a symbol in the table of filename elements
  160. */
  161. void
  162. zenter(Sym *s)
  163. {
  164. static int maxf = 0;
  165. if (s->value > maxf) {
  166. maxf = (s->value+CHUNK-1) &~ (CHUNK-1);
  167. fnames = realloc(fnames, (maxf+1)*sizeof(*fnames));
  168. if(fnames == 0) {
  169. error("out of memory", argv0);
  170. exits("memory");
  171. }
  172. }
  173. fnames[s->value] = s;
  174. }
  175. /*
  176. * get the symbol table from an executable file, if it has one
  177. */
  178. void
  179. execsyms(int fd)
  180. {
  181. Fhdr f;
  182. Sym *s;
  183. int32_t n;
  184. seek(fd, 0, 0);
  185. if (crackhdr(fd, &f) == 0) {
  186. error("Can't read header for %s", filename);
  187. return;
  188. }
  189. if (syminit(fd, &f) < 0)
  190. return;
  191. s = symbase(&n);
  192. nsym = 0;
  193. while(n--)
  194. psym(s++, 0);
  195. printsyms(symptr, nsym);
  196. }
  197. void
  198. psym(Sym *s, void* p)
  199. {
  200. USED(p);
  201. switch(s->type) {
  202. case 'T':
  203. case 'L':
  204. case 'D':
  205. case 'B':
  206. if (uflag)
  207. return;
  208. if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
  209. return;
  210. break;
  211. case 'b':
  212. case 'd':
  213. case 'l':
  214. case 't':
  215. if (uflag || gflag)
  216. return;
  217. if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
  218. return;
  219. break;
  220. case 'U':
  221. if (gflag)
  222. return;
  223. break;
  224. case 'Z':
  225. if (!aflag)
  226. return;
  227. break;
  228. case 'm':
  229. case 'f': /* we only see a 'z' when the following is true*/
  230. if(!aflag || uflag || gflag)
  231. return;
  232. if (strcmp(s->name, ".frame"))
  233. zenter(s);
  234. break;
  235. case 'a':
  236. case 'p':
  237. case 'z':
  238. default:
  239. if(!aflag || uflag || gflag)
  240. return;
  241. break;
  242. }
  243. symptr = realloc(symptr, (nsym+1)*sizeof(Sym*));
  244. if (symptr == 0) {
  245. error("out of memory");
  246. exits("memory");
  247. }
  248. symptr[nsym++] = s;
  249. }
  250. void
  251. printsyms(Sym **symptr, int32_t nsym)
  252. {
  253. int i, wid;
  254. Sym *s;
  255. char *cp;
  256. char path[512];
  257. if(!sflag)
  258. qsort(symptr, nsym, sizeof(*symptr), cmp);
  259. wid = 0;
  260. for (i=0; i<nsym; i++) {
  261. s = symptr[i];
  262. if (s->value && wid == 0)
  263. wid = 8;
  264. else if (s->value >= 0x100000000LL && wid == 8)
  265. wid = 16;
  266. }
  267. for (i=0; i<nsym; i++) {
  268. s = symptr[i];
  269. if (multifile && !hflag)
  270. Bprint(&bout, "%s:", filename);
  271. if (s->type == 'z') {
  272. fileelem(fnames, (uint8_t *) s->name, path, 512);
  273. cp = path;
  274. } else
  275. cp = s->name;
  276. if (Tflag)
  277. Bprint(&bout, "%8ux ", s->sig);
  278. if (s->value || s->type == 'a' || s->type == 'p')
  279. Bprint(&bout, "%*llux ", wid, s->value);
  280. else
  281. Bprint(&bout, "%*s ", wid, "");
  282. Bprint(&bout, "%c %s\n", s->type, cp);
  283. }
  284. }
  285. void
  286. error(char *fmt, ...)
  287. {
  288. Fmt f;
  289. char buf[128];
  290. va_list arg;
  291. fmtfdinit(&f, 2, buf, sizeof buf);
  292. fmtprint(&f, "%s: ", argv0);
  293. va_start(arg, fmt);
  294. fmtvprint(&f, fmt, arg);
  295. va_end(arg);
  296. fmtprint(&f, "\n");
  297. fmtfdflush(&f);
  298. errs = "errors";
  299. }