Thomas Gleixner | 1ccea77 | 2019-05-19 15:51:43 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 2 | /* |
| 3 | * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 4 | */ |
| 5 | |
| 6 | #ifndef _OBJTOOL_ELF_H |
| 7 | #define _OBJTOOL_ELF_H |
| 8 | |
| 9 | #include <stdio.h> |
| 10 | #include <gelf.h> |
| 11 | #include <linux/list.h> |
Josh Poimboeuf | 042ba73 | 2016-03-09 00:07:00 -0600 | [diff] [blame] | 12 | #include <linux/hashtable.h> |
Peter Zijlstra | 2a362ec | 2020-03-12 09:34:42 +0100 | [diff] [blame] | 13 | #include <linux/rbtree.h> |
Peter Zijlstra | ae35819 | 2020-03-12 09:32:10 +0100 | [diff] [blame] | 14 | #include <linux/jhash.h> |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 15 | |
Jan Beulich | 2e51f26 | 2016-05-16 15:31:07 -0500 | [diff] [blame] | 16 | #ifdef LIBELF_USE_DEPRECATED |
| 17 | # define elf_getshdrnum elf_getshnum |
| 18 | # define elf_getshdrstrndx elf_getshstrndx |
| 19 | #endif |
| 20 | |
Josh Poimboeuf | 627fce1 | 2017-07-11 10:33:42 -0500 | [diff] [blame] | 21 | /* |
| 22 | * Fallback for systems without this "read, mmaping if possible" cmd. |
| 23 | */ |
| 24 | #ifndef ELF_C_READ_MMAP |
| 25 | #define ELF_C_READ_MMAP ELF_C_READ |
| 26 | #endif |
| 27 | |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 28 | struct section { |
| 29 | struct list_head list; |
Peter Zijlstra | 53038996 | 2020-03-10 18:43:35 +0100 | [diff] [blame] | 30 | struct hlist_node hash; |
Peter Zijlstra | ae35819 | 2020-03-12 09:32:10 +0100 | [diff] [blame] | 31 | struct hlist_node name_hash; |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 32 | GElf_Shdr sh; |
Peter Zijlstra | 2a362ec | 2020-03-12 09:34:42 +0100 | [diff] [blame] | 33 | struct rb_root symbol_tree; |
Josh Poimboeuf | a196e17 | 2016-03-09 00:06:57 -0600 | [diff] [blame] | 34 | struct list_head symbol_list; |
| 35 | struct list_head rela_list; |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 36 | struct section *base, *rela; |
| 37 | struct symbol *sym; |
Josh Poimboeuf | baa4146 | 2017-06-28 10:11:07 -0500 | [diff] [blame] | 38 | Elf_Data *data; |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 39 | char *name; |
| 40 | int idx; |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 41 | unsigned int len; |
Peter Zijlstra | c4a3393 | 2020-03-10 18:57:41 +0100 | [diff] [blame] | 42 | bool changed, text, rodata, noinstr; |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 43 | }; |
| 44 | |
| 45 | struct symbol { |
| 46 | struct list_head list; |
Peter Zijlstra | 2a362ec | 2020-03-12 09:34:42 +0100 | [diff] [blame] | 47 | struct rb_node node; |
Josh Poimboeuf | 042ba73 | 2016-03-09 00:07:00 -0600 | [diff] [blame] | 48 | struct hlist_node hash; |
Peter Zijlstra | cdb3d05 | 2020-03-12 10:17:38 +0100 | [diff] [blame] | 49 | struct hlist_node name_hash; |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 50 | GElf_Sym sym; |
| 51 | struct section *sec; |
| 52 | char *name; |
Josh Poimboeuf | 042ba73 | 2016-03-09 00:07:00 -0600 | [diff] [blame] | 53 | unsigned int idx; |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 54 | unsigned char bind, type; |
| 55 | unsigned long offset; |
| 56 | unsigned int len; |
Peter Zijlstra | 09f30d8 | 2019-02-28 14:17:50 +0100 | [diff] [blame] | 57 | struct symbol *pfunc, *cfunc, *alias; |
Peter Zijlstra | ea24213 | 2019-02-25 12:50:09 +0100 | [diff] [blame] | 58 | bool uaccess_safe; |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 59 | }; |
| 60 | |
| 61 | struct rela { |
| 62 | struct list_head list; |
Josh Poimboeuf | 042ba73 | 2016-03-09 00:07:00 -0600 | [diff] [blame] | 63 | struct hlist_node hash; |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 64 | GElf_Rela rela; |
Josh Poimboeuf | e7c2bc3 | 2019-07-17 20:36:53 -0500 | [diff] [blame] | 65 | struct section *sec; |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 66 | struct symbol *sym; |
| 67 | unsigned int type; |
Josh Poimboeuf | 042ba73 | 2016-03-09 00:07:00 -0600 | [diff] [blame] | 68 | unsigned long offset; |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 69 | int addend; |
Jann Horn | bd98c81 | 2019-07-17 20:36:54 -0500 | [diff] [blame] | 70 | bool jump_table_start; |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 71 | }; |
| 72 | |
Peter Zijlstra | 34f7c96 | 2020-03-12 14:29:38 +0100 | [diff] [blame] | 73 | #define ELF_HASH_BITS 20 |
| 74 | |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 75 | struct elf { |
| 76 | Elf *elf; |
| 77 | GElf_Ehdr ehdr; |
| 78 | int fd; |
| 79 | char *name; |
| 80 | struct list_head sections; |
Peter Zijlstra | 34f7c96 | 2020-03-12 14:29:38 +0100 | [diff] [blame] | 81 | DECLARE_HASHTABLE(symbol_hash, ELF_HASH_BITS); |
| 82 | DECLARE_HASHTABLE(symbol_name_hash, ELF_HASH_BITS); |
| 83 | DECLARE_HASHTABLE(section_hash, ELF_HASH_BITS); |
| 84 | DECLARE_HASHTABLE(section_name_hash, ELF_HASH_BITS); |
| 85 | DECLARE_HASHTABLE(rela_hash, ELF_HASH_BITS); |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 86 | }; |
| 87 | |
Peter Zijlstra | 74b873e | 2020-03-12 11:30:50 +0100 | [diff] [blame] | 88 | #define OFFSET_STRIDE_BITS 4 |
| 89 | #define OFFSET_STRIDE (1UL << OFFSET_STRIDE_BITS) |
| 90 | #define OFFSET_STRIDE_MASK (~(OFFSET_STRIDE - 1)) |
| 91 | |
Josh Poimboeuf | 53fb6e9 | 2020-04-25 14:19:01 -0500 | [diff] [blame] | 92 | #define for_offset_range(_offset, _start, _end) \ |
| 93 | for (_offset = ((_start) & OFFSET_STRIDE_MASK); \ |
| 94 | _offset >= ((_start) & OFFSET_STRIDE_MASK) && \ |
| 95 | _offset <= ((_end) & OFFSET_STRIDE_MASK); \ |
Peter Zijlstra | 74b873e | 2020-03-12 11:30:50 +0100 | [diff] [blame] | 96 | _offset += OFFSET_STRIDE) |
| 97 | |
Peter Zijlstra | 8b5fa6b | 2020-03-12 11:23:36 +0100 | [diff] [blame] | 98 | static inline u32 sec_offset_hash(struct section *sec, unsigned long offset) |
| 99 | { |
Peter Zijlstra | 74b873e | 2020-03-12 11:30:50 +0100 | [diff] [blame] | 100 | u32 ol, oh, idx = sec->idx; |
| 101 | |
| 102 | offset &= OFFSET_STRIDE_MASK; |
| 103 | |
| 104 | ol = offset; |
Peter Zijlstra | 963d566 | 2020-04-20 10:33:32 +0200 | [diff] [blame] | 105 | oh = (offset >> 16) >> 16; |
Peter Zijlstra | 8b5fa6b | 2020-03-12 11:23:36 +0100 | [diff] [blame] | 106 | |
| 107 | __jhash_mix(ol, oh, idx); |
| 108 | |
| 109 | return ol; |
| 110 | } |
| 111 | |
| 112 | static inline u32 rela_hash(struct rela *rela) |
| 113 | { |
| 114 | return sec_offset_hash(rela->sec, rela->offset); |
| 115 | } |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 116 | |
Ingo Molnar | bc359ff | 2020-04-22 12:32:04 +0200 | [diff] [blame] | 117 | struct elf *elf_open_read(const char *name, int flags); |
Ingo Molnar | 894e48c | 2020-04-22 12:32:03 +0200 | [diff] [blame] | 118 | struct section *elf_create_section(struct elf *elf, const char *name, size_t entsize, int nr); |
| 119 | struct section *elf_create_rela_section(struct elf *elf, struct section *base); |
| 120 | void elf_add_rela(struct elf *elf, struct rela *rela); |
| 121 | int elf_write(const struct elf *elf); |
| 122 | void elf_close(struct elf *elf); |
| 123 | |
| 124 | struct section *find_section_by_name(const struct elf *elf, const char *name); |
Josh Poimboeuf | 7acfe53 | 2020-02-17 21:41:54 -0600 | [diff] [blame] | 125 | struct symbol *find_func_by_offset(struct section *sec, unsigned long offset); |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 126 | struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); |
Ingo Molnar | 894e48c | 2020-04-22 12:32:03 +0200 | [diff] [blame] | 127 | struct symbol *find_symbol_by_name(const struct elf *elf, const char *name); |
Miroslav Benes | b490f45 | 2020-04-24 16:30:42 +0200 | [diff] [blame] | 128 | struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset); |
Ingo Molnar | 894e48c | 2020-04-22 12:32:03 +0200 | [diff] [blame] | 129 | struct rela *find_rela_by_dest(const struct elf *elf, struct section *sec, unsigned long offset); |
| 130 | struct rela *find_rela_by_dest_range(const struct elf *elf, struct section *sec, |
Peter Zijlstra | 8b5fa6b | 2020-03-12 11:23:36 +0100 | [diff] [blame] | 131 | unsigned long offset, unsigned int len); |
Peter Zijlstra | 53d2072 | 2020-03-16 10:36:53 +0100 | [diff] [blame] | 132 | struct symbol *find_func_containing(struct section *sec, unsigned long offset); |
Josh Poimboeuf | 627fce1 | 2017-07-11 10:33:42 -0500 | [diff] [blame] | 133 | int elf_rebuild_rela_section(struct section *sec); |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 134 | |
Josh Poimboeuf | baa4146 | 2017-06-28 10:11:07 -0500 | [diff] [blame] | 135 | #define for_each_sec(file, sec) \ |
| 136 | list_for_each_entry(sec, &file->elf->sections, list) |
Josh Poimboeuf | 442f04c | 2016-02-28 22:22:41 -0600 | [diff] [blame] | 137 | |
| 138 | #endif /* _OBJTOOL_ELF_H */ |