nm.c 4.8 KB

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