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