18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com>
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#ifndef _OBJTOOL_ELF_H
78c2ecf20Sopenharmony_ci#define _OBJTOOL_ELF_H
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <stdio.h>
108c2ecf20Sopenharmony_ci#include <gelf.h>
118c2ecf20Sopenharmony_ci#include <linux/list.h>
128c2ecf20Sopenharmony_ci#include <linux/hashtable.h>
138c2ecf20Sopenharmony_ci#include <linux/rbtree.h>
148c2ecf20Sopenharmony_ci#include <linux/jhash.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#ifdef LIBELF_USE_DEPRECATED
178c2ecf20Sopenharmony_ci# define elf_getshdrnum    elf_getshnum
188c2ecf20Sopenharmony_ci# define elf_getshdrstrndx elf_getshstrndx
198c2ecf20Sopenharmony_ci#endif
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/*
228c2ecf20Sopenharmony_ci * Fallback for systems without this "read, mmaping if possible" cmd.
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_ci#ifndef ELF_C_READ_MMAP
258c2ecf20Sopenharmony_ci#define ELF_C_READ_MMAP ELF_C_READ
268c2ecf20Sopenharmony_ci#endif
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistruct section {
298c2ecf20Sopenharmony_ci	struct list_head list;
308c2ecf20Sopenharmony_ci	struct hlist_node hash;
318c2ecf20Sopenharmony_ci	struct hlist_node name_hash;
328c2ecf20Sopenharmony_ci	GElf_Shdr sh;
338c2ecf20Sopenharmony_ci	struct rb_root symbol_tree;
348c2ecf20Sopenharmony_ci	struct list_head symbol_list;
358c2ecf20Sopenharmony_ci	struct list_head reloc_list;
368c2ecf20Sopenharmony_ci	struct section *base, *reloc;
378c2ecf20Sopenharmony_ci	struct symbol *sym;
388c2ecf20Sopenharmony_ci	Elf_Data *data;
398c2ecf20Sopenharmony_ci	char *name;
408c2ecf20Sopenharmony_ci	int idx;
418c2ecf20Sopenharmony_ci	unsigned int len;
428c2ecf20Sopenharmony_ci	bool changed, text, rodata, noinstr;
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistruct symbol {
468c2ecf20Sopenharmony_ci	struct list_head list;
478c2ecf20Sopenharmony_ci	struct rb_node node;
488c2ecf20Sopenharmony_ci	struct hlist_node hash;
498c2ecf20Sopenharmony_ci	struct hlist_node name_hash;
508c2ecf20Sopenharmony_ci	GElf_Sym sym;
518c2ecf20Sopenharmony_ci	struct section *sec;
528c2ecf20Sopenharmony_ci	char *name;
538c2ecf20Sopenharmony_ci	unsigned int idx;
548c2ecf20Sopenharmony_ci	unsigned char bind, type;
558c2ecf20Sopenharmony_ci	unsigned long offset;
568c2ecf20Sopenharmony_ci	unsigned int len;
578c2ecf20Sopenharmony_ci	struct symbol *pfunc, *cfunc, *alias;
588c2ecf20Sopenharmony_ci	u8 uaccess_safe      : 1;
598c2ecf20Sopenharmony_ci	u8 static_call_tramp : 1;
608c2ecf20Sopenharmony_ci	u8 retpoline_thunk   : 1;
618c2ecf20Sopenharmony_ci	u8 return_thunk      : 1;
628c2ecf20Sopenharmony_ci	u8 fentry            : 1;
638c2ecf20Sopenharmony_ci	u8 kcov              : 1;
648c2ecf20Sopenharmony_ci	u8 embedded_insn     : 1;
658c2ecf20Sopenharmony_ci};
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistruct reloc {
688c2ecf20Sopenharmony_ci	struct list_head list;
698c2ecf20Sopenharmony_ci	struct hlist_node hash;
708c2ecf20Sopenharmony_ci	union {
718c2ecf20Sopenharmony_ci		GElf_Rela rela;
728c2ecf20Sopenharmony_ci		GElf_Rel  rel;
738c2ecf20Sopenharmony_ci	};
748c2ecf20Sopenharmony_ci	struct section *sec;
758c2ecf20Sopenharmony_ci	struct symbol *sym;
768c2ecf20Sopenharmony_ci	unsigned long offset;
778c2ecf20Sopenharmony_ci	unsigned int type;
788c2ecf20Sopenharmony_ci	s64 addend;
798c2ecf20Sopenharmony_ci	int idx;
808c2ecf20Sopenharmony_ci	bool jump_table_start;
818c2ecf20Sopenharmony_ci};
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci#define ELF_HASH_BITS	20
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistruct elf {
868c2ecf20Sopenharmony_ci	Elf *elf;
878c2ecf20Sopenharmony_ci	GElf_Ehdr ehdr;
888c2ecf20Sopenharmony_ci	int fd;
898c2ecf20Sopenharmony_ci	bool changed;
908c2ecf20Sopenharmony_ci	char *name;
918c2ecf20Sopenharmony_ci	struct list_head sections;
928c2ecf20Sopenharmony_ci	DECLARE_HASHTABLE(symbol_hash, ELF_HASH_BITS);
938c2ecf20Sopenharmony_ci	DECLARE_HASHTABLE(symbol_name_hash, ELF_HASH_BITS);
948c2ecf20Sopenharmony_ci	DECLARE_HASHTABLE(section_hash, ELF_HASH_BITS);
958c2ecf20Sopenharmony_ci	DECLARE_HASHTABLE(section_name_hash, ELF_HASH_BITS);
968c2ecf20Sopenharmony_ci	DECLARE_HASHTABLE(reloc_hash, ELF_HASH_BITS);
978c2ecf20Sopenharmony_ci};
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci#define OFFSET_STRIDE_BITS	4
1008c2ecf20Sopenharmony_ci#define OFFSET_STRIDE		(1UL << OFFSET_STRIDE_BITS)
1018c2ecf20Sopenharmony_ci#define OFFSET_STRIDE_MASK	(~(OFFSET_STRIDE - 1))
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci#define for_offset_range(_offset, _start, _end)			\
1048c2ecf20Sopenharmony_ci	for (_offset = ((_start) & OFFSET_STRIDE_MASK);		\
1058c2ecf20Sopenharmony_ci	     _offset >= ((_start) & OFFSET_STRIDE_MASK) &&	\
1068c2ecf20Sopenharmony_ci	     _offset <= ((_end) & OFFSET_STRIDE_MASK);		\
1078c2ecf20Sopenharmony_ci	     _offset += OFFSET_STRIDE)
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic inline u32 sec_offset_hash(struct section *sec, unsigned long offset)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	u32 ol, oh, idx = sec->idx;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	offset &= OFFSET_STRIDE_MASK;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	ol = offset;
1168c2ecf20Sopenharmony_ci	oh = (offset >> 16) >> 16;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	__jhash_mix(ol, oh, idx);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	return ol;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic inline u32 reloc_hash(struct reloc *reloc)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	return sec_offset_hash(reloc->sec, reloc->offset);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistruct elf *elf_open_read(const char *name, int flags);
1298c2ecf20Sopenharmony_cistruct section *elf_create_section(struct elf *elf, const char *name, unsigned int sh_flags, size_t entsize, int nr);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ciint elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
1328c2ecf20Sopenharmony_ci		  unsigned int type, struct symbol *sym, s64 addend);
1338c2ecf20Sopenharmony_ciint elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
1348c2ecf20Sopenharmony_ci			  unsigned long offset, unsigned int type,
1358c2ecf20Sopenharmony_ci			  struct section *insn_sec, unsigned long insn_off);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ciint elf_write_insn(struct elf *elf, struct section *sec,
1388c2ecf20Sopenharmony_ci		   unsigned long offset, unsigned int len,
1398c2ecf20Sopenharmony_ci		   const char *insn);
1408c2ecf20Sopenharmony_ciint elf_write_reloc(struct elf *elf, struct reloc *reloc);
1418c2ecf20Sopenharmony_ciint elf_write(struct elf *elf);
1428c2ecf20Sopenharmony_civoid elf_close(struct elf *elf);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistruct section *find_section_by_name(const struct elf *elf, const char *name);
1458c2ecf20Sopenharmony_cistruct symbol *find_func_by_offset(struct section *sec, unsigned long offset);
1468c2ecf20Sopenharmony_cistruct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
1478c2ecf20Sopenharmony_cistruct symbol *find_symbol_by_name(const struct elf *elf, const char *name);
1488c2ecf20Sopenharmony_cistruct symbol *find_symbol_containing(const struct section *sec, unsigned long offset);
1498c2ecf20Sopenharmony_cistruct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset);
1508c2ecf20Sopenharmony_cistruct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
1518c2ecf20Sopenharmony_ci				     unsigned long offset, unsigned int len);
1528c2ecf20Sopenharmony_cistruct symbol *find_func_containing(struct section *sec, unsigned long offset);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci#define for_each_sec(file, sec)						\
1558c2ecf20Sopenharmony_ci	list_for_each_entry(sec, &file->elf->sections, list)
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci#endif /* _OBJTOOL_ELF_H */
158