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 elf_hash_node {
30 struct elf_hash_node *next;
31 };
32
33 struct section {
34 struct list_head list;
35 struct elf_hash_node hash;
36 struct elf_hash_node name_hash;
37 GElf_Shdr sh;
38 struct rb_root_cached symbol_tree;
39 struct list_head symbol_list;
40 struct section *base, *rsec;
41 struct symbol *sym;
42 Elf_Data *data;
43 char *name;
44 int idx;
45 bool _changed, text, rodata, noinstr, init, truncate;
46 struct reloc *relocs;
47 };
48
49 struct symbol {
50 struct list_head list;
51 struct rb_node node;
52 struct elf_hash_node hash;
53 struct elf_hash_node name_hash;
54 GElf_Sym sym;
55 struct section *sec;
56 char *name;
57 unsigned int idx, len;
58 unsigned long offset;
59 unsigned long __subtree_last;
60 struct symbol *pfunc, *cfunc, *alias;
61 unsigned char bind, type;
62 u8 uaccess_safe : 1;
63 u8 static_call_tramp : 1;
64 u8 retpoline_thunk : 1;
65 u8 return_thunk : 1;
66 u8 fentry : 1;
67 u8 profiling_func : 1;
68 u8 warned : 1;
69 u8 embedded_insn : 1;
70 u8 local_label : 1;
71 u8 frame_pointer : 1;
72 u8 ignore : 1;
73 u8 nocfi : 1;
74 struct list_head pv_target;
75 struct reloc *relocs;
76 struct section *group_sec;
77 };
78
79 struct reloc {
80 struct elf_hash_node hash;
81 struct section *sec;
82 struct symbol *sym;
83 unsigned long _sym_next_reloc;
84 };
85
86 struct elf {
87 Elf *elf;
88 GElf_Ehdr ehdr;
89 int fd;
90 bool changed;
91 char *name;
92 unsigned int num_files;
93 struct list_head sections;
94 unsigned long num_relocs;
95
96 int symbol_bits;
97 int symbol_name_bits;
98 int section_bits;
99 int section_name_bits;
100 int reloc_bits;
101
102 struct elf_hash_node **symbol_hash;
103 struct elf_hash_node **symbol_name_hash;
104 struct elf_hash_node **section_hash;
105 struct elf_hash_node **section_name_hash;
106 struct elf_hash_node **reloc_hash;
107
108 struct section *section_data;
109 struct symbol *symbol_data;
110 };
111
112 struct elf *elf_open_read(const char *name, int flags);
113
114 struct section *elf_create_section(struct elf *elf, const char *name,
115 size_t entsize, unsigned int nr);
116 struct section *elf_create_section_pair(struct elf *elf, const char *name,
117 size_t entsize, unsigned int nr,
118 unsigned int reloc_nr);
119
120 struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size);
121
122 struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec,
123 unsigned long offset,
124 unsigned int reloc_idx,
125 struct section *insn_sec,
126 unsigned long insn_off);
127
128 struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec,
129 unsigned long offset,
130 unsigned int reloc_idx,
131 struct symbol *sym,
132 s64 addend);
133
134 int elf_write_insn(struct elf *elf, struct section *sec,
135 unsigned long offset, unsigned int len,
136 const char *insn);
137 int elf_write(struct elf *elf);
138 void elf_close(struct elf *elf);
139
140 struct section *find_section_by_name(const struct elf *elf, const char *name);
141 struct symbol *find_func_by_offset(struct section *sec, unsigned long offset);
142 struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
143 struct symbol *find_symbol_by_name(const struct elf *elf, const char *name);
144 struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset);
145 int find_symbol_hole_containing(const struct section *sec, unsigned long offset);
146 struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset);
147 struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
148 unsigned long offset, unsigned int len);
149 struct symbol *find_func_containing(struct section *sec, unsigned long offset);
150
151 /*
152 * Try to see if it's a whole archive (vmlinux.o or module).
153 *
154 * Note this will miss the case where a module only has one source file.
155 */
has_multiple_files(struct elf * elf)156 static inline bool has_multiple_files(struct elf *elf)
157 {
158 return elf->num_files > 1;
159 }
160
elf_addr_size(struct elf * elf)161 static inline size_t elf_addr_size(struct elf *elf)
162 {
163 return elf->ehdr.e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
164 }
165
elf_rela_size(struct elf * elf)166 static inline size_t elf_rela_size(struct elf *elf)
167 {
168 return elf_addr_size(elf) == 4 ? sizeof(Elf32_Rela) : sizeof(Elf64_Rela);
169 }
170
elf_data_rela_type(struct elf * elf)171 static inline unsigned int elf_data_rela_type(struct elf *elf)
172 {
173 return elf_addr_size(elf) == 4 ? R_DATA32 : R_DATA64;
174 }
175
elf_text_rela_type(struct elf * elf)176 static inline unsigned int elf_text_rela_type(struct elf *elf)
177 {
178 return elf_addr_size(elf) == 4 ? R_TEXT32 : R_TEXT64;
179 }
180
is_reloc_sec(struct section * sec)181 static inline bool is_reloc_sec(struct section *sec)
182 {
183 return sec->sh.sh_type == SHT_RELA || sec->sh.sh_type == SHT_REL;
184 }
185
sec_changed(struct section * sec)186 static inline bool sec_changed(struct section *sec)
187 {
188 return sec->_changed;
189 }
190
mark_sec_changed(struct elf * elf,struct section * sec,bool changed)191 static inline void mark_sec_changed(struct elf *elf, struct section *sec,
192 bool changed)
193 {
194 sec->_changed = changed;
195 elf->changed |= changed;
196 }
197
sec_num_entries(struct section * sec)198 static inline unsigned int sec_num_entries(struct section *sec)
199 {
200 return sec->sh.sh_size / sec->sh.sh_entsize;
201 }
202
reloc_idx(struct reloc * reloc)203 static inline unsigned int reloc_idx(struct reloc *reloc)
204 {
205 return reloc - reloc->sec->relocs;
206 }
207
reloc_rel(struct reloc * reloc)208 static inline void *reloc_rel(struct reloc *reloc)
209 {
210 struct section *rsec = reloc->sec;
211
212 return rsec->data->d_buf + (reloc_idx(reloc) * rsec->sh.sh_entsize);
213 }
214
is_32bit_reloc(struct reloc * reloc)215 static inline bool is_32bit_reloc(struct reloc *reloc)
216 {
217 /*
218 * Elf32_Rel: 8 bytes
219 * Elf32_Rela: 12 bytes
220 * Elf64_Rel: 16 bytes
221 * Elf64_Rela: 24 bytes
222 */
223 return reloc->sec->sh.sh_entsize < 16;
224 }
225
226 #define __get_reloc_field(reloc, field) \
227 ({ \
228 is_32bit_reloc(reloc) ? \
229 ((Elf32_Rela *)reloc_rel(reloc))->field : \
230 ((Elf64_Rela *)reloc_rel(reloc))->field; \
231 })
232
233 #define __set_reloc_field(reloc, field, val) \
234 ({ \
235 if (is_32bit_reloc(reloc)) \
236 ((Elf32_Rela *)reloc_rel(reloc))->field = val; \
237 else \
238 ((Elf64_Rela *)reloc_rel(reloc))->field = val; \
239 })
240
reloc_offset(struct reloc * reloc)241 static inline u64 reloc_offset(struct reloc *reloc)
242 {
243 return __get_reloc_field(reloc, r_offset);
244 }
245
set_reloc_offset(struct elf * elf,struct reloc * reloc,u64 offset)246 static inline void set_reloc_offset(struct elf *elf, struct reloc *reloc, u64 offset)
247 {
248 __set_reloc_field(reloc, r_offset, offset);
249 mark_sec_changed(elf, reloc->sec, true);
250 }
251
reloc_addend(struct reloc * reloc)252 static inline s64 reloc_addend(struct reloc *reloc)
253 {
254 return __get_reloc_field(reloc, r_addend);
255 }
256
set_reloc_addend(struct elf * elf,struct reloc * reloc,s64 addend)257 static inline void set_reloc_addend(struct elf *elf, struct reloc *reloc, s64 addend)
258 {
259 __set_reloc_field(reloc, r_addend, addend);
260 mark_sec_changed(elf, reloc->sec, true);
261 }
262
263
reloc_sym(struct reloc * reloc)264 static inline unsigned int reloc_sym(struct reloc *reloc)
265 {
266 u64 info = __get_reloc_field(reloc, r_info);
267
268 return is_32bit_reloc(reloc) ?
269 ELF32_R_SYM(info) :
270 ELF64_R_SYM(info);
271 }
272
reloc_type(struct reloc * reloc)273 static inline unsigned int reloc_type(struct reloc *reloc)
274 {
275 u64 info = __get_reloc_field(reloc, r_info);
276
277 return is_32bit_reloc(reloc) ?
278 ELF32_R_TYPE(info) :
279 ELF64_R_TYPE(info);
280 }
281
set_reloc_sym(struct elf * elf,struct reloc * reloc,unsigned int sym)282 static inline void set_reloc_sym(struct elf *elf, struct reloc *reloc, unsigned int sym)
283 {
284 u64 info = is_32bit_reloc(reloc) ?
285 ELF32_R_INFO(sym, reloc_type(reloc)) :
286 ELF64_R_INFO(sym, reloc_type(reloc));
287
288 __set_reloc_field(reloc, r_info, info);
289
290 mark_sec_changed(elf, reloc->sec, true);
291 }
set_reloc_type(struct elf * elf,struct reloc * reloc,unsigned int type)292 static inline void set_reloc_type(struct elf *elf, struct reloc *reloc, unsigned int type)
293 {
294 u64 info = is_32bit_reloc(reloc) ?
295 ELF32_R_INFO(reloc_sym(reloc), type) :
296 ELF64_R_INFO(reloc_sym(reloc), type);
297
298 __set_reloc_field(reloc, r_info, info);
299
300 mark_sec_changed(elf, reloc->sec, true);
301 }
302
303 #define RELOC_JUMP_TABLE_BIT 1UL
304
305 /* Does reloc mark the beginning of a jump table? */
is_jump_table(struct reloc * reloc)306 static inline bool is_jump_table(struct reloc *reloc)
307 {
308 return reloc->_sym_next_reloc & RELOC_JUMP_TABLE_BIT;
309 }
310
set_jump_table(struct reloc * reloc)311 static inline void set_jump_table(struct reloc *reloc)
312 {
313 reloc->_sym_next_reloc |= RELOC_JUMP_TABLE_BIT;
314 }
315
sym_next_reloc(struct reloc * reloc)316 static inline struct reloc *sym_next_reloc(struct reloc *reloc)
317 {
318 return (struct reloc *)(reloc->_sym_next_reloc & ~RELOC_JUMP_TABLE_BIT);
319 }
320
set_sym_next_reloc(struct reloc * reloc,struct reloc * next)321 static inline void set_sym_next_reloc(struct reloc *reloc, struct reloc *next)
322 {
323 unsigned long bit = reloc->_sym_next_reloc & RELOC_JUMP_TABLE_BIT;
324
325 reloc->_sym_next_reloc = (unsigned long)next | bit;
326 }
327
328 #define for_each_sec(file, sec) \
329 list_for_each_entry(sec, &file->elf->sections, list)
330
331 #define sec_for_each_sym(sec, sym) \
332 list_for_each_entry(sym, &sec->symbol_list, list)
333
334 #define for_each_sym(file, sym) \
335 for (struct section *__sec, *__fake = (struct section *)1; \
336 __fake; __fake = NULL) \
337 for_each_sec(file, __sec) \
338 sec_for_each_sym(__sec, sym)
339
340 #define for_each_reloc(rsec, reloc) \
341 for (int __i = 0, __fake = 1; __fake; __fake = 0) \
342 for (reloc = rsec->relocs; \
343 __i < sec_num_entries(rsec); \
344 __i++, reloc++)
345
346 #define for_each_reloc_from(rsec, reloc) \
347 for (int __i = reloc_idx(reloc); \
348 __i < sec_num_entries(rsec); \
349 __i++, reloc++)
350
351 #define OFFSET_STRIDE_BITS 4
352 #define OFFSET_STRIDE (1UL << OFFSET_STRIDE_BITS)
353 #define OFFSET_STRIDE_MASK (~(OFFSET_STRIDE - 1))
354
355 #define for_offset_range(_offset, _start, _end) \
356 for (_offset = ((_start) & OFFSET_STRIDE_MASK); \
357 _offset >= ((_start) & OFFSET_STRIDE_MASK) && \
358 _offset <= ((_end) & OFFSET_STRIDE_MASK); \
359 _offset += OFFSET_STRIDE)
360
sec_offset_hash(struct section * sec,unsigned long offset)361 static inline u32 sec_offset_hash(struct section *sec, unsigned long offset)
362 {
363 u32 ol, oh, idx = sec->idx;
364
365 offset &= OFFSET_STRIDE_MASK;
366
367 ol = offset;
368 oh = (offset >> 16) >> 16;
369
370 __jhash_mix(ol, oh, idx);
371
372 return ol;
373 }
374
reloc_hash(struct reloc * reloc)375 static inline u32 reloc_hash(struct reloc *reloc)
376 {
377 return sec_offset_hash(reloc->sec, reloc_offset(reloc));
378 }
379
380 #endif /* _OBJTOOL_ELF_H */
381