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 if writable is true, otherwise open 21 * read-only. 22 */ 23 static void *map_file(char const *fname, size_t *size, bool writable) 24 { 25 int fd, prot = PROT_READ, flags = MAP_PRIVATE; 26 struct stat sb; 27 void *addr = NULL; 28 29 if (writable) { 30 prot |= PROT_WRITE; 31 flags = MAP_SHARED; 32 } 33 34 fd = open(fname, writable ? O_RDWR : O_RDONLY); 35 if (fd < 0) { 36 perror(fname); 37 return NULL; 38 } 39 if (fstat(fd, &sb) < 0) { 40 perror(fname); 41 goto out; 42 } 43 if (!S_ISREG(sb.st_mode)) { 44 fprintf(stderr, "not a regular file: %s\n", fname); 45 goto out; 46 } 47 48 addr = mmap(0, sb.st_size, prot, flags, fd, 0); 49 if (addr == MAP_FAILED) { 50 fprintf(stderr, "Could not mmap file: %s\n", fname); 51 goto out; 52 } 53 54 *size = sb.st_size; 55 56 out: 57 close(fd); 58 return addr; 59 } 60 61 static int elf_parse(const char *fname, void *addr, uint32_t types) 62 { 63 Elf_Ehdr *ehdr = addr; 64 uint16_t type; 65 66 if (memcmp(ELFMAG, ehdr->e32.e_ident, SELFMAG) != 0 || 67 ehdr->e32.e_ident[EI_VERSION] != EV_CURRENT) { 68 fprintf(stderr, "unrecognized ELF file %s\n", fname); 69 return -1; 70 } 71 72 switch (ehdr->e32.e_ident[EI_DATA]) { 73 case ELFDATA2LSB: 74 elf_parser.r = rle; 75 elf_parser.r2 = r2le; 76 elf_parser.r8 = r8le; 77 elf_parser.w = wle; 78 elf_parser.w8 = w8le; 79 break; 80 case ELFDATA2MSB: 81 elf_parser.r = rbe; 82 elf_parser.r2 = r2be; 83 elf_parser.r8 = r8be; 84 elf_parser.w = wbe; 85 elf_parser.w8 = w8be; 86 break; 87 default: 88 fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", 89 ehdr->e32.e_ident[EI_DATA], fname); 90 return -1; 91 } 92 93 type = elf_parser.r2(&ehdr->e32.e_type); 94 if (!((1 << type) & types)) { 95 fprintf(stderr, "Invalid ELF type file %s\n", fname); 96 return -1; 97 } 98 99 switch (ehdr->e32.e_ident[EI_CLASS]) { 100 case ELFCLASS32: { 101 elf_parser.ehdr_shoff = ehdr32_shoff; 102 elf_parser.ehdr_shentsize = ehdr32_shentsize; 103 elf_parser.ehdr_shstrndx = ehdr32_shstrndx; 104 elf_parser.ehdr_shnum = ehdr32_shnum; 105 elf_parser.shdr_addr = shdr32_addr; 106 elf_parser.shdr_offset = shdr32_offset; 107 elf_parser.shdr_link = shdr32_link; 108 elf_parser.shdr_size = shdr32_size; 109 elf_parser.shdr_name = shdr32_name; 110 elf_parser.shdr_type = shdr32_type; 111 elf_parser.shdr_entsize = shdr32_entsize; 112 elf_parser.shdr_flags = shdr32_flags; 113 elf_parser.sym_type = sym32_type; 114 elf_parser.sym_bind = sym32_bind; 115 elf_parser.sym_name = sym32_name; 116 elf_parser.sym_value = sym32_value; 117 elf_parser.sym_shndx = sym32_shndx; 118 elf_parser.rela_offset = rela32_offset; 119 elf_parser.rela_info = rela32_info; 120 elf_parser.rela_addend = rela32_addend; 121 elf_parser.rela_write_addend = rela32_write_addend; 122 123 if (elf_parser.r2(&ehdr->e32.e_ehsize) != sizeof(Elf32_Ehdr) || 124 elf_parser.r2(&ehdr->e32.e_shentsize) != sizeof(Elf32_Shdr)) { 125 fprintf(stderr, 126 "unrecognized ET_EXEC/ET_DYN file: %s\n", fname); 127 return -1; 128 } 129 130 } 131 break; 132 case ELFCLASS64: { 133 elf_parser.ehdr_shoff = ehdr64_shoff; 134 elf_parser.ehdr_shentsize = ehdr64_shentsize; 135 elf_parser.ehdr_shstrndx = ehdr64_shstrndx; 136 elf_parser.ehdr_shnum = ehdr64_shnum; 137 elf_parser.shdr_addr = shdr64_addr; 138 elf_parser.shdr_offset = shdr64_offset; 139 elf_parser.shdr_link = shdr64_link; 140 elf_parser.shdr_size = shdr64_size; 141 elf_parser.shdr_name = shdr64_name; 142 elf_parser.shdr_type = shdr64_type; 143 elf_parser.shdr_entsize = shdr64_entsize; 144 elf_parser.shdr_flags = shdr64_flags; 145 elf_parser.sym_type = sym64_type; 146 elf_parser.sym_bind = sym64_bind; 147 elf_parser.sym_name = sym64_name; 148 elf_parser.sym_value = sym64_value; 149 elf_parser.sym_shndx = sym64_shndx; 150 elf_parser.rela_offset = rela64_offset; 151 elf_parser.rela_info = rela64_info; 152 elf_parser.rela_addend = rela64_addend; 153 elf_parser.rela_write_addend = rela64_write_addend; 154 155 if (elf_parser.r2(&ehdr->e64.e_ehsize) != sizeof(Elf64_Ehdr) || 156 elf_parser.r2(&ehdr->e64.e_shentsize) != sizeof(Elf64_Shdr)) { 157 fprintf(stderr, 158 "unrecognized ET_EXEC/ET_DYN file: %s\n", 159 fname); 160 return -1; 161 } 162 163 } 164 break; 165 default: 166 fprintf(stderr, "unrecognized ELF class %d %s\n", 167 ehdr->e32.e_ident[EI_CLASS], fname); 168 return -1; 169 } 170 return 0; 171 } 172 173 int elf_map_machine(void *addr) 174 { 175 Elf_Ehdr *ehdr = addr; 176 177 return elf_parser.r2(&ehdr->e32.e_machine); 178 } 179 180 int elf_map_long_size(void *addr) 181 { 182 Elf_Ehdr *ehdr = addr; 183 184 return ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; 185 } 186 187 static void *__elf_map(char const *fname, size_t *size, uint32_t types, 188 bool writable) 189 { 190 void *addr; 191 int ret; 192 193 addr = map_file(fname, size, writable); 194 if (!addr) 195 return NULL; 196 197 ret = elf_parse(fname, addr, types); 198 if (ret < 0) { 199 elf_unmap(addr, *size); 200 return NULL; 201 } 202 203 return addr; 204 } 205 206 void *elf_map(char const *fname, size_t *size, uint32_t types) 207 { 208 return __elf_map(fname, size, types, true); 209 } 210 211 /* For tools that only read the file. */ 212 void *elf_map_ro(char const *fname, size_t *size, uint32_t types) 213 { 214 return __elf_map(fname, size, types, false); 215 } 216 217 void elf_unmap(void *addr, size_t size) 218 { 219 munmap(addr, size); 220 } 221 222 /* 223 * Open an ELF file and map it read-only, locating its section headers, section 224 * names and symbol table which are populated in the elf out parameter. 225 * 226 * Returns 0 on success, otherwise -1. 227 */ 228 int elf_open_ro(char const *fname, uint32_t types, struct elf_file *elf) 229 { 230 Elf_Ehdr *ehdr; 231 Elf_Shdr *first; 232 unsigned int shstrndx, i; 233 234 memset(elf, 0, sizeof(*elf)); 235 elf->base = elf_map_ro(fname, &elf->size, types); 236 if (!elf->base) 237 return -1; 238 239 ehdr = elf->base; 240 elf->shdrs = (const char *)elf->base + ehdr_shoff(ehdr); 241 elf->shentsize = ehdr_shentsize(ehdr); 242 first = elf_section(elf, 0); 243 244 /* A count or index too large for the header lives in section 0. */ 245 elf->shnum = ehdr_shnum(ehdr); 246 if (elf->shnum == SHN_UNDEF) 247 elf->shnum = shdr_size(first); 248 shstrndx = ehdr_shstrndx(ehdr); 249 if (shstrndx == SHN_XINDEX) 250 shstrndx = shdr_link(first); 251 elf->shstrtab = (const char *)elf->base + 252 shdr_offset(elf_section(elf, shstrndx)); 253 254 for (i = 0; i < elf->shnum && !elf->symtab; i++) 255 if (shdr_type(elf_section(elf, i)) == SHT_SYMTAB) 256 elf->symtab = elf_section(elf, i); 257 258 if (!elf->symtab) { 259 fprintf(stderr, "%s: no symbol table\n", fname); 260 elf_close(elf); 261 return -1; 262 } 263 264 elf->strtab = (const char *)elf->base + 265 shdr_offset(elf_section(elf, shdr_link(elf->symtab))); 266 elf->nr_syms = shdr_size(elf->symtab) / shdr_entsize(elf->symtab); 267 268 return 0; 269 } 270 271 void elf_close(struct elf_file *elf) 272 { 273 elf_unmap(elf->base, elf->size); 274 elf->base = NULL; 275 } 276