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 struct section *find_section_by_name(struct elf *elf, const char *name) 41 { 42 struct section *sec; 43 44 list_for_each_entry(sec, &elf->sections, list) 45 if (!strcmp(sec->name, name)) 46 return sec; 47 48 return NULL; 49 } 50 51 static struct section *find_section_by_index(struct elf *elf, 52 unsigned int idx) 53 { 54 struct section *sec; 55 56 list_for_each_entry(sec, &elf->sections, list) 57 if (sec->idx == idx) 58 return sec; 59 60 return NULL; 61 } 62 63 static struct symbol *find_symbol_by_index(struct elf *elf, unsigned int idx) 64 { 65 struct section *sec; 66 struct symbol *sym; 67 68 list_for_each_entry(sec, &elf->sections, list) 69 hash_for_each_possible(sec->symbol_hash, sym, hash, idx) 70 if (sym->idx == idx) 71 return sym; 72 73 return NULL; 74 } 75 76 struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset) 77 { 78 struct symbol *sym; 79 80 list_for_each_entry(sym, &sec->symbol_list, list) 81 if (sym->type != STT_SECTION && 82 sym->offset == offset) 83 return sym; 84 85 return NULL; 86 } 87 88 struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset, 89 unsigned int len) 90 { 91 struct rela *rela; 92 unsigned long o; 93 94 if (!sec->rela) 95 return NULL; 96 97 for (o = offset; o < offset + len; o++) 98 hash_for_each_possible(sec->rela->rela_hash, rela, hash, o) 99 if (rela->offset == o) 100 return rela; 101 102 return NULL; 103 } 104 105 struct rela *find_rela_by_dest(struct section *sec, unsigned long offset) 106 { 107 return find_rela_by_dest_range(sec, offset, 1); 108 } 109 110 struct symbol *find_containing_func(struct section *sec, unsigned long offset) 111 { 112 struct symbol *func; 113 114 list_for_each_entry(func, &sec->symbol_list, list) 115 if (func->type == STT_FUNC && offset >= func->offset && 116 offset < func->offset + func->len) 117 return func; 118 119 return NULL; 120 } 121 122 static int read_sections(struct elf *elf) 123 { 124 Elf_Scn *s = NULL; 125 struct section *sec; 126 size_t shstrndx, sections_nr; 127 int i; 128 129 if (elf_getshdrnum(elf->elf, §ions_nr)) { 130 perror("elf_getshdrnum"); 131 return -1; 132 } 133 134 if (elf_getshdrstrndx(elf->elf, &shstrndx)) { 135 perror("elf_getshdrstrndx"); 136 return -1; 137 } 138 139 for (i = 0; i < sections_nr; i++) { 140 sec = malloc(sizeof(*sec)); 141 if (!sec) { 142 perror("malloc"); 143 return -1; 144 } 145 memset(sec, 0, sizeof(*sec)); 146 147 INIT_LIST_HEAD(&sec->symbol_list); 148 INIT_LIST_HEAD(&sec->rela_list); 149 hash_init(sec->rela_hash); 150 hash_init(sec->symbol_hash); 151 152 list_add_tail(&sec->list, &elf->sections); 153 154 s = elf_getscn(elf->elf, i); 155 if (!s) { 156 perror("elf_getscn"); 157 return -1; 158 } 159 160 sec->idx = elf_ndxscn(s); 161 162 if (!gelf_getshdr(s, &sec->sh)) { 163 perror("gelf_getshdr"); 164 return -1; 165 } 166 167 sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name); 168 if (!sec->name) { 169 perror("elf_strptr"); 170 return -1; 171 } 172 173 sec->elf_data = elf_getdata(s, NULL); 174 if (!sec->elf_data) { 175 perror("elf_getdata"); 176 return -1; 177 } 178 179 if (sec->elf_data->d_off != 0 || 180 sec->elf_data->d_size != sec->sh.sh_size) { 181 WARN("unexpected data attributes for %s", sec->name); 182 return -1; 183 } 184 185 sec->data = (unsigned long)sec->elf_data->d_buf; 186 sec->len = sec->elf_data->d_size; 187 } 188 189 /* sanity check, one more call to elf_nextscn() should return NULL */ 190 if (elf_nextscn(elf->elf, s)) { 191 WARN("section entry mismatch"); 192 return -1; 193 } 194 195 return 0; 196 } 197 198 static int read_symbols(struct elf *elf) 199 { 200 struct section *symtab; 201 struct symbol *sym; 202 struct list_head *entry, *tmp; 203 int symbols_nr, i; 204 205 symtab = find_section_by_name(elf, ".symtab"); 206 if (!symtab) { 207 WARN("missing symbol table"); 208 return -1; 209 } 210 211 symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize; 212 213 for (i = 0; i < symbols_nr; i++) { 214 sym = malloc(sizeof(*sym)); 215 if (!sym) { 216 perror("malloc"); 217 return -1; 218 } 219 memset(sym, 0, sizeof(*sym)); 220 221 sym->idx = i; 222 223 if (!gelf_getsym(symtab->elf_data, i, &sym->sym)) { 224 perror("gelf_getsym"); 225 goto err; 226 } 227 228 sym->name = elf_strptr(elf->elf, symtab->sh.sh_link, 229 sym->sym.st_name); 230 if (!sym->name) { 231 perror("elf_strptr"); 232 goto err; 233 } 234 235 sym->type = GELF_ST_TYPE(sym->sym.st_info); 236 sym->bind = GELF_ST_BIND(sym->sym.st_info); 237 238 if (sym->sym.st_shndx > SHN_UNDEF && 239 sym->sym.st_shndx < SHN_LORESERVE) { 240 sym->sec = find_section_by_index(elf, 241 sym->sym.st_shndx); 242 if (!sym->sec) { 243 WARN("couldn't find section for symbol %s", 244 sym->name); 245 goto err; 246 } 247 if (sym->type == STT_SECTION) { 248 sym->name = sym->sec->name; 249 sym->sec->sym = sym; 250 } 251 } else 252 sym->sec = find_section_by_index(elf, 0); 253 254 sym->offset = sym->sym.st_value; 255 sym->len = sym->sym.st_size; 256 257 /* sorted insert into a per-section list */ 258 entry = &sym->sec->symbol_list; 259 list_for_each_prev(tmp, &sym->sec->symbol_list) { 260 struct symbol *s; 261 262 s = list_entry(tmp, struct symbol, list); 263 264 if (sym->offset > s->offset) { 265 entry = tmp; 266 break; 267 } 268 269 if (sym->offset == s->offset && sym->len >= s->len) { 270 entry = tmp; 271 break; 272 } 273 } 274 list_add(&sym->list, entry); 275 hash_add(sym->sec->symbol_hash, &sym->hash, sym->idx); 276 } 277 278 return 0; 279 280 err: 281 free(sym); 282 return -1; 283 } 284 285 static int read_relas(struct elf *elf) 286 { 287 struct section *sec; 288 struct rela *rela; 289 int i; 290 unsigned int symndx; 291 292 list_for_each_entry(sec, &elf->sections, list) { 293 if (sec->sh.sh_type != SHT_RELA) 294 continue; 295 296 sec->base = find_section_by_name(elf, sec->name + 5); 297 if (!sec->base) { 298 WARN("can't find base section for rela section %s", 299 sec->name); 300 return -1; 301 } 302 303 sec->base->rela = sec; 304 305 for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) { 306 rela = malloc(sizeof(*rela)); 307 if (!rela) { 308 perror("malloc"); 309 return -1; 310 } 311 memset(rela, 0, sizeof(*rela)); 312 313 if (!gelf_getrela(sec->elf_data, i, &rela->rela)) { 314 perror("gelf_getrela"); 315 return -1; 316 } 317 318 rela->type = GELF_R_TYPE(rela->rela.r_info); 319 rela->addend = rela->rela.r_addend; 320 rela->offset = rela->rela.r_offset; 321 symndx = GELF_R_SYM(rela->rela.r_info); 322 rela->sym = find_symbol_by_index(elf, symndx); 323 if (!rela->sym) { 324 WARN("can't find rela entry symbol %d for %s", 325 symndx, sec->name); 326 return -1; 327 } 328 329 list_add_tail(&rela->list, &sec->rela_list); 330 hash_add(sec->rela_hash, &rela->hash, rela->offset); 331 332 } 333 } 334 335 return 0; 336 } 337 338 struct elf *elf_open(const char *name) 339 { 340 struct elf *elf; 341 342 elf_version(EV_CURRENT); 343 344 elf = malloc(sizeof(*elf)); 345 if (!elf) { 346 perror("malloc"); 347 return NULL; 348 } 349 memset(elf, 0, sizeof(*elf)); 350 351 INIT_LIST_HEAD(&elf->sections); 352 353 elf->name = strdup(name); 354 if (!elf->name) { 355 perror("strdup"); 356 goto err; 357 } 358 359 elf->fd = open(name, O_RDONLY); 360 if (elf->fd == -1) { 361 perror("open"); 362 goto err; 363 } 364 365 elf->elf = elf_begin(elf->fd, ELF_C_READ_MMAP, NULL); 366 if (!elf->elf) { 367 perror("elf_begin"); 368 goto err; 369 } 370 371 if (!gelf_getehdr(elf->elf, &elf->ehdr)) { 372 perror("gelf_getehdr"); 373 goto err; 374 } 375 376 if (read_sections(elf)) 377 goto err; 378 379 if (read_symbols(elf)) 380 goto err; 381 382 if (read_relas(elf)) 383 goto err; 384 385 return elf; 386 387 err: 388 elf_close(elf); 389 return NULL; 390 } 391 392 void elf_close(struct elf *elf) 393 { 394 struct section *sec, *tmpsec; 395 struct symbol *sym, *tmpsym; 396 struct rela *rela, *tmprela; 397 398 list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) { 399 list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) { 400 list_del(&sym->list); 401 hash_del(&sym->hash); 402 free(sym); 403 } 404 list_for_each_entry_safe(rela, tmprela, &sec->rela_list, list) { 405 list_del(&rela->list); 406 hash_del(&rela->hash); 407 free(rela); 408 } 409 list_del(&sec->list); 410 free(sec); 411 } 412 if (elf->name) 413 free(elf->name); 414 if (elf->fd > 0) 415 close(elf->fd); 416 if (elf->elf) 417 elf_end(elf->elf); 418 free(elf); 419 } 420