elf-parse.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. #include <sys/types.h>
  2. #include <sys/mman.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <stdbool.h>
  8. #include <string.h>
  9. #include <unistd.h>
  10. #include <errno.h>
  11. #include "elf-parse.h"
  12. struct elf_funcs elf_parser;
  13. /*
  14. * Get the whole file as a programming convenience in order to avoid
  15. * malloc+lseek+read+free of many pieces. If successful, then mmap
  16. * avoids copying unused pieces; else just read the whole file.
  17. * Open for both read and write.
  18. */
  19. static void *map_file(char const *fname, size_t *size)
  20. {
  21. int fd;
  22. struct stat sb;
  23. void *addr = NULL;
  24. fd = open(fname, O_RDWR);
  25. if (fd < 0) {
  26. perror(fname);
  27. return NULL;
  28. }
  29. if (fstat(fd, &sb) < 0) {
  30. perror(fname);
  31. goto out;
  32. }
  33. if (!S_ISREG(sb.st_mode)) {
  34. fprintf(stderr, "not a regular file: %s\n", fname);
  35. goto out;
  36. }
  37. addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  38. if (addr == MAP_FAILED) {
  39. fprintf(stderr, "Could not mmap file: %s\n", fname);
  40. goto out;
  41. }
  42. *size = sb.st_size;
  43. out:
  44. close(fd);
  45. return addr;
  46. }
  47. static int elf_parse(const char *fname, void *addr, uint32_t types)
  48. {
  49. Elf_Ehdr *ehdr = addr;
  50. uint16_t type;
  51. switch (ehdr->e32.e_ident[EI_DATA]) {
  52. case ELFDATA2LSB:
  53. elf_parser.r = rle;
  54. elf_parser.r2 = r2le;
  55. elf_parser.r8 = r8le;
  56. elf_parser.w = wle;
  57. elf_parser.w8 = w8le;
  58. break;
  59. case ELFDATA2MSB:
  60. elf_parser.r = rbe;
  61. elf_parser.r2 = r2be;
  62. elf_parser.r8 = r8be;
  63. elf_parser.w = wbe;
  64. elf_parser.w8 = w8be;
  65. break;
  66. default:
  67. fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
  68. ehdr->e32.e_ident[EI_DATA], fname);
  69. return -1;
  70. }
  71. if (memcmp(ELFMAG, ehdr->e32.e_ident, SELFMAG) != 0 ||
  72. ehdr->e32.e_ident[EI_VERSION] != EV_CURRENT) {
  73. fprintf(stderr, "unrecognized ELF file %s\n", fname);
  74. return -1;
  75. }
  76. type = elf_parser.r2(&ehdr->e32.e_type);
  77. if (!((1 << type) & types)) {
  78. fprintf(stderr, "Invalid ELF type file %s\n", fname);
  79. return -1;
  80. }
  81. switch (ehdr->e32.e_ident[EI_CLASS]) {
  82. case ELFCLASS32: {
  83. elf_parser.ehdr_shoff = ehdr32_shoff;
  84. elf_parser.ehdr_shentsize = ehdr32_shentsize;
  85. elf_parser.ehdr_shstrndx = ehdr32_shstrndx;
  86. elf_parser.ehdr_shnum = ehdr32_shnum;
  87. elf_parser.shdr_addr = shdr32_addr;
  88. elf_parser.shdr_offset = shdr32_offset;
  89. elf_parser.shdr_link = shdr32_link;
  90. elf_parser.shdr_size = shdr32_size;
  91. elf_parser.shdr_name = shdr32_name;
  92. elf_parser.shdr_type = shdr32_type;
  93. elf_parser.shdr_entsize = shdr32_entsize;
  94. elf_parser.sym_type = sym32_type;
  95. elf_parser.sym_name = sym32_name;
  96. elf_parser.sym_value = sym32_value;
  97. elf_parser.sym_shndx = sym32_shndx;
  98. elf_parser.rela_offset = rela32_offset;
  99. elf_parser.rela_info = rela32_info;
  100. elf_parser.rela_addend = rela32_addend;
  101. elf_parser.rela_write_addend = rela32_write_addend;
  102. if (elf_parser.r2(&ehdr->e32.e_ehsize) != sizeof(Elf32_Ehdr) ||
  103. elf_parser.r2(&ehdr->e32.e_shentsize) != sizeof(Elf32_Shdr)) {
  104. fprintf(stderr,
  105. "unrecognized ET_EXEC/ET_DYN file: %s\n", fname);
  106. return -1;
  107. }
  108. }
  109. break;
  110. case ELFCLASS64: {
  111. elf_parser.ehdr_shoff = ehdr64_shoff;
  112. elf_parser.ehdr_shentsize = ehdr64_shentsize;
  113. elf_parser.ehdr_shstrndx = ehdr64_shstrndx;
  114. elf_parser.ehdr_shnum = ehdr64_shnum;
  115. elf_parser.shdr_addr = shdr64_addr;
  116. elf_parser.shdr_offset = shdr64_offset;
  117. elf_parser.shdr_link = shdr64_link;
  118. elf_parser.shdr_size = shdr64_size;
  119. elf_parser.shdr_name = shdr64_name;
  120. elf_parser.shdr_type = shdr64_type;
  121. elf_parser.shdr_entsize = shdr64_entsize;
  122. elf_parser.sym_type = sym64_type;
  123. elf_parser.sym_name = sym64_name;
  124. elf_parser.sym_value = sym64_value;
  125. elf_parser.sym_shndx = sym64_shndx;
  126. elf_parser.rela_offset = rela64_offset;
  127. elf_parser.rela_info = rela64_info;
  128. elf_parser.rela_addend = rela64_addend;
  129. elf_parser.rela_write_addend = rela64_write_addend;
  130. if (elf_parser.r2(&ehdr->e64.e_ehsize) != sizeof(Elf64_Ehdr) ||
  131. elf_parser.r2(&ehdr->e64.e_shentsize) != sizeof(Elf64_Shdr)) {
  132. fprintf(stderr,
  133. "unrecognized ET_EXEC/ET_DYN file: %s\n",
  134. fname);
  135. return -1;
  136. }
  137. }
  138. break;
  139. default:
  140. fprintf(stderr, "unrecognized ELF class %d %s\n",
  141. ehdr->e32.e_ident[EI_CLASS], fname);
  142. return -1;
  143. }
  144. return 0;
  145. }
  146. int elf_map_machine(void *addr)
  147. {
  148. Elf_Ehdr *ehdr = addr;
  149. return elf_parser.r2(&ehdr->e32.e_machine);
  150. }
  151. int elf_map_long_size(void *addr)
  152. {
  153. Elf_Ehdr *ehdr = addr;
  154. return ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
  155. }
  156. void *elf_map(char const *fname, size_t *size, uint32_t types)
  157. {
  158. void *addr;
  159. int ret;
  160. addr = map_file(fname, size);
  161. if (!addr)
  162. return NULL;
  163. ret = elf_parse(fname, addr, types);
  164. if (ret < 0) {
  165. elf_unmap(addr, *size);
  166. return NULL;
  167. }
  168. return addr;
  169. }
  170. void elf_unmap(void *addr, size_t size)
  171. {
  172. munmap(addr, size);
  173. }