]> git.ipfire.org Git - thirdparty/linux.git/blob - tools/objtool/include/objtool/elf.h
be08b32a93ee1ace905dba8828e46b64cd410cf5
[thirdparty/linux.git] / tools / objtool / include / objtool / elf.h
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3 * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com>
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>
12 #include <linux/hashtable.h>
13 #include <linux/rbtree.h>
14 #include <linux/jhash.h>
15 #include <arch/elf.h>
16
17 #ifdef LIBELF_USE_DEPRECATED
18 # define elf_getshdrnum elf_getshnum
19 # define elf_getshdrstrndx elf_getshstrndx
20 #endif
21
22 /*
23 * Fallback for systems without this "read, mmaping if possible" cmd.
24 */
25 #ifndef ELF_C_READ_MMAP
26 #define ELF_C_READ_MMAP ELF_C_READ
27 #endif
28
29 struct section {
30 struct list_head list;
31 struct hlist_node hash;
32 struct hlist_node name_hash;
33 GElf_Shdr sh;
34 struct rb_root_cached symbol_tree;
35 struct list_head symbol_list;
36 struct section *base, *rsec;
37 struct symbol *sym;
38 Elf_Data *data;
39 char *name;
40 int idx;
41 bool _changed, text, rodata, noinstr, init, truncate;
42 struct reloc *relocs;
43 };
44
45 struct symbol {
46 struct list_head list;
47 struct rb_node node;
48 struct hlist_node hash;
49 struct hlist_node name_hash;
50 GElf_Sym sym;
51 struct section *sec;
52 char *name;
53 unsigned int idx, len;
54 unsigned long offset;
55 unsigned long __subtree_last;
56 struct symbol *pfunc, *cfunc, *alias;
57 unsigned char bind, type;
58 u8 uaccess_safe : 1;
59 u8 static_call_tramp : 1;
60 u8 retpoline_thunk : 1;
61 u8 return_thunk : 1;
62 u8 fentry : 1;
63 u8 profiling_func : 1;
64 u8 warned : 1;
65 struct list_head pv_target;
66 struct list_head reloc_list;
67 };
68
69 struct reloc {
70 struct hlist_node hash;
71 union {
72 GElf_Rela rela;
73 GElf_Rel rel;
74 };
75 struct section *sec;
76 struct symbol *sym;
77 struct list_head sym_reloc_entry;
78 bool jump_table_start;
79 };
80
81 struct elf {
82 Elf *elf;
83 GElf_Ehdr ehdr;
84 int fd;
85 bool changed;
86 char *name;
87 unsigned int num_files;
88 struct list_head sections;
89 unsigned long num_relocs;
90
91 int symbol_bits;
92 int symbol_name_bits;
93 int section_bits;
94 int section_name_bits;
95 int reloc_bits;
96
97 struct hlist_head *symbol_hash;
98 struct hlist_head *symbol_name_hash;
99 struct hlist_head *section_hash;
100 struct hlist_head *section_name_hash;
101 struct hlist_head *reloc_hash;
102
103 struct section *section_data;
104 struct symbol *symbol_data;
105 };
106
107 struct elf *elf_open_read(const char *name, int flags);
108
109 struct section *elf_create_section(struct elf *elf, const char *name,
110 size_t entsize, unsigned int nr);
111 struct section *elf_create_section_pair(struct elf *elf, const char *name,
112 size_t entsize, unsigned int nr,
113 unsigned int reloc_nr);
114
115 struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size);
116
117 struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec,
118 unsigned long offset,
119 unsigned int reloc_idx,
120 struct section *insn_sec,
121 unsigned long insn_off);
122
123 struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec,
124 unsigned long offset,
125 unsigned int reloc_idx,
126 struct symbol *sym,
127 s64 addend);
128
129 int elf_write_insn(struct elf *elf, struct section *sec,
130 unsigned long offset, unsigned int len,
131 const char *insn);
132 int elf_write_reloc(struct elf *elf, struct reloc *reloc);
133 int elf_write(struct elf *elf);
134 void elf_close(struct elf *elf);
135
136 struct section *find_section_by_name(const struct elf *elf, const char *name);
137 struct symbol *find_func_by_offset(struct section *sec, unsigned long offset);
138 struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
139 struct symbol *find_symbol_by_name(const struct elf *elf, const char *name);
140 struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset);
141 int find_symbol_hole_containing(const struct section *sec, unsigned long offset);
142 struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset);
143 struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
144 unsigned long offset, unsigned int len);
145 struct symbol *find_func_containing(struct section *sec, unsigned long offset);
146
147 /*
148 * Try to see if it's a whole archive (vmlinux.o or module).
149 *
150 * Note this will miss the case where a module only has one source file.
151 */
152 static inline bool has_multiple_files(struct elf *elf)
153 {
154 return elf->num_files > 1;
155 }
156
157 static inline size_t elf_addr_size(struct elf *elf)
158 {
159 return elf->ehdr.e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
160 }
161
162 static inline size_t elf_rela_size(struct elf *elf)
163 {
164 return elf_addr_size(elf) == 4 ? sizeof(Elf32_Rela) : sizeof(Elf64_Rela);
165 }
166
167 static inline unsigned int elf_data_rela_type(struct elf *elf)
168 {
169 return elf_addr_size(elf) == 4 ? R_DATA32 : R_DATA64;
170 }
171
172 static inline unsigned int elf_text_rela_type(struct elf *elf)
173 {
174 return elf_addr_size(elf) == 4 ? R_TEXT32 : R_TEXT64;
175 }
176
177 static inline bool is_reloc_sec(struct section *sec)
178 {
179 return sec->sh.sh_type == SHT_RELA || sec->sh.sh_type == SHT_REL;
180 }
181
182 static inline bool sec_changed(struct section *sec)
183 {
184 return sec->_changed;
185 }
186
187 static inline void mark_sec_changed(struct elf *elf, struct section *sec,
188 bool changed)
189 {
190 sec->_changed = changed;
191 elf->changed |= changed;
192 }
193
194 static inline unsigned int sec_num_entries(struct section *sec)
195 {
196 return sec->sh.sh_size / sec->sh.sh_entsize;
197 }
198
199 static inline unsigned int reloc_idx(struct reloc *reloc)
200 {
201 return reloc - reloc->sec->relocs;
202 }
203
204 static inline unsigned long reloc_offset(struct reloc *reloc)
205 {
206 return reloc->rel.r_offset;
207 }
208
209 static inline unsigned int reloc_type(struct reloc *reloc)
210 {
211 return GELF_R_TYPE(reloc->rel.r_info);
212 }
213
214 static inline void set_reloc_type(struct reloc *reloc, int type)
215 {
216 reloc->rel.r_info = GELF_R_INFO(GELF_R_SYM(reloc->rel.r_info), type);
217 }
218
219 static inline s64 reloc_addend(struct reloc *reloc)
220 {
221 return reloc->rela.r_addend;
222 }
223
224 #define for_each_sec(file, sec) \
225 list_for_each_entry(sec, &file->elf->sections, list)
226
227 #define sec_for_each_sym(sec, sym) \
228 list_for_each_entry(sym, &sec->symbol_list, list)
229
230 #define for_each_sym(file, sym) \
231 for (struct section *__sec, *__fake = (struct section *)1; \
232 __fake; __fake = NULL) \
233 for_each_sec(file, __sec) \
234 sec_for_each_sym(__sec, sym)
235
236 #define for_each_reloc(rsec, reloc) \
237 for (int __i = 0, __fake = 1; __fake; __fake = 0) \
238 for (reloc = rsec->relocs; \
239 __i < sec_num_entries(rsec); \
240 __i++, reloc++)
241
242 #define for_each_reloc_from(rsec, reloc) \
243 for (int __i = reloc_idx(reloc); \
244 __i < sec_num_entries(rsec); \
245 __i++, reloc++)
246
247 #define OFFSET_STRIDE_BITS 4
248 #define OFFSET_STRIDE (1UL << OFFSET_STRIDE_BITS)
249 #define OFFSET_STRIDE_MASK (~(OFFSET_STRIDE - 1))
250
251 #define for_offset_range(_offset, _start, _end) \
252 for (_offset = ((_start) & OFFSET_STRIDE_MASK); \
253 _offset >= ((_start) & OFFSET_STRIDE_MASK) && \
254 _offset <= ((_end) & OFFSET_STRIDE_MASK); \
255 _offset += OFFSET_STRIDE)
256
257 static inline u32 sec_offset_hash(struct section *sec, unsigned long offset)
258 {
259 u32 ol, oh, idx = sec->idx;
260
261 offset &= OFFSET_STRIDE_MASK;
262
263 ol = offset;
264 oh = (offset >> 16) >> 16;
265
266 __jhash_mix(ol, oh, idx);
267
268 return ol;
269 }
270
271 static inline u32 reloc_hash(struct reloc *reloc)
272 {
273 return sec_offset_hash(reloc->sec, reloc_offset(reloc));
274 }
275
276 #endif /* _OBJTOOL_ELF_H */