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 */ has_multiple_files(struct elf * elf)151 static inline bool has_multiple_files(struct elf *elf) 152 { 153 return elf->num_files > 1; 154 } 155 elf_addr_size(struct elf * elf)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 elf_rela_size(struct elf * elf)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 elf_data_rela_type(struct elf * elf)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 elf_text_rela_type(struct elf * elf)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 is_reloc_sec(struct section * sec)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 sec_changed(struct section * sec)181 static inline bool sec_changed(struct section *sec) 182 { 183 return sec->_changed; 184 } 185 mark_sec_changed(struct elf * elf,struct section * sec,bool changed)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 sec_num_entries(struct section * sec)193 static inline unsigned int sec_num_entries(struct section *sec) 194 { 195 return sec->sh.sh_size / sec->sh.sh_entsize; 196 } 197 reloc_idx(struct reloc * reloc)198 static inline unsigned int reloc_idx(struct reloc *reloc) 199 { 200 return reloc - reloc->sec->relocs; 201 } 202 reloc_rel(struct reloc * reloc)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 is_32bit_reloc(struct reloc * reloc)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 reloc_offset(struct reloc * reloc)236 static inline u64 reloc_offset(struct reloc *reloc) 237 { 238 return __get_reloc_field(reloc, r_offset); 239 } 240 set_reloc_offset(struct elf * elf,struct reloc * reloc,u64 offset)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 reloc_addend(struct reloc * reloc)247 static inline s64 reloc_addend(struct reloc *reloc) 248 { 249 return __get_reloc_field(reloc, r_addend); 250 } 251 set_reloc_addend(struct elf * elf,struct reloc * reloc,s64 addend)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 reloc_sym(struct reloc * reloc)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 reloc_type(struct reloc * reloc)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 set_reloc_sym(struct elf * elf,struct reloc * reloc,unsigned int sym)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 } set_reloc_type(struct elf * elf,struct reloc * reloc,unsigned int type)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 sec_offset_hash(struct section * sec,unsigned long offset)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 reloc_hash(struct reloc * reloc)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 */ 351