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; 1085377cae9SJulien Thierry 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 2158b5fa6bcSPeter Zijlstra struct rela *find_rela_by_dest_range(struct elf *elf, struct section *sec, 2168b5fa6bcSPeter Zijlstra unsigned long offset, unsigned int len) 217442f04c3SJosh Poimboeuf { 21874b873e4SPeter Zijlstra struct rela *rela, *r = NULL; 219042ba73fSJosh Poimboeuf unsigned long o; 220442f04c3SJosh Poimboeuf 221442f04c3SJosh Poimboeuf if (!sec->rela) 222442f04c3SJosh Poimboeuf return NULL; 223442f04c3SJosh Poimboeuf 2248b5fa6bcSPeter Zijlstra sec = sec->rela; 2258b5fa6bcSPeter Zijlstra 22674b873e4SPeter Zijlstra for_offset_range(o, offset, offset + len) { 2278b5fa6bcSPeter Zijlstra hash_for_each_possible(elf->rela_hash, rela, hash, 2288b5fa6bcSPeter Zijlstra sec_offset_hash(sec, o)) { 22974b873e4SPeter Zijlstra if (rela->sec != sec) 23074b873e4SPeter Zijlstra continue; 23174b873e4SPeter Zijlstra 23274b873e4SPeter Zijlstra if (rela->offset >= offset && rela->offset < offset + len) { 23374b873e4SPeter Zijlstra if (!r || rela->offset < r->offset) 23474b873e4SPeter Zijlstra r = rela; 2358b5fa6bcSPeter Zijlstra } 2368b5fa6bcSPeter Zijlstra } 23774b873e4SPeter Zijlstra if (r) 23874b873e4SPeter Zijlstra return r; 23974b873e4SPeter Zijlstra } 240442f04c3SJosh Poimboeuf 241442f04c3SJosh Poimboeuf return NULL; 242442f04c3SJosh Poimboeuf } 243442f04c3SJosh Poimboeuf 2448b5fa6bcSPeter Zijlstra struct rela *find_rela_by_dest(struct elf *elf, struct section *sec, unsigned long offset) 245442f04c3SJosh Poimboeuf { 2468b5fa6bcSPeter Zijlstra return find_rela_by_dest_range(elf, sec, offset, 1); 247442f04c3SJosh Poimboeuf } 248442f04c3SJosh Poimboeuf 249442f04c3SJosh Poimboeuf static int read_sections(struct elf *elf) 250442f04c3SJosh Poimboeuf { 251442f04c3SJosh Poimboeuf Elf_Scn *s = NULL; 252442f04c3SJosh Poimboeuf struct section *sec; 253442f04c3SJosh Poimboeuf size_t shstrndx, sections_nr; 254442f04c3SJosh Poimboeuf int i; 255442f04c3SJosh Poimboeuf 256442f04c3SJosh Poimboeuf if (elf_getshdrnum(elf->elf, §ions_nr)) { 257baa41469SJosh Poimboeuf WARN_ELF("elf_getshdrnum"); 258442f04c3SJosh Poimboeuf return -1; 259442f04c3SJosh Poimboeuf } 260442f04c3SJosh Poimboeuf 261442f04c3SJosh Poimboeuf if (elf_getshdrstrndx(elf->elf, &shstrndx)) { 262baa41469SJosh Poimboeuf WARN_ELF("elf_getshdrstrndx"); 263442f04c3SJosh Poimboeuf return -1; 264442f04c3SJosh Poimboeuf } 265442f04c3SJosh Poimboeuf 266442f04c3SJosh Poimboeuf for (i = 0; i < sections_nr; i++) { 267442f04c3SJosh Poimboeuf sec = malloc(sizeof(*sec)); 268442f04c3SJosh Poimboeuf if (!sec) { 269442f04c3SJosh Poimboeuf perror("malloc"); 270442f04c3SJosh Poimboeuf return -1; 271442f04c3SJosh Poimboeuf } 272442f04c3SJosh Poimboeuf memset(sec, 0, sizeof(*sec)); 273442f04c3SJosh Poimboeuf 274a196e171SJosh Poimboeuf INIT_LIST_HEAD(&sec->symbol_list); 275a196e171SJosh Poimboeuf INIT_LIST_HEAD(&sec->rela_list); 276442f04c3SJosh Poimboeuf 277442f04c3SJosh Poimboeuf s = elf_getscn(elf->elf, i); 278442f04c3SJosh Poimboeuf if (!s) { 279baa41469SJosh Poimboeuf WARN_ELF("elf_getscn"); 280442f04c3SJosh Poimboeuf return -1; 281442f04c3SJosh Poimboeuf } 282442f04c3SJosh Poimboeuf 283442f04c3SJosh Poimboeuf sec->idx = elf_ndxscn(s); 284442f04c3SJosh Poimboeuf 285442f04c3SJosh Poimboeuf if (!gelf_getshdr(s, &sec->sh)) { 286baa41469SJosh Poimboeuf WARN_ELF("gelf_getshdr"); 287442f04c3SJosh Poimboeuf return -1; 288442f04c3SJosh Poimboeuf } 289442f04c3SJosh Poimboeuf 290442f04c3SJosh Poimboeuf sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name); 291442f04c3SJosh Poimboeuf if (!sec->name) { 292baa41469SJosh Poimboeuf WARN_ELF("elf_strptr"); 293442f04c3SJosh Poimboeuf return -1; 294442f04c3SJosh Poimboeuf } 295442f04c3SJosh Poimboeuf 296df968c93SPetr Vandrovec if (sec->sh.sh_size != 0) { 297baa41469SJosh Poimboeuf sec->data = elf_getdata(s, NULL); 298baa41469SJosh Poimboeuf if (!sec->data) { 299baa41469SJosh Poimboeuf WARN_ELF("elf_getdata"); 300442f04c3SJosh Poimboeuf return -1; 301442f04c3SJosh Poimboeuf } 302baa41469SJosh Poimboeuf if (sec->data->d_off != 0 || 303baa41469SJosh Poimboeuf sec->data->d_size != sec->sh.sh_size) { 304df968c93SPetr Vandrovec WARN("unexpected data attributes for %s", 305df968c93SPetr Vandrovec sec->name); 306442f04c3SJosh Poimboeuf return -1; 307442f04c3SJosh Poimboeuf } 308df968c93SPetr Vandrovec } 309df968c93SPetr Vandrovec sec->len = sec->sh.sh_size; 31053038996SPeter Zijlstra 31153038996SPeter Zijlstra list_add_tail(&sec->list, &elf->sections); 31253038996SPeter Zijlstra hash_add(elf->section_hash, &sec->hash, sec->idx); 313ae358196SPeter Zijlstra hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name)); 314442f04c3SJosh Poimboeuf } 315442f04c3SJosh Poimboeuf 3161e11f3fdSPeter Zijlstra if (stats) 3171e11f3fdSPeter Zijlstra printf("nr_sections: %lu\n", (unsigned long)sections_nr); 3181e11f3fdSPeter Zijlstra 319442f04c3SJosh Poimboeuf /* sanity check, one more call to elf_nextscn() should return NULL */ 320442f04c3SJosh Poimboeuf if (elf_nextscn(elf->elf, s)) { 321442f04c3SJosh Poimboeuf WARN("section entry mismatch"); 322442f04c3SJosh Poimboeuf return -1; 323442f04c3SJosh Poimboeuf } 324442f04c3SJosh Poimboeuf 325442f04c3SJosh Poimboeuf return 0; 326442f04c3SJosh Poimboeuf } 327442f04c3SJosh Poimboeuf 328442f04c3SJosh Poimboeuf static int read_symbols(struct elf *elf) 329442f04c3SJosh Poimboeuf { 33013810435SJosh Poimboeuf struct section *symtab, *sec; 3312a362eccSPeter Zijlstra struct symbol *sym, *pfunc; 3322a362eccSPeter Zijlstra struct list_head *entry; 3332a362eccSPeter Zijlstra struct rb_node *pnode; 334442f04c3SJosh Poimboeuf int symbols_nr, i; 33513810435SJosh Poimboeuf char *coldstr; 336442f04c3SJosh Poimboeuf 337442f04c3SJosh Poimboeuf symtab = find_section_by_name(elf, ".symtab"); 338442f04c3SJosh Poimboeuf if (!symtab) { 339442f04c3SJosh Poimboeuf WARN("missing symbol table"); 340442f04c3SJosh Poimboeuf return -1; 341442f04c3SJosh Poimboeuf } 342442f04c3SJosh Poimboeuf 343442f04c3SJosh Poimboeuf symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize; 344442f04c3SJosh Poimboeuf 345442f04c3SJosh Poimboeuf for (i = 0; i < symbols_nr; i++) { 346442f04c3SJosh Poimboeuf sym = malloc(sizeof(*sym)); 347442f04c3SJosh Poimboeuf if (!sym) { 348442f04c3SJosh Poimboeuf perror("malloc"); 349442f04c3SJosh Poimboeuf return -1; 350442f04c3SJosh Poimboeuf } 351442f04c3SJosh Poimboeuf memset(sym, 0, sizeof(*sym)); 3522a362eccSPeter Zijlstra sym->alias = sym; 353442f04c3SJosh Poimboeuf 354442f04c3SJosh Poimboeuf sym->idx = i; 355442f04c3SJosh Poimboeuf 356baa41469SJosh Poimboeuf if (!gelf_getsym(symtab->data, i, &sym->sym)) { 357baa41469SJosh Poimboeuf WARN_ELF("gelf_getsym"); 358442f04c3SJosh Poimboeuf goto err; 359442f04c3SJosh Poimboeuf } 360442f04c3SJosh Poimboeuf 361442f04c3SJosh Poimboeuf sym->name = elf_strptr(elf->elf, symtab->sh.sh_link, 362442f04c3SJosh Poimboeuf sym->sym.st_name); 363442f04c3SJosh Poimboeuf if (!sym->name) { 364baa41469SJosh Poimboeuf WARN_ELF("elf_strptr"); 365442f04c3SJosh Poimboeuf goto err; 366442f04c3SJosh Poimboeuf } 367442f04c3SJosh Poimboeuf 368442f04c3SJosh Poimboeuf sym->type = GELF_ST_TYPE(sym->sym.st_info); 369442f04c3SJosh Poimboeuf sym->bind = GELF_ST_BIND(sym->sym.st_info); 370442f04c3SJosh Poimboeuf 371442f04c3SJosh Poimboeuf if (sym->sym.st_shndx > SHN_UNDEF && 372442f04c3SJosh Poimboeuf sym->sym.st_shndx < SHN_LORESERVE) { 373442f04c3SJosh Poimboeuf sym->sec = find_section_by_index(elf, 374442f04c3SJosh Poimboeuf sym->sym.st_shndx); 375442f04c3SJosh Poimboeuf if (!sym->sec) { 376442f04c3SJosh Poimboeuf WARN("couldn't find section for symbol %s", 377442f04c3SJosh Poimboeuf sym->name); 378442f04c3SJosh Poimboeuf goto err; 379442f04c3SJosh Poimboeuf } 380442f04c3SJosh Poimboeuf if (sym->type == STT_SECTION) { 381442f04c3SJosh Poimboeuf sym->name = sym->sec->name; 382442f04c3SJosh Poimboeuf sym->sec->sym = sym; 383442f04c3SJosh Poimboeuf } 384442f04c3SJosh Poimboeuf } else 385442f04c3SJosh Poimboeuf sym->sec = find_section_by_index(elf, 0); 386442f04c3SJosh Poimboeuf 387442f04c3SJosh Poimboeuf sym->offset = sym->sym.st_value; 388442f04c3SJosh Poimboeuf sym->len = sym->sym.st_size; 389442f04c3SJosh Poimboeuf 3902a362eccSPeter Zijlstra rb_add(&sym->sec->symbol_tree, &sym->node, symbol_to_offset); 3912a362eccSPeter Zijlstra pnode = rb_prev(&sym->node); 3922a362eccSPeter Zijlstra if (pnode) 3932a362eccSPeter Zijlstra entry = &rb_entry(pnode, struct symbol, node)->list; 3942a362eccSPeter Zijlstra else 395a196e171SJosh Poimboeuf entry = &sym->sec->symbol_list; 396442f04c3SJosh Poimboeuf list_add(&sym->list, entry); 39765fb11a7SPeter Zijlstra hash_add(elf->symbol_hash, &sym->hash, sym->idx); 398cdb3d057SPeter Zijlstra hash_add(elf->symbol_name_hash, &sym->name_hash, str_hash(sym->name)); 399442f04c3SJosh Poimboeuf } 400442f04c3SJosh Poimboeuf 4011e11f3fdSPeter Zijlstra if (stats) 4021e11f3fdSPeter Zijlstra printf("nr_symbols: %lu\n", (unsigned long)symbols_nr); 4031e11f3fdSPeter Zijlstra 40413810435SJosh Poimboeuf /* Create parent/child links for any cold subfunctions */ 40513810435SJosh Poimboeuf list_for_each_entry(sec, &elf->sections, list) { 40613810435SJosh Poimboeuf list_for_each_entry(sym, &sec->symbol_list, list) { 40722566c16SArtem Savkov char pname[MAX_NAME_LEN + 1]; 40822566c16SArtem Savkov size_t pnamelen; 40913810435SJosh Poimboeuf if (sym->type != STT_FUNC) 41013810435SJosh Poimboeuf continue; 41113810435SJosh Poimboeuf sym->pfunc = sym->cfunc = sym; 412bcb6fb5dSJosh Poimboeuf coldstr = strstr(sym->name, ".cold"); 41308b393d0SJosh Poimboeuf if (!coldstr) 41408b393d0SJosh Poimboeuf continue; 41508b393d0SJosh Poimboeuf 41622566c16SArtem Savkov pnamelen = coldstr - sym->name; 41722566c16SArtem Savkov if (pnamelen > MAX_NAME_LEN) { 41822566c16SArtem Savkov WARN("%s(): parent function name exceeds maximum length of %d characters", 41922566c16SArtem Savkov sym->name, MAX_NAME_LEN); 42022566c16SArtem Savkov return -1; 42122566c16SArtem Savkov } 42222566c16SArtem Savkov 42322566c16SArtem Savkov strncpy(pname, sym->name, pnamelen); 42422566c16SArtem Savkov pname[pnamelen] = '\0'; 42522566c16SArtem Savkov pfunc = find_symbol_by_name(elf, pname); 42613810435SJosh Poimboeuf 42713810435SJosh Poimboeuf if (!pfunc) { 42813810435SJosh Poimboeuf WARN("%s(): can't find parent function", 42913810435SJosh Poimboeuf sym->name); 4300b9301fbSArtem Savkov return -1; 43113810435SJosh Poimboeuf } 43213810435SJosh Poimboeuf 43313810435SJosh Poimboeuf sym->pfunc = pfunc; 43413810435SJosh Poimboeuf pfunc->cfunc = sym; 43508b393d0SJosh Poimboeuf 43608b393d0SJosh Poimboeuf /* 43708b393d0SJosh Poimboeuf * Unfortunately, -fnoreorder-functions puts the child 43808b393d0SJosh Poimboeuf * inside the parent. Remove the overlap so we can 43908b393d0SJosh Poimboeuf * have sane assumptions. 44008b393d0SJosh Poimboeuf * 44108b393d0SJosh Poimboeuf * Note that pfunc->len now no longer matches 44208b393d0SJosh Poimboeuf * pfunc->sym.st_size. 44308b393d0SJosh Poimboeuf */ 44408b393d0SJosh Poimboeuf if (sym->sec == pfunc->sec && 44508b393d0SJosh Poimboeuf sym->offset >= pfunc->offset && 44608b393d0SJosh Poimboeuf sym->offset + sym->len == pfunc->offset + pfunc->len) { 44708b393d0SJosh Poimboeuf pfunc->len -= sym->len; 44813810435SJosh Poimboeuf } 44913810435SJosh Poimboeuf } 45013810435SJosh Poimboeuf } 45113810435SJosh Poimboeuf 452442f04c3SJosh Poimboeuf return 0; 453442f04c3SJosh Poimboeuf 454442f04c3SJosh Poimboeuf err: 455442f04c3SJosh Poimboeuf free(sym); 456442f04c3SJosh Poimboeuf return -1; 457442f04c3SJosh Poimboeuf } 458442f04c3SJosh Poimboeuf 459442f04c3SJosh Poimboeuf static int read_relas(struct elf *elf) 460442f04c3SJosh Poimboeuf { 461442f04c3SJosh Poimboeuf struct section *sec; 462442f04c3SJosh Poimboeuf struct rela *rela; 463442f04c3SJosh Poimboeuf int i; 464442f04c3SJosh Poimboeuf unsigned int symndx; 4651e11f3fdSPeter Zijlstra unsigned long nr_rela, max_rela = 0, tot_rela = 0; 466442f04c3SJosh Poimboeuf 467442f04c3SJosh Poimboeuf list_for_each_entry(sec, &elf->sections, list) { 468442f04c3SJosh Poimboeuf if (sec->sh.sh_type != SHT_RELA) 469442f04c3SJosh Poimboeuf continue; 470442f04c3SJosh Poimboeuf 471442f04c3SJosh Poimboeuf sec->base = find_section_by_name(elf, sec->name + 5); 472442f04c3SJosh Poimboeuf if (!sec->base) { 473442f04c3SJosh Poimboeuf WARN("can't find base section for rela section %s", 474442f04c3SJosh Poimboeuf sec->name); 475442f04c3SJosh Poimboeuf return -1; 476442f04c3SJosh Poimboeuf } 477442f04c3SJosh Poimboeuf 478442f04c3SJosh Poimboeuf sec->base->rela = sec; 479442f04c3SJosh Poimboeuf 4801e11f3fdSPeter Zijlstra nr_rela = 0; 481442f04c3SJosh Poimboeuf for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) { 482442f04c3SJosh Poimboeuf rela = malloc(sizeof(*rela)); 483442f04c3SJosh Poimboeuf if (!rela) { 484442f04c3SJosh Poimboeuf perror("malloc"); 485442f04c3SJosh Poimboeuf return -1; 486442f04c3SJosh Poimboeuf } 487442f04c3SJosh Poimboeuf memset(rela, 0, sizeof(*rela)); 488442f04c3SJosh Poimboeuf 489baa41469SJosh Poimboeuf if (!gelf_getrela(sec->data, i, &rela->rela)) { 490baa41469SJosh Poimboeuf WARN_ELF("gelf_getrela"); 491442f04c3SJosh Poimboeuf return -1; 492442f04c3SJosh Poimboeuf } 493442f04c3SJosh Poimboeuf 494442f04c3SJosh Poimboeuf rela->type = GELF_R_TYPE(rela->rela.r_info); 495442f04c3SJosh Poimboeuf rela->addend = rela->rela.r_addend; 496442f04c3SJosh Poimboeuf rela->offset = rela->rela.r_offset; 497442f04c3SJosh Poimboeuf symndx = GELF_R_SYM(rela->rela.r_info); 498442f04c3SJosh Poimboeuf rela->sym = find_symbol_by_index(elf, symndx); 499e7c2bc37SJosh Poimboeuf rela->sec = sec; 500442f04c3SJosh Poimboeuf if (!rela->sym) { 501442f04c3SJosh Poimboeuf WARN("can't find rela entry symbol %d for %s", 502442f04c3SJosh Poimboeuf symndx, sec->name); 503442f04c3SJosh Poimboeuf return -1; 504442f04c3SJosh Poimboeuf } 505042ba73fSJosh Poimboeuf 506042ba73fSJosh Poimboeuf list_add_tail(&rela->list, &sec->rela_list); 5078b5fa6bcSPeter Zijlstra hash_add(elf->rela_hash, &rela->hash, rela_hash(rela)); 5081e11f3fdSPeter Zijlstra nr_rela++; 509442f04c3SJosh Poimboeuf } 5101e11f3fdSPeter Zijlstra max_rela = max(max_rela, nr_rela); 5111e11f3fdSPeter Zijlstra tot_rela += nr_rela; 5121e11f3fdSPeter Zijlstra } 5131e11f3fdSPeter Zijlstra 5141e11f3fdSPeter Zijlstra if (stats) { 5151e11f3fdSPeter Zijlstra printf("max_rela: %lu\n", max_rela); 5161e11f3fdSPeter Zijlstra printf("tot_rela: %lu\n", tot_rela); 517442f04c3SJosh Poimboeuf } 518442f04c3SJosh Poimboeuf 519442f04c3SJosh Poimboeuf return 0; 520442f04c3SJosh Poimboeuf } 521442f04c3SJosh Poimboeuf 5228e144797SMichael Forney struct elf *elf_read(const char *name, int flags) 523442f04c3SJosh Poimboeuf { 524442f04c3SJosh Poimboeuf struct elf *elf; 525627fce14SJosh Poimboeuf Elf_Cmd cmd; 526442f04c3SJosh Poimboeuf 527442f04c3SJosh Poimboeuf elf_version(EV_CURRENT); 528442f04c3SJosh Poimboeuf 529442f04c3SJosh Poimboeuf elf = malloc(sizeof(*elf)); 530442f04c3SJosh Poimboeuf if (!elf) { 531442f04c3SJosh Poimboeuf perror("malloc"); 532442f04c3SJosh Poimboeuf return NULL; 533442f04c3SJosh Poimboeuf } 534442f04c3SJosh Poimboeuf memset(elf, 0, sizeof(*elf)); 535442f04c3SJosh Poimboeuf 53665fb11a7SPeter Zijlstra hash_init(elf->symbol_hash); 537cdb3d057SPeter Zijlstra hash_init(elf->symbol_name_hash); 53853038996SPeter Zijlstra hash_init(elf->section_hash); 539ae358196SPeter Zijlstra hash_init(elf->section_name_hash); 5408b5fa6bcSPeter Zijlstra hash_init(elf->rela_hash); 541442f04c3SJosh Poimboeuf INIT_LIST_HEAD(&elf->sections); 542442f04c3SJosh Poimboeuf 543627fce14SJosh Poimboeuf elf->fd = open(name, flags); 544442f04c3SJosh Poimboeuf if (elf->fd == -1) { 545385d11b1SJosh Poimboeuf fprintf(stderr, "objtool: Can't open '%s': %s\n", 546385d11b1SJosh Poimboeuf name, strerror(errno)); 547442f04c3SJosh Poimboeuf goto err; 548442f04c3SJosh Poimboeuf } 549442f04c3SJosh Poimboeuf 550627fce14SJosh Poimboeuf if ((flags & O_ACCMODE) == O_RDONLY) 551627fce14SJosh Poimboeuf cmd = ELF_C_READ_MMAP; 552627fce14SJosh Poimboeuf else if ((flags & O_ACCMODE) == O_RDWR) 553627fce14SJosh Poimboeuf cmd = ELF_C_RDWR; 554627fce14SJosh Poimboeuf else /* O_WRONLY */ 555627fce14SJosh Poimboeuf cmd = ELF_C_WRITE; 556627fce14SJosh Poimboeuf 557627fce14SJosh Poimboeuf elf->elf = elf_begin(elf->fd, cmd, NULL); 558442f04c3SJosh Poimboeuf if (!elf->elf) { 559baa41469SJosh Poimboeuf WARN_ELF("elf_begin"); 560442f04c3SJosh Poimboeuf goto err; 561442f04c3SJosh Poimboeuf } 562442f04c3SJosh Poimboeuf 563442f04c3SJosh Poimboeuf if (!gelf_getehdr(elf->elf, &elf->ehdr)) { 564baa41469SJosh Poimboeuf WARN_ELF("gelf_getehdr"); 565442f04c3SJosh Poimboeuf goto err; 566442f04c3SJosh Poimboeuf } 567442f04c3SJosh Poimboeuf 568442f04c3SJosh Poimboeuf if (read_sections(elf)) 569442f04c3SJosh Poimboeuf goto err; 570442f04c3SJosh Poimboeuf 571442f04c3SJosh Poimboeuf if (read_symbols(elf)) 572442f04c3SJosh Poimboeuf goto err; 573442f04c3SJosh Poimboeuf 574442f04c3SJosh Poimboeuf if (read_relas(elf)) 575442f04c3SJosh Poimboeuf goto err; 576442f04c3SJosh Poimboeuf 577442f04c3SJosh Poimboeuf return elf; 578442f04c3SJosh Poimboeuf 579442f04c3SJosh Poimboeuf err: 580442f04c3SJosh Poimboeuf elf_close(elf); 581442f04c3SJosh Poimboeuf return NULL; 582442f04c3SJosh Poimboeuf } 583442f04c3SJosh Poimboeuf 584627fce14SJosh Poimboeuf struct section *elf_create_section(struct elf *elf, const char *name, 585627fce14SJosh Poimboeuf size_t entsize, int nr) 586627fce14SJosh Poimboeuf { 587627fce14SJosh Poimboeuf struct section *sec, *shstrtab; 588627fce14SJosh Poimboeuf size_t size = entsize * nr; 5893c3ea503SMichael Forney Elf_Scn *s; 590627fce14SJosh Poimboeuf Elf_Data *data; 591627fce14SJosh Poimboeuf 592627fce14SJosh Poimboeuf sec = malloc(sizeof(*sec)); 593627fce14SJosh Poimboeuf if (!sec) { 594627fce14SJosh Poimboeuf perror("malloc"); 595627fce14SJosh Poimboeuf return NULL; 596627fce14SJosh Poimboeuf } 597627fce14SJosh Poimboeuf memset(sec, 0, sizeof(*sec)); 598627fce14SJosh Poimboeuf 599627fce14SJosh Poimboeuf INIT_LIST_HEAD(&sec->symbol_list); 600627fce14SJosh Poimboeuf INIT_LIST_HEAD(&sec->rela_list); 601627fce14SJosh Poimboeuf 602627fce14SJosh Poimboeuf s = elf_newscn(elf->elf); 603627fce14SJosh Poimboeuf if (!s) { 604627fce14SJosh Poimboeuf WARN_ELF("elf_newscn"); 605627fce14SJosh Poimboeuf return NULL; 606627fce14SJosh Poimboeuf } 607627fce14SJosh Poimboeuf 608627fce14SJosh Poimboeuf sec->name = strdup(name); 609627fce14SJosh Poimboeuf if (!sec->name) { 610627fce14SJosh Poimboeuf perror("strdup"); 611627fce14SJosh Poimboeuf return NULL; 612627fce14SJosh Poimboeuf } 613627fce14SJosh Poimboeuf 614627fce14SJosh Poimboeuf sec->idx = elf_ndxscn(s); 615627fce14SJosh Poimboeuf sec->len = size; 616627fce14SJosh Poimboeuf sec->changed = true; 617627fce14SJosh Poimboeuf 618627fce14SJosh Poimboeuf sec->data = elf_newdata(s); 619627fce14SJosh Poimboeuf if (!sec->data) { 620627fce14SJosh Poimboeuf WARN_ELF("elf_newdata"); 621627fce14SJosh Poimboeuf return NULL; 622627fce14SJosh Poimboeuf } 623627fce14SJosh Poimboeuf 624627fce14SJosh Poimboeuf sec->data->d_size = size; 625627fce14SJosh Poimboeuf sec->data->d_align = 1; 626627fce14SJosh Poimboeuf 627627fce14SJosh Poimboeuf if (size) { 628627fce14SJosh Poimboeuf sec->data->d_buf = malloc(size); 629627fce14SJosh Poimboeuf if (!sec->data->d_buf) { 630627fce14SJosh Poimboeuf perror("malloc"); 631627fce14SJosh Poimboeuf return NULL; 632627fce14SJosh Poimboeuf } 633627fce14SJosh Poimboeuf memset(sec->data->d_buf, 0, size); 634627fce14SJosh Poimboeuf } 635627fce14SJosh Poimboeuf 636627fce14SJosh Poimboeuf if (!gelf_getshdr(s, &sec->sh)) { 637627fce14SJosh Poimboeuf WARN_ELF("gelf_getshdr"); 638627fce14SJosh Poimboeuf return NULL; 639627fce14SJosh Poimboeuf } 640627fce14SJosh Poimboeuf 641627fce14SJosh Poimboeuf sec->sh.sh_size = size; 642627fce14SJosh Poimboeuf sec->sh.sh_entsize = entsize; 643627fce14SJosh Poimboeuf sec->sh.sh_type = SHT_PROGBITS; 644627fce14SJosh Poimboeuf sec->sh.sh_addralign = 1; 645627fce14SJosh Poimboeuf sec->sh.sh_flags = SHF_ALLOC; 646627fce14SJosh Poimboeuf 647627fce14SJosh Poimboeuf 6486d77d3b4SSimon Ser /* Add section name to .shstrtab (or .strtab for Clang) */ 649627fce14SJosh Poimboeuf shstrtab = find_section_by_name(elf, ".shstrtab"); 6506d77d3b4SSimon Ser if (!shstrtab) 6516d77d3b4SSimon Ser shstrtab = find_section_by_name(elf, ".strtab"); 652627fce14SJosh Poimboeuf if (!shstrtab) { 6536d77d3b4SSimon Ser WARN("can't find .shstrtab or .strtab section"); 654627fce14SJosh Poimboeuf return NULL; 655627fce14SJosh Poimboeuf } 656627fce14SJosh Poimboeuf 657627fce14SJosh Poimboeuf s = elf_getscn(elf->elf, shstrtab->idx); 658627fce14SJosh Poimboeuf if (!s) { 659627fce14SJosh Poimboeuf WARN_ELF("elf_getscn"); 660627fce14SJosh Poimboeuf return NULL; 661627fce14SJosh Poimboeuf } 662627fce14SJosh Poimboeuf 663627fce14SJosh Poimboeuf data = elf_newdata(s); 664627fce14SJosh Poimboeuf if (!data) { 665627fce14SJosh Poimboeuf WARN_ELF("elf_newdata"); 666627fce14SJosh Poimboeuf return NULL; 667627fce14SJosh Poimboeuf } 668627fce14SJosh Poimboeuf 669627fce14SJosh Poimboeuf data->d_buf = sec->name; 670627fce14SJosh Poimboeuf data->d_size = strlen(name) + 1; 671627fce14SJosh Poimboeuf data->d_align = 1; 672627fce14SJosh Poimboeuf 673627fce14SJosh Poimboeuf sec->sh.sh_name = shstrtab->len; 674627fce14SJosh Poimboeuf 675627fce14SJosh Poimboeuf shstrtab->len += strlen(name) + 1; 676627fce14SJosh Poimboeuf shstrtab->changed = true; 677627fce14SJosh Poimboeuf 67853038996SPeter Zijlstra list_add_tail(&sec->list, &elf->sections); 67953038996SPeter Zijlstra hash_add(elf->section_hash, &sec->hash, sec->idx); 680ae358196SPeter Zijlstra hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name)); 68153038996SPeter Zijlstra 682627fce14SJosh Poimboeuf return sec; 683627fce14SJosh Poimboeuf } 684627fce14SJosh Poimboeuf 685627fce14SJosh Poimboeuf struct section *elf_create_rela_section(struct elf *elf, struct section *base) 686627fce14SJosh Poimboeuf { 687627fce14SJosh Poimboeuf char *relaname; 688627fce14SJosh Poimboeuf struct section *sec; 689627fce14SJosh Poimboeuf 690627fce14SJosh Poimboeuf relaname = malloc(strlen(base->name) + strlen(".rela") + 1); 691627fce14SJosh Poimboeuf if (!relaname) { 692627fce14SJosh Poimboeuf perror("malloc"); 693627fce14SJosh Poimboeuf return NULL; 694627fce14SJosh Poimboeuf } 695627fce14SJosh Poimboeuf strcpy(relaname, ".rela"); 696627fce14SJosh Poimboeuf strcat(relaname, base->name); 697627fce14SJosh Poimboeuf 698627fce14SJosh Poimboeuf sec = elf_create_section(elf, relaname, sizeof(GElf_Rela), 0); 6990998b7a0SMartin Kepplinger free(relaname); 700627fce14SJosh Poimboeuf if (!sec) 701627fce14SJosh Poimboeuf return NULL; 702627fce14SJosh Poimboeuf 703627fce14SJosh Poimboeuf base->rela = sec; 704627fce14SJosh Poimboeuf sec->base = base; 705627fce14SJosh Poimboeuf 706627fce14SJosh Poimboeuf sec->sh.sh_type = SHT_RELA; 707627fce14SJosh Poimboeuf sec->sh.sh_addralign = 8; 708627fce14SJosh Poimboeuf sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx; 709627fce14SJosh Poimboeuf sec->sh.sh_info = base->idx; 710627fce14SJosh Poimboeuf sec->sh.sh_flags = SHF_INFO_LINK; 711627fce14SJosh Poimboeuf 712627fce14SJosh Poimboeuf return sec; 713627fce14SJosh Poimboeuf } 714627fce14SJosh Poimboeuf 715627fce14SJosh Poimboeuf int elf_rebuild_rela_section(struct section *sec) 716627fce14SJosh Poimboeuf { 717627fce14SJosh Poimboeuf struct rela *rela; 718627fce14SJosh Poimboeuf int nr, idx = 0, size; 719627fce14SJosh Poimboeuf GElf_Rela *relas; 720627fce14SJosh Poimboeuf 721627fce14SJosh Poimboeuf nr = 0; 722627fce14SJosh Poimboeuf list_for_each_entry(rela, &sec->rela_list, list) 723627fce14SJosh Poimboeuf nr++; 724627fce14SJosh Poimboeuf 725627fce14SJosh Poimboeuf size = nr * sizeof(*relas); 726627fce14SJosh Poimboeuf relas = malloc(size); 727627fce14SJosh Poimboeuf if (!relas) { 728627fce14SJosh Poimboeuf perror("malloc"); 729627fce14SJosh Poimboeuf return -1; 730627fce14SJosh Poimboeuf } 731627fce14SJosh Poimboeuf 732627fce14SJosh Poimboeuf sec->data->d_buf = relas; 733627fce14SJosh Poimboeuf sec->data->d_size = size; 734627fce14SJosh Poimboeuf 735627fce14SJosh Poimboeuf sec->sh.sh_size = size; 736627fce14SJosh Poimboeuf 737627fce14SJosh Poimboeuf idx = 0; 738627fce14SJosh Poimboeuf list_for_each_entry(rela, &sec->rela_list, list) { 739627fce14SJosh Poimboeuf relas[idx].r_offset = rela->offset; 740627fce14SJosh Poimboeuf relas[idx].r_addend = rela->addend; 741627fce14SJosh Poimboeuf relas[idx].r_info = GELF_R_INFO(rela->sym->idx, rela->type); 742627fce14SJosh Poimboeuf idx++; 743627fce14SJosh Poimboeuf } 744627fce14SJosh Poimboeuf 745627fce14SJosh Poimboeuf return 0; 746627fce14SJosh Poimboeuf } 747627fce14SJosh Poimboeuf 748627fce14SJosh Poimboeuf int elf_write(struct elf *elf) 749627fce14SJosh Poimboeuf { 750627fce14SJosh Poimboeuf struct section *sec; 751627fce14SJosh Poimboeuf Elf_Scn *s; 752627fce14SJosh Poimboeuf 75397dab2aeSJosh Poimboeuf /* Update section headers for changed sections: */ 754627fce14SJosh Poimboeuf list_for_each_entry(sec, &elf->sections, list) { 755627fce14SJosh Poimboeuf if (sec->changed) { 756627fce14SJosh Poimboeuf s = elf_getscn(elf->elf, sec->idx); 757627fce14SJosh Poimboeuf if (!s) { 758627fce14SJosh Poimboeuf WARN_ELF("elf_getscn"); 759627fce14SJosh Poimboeuf return -1; 760627fce14SJosh Poimboeuf } 761627fce14SJosh Poimboeuf if (!gelf_update_shdr(s, &sec->sh)) { 762627fce14SJosh Poimboeuf WARN_ELF("gelf_update_shdr"); 763627fce14SJosh Poimboeuf return -1; 764627fce14SJosh Poimboeuf } 765627fce14SJosh Poimboeuf } 766627fce14SJosh Poimboeuf } 767627fce14SJosh Poimboeuf 76897dab2aeSJosh Poimboeuf /* Make sure the new section header entries get updated properly. */ 76997dab2aeSJosh Poimboeuf elf_flagelf(elf->elf, ELF_C_SET, ELF_F_DIRTY); 77097dab2aeSJosh Poimboeuf 77197dab2aeSJosh Poimboeuf /* Write all changes to the file. */ 772627fce14SJosh Poimboeuf if (elf_update(elf->elf, ELF_C_WRITE) < 0) { 773627fce14SJosh Poimboeuf WARN_ELF("elf_update"); 774627fce14SJosh Poimboeuf return -1; 775627fce14SJosh Poimboeuf } 776627fce14SJosh Poimboeuf 777627fce14SJosh Poimboeuf return 0; 778627fce14SJosh Poimboeuf } 779627fce14SJosh Poimboeuf 780442f04c3SJosh Poimboeuf void elf_close(struct elf *elf) 781442f04c3SJosh Poimboeuf { 782442f04c3SJosh Poimboeuf struct section *sec, *tmpsec; 783442f04c3SJosh Poimboeuf struct symbol *sym, *tmpsym; 784442f04c3SJosh Poimboeuf struct rela *rela, *tmprela; 785442f04c3SJosh Poimboeuf 786baa41469SJosh Poimboeuf if (elf->elf) 787baa41469SJosh Poimboeuf elf_end(elf->elf); 788baa41469SJosh Poimboeuf 789baa41469SJosh Poimboeuf if (elf->fd > 0) 790baa41469SJosh Poimboeuf close(elf->fd); 791baa41469SJosh Poimboeuf 792442f04c3SJosh Poimboeuf list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) { 793a196e171SJosh Poimboeuf list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) { 794442f04c3SJosh Poimboeuf list_del(&sym->list); 795042ba73fSJosh Poimboeuf hash_del(&sym->hash); 796442f04c3SJosh Poimboeuf free(sym); 797442f04c3SJosh Poimboeuf } 798a196e171SJosh Poimboeuf list_for_each_entry_safe(rela, tmprela, &sec->rela_list, list) { 799442f04c3SJosh Poimboeuf list_del(&rela->list); 800042ba73fSJosh Poimboeuf hash_del(&rela->hash); 801442f04c3SJosh Poimboeuf free(rela); 802442f04c3SJosh Poimboeuf } 803442f04c3SJosh Poimboeuf list_del(&sec->list); 804442f04c3SJosh Poimboeuf free(sec); 805442f04c3SJosh Poimboeuf } 806baa41469SJosh Poimboeuf 807442f04c3SJosh Poimboeuf free(elf); 808442f04c3SJosh Poimboeuf } 809