Merge tag 'drm-misc-next-fixes-2023-09-01' of git://anongit.freedesktop.org/drm/drm...
[platform/kernel/linux-rpi.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 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         struct list_head pv_target;
71         struct reloc *relocs;
72 };
73
74 struct reloc {
75         struct elf_hash_node hash;
76         struct section *sec;
77         struct symbol *sym;
78         struct reloc *sym_next_reloc;
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 elf_hash_node **symbol_hash;
98         struct elf_hash_node **symbol_name_hash;
99         struct elf_hash_node **section_hash;
100         struct elf_hash_node **section_name_hash;
101         struct elf_hash_node **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(struct elf *elf);
133 void elf_close(struct elf *elf);
134
135 struct section *find_section_by_name(const struct elf *elf, const char *name);
136 struct symbol *find_func_by_offset(struct section *sec, unsigned long offset);
137 struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
138 struct symbol *find_symbol_by_name(const struct elf *elf, const char *name);
139 struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset);
140 int find_symbol_hole_containing(const struct section *sec, unsigned long offset);
141 struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset);
142 struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
143                                      unsigned long offset, unsigned int len);
144 struct symbol *find_func_containing(struct section *sec, unsigned long offset);
145
146 /*
147  * Try to see if it's a whole archive (vmlinux.o or module).
148  *
149  * Note this will miss the case where a module only has one source file.
150  */
151 static inline bool has_multiple_files(struct elf *elf)
152 {
153         return elf->num_files > 1;
154 }
155
156 static inline size_t elf_addr_size(struct elf *elf)
157 {
158         return elf->ehdr.e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
159 }
160
161 static inline size_t elf_rela_size(struct elf *elf)
162 {
163         return elf_addr_size(elf) == 4 ? sizeof(Elf32_Rela) : sizeof(Elf64_Rela);
164 }
165
166 static inline unsigned int elf_data_rela_type(struct elf *elf)
167 {
168         return elf_addr_size(elf) == 4 ? R_DATA32 : R_DATA64;
169 }
170
171 static inline unsigned int elf_text_rela_type(struct elf *elf)
172 {
173         return elf_addr_size(elf) == 4 ? R_TEXT32 : R_TEXT64;
174 }
175
176 static inline bool is_reloc_sec(struct section *sec)
177 {
178         return sec->sh.sh_type == SHT_RELA || sec->sh.sh_type == SHT_REL;
179 }
180
181 static inline bool sec_changed(struct section *sec)
182 {
183         return sec->_changed;
184 }
185
186 static inline void mark_sec_changed(struct elf *elf, struct section *sec,
187                                     bool changed)
188 {
189         sec->_changed = changed;
190         elf->changed |= changed;
191 }
192
193 static inline unsigned int sec_num_entries(struct section *sec)
194 {
195         return sec->sh.sh_size / sec->sh.sh_entsize;
196 }
197
198 static inline unsigned int reloc_idx(struct reloc *reloc)
199 {
200         return reloc - reloc->sec->relocs;
201 }
202
203 static inline void *reloc_rel(struct reloc *reloc)
204 {
205         struct section *rsec = reloc->sec;
206
207         return rsec->data->d_buf + (reloc_idx(reloc) * rsec->sh.sh_entsize);
208 }
209
210 static inline bool is_32bit_reloc(struct reloc *reloc)
211 {
212         /*
213          * Elf32_Rel:   8 bytes
214          * Elf32_Rela: 12 bytes
215          * Elf64_Rel:  16 bytes
216          * Elf64_Rela: 24 bytes
217          */
218         return reloc->sec->sh.sh_entsize < 16;
219 }
220
221 #define __get_reloc_field(reloc, field)                                 \
222 ({                                                                      \
223         is_32bit_reloc(reloc) ?                                         \
224                 ((Elf32_Rela *)reloc_rel(reloc))->field :               \
225                 ((Elf64_Rela *)reloc_rel(reloc))->field;                \
226 })
227
228 #define __set_reloc_field(reloc, field, val)                            \
229 ({                                                                      \
230         if (is_32bit_reloc(reloc))                                      \
231                 ((Elf32_Rela *)reloc_rel(reloc))->field = val;          \
232         else                                                            \
233                 ((Elf64_Rela *)reloc_rel(reloc))->field = val;          \
234 })
235
236 static inline u64 reloc_offset(struct reloc *reloc)
237 {
238         return __get_reloc_field(reloc, r_offset);
239 }
240
241 static inline void set_reloc_offset(struct elf *elf, struct reloc *reloc, u64 offset)
242 {
243         __set_reloc_field(reloc, r_offset, offset);
244         mark_sec_changed(elf, reloc->sec, true);
245 }
246
247 static inline s64 reloc_addend(struct reloc *reloc)
248 {
249         return __get_reloc_field(reloc, r_addend);
250 }
251
252 static inline void set_reloc_addend(struct elf *elf, struct reloc *reloc, s64 addend)
253 {
254         __set_reloc_field(reloc, r_addend, addend);
255         mark_sec_changed(elf, reloc->sec, true);
256 }
257
258
259 static inline unsigned int reloc_sym(struct reloc *reloc)
260 {
261         u64 info = __get_reloc_field(reloc, r_info);
262
263         return is_32bit_reloc(reloc) ?
264                 ELF32_R_SYM(info) :
265                 ELF64_R_SYM(info);
266 }
267
268 static inline unsigned int reloc_type(struct reloc *reloc)
269 {
270         u64 info = __get_reloc_field(reloc, r_info);
271
272         return is_32bit_reloc(reloc) ?
273                 ELF32_R_TYPE(info) :
274                 ELF64_R_TYPE(info);
275 }
276
277 static inline void set_reloc_sym(struct elf *elf, struct reloc *reloc, unsigned int sym)
278 {
279         u64 info = is_32bit_reloc(reloc) ?
280                 ELF32_R_INFO(sym, reloc_type(reloc)) :
281                 ELF64_R_INFO(sym, reloc_type(reloc));
282
283         __set_reloc_field(reloc, r_info, info);
284
285         mark_sec_changed(elf, reloc->sec, true);
286 }
287 static inline void set_reloc_type(struct elf *elf, struct reloc *reloc, unsigned int type)
288 {
289         u64 info = is_32bit_reloc(reloc) ?
290                 ELF32_R_INFO(reloc_sym(reloc), type) :
291                 ELF64_R_INFO(reloc_sym(reloc), type);
292
293         __set_reloc_field(reloc, r_info, info);
294
295         mark_sec_changed(elf, reloc->sec, true);
296 }
297
298 #define for_each_sec(file, sec)                                         \
299         list_for_each_entry(sec, &file->elf->sections, list)
300
301 #define sec_for_each_sym(sec, sym)                                      \
302         list_for_each_entry(sym, &sec->symbol_list, list)
303
304 #define for_each_sym(file, sym)                                         \
305         for (struct section *__sec, *__fake = (struct section *)1;      \
306              __fake; __fake = NULL)                                     \
307                 for_each_sec(file, __sec)                               \
308                         sec_for_each_sym(__sec, sym)
309
310 #define for_each_reloc(rsec, reloc)                                     \
311         for (int __i = 0, __fake = 1; __fake; __fake = 0)               \
312                 for (reloc = rsec->relocs;                              \
313                      __i < sec_num_entries(rsec);                       \
314                      __i++, reloc++)
315
316 #define for_each_reloc_from(rsec, reloc)                                \
317         for (int __i = reloc_idx(reloc);                                \
318              __i < sec_num_entries(rsec);                               \
319              __i++, reloc++)
320
321 #define OFFSET_STRIDE_BITS      4
322 #define OFFSET_STRIDE           (1UL << OFFSET_STRIDE_BITS)
323 #define OFFSET_STRIDE_MASK      (~(OFFSET_STRIDE - 1))
324
325 #define for_offset_range(_offset, _start, _end)                 \
326         for (_offset = ((_start) & OFFSET_STRIDE_MASK);         \
327              _offset >= ((_start) & OFFSET_STRIDE_MASK) &&      \
328              _offset <= ((_end) & OFFSET_STRIDE_MASK);          \
329              _offset += OFFSET_STRIDE)
330
331 static inline u32 sec_offset_hash(struct section *sec, unsigned long offset)
332 {
333         u32 ol, oh, idx = sec->idx;
334
335         offset &= OFFSET_STRIDE_MASK;
336
337         ol = offset;
338         oh = (offset >> 16) >> 16;
339
340         __jhash_mix(ol, oh, idx);
341
342         return ol;
343 }
344
345 static inline u32 reloc_hash(struct reloc *reloc)
346 {
347         return sec_offset_hash(reloc->sec, reloc_offset(reloc));
348 }
349
350 #endif /* _OBJTOOL_ELF_H */