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
29struct elf_hash_node {
30	struct elf_hash_node *next;
31};
32
33struct 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
49struct 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	struct list_head pv_target;
72	struct reloc *relocs;
73};
74
75struct reloc {
76	struct elf_hash_node hash;
77	struct section *sec;
78	struct symbol *sym;
79	struct reloc *sym_next_reloc;
80};
81
82struct elf {
83	Elf *elf;
84	GElf_Ehdr ehdr;
85	int fd;
86	bool changed;
87	char *name;
88	unsigned int num_files;
89	struct list_head sections;
90	unsigned long num_relocs;
91
92	int symbol_bits;
93	int symbol_name_bits;
94	int section_bits;
95	int section_name_bits;
96	int reloc_bits;
97
98	struct elf_hash_node **symbol_hash;
99	struct elf_hash_node **symbol_name_hash;
100	struct elf_hash_node **section_hash;
101	struct elf_hash_node **section_name_hash;
102	struct elf_hash_node **reloc_hash;
103
104	struct section *section_data;
105	struct symbol *symbol_data;
106};
107
108struct elf *elf_open_read(const char *name, int flags);
109
110struct section *elf_create_section(struct elf *elf, const char *name,
111				   size_t entsize, unsigned int nr);
112struct section *elf_create_section_pair(struct elf *elf, const char *name,
113					size_t entsize, unsigned int nr,
114					unsigned int reloc_nr);
115
116struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size);
117
118struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec,
119				      unsigned long offset,
120				      unsigned int reloc_idx,
121				      struct section *insn_sec,
122				      unsigned long insn_off);
123
124struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec,
125				      unsigned long offset,
126				      unsigned int reloc_idx,
127				      struct symbol *sym,
128				      s64 addend);
129
130int elf_write_insn(struct elf *elf, struct section *sec,
131		   unsigned long offset, unsigned int len,
132		   const char *insn);
133int elf_write(struct elf *elf);
134void elf_close(struct elf *elf);
135
136struct section *find_section_by_name(const struct elf *elf, const char *name);
137struct symbol *find_func_by_offset(struct section *sec, unsigned long offset);
138struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
139struct symbol *find_symbol_by_name(const struct elf *elf, const char *name);
140struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset);
141int find_symbol_hole_containing(const struct section *sec, unsigned long offset);
142struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset);
143struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
144				     unsigned long offset, unsigned int len);
145struct 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 */
152static inline bool has_multiple_files(struct elf *elf)
153{
154	return elf->num_files > 1;
155}
156
157static inline size_t elf_addr_size(struct elf *elf)
158{
159	return elf->ehdr.e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
160}
161
162static 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
167static inline unsigned int elf_data_rela_type(struct elf *elf)
168{
169	return elf_addr_size(elf) == 4 ? R_DATA32 : R_DATA64;
170}
171
172static inline unsigned int elf_text_rela_type(struct elf *elf)
173{
174	return elf_addr_size(elf) == 4 ? R_TEXT32 : R_TEXT64;
175}
176
177static 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
182static inline bool sec_changed(struct section *sec)
183{
184	return sec->_changed;
185}
186
187static 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
194static inline unsigned int sec_num_entries(struct section *sec)
195{
196	return sec->sh.sh_size / sec->sh.sh_entsize;
197}
198
199static inline unsigned int reloc_idx(struct reloc *reloc)
200{
201	return reloc - reloc->sec->relocs;
202}
203
204static inline void *reloc_rel(struct reloc *reloc)
205{
206	struct section *rsec = reloc->sec;
207
208	return rsec->data->d_buf + (reloc_idx(reloc) * rsec->sh.sh_entsize);
209}
210
211static inline bool is_32bit_reloc(struct reloc *reloc)
212{
213	/*
214	 * Elf32_Rel:   8 bytes
215	 * Elf32_Rela: 12 bytes
216	 * Elf64_Rel:  16 bytes
217	 * Elf64_Rela: 24 bytes
218	 */
219	return reloc->sec->sh.sh_entsize < 16;
220}
221
222#define __get_reloc_field(reloc, field)					\
223({									\
224	is_32bit_reloc(reloc) ?						\
225		((Elf32_Rela *)reloc_rel(reloc))->field :		\
226		((Elf64_Rela *)reloc_rel(reloc))->field;		\
227})
228
229#define __set_reloc_field(reloc, field, val)				\
230({									\
231	if (is_32bit_reloc(reloc))					\
232		((Elf32_Rela *)reloc_rel(reloc))->field = val;		\
233	else								\
234		((Elf64_Rela *)reloc_rel(reloc))->field = val;		\
235})
236
237static inline u64 reloc_offset(struct reloc *reloc)
238{
239	return __get_reloc_field(reloc, r_offset);
240}
241
242static inline void set_reloc_offset(struct elf *elf, struct reloc *reloc, u64 offset)
243{
244	__set_reloc_field(reloc, r_offset, offset);
245	mark_sec_changed(elf, reloc->sec, true);
246}
247
248static inline s64 reloc_addend(struct reloc *reloc)
249{
250	return __get_reloc_field(reloc, r_addend);
251}
252
253static inline void set_reloc_addend(struct elf *elf, struct reloc *reloc, s64 addend)
254{
255	__set_reloc_field(reloc, r_addend, addend);
256	mark_sec_changed(elf, reloc->sec, true);
257}
258
259
260static inline unsigned int reloc_sym(struct reloc *reloc)
261{
262	u64 info = __get_reloc_field(reloc, r_info);
263
264	return is_32bit_reloc(reloc) ?
265		ELF32_R_SYM(info) :
266		ELF64_R_SYM(info);
267}
268
269static inline unsigned int reloc_type(struct reloc *reloc)
270{
271	u64 info = __get_reloc_field(reloc, r_info);
272
273	return is_32bit_reloc(reloc) ?
274		ELF32_R_TYPE(info) :
275		ELF64_R_TYPE(info);
276}
277
278static inline void set_reloc_sym(struct elf *elf, struct reloc *reloc, unsigned int sym)
279{
280	u64 info = is_32bit_reloc(reloc) ?
281		ELF32_R_INFO(sym, reloc_type(reloc)) :
282		ELF64_R_INFO(sym, reloc_type(reloc));
283
284	__set_reloc_field(reloc, r_info, info);
285
286	mark_sec_changed(elf, reloc->sec, true);
287}
288static inline void set_reloc_type(struct elf *elf, struct reloc *reloc, unsigned int type)
289{
290	u64 info = is_32bit_reloc(reloc) ?
291		ELF32_R_INFO(reloc_sym(reloc), type) :
292		ELF64_R_INFO(reloc_sym(reloc), type);
293
294	__set_reloc_field(reloc, r_info, info);
295
296	mark_sec_changed(elf, reloc->sec, true);
297}
298
299#define for_each_sec(file, sec)						\
300	list_for_each_entry(sec, &file->elf->sections, list)
301
302#define sec_for_each_sym(sec, sym)					\
303	list_for_each_entry(sym, &sec->symbol_list, list)
304
305#define for_each_sym(file, sym)						\
306	for (struct section *__sec, *__fake = (struct section *)1;	\
307	     __fake; __fake = NULL)					\
308		for_each_sec(file, __sec)				\
309			sec_for_each_sym(__sec, sym)
310
311#define for_each_reloc(rsec, reloc)					\
312	for (int __i = 0, __fake = 1; __fake; __fake = 0)		\
313		for (reloc = rsec->relocs;				\
314		     __i < sec_num_entries(rsec);			\
315		     __i++, reloc++)
316
317#define for_each_reloc_from(rsec, reloc)				\
318	for (int __i = reloc_idx(reloc);				\
319	     __i < sec_num_entries(rsec);				\
320	     __i++, reloc++)
321
322#define OFFSET_STRIDE_BITS	4
323#define OFFSET_STRIDE		(1UL << OFFSET_STRIDE_BITS)
324#define OFFSET_STRIDE_MASK	(~(OFFSET_STRIDE - 1))
325
326#define for_offset_range(_offset, _start, _end)			\
327	for (_offset = ((_start) & OFFSET_STRIDE_MASK);		\
328	     _offset >= ((_start) & OFFSET_STRIDE_MASK) &&	\
329	     _offset <= ((_end) & OFFSET_STRIDE_MASK);		\
330	     _offset += OFFSET_STRIDE)
331
332static inline u32 sec_offset_hash(struct section *sec, unsigned long offset)
333{
334	u32 ol, oh, idx = sec->idx;
335
336	offset &= OFFSET_STRIDE_MASK;
337
338	ol = offset;
339	oh = (offset >> 16) >> 16;
340
341	__jhash_mix(ol, oh, idx);
342
343	return ol;
344}
345
346static inline u32 reloc_hash(struct reloc *reloc)
347{
348	return sec_offset_hash(reloc->sec, reloc_offset(reloc));
349}
350
351#endif /* _OBJTOOL_ELF_H */
352