readelf.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. #include "file.h"
  2. #ifdef BUILTIN_ELF
  3. #ifdef HAVE_CONFIG_H
  4. #include <config.h>
  5. #endif
  6. #include <sys/types.h>
  7. #include <string.h>
  8. #include <stdio.h>
  9. #include <ctype.h>
  10. #include <stdlib.h>
  11. #ifdef HAVE_UNISTD_H
  12. #include <unistd.h>
  13. #endif
  14. #include <errno.h>
  15. #include "readelf.h"
  16. #ifndef lint
  17. FILE_RCSID("@(#)$Id: readelf.c,v 1.17 2000/08/05 19:00:12 christos Exp $")
  18. #endif
  19. #ifdef ELFCORE
  20. static void dophn_core __P((int, int, int, off_t, int, size_t));
  21. #endif
  22. static void dophn_exec __P((int, int, int, off_t, int, size_t));
  23. static void doshn __P((int, int, int, off_t, int, size_t));
  24. static uint16_t getu16 __P((int, int));
  25. static uint32_t getu32 __P((int, uint32_t));
  26. static uint64_t getu64 __P((int, uint64_t));
  27. static uint16_t
  28. getu16(swap, value)
  29. int swap;
  30. uint16_t value;
  31. {
  32. union {
  33. uint16_t ui;
  34. char c[2];
  35. } retval, tmpval;
  36. if (swap) {
  37. tmpval.ui = value;
  38. retval.c[0] = tmpval.c[1];
  39. retval.c[1] = tmpval.c[0];
  40. return retval.ui;
  41. } else
  42. return value;
  43. }
  44. static uint32_t
  45. getu32(swap, value)
  46. int swap;
  47. uint32_t value;
  48. {
  49. union {
  50. uint32_t ui;
  51. char c[4];
  52. } retval, tmpval;
  53. if (swap) {
  54. tmpval.ui = value;
  55. retval.c[0] = tmpval.c[3];
  56. retval.c[1] = tmpval.c[2];
  57. retval.c[2] = tmpval.c[1];
  58. retval.c[3] = tmpval.c[0];
  59. return retval.ui;
  60. } else
  61. return value;
  62. }
  63. static uint64_t
  64. getu64(swap, value)
  65. int swap;
  66. uint64_t value;
  67. {
  68. union {
  69. uint64_t ui;
  70. char c[8];
  71. } retval, tmpval;
  72. if (swap) {
  73. tmpval.ui = value;
  74. retval.c[0] = tmpval.c[7];
  75. retval.c[1] = tmpval.c[6];
  76. retval.c[2] = tmpval.c[5];
  77. retval.c[3] = tmpval.c[4];
  78. retval.c[4] = tmpval.c[3];
  79. retval.c[5] = tmpval.c[2];
  80. retval.c[6] = tmpval.c[1];
  81. retval.c[7] = tmpval.c[0];
  82. return retval.ui;
  83. } else
  84. return value;
  85. }
  86. #define sh_addr (class == ELFCLASS32 \
  87. ? (void *) &sh32 \
  88. : (void *) &sh64)
  89. #define sh_size (class == ELFCLASS32 \
  90. ? sizeof sh32 \
  91. : sizeof sh64)
  92. #define shs_type (class == ELFCLASS32 \
  93. ? getu32(swap, sh32.sh_type) \
  94. : getu32(swap, sh64.sh_type))
  95. #define ph_addr (class == ELFCLASS32 \
  96. ? (void *) &ph32 \
  97. : (void *) &ph64)
  98. #define ph_size (class == ELFCLASS32 \
  99. ? sizeof ph32 \
  100. : sizeof ph64)
  101. #define ph_type (class == ELFCLASS32 \
  102. ? getu32(swap, ph32.p_type) \
  103. : getu32(swap, ph64.p_type))
  104. #define ph_offset (class == ELFCLASS32 \
  105. ? getu32(swap, ph32.p_offset) \
  106. : getu64(swap, ph64.p_offset))
  107. #define nh_size (class == ELFCLASS32 \
  108. ? sizeof *nh32 \
  109. : sizeof *nh64)
  110. #define nh_type (class == ELFCLASS32 \
  111. ? getu32(swap, nh32->n_type) \
  112. : getu32(swap, nh64->n_type))
  113. #define nh_namesz (class == ELFCLASS32 \
  114. ? getu32(swap, nh32->n_namesz) \
  115. : getu32(swap, nh64->n_namesz))
  116. #define nh_descsz (class == ELFCLASS32 \
  117. ? getu32(swap, nh32->n_descsz) \
  118. : getu32(swap, nh64->n_descsz))
  119. #define prpsoffsets(i) (class == ELFCLASS32 \
  120. ? prpsoffsets32[i] \
  121. : prpsoffsets64[i])
  122. static void
  123. doshn(class, swap, fd, off, num, size)
  124. int class;
  125. int swap;
  126. int fd;
  127. off_t off;
  128. int num;
  129. size_t size;
  130. {
  131. Elf32_Shdr sh32;
  132. Elf64_Shdr sh64;
  133. if (size != sh_size)
  134. error("corrupted section header size.\n");
  135. if (lseek(fd, off, SEEK_SET) == -1)
  136. error("lseek failed (%s).\n", strerror(errno));
  137. for ( ; num; num--) {
  138. if (read(fd, sh_addr, sh_size) == -1)
  139. error("read failed (%s).\n", strerror(errno));
  140. if (shs_type == SHT_SYMTAB /* || shs_type == SHT_DYNSYM */) {
  141. (void) printf (", not stripped");
  142. return;
  143. }
  144. }
  145. (void) printf (", stripped");
  146. }
  147. /*
  148. * Look through the program headers of an executable image, searching
  149. * for a PT_INTERP section; if one is found, it's dynamically linked,
  150. * otherwise it's statically linked.
  151. */
  152. static void
  153. dophn_exec(class, swap, fd, off, num, size)
  154. int class;
  155. int swap;
  156. int fd;
  157. off_t off;
  158. int num;
  159. size_t size;
  160. {
  161. Elf32_Phdr ph32;
  162. Elf64_Phdr ph64;
  163. char *linking_style = "statically";
  164. char *shared_libraries = "";
  165. if (size != ph_size)
  166. error("corrupted program header size.\n");
  167. if (lseek(fd, off, SEEK_SET) == -1)
  168. error("lseek failed (%s).\n", strerror(errno));
  169. for ( ; num; num--) {
  170. if (read(fd, ph_addr, ph_size) == -1)
  171. error("read failed (%s).\n", strerror(errno));
  172. switch (ph_type) {
  173. case PT_DYNAMIC:
  174. linking_style = "dynamically";
  175. break;
  176. case PT_INTERP:
  177. shared_libraries = " (uses shared libs)";
  178. break;
  179. }
  180. }
  181. printf(", %s linked%s", linking_style, shared_libraries);
  182. }
  183. #ifdef ELFCORE
  184. size_t prpsoffsets32[] = {
  185. 8, /* FreeBSD */
  186. 28, /* Linux 2.0.36 */
  187. 32, /* Linux (I forget which kernel version) */
  188. 84, /* SunOS 5.x */
  189. };
  190. size_t prpsoffsets64[] = {
  191. 120, /* SunOS 5.x, 64-bit */
  192. };
  193. #define NOFFSETS32 (sizeof prpsoffsets32 / sizeof prpsoffsets32[0])
  194. #define NOFFSETS64 (sizeof prpsoffsets64 / sizeof prpsoffsets64[0])
  195. #define NOFFSETS (class == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
  196. /*
  197. * Look through the program headers of an executable image, searching
  198. * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or
  199. * "FreeBSD"; if one is found, try looking in various places in its
  200. * contents for a 16-character string containing only printable
  201. * characters - if found, that string should be the name of the program
  202. * that dropped core. Note: right after that 16-character string is,
  203. * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and
  204. * Linux, a longer string (80 characters, in 5.x, probably other
  205. * SVR4-flavored systems, and Linux) containing the start of the
  206. * command line for that program.
  207. *
  208. * The signal number probably appears in a section of type NT_PRSTATUS,
  209. * but that's also rather OS-dependent, in ways that are harder to
  210. * dissect with heuristics, so I'm not bothering with the signal number.
  211. * (I suppose the signal number could be of interest in situations where
  212. * you don't have the binary of the program that dropped core; if you
  213. * *do* have that binary, the debugger will probably tell you what
  214. * signal it was.)
  215. */
  216. static void
  217. dophn_core(class, swap, fd, off, num, size)
  218. int class;
  219. int swap;
  220. int fd;
  221. off_t off;
  222. int num;
  223. size_t size;
  224. {
  225. Elf32_Phdr ph32;
  226. Elf32_Nhdr *nh32;
  227. Elf64_Phdr ph64;
  228. Elf64_Nhdr *nh64;
  229. size_t offset, nameoffset, noffset, reloffset;
  230. unsigned char c;
  231. int i, j;
  232. char nbuf[BUFSIZ];
  233. int bufsize;
  234. int is_freebsd;
  235. if (size != ph_size)
  236. error("corrupted program header size.\n");
  237. /*
  238. * Loop through all the program headers.
  239. */
  240. for ( ; num; num--) {
  241. if (lseek(fd, off, SEEK_SET) == -1)
  242. error("lseek failed (%s).\n", strerror(errno));
  243. if (read(fd, ph_addr, ph_size) == -1)
  244. error("read failed (%s).\n", strerror(errno));
  245. off += size;
  246. if (ph_type != PT_NOTE)
  247. continue;
  248. /*
  249. * This is a PT_NOTE section; loop through all the notes
  250. * in the section.
  251. */
  252. if (lseek(fd, (off_t) ph_offset, SEEK_SET) == -1)
  253. error("lseek failed (%s).\n", strerror(errno));
  254. bufsize = read(fd, nbuf, BUFSIZ);
  255. if (bufsize == -1)
  256. error(": " "read failed (%s).\n", strerror(errno));
  257. offset = 0;
  258. for (;;) {
  259. if (offset >= bufsize)
  260. break;
  261. if (class == ELFCLASS32)
  262. nh32 = (Elf32_Nhdr *)&nbuf[offset];
  263. else
  264. nh64 = (Elf64_Nhdr *)&nbuf[offset];
  265. offset += nh_size;
  266. /*
  267. * Check whether this note has the name "CORE" or
  268. * "FreeBSD".
  269. */
  270. if (offset + nh_namesz >= bufsize) {
  271. /*
  272. * We're past the end of the buffer.
  273. */
  274. break;
  275. }
  276. nameoffset = offset;
  277. offset += nh_namesz;
  278. offset = ((offset + 3)/4)*4;
  279. /*
  280. * Sigh. The 2.0.36 kernel in Debian 2.1, at
  281. * least, doesn't correctly implement name
  282. * sections, in core dumps, as specified by
  283. * the "Program Linking" section of "UNIX(R) System
  284. * V Release 4 Programmer's Guide: ANSI C and
  285. * Programming Support Tools", because my copy
  286. * clearly says "The first 'namesz' bytes in 'name'
  287. * contain a *null-terminated* [emphasis mine]
  288. * character representation of the entry's owner
  289. * or originator", but the 2.0.36 kernel code
  290. * doesn't include the terminating null in the
  291. * name....
  292. */
  293. if ((nh_namesz == 4 &&
  294. strncmp(&nbuf[nameoffset], "CORE", 4) == 0) ||
  295. (nh_namesz == 5 &&
  296. strcmp(&nbuf[nameoffset], "CORE") == 0))
  297. is_freebsd = 0;
  298. else if ((nh_namesz == 8 &&
  299. strcmp(&nbuf[nameoffset], "FreeBSD") == 0))
  300. is_freebsd = 1;
  301. else
  302. continue;
  303. if (nh_type == NT_PRPSINFO) {
  304. /*
  305. * Extract the program name. We assume
  306. * it to be 16 characters (that's what it
  307. * is in SunOS 5.x and Linux).
  308. *
  309. * Unfortunately, it's at a different offset
  310. * in varous OSes, so try multiple offsets.
  311. * If the characters aren't all printable,
  312. * reject it.
  313. */
  314. for (i = 0; i < NOFFSETS; i++) {
  315. reloffset = prpsoffsets(i);
  316. noffset = offset + reloffset;
  317. for (j = 0; j < 16;
  318. j++, noffset++, reloffset++) {
  319. /*
  320. * Make sure we're not past
  321. * the end of the buffer; if
  322. * we are, just give up.
  323. */
  324. if (noffset >= bufsize)
  325. goto tryanother;
  326. /*
  327. * Make sure we're not past
  328. * the end of the contents;
  329. * if we are, this obviously
  330. * isn't the right offset.
  331. */
  332. if (reloffset >= nh_descsz)
  333. goto tryanother;
  334. c = nbuf[noffset];
  335. if (c == '\0') {
  336. /*
  337. * A '\0' at the
  338. * beginning is
  339. * obviously wrong.
  340. * Any other '\0'
  341. * means we're done.
  342. */
  343. if (j == 0)
  344. goto tryanother;
  345. else
  346. break;
  347. } else {
  348. /*
  349. * A nonprintable
  350. * character is also
  351. * wrong.
  352. */
  353. #define isquote(c) (strchr("'\"`", (c)) != NULL)
  354. if (!isprint(c) ||
  355. isquote(c))
  356. goto tryanother;
  357. }
  358. }
  359. /*
  360. * Well, that worked.
  361. */
  362. printf(", from '%.16s'",
  363. &nbuf[offset + prpsoffsets(i)]);
  364. break;
  365. tryanother:
  366. ;
  367. }
  368. break;
  369. }
  370. offset += nh_descsz;
  371. offset = ((offset + 3)/4)*4;
  372. }
  373. }
  374. }
  375. #endif
  376. pipe2file(int fd, char *startbuf, int nbytes)
  377. {
  378. FILE *tmp = tmpfile();
  379. char buf[4096];
  380. int r = 0, w = 0, available = 4096, rc;
  381. if (tmp == NULL) {
  382. error("can't create temporary file for pipe copy(%s).\n", strerror(errno));
  383. /*NOTREACHED*/
  384. }
  385. while(w!=-1 && nbytes)
  386. {
  387. nbytes-=fwrite(startbuf, 1, nbytes, tmp);
  388. if(nbytes && errno!=EINTR)
  389. w=-1;
  390. }
  391. while (r!=-1 && w!=-1)
  392. {
  393. char *ptr;
  394. r = read(fd, buf, available);
  395. if (r == -1 && errno == EINTR)
  396. continue;
  397. if (r <= 0)
  398. break;
  399. ptr = buf;
  400. while (r) {
  401. w = fwrite(ptr, 1, r, tmp);
  402. if (w < r && errno != EINTR)
  403. {
  404. w=-1;
  405. break;
  406. }
  407. r -= w;
  408. ptr += w;
  409. }
  410. }
  411. if (r == -1) {
  412. error("error while copying from pipe to tempfile(%s).\n", strerror(errno));
  413. /*NOTREACHED*/
  414. }
  415. if (w == -1) {
  416. error("error while writing to tempfile(%s).\n", strerror(errno));
  417. /*NOTREACHED*/
  418. }
  419. /* We duplicate the file descriptor, because fclose on a
  420. * tmpfile will delete the file, but any open descriptors
  421. * can still access the phantom inode.
  422. */
  423. if ((fd = dup2(fileno(tmp), fd)) == -1) {
  424. error("couldn't dup destcriptor for tmpfile(%s).\n", strerror(errno));
  425. /*NOTREACHED*/
  426. }
  427. fclose(tmp);
  428. if (lseek(fd, 0, SEEK_SET)) {
  429. error("couldn't seek on tmpfile(%s).\n", strerror(errno));
  430. /*NOTREACHED*/
  431. }
  432. return fd;
  433. }
  434. void
  435. tryelf(fd, buf, nbytes)
  436. int fd;
  437. unsigned char *buf;
  438. int nbytes;
  439. {
  440. union {
  441. int32 l;
  442. char c[sizeof (int32)];
  443. } u;
  444. int class;
  445. int swap;
  446. /*
  447. * ELF executables have multiple section headers in arbitrary
  448. * file locations and thus file(1) cannot determine it from easily.
  449. * Instead we traverse thru all section headers until a symbol table
  450. * one is found or else the binary is stripped.
  451. */
  452. if (buf[EI_MAG0] != ELFMAG0
  453. || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1)
  454. || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
  455. return;
  456. /*
  457. * If we can't seek, it must be a pipe, socket or fifo.
  458. */
  459. if((lseek(fd,5,SEEK_SET) == (off_t)-1) && (errno == ESPIPE))
  460. fd=pipe2file(fd,buf,nbytes);
  461. class = buf[4];
  462. if (class == ELFCLASS32) {
  463. Elf32_Ehdr elfhdr;
  464. if (nbytes <= sizeof (Elf32_Ehdr))
  465. return;
  466. u.l = 1;
  467. (void) memcpy(&elfhdr, buf, sizeof elfhdr);
  468. swap = (u.c[sizeof(int32) - 1] + 1) != elfhdr.e_ident[5];
  469. if (getu16(swap, elfhdr.e_type) == ET_CORE)
  470. #ifdef ELFCORE
  471. dophn_core(class, swap,
  472. fd,
  473. getu32(swap, elfhdr.e_phoff),
  474. getu16(swap, elfhdr.e_phnum),
  475. getu16(swap, elfhdr.e_phentsize));
  476. #else
  477. ;
  478. #endif
  479. else {
  480. if (getu16(swap, elfhdr.e_type) == ET_EXEC) {
  481. dophn_exec(class, swap,
  482. fd,
  483. getu32(swap, elfhdr.e_phoff),
  484. getu16(swap, elfhdr.e_phnum),
  485. getu16(swap, elfhdr.e_phentsize));
  486. }
  487. doshn(class, swap,
  488. fd,
  489. getu32(swap, elfhdr.e_shoff),
  490. getu16(swap, elfhdr.e_shnum),
  491. getu16(swap, elfhdr.e_shentsize));
  492. }
  493. return;
  494. }
  495. if (class == ELFCLASS64) {
  496. Elf64_Ehdr elfhdr;
  497. if (nbytes <= sizeof (Elf64_Ehdr))
  498. return;
  499. u.l = 1;
  500. (void) memcpy(&elfhdr, buf, sizeof elfhdr);
  501. swap = (u.c[sizeof(int32) - 1] + 1) != elfhdr.e_ident[5];
  502. if (getu16(swap, elfhdr.e_type) == ET_CORE)
  503. #ifdef ELFCORE
  504. dophn_core(class, swap,
  505. fd,
  506. #ifdef USE_ARRAY_FOR_64BIT_TYPES
  507. getu32(swap, elfhdr.e_phoff[1]),
  508. #else
  509. getu64(swap, elfhdr.e_phoff),
  510. #endif
  511. getu16(swap, elfhdr.e_phnum),
  512. getu16(swap, elfhdr.e_phentsize));
  513. #else
  514. ;
  515. #endif
  516. else
  517. {
  518. if (getu16(swap, elfhdr.e_type) == ET_EXEC) {
  519. dophn_exec(class, swap,
  520. fd,
  521. #ifdef USE_ARRAY_FOR_64BIT_TYPES
  522. getu32(swap, elfhdr.e_phoff[1]),
  523. #else
  524. getu64(swap, elfhdr.e_phoff),
  525. #endif
  526. getu16(swap, elfhdr.e_phnum),
  527. getu16(swap, elfhdr.e_phentsize));
  528. }
  529. doshn(class, swap,
  530. fd,
  531. #ifdef USE_ARRAY_FOR_64BIT_TYPES
  532. getu32(swap, elfhdr.e_shoff[1]),
  533. #else
  534. getu64(swap, elfhdr.e_shoff),
  535. #endif
  536. getu16(swap, elfhdr.e_shnum),
  537. getu16(swap, elfhdr.e_shentsize));
  538. }
  539. return;
  540. }
  541. }
  542. #endif