11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2442f04c3SJosh Poimboeuf /* 3442f04c3SJosh Poimboeuf * elf.c - ELF access library 4442f04c3SJosh Poimboeuf * 5442f04c3SJosh Poimboeuf * Adapted from kpatch (https://github.com/dynup/kpatch): 6442f04c3SJosh Poimboeuf * Copyright (C) 2013-2015 Josh Poimboeuf <jpoimboe@redhat.com> 7442f04c3SJosh Poimboeuf * Copyright (C) 2014 Seth Jennings <sjenning@redhat.com> 8442f04c3SJosh Poimboeuf */ 9442f04c3SJosh Poimboeuf 10442f04c3SJosh Poimboeuf #include <sys/types.h> 11442f04c3SJosh Poimboeuf #include <sys/stat.h> 12442f04c3SJosh Poimboeuf #include <fcntl.h> 13442f04c3SJosh Poimboeuf #include <stdio.h> 14442f04c3SJosh Poimboeuf #include <stdlib.h> 15442f04c3SJosh Poimboeuf #include <string.h> 16442f04c3SJosh Poimboeuf #include <unistd.h> 17385d11b1SJosh Poimboeuf #include <errno.h> 181e11f3fdSPeter Zijlstra #include "builtin.h" 19442f04c3SJosh Poimboeuf 20442f04c3SJosh Poimboeuf #include "elf.h" 21442f04c3SJosh Poimboeuf #include "warn.h" 22442f04c3SJosh Poimboeuf 2322566c16SArtem Savkov #define MAX_NAME_LEN 128 2422566c16SArtem Savkov 25ae358196SPeter Zijlstra static inline u32 str_hash(const char *str) 26ae358196SPeter Zijlstra { 27ae358196SPeter Zijlstra return jhash(str, strlen(str), 0); 28ae358196SPeter Zijlstra } 29ae358196SPeter Zijlstra 302a362eccSPeter Zijlstra static void rb_add(struct rb_root *tree, struct rb_node *node, 312a362eccSPeter Zijlstra int (*cmp)(struct rb_node *, const struct rb_node *)) 322a362eccSPeter Zijlstra { 332a362eccSPeter Zijlstra struct rb_node **link = &tree->rb_node; 342a362eccSPeter Zijlstra struct rb_node *parent = NULL; 352a362eccSPeter Zijlstra 362a362eccSPeter Zijlstra while (*link) { 372a362eccSPeter Zijlstra parent = *link; 382a362eccSPeter Zijlstra if (cmp(node, parent) < 0) 392a362eccSPeter Zijlstra link = &parent->rb_left; 402a362eccSPeter Zijlstra else 412a362eccSPeter Zijlstra link = &parent->rb_right; 422a362eccSPeter Zijlstra } 432a362eccSPeter Zijlstra 442a362eccSPeter Zijlstra rb_link_node(node, parent, link); 452a362eccSPeter Zijlstra rb_insert_color(node, tree); 462a362eccSPeter Zijlstra } 472a362eccSPeter Zijlstra 482a362eccSPeter Zijlstra static struct rb_node *rb_find_first(struct rb_root *tree, const void *key, 492a362eccSPeter Zijlstra int (*cmp)(const void *key, const struct rb_node *)) 502a362eccSPeter Zijlstra { 512a362eccSPeter Zijlstra struct rb_node *node = tree->rb_node; 522a362eccSPeter Zijlstra struct rb_node *match = NULL; 532a362eccSPeter Zijlstra 542a362eccSPeter Zijlstra while (node) { 552a362eccSPeter Zijlstra int c = cmp(key, node); 562a362eccSPeter Zijlstra if (c <= 0) { 572a362eccSPeter Zijlstra if (!c) 582a362eccSPeter Zijlstra match = node; 592a362eccSPeter Zijlstra node = node->rb_left; 602a362eccSPeter Zijlstra } else if (c > 0) { 612a362eccSPeter Zijlstra node = node->rb_right; 622a362eccSPeter Zijlstra } 632a362eccSPeter Zijlstra } 642a362eccSPeter Zijlstra 652a362eccSPeter Zijlstra return match; 662a362eccSPeter Zijlstra } 672a362eccSPeter Zijlstra 682a362eccSPeter Zijlstra static struct rb_node *rb_next_match(struct rb_node *node, const void *key, 692a362eccSPeter Zijlstra int (*cmp)(const void *key, const struct rb_node *)) 702a362eccSPeter Zijlstra { 712a362eccSPeter Zijlstra node = rb_next(node); 722a362eccSPeter Zijlstra if (node && cmp(key, node)) 732a362eccSPeter Zijlstra node = NULL; 742a362eccSPeter Zijlstra return node; 752a362eccSPeter Zijlstra } 762a362eccSPeter Zijlstra 772a362eccSPeter Zijlstra #define rb_for_each(tree, node, key, cmp) \ 782a362eccSPeter Zijlstra for ((node) = rb_find_first((tree), (key), (cmp)); \ 792a362eccSPeter Zijlstra (node); (node) = rb_next_match((node), (key), (cmp))) 802a362eccSPeter Zijlstra 812a362eccSPeter Zijlstra static int symbol_to_offset(struct rb_node *a, const struct rb_node *b) 822a362eccSPeter Zijlstra { 832a362eccSPeter Zijlstra struct symbol *sa = rb_entry(a, struct symbol, node); 842a362eccSPeter Zijlstra struct symbol *sb = rb_entry(b, struct symbol, node); 852a362eccSPeter Zijlstra 862a362eccSPeter Zijlstra if (sa->offset < sb->offset) 872a362eccSPeter Zijlstra return -1; 882a362eccSPeter Zijlstra if (sa->offset > sb->offset) 892a362eccSPeter Zijlstra return 1; 902a362eccSPeter Zijlstra 912a362eccSPeter Zijlstra if (sa->len < sb->len) 922a362eccSPeter Zijlstra return -1; 932a362eccSPeter Zijlstra if (sa->len > sb->len) 942a362eccSPeter Zijlstra return 1; 952a362eccSPeter Zijlstra 962a362eccSPeter Zijlstra sa->alias = sb; 972a362eccSPeter Zijlstra 982a362eccSPeter Zijlstra return 0; 992a362eccSPeter Zijlstra } 1002a362eccSPeter Zijlstra 1012a362eccSPeter Zijlstra static int symbol_by_offset(const void *key, const struct rb_node *node) 1022a362eccSPeter Zijlstra { 1032a362eccSPeter Zijlstra const struct symbol *s = rb_entry(node, struct symbol, node); 1042a362eccSPeter Zijlstra const unsigned long *o = key; 1052a362eccSPeter Zijlstra 1062a362eccSPeter Zijlstra if (*o < s->offset) 1072a362eccSPeter Zijlstra return -1; 1082a362eccSPeter Zijlstra if (*o > s->offset + s->len) 1092a362eccSPeter Zijlstra return 1; 1102a362eccSPeter Zijlstra 1112a362eccSPeter Zijlstra return 0; 1122a362eccSPeter Zijlstra } 1132a362eccSPeter Zijlstra 114442f04c3SJosh Poimboeuf struct section *find_section_by_name(struct elf *elf, const char *name) 115442f04c3SJosh Poimboeuf { 116442f04c3SJosh Poimboeuf struct section *sec; 117442f04c3SJosh Poimboeuf 118ae358196SPeter Zijlstra hash_for_each_possible(elf->section_name_hash, sec, name_hash, str_hash(name)) 119442f04c3SJosh Poimboeuf if (!strcmp(sec->name, name)) 120442f04c3SJosh Poimboeuf return sec; 121442f04c3SJosh Poimboeuf 122442f04c3SJosh Poimboeuf return NULL; 123442f04c3SJosh Poimboeuf } 124442f04c3SJosh Poimboeuf 125442f04c3SJosh Poimboeuf static struct section *find_section_by_index(struct elf *elf, 126442f04c3SJosh Poimboeuf unsigned int idx) 127442f04c3SJosh Poimboeuf { 128442f04c3SJosh Poimboeuf struct section *sec; 129442f04c3SJosh Poimboeuf 13053038996SPeter Zijlstra hash_for_each_possible(elf->section_hash, sec, hash, idx) 131442f04c3SJosh Poimboeuf if (sec->idx == idx) 132442f04c3SJosh Poimboeuf return sec; 133442f04c3SJosh Poimboeuf 134442f04c3SJosh Poimboeuf return NULL; 135442f04c3SJosh Poimboeuf } 136442f04c3SJosh Poimboeuf 137442f04c3SJosh Poimboeuf static struct symbol *find_symbol_by_index(struct elf *elf, unsigned int idx) 138442f04c3SJosh Poimboeuf { 139442f04c3SJosh Poimboeuf struct symbol *sym; 140442f04c3SJosh Poimboeuf 14165fb11a7SPeter Zijlstra hash_for_each_possible(elf->symbol_hash, sym, hash, idx) 142442f04c3SJosh Poimboeuf if (sym->idx == idx) 143442f04c3SJosh Poimboeuf return sym; 144442f04c3SJosh Poimboeuf 145442f04c3SJosh Poimboeuf return NULL; 146442f04c3SJosh Poimboeuf } 147442f04c3SJosh Poimboeuf 148442f04c3SJosh Poimboeuf struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset) 149442f04c3SJosh Poimboeuf { 1502a362eccSPeter Zijlstra struct rb_node *node; 151442f04c3SJosh Poimboeuf 1522a362eccSPeter Zijlstra rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) { 1532a362eccSPeter Zijlstra struct symbol *s = rb_entry(node, struct symbol, node); 1542a362eccSPeter Zijlstra 1552a362eccSPeter Zijlstra if (s->offset == offset && s->type != STT_SECTION) 1562a362eccSPeter Zijlstra return s; 1572a362eccSPeter Zijlstra } 1587acfe531SJosh Poimboeuf 1597acfe531SJosh Poimboeuf return NULL; 1607acfe531SJosh Poimboeuf } 1617acfe531SJosh Poimboeuf 1627acfe531SJosh Poimboeuf struct symbol *find_func_by_offset(struct section *sec, unsigned long offset) 1637acfe531SJosh Poimboeuf { 1642a362eccSPeter Zijlstra struct rb_node *node; 1657acfe531SJosh Poimboeuf 1662a362eccSPeter Zijlstra rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) { 1672a362eccSPeter Zijlstra struct symbol *s = rb_entry(node, struct symbol, node); 1682a362eccSPeter Zijlstra 1692a362eccSPeter Zijlstra if (s->offset == offset && s->type == STT_FUNC) 1702a362eccSPeter Zijlstra return s; 1712a362eccSPeter Zijlstra } 1722a362eccSPeter Zijlstra 1732a362eccSPeter Zijlstra return NULL; 1742a362eccSPeter Zijlstra } 1752a362eccSPeter Zijlstra 1762a362eccSPeter Zijlstra struct symbol *find_symbol_containing(struct section *sec, unsigned long offset) 1772a362eccSPeter Zijlstra { 1782a362eccSPeter Zijlstra struct rb_node *node; 1792a362eccSPeter Zijlstra 1802a362eccSPeter Zijlstra rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) { 1812a362eccSPeter Zijlstra struct symbol *s = rb_entry(node, struct symbol, node); 1822a362eccSPeter Zijlstra 1832a362eccSPeter Zijlstra if (s->type != STT_SECTION) 1842a362eccSPeter Zijlstra return s; 1852a362eccSPeter Zijlstra } 1862a362eccSPeter Zijlstra 1872a362eccSPeter Zijlstra return NULL; 1882a362eccSPeter Zijlstra } 1892a362eccSPeter Zijlstra 19053d20720SPeter Zijlstra struct symbol *find_func_containing(struct section *sec, unsigned long offset) 1912a362eccSPeter Zijlstra { 1922a362eccSPeter Zijlstra struct rb_node *node; 1932a362eccSPeter Zijlstra 1942a362eccSPeter Zijlstra rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) { 1952a362eccSPeter Zijlstra struct symbol *s = rb_entry(node, struct symbol, node); 1962a362eccSPeter Zijlstra 1972a362eccSPeter Zijlstra if (s->type == STT_FUNC) 1982a362eccSPeter Zijlstra return s; 1992a362eccSPeter Zijlstra } 200442f04c3SJosh Poimboeuf 201442f04c3SJosh Poimboeuf return NULL; 202442f04c3SJosh Poimboeuf } 203442f04c3SJosh Poimboeuf 20413810435SJosh Poimboeuf struct symbol *find_symbol_by_name(struct elf *elf, const char *name) 20513810435SJosh Poimboeuf { 20613810435SJosh Poimboeuf struct symbol *sym; 20713810435SJosh Poimboeuf 208cdb3d057SPeter Zijlstra hash_for_each_possible(elf->symbol_name_hash, sym, name_hash, str_hash(name)) 20913810435SJosh Poimboeuf if (!strcmp(sym->name, name)) 21013810435SJosh Poimboeuf return sym; 21113810435SJosh Poimboeuf 21213810435SJosh Poimboeuf return NULL; 21313810435SJosh Poimboeuf } 21413810435SJosh Poimboeuf 215442f04c3SJosh Poimboeuf struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset, 216442f04c3SJosh Poimboeuf unsigned int len) 217442f04c3SJosh Poimboeuf { 218442f04c3SJosh Poimboeuf struct rela *rela; 219042ba73fSJosh Poimboeuf unsigned long o; 220442f04c3SJosh Poimboeuf 221442f04c3SJosh Poimboeuf if (!sec->rela) 222442f04c3SJosh Poimboeuf return NULL; 223442f04c3SJosh Poimboeuf 224042ba73fSJosh Poimboeuf for (o = offset; o < offset + len; o++) 225042ba73fSJosh Poimboeuf hash_for_each_possible(sec->rela->rela_hash, rela, hash, o) 226042ba73fSJosh Poimboeuf if (rela->offset == o) 227442f04c3SJosh Poimboeuf return rela; 228442f04c3SJosh Poimboeuf 229442f04c3SJosh Poimboeuf return NULL; 230442f04c3SJosh Poimboeuf } 231442f04c3SJosh Poimboeuf 232442f04c3SJosh Poimboeuf struct rela *find_rela_by_dest(struct section *sec, unsigned long offset) 233442f04c3SJosh Poimboeuf { 234442f04c3SJosh Poimboeuf return find_rela_by_dest_range(sec, offset, 1); 235442f04c3SJosh Poimboeuf } 236442f04c3SJosh Poimboeuf 237442f04c3SJosh Poimboeuf static int read_sections(struct elf *elf) 238442f04c3SJosh Poimboeuf { 239442f04c3SJosh Poimboeuf Elf_Scn *s = NULL; 240442f04c3SJosh Poimboeuf struct section *sec; 241442f04c3SJosh Poimboeuf size_t shstrndx, sections_nr; 242442f04c3SJosh Poimboeuf int i; 243442f04c3SJosh Poimboeuf 244442f04c3SJosh Poimboeuf if (elf_getshdrnum(elf->elf, §ions_nr)) { 245baa41469SJosh Poimboeuf WARN_ELF("elf_getshdrnum"); 246442f04c3SJosh Poimboeuf return -1; 247442f04c3SJosh Poimboeuf } 248442f04c3SJosh Poimboeuf 249442f04c3SJosh Poimboeuf if (elf_getshdrstrndx(elf->elf, &shstrndx)) { 250baa41469SJosh Poimboeuf WARN_ELF("elf_getshdrstrndx"); 251442f04c3SJosh Poimboeuf return -1; 252442f04c3SJosh Poimboeuf } 253442f04c3SJosh Poimboeuf 254442f04c3SJosh Poimboeuf for (i = 0; i < sections_nr; i++) { 255442f04c3SJosh Poimboeuf sec = malloc(sizeof(*sec)); 256442f04c3SJosh Poimboeuf if (!sec) { 257442f04c3SJosh Poimboeuf perror("malloc"); 258442f04c3SJosh Poimboeuf return -1; 259442f04c3SJosh Poimboeuf } 260442f04c3SJosh Poimboeuf memset(sec, 0, sizeof(*sec)); 261442f04c3SJosh Poimboeuf 262a196e171SJosh Poimboeuf INIT_LIST_HEAD(&sec->symbol_list); 263a196e171SJosh Poimboeuf INIT_LIST_HEAD(&sec->rela_list); 264042ba73fSJosh Poimboeuf hash_init(sec->rela_hash); 265442f04c3SJosh Poimboeuf 266442f04c3SJosh Poimboeuf s = elf_getscn(elf->elf, i); 267442f04c3SJosh Poimboeuf if (!s) { 268baa41469SJosh Poimboeuf WARN_ELF("elf_getscn"); 269442f04c3SJosh Poimboeuf return -1; 270442f04c3SJosh Poimboeuf } 271442f04c3SJosh Poimboeuf 272442f04c3SJosh Poimboeuf sec->idx = elf_ndxscn(s); 273442f04c3SJosh Poimboeuf 274442f04c3SJosh Poimboeuf if (!gelf_getshdr(s, &sec->sh)) { 275baa41469SJosh Poimboeuf WARN_ELF("gelf_getshdr"); 276442f04c3SJosh Poimboeuf return -1; 277442f04c3SJosh Poimboeuf } 278442f04c3SJosh Poimboeuf 279442f04c3SJosh Poimboeuf sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name); 280442f04c3SJosh Poimboeuf if (!sec->name) { 281baa41469SJosh Poimboeuf WARN_ELF("elf_strptr"); 282442f04c3SJosh Poimboeuf return -1; 283442f04c3SJosh Poimboeuf } 284442f04c3SJosh Poimboeuf 285df968c93SPetr Vandrovec if (sec->sh.sh_size != 0) { 286baa41469SJosh Poimboeuf sec->data = elf_getdata(s, NULL); 287baa41469SJosh Poimboeuf if (!sec->data) { 288baa41469SJosh Poimboeuf WARN_ELF("elf_getdata"); 289442f04c3SJosh Poimboeuf return -1; 290442f04c3SJosh Poimboeuf } 291baa41469SJosh Poimboeuf if (sec->data->d_off != 0 || 292baa41469SJosh Poimboeuf sec->data->d_size != sec->sh.sh_size) { 293df968c93SPetr Vandrovec WARN("unexpected data attributes for %s", 294df968c93SPetr Vandrovec sec->name); 295442f04c3SJosh Poimboeuf return -1; 296442f04c3SJosh Poimboeuf } 297df968c93SPetr Vandrovec } 298df968c93SPetr Vandrovec sec->len = sec->sh.sh_size; 29953038996SPeter Zijlstra 30053038996SPeter Zijlstra list_add_tail(&sec->list, &elf->sections); 30153038996SPeter Zijlstra hash_add(elf->section_hash, &sec->hash, sec->idx); 302ae358196SPeter Zijlstra hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name)); 303442f04c3SJosh Poimboeuf } 304442f04c3SJosh Poimboeuf 3051e11f3fdSPeter Zijlstra if (stats) 3061e11f3fdSPeter Zijlstra printf("nr_sections: %lu\n", (unsigned long)sections_nr); 3071e11f3fdSPeter Zijlstra 308442f04c3SJosh Poimboeuf /* sanity check, one more call to elf_nextscn() should return NULL */ 309442f04c3SJosh Poimboeuf if (elf_nextscn(elf->elf, s)) { 310442f04c3SJosh Poimboeuf WARN("section entry mismatch"); 311442f04c3SJosh Poimboeuf return -1; 312442f04c3SJosh Poimboeuf } 313442f04c3SJosh Poimboeuf 314442f04c3SJosh Poimboeuf return 0; 315442f04c3SJosh Poimboeuf } 316442f04c3SJosh Poimboeuf 317442f04c3SJosh Poimboeuf static int read_symbols(struct elf *elf) 318442f04c3SJosh Poimboeuf { 31913810435SJosh Poimboeuf struct section *symtab, *sec; 3202a362eccSPeter Zijlstra struct symbol *sym, *pfunc; 3212a362eccSPeter Zijlstra struct list_head *entry; 3222a362eccSPeter Zijlstra struct rb_node *pnode; 323442f04c3SJosh Poimboeuf int symbols_nr, i; 32413810435SJosh Poimboeuf char *coldstr; 325442f04c3SJosh Poimboeuf 326442f04c3SJosh Poimboeuf symtab = find_section_by_name(elf, ".symtab"); 327442f04c3SJosh Poimboeuf if (!symtab) { 328442f04c3SJosh Poimboeuf WARN("missing symbol table"); 329442f04c3SJosh Poimboeuf return -1; 330442f04c3SJosh Poimboeuf } 331442f04c3SJosh Poimboeuf 332442f04c3SJosh Poimboeuf symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize; 333442f04c3SJosh Poimboeuf 334442f04c3SJosh Poimboeuf for (i = 0; i < symbols_nr; i++) { 335442f04c3SJosh Poimboeuf sym = malloc(sizeof(*sym)); 336442f04c3SJosh Poimboeuf if (!sym) { 337442f04c3SJosh Poimboeuf perror("malloc"); 338442f04c3SJosh Poimboeuf return -1; 339442f04c3SJosh Poimboeuf } 340442f04c3SJosh Poimboeuf memset(sym, 0, sizeof(*sym)); 3412a362eccSPeter Zijlstra sym->alias = sym; 342442f04c3SJosh Poimboeuf 343442f04c3SJosh Poimboeuf sym->idx = i; 344442f04c3SJosh Poimboeuf 345baa41469SJosh Poimboeuf if (!gelf_getsym(symtab->data, i, &sym->sym)) { 346baa41469SJosh Poimboeuf WARN_ELF("gelf_getsym"); 347442f04c3SJosh Poimboeuf goto err; 348442f04c3SJosh Poimboeuf } 349442f04c3SJosh Poimboeuf 350442f04c3SJosh Poimboeuf sym->name = elf_strptr(elf->elf, symtab->sh.sh_link, 351442f04c3SJosh Poimboeuf sym->sym.st_name); 352442f04c3SJosh Poimboeuf if (!sym->name) { 353baa41469SJosh Poimboeuf WARN_ELF("elf_strptr"); 354442f04c3SJosh Poimboeuf goto err; 355442f04c3SJosh Poimboeuf } 356442f04c3SJosh Poimboeuf 357442f04c3SJosh Poimboeuf sym->type = GELF_ST_TYPE(sym->sym.st_info); 358442f04c3SJosh Poimboeuf sym->bind = GELF_ST_BIND(sym->sym.st_info); 359442f04c3SJosh Poimboeuf 360442f04c3SJosh Poimboeuf if (sym->sym.st_shndx > SHN_UNDEF && 361442f04c3SJosh Poimboeuf sym->sym.st_shndx < SHN_LORESERVE) { 362442f04c3SJosh Poimboeuf sym->sec = find_section_by_index(elf, 363442f04c3SJosh Poimboeuf sym->sym.st_shndx); 364442f04c3SJosh Poimboeuf if (!sym->sec) { 365442f04c3SJosh Poimboeuf WARN("couldn't find section for symbol %s", 366442f04c3SJosh Poimboeuf sym->name); 367442f04c3SJosh Poimboeuf goto err; 368442f04c3SJosh Poimboeuf } 369442f04c3SJosh Poimboeuf if (sym->type == STT_SECTION) { 370442f04c3SJosh Poimboeuf sym->name = sym->sec->name; 371442f04c3SJosh Poimboeuf sym->sec->sym = sym; 372442f04c3SJosh Poimboeuf } 373442f04c3SJosh Poimboeuf } else 374442f04c3SJosh Poimboeuf sym->sec = find_section_by_index(elf, 0); 375442f04c3SJosh Poimboeuf 376442f04c3SJosh Poimboeuf sym->offset = sym->sym.st_value; 377442f04c3SJosh Poimboeuf sym->len = sym->sym.st_size; 378442f04c3SJosh Poimboeuf 3792a362eccSPeter Zijlstra rb_add(&sym->sec->symbol_tree, &sym->node, symbol_to_offset); 3802a362eccSPeter Zijlstra pnode = rb_prev(&sym->node); 3812a362eccSPeter Zijlstra if (pnode) 3822a362eccSPeter Zijlstra entry = &rb_entry(pnode, struct symbol, node)->list; 3832a362eccSPeter Zijlstra else 384a196e171SJosh Poimboeuf entry = &sym->sec->symbol_list; 385442f04c3SJosh Poimboeuf list_add(&sym->list, entry); 38665fb11a7SPeter Zijlstra hash_add(elf->symbol_hash, &sym->hash, sym->idx); 387cdb3d057SPeter Zijlstra hash_add(elf->symbol_name_hash, &sym->name_hash, str_hash(sym->name)); 388442f04c3SJosh Poimboeuf } 389442f04c3SJosh Poimboeuf 3901e11f3fdSPeter Zijlstra if (stats) 3911e11f3fdSPeter Zijlstra printf("nr_symbols: %lu\n", (unsigned long)symbols_nr); 3921e11f3fdSPeter Zijlstra 39313810435SJosh Poimboeuf /* Create parent/child links for any cold subfunctions */ 39413810435SJosh Poimboeuf list_for_each_entry(sec, &elf->sections, list) { 39513810435SJosh Poimboeuf list_for_each_entry(sym, &sec->symbol_list, list) { 39622566c16SArtem Savkov char pname[MAX_NAME_LEN + 1]; 39722566c16SArtem Savkov size_t pnamelen; 39813810435SJosh Poimboeuf if (sym->type != STT_FUNC) 39913810435SJosh Poimboeuf continue; 40013810435SJosh Poimboeuf sym->pfunc = sym->cfunc = sym; 401bcb6fb5dSJosh Poimboeuf coldstr = strstr(sym->name, ".cold"); 40208b393d0SJosh Poimboeuf if (!coldstr) 40308b393d0SJosh Poimboeuf continue; 40408b393d0SJosh Poimboeuf 40522566c16SArtem Savkov pnamelen = coldstr - sym->name; 40622566c16SArtem Savkov if (pnamelen > MAX_NAME_LEN) { 40722566c16SArtem Savkov WARN("%s(): parent function name exceeds maximum length of %d characters", 40822566c16SArtem Savkov sym->name, MAX_NAME_LEN); 40922566c16SArtem Savkov return -1; 41022566c16SArtem Savkov } 41122566c16SArtem Savkov 41222566c16SArtem Savkov strncpy(pname, sym->name, pnamelen); 41322566c16SArtem Savkov pname[pnamelen] = '\0'; 41422566c16SArtem Savkov pfunc = find_symbol_by_name(elf, pname); 41513810435SJosh Poimboeuf 41613810435SJosh Poimboeuf if (!pfunc) { 41713810435SJosh Poimboeuf WARN("%s(): can't find parent function", 41813810435SJosh Poimboeuf sym->name); 4190b9301fbSArtem Savkov return -1; 42013810435SJosh Poimboeuf } 42113810435SJosh Poimboeuf 42213810435SJosh Poimboeuf sym->pfunc = pfunc; 42313810435SJosh Poimboeuf pfunc->cfunc = sym; 42408b393d0SJosh Poimboeuf 42508b393d0SJosh Poimboeuf /* 42608b393d0SJosh Poimboeuf * Unfortunately, -fnoreorder-functions puts the child 42708b393d0SJosh Poimboeuf * inside the parent. Remove the overlap so we can 42808b393d0SJosh Poimboeuf * have sane assumptions. 42908b393d0SJosh Poimboeuf * 43008b393d0SJosh Poimboeuf * Note that pfunc->len now no longer matches 43108b393d0SJosh Poimboeuf * pfunc->sym.st_size. 43208b393d0SJosh Poimboeuf */ 43308b393d0SJosh Poimboeuf if (sym->sec == pfunc->sec && 43408b393d0SJosh Poimboeuf sym->offset >= pfunc->offset && 43508b393d0SJosh Poimboeuf sym->offset + sym->len == pfunc->offset + pfunc->len) { 43608b393d0SJosh Poimboeuf pfunc->len -= sym->len; 43713810435SJosh Poimboeuf } 43813810435SJosh Poimboeuf } 43913810435SJosh Poimboeuf } 44013810435SJosh Poimboeuf 441442f04c3SJosh Poimboeuf return 0; 442442f04c3SJosh Poimboeuf 443442f04c3SJosh Poimboeuf err: 444442f04c3SJosh Poimboeuf free(sym); 445442f04c3SJosh Poimboeuf return -1; 446442f04c3SJosh Poimboeuf } 447442f04c3SJosh Poimboeuf 448442f04c3SJosh Poimboeuf static int read_relas(struct elf *elf) 449442f04c3SJosh Poimboeuf { 450442f04c3SJosh Poimboeuf struct section *sec; 451442f04c3SJosh Poimboeuf struct rela *rela; 452442f04c3SJosh Poimboeuf int i; 453442f04c3SJosh Poimboeuf unsigned int symndx; 4541e11f3fdSPeter Zijlstra unsigned long nr_rela, max_rela = 0, tot_rela = 0; 455442f04c3SJosh Poimboeuf 456442f04c3SJosh Poimboeuf list_for_each_entry(sec, &elf->sections, list) { 457442f04c3SJosh Poimboeuf if (sec->sh.sh_type != SHT_RELA) 458442f04c3SJosh Poimboeuf continue; 459442f04c3SJosh Poimboeuf 460442f04c3SJosh Poimboeuf sec->base = find_section_by_name(elf, sec->name + 5); 461442f04c3SJosh Poimboeuf if (!sec->base) { 462442f04c3SJosh Poimboeuf WARN("can't find base section for rela section %s", 463442f04c3SJosh Poimboeuf sec->name); 464442f04c3SJosh Poimboeuf return -1; 465442f04c3SJosh Poimboeuf } 466442f04c3SJosh Poimboeuf 467442f04c3SJosh Poimboeuf sec->base->rela = sec; 468442f04c3SJosh Poimboeuf 4691e11f3fdSPeter Zijlstra nr_rela = 0; 470442f04c3SJosh Poimboeuf for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) { 471442f04c3SJosh Poimboeuf rela = malloc(sizeof(*rela)); 472442f04c3SJosh Poimboeuf if (!rela) { 473442f04c3SJosh Poimboeuf perror("malloc"); 474442f04c3SJosh Poimboeuf return -1; 475442f04c3SJosh Poimboeuf } 476442f04c3SJosh Poimboeuf memset(rela, 0, sizeof(*rela)); 477442f04c3SJosh Poimboeuf 478baa41469SJosh Poimboeuf if (!gelf_getrela(sec->data, i, &rela->rela)) { 479baa41469SJosh Poimboeuf WARN_ELF("gelf_getrela"); 480442f04c3SJosh Poimboeuf return -1; 481442f04c3SJosh Poimboeuf } 482442f04c3SJosh Poimboeuf 483442f04c3SJosh Poimboeuf rela->type = GELF_R_TYPE(rela->rela.r_info); 484442f04c3SJosh Poimboeuf rela->addend = rela->rela.r_addend; 485442f04c3SJosh Poimboeuf rela->offset = rela->rela.r_offset; 486442f04c3SJosh Poimboeuf symndx = GELF_R_SYM(rela->rela.r_info); 487442f04c3SJosh Poimboeuf rela->sym = find_symbol_by_index(elf, symndx); 488e7c2bc37SJosh Poimboeuf rela->sec = sec; 489442f04c3SJosh Poimboeuf if (!rela->sym) { 490442f04c3SJosh Poimboeuf WARN("can't find rela entry symbol %d for %s", 491442f04c3SJosh Poimboeuf symndx, sec->name); 492442f04c3SJosh Poimboeuf return -1; 493442f04c3SJosh Poimboeuf } 494042ba73fSJosh Poimboeuf 495042ba73fSJosh Poimboeuf list_add_tail(&rela->list, &sec->rela_list); 496042ba73fSJosh Poimboeuf hash_add(sec->rela_hash, &rela->hash, rela->offset); 4971e11f3fdSPeter Zijlstra nr_rela++; 498442f04c3SJosh Poimboeuf } 4991e11f3fdSPeter Zijlstra max_rela = max(max_rela, nr_rela); 5001e11f3fdSPeter Zijlstra tot_rela += nr_rela; 5011e11f3fdSPeter Zijlstra } 5021e11f3fdSPeter Zijlstra 5031e11f3fdSPeter Zijlstra if (stats) { 5041e11f3fdSPeter Zijlstra printf("max_rela: %lu\n", max_rela); 5051e11f3fdSPeter Zijlstra printf("tot_rela: %lu\n", tot_rela); 506442f04c3SJosh Poimboeuf } 507442f04c3SJosh Poimboeuf 508442f04c3SJosh Poimboeuf return 0; 509442f04c3SJosh Poimboeuf } 510442f04c3SJosh Poimboeuf 5118e144797SMichael Forney struct elf *elf_read(const char *name, int flags) 512442f04c3SJosh Poimboeuf { 513442f04c3SJosh Poimboeuf struct elf *elf; 514627fce14SJosh Poimboeuf Elf_Cmd cmd; 515442f04c3SJosh Poimboeuf 516442f04c3SJosh Poimboeuf elf_version(EV_CURRENT); 517442f04c3SJosh Poimboeuf 518442f04c3SJosh Poimboeuf elf = malloc(sizeof(*elf)); 519442f04c3SJosh Poimboeuf if (!elf) { 520442f04c3SJosh Poimboeuf perror("malloc"); 521442f04c3SJosh Poimboeuf return NULL; 522442f04c3SJosh Poimboeuf } 523442f04c3SJosh Poimboeuf memset(elf, 0, sizeof(*elf)); 524442f04c3SJosh Poimboeuf 52565fb11a7SPeter Zijlstra hash_init(elf->symbol_hash); 526cdb3d057SPeter Zijlstra hash_init(elf->symbol_name_hash); 52753038996SPeter Zijlstra hash_init(elf->section_hash); 528ae358196SPeter Zijlstra hash_init(elf->section_name_hash); 529442f04c3SJosh Poimboeuf INIT_LIST_HEAD(&elf->sections); 530442f04c3SJosh Poimboeuf 531627fce14SJosh Poimboeuf elf->fd = open(name, flags); 532442f04c3SJosh Poimboeuf if (elf->fd == -1) { 533385d11b1SJosh Poimboeuf fprintf(stderr, "objtool: Can't open '%s': %s\n", 534385d11b1SJosh Poimboeuf name, strerror(errno)); 535442f04c3SJosh Poimboeuf goto err; 536442f04c3SJosh Poimboeuf } 537442f04c3SJosh Poimboeuf 538627fce14SJosh Poimboeuf if ((flags & O_ACCMODE) == O_RDONLY) 539627fce14SJosh Poimboeuf cmd = ELF_C_READ_MMAP; 540627fce14SJosh Poimboeuf else if ((flags & O_ACCMODE) == O_RDWR) 541627fce14SJosh Poimboeuf cmd = ELF_C_RDWR; 542627fce14SJosh Poimboeuf else /* O_WRONLY */ 543627fce14SJosh Poimboeuf cmd = ELF_C_WRITE; 544627fce14SJosh Poimboeuf 545627fce14SJosh Poimboeuf elf->elf = elf_begin(elf->fd, cmd, NULL); 546442f04c3SJosh Poimboeuf if (!elf->elf) { 547baa41469SJosh Poimboeuf WARN_ELF("elf_begin"); 548442f04c3SJosh Poimboeuf goto err; 549442f04c3SJosh Poimboeuf } 550442f04c3SJosh Poimboeuf 551442f04c3SJosh Poimboeuf if (!gelf_getehdr(elf->elf, &elf->ehdr)) { 552baa41469SJosh Poimboeuf WARN_ELF("gelf_getehdr"); 553442f04c3SJosh Poimboeuf goto err; 554442f04c3SJosh Poimboeuf } 555442f04c3SJosh Poimboeuf 556442f04c3SJosh Poimboeuf if (read_sections(elf)) 557442f04c3SJosh Poimboeuf goto err; 558442f04c3SJosh Poimboeuf 559442f04c3SJosh Poimboeuf if (read_symbols(elf)) 560442f04c3SJosh Poimboeuf goto err; 561442f04c3SJosh Poimboeuf 562442f04c3SJosh Poimboeuf if (read_relas(elf)) 563442f04c3SJosh Poimboeuf goto err; 564442f04c3SJosh Poimboeuf 565442f04c3SJosh Poimboeuf return elf; 566442f04c3SJosh Poimboeuf 567442f04c3SJosh Poimboeuf err: 568442f04c3SJosh Poimboeuf elf_close(elf); 569442f04c3SJosh Poimboeuf return NULL; 570442f04c3SJosh Poimboeuf } 571442f04c3SJosh Poimboeuf 572627fce14SJosh Poimboeuf struct section *elf_create_section(struct elf *elf, const char *name, 573627fce14SJosh Poimboeuf size_t entsize, int nr) 574627fce14SJosh Poimboeuf { 575627fce14SJosh Poimboeuf struct section *sec, *shstrtab; 576627fce14SJosh Poimboeuf size_t size = entsize * nr; 5773c3ea503SMichael Forney Elf_Scn *s; 578627fce14SJosh Poimboeuf Elf_Data *data; 579627fce14SJosh Poimboeuf 580627fce14SJosh Poimboeuf sec = malloc(sizeof(*sec)); 581627fce14SJosh Poimboeuf if (!sec) { 582627fce14SJosh Poimboeuf perror("malloc"); 583627fce14SJosh Poimboeuf return NULL; 584627fce14SJosh Poimboeuf } 585627fce14SJosh Poimboeuf memset(sec, 0, sizeof(*sec)); 586627fce14SJosh Poimboeuf 587627fce14SJosh Poimboeuf INIT_LIST_HEAD(&sec->symbol_list); 588627fce14SJosh Poimboeuf INIT_LIST_HEAD(&sec->rela_list); 589627fce14SJosh Poimboeuf hash_init(sec->rela_hash); 590627fce14SJosh Poimboeuf 591627fce14SJosh Poimboeuf s = elf_newscn(elf->elf); 592627fce14SJosh Poimboeuf if (!s) { 593627fce14SJosh Poimboeuf WARN_ELF("elf_newscn"); 594627fce14SJosh Poimboeuf return NULL; 595627fce14SJosh Poimboeuf } 596627fce14SJosh Poimboeuf 597627fce14SJosh Poimboeuf sec->name = strdup(name); 598627fce14SJosh Poimboeuf if (!sec->name) { 599627fce14SJosh Poimboeuf perror("strdup"); 600627fce14SJosh Poimboeuf return NULL; 601627fce14SJosh Poimboeuf } 602627fce14SJosh Poimboeuf 603627fce14SJosh Poimboeuf sec->idx = elf_ndxscn(s); 604627fce14SJosh Poimboeuf sec->len = size; 605627fce14SJosh Poimboeuf sec->changed = true; 606627fce14SJosh Poimboeuf 607627fce14SJosh Poimboeuf sec->data = elf_newdata(s); 608627fce14SJosh Poimboeuf if (!sec->data) { 609627fce14SJosh Poimboeuf WARN_ELF("elf_newdata"); 610627fce14SJosh Poimboeuf return NULL; 611627fce14SJosh Poimboeuf } 612627fce14SJosh Poimboeuf 613627fce14SJosh Poimboeuf sec->data->d_size = size; 614627fce14SJosh Poimboeuf sec->data->d_align = 1; 615627fce14SJosh Poimboeuf 616627fce14SJosh Poimboeuf if (size) { 617627fce14SJosh Poimboeuf sec->data->d_buf = malloc(size); 618627fce14SJosh Poimboeuf if (!sec->data->d_buf) { 619627fce14SJosh Poimboeuf perror("malloc"); 620627fce14SJosh Poimboeuf return NULL; 621627fce14SJosh Poimboeuf } 622627fce14SJosh Poimboeuf memset(sec->data->d_buf, 0, size); 623627fce14SJosh Poimboeuf } 624627fce14SJosh Poimboeuf 625627fce14SJosh Poimboeuf if (!gelf_getshdr(s, &sec->sh)) { 626627fce14SJosh Poimboeuf WARN_ELF("gelf_getshdr"); 627627fce14SJosh Poimboeuf return NULL; 628627fce14SJosh Poimboeuf } 629627fce14SJosh Poimboeuf 630627fce14SJosh Poimboeuf sec->sh.sh_size = size; 631627fce14SJosh Poimboeuf sec->sh.sh_entsize = entsize; 632627fce14SJosh Poimboeuf sec->sh.sh_type = SHT_PROGBITS; 633627fce14SJosh Poimboeuf sec->sh.sh_addralign = 1; 634627fce14SJosh Poimboeuf sec->sh.sh_flags = SHF_ALLOC; 635627fce14SJosh Poimboeuf 636627fce14SJosh Poimboeuf 6376d77d3b4SSimon Ser /* Add section name to .shstrtab (or .strtab for Clang) */ 638627fce14SJosh Poimboeuf shstrtab = find_section_by_name(elf, ".shstrtab"); 6396d77d3b4SSimon Ser if (!shstrtab) 6406d77d3b4SSimon Ser shstrtab = find_section_by_name(elf, ".strtab"); 641627fce14SJosh Poimboeuf if (!shstrtab) { 6426d77d3b4SSimon Ser WARN("can't find .shstrtab or .strtab section"); 643627fce14SJosh Poimboeuf return NULL; 644627fce14SJosh Poimboeuf } 645627fce14SJosh Poimboeuf 646627fce14SJosh Poimboeuf s = elf_getscn(elf->elf, shstrtab->idx); 647627fce14SJosh Poimboeuf if (!s) { 648627fce14SJosh Poimboeuf WARN_ELF("elf_getscn"); 649627fce14SJosh Poimboeuf return NULL; 650627fce14SJosh Poimboeuf } 651627fce14SJosh Poimboeuf 652627fce14SJosh Poimboeuf data = elf_newdata(s); 653627fce14SJosh Poimboeuf if (!data) { 654627fce14SJosh Poimboeuf WARN_ELF("elf_newdata"); 655627fce14SJosh Poimboeuf return NULL; 656627fce14SJosh Poimboeuf } 657627fce14SJosh Poimboeuf 658627fce14SJosh Poimboeuf data->d_buf = sec->name; 659627fce14SJosh Poimboeuf data->d_size = strlen(name) + 1; 660627fce14SJosh Poimboeuf data->d_align = 1; 661627fce14SJosh Poimboeuf 662627fce14SJosh Poimboeuf sec->sh.sh_name = shstrtab->len; 663627fce14SJosh Poimboeuf 664627fce14SJosh Poimboeuf shstrtab->len += strlen(name) + 1; 665627fce14SJosh Poimboeuf shstrtab->changed = true; 666627fce14SJosh Poimboeuf 66753038996SPeter Zijlstra list_add_tail(&sec->list, &elf->sections); 66853038996SPeter Zijlstra hash_add(elf->section_hash, &sec->hash, sec->idx); 669ae358196SPeter Zijlstra hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name)); 67053038996SPeter Zijlstra 671627fce14SJosh Poimboeuf return sec; 672627fce14SJosh Poimboeuf } 673627fce14SJosh Poimboeuf 674627fce14SJosh Poimboeuf struct section *elf_create_rela_section(struct elf *elf, struct section *base) 675627fce14SJosh Poimboeuf { 676627fce14SJosh Poimboeuf char *relaname; 677627fce14SJosh Poimboeuf struct section *sec; 678627fce14SJosh Poimboeuf 679627fce14SJosh Poimboeuf relaname = malloc(strlen(base->name) + strlen(".rela") + 1); 680627fce14SJosh Poimboeuf if (!relaname) { 681627fce14SJosh Poimboeuf perror("malloc"); 682627fce14SJosh Poimboeuf return NULL; 683627fce14SJosh Poimboeuf } 684627fce14SJosh Poimboeuf strcpy(relaname, ".rela"); 685627fce14SJosh Poimboeuf strcat(relaname, base->name); 686627fce14SJosh Poimboeuf 687627fce14SJosh Poimboeuf sec = elf_create_section(elf, relaname, sizeof(GElf_Rela), 0); 6880998b7a0SMartin Kepplinger free(relaname); 689627fce14SJosh Poimboeuf if (!sec) 690627fce14SJosh Poimboeuf return NULL; 691627fce14SJosh Poimboeuf 692627fce14SJosh Poimboeuf base->rela = sec; 693627fce14SJosh Poimboeuf sec->base = base; 694627fce14SJosh Poimboeuf 695627fce14SJosh Poimboeuf sec->sh.sh_type = SHT_RELA; 696627fce14SJosh Poimboeuf sec->sh.sh_addralign = 8; 697627fce14SJosh Poimboeuf sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx; 698627fce14SJosh Poimboeuf sec->sh.sh_info = base->idx; 699627fce14SJosh Poimboeuf sec->sh.sh_flags = SHF_INFO_LINK; 700627fce14SJosh Poimboeuf 701627fce14SJosh Poimboeuf return sec; 702627fce14SJosh Poimboeuf } 703627fce14SJosh Poimboeuf 704627fce14SJosh Poimboeuf int elf_rebuild_rela_section(struct section *sec) 705627fce14SJosh Poimboeuf { 706627fce14SJosh Poimboeuf struct rela *rela; 707627fce14SJosh Poimboeuf int nr, idx = 0, size; 708627fce14SJosh Poimboeuf GElf_Rela *relas; 709627fce14SJosh Poimboeuf 710627fce14SJosh Poimboeuf nr = 0; 711627fce14SJosh Poimboeuf list_for_each_entry(rela, &sec->rela_list, list) 712627fce14SJosh Poimboeuf nr++; 713627fce14SJosh Poimboeuf 714627fce14SJosh Poimboeuf size = nr * sizeof(*relas); 715627fce14SJosh Poimboeuf relas = malloc(size); 716627fce14SJosh Poimboeuf if (!relas) { 717627fce14SJosh Poimboeuf perror("malloc"); 718627fce14SJosh Poimboeuf return -1; 719627fce14SJosh Poimboeuf } 720627fce14SJosh Poimboeuf 721627fce14SJosh Poimboeuf sec->data->d_buf = relas; 722627fce14SJosh Poimboeuf sec->data->d_size = size; 723627fce14SJosh Poimboeuf 724627fce14SJosh Poimboeuf sec->sh.sh_size = size; 725627fce14SJosh Poimboeuf 726627fce14SJosh Poimboeuf idx = 0; 727627fce14SJosh Poimboeuf list_for_each_entry(rela, &sec->rela_list, list) { 728627fce14SJosh Poimboeuf relas[idx].r_offset = rela->offset; 729627fce14SJosh Poimboeuf relas[idx].r_addend = rela->addend; 730627fce14SJosh Poimboeuf relas[idx].r_info = GELF_R_INFO(rela->sym->idx, rela->type); 731627fce14SJosh Poimboeuf idx++; 732627fce14SJosh Poimboeuf } 733627fce14SJosh Poimboeuf 734627fce14SJosh Poimboeuf return 0; 735627fce14SJosh Poimboeuf } 736627fce14SJosh Poimboeuf 737627fce14SJosh Poimboeuf int elf_write(struct elf *elf) 738627fce14SJosh Poimboeuf { 739627fce14SJosh Poimboeuf struct section *sec; 740627fce14SJosh Poimboeuf Elf_Scn *s; 741627fce14SJosh Poimboeuf 74297dab2aeSJosh Poimboeuf /* Update section headers for changed sections: */ 743627fce14SJosh Poimboeuf list_for_each_entry(sec, &elf->sections, list) { 744627fce14SJosh Poimboeuf if (sec->changed) { 745627fce14SJosh Poimboeuf s = elf_getscn(elf->elf, sec->idx); 746627fce14SJosh Poimboeuf if (!s) { 747627fce14SJosh Poimboeuf WARN_ELF("elf_getscn"); 748627fce14SJosh Poimboeuf return -1; 749627fce14SJosh Poimboeuf } 750627fce14SJosh Poimboeuf if (!gelf_update_shdr(s, &sec->sh)) { 751627fce14SJosh Poimboeuf WARN_ELF("gelf_update_shdr"); 752627fce14SJosh Poimboeuf return -1; 753627fce14SJosh Poimboeuf } 754627fce14SJosh Poimboeuf } 755627fce14SJosh Poimboeuf } 756627fce14SJosh Poimboeuf 75797dab2aeSJosh Poimboeuf /* Make sure the new section header entries get updated properly. */ 75897dab2aeSJosh Poimboeuf elf_flagelf(elf->elf, ELF_C_SET, ELF_F_DIRTY); 75997dab2aeSJosh Poimboeuf 76097dab2aeSJosh Poimboeuf /* Write all changes to the file. */ 761627fce14SJosh Poimboeuf if (elf_update(elf->elf, ELF_C_WRITE) < 0) { 762627fce14SJosh Poimboeuf WARN_ELF("elf_update"); 763627fce14SJosh Poimboeuf return -1; 764627fce14SJosh Poimboeuf } 765627fce14SJosh Poimboeuf 766627fce14SJosh Poimboeuf return 0; 767627fce14SJosh Poimboeuf } 768627fce14SJosh Poimboeuf 769442f04c3SJosh Poimboeuf void elf_close(struct elf *elf) 770442f04c3SJosh Poimboeuf { 771442f04c3SJosh Poimboeuf struct section *sec, *tmpsec; 772442f04c3SJosh Poimboeuf struct symbol *sym, *tmpsym; 773442f04c3SJosh Poimboeuf struct rela *rela, *tmprela; 774442f04c3SJosh Poimboeuf 775baa41469SJosh Poimboeuf if (elf->elf) 776baa41469SJosh Poimboeuf elf_end(elf->elf); 777baa41469SJosh Poimboeuf 778baa41469SJosh Poimboeuf if (elf->fd > 0) 779baa41469SJosh Poimboeuf close(elf->fd); 780baa41469SJosh Poimboeuf 781442f04c3SJosh Poimboeuf list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) { 782a196e171SJosh Poimboeuf list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) { 783442f04c3SJosh Poimboeuf list_del(&sym->list); 784042ba73fSJosh Poimboeuf hash_del(&sym->hash); 785442f04c3SJosh Poimboeuf free(sym); 786442f04c3SJosh Poimboeuf } 787a196e171SJosh Poimboeuf list_for_each_entry_safe(rela, tmprela, &sec->rela_list, list) { 788442f04c3SJosh Poimboeuf list_del(&rela->list); 789042ba73fSJosh Poimboeuf hash_del(&rela->hash); 790442f04c3SJosh Poimboeuf free(rela); 791442f04c3SJosh Poimboeuf } 792442f04c3SJosh Poimboeuf list_del(&sec->list); 793442f04c3SJosh Poimboeuf free(sec); 794442f04c3SJosh Poimboeuf } 795baa41469SJosh Poimboeuf 796442f04c3SJosh Poimboeuf free(elf); 797442f04c3SJosh Poimboeuf } 798