readelf.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  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.11 1999/10/31 22:23:04 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 shs_type (class == ELFCLASS32 \
  90. ? getu32(swap, sh32.sh_type) \
  91. : getu32(swap, sh64.sh_type))
  92. #define ph_addr (class == ELFCLASS32 \
  93. ? (void *) &ph32 \
  94. : (void *) &ph64)
  95. #define ph_type (class == ELFCLASS32 \
  96. ? getu32(swap, ph32.p_type) \
  97. : getu32(swap, ph64.p_type))
  98. #define ph_offset (class == ELFCLASS32 \
  99. ? getu32(swap, ph32.p_offset) \
  100. : getu64(swap, ph64.p_offset))
  101. #define nh_size (class == ELFCLASS32 \
  102. ? sizeof *nh32 \
  103. : sizeof *nh64)
  104. #define nh_type (class == ELFCLASS32 \
  105. ? getu32(swap, nh32->n_type) \
  106. : getu32(swap, nh64->n_type))
  107. #define nh_namesz (class == ELFCLASS32 \
  108. ? getu32(swap, nh32->n_namesz) \
  109. : getu32(swap, nh64->n_namesz))
  110. #define nh_descsz (class == ELFCLASS32 \
  111. ? getu32(swap, nh32->n_descsz) \
  112. : getu32(swap, nh64->n_descsz))
  113. #define prpsoffsets(i) (class == ELFCLASS32 \
  114. ? prpsoffsets32[i] \
  115. : prpsoffsets64[i])
  116. static void
  117. doshn(class, swap, fd, off, num, size)
  118. int class;
  119. int swap;
  120. int fd;
  121. off_t off;
  122. int num;
  123. size_t size;
  124. {
  125. Elf32_Shdr sh32;
  126. Elf64_Shdr sh64;
  127. if (lseek(fd, off, SEEK_SET) == -1)
  128. error("lseek failed (%s).\n", strerror(errno));
  129. for ( ; num; num--) {
  130. if (read(fd, sh_addr, size) == -1)
  131. error("read failed (%s).\n", strerror(errno));
  132. if (shs_type == SHT_SYMTAB /* || shs_type == SHT_DYNSYM */) {
  133. (void) printf (", not stripped");
  134. return;
  135. }
  136. }
  137. (void) printf (", stripped");
  138. }
  139. /*
  140. * Look through the program headers of an executable image, searching
  141. * for a PT_INTERP section; if one is found, it's dynamically linked,
  142. * otherwise it's statically linked.
  143. */
  144. static void
  145. dophn_exec(class, swap, fd, off, num, size)
  146. int class;
  147. int swap;
  148. int fd;
  149. off_t off;
  150. int num;
  151. size_t size;
  152. {
  153. Elf32_Phdr ph32;
  154. Elf64_Phdr ph64;
  155. char *linking_style = "statically";
  156. char *shared_libraries = "";
  157. if (lseek(fd, off, SEEK_SET) == -1)
  158. error("lseek failed (%s).\n", strerror(errno));
  159. for ( ; num; num--) {
  160. if (read(fd, ph_addr, size) == -1)
  161. error("read failed (%s).\n", strerror(errno));
  162. switch (ph_type) {
  163. case PT_DYNAMIC:
  164. linking_style = "dynamically";
  165. break;
  166. case PT_INTERP:
  167. shared_libraries = " (uses shared libs)";
  168. break;
  169. }
  170. }
  171. printf(", %s linked%s", linking_style, shared_libraries);
  172. }
  173. #ifdef ELFCORE
  174. size_t prpsoffsets32[] = {
  175. 84, /* SunOS 5.x */
  176. 32, /* Linux */
  177. };
  178. size_t prpsoffsets64[] = {
  179. 120, /* SunOS 5.x, 64-bit */
  180. };
  181. #define NOFFSETS32 (sizeof prpsoffsets32 / sizeof prpsoffsets32[0])
  182. #define NOFFSETS64 (sizeof prpsoffsets64 / sizeof prpsoffsets64[0])
  183. #define NOFFSETS (class == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
  184. /*
  185. * Look through the program headers of an executable image, searching
  186. * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE"; if one
  187. * is found, try looking in various places in its contents for a 16-character
  188. * string containing only printable characters - if found, that string
  189. * should be the name of the program that dropped core.
  190. * Note: right after that 16-character string is, at least in SunOS 5.x
  191. * (and possibly other SVR4-flavored systems) and Linux, a longer string
  192. * (80 characters, in 5.x, probably other SVR4-flavored systems, and Linux)
  193. * containing the start of the command line for that program.
  194. */
  195. static void
  196. dophn_core(class, swap, fd, off, num, size)
  197. int class;
  198. int swap;
  199. int fd;
  200. off_t off;
  201. int num;
  202. size_t size;
  203. {
  204. Elf32_Phdr ph32;
  205. Elf32_Nhdr *nh32;
  206. Elf64_Phdr ph64;
  207. Elf64_Nhdr *nh64;
  208. size_t offset, noffset, reloffset;
  209. unsigned char c;
  210. int i, j;
  211. char nbuf[BUFSIZ];
  212. int bufsize;
  213. for ( ; num; num--) {
  214. if (lseek(fd, off, SEEK_SET) == -1)
  215. error("lseek failed (%s).\n", strerror(errno));
  216. if (read(fd, ph_addr, size) == -1)
  217. error("read failed (%s).\n", strerror(errno));
  218. off += size;
  219. if (ph_type != PT_NOTE)
  220. continue;
  221. if (lseek(fd, (off_t) ph_offset, SEEK_SET) == -1)
  222. error("lseek failed (%s).\n", strerror(errno));
  223. bufsize = read(fd, nbuf, BUFSIZ);
  224. if (bufsize == -1)
  225. error("read failed (%s).\n", strerror(errno));
  226. offset = 0;
  227. for (;;) {
  228. if (offset >= bufsize)
  229. break;
  230. if (class == ELFCLASS32)
  231. nh32 = (Elf32_Nhdr *)&nbuf[offset];
  232. else
  233. nh64 = (Elf64_Nhdr *)&nbuf[offset];
  234. offset += nh_size;
  235. /*
  236. * If this note isn't an NT_PRPSINFO note, it's
  237. * not what we're looking for.
  238. */
  239. if (nh_type != NT_PRPSINFO) {
  240. offset += nh_namesz;
  241. offset = ((offset + 3)/4)*4;
  242. offset += nh_descsz;
  243. offset = ((offset + 3)/4)*4;
  244. continue;
  245. }
  246. /*
  247. * Make sure this note has the name "CORE".
  248. */
  249. if (offset + nh_namesz >= bufsize) {
  250. /*
  251. * We're past the end of the buffer.
  252. */
  253. break;
  254. }
  255. if (nh_namesz != 5
  256. || strcmp(&nbuf[offset], "CORE") != 0)
  257. continue;
  258. offset += nh_namesz;
  259. offset = ((offset + 3)/4)*4;
  260. /*
  261. * Extract the program name. We assume it to be
  262. * 16 characters (that's what it is in SunOS 5.x
  263. * and Linux).
  264. *
  265. * Unfortunately, it's at a different offset in
  266. * SunOS 5.x and Linux, so try multiple offsets.
  267. * If the characters aren't all printable, reject
  268. * it.
  269. */
  270. for (i = 0; i < NOFFSETS; i++) {
  271. reloffset = prpsoffsets(i);
  272. noffset = offset + reloffset;
  273. for (j = 0; j < 16;
  274. j++, noffset++, reloffset++) {
  275. /*
  276. * Make sure we're not past the end
  277. * of the buffer; if we are, just
  278. * give up.
  279. */
  280. if (noffset >= bufsize)
  281. return;
  282. /*
  283. * Make sure we're not past the
  284. * end of the contents; if we
  285. * are, this obviously isn't
  286. * the right offset.
  287. */
  288. if (reloffset >= nh_descsz)
  289. goto tryanother;
  290. c = nbuf[noffset];
  291. if (c != '\0' && !isprint(c))
  292. goto tryanother;
  293. }
  294. /*
  295. * Well, that worked.
  296. */
  297. printf(", from '%.16s'",
  298. &nbuf[offset + prpsoffsets(i)]);
  299. return;
  300. tryanother:
  301. ;
  302. }
  303. offset += nh_descsz;
  304. offset = ((offset + 3)/4)*4;
  305. }
  306. }
  307. }
  308. #endif
  309. void
  310. tryelf(fd, buf, nbytes)
  311. int fd;
  312. unsigned char *buf;
  313. int nbytes;
  314. {
  315. union {
  316. int32 l;
  317. char c[sizeof (int32)];
  318. } u;
  319. int class;
  320. int swap;
  321. /*
  322. * ELF executables have multiple section headers in arbitrary
  323. * file locations and thus file(1) cannot determine it from easily.
  324. * Instead we traverse thru all section headers until a symbol table
  325. * one is found or else the binary is stripped.
  326. */
  327. if (buf[EI_MAG0] != ELFMAG0
  328. || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1)
  329. || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
  330. return;
  331. class = buf[4];
  332. if (class == ELFCLASS32) {
  333. Elf32_Ehdr elfhdr;
  334. if (nbytes <= sizeof (Elf32_Ehdr))
  335. return;
  336. u.l = 1;
  337. (void) memcpy(&elfhdr, buf, sizeof elfhdr);
  338. swap = (u.c[sizeof(long) - 1] + 1) != elfhdr.e_ident[5];
  339. if (getu16(swap, elfhdr.e_type) == ET_CORE)
  340. #ifdef ELFCORE
  341. dophn_core(class, swap,
  342. fd,
  343. getu32(swap, elfhdr.e_phoff),
  344. getu16(swap, elfhdr.e_phnum),
  345. getu16(swap, elfhdr.e_phentsize));
  346. #else
  347. ;
  348. #endif
  349. else {
  350. if (getu16(swap, elfhdr.e_type) == ET_EXEC) {
  351. dophn_exec(class, swap,
  352. fd,
  353. getu32(swap, elfhdr.e_phoff),
  354. getu16(swap, elfhdr.e_phnum),
  355. getu16(swap, elfhdr.e_phentsize));
  356. }
  357. doshn(class, swap,
  358. fd,
  359. getu32(swap, elfhdr.e_shoff),
  360. getu16(swap, elfhdr.e_shnum),
  361. getu16(swap, elfhdr.e_shentsize));
  362. }
  363. return;
  364. }
  365. if (class == ELFCLASS64) {
  366. Elf64_Ehdr elfhdr;
  367. if (nbytes <= sizeof (Elf64_Ehdr))
  368. return;
  369. u.l = 1;
  370. (void) memcpy(&elfhdr, buf, sizeof elfhdr);
  371. swap = (u.c[sizeof(long) - 1] + 1) != elfhdr.e_ident[5];
  372. if (getu16(swap, elfhdr.e_type) == ET_CORE)
  373. #ifdef ELFCORE
  374. dophn_core(class, swap,
  375. fd,
  376. #ifdef USE_ARRAY_FOR_64BIT_TYPES
  377. getu32(swap, elfhdr.e_phoff[1]),
  378. #else
  379. getu64(swap, elfhdr.e_phoff),
  380. #endif
  381. getu16(swap, elfhdr.e_phnum),
  382. getu16(swap, elfhdr.e_phentsize));
  383. #else
  384. ;
  385. #endif
  386. else
  387. {
  388. if (getu16(swap, elfhdr.e_type) == ET_EXEC) {
  389. dophn_exec(class, swap,
  390. fd,
  391. #ifdef USE_ARRAY_FOR_64BIT_TYPES
  392. getu32(swap, elfhdr.e_phoff[1]),
  393. #else
  394. getu64(swap, elfhdr.e_phoff),
  395. #endif
  396. getu16(swap, elfhdr.e_phnum),
  397. getu16(swap, elfhdr.e_phentsize));
  398. }
  399. doshn(class, swap,
  400. fd,
  401. #ifdef USE_ARRAY_FOR_64BIT_TYPES
  402. getu32(swap, elfhdr.e_shoff[1]),
  403. #else
  404. getu64(swap, elfhdr.e_shoff),
  405. #endif
  406. getu16(swap, elfhdr.e_shnum),
  407. getu16(swap, elfhdr.e_shentsize));
  408. }
  409. return;
  410. }
  411. }
  412. #endif