Lines Matching +full:- +full:section

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * elf.c - ELF access library
6 * Copyright (C) 2013-2015 Josh Poimboeuf <jpoimboe@redhat.com>
49 struct rb_node **link = &tree->rb_node; in rb_add()
55 link = &parent->rb_left; in rb_add()
57 link = &parent->rb_right; in rb_add()
67 struct rb_node *node = tree->rb_node; in rb_find_first()
75 node = node->rb_left; in rb_find_first()
77 node = node->rb_right; in rb_find_first()
102 if (sa->offset < sb->offset) in symbol_to_offset()
103 return -1; in symbol_to_offset()
104 if (sa->offset > sb->offset) in symbol_to_offset()
107 if (sa->len < sb->len) in symbol_to_offset()
108 return -1; in symbol_to_offset()
109 if (sa->len > sb->len) in symbol_to_offset()
112 sa->alias = sb; in symbol_to_offset()
122 if (*o < s->offset) in symbol_by_offset()
123 return -1; in symbol_by_offset()
124 if (*o >= s->offset + s->len) in symbol_by_offset()
130 struct section *find_section_by_name(const struct elf *elf, const char *name) in find_section_by_name()
132 struct section *sec; in find_section_by_name()
134 elf_hash_for_each_possible(elf->section_name_hash, sec, name_hash, str_hash(name)) in find_section_by_name()
135 if (!strcmp(sec->name, name)) in find_section_by_name()
141 static struct section *find_section_by_index(struct elf *elf, in find_section_by_index()
144 struct section *sec; in find_section_by_index()
146 elf_hash_for_each_possible(elf->section_hash, sec, hash, idx) in find_section_by_index()
147 if (sec->idx == idx) in find_section_by_index()
157 elf_hash_for_each_possible(elf->symbol_hash, sym, hash, idx) in find_symbol_by_index()
158 if (sym->idx == idx) in find_symbol_by_index()
164 struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset) in find_symbol_by_offset()
168 rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) { in find_symbol_by_offset()
171 if (s->offset == offset && s->type != STT_SECTION) in find_symbol_by_offset()
178 struct symbol *find_func_by_offset(struct section *sec, unsigned long offset) in find_func_by_offset()
182 rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) { in find_func_by_offset()
185 if (s->offset == offset && s->type == STT_FUNC) in find_func_by_offset()
192 struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset) in find_symbol_containing()
196 rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) { in find_symbol_containing()
199 if (s->type != STT_SECTION) in find_symbol_containing()
206 struct symbol *find_func_containing(struct section *sec, unsigned long offset) in find_func_containing()
210 rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) { in find_func_containing()
213 if (s->type == STT_FUNC) in find_func_containing()
224 elf_hash_for_each_possible(elf->symbol_name_hash, sym, name_hash, str_hash(name)) in find_symbol_by_name()
225 if (!strcmp(sym->name, name)) in find_symbol_by_name()
231 struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec, in find_reloc_by_dest_range()
237 if (!sec->reloc) in find_reloc_by_dest_range()
240 sec = sec->reloc; in find_reloc_by_dest_range()
243 elf_hash_for_each_possible(elf->reloc_hash, reloc, hash, in find_reloc_by_dest_range()
245 if (reloc->sec != sec) in find_reloc_by_dest_range()
248 if (reloc->offset >= offset && reloc->offset < offset + len) { in find_reloc_by_dest_range()
249 if (!r || reloc->offset < r->offset) in find_reloc_by_dest_range()
260 struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset) in find_reloc_by_dest()
268 struct section *sec; in read_sections()
272 if (elf_getshdrnum(elf->elf, &sections_nr)) { in read_sections()
274 return -1; in read_sections()
277 if (elf_getshdrstrndx(elf->elf, &shstrndx)) { in read_sections()
279 return -1; in read_sections()
286 return -1; in read_sections()
290 INIT_LIST_HEAD(&sec->symbol_list); in read_sections()
291 INIT_LIST_HEAD(&sec->reloc_list); in read_sections()
293 s = elf_getscn(elf->elf, i); in read_sections()
296 return -1; in read_sections()
299 sec->idx = elf_ndxscn(s); in read_sections()
301 if (!gelf_getshdr(s, &sec->sh)) { in read_sections()
303 return -1; in read_sections()
306 sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name); in read_sections()
307 if (!sec->name) { in read_sections()
309 return -1; in read_sections()
312 if (sec->sh.sh_size != 0) { in read_sections()
313 sec->data = elf_getdata(s, NULL); in read_sections()
314 if (!sec->data) { in read_sections()
316 return -1; in read_sections()
318 if (sec->data->d_off != 0 || in read_sections()
319 sec->data->d_size != sec->sh.sh_size) { in read_sections()
321 sec->name); in read_sections()
322 return -1; in read_sections()
325 sec->len = sec->sh.sh_size; in read_sections()
327 list_add_tail(&sec->list, &elf->sections); in read_sections()
328 elf_hash_add(elf->section_hash, &sec->hash, sec->idx); in read_sections()
329 elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name)); in read_sections()
336 if (elf_nextscn(elf->elf, s)) { in read_sections()
337 WARN("section entry mismatch"); in read_sections()
338 return -1; in read_sections()
346 struct section *symtab, *symtab_shndx, *sec; in read_symbols()
358 return -1; in read_symbols()
363 shndx_data = symtab_shndx->data; in read_symbols()
365 symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize; in read_symbols()
371 return -1; in read_symbols()
374 sym->alias = sym; in read_symbols()
376 sym->idx = i; in read_symbols()
378 if (!gelf_getsymshndx(symtab->data, shndx_data, i, &sym->sym, in read_symbols()
384 sym->name = elf_strptr(elf->elf, symtab->sh.sh_link, in read_symbols()
385 sym->sym.st_name); in read_symbols()
386 if (!sym->name) { in read_symbols()
391 sym->type = GELF_ST_TYPE(sym->sym.st_info); in read_symbols()
392 sym->bind = GELF_ST_BIND(sym->sym.st_info); in read_symbols()
394 if ((sym->sym.st_shndx > SHN_UNDEF && in read_symbols()
395 sym->sym.st_shndx < SHN_LORESERVE) || in read_symbols()
396 (shndx_data && sym->sym.st_shndx == SHN_XINDEX)) { in read_symbols()
397 if (sym->sym.st_shndx != SHN_XINDEX) in read_symbols()
398 shndx = sym->sym.st_shndx; in read_symbols()
400 sym->sec = find_section_by_index(elf, shndx); in read_symbols()
401 if (!sym->sec) { in read_symbols()
402 WARN("couldn't find section for symbol %s", in read_symbols()
403 sym->name); in read_symbols()
406 if (sym->type == STT_SECTION) { in read_symbols()
407 sym->name = sym->sec->name; in read_symbols()
408 sym->sec->sym = sym; in read_symbols()
411 sym->sec = find_section_by_index(elf, 0); in read_symbols()
413 sym->offset = sym->sym.st_value; in read_symbols()
414 sym->len = sym->sym.st_size; in read_symbols()
416 rb_add(&sym->sec->symbol_tree, &sym->node, symbol_to_offset); in read_symbols()
417 pnode = rb_prev(&sym->node); in read_symbols()
419 entry = &rb_entry(pnode, struct symbol, node)->list; in read_symbols()
421 entry = &sym->sec->symbol_list; in read_symbols()
422 list_add(&sym->list, entry); in read_symbols()
423 elf_hash_add(elf->symbol_hash, &sym->hash, sym->idx); in read_symbols()
424 elf_hash_add(elf->symbol_name_hash, &sym->name_hash, str_hash(sym->name)); in read_symbols()
431 list_for_each_entry(sec, &elf->sections, list) { in read_symbols()
432 list_for_each_entry(sym, &sec->symbol_list, list) { in read_symbols()
435 if (sym->type != STT_FUNC) in read_symbols()
438 if (sym->pfunc == NULL) in read_symbols()
439 sym->pfunc = sym; in read_symbols()
441 if (sym->cfunc == NULL) in read_symbols()
442 sym->cfunc = sym; in read_symbols()
444 coldstr = strstr(sym->name, ".cold"); in read_symbols()
448 pnamelen = coldstr - sym->name; in read_symbols()
451 sym->name, MAX_NAME_LEN); in read_symbols()
452 return -1; in read_symbols()
455 strncpy(pname, sym->name, pnamelen); in read_symbols()
461 sym->name); in read_symbols()
462 return -1; in read_symbols()
465 sym->pfunc = pfunc; in read_symbols()
466 pfunc->cfunc = sym; in read_symbols()
469 * Unfortunately, -fnoreorder-functions puts the child in read_symbols()
473 * Note that pfunc->len now no longer matches in read_symbols()
474 * pfunc->sym.st_size. in read_symbols()
476 if (sym->sec == pfunc->sec && in read_symbols()
477 sym->offset >= pfunc->offset && in read_symbols()
478 sym->offset + sym->len == pfunc->offset + pfunc->len) { in read_symbols()
479 pfunc->len -= sym->len; in read_symbols()
488 return -1; in read_symbols()
493 struct section *sec = reloc->sec; in elf_add_reloc()
495 list_add_tail(&reloc->list, &sec->reloc_list); in elf_add_reloc()
496 elf_hash_add(elf->reloc_hash, &reloc->hash, reloc_hash(reloc)); in elf_add_reloc()
499 static int read_rel_reloc(struct section *sec, int i, struct reloc *reloc, unsigned int *symndx) in read_rel_reloc()
501 if (!gelf_getrel(sec->data, i, &reloc->rel)) { in read_rel_reloc()
503 return -1; in read_rel_reloc()
505 reloc->type = GELF_R_TYPE(reloc->rel.r_info); in read_rel_reloc()
506 reloc->addend = 0; in read_rel_reloc()
507 reloc->offset = reloc->rel.r_offset; in read_rel_reloc()
508 *symndx = GELF_R_SYM(reloc->rel.r_info); in read_rel_reloc()
512 static int read_rela_reloc(struct section *sec, int i, struct reloc *reloc, unsigned int *symndx) in read_rela_reloc()
514 if (!gelf_getrela(sec->data, i, &reloc->rela)) { in read_rela_reloc()
516 return -1; in read_rela_reloc()
518 reloc->type = GELF_R_TYPE(reloc->rela.r_info); in read_rela_reloc()
519 reloc->addend = reloc->rela.r_addend; in read_rela_reloc()
520 reloc->offset = reloc->rela.r_offset; in read_rela_reloc()
521 *symndx = GELF_R_SYM(reloc->rela.r_info); in read_rela_reloc()
527 struct section *sec; in read_relocs()
533 list_for_each_entry(sec, &elf->sections, list) { in read_relocs()
534 if ((sec->sh.sh_type != SHT_RELA) && in read_relocs()
535 (sec->sh.sh_type != SHT_REL)) in read_relocs()
538 sec->base = find_section_by_index(elf, sec->sh.sh_info); in read_relocs()
539 if (!sec->base) { in read_relocs()
540 WARN("can't find base section for reloc section %s", in read_relocs()
541 sec->name); in read_relocs()
542 return -1; in read_relocs()
545 sec->base->reloc = sec; in read_relocs()
548 for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) { in read_relocs()
552 return -1; in read_relocs()
555 switch (sec->sh.sh_type) { in read_relocs()
558 return -1; in read_relocs()
562 return -1; in read_relocs()
564 default: return -1; in read_relocs()
567 reloc->sec = sec; in read_relocs()
568 reloc->idx = i; in read_relocs()
569 reloc->sym = find_symbol_by_index(elf, symndx); in read_relocs()
570 if (!reloc->sym) { in read_relocs()
572 symndx, sec->name); in read_relocs()
573 return -1; in read_relocs()
605 INIT_LIST_HEAD(&elf->sections); in elf_open_read()
607 elf_hash_init(elf->symbol_hash); in elf_open_read()
608 elf_hash_init(elf->symbol_name_hash); in elf_open_read()
609 elf_hash_init(elf->section_hash); in elf_open_read()
610 elf_hash_init(elf->section_name_hash); in elf_open_read()
611 elf_hash_init(elf->reloc_hash); in elf_open_read()
613 elf->fd = open(name, flags); in elf_open_read()
614 if (elf->fd == -1) { in elf_open_read()
627 elf->elf = elf_begin(elf->fd, cmd, NULL); in elf_open_read()
628 if (!elf->elf) { in elf_open_read()
633 if (!gelf_getehdr(elf->elf, &elf->ehdr)) { in elf_open_read()
654 struct section *elf_create_section(struct elf *elf, const char *name, in elf_create_section()
657 struct section *sec, *shstrtab; in elf_create_section()
669 INIT_LIST_HEAD(&sec->symbol_list); in elf_create_section()
670 INIT_LIST_HEAD(&sec->reloc_list); in elf_create_section()
672 s = elf_newscn(elf->elf); in elf_create_section()
678 sec->name = strdup(name); in elf_create_section()
679 if (!sec->name) { in elf_create_section()
684 sec->idx = elf_ndxscn(s); in elf_create_section()
685 sec->len = size; in elf_create_section()
686 sec->changed = true; in elf_create_section()
688 sec->data = elf_newdata(s); in elf_create_section()
689 if (!sec->data) { in elf_create_section()
694 sec->data->d_size = size; in elf_create_section()
695 sec->data->d_align = 1; in elf_create_section()
698 sec->data->d_buf = malloc(size); in elf_create_section()
699 if (!sec->data->d_buf) { in elf_create_section()
703 memset(sec->data->d_buf, 0, size); in elf_create_section()
706 if (!gelf_getshdr(s, &sec->sh)) { in elf_create_section()
711 sec->sh.sh_size = size; in elf_create_section()
712 sec->sh.sh_entsize = entsize; in elf_create_section()
713 sec->sh.sh_type = SHT_PROGBITS; in elf_create_section()
714 sec->sh.sh_addralign = 1; in elf_create_section()
715 sec->sh.sh_flags = SHF_ALLOC | sh_flags; in elf_create_section()
718 /* Add section name to .shstrtab (or .strtab for Clang) */ in elf_create_section()
723 WARN("can't find .shstrtab or .strtab section"); in elf_create_section()
727 s = elf_getscn(elf->elf, shstrtab->idx); in elf_create_section()
739 data->d_buf = sec->name; in elf_create_section()
740 data->d_size = strlen(name) + 1; in elf_create_section()
741 data->d_align = 1; in elf_create_section()
743 sec->sh.sh_name = shstrtab->len; in elf_create_section()
745 shstrtab->len += strlen(name) + 1; in elf_create_section()
746 shstrtab->changed = true; in elf_create_section()
748 list_add_tail(&sec->list, &elf->sections); in elf_create_section()
749 elf_hash_add(elf->section_hash, &sec->hash, sec->idx); in elf_create_section()
750 elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name)); in elf_create_section()
752 elf->changed = true; in elf_create_section()
757 static struct section *elf_create_rel_reloc_section(struct elf *elf, struct section *base) in elf_create_rel_reloc_section()
760 struct section *sec; in elf_create_rel_reloc_section()
762 relocname = malloc(strlen(base->name) + strlen(".rel") + 1); in elf_create_rel_reloc_section()
768 strcat(relocname, base->name); in elf_create_rel_reloc_section()
775 base->reloc = sec; in elf_create_rel_reloc_section()
776 sec->base = base; in elf_create_rel_reloc_section()
778 sec->sh.sh_type = SHT_REL; in elf_create_rel_reloc_section()
779 sec->sh.sh_addralign = 8; in elf_create_rel_reloc_section()
780 sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx; in elf_create_rel_reloc_section()
781 sec->sh.sh_info = base->idx; in elf_create_rel_reloc_section()
782 sec->sh.sh_flags = SHF_INFO_LINK; in elf_create_rel_reloc_section()
787 static struct section *elf_create_rela_reloc_section(struct elf *elf, struct section *base) in elf_create_rela_reloc_section()
790 struct section *sec; in elf_create_rela_reloc_section()
792 relocname = malloc(strlen(base->name) + strlen(".rela") + 1); in elf_create_rela_reloc_section()
798 strcat(relocname, base->name); in elf_create_rela_reloc_section()
805 base->reloc = sec; in elf_create_rela_reloc_section()
806 sec->base = base; in elf_create_rela_reloc_section()
808 sec->sh.sh_type = SHT_RELA; in elf_create_rela_reloc_section()
809 sec->sh.sh_addralign = 8; in elf_create_rela_reloc_section()
810 sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx; in elf_create_rela_reloc_section()
811 sec->sh.sh_info = base->idx; in elf_create_rela_reloc_section()
812 sec->sh.sh_flags = SHF_INFO_LINK; in elf_create_rela_reloc_section()
817 struct section *elf_create_reloc_section(struct elf *elf, in elf_create_reloc_section()
818 struct section *base, in elf_create_reloc_section()
828 static int elf_rebuild_rel_reloc_section(struct section *sec, int nr) in elf_rebuild_rel_reloc_section()
839 return -1; in elf_rebuild_rel_reloc_section()
842 sec->data->d_buf = relocs; in elf_rebuild_rel_reloc_section()
843 sec->data->d_size = size; in elf_rebuild_rel_reloc_section()
845 sec->sh.sh_size = size; in elf_rebuild_rel_reloc_section()
848 list_for_each_entry(reloc, &sec->reloc_list, list) { in elf_rebuild_rel_reloc_section()
849 relocs[idx].r_offset = reloc->offset; in elf_rebuild_rel_reloc_section()
850 relocs[idx].r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); in elf_rebuild_rel_reloc_section()
857 static int elf_rebuild_rela_reloc_section(struct section *sec, int nr) in elf_rebuild_rela_reloc_section()
868 return -1; in elf_rebuild_rela_reloc_section()
871 sec->data->d_buf = relocs; in elf_rebuild_rela_reloc_section()
872 sec->data->d_size = size; in elf_rebuild_rela_reloc_section()
874 sec->sh.sh_size = size; in elf_rebuild_rela_reloc_section()
877 list_for_each_entry(reloc, &sec->reloc_list, list) { in elf_rebuild_rela_reloc_section()
878 relocs[idx].r_offset = reloc->offset; in elf_rebuild_rela_reloc_section()
879 relocs[idx].r_addend = reloc->addend; in elf_rebuild_rela_reloc_section()
880 relocs[idx].r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); in elf_rebuild_rela_reloc_section()
887 int elf_rebuild_reloc_section(struct elf *elf, struct section *sec) in elf_rebuild_reloc_section()
892 sec->changed = true; in elf_rebuild_reloc_section()
893 elf->changed = true; in elf_rebuild_reloc_section()
896 list_for_each_entry(reloc, &sec->reloc_list, list) in elf_rebuild_reloc_section()
899 switch (sec->sh.sh_type) { in elf_rebuild_reloc_section()
902 default: return -1; in elf_rebuild_reloc_section()
906 int elf_write_insn(struct elf *elf, struct section *sec, in elf_write_insn()
910 Elf_Data *data = sec->data; in elf_write_insn()
912 if (data->d_type != ELF_T_BYTE || data->d_off) { in elf_write_insn()
913 WARN("write to unexpected data for section: %s", sec->name); in elf_write_insn()
914 return -1; in elf_write_insn()
917 memcpy(data->d_buf + offset, insn, len); in elf_write_insn()
920 elf->changed = true; in elf_write_insn()
927 struct section *sec = reloc->sec; in elf_write_reloc()
929 if (sec->sh.sh_type == SHT_REL) { in elf_write_reloc()
930 reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); in elf_write_reloc()
931 reloc->rel.r_offset = reloc->offset; in elf_write_reloc()
933 if (!gelf_update_rel(sec->data, reloc->idx, &reloc->rel)) { in elf_write_reloc()
935 return -1; in elf_write_reloc()
938 reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); in elf_write_reloc()
939 reloc->rela.r_addend = reloc->addend; in elf_write_reloc()
940 reloc->rela.r_offset = reloc->offset; in elf_write_reloc()
942 if (!gelf_update_rela(sec->data, reloc->idx, &reloc->rela)) { in elf_write_reloc()
944 return -1; in elf_write_reloc()
948 elf->changed = true; in elf_write_reloc()
955 struct section *sec; in elf_write()
958 /* Update section headers for changed sections: */ in elf_write()
959 list_for_each_entry(sec, &elf->sections, list) { in elf_write()
960 if (sec->changed) { in elf_write()
961 s = elf_getscn(elf->elf, sec->idx); in elf_write()
964 return -1; in elf_write()
966 if (!gelf_update_shdr(s, &sec->sh)) { in elf_write()
968 return -1; in elf_write()
971 sec->changed = false; in elf_write()
975 /* Make sure the new section header entries get updated properly. */ in elf_write()
976 elf_flagelf(elf->elf, ELF_C_SET, ELF_F_DIRTY); in elf_write()
979 if (elf_update(elf->elf, ELF_C_WRITE) < 0) { in elf_write()
981 return -1; in elf_write()
984 elf->changed = false; in elf_write()
991 struct section *sec, *tmpsec; in elf_close()
995 if (elf->elf) in elf_close()
996 elf_end(elf->elf); in elf_close()
998 if (elf->fd > 0) in elf_close()
999 close(elf->fd); in elf_close()
1001 list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) { in elf_close()
1002 list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) { in elf_close()
1003 list_del(&sym->list); in elf_close()
1004 hash_del(&sym->hash); in elf_close()
1007 list_for_each_entry_safe(reloc, tmpreloc, &sec->reloc_list, list) { in elf_close()
1008 list_del(&reloc->list); in elf_close()
1009 hash_del(&reloc->hash); in elf_close()
1012 list_del(&sec->list); in elf_close()