Commit | Line | Data |
---|---|---|
1ccea77e | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
442f04c3 JP |
2 | /* |
3 | * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> | |
442f04c3 JP |
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> | |
042ba73f | 12 | #include <linux/hashtable.h> |
2a362ecc | 13 | #include <linux/rbtree.h> |
ae358196 | 14 | #include <linux/jhash.h> |
442f04c3 | 15 | |
2e51f262 JB |
16 | #ifdef LIBELF_USE_DEPRECATED |
17 | # define elf_getshdrnum elf_getshnum | |
18 | # define elf_getshdrstrndx elf_getshstrndx | |
19 | #endif | |
20 | ||
627fce14 JP |
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 | ||
442f04c3 JP |
28 | struct section { |
29 | struct list_head list; | |
53038996 | 30 | struct hlist_node hash; |
ae358196 | 31 | struct hlist_node name_hash; |
442f04c3 | 32 | GElf_Shdr sh; |
2a362ecc | 33 | struct rb_root symbol_tree; |
a196e171 | 34 | struct list_head symbol_list; |
f1974222 MH |
35 | struct list_head reloc_list; |
36 | struct section *base, *reloc; | |
442f04c3 | 37 | struct symbol *sym; |
baa41469 | 38 | Elf_Data *data; |
442f04c3 JP |
39 | char *name; |
40 | int idx; | |
c4a33939 | 41 | bool changed, text, rodata, noinstr; |
442f04c3 JP |
42 | }; |
43 | ||
44 | struct symbol { | |
45 | struct list_head list; | |
2a362ecc | 46 | struct rb_node node; |
042ba73f | 47 | struct hlist_node hash; |
cdb3d057 | 48 | struct hlist_node name_hash; |
442f04c3 JP |
49 | GElf_Sym sym; |
50 | struct section *sec; | |
51 | char *name; | |
042ba73f | 52 | unsigned int idx; |
442f04c3 JP |
53 | unsigned char bind, type; |
54 | unsigned long offset; | |
55 | unsigned int len; | |
09f30d83 | 56 | struct symbol *pfunc, *cfunc, *alias; |
1739c66e PZ |
57 | u8 uaccess_safe : 1; |
58 | u8 static_call_tramp : 1; | |
59 | u8 retpoline_thunk : 1; | |
d9e9d230 | 60 | u8 return_thunk : 1; |
1739c66e | 61 | u8 fentry : 1; |
05098119 | 62 | u8 profiling_func : 1; |
db2b0c5d | 63 | struct list_head pv_target; |
442f04c3 JP |
64 | }; |
65 | ||
f1974222 | 66 | struct reloc { |
442f04c3 | 67 | struct list_head list; |
042ba73f | 68 | struct hlist_node hash; |
fb414783 MH |
69 | union { |
70 | GElf_Rela rela; | |
71 | GElf_Rel rel; | |
72 | }; | |
e7c2bc37 | 73 | struct section *sec; |
442f04c3 | 74 | struct symbol *sym; |
042ba73f | 75 | unsigned long offset; |
fdabdd0b | 76 | unsigned int type; |
22682a07 | 77 | s64 addend; |
fdabdd0b | 78 | int idx; |
bd98c813 | 79 | bool jump_table_start; |
442f04c3 JP |
80 | }; |
81 | ||
34f7c96d PZ |
82 | #define ELF_HASH_BITS 20 |
83 | ||
442f04c3 JP |
84 | struct elf { |
85 | Elf *elf; | |
86 | GElf_Ehdr ehdr; | |
87 | int fd; | |
2b10be23 | 88 | bool changed; |
442f04c3 | 89 | char *name; |
753da417 | 90 | unsigned int text_size, num_files; |
442f04c3 | 91 | struct list_head sections; |
25cf0d8a PZ |
92 | |
93 | int symbol_bits; | |
94 | int symbol_name_bits; | |
95 | int section_bits; | |
96 | int section_name_bits; | |
97 | int reloc_bits; | |
98 | ||
99 | struct hlist_head *symbol_hash; | |
100 | struct hlist_head *symbol_name_hash; | |
101 | struct hlist_head *section_hash; | |
102 | struct hlist_head *section_name_hash; | |
103 | struct hlist_head *reloc_hash; | |
442f04c3 JP |
104 | }; |
105 | ||
74b873e4 PZ |
106 | #define OFFSET_STRIDE_BITS 4 |
107 | #define OFFSET_STRIDE (1UL << OFFSET_STRIDE_BITS) | |
108 | #define OFFSET_STRIDE_MASK (~(OFFSET_STRIDE - 1)) | |
109 | ||
53fb6e99 JP |
110 | #define for_offset_range(_offset, _start, _end) \ |
111 | for (_offset = ((_start) & OFFSET_STRIDE_MASK); \ | |
112 | _offset >= ((_start) & OFFSET_STRIDE_MASK) && \ | |
113 | _offset <= ((_end) & OFFSET_STRIDE_MASK); \ | |
74b873e4 PZ |
114 | _offset += OFFSET_STRIDE) |
115 | ||
8b5fa6bc PZ |
116 | static inline u32 sec_offset_hash(struct section *sec, unsigned long offset) |
117 | { | |
74b873e4 PZ |
118 | u32 ol, oh, idx = sec->idx; |
119 | ||
120 | offset &= OFFSET_STRIDE_MASK; | |
121 | ||
122 | ol = offset; | |
963d5669 | 123 | oh = (offset >> 16) >> 16; |
8b5fa6bc PZ |
124 | |
125 | __jhash_mix(ol, oh, idx); | |
126 | ||
127 | return ol; | |
128 | } | |
129 | ||
f1974222 | 130 | static inline u32 reloc_hash(struct reloc *reloc) |
8b5fa6bc | 131 | { |
f1974222 | 132 | return sec_offset_hash(reloc->sec, reloc->offset); |
8b5fa6bc | 133 | } |
442f04c3 | 134 | |
753da417 JP |
135 | /* |
136 | * Try to see if it's a whole archive (vmlinux.o or module). | |
137 | * | |
138 | * Note this will miss the case where a module only has one source file. | |
139 | */ | |
140 | static inline bool has_multiple_files(struct elf *elf) | |
141 | { | |
142 | return elf->num_files > 1; | |
143 | } | |
144 | ||
bc359ff2 | 145 | struct elf *elf_open_read(const char *name, int flags); |
1e7e4788 | 146 | struct section *elf_create_section(struct elf *elf, const char *name, unsigned int sh_flags, size_t entsize, int nr); |
ef47cc01 PZ |
147 | |
148 | int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset, | |
22682a07 | 149 | unsigned int type, struct symbol *sym, s64 addend); |
ef47cc01 PZ |
150 | int elf_add_reloc_to_insn(struct elf *elf, struct section *sec, |
151 | unsigned long offset, unsigned int type, | |
152 | struct section *insn_sec, unsigned long insn_off); | |
153 | ||
fdabdd0b PZ |
154 | int elf_write_insn(struct elf *elf, struct section *sec, |
155 | unsigned long offset, unsigned int len, | |
156 | const char *insn); | |
d832c005 | 157 | int elf_write_reloc(struct elf *elf, struct reloc *reloc); |
2b10be23 | 158 | int elf_write(struct elf *elf); |
894e48ca IM |
159 | void elf_close(struct elf *elf); |
160 | ||
161 | struct section *find_section_by_name(const struct elf *elf, const char *name); | |
7acfe531 | 162 | struct symbol *find_func_by_offset(struct section *sec, unsigned long offset); |
442f04c3 | 163 | struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); |
894e48ca | 164 | struct symbol *find_symbol_by_name(const struct elf *elf, const char *name); |
b490f453 | 165 | struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset); |
4adb2368 | 166 | int find_symbol_hole_containing(const struct section *sec, unsigned long offset); |
f1974222 MH |
167 | struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset); |
168 | struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec, | |
8b5fa6bc | 169 | unsigned long offset, unsigned int len); |
53d20720 | 170 | struct symbol *find_func_containing(struct section *sec, unsigned long offset); |
442f04c3 | 171 | |
baa41469 JP |
172 | #define for_each_sec(file, sec) \ |
173 | list_for_each_entry(sec, &file->elf->sections, list) | |
442f04c3 JP |
174 | |
175 | #endif /* _OBJTOOL_ELF_H */ |