1 /* 2 * elf.c - ELF access library 3 * 4 * Adapted from kpatch (https://github.com/dynup/kpatch): 5 * Copyright (C) 2013-2015 Josh Poimboeuf <jpoimboe@redhat.com> 6 * Copyright (C) 2014 Seth Jennings <sjenning@redhat.com> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * as published by the Free Software Foundation; either version 2 11 * of the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, see <http://www.gnu.org/licenses/>. 20 */ 21 22 #include <sys/types.h> 23 #include <sys/stat.h> 24 #include <fcntl.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <unistd.h> 29 30 #include "elf.h" 31 #include "warn.h" 32 33 /* 34 * Fallback for systems without this "read, mmaping if possible" cmd. 35 */ 36 #ifndef ELF_C_READ_MMAP 37 #define ELF_C_READ_MMAP ELF_C_READ 38 #endif 39 40 #define WARN_ELF(format, ...) \ 41 WARN(format ": %s", ##__VA_ARGS__, elf_errmsg(-1)) 42 43 struct section *find_section_by_name(struct elf *elf, const char *name) 44 { 45 struct section *sec; 46 47 list_for_each_entry(sec, &elf->sections, list) 48 if (!strcmp(sec->name, name)) 49 return sec; 50 51 return NULL; 52 } 53 54 static struct section *find_section_by_index(struct elf *elf, 55 unsigned int idx) 56 { 57 struct section *sec; 58 59 list_for_each_entry(sec, &elf->sections, list) 60 if (sec->idx == idx) 61 return sec; 62 63 return NULL; 64 } 65 66 static struct symbol *find_symbol_by_index(struct elf *elf, unsigned int idx) 67 { 68 struct section *sec; 69 struct symbol *sym; 70 71 list_for_each_entry(sec, &elf->sections, list) 72 hash_for_each_possible(sec->symbol_hash, sym, hash, idx) 73 if (sym->idx == idx) 74 return sym; 75 76 return NULL; 77 } 78 79 struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset) 80 { 81 struct symbol *sym; 82 83 list_for_each_entry(sym, &sec->symbol_list, list) 84 if (sym->type != STT_SECTION && 85 sym->offset == offset) 86 return sym; 87 88 return NULL; 89 } 90 91 struct symbol *find_symbol_containing(struct section *sec, unsigned long offset) 92 { 93 struct symbol *sym; 94 95 list_for_each_entry(sym, &sec->symbol_list, list) 96 if (sym->type != STT_SECTION && 97 offset >= sym->offset && offset < sym->offset + sym->len) 98 return sym; 99 100 return NULL; 101 } 102 103 struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset, 104 unsigned int len) 105 { 106 struct rela *rela; 107 unsigned long o; 108 109 if (!sec->rela) 110 return NULL; 111 112 for (o = offset; o < offset + len; o++) 113 hash_for_each_possible(sec->rela->rela_hash, rela, hash, o) 114 if (rela->offset == o) 115 return rela; 116 117 return NULL; 118 } 119 120 struct rela *find_rela_by_dest(struct section *sec, unsigned long offset) 121 { 122 return find_rela_by_dest_range(sec, offset, 1); 123 } 124 125 struct symbol *find_containing_func(struct section *sec, unsigned long offset) 126 { 127 struct symbol *func; 128 129 list_for_each_entry(func, &sec->symbol_list, list) 130 if (func->type == STT_FUNC && offset >= func->offset && 131 offset < func->offset + func->len) 132 return func; 133 134 return NULL; 135 } 136 137 static int read_sections(struct elf *elf) 138 { 139 Elf_Scn *s = NULL; 140 struct section *sec; 141 size_t shstrndx, sections_nr; 142 int i; 143 144 if (elf_getshdrnum(elf->elf, §ions_nr)) { 145 WARN_ELF("elf_getshdrnum"); 146 return -1; 147 } 148 149 if (elf_getshdrstrndx(elf->elf, &shstrndx)) { 150 WARN_ELF("elf_getshdrstrndx"); 151 return -1; 152 } 153 154 for (i = 0; i < sections_nr; i++) { 155 sec = malloc(sizeof(*sec)); 156 if (!sec) { 157 perror("malloc"); 158 return -1; 159 } 160 memset(sec, 0, sizeof(*sec)); 161 162 INIT_LIST_HEAD(&sec->symbol_list); 163 INIT_LIST_HEAD(&sec->rela_list); 164 hash_init(sec->rela_hash); 165 hash_init(sec->symbol_hash); 166 167 list_add_tail(&sec->list, &elf->sections); 168 169 s = elf_getscn(elf->elf, i); 170 if (!s) { 171 WARN_ELF("elf_getscn"); 172 return -1; 173 } 174 175 sec->idx = elf_ndxscn(s); 176 177 if (!gelf_getshdr(s, &sec->sh)) { 178 WARN_ELF("gelf_getshdr"); 179 return -1; 180 } 181 182 sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name); 183 if (!sec->name) { 184 WARN_ELF("elf_strptr"); 185 return -1; 186 } 187 188 sec->data = elf_getdata(s, NULL); 189 if (!sec->data) { 190 WARN_ELF("elf_getdata"); 191 return -1; 192 } 193 194 if (sec->data->d_off != 0 || 195 sec->data->d_size != sec->sh.sh_size) { 196 WARN("unexpected data attributes for %s", sec->name); 197 return -1; 198 } 199 200 sec->len = sec->data->d_size; 201 } 202 203 /* sanity check, one more call to elf_nextscn() should return NULL */ 204 if (elf_nextscn(elf->elf, s)) { 205 WARN("section entry mismatch"); 206 return -1; 207 } 208 209 return 0; 210 } 211 212 static int read_symbols(struct elf *elf) 213 { 214 struct section *symtab; 215 struct symbol *sym; 216 struct list_head *entry, *tmp; 217 int symbols_nr, i; 218 219 symtab = find_section_by_name(elf, ".symtab"); 220 if (!symtab) { 221 WARN("missing symbol table"); 222 return -1; 223 } 224 225 symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize; 226 227 for (i = 0; i < symbols_nr; i++) { 228 sym = malloc(sizeof(*sym)); 229 if (!sym) { 230 perror("malloc"); 231 return -1; 232 } 233 memset(sym, 0, sizeof(*sym)); 234 235 sym->idx = i; 236 237 if (!gelf_getsym(symtab->data, i, &sym->sym)) { 238 WARN_ELF("gelf_getsym"); 239 goto err; 240 } 241 242 sym->name = elf_strptr(elf->elf, symtab->sh.sh_link, 243 sym->sym.st_name); 244 if (!sym->name) { 245 WARN_ELF("elf_strptr"); 246 goto err; 247 } 248 249 sym->type = GELF_ST_TYPE(sym->sym.st_info); 250 sym->bind = GELF_ST_BIND(sym->sym.st_info); 251 252 if (sym->sym.st_shndx > SHN_UNDEF && 253 sym->sym.st_shndx < SHN_LORESERVE) { 254 sym->sec = find_section_by_index(elf, 255 sym->sym.st_shndx); 256 if (!sym->sec) { 257 WARN("couldn't find section for symbol %s", 258 sym->name); 259 goto err; 260 } 261 if (sym->type == STT_SECTION) { 262 sym->name = sym->sec->name; 263 sym->sec->sym = sym; 264 } 265 } else 266 sym->sec = find_section_by_index(elf, 0); 267 268 sym->offset = sym->sym.st_value; 269 sym->len = sym->sym.st_size; 270 271 /* sorted insert into a per-section list */ 272 entry = &sym->sec->symbol_list; 273 list_for_each_prev(tmp, &sym->sec->symbol_list) { 274 struct symbol *s; 275 276 s = list_entry(tmp, struct symbol, list); 277 278 if (sym->offset > s->offset) { 279 entry = tmp; 280 break; 281 } 282 283 if (sym->offset == s->offset && sym->len >= s->len) { 284 entry = tmp; 285 break; 286 } 287 } 288 list_add(&sym->list, entry); 289 hash_add(sym->sec->symbol_hash, &sym->hash, sym->idx); 290 } 291 292 return 0; 293 294 err: 295 free(sym); 296 return -1; 297 } 298 299 static int read_relas(struct elf *elf) 300 { 301 struct section *sec; 302 struct rela *rela; 303 int i; 304 unsigned int symndx; 305 306 list_for_each_entry(sec, &elf->sections, list) { 307 if (sec->sh.sh_type != SHT_RELA) 308 continue; 309 310 sec->base = find_section_by_name(elf, sec->name + 5); 311 if (!sec->base) { 312 WARN("can't find base section for rela section %s", 313 sec->name); 314 return -1; 315 } 316 317 sec->base->rela = sec; 318 319 for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) { 320 rela = malloc(sizeof(*rela)); 321 if (!rela) { 322 perror("malloc"); 323 return -1; 324 } 325 memset(rela, 0, sizeof(*rela)); 326 327 if (!gelf_getrela(sec->data, i, &rela->rela)) { 328 WARN_ELF("gelf_getrela"); 329 return -1; 330 } 331 332 rela->type = GELF_R_TYPE(rela->rela.r_info); 333 rela->addend = rela->rela.r_addend; 334 rela->offset = rela->rela.r_offset; 335 symndx = GELF_R_SYM(rela->rela.r_info); 336 rela->sym = find_symbol_by_index(elf, symndx); 337 if (!rela->sym) { 338 WARN("can't find rela entry symbol %d for %s", 339 symndx, sec->name); 340 return -1; 341 } 342 343 list_add_tail(&rela->list, &sec->rela_list); 344 hash_add(sec->rela_hash, &rela->hash, rela->offset); 345 346 } 347 } 348 349 return 0; 350 } 351 352 struct elf *elf_open(const char *name) 353 { 354 struct elf *elf; 355 356 elf_version(EV_CURRENT); 357 358 elf = malloc(sizeof(*elf)); 359 if (!elf) { 360 perror("malloc"); 361 return NULL; 362 } 363 memset(elf, 0, sizeof(*elf)); 364 365 INIT_LIST_HEAD(&elf->sections); 366 367 elf->fd = open(name, O_RDONLY); 368 if (elf->fd == -1) { 369 perror("open"); 370 goto err; 371 } 372 373 elf->elf = elf_begin(elf->fd, ELF_C_READ_MMAP, NULL); 374 if (!elf->elf) { 375 WARN_ELF("elf_begin"); 376 goto err; 377 } 378 379 if (!gelf_getehdr(elf->elf, &elf->ehdr)) { 380 WARN_ELF("gelf_getehdr"); 381 goto err; 382 } 383 384 if (read_sections(elf)) 385 goto err; 386 387 if (read_symbols(elf)) 388 goto err; 389 390 if (read_relas(elf)) 391 goto err; 392 393 return elf; 394 395 err: 396 elf_close(elf); 397 return NULL; 398 } 399 400 void elf_close(struct elf *elf) 401 { 402 struct section *sec, *tmpsec; 403 struct symbol *sym, *tmpsym; 404 struct rela *rela, *tmprela; 405 406 if (elf->elf) 407 elf_end(elf->elf); 408 409 if (elf->fd > 0) 410 close(elf->fd); 411 412 list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) { 413 list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) { 414 list_del(&sym->list); 415 hash_del(&sym->hash); 416 free(sym); 417 } 418 list_for_each_entry_safe(rela, tmprela, &sec->rela_list, list) { 419 list_del(&rela->list); 420 hash_del(&rela->hash); 421 free(rela); 422 } 423 list_del(&sec->list); 424 free(sec); 425 } 426 427 free(elf); 428 } 429