readelf.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. #ifdef BUILTIN_ELF
  2. #include <sys/types.h>
  3. #include <string.h>
  4. #include <stdio.h>
  5. #include <ctype.h>
  6. #include <stdlib.h>
  7. #include <unistd.h>
  8. #include <errno.h>
  9. #include "readelf.h"
  10. #include "file.h"
  11. static void
  12. doshn(fd, off, num, size, buf)
  13. int fd;
  14. off_t off;
  15. int num;
  16. size_t size;
  17. char *buf;
  18. {
  19. /*
  20. * This works for both 32-bit and 64-bit ELF formats,
  21. * because it looks only at the "sh_type" field, which is
  22. * always 32 bits, and is preceded only by the "sh_name"
  23. * field which is also always 32 bits, and because it uses
  24. * the shdr size from the ELF header rather than using
  25. * the size of an "Elf32_Shdr".
  26. */
  27. Elf32_Shdr *sh = (Elf32_Shdr *) buf;
  28. if (lseek(fd, off, SEEK_SET) == -1)
  29. error("lseek failed (%m).\n");
  30. for ( ; num; num--) {
  31. if (read(fd, buf, size) == -1)
  32. error("read failed (%m).\n");
  33. if (sh->sh_type == SHT_SYMTAB) {
  34. (void) printf (", not stripped");
  35. return;
  36. }
  37. }
  38. (void) printf (", stripped");
  39. }
  40. /*
  41. * Look through the program headers of an executable image, searching
  42. * for a PT_INTERP section; if one is found, it's dynamically linked,
  43. * otherwise it's statically linked.
  44. */
  45. static void
  46. dophn_exec(fd, off, num, size, buf)
  47. int fd;
  48. off_t off;
  49. int num;
  50. size_t size;
  51. char *buf;
  52. {
  53. /* I am not sure if this works for 64 bit elf formats */
  54. Elf32_Phdr *ph = (Elf32_Phdr *) buf;
  55. if (lseek(fd, off, SEEK_SET) == -1)
  56. error("lseek failed (%m).\n");
  57. for ( ; num; num--) {
  58. if (read(fd, buf, size) == -1)
  59. error("read failed (%m).\n");
  60. if (ph->p_type == PT_INTERP) {
  61. /*
  62. * Has an interpreter - must be a dynamically-linked
  63. * executable.
  64. */
  65. printf(", dynamically linked");
  66. return;
  67. }
  68. }
  69. printf(", statically linked");
  70. }
  71. size_t prpsoffsets[] = {
  72. 84, /* SunOS 5.x */
  73. 32, /* Linux */
  74. };
  75. #define NOFFSETS (sizeof prpsoffsets / sizeof prpsoffsets[0])
  76. /*
  77. * Look through the program headers of an executable image, searching
  78. * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE"; if one
  79. * is found, try looking in various places in its contents for a 16-character
  80. * string containing only printable characters - if found, that string
  81. * should be the name of the program that dropped core.
  82. * Note: right after that 16-character string is, at least in SunOS 5.x
  83. * (and possibly other SVR4-flavored systems) and Linux, a longer string
  84. * (80 characters, in 5.x, probably other SVR4-flavored systems, and Linux)
  85. * containing the start of the command line for that program.
  86. */
  87. static void
  88. dophn_core(fd, off, num, size, buf)
  89. int fd;
  90. off_t off;
  91. int num;
  92. size_t size;
  93. char *buf;
  94. {
  95. /*
  96. * This doesn't work for 64-bit ELF, as the "p_offset" field is
  97. * 64 bits in 64-bit ELF.
  98. */
  99. Elf32_Phdr *ph = (Elf32_Phdr *) buf;
  100. Elf32_Nhdr *nh;
  101. size_t offset, noffset, reloffset;
  102. unsigned char c;
  103. int i, j;
  104. char nbuf[BUFSIZ];
  105. int bufsize;
  106. for ( ; num; num--) {
  107. if (lseek(fd, off, SEEK_SET) == -1)
  108. error("lseek failed (%m).\n");
  109. if (read(fd, buf, size) == -1)
  110. error("read failed (%m).\n");
  111. off += size;
  112. if (ph->p_type != PT_NOTE)
  113. continue;
  114. if (lseek(fd, ph->p_offset, SEEK_SET) == -1)
  115. error("lseek failed (%m).\n");
  116. bufsize = read(fd, nbuf, BUFSIZ);
  117. if (bufsize == -1)
  118. error("read failed (%m).\n");
  119. offset = 0;
  120. for (;;) {
  121. if (offset >= bufsize)
  122. break;
  123. nh = (Elf32_Nhdr *)&nbuf[offset];
  124. offset += sizeof *nh;
  125. /*
  126. * If this note isn't an NT_PRPSINFO note, it's
  127. * not what we're looking for.
  128. */
  129. if (nh->n_type != NT_PRPSINFO) {
  130. offset += nh->n_namesz;
  131. offset = ((offset + 3)/4)*4;
  132. offset += nh->n_descsz;
  133. offset = ((offset + 3)/4)*4;
  134. continue;
  135. }
  136. /*
  137. * Make sure this note has the name "CORE".
  138. */
  139. if (offset + nh->n_namesz >= bufsize) {
  140. /*
  141. * We're past the end of the buffer.
  142. */
  143. break;
  144. }
  145. if (nh->n_namesz != 5
  146. || strcmp(&nbuf[offset], "CORE") != 0)
  147. continue;
  148. offset += nh->n_namesz;
  149. offset = ((offset + 3)/4)*4;
  150. /*
  151. * Extract the program name. We assume it to be
  152. * 16 characters (that's what it is in SunOS 5.x
  153. * and Linux).
  154. *
  155. * Unfortunately, it's at a different offset in
  156. * SunOS 5.x and Linux, so try multiple offsets.
  157. * If the characters aren't all printable, reject
  158. * it.
  159. */
  160. for (i = 0; i < NOFFSETS; i++) {
  161. reloffset = prpsoffsets[i];
  162. noffset = offset + reloffset;
  163. for (j = 0; j < 16;
  164. j++, noffset++, reloffset++) {
  165. /*
  166. * Make sure we're not past the end
  167. * of the buffer; if we are, just
  168. * give up.
  169. */
  170. if (noffset >= bufsize)
  171. return;
  172. /*
  173. * Make sure we're not past the
  174. * end of the contents; if we
  175. * are, this obviously isn't
  176. * the right offset.
  177. */
  178. if (reloffset >= nh->n_descsz)
  179. goto tryanother;
  180. c = nbuf[noffset];
  181. if (c != '\0' && !isprint(c))
  182. goto tryanother;
  183. }
  184. /*
  185. * Well, that worked.
  186. */
  187. printf(", from '%.16s'",
  188. &nbuf[offset + prpsoffsets[i]]);
  189. return;
  190. tryanother:
  191. ;
  192. }
  193. offset += nh->n_descsz;
  194. offset = ((offset + 3)/4)*4;
  195. }
  196. }
  197. }
  198. void
  199. tryelf(fd, buf, nbytes)
  200. int fd;
  201. char *buf;
  202. int nbytes;
  203. {
  204. union {
  205. int32 l;
  206. char c[sizeof (int32)];
  207. } u;
  208. /*
  209. * ELF executables have multiple section headers in arbitrary
  210. * file locations and thus file(1) cannot determine it from easily.
  211. * Instead we traverse thru all section headers until a symbol table
  212. * one is found or else the binary is stripped.
  213. */
  214. if (buf[EI_MAG0] != ELFMAG0 || buf[EI_MAG1] != ELFMAG1
  215. || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
  216. return;
  217. if (buf[4] == ELFCLASS32) {
  218. Elf32_Ehdr elfhdr;
  219. if (nbytes <= sizeof (Elf32_Ehdr))
  220. return;
  221. u.l = 1;
  222. (void) memcpy(&elfhdr, buf, sizeof elfhdr);
  223. /*
  224. * If the system byteorder does not equal the
  225. * object byteorder then don't test.
  226. * XXX - we could conceivably fix up the "dophn_XXX()" and
  227. * "doshn()" routines to extract stuff in the right
  228. * byte order....
  229. */
  230. if ((u.c[sizeof(long) - 1] + 1) == elfhdr.e_ident[5]) {
  231. if (elfhdr.e_type == ET_CORE)
  232. dophn_core(fd, elfhdr.e_phoff, elfhdr.e_phnum,
  233. elfhdr.e_phentsize, buf);
  234. else {
  235. if (elfhdr.e_type == ET_EXEC) {
  236. dophn_exec(fd, elfhdr.e_phoff,
  237. elfhdr.e_phnum,
  238. elfhdr.e_phentsize, buf);
  239. }
  240. doshn(fd, elfhdr.e_shoff, elfhdr.e_shnum,
  241. elfhdr.e_shentsize, buf);
  242. }
  243. }
  244. return;
  245. }
  246. if (buf[4] == ELFCLASS64) {
  247. Elf64_Ehdr elfhdr;
  248. if (nbytes <= sizeof (Elf64_Ehdr))
  249. return;
  250. u.l = 1;
  251. (void) memcpy(&elfhdr, buf, sizeof elfhdr);
  252. /*
  253. * If the system byteorder does not equal the
  254. * object byteorder then don't test.
  255. * XXX - we could conceivably fix up the "dophn_XXX()" and
  256. * "doshn()" routines to extract stuff in the right
  257. * byte order....
  258. */
  259. if ((u.c[sizeof(long) - 1] + 1) == elfhdr.e_ident[5]) {
  260. #ifdef notyet
  261. if (elfhdr.e_type == ET_CORE)
  262. dophn_core(fd, elfhdr.e_phoff[1],
  263. elfhdr.e_phnum,
  264. elfhdr.e_phentsize, buf);
  265. else
  266. #endif
  267. {
  268. #ifdef notyet
  269. if (elfhdr.e_type == ET_EXEC) {
  270. dophn_exec(fd, elfhdr.e_phoff[1],
  271. elfhdr.e_phnum,
  272. elfhdr.e_phentsize, buf);
  273. }
  274. #endif
  275. doshn(fd, elfhdr.e_shoff[1],
  276. elfhdr.e_shnum,
  277. elfhdr.e_shentsize, buf);
  278. }
  279. }
  280. return;
  281. }
  282. }
  283. #endif