/usr.bin/ldd/sods.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 572 lines · 425 code · 84 blank · 63 comment · 62 complexity · 26e97a0cd3a032f51c9da2f2679da4d9 MD5 · raw file

  1. /*
  2. * Copyright (C) 1996-1997 John D. Polstra. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY JOHN D. POLSTRA AND CONTRIBUTORS ``AS IS'' AND
  14. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16. * ARE DISCLAIMED. IN NO EVENT SHALL JOHN D. POLSTRA OR CONTRIBUTORS BE LIABLE
  17. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  18. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  19. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  20. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  21. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  22. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  23. * SUCH DAMAGE.
  24. */
  25. #include <sys/cdefs.h>
  26. __FBSDID("$FreeBSD$");
  27. #include <sys/types.h>
  28. #include <sys/mman.h>
  29. #include <sys/stat.h>
  30. #include <machine/elf.h>
  31. #include <arpa/inet.h>
  32. #include <a.out.h>
  33. #include <assert.h>
  34. #include <ctype.h>
  35. #include <err.h>
  36. #include <fcntl.h>
  37. #include <sys/link_aout.h>
  38. #include <stab.h>
  39. #include <stdio.h>
  40. #include <stdlib.h>
  41. #include <string.h>
  42. #include <unistd.h>
  43. #include "extern.h"
  44. #define PAGE_SIZE 4096 /* i386 specific */
  45. #ifndef N_SETA
  46. #define N_SETA 0x14 /* Absolute set element symbol */
  47. #endif /* This is input to LD, in a .o file. */
  48. #ifndef N_SETT
  49. #define N_SETT 0x16 /* Text set element symbol */
  50. #endif /* This is input to LD, in a .o file. */
  51. #ifndef N_SETD
  52. #define N_SETD 0x18 /* Data set element symbol */
  53. #endif /* This is input to LD, in a .o file. */
  54. #ifndef N_SETB
  55. #define N_SETB 0x1A /* Bss set element symbol */
  56. #endif /* This is input to LD, in a .o file. */
  57. #ifndef N_SETV
  58. #define N_SETV 0x1C /* Pointer to set vector in data area. */
  59. #endif /* This is output from LD. */
  60. #ifdef STANDALONE
  61. static
  62. #endif
  63. static void dump_rels(const char *, const struct relocation_info *,
  64. unsigned long, const char *(*)(unsigned long), unsigned char *);
  65. static void dump_segs(void);
  66. static void dump_sods(void);
  67. static void dump_sym(const struct nlist *);
  68. static void dump_syms(void);
  69. static void dump_rtsyms(void);
  70. static const char *rtsym_name(unsigned long);
  71. static const char *sym_name(unsigned long);
  72. #ifdef STANDALONE
  73. static
  74. #endif
  75. int error_count;
  76. /*
  77. * Variables ending in _base are pointers to things in our address space,
  78. * i.e., in the file itself.
  79. *
  80. * Variables ending in _addr are adjusted according to where things would
  81. * actually appear in memory if the file were loaded.
  82. */
  83. static const char *file_base;
  84. static const char *text_base;
  85. static const char *data_base;
  86. static const struct relocation_info *rel_base;
  87. static const struct nlist *sym_base;
  88. static const char *str_base;
  89. static const struct relocation_info *rtrel_base;
  90. static const struct nzlist *rtsym_base;
  91. static const char *rtstr_base;
  92. static const struct exec *ex;
  93. static const struct _dynamic *dyn;
  94. static const struct section_dispatch_table *sdt;
  95. static const char *text_addr;
  96. static const char *data_addr;
  97. static unsigned long rel_count;
  98. static unsigned long sym_count;
  99. static unsigned long rtrel_count;
  100. static unsigned long rtsym_count;
  101. /* Dynamically allocated flags, 1 byte per symbol, to record whether each
  102. symbol was referenced by a relocation entry. */
  103. static unsigned char *sym_used;
  104. static unsigned char *rtsym_used;
  105. static unsigned long origin; /* What values are relocated relative to */
  106. #ifdef STANDALONE
  107. int
  108. main(int argc, char *argv[])
  109. {
  110. int i;
  111. for (i = 1; i < argc; ++i)
  112. dump_file(argv[i]);
  113. return error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
  114. }
  115. #endif
  116. static inline const void *align_struct(const void *expr)
  117. {
  118. assert(!(((int)expr) & 3));
  119. return expr;
  120. }
  121. static inline const void *align_long(const void *expr)
  122. {
  123. assert(!(((int)expr) & 3));
  124. return expr;
  125. }
  126. static inline const void *align_short(const void *expr)
  127. {
  128. assert(!(((int)expr) & 1));
  129. return expr;
  130. }
  131. #ifdef STANDALONE
  132. static
  133. #endif
  134. void
  135. dump_file(const char *fname)
  136. {
  137. int fd;
  138. struct stat sb;
  139. caddr_t objbase;
  140. if (stat(fname, &sb) == -1) {
  141. warnx("cannot stat \"%s\"", fname);
  142. ++error_count;
  143. return;
  144. }
  145. if ((sb.st_mode & S_IFMT) != S_IFREG) {
  146. warnx("\"%s\" is not a regular file", fname);
  147. ++error_count;
  148. return;
  149. }
  150. if ((fd = open(fname, O_RDONLY, 0)) == -1) {
  151. warnx("cannot open \"%s\"", fname);
  152. ++error_count;
  153. return;
  154. }
  155. objbase = mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
  156. if (objbase == (caddr_t) -1) {
  157. warnx("cannot mmap \"%s\"", fname);
  158. ++error_count;
  159. close(fd);
  160. return;
  161. }
  162. close(fd);
  163. file_base = (const char *) objbase; /* Makes address arithmetic easier */
  164. if (IS_ELF(*(const Elf32_Ehdr*) align_struct(file_base))) {
  165. warnx("%s: this is an ELF program; use objdump to examine", fname);
  166. ++error_count;
  167. munmap(objbase, sb.st_size);
  168. close(fd);
  169. return;
  170. }
  171. ex = (const struct exec *) align_struct(file_base);
  172. printf("%s: a_midmag = 0x%lx\n", fname, (long)ex->a_midmag);
  173. printf(" magic = 0x%lx = 0%lo, netmagic = 0x%lx = 0%lo\n",
  174. (long)N_GETMAGIC(*ex), (long)N_GETMAGIC(*ex),
  175. (long)N_GETMAGIC_NET(*ex), (long)N_GETMAGIC_NET(*ex));
  176. if (N_BADMAG(*ex)) {
  177. warnx("%s: bad magic number", fname);
  178. ++error_count;
  179. munmap(objbase, sb.st_size);
  180. return;
  181. }
  182. printf(" a_text = 0x%lx\n", (long)ex->a_text);
  183. printf(" a_data = 0x%lx\n", (long)ex->a_data);
  184. printf(" a_bss = 0x%lx\n", (long)ex->a_bss);
  185. printf(" a_syms = 0x%lx\n", (long)ex->a_syms);
  186. printf(" a_entry = 0x%lx\n", (long)ex->a_entry);
  187. printf(" a_trsize = 0x%lx\n", (long)ex->a_trsize);
  188. printf(" a_drsize = 0x%lx\n", (long)ex->a_drsize);
  189. text_base = file_base + N_TXTOFF(*ex);
  190. data_base = file_base + N_DATOFF(*ex);
  191. rel_base = (const struct relocation_info *)
  192. align_struct(file_base + N_RELOFF(*ex));
  193. sym_base = (const struct nlist *) align_struct(file_base + N_SYMOFF(*ex));
  194. str_base = file_base + N_STROFF(*ex);
  195. rel_count = (ex->a_trsize + ex->a_drsize) / sizeof rel_base[0];
  196. assert(rel_count * sizeof rel_base[0] == ex->a_trsize + ex->a_drsize);
  197. sym_count = ex->a_syms / sizeof sym_base[0];
  198. assert(sym_count * sizeof sym_base[0] == ex->a_syms);
  199. if (sym_count != 0) {
  200. sym_used = (unsigned char *) calloc(sym_count, sizeof(unsigned char));
  201. assert(sym_used != NULL);
  202. }
  203. printf(" Entry = 0x%lx\n", (long)ex->a_entry);
  204. printf(" Text offset = %x, address = %lx\n", N_TXTOFF(*ex),
  205. (long)N_TXTADDR(*ex));
  206. printf(" Data offset = %lx, address = %lx\n", (long)N_DATOFF(*ex),
  207. (long)N_DATADDR(*ex));
  208. /*
  209. * In an executable program file, everything is relocated relative to
  210. * the assumed run-time load address, i.e., N_TXTADDR(*ex), i.e., 0x1000.
  211. *
  212. * In a shared library file, everything is relocated relative to the
  213. * start of the file, i.e., N_TXTOFF(*ex), i.e., 0.
  214. *
  215. * The way to tell the difference is by looking at ex->a_entry. If it
  216. * is >= 0x1000, then we have an executable program. Otherwise, we
  217. * have a shared library.
  218. *
  219. * When a program is executed, the entire file is mapped into memory,
  220. * including the a.out header and so forth. But it is not mapped at
  221. * address 0; rather it is mapped at address 0x1000. The first page
  222. * of the user's address space is left unmapped in order to catch null
  223. * pointer dereferences.
  224. *
  225. * In this program, when we map in an executable program, we have to
  226. * simulate the empty page by decrementing our assumed base address by
  227. * a pagesize.
  228. */
  229. text_addr = text_base;
  230. data_addr = data_base;
  231. origin = 0;
  232. if (ex->a_entry >= PAGE_SIZE) { /* Executable, not a shared library */
  233. /*
  234. * The fields in the object have already been relocated on the
  235. * assumption that the object will be loaded at N_TXTADDR(*ex).
  236. * We have to compensate for that.
  237. */
  238. text_addr -= PAGE_SIZE;
  239. data_addr -= PAGE_SIZE;
  240. origin = PAGE_SIZE;
  241. printf(" Program, origin = %lx\n", origin);
  242. } else if (N_GETFLAG(*ex) & EX_DYNAMIC)
  243. printf(" Shared library, origin = %lx\n", origin);
  244. else
  245. printf(" Object file, origin = %lx\n", origin);
  246. if (N_GETFLAG(*ex) & EX_DYNAMIC) {
  247. dyn = (const struct _dynamic *) align_struct(data_base);
  248. printf(" Dynamic version = %d\n", dyn->d_version);
  249. sdt = (const struct section_dispatch_table *)
  250. align_struct(text_addr + (unsigned long) dyn->d_un.d_sdt);
  251. rtrel_base = (const struct relocation_info *)
  252. align_struct(text_addr + sdt->sdt_rel);
  253. rtrel_count = (sdt->sdt_hash - sdt->sdt_rel) / sizeof rtrel_base[0];
  254. assert(rtrel_count * sizeof rtrel_base[0] ==
  255. (size_t)(sdt->sdt_hash - sdt->sdt_rel));
  256. rtsym_base = (const struct nzlist *)
  257. align_struct(text_addr + sdt->sdt_nzlist);
  258. rtsym_count = (sdt->sdt_strings - sdt->sdt_nzlist) /
  259. sizeof rtsym_base[0];
  260. assert(rtsym_count * sizeof rtsym_base[0] ==
  261. (size_t)(sdt->sdt_strings - sdt->sdt_nzlist));
  262. if (rtsym_count != 0) {
  263. rtsym_used = (unsigned char *) calloc(rtsym_count,
  264. sizeof(unsigned char));
  265. assert(rtsym_used != NULL);
  266. }
  267. rtstr_base = text_addr + sdt->sdt_strings;
  268. }
  269. dump_segs();
  270. dump_sods();
  271. dump_rels("Relocations", rel_base, rel_count, sym_name, sym_used);
  272. dump_syms();
  273. dump_rels("Run-time relocations", rtrel_base, rtrel_count, rtsym_name,
  274. rtsym_used);
  275. dump_rtsyms();
  276. if (rtsym_used != NULL) {
  277. free(rtsym_used);
  278. rtsym_used = NULL;
  279. }
  280. if (sym_used != NULL) {
  281. free(sym_used);
  282. sym_used = NULL;
  283. }
  284. munmap(objbase, sb.st_size);
  285. }
  286. static void
  287. dump_rels(const char *label, const struct relocation_info *base,
  288. unsigned long count, const char *(*name)(unsigned long),
  289. unsigned char *sym_used_flags)
  290. {
  291. unsigned long i;
  292. printf(" %s:\n", label);
  293. for (i = 0; i < count; ++i) {
  294. const struct relocation_info *r = &base[i];
  295. unsigned int size;
  296. char contents[16];
  297. size = 1u << r->r_length;
  298. if (origin <= (unsigned long)r->r_address
  299. && (unsigned long)r->r_address < origin + ex->a_text + ex->a_data
  300. && 1 <= size && size <= 4) {
  301. /*
  302. * XXX - This can cause unaligned accesses. OK for the
  303. * i386, not so for other architectures.
  304. */
  305. switch (size) {
  306. case 1:
  307. snprintf(contents, sizeof contents, " [%02x]",
  308. *(unsigned const char *)(text_addr + r->r_address));
  309. break;
  310. case 2:
  311. snprintf(contents, sizeof contents, " [%04x]",
  312. *(unsigned const short *)
  313. align_short(text_addr + r->r_address));
  314. break;
  315. case 4:
  316. snprintf(contents, sizeof contents, "[%08lx]",
  317. *(unsigned const long *)
  318. align_long(text_addr + r->r_address));
  319. break;
  320. }
  321. } else
  322. snprintf(contents, sizeof contents, " ");
  323. printf(" %6lu %8x/%u %s %c%c%c%c%c%c", i,
  324. r->r_address, size,
  325. contents,
  326. r->r_extern ? 'e' : '-',
  327. r->r_jmptable ? 'j' : '-',
  328. r->r_relative ? 'r' : '-',
  329. r->r_baserel ? 'b' : '-',
  330. r->r_pcrel ? 'p' : '-',
  331. r->r_copy ? 'c' : '-');
  332. if (r->r_extern || r->r_baserel || r->r_jmptable || r->r_copy) {
  333. printf(" %4u %s", r->r_symbolnum, name(r->r_symbolnum));
  334. sym_used_flags[r->r_symbolnum] = 1;
  335. }
  336. printf("\n");
  337. }
  338. }
  339. static void
  340. dump_rtsyms(void)
  341. {
  342. unsigned long i;
  343. printf(" Run-time symbols:\n");
  344. for (i = 0; i < rtsym_count; ++i) {
  345. printf(" %6lu%c ", i, rtsym_used[i] ? '*' : ' ');
  346. dump_sym(&rtsym_base[i].nlist);
  347. printf("/%-5ld %s\n", rtsym_base[i].nz_size, rtsym_name(i));
  348. }
  349. }
  350. static void
  351. dump_segs(void)
  352. {
  353. printf(" Text segment starts at address %lx\n", origin + N_TXTOFF(*ex));
  354. if (N_GETFLAG(*ex) & EX_DYNAMIC) {
  355. printf(" rel starts at %lx\n", sdt->sdt_rel);
  356. printf(" hash starts at %lx\n", sdt->sdt_hash);
  357. printf(" nzlist starts at %lx\n", sdt->sdt_nzlist);
  358. printf(" strings starts at %lx\n", sdt->sdt_strings);
  359. }
  360. printf(" Data segment starts at address %lx\n", origin + N_DATOFF(*ex));
  361. if (N_GETFLAG(*ex) & EX_DYNAMIC) {
  362. printf(" _dynamic starts at %lx\n", origin + N_DATOFF(*ex));
  363. printf(" so_debug starts at %lx\n", (unsigned long) dyn->d_debug);
  364. printf(" sdt starts at %lx\n", (unsigned long) dyn->d_un.d_sdt);
  365. printf(" got starts at %lx\n", sdt->sdt_got);
  366. printf(" plt starts at %lx\n", sdt->sdt_plt);
  367. printf(" rest of stuff starts at %lx\n",
  368. sdt->sdt_plt + sdt->sdt_plt_sz);
  369. }
  370. }
  371. static void
  372. dump_sods(void)
  373. {
  374. long sod_offset;
  375. long paths_offset;
  376. if (dyn == NULL) /* Not a shared object */
  377. return;
  378. sod_offset = sdt->sdt_sods;
  379. printf(" Shared object dependencies:\n");
  380. while (sod_offset != 0) {
  381. const struct sod *sodp = (const struct sod *) align_struct((text_addr + sod_offset));
  382. const char *name = (const char *) (text_addr + sodp->sod_name);
  383. if (sodp->sod_library)
  384. printf(" -l%-16s version %d.%d\n", name, sodp->sod_major,
  385. sodp->sod_minor);
  386. else
  387. printf(" %s\n", name);
  388. sod_offset = sodp->sod_next;
  389. }
  390. paths_offset = sdt->sdt_paths;
  391. printf(" Shared object additional paths:\n");
  392. if (paths_offset != 0) {
  393. printf(" %s\n", (const char *)(text_addr + paths_offset));
  394. } else {
  395. printf(" (none)\n");
  396. }
  397. }
  398. static void
  399. dump_sym(const struct nlist *np)
  400. {
  401. char type[8];
  402. char aux[8];
  403. char weak;
  404. char *p;
  405. switch (np->n_type & ~N_EXT) {
  406. case N_UNDF: strcpy(type, "undf"); break;
  407. case N_ABS: strcpy(type, "abs"); break;
  408. case N_TEXT: strcpy(type, "text"); break;
  409. case N_DATA: strcpy(type, "data"); break;
  410. case N_BSS: strcpy(type, "bss"); break;
  411. case N_INDR: strcpy(type, "indr"); break;
  412. case N_SIZE: strcpy(type, "size"); break;
  413. case N_COMM: strcpy(type, "comm"); break;
  414. case N_SETA: strcpy(type, "seta"); break;
  415. case N_SETT: strcpy(type, "sett"); break;
  416. case N_SETD: strcpy(type, "setd"); break;
  417. case N_SETB: strcpy(type, "setb"); break;
  418. case N_SETV: strcpy(type, "setv"); break;
  419. case N_FN: strcpy(type, np->n_type&N_EXT ? "fn" : "warn"); break;
  420. case N_GSYM: strcpy(type, "gsym"); break;
  421. case N_FNAME: strcpy(type, "fname"); break;
  422. case N_FUN: strcpy(type, "fun"); break;
  423. case N_STSYM: strcpy(type, "stsym"); break;
  424. case N_LCSYM: strcpy(type, "lcsym"); break;
  425. case N_MAIN: strcpy(type, "main"); break;
  426. case N_PC: strcpy(type, "pc"); break;
  427. case N_RSYM: strcpy(type, "rsym"); break;
  428. case N_SLINE: strcpy(type, "sline"); break;
  429. case N_DSLINE: strcpy(type, "dsline"); break;
  430. case N_BSLINE: strcpy(type, "bsline"); break;
  431. case N_SSYM: strcpy(type, "ssym"); break;
  432. case N_SO: strcpy(type, "so"); break;
  433. case N_LSYM: strcpy(type, "lsym"); break;
  434. case N_BINCL: strcpy(type, "bincl"); break;
  435. case N_SOL: strcpy(type, "sol"); break;
  436. case N_PSYM: strcpy(type, "psym"); break;
  437. case N_EINCL: strcpy(type, "eincl"); break;
  438. case N_ENTRY: strcpy(type, "entry"); break;
  439. case N_LBRAC: strcpy(type, "lbrac"); break;
  440. case N_EXCL: strcpy(type, "excl"); break;
  441. case N_RBRAC: strcpy(type, "rbrac"); break;
  442. case N_BCOMM: strcpy(type, "bcomm"); break;
  443. case N_ECOMM: strcpy(type, "ecomm"); break;
  444. case N_ECOML: strcpy(type, "ecoml"); break;
  445. case N_LENG: strcpy(type, "leng"); break;
  446. default:
  447. snprintf(type, sizeof type, "%#02x", np->n_type);
  448. break;
  449. }
  450. if (np->n_type & N_EXT && type[0] != '0')
  451. for (p = type; *p != '\0'; ++p)
  452. *p = toupper(*p);
  453. switch (N_AUX(np)) {
  454. case 0: strcpy(aux, ""); break;
  455. case AUX_OBJECT: strcpy(aux, "objt"); break;
  456. case AUX_FUNC: strcpy(aux, "func"); break;
  457. default: snprintf(aux, sizeof aux, "%#01x", N_AUX(np)); break;
  458. }
  459. weak = N_BIND(np) == BIND_WEAK ? 'w' : ' ';
  460. printf("%c%-6s %-4s %8lx", weak, type, aux, np->n_value);
  461. }
  462. static void
  463. dump_syms(void)
  464. {
  465. unsigned long i;
  466. printf(" Symbols:\n");
  467. for (i = 0; i < sym_count; ++i) {
  468. printf(" %6lu%c ", i, sym_used[i] ? '*' : ' ');
  469. dump_sym(&sym_base[i]);
  470. printf(" %s\n", sym_name(i));
  471. }
  472. }
  473. static const char *
  474. rtsym_name(unsigned long n)
  475. {
  476. assert(n < rtsym_count);
  477. if (rtsym_base[n].nz_strx == 0)
  478. return "";
  479. return rtstr_base + rtsym_base[n].nz_strx;
  480. }
  481. static const char *
  482. sym_name(unsigned long n)
  483. {
  484. assert(n < sym_count);
  485. if (sym_base[n].n_un.n_strx == 0)
  486. return "";
  487. return str_base + sym_base[n].n_un.n_strx;
  488. }