1e01aa904Sopenharmony_ci// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 2e01aa904Sopenharmony_ci// -*- Mode: C++ -*- 3e01aa904Sopenharmony_ci// 4e01aa904Sopenharmony_ci// Copyright (C) 2020-2022 Google, Inc. 5e01aa904Sopenharmony_ci 6e01aa904Sopenharmony_ci/// @file 7e01aa904Sopenharmony_ci/// 8e01aa904Sopenharmony_ci/// This contains the definitions of the ELF utilities for the dwarf reader. 9e01aa904Sopenharmony_ci#include <sys/types.h> 10e01aa904Sopenharmony_ci#include <sys/stat.h> 11e01aa904Sopenharmony_ci#include <fcntl.h> 12e01aa904Sopenharmony_ci#include <unistd.h> 13e01aa904Sopenharmony_ci#include <limits.h> 14e01aa904Sopenharmony_ci#include <elfutils/libdwfl.h> 15e01aa904Sopenharmony_ci#include "abg-elf-helpers.h" 16e01aa904Sopenharmony_ci#include "abg-tools-utils.h" 17e01aa904Sopenharmony_ci 18e01aa904Sopenharmony_cinamespace abigail 19e01aa904Sopenharmony_ci{ 20e01aa904Sopenharmony_ci 21e01aa904Sopenharmony_cinamespace elf_helpers 22e01aa904Sopenharmony_ci{ 23e01aa904Sopenharmony_ci 24e01aa904Sopenharmony_ci/// Convert an elf symbol type (given by the ELF{32,64}_ST_TYPE 25e01aa904Sopenharmony_ci/// macros) into an elf_symbol::type value. 26e01aa904Sopenharmony_ci/// 27e01aa904Sopenharmony_ci/// Note that this function aborts when given an unexpected value. 28e01aa904Sopenharmony_ci/// 29e01aa904Sopenharmony_ci/// @param the symbol type value to convert. 30e01aa904Sopenharmony_ci/// 31e01aa904Sopenharmony_ci/// @return the converted value. 32e01aa904Sopenharmony_cielf_symbol::type 33e01aa904Sopenharmony_cistt_to_elf_symbol_type(unsigned char stt) 34e01aa904Sopenharmony_ci{ 35e01aa904Sopenharmony_ci switch (stt) 36e01aa904Sopenharmony_ci { 37e01aa904Sopenharmony_ci case STT_NOTYPE: 38e01aa904Sopenharmony_ci return elf_symbol::NOTYPE_TYPE; 39e01aa904Sopenharmony_ci case STT_OBJECT: 40e01aa904Sopenharmony_ci return elf_symbol::OBJECT_TYPE; 41e01aa904Sopenharmony_ci case STT_FUNC: 42e01aa904Sopenharmony_ci return elf_symbol::FUNC_TYPE; 43e01aa904Sopenharmony_ci case STT_SECTION: 44e01aa904Sopenharmony_ci return elf_symbol::SECTION_TYPE; 45e01aa904Sopenharmony_ci case STT_FILE: 46e01aa904Sopenharmony_ci return elf_symbol::FILE_TYPE; 47e01aa904Sopenharmony_ci case STT_COMMON: 48e01aa904Sopenharmony_ci return elf_symbol::COMMON_TYPE; 49e01aa904Sopenharmony_ci case STT_TLS: 50e01aa904Sopenharmony_ci return elf_symbol::TLS_TYPE; 51e01aa904Sopenharmony_ci case STT_GNU_IFUNC: 52e01aa904Sopenharmony_ci return elf_symbol::GNU_IFUNC_TYPE; 53e01aa904Sopenharmony_ci default: 54e01aa904Sopenharmony_ci // An unknown value that probably ought to be supported? Let's 55e01aa904Sopenharmony_ci // abort right here rather than yielding garbage. 56e01aa904Sopenharmony_ci ABG_ASSERT_NOT_REACHED; 57e01aa904Sopenharmony_ci } 58e01aa904Sopenharmony_ci} 59e01aa904Sopenharmony_ci 60e01aa904Sopenharmony_ci/// Convert an elf symbol binding (given by the ELF{32,64}_ST_BIND 61e01aa904Sopenharmony_ci/// macros) into an elf_symbol::binding value. 62e01aa904Sopenharmony_ci/// 63e01aa904Sopenharmony_ci/// Note that this function aborts when given an unexpected value. 64e01aa904Sopenharmony_ci/// 65e01aa904Sopenharmony_ci/// @param the symbol binding value to convert. 66e01aa904Sopenharmony_ci/// 67e01aa904Sopenharmony_ci/// @return the converted value. 68e01aa904Sopenharmony_cielf_symbol::binding 69e01aa904Sopenharmony_cistb_to_elf_symbol_binding(unsigned char stb) 70e01aa904Sopenharmony_ci{ 71e01aa904Sopenharmony_ci switch (stb) 72e01aa904Sopenharmony_ci { 73e01aa904Sopenharmony_ci case STB_LOCAL: 74e01aa904Sopenharmony_ci return elf_symbol::LOCAL_BINDING; 75e01aa904Sopenharmony_ci case STB_GLOBAL: 76e01aa904Sopenharmony_ci return elf_symbol::GLOBAL_BINDING; 77e01aa904Sopenharmony_ci case STB_WEAK: 78e01aa904Sopenharmony_ci return elf_symbol::WEAK_BINDING; 79e01aa904Sopenharmony_ci case STB_GNU_UNIQUE: 80e01aa904Sopenharmony_ci return elf_symbol::GNU_UNIQUE_BINDING; 81e01aa904Sopenharmony_ci default: 82e01aa904Sopenharmony_ci ABG_ASSERT_NOT_REACHED; 83e01aa904Sopenharmony_ci } 84e01aa904Sopenharmony_ci} 85e01aa904Sopenharmony_ci 86e01aa904Sopenharmony_ci/// Convert an ELF symbol visiblity given by the symbols ->st_other 87e01aa904Sopenharmony_ci/// data member as returned by the GELF_ST_VISIBILITY macro into a 88e01aa904Sopenharmony_ci/// elf_symbol::visiblity value. 89e01aa904Sopenharmony_ci/// 90e01aa904Sopenharmony_ci/// @param stv the value of the ->st_other data member of the ELF 91e01aa904Sopenharmony_ci/// symbol. 92e01aa904Sopenharmony_ci/// 93e01aa904Sopenharmony_ci/// @return the converted elf_symbol::visiblity value. 94e01aa904Sopenharmony_cielf_symbol::visibility 95e01aa904Sopenharmony_cistv_to_elf_symbol_visibility(unsigned char stv) 96e01aa904Sopenharmony_ci{ 97e01aa904Sopenharmony_ci switch (stv) 98e01aa904Sopenharmony_ci { 99e01aa904Sopenharmony_ci case STV_DEFAULT: 100e01aa904Sopenharmony_ci return elf_symbol::DEFAULT_VISIBILITY; 101e01aa904Sopenharmony_ci case STV_INTERNAL: 102e01aa904Sopenharmony_ci return elf_symbol::INTERNAL_VISIBILITY; 103e01aa904Sopenharmony_ci case STV_HIDDEN: 104e01aa904Sopenharmony_ci return elf_symbol::HIDDEN_VISIBILITY; 105e01aa904Sopenharmony_ci case STV_PROTECTED: 106e01aa904Sopenharmony_ci return elf_symbol::PROTECTED_VISIBILITY; 107e01aa904Sopenharmony_ci default: 108e01aa904Sopenharmony_ci ABG_ASSERT_NOT_REACHED; 109e01aa904Sopenharmony_ci } 110e01aa904Sopenharmony_ci} 111e01aa904Sopenharmony_ci 112e01aa904Sopenharmony_ci/// Convert the value of the e_machine field of GElf_Ehdr into a 113e01aa904Sopenharmony_ci/// string. This is to get a string representing the architecture of 114e01aa904Sopenharmony_ci/// the elf file at hand. 115e01aa904Sopenharmony_ci/// 116e01aa904Sopenharmony_ci/// @param e_machine the value of GElf_Ehdr::e_machine. 117e01aa904Sopenharmony_ci/// 118e01aa904Sopenharmony_ci/// @return the string representation of GElf_Ehdr::e_machine. 119e01aa904Sopenharmony_cistd::string 120e01aa904Sopenharmony_cie_machine_to_string(GElf_Half e_machine) 121e01aa904Sopenharmony_ci{ 122e01aa904Sopenharmony_ci switch (e_machine) 123e01aa904Sopenharmony_ci { 124e01aa904Sopenharmony_ci case EM_NONE: 125e01aa904Sopenharmony_ci return "elf-no-arch"; 126e01aa904Sopenharmony_ci case EM_M32: 127e01aa904Sopenharmony_ci return "elf-att-we-32100"; 128e01aa904Sopenharmony_ci case EM_SPARC: 129e01aa904Sopenharmony_ci return "elf-sun-sparc"; 130e01aa904Sopenharmony_ci case EM_386: 131e01aa904Sopenharmony_ci return "elf-intel-80386"; 132e01aa904Sopenharmony_ci case EM_68K: 133e01aa904Sopenharmony_ci return "elf-motorola-68k"; 134e01aa904Sopenharmony_ci case EM_88K: 135e01aa904Sopenharmony_ci return "elf-motorola-88k"; 136e01aa904Sopenharmony_ci case EM_860: 137e01aa904Sopenharmony_ci return "elf-intel-80860"; 138e01aa904Sopenharmony_ci case EM_MIPS: 139e01aa904Sopenharmony_ci return "elf-mips-r3000-be"; 140e01aa904Sopenharmony_ci case EM_S370: 141e01aa904Sopenharmony_ci return "elf-ibm-s370"; 142e01aa904Sopenharmony_ci case EM_MIPS_RS3_LE: 143e01aa904Sopenharmony_ci return "elf-mips-r3000-le"; 144e01aa904Sopenharmony_ci case EM_PARISC: 145e01aa904Sopenharmony_ci return "elf-hp-parisc"; 146e01aa904Sopenharmony_ci case EM_VPP500: 147e01aa904Sopenharmony_ci return "elf-fujitsu-vpp500"; 148e01aa904Sopenharmony_ci case EM_SPARC32PLUS: 149e01aa904Sopenharmony_ci return "elf-sun-sparc-v8plus"; 150e01aa904Sopenharmony_ci case EM_960: 151e01aa904Sopenharmony_ci return "elf-intel-80960"; 152e01aa904Sopenharmony_ci case EM_PPC: 153e01aa904Sopenharmony_ci return "elf-powerpc"; 154e01aa904Sopenharmony_ci case EM_PPC64: 155e01aa904Sopenharmony_ci return "elf-powerpc-64"; 156e01aa904Sopenharmony_ci case EM_S390: 157e01aa904Sopenharmony_ci return "elf-ibm-s390"; 158e01aa904Sopenharmony_ci case EM_V800: 159e01aa904Sopenharmony_ci return "elf-nec-v800"; 160e01aa904Sopenharmony_ci case EM_FR20: 161e01aa904Sopenharmony_ci return "elf-fujitsu-fr20"; 162e01aa904Sopenharmony_ci case EM_RH32: 163e01aa904Sopenharmony_ci return "elf-trw-rh32"; 164e01aa904Sopenharmony_ci case EM_RCE: 165e01aa904Sopenharmony_ci return "elf-motorola-rce"; 166e01aa904Sopenharmony_ci case EM_ARM: 167e01aa904Sopenharmony_ci return "elf-arm"; 168e01aa904Sopenharmony_ci case EM_FAKE_ALPHA: 169e01aa904Sopenharmony_ci return "elf-digital-alpha"; 170e01aa904Sopenharmony_ci case EM_SH: 171e01aa904Sopenharmony_ci return "elf-hitachi-sh"; 172e01aa904Sopenharmony_ci case EM_SPARCV9: 173e01aa904Sopenharmony_ci return "elf-sun-sparc-v9-64"; 174e01aa904Sopenharmony_ci case EM_TRICORE: 175e01aa904Sopenharmony_ci return "elf-siemens-tricore"; 176e01aa904Sopenharmony_ci case EM_ARC: 177e01aa904Sopenharmony_ci return "elf-argonaut-risc-core"; 178e01aa904Sopenharmony_ci case EM_H8_300: 179e01aa904Sopenharmony_ci return "elf-hitachi-h8-300"; 180e01aa904Sopenharmony_ci case EM_H8_300H: 181e01aa904Sopenharmony_ci return "elf-hitachi-h8-300h"; 182e01aa904Sopenharmony_ci case EM_H8S: 183e01aa904Sopenharmony_ci return "elf-hitachi-h8s"; 184e01aa904Sopenharmony_ci case EM_H8_500: 185e01aa904Sopenharmony_ci return "elf-hitachi-h8-500"; 186e01aa904Sopenharmony_ci case EM_IA_64: 187e01aa904Sopenharmony_ci return "elf-intel-ia-64"; 188e01aa904Sopenharmony_ci case EM_MIPS_X: 189e01aa904Sopenharmony_ci return "elf-stanford-mips-x"; 190e01aa904Sopenharmony_ci case EM_COLDFIRE: 191e01aa904Sopenharmony_ci return "elf-motorola-coldfire"; 192e01aa904Sopenharmony_ci case EM_68HC12: 193e01aa904Sopenharmony_ci return "elf-motorola-68hc12"; 194e01aa904Sopenharmony_ci case EM_MMA: 195e01aa904Sopenharmony_ci return "elf-fujitsu-mma"; 196e01aa904Sopenharmony_ci case EM_PCP: 197e01aa904Sopenharmony_ci return "elf-siemens-pcp"; 198e01aa904Sopenharmony_ci case EM_NCPU: 199e01aa904Sopenharmony_ci return "elf-sony-ncpu"; 200e01aa904Sopenharmony_ci case EM_NDR1: 201e01aa904Sopenharmony_ci return "elf-denso-ndr1"; 202e01aa904Sopenharmony_ci case EM_STARCORE: 203e01aa904Sopenharmony_ci return "elf-motorola-starcore"; 204e01aa904Sopenharmony_ci case EM_ME16: 205e01aa904Sopenharmony_ci return "elf-toyota-me16"; 206e01aa904Sopenharmony_ci case EM_ST100: 207e01aa904Sopenharmony_ci return "elf-stm-st100"; 208e01aa904Sopenharmony_ci case EM_TINYJ: 209e01aa904Sopenharmony_ci return "elf-alc-tinyj"; 210e01aa904Sopenharmony_ci case EM_X86_64: 211e01aa904Sopenharmony_ci return "elf-amd-x86_64"; 212e01aa904Sopenharmony_ci case EM_PDSP: 213e01aa904Sopenharmony_ci return "elf-sony-pdsp"; 214e01aa904Sopenharmony_ci case EM_FX66: 215e01aa904Sopenharmony_ci return "elf-siemens-fx66"; 216e01aa904Sopenharmony_ci case EM_ST9PLUS: 217e01aa904Sopenharmony_ci return "elf-stm-st9+"; 218e01aa904Sopenharmony_ci case EM_ST7: 219e01aa904Sopenharmony_ci return "elf-stm-st7"; 220e01aa904Sopenharmony_ci case EM_68HC16: 221e01aa904Sopenharmony_ci return "elf-motorola-68hc16"; 222e01aa904Sopenharmony_ci case EM_68HC11: 223e01aa904Sopenharmony_ci return "elf-motorola-68hc11"; 224e01aa904Sopenharmony_ci case EM_68HC08: 225e01aa904Sopenharmony_ci return "elf-motorola-68hc08"; 226e01aa904Sopenharmony_ci case EM_68HC05: 227e01aa904Sopenharmony_ci return "elf-motorola-68hc05"; 228e01aa904Sopenharmony_ci case EM_SVX: 229e01aa904Sopenharmony_ci return "elf-sg-svx"; 230e01aa904Sopenharmony_ci case EM_ST19: 231e01aa904Sopenharmony_ci return "elf-stm-st19"; 232e01aa904Sopenharmony_ci case EM_VAX: 233e01aa904Sopenharmony_ci return "elf-digital-vax"; 234e01aa904Sopenharmony_ci case EM_CRIS: 235e01aa904Sopenharmony_ci return "elf-axis-cris"; 236e01aa904Sopenharmony_ci case EM_JAVELIN: 237e01aa904Sopenharmony_ci return "elf-infineon-javelin"; 238e01aa904Sopenharmony_ci case EM_FIREPATH: 239e01aa904Sopenharmony_ci return "elf-firepath"; 240e01aa904Sopenharmony_ci case EM_ZSP: 241e01aa904Sopenharmony_ci return "elf-lsi-zsp"; 242e01aa904Sopenharmony_ci case EM_MMIX: 243e01aa904Sopenharmony_ci return "elf-don-knuth-mmix"; 244e01aa904Sopenharmony_ci case EM_HUANY: 245e01aa904Sopenharmony_ci return "elf-harvard-huany"; 246e01aa904Sopenharmony_ci case EM_PRISM: 247e01aa904Sopenharmony_ci return "elf-sitera-prism"; 248e01aa904Sopenharmony_ci case EM_AVR: 249e01aa904Sopenharmony_ci return "elf-atmel-avr"; 250e01aa904Sopenharmony_ci case EM_FR30: 251e01aa904Sopenharmony_ci return "elf-fujistu-fr30"; 252e01aa904Sopenharmony_ci case EM_D10V: 253e01aa904Sopenharmony_ci return "elf-mitsubishi-d10v"; 254e01aa904Sopenharmony_ci case EM_D30V: 255e01aa904Sopenharmony_ci return "elf-mitsubishi-d30v"; 256e01aa904Sopenharmony_ci case EM_V850: 257e01aa904Sopenharmony_ci return "elf-nec-v850"; 258e01aa904Sopenharmony_ci case EM_M32R: 259e01aa904Sopenharmony_ci return "elf-mitsubishi-m32r"; 260e01aa904Sopenharmony_ci case EM_MN10300: 261e01aa904Sopenharmony_ci return "elf-matsushita-mn10300"; 262e01aa904Sopenharmony_ci case EM_MN10200: 263e01aa904Sopenharmony_ci return "elf-matsushita-mn10200"; 264e01aa904Sopenharmony_ci case EM_PJ: 265e01aa904Sopenharmony_ci return "elf-picojava"; 266e01aa904Sopenharmony_ci case EM_OPENRISC: 267e01aa904Sopenharmony_ci return "elf-openrisc-32"; 268e01aa904Sopenharmony_ci case EM_ARC_A5: 269e01aa904Sopenharmony_ci return "elf-arc-a5"; 270e01aa904Sopenharmony_ci case EM_XTENSA: 271e01aa904Sopenharmony_ci return "elf-tensilica-xtensa"; 272e01aa904Sopenharmony_ci 273e01aa904Sopenharmony_ci#ifdef HAVE_EM_AARCH64_MACRO 274e01aa904Sopenharmony_ci case EM_AARCH64: 275e01aa904Sopenharmony_ci return "elf-arm-aarch64"; 276e01aa904Sopenharmony_ci#endif 277e01aa904Sopenharmony_ci 278e01aa904Sopenharmony_ci#ifdef HAVE_EM_TILEPRO_MACRO 279e01aa904Sopenharmony_ci case EM_TILEPRO: 280e01aa904Sopenharmony_ci return "elf-tilera-tilepro"; 281e01aa904Sopenharmony_ci#endif 282e01aa904Sopenharmony_ci 283e01aa904Sopenharmony_ci#ifdef HAVE_EM_TILEGX_MACRO 284e01aa904Sopenharmony_ci case EM_TILEGX: 285e01aa904Sopenharmony_ci return "elf-tilera-tilegx"; 286e01aa904Sopenharmony_ci#endif 287e01aa904Sopenharmony_ci 288e01aa904Sopenharmony_ci case EM_NUM: 289e01aa904Sopenharmony_ci return "elf-last-arch-number"; 290e01aa904Sopenharmony_ci case EM_ALPHA: 291e01aa904Sopenharmony_ci return "elf-non-official-alpha"; 292e01aa904Sopenharmony_ci default: 293e01aa904Sopenharmony_ci { 294e01aa904Sopenharmony_ci std::ostringstream o; 295e01aa904Sopenharmony_ci o << "elf-unknown-arch-value-" << e_machine; 296e01aa904Sopenharmony_ci return o.str(); 297e01aa904Sopenharmony_ci } 298e01aa904Sopenharmony_ci } 299e01aa904Sopenharmony_ci} 300e01aa904Sopenharmony_ci 301e01aa904Sopenharmony_ci/// Find and return a section by its name. 302e01aa904Sopenharmony_ci/// 303e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use. 304e01aa904Sopenharmony_ci/// 305e01aa904Sopenharmony_ci/// @param name the section name. 306e01aa904Sopenharmony_ci/// 307e01aa904Sopenharmony_ci/// @return the section found, nor nil if none was found. 308e01aa904Sopenharmony_ciElf_Scn* 309e01aa904Sopenharmony_cifind_section_by_name(Elf* elf_handle, const std::string& name) 310e01aa904Sopenharmony_ci{ 311e01aa904Sopenharmony_ci size_t section_header_string_index = 0; 312e01aa904Sopenharmony_ci if (elf_getshdrstrndx (elf_handle, §ion_header_string_index) < 0) 313e01aa904Sopenharmony_ci return 0; 314e01aa904Sopenharmony_ci 315e01aa904Sopenharmony_ci Elf_Scn* section = 0; 316e01aa904Sopenharmony_ci GElf_Shdr header_mem, *header; 317e01aa904Sopenharmony_ci while ((section = elf_nextscn(elf_handle, section)) != 0) 318e01aa904Sopenharmony_ci { 319e01aa904Sopenharmony_ci header = gelf_getshdr(section, &header_mem); 320e01aa904Sopenharmony_ci if (header == NULL) 321e01aa904Sopenharmony_ci continue; 322e01aa904Sopenharmony_ci 323e01aa904Sopenharmony_ci const char* section_name = 324e01aa904Sopenharmony_ci elf_strptr(elf_handle, section_header_string_index, header->sh_name); 325e01aa904Sopenharmony_ci if (section_name && name == section_name) 326e01aa904Sopenharmony_ci return section; 327e01aa904Sopenharmony_ci } 328e01aa904Sopenharmony_ci 329e01aa904Sopenharmony_ci return 0; 330e01aa904Sopenharmony_ci} 331e01aa904Sopenharmony_ci 332e01aa904Sopenharmony_ci/// Find and return a section by its name and its type. 333e01aa904Sopenharmony_ci/// 334e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use. 335e01aa904Sopenharmony_ci/// 336e01aa904Sopenharmony_ci/// @param name the name of the section. 337e01aa904Sopenharmony_ci/// 338e01aa904Sopenharmony_ci/// @param section_type the type of the section. This is the 339e01aa904Sopenharmony_ci/// Elf32_Shdr::sh_type (or Elf64_Shdr::sh_type) data member. 340e01aa904Sopenharmony_ci/// Examples of values of this parameter are SHT_PROGBITS or SHT_NOBITS. 341e01aa904Sopenharmony_ci/// 342e01aa904Sopenharmony_ci/// @return the section found, nor nil if none was found. 343e01aa904Sopenharmony_ciElf_Scn* 344e01aa904Sopenharmony_cifind_section(Elf* elf_handle, const std::string& name, Elf64_Word section_type) 345e01aa904Sopenharmony_ci{ 346e01aa904Sopenharmony_ci size_t section_header_string_index = 0; 347e01aa904Sopenharmony_ci if (elf_getshdrstrndx (elf_handle, §ion_header_string_index) < 0) 348e01aa904Sopenharmony_ci return 0; 349e01aa904Sopenharmony_ci 350e01aa904Sopenharmony_ci Elf_Scn* section = 0; 351e01aa904Sopenharmony_ci GElf_Shdr header_mem, *header; 352e01aa904Sopenharmony_ci while ((section = elf_nextscn(elf_handle, section)) != 0) 353e01aa904Sopenharmony_ci { 354e01aa904Sopenharmony_ci header = gelf_getshdr(section, &header_mem); 355e01aa904Sopenharmony_ci if (header == NULL || header->sh_type != section_type) 356e01aa904Sopenharmony_ci continue; 357e01aa904Sopenharmony_ci 358e01aa904Sopenharmony_ci const char* section_name = 359e01aa904Sopenharmony_ci elf_strptr(elf_handle, section_header_string_index, header->sh_name); 360e01aa904Sopenharmony_ci if (section_name && name == section_name) 361e01aa904Sopenharmony_ci return section; 362e01aa904Sopenharmony_ci } 363e01aa904Sopenharmony_ci 364e01aa904Sopenharmony_ci return 0; 365e01aa904Sopenharmony_ci} 366e01aa904Sopenharmony_ci 367e01aa904Sopenharmony_ci/// Find and return a section by its type. 368e01aa904Sopenharmony_ci/// 369e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use. 370e01aa904Sopenharmony_ci/// 371e01aa904Sopenharmony_ci/// @param section_type the type of the section. This is the 372e01aa904Sopenharmony_ci/// Elf32_Shdr::sh_type (or Elf64_Shdr::sh_type) data member. 373e01aa904Sopenharmony_ci/// Examples of values of this parameter are SHT_PROGBITS or SHT_NOBITS. 374e01aa904Sopenharmony_ci/// 375e01aa904Sopenharmony_ci/// @return the section found, or nil if none was found. 376e01aa904Sopenharmony_ciElf_Scn* 377e01aa904Sopenharmony_cifind_section(Elf* elf_handle, Elf64_Word section_type) 378e01aa904Sopenharmony_ci{ 379e01aa904Sopenharmony_ci Elf_Scn* section = nullptr; 380e01aa904Sopenharmony_ci while ((section = elf_nextscn(elf_handle, section)) != 0) 381e01aa904Sopenharmony_ci { 382e01aa904Sopenharmony_ci GElf_Shdr header_mem, *header; 383e01aa904Sopenharmony_ci header = gelf_getshdr(section, &header_mem); 384e01aa904Sopenharmony_ci if (header->sh_type == section_type) 385e01aa904Sopenharmony_ci break; 386e01aa904Sopenharmony_ci } 387e01aa904Sopenharmony_ci return section; 388e01aa904Sopenharmony_ci} 389e01aa904Sopenharmony_ci 390e01aa904Sopenharmony_ci/// Find and return the .symtab section 391e01aa904Sopenharmony_ci/// 392e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use. 393e01aa904Sopenharmony_ci/// 394e01aa904Sopenharmony_ci/// @return the section found, or nil if none was found 395e01aa904Sopenharmony_ciElf_Scn* 396e01aa904Sopenharmony_cifind_symtab_section(Elf* elf_handle) 397e01aa904Sopenharmony_ci{ 398e01aa904Sopenharmony_ci return find_section(elf_handle, SHT_SYMTAB); 399e01aa904Sopenharmony_ci} 400e01aa904Sopenharmony_ci 401e01aa904Sopenharmony_ci/// Find and return the .symtab section 402e01aa904Sopenharmony_ci/// 403e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use. 404e01aa904Sopenharmony_ci/// 405e01aa904Sopenharmony_ci/// @return the section found, or nil if none was found 406e01aa904Sopenharmony_ciElf_Scn* 407e01aa904Sopenharmony_cifind_dynsym_section(Elf* elf_handle) 408e01aa904Sopenharmony_ci{ 409e01aa904Sopenharmony_ci return find_section(elf_handle, SHT_DYNSYM); 410e01aa904Sopenharmony_ci} 411e01aa904Sopenharmony_ci 412e01aa904Sopenharmony_ci/// Find the symbol table. 413e01aa904Sopenharmony_ci/// 414e01aa904Sopenharmony_ci/// If we are looking at a relocatable or executable file, this 415e01aa904Sopenharmony_ci/// function will return the .symtab symbol table (of type 416e01aa904Sopenharmony_ci/// SHT_SYMTAB). But if we are looking at a DSO it returns the 417e01aa904Sopenharmony_ci/// .dynsym symbol table (of type SHT_DYNSYM). 418e01aa904Sopenharmony_ci/// 419e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to consider. 420e01aa904Sopenharmony_ci/// 421e01aa904Sopenharmony_ci/// @param symtab the symbol table found. 422e01aa904Sopenharmony_ci/// 423e01aa904Sopenharmony_ci/// @return the symbol table section 424e01aa904Sopenharmony_ciElf_Scn* 425e01aa904Sopenharmony_cifind_symbol_table_section(Elf* elf_handle) 426e01aa904Sopenharmony_ci{ 427e01aa904Sopenharmony_ci Elf_Scn *dynsym = find_dynsym_section(elf_handle), 428e01aa904Sopenharmony_ci *sym_tab = find_symtab_section(elf_handle); 429e01aa904Sopenharmony_ci 430e01aa904Sopenharmony_ci if (dynsym || sym_tab) 431e01aa904Sopenharmony_ci { 432e01aa904Sopenharmony_ci GElf_Ehdr eh_mem; 433e01aa904Sopenharmony_ci GElf_Ehdr* elf_header = gelf_getehdr(elf_handle, &eh_mem); 434e01aa904Sopenharmony_ci if (elf_header->e_type == ET_REL 435e01aa904Sopenharmony_ci || elf_header->e_type == ET_EXEC) 436e01aa904Sopenharmony_ci return sym_tab ? sym_tab : dynsym; 437e01aa904Sopenharmony_ci else 438e01aa904Sopenharmony_ci return dynsym ? dynsym : sym_tab; 439e01aa904Sopenharmony_ci } 440e01aa904Sopenharmony_ci return nullptr; 441e01aa904Sopenharmony_ci} 442e01aa904Sopenharmony_ci 443e01aa904Sopenharmony_ci/// Find the index (in the section headers table) of the symbol table 444e01aa904Sopenharmony_ci/// section. 445e01aa904Sopenharmony_ci/// 446e01aa904Sopenharmony_ci/// If we are looking at a relocatable or executable file, this 447e01aa904Sopenharmony_ci/// function will return the index for the .symtab symbol table (of 448e01aa904Sopenharmony_ci/// type SHT_SYMTAB). But if we are looking at a DSO it returns the 449e01aa904Sopenharmony_ci/// index for the .dynsym symbol table (of type SHT_DYNSYM). 450e01aa904Sopenharmony_ci/// 451e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use. 452e01aa904Sopenharmony_ci/// 453e01aa904Sopenharmony_ci/// @param symtab_index the index of the symbol_table, that was found. 454e01aa904Sopenharmony_ci/// 455e01aa904Sopenharmony_ci/// @return true iff the symbol table section index was found. 456e01aa904Sopenharmony_cibool 457e01aa904Sopenharmony_cifind_symbol_table_section_index(Elf* elf_handle, size_t& symtab_index) 458e01aa904Sopenharmony_ci{ 459e01aa904Sopenharmony_ci Elf_Scn* section = find_symbol_table_section(elf_handle); 460e01aa904Sopenharmony_ci 461e01aa904Sopenharmony_ci if (!section) 462e01aa904Sopenharmony_ci return false; 463e01aa904Sopenharmony_ci 464e01aa904Sopenharmony_ci symtab_index = elf_ndxscn(section); 465e01aa904Sopenharmony_ci return true; 466e01aa904Sopenharmony_ci} 467e01aa904Sopenharmony_ci 468e01aa904Sopenharmony_ci/// Get the offset offset of the hash table section. 469e01aa904Sopenharmony_ci/// 470e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use. 471e01aa904Sopenharmony_ci/// 472e01aa904Sopenharmony_ci/// @param ht_section_offset this is set to the resulting offset 473e01aa904Sopenharmony_ci/// of the hash table section. This is set iff the function returns true. 474e01aa904Sopenharmony_ci/// 475e01aa904Sopenharmony_ci/// @param symtab_section_offset the offset of the section of the 476e01aa904Sopenharmony_ci/// symbol table the hash table refers to. 477e01aa904Sopenharmony_cihash_table_kind 478e01aa904Sopenharmony_cifind_hash_table_section_index(Elf* elf_handle, 479e01aa904Sopenharmony_ci size_t& ht_section_index, 480e01aa904Sopenharmony_ci size_t& symtab_section_index) 481e01aa904Sopenharmony_ci{ 482e01aa904Sopenharmony_ci if (!elf_handle) 483e01aa904Sopenharmony_ci return NO_HASH_TABLE_KIND; 484e01aa904Sopenharmony_ci 485e01aa904Sopenharmony_ci GElf_Shdr header_mem, *section_header; 486e01aa904Sopenharmony_ci bool found_sysv_ht = false, found_gnu_ht = false; 487e01aa904Sopenharmony_ci for (Elf_Scn* section = elf_nextscn(elf_handle, 0); 488e01aa904Sopenharmony_ci section != 0; 489e01aa904Sopenharmony_ci section = elf_nextscn(elf_handle, section)) 490e01aa904Sopenharmony_ci { 491e01aa904Sopenharmony_ci section_header= gelf_getshdr(section, &header_mem); 492e01aa904Sopenharmony_ci if (section_header->sh_type != SHT_HASH 493e01aa904Sopenharmony_ci && section_header->sh_type != SHT_GNU_HASH) 494e01aa904Sopenharmony_ci continue; 495e01aa904Sopenharmony_ci 496e01aa904Sopenharmony_ci ht_section_index = elf_ndxscn(section); 497e01aa904Sopenharmony_ci symtab_section_index = section_header->sh_link; 498e01aa904Sopenharmony_ci 499e01aa904Sopenharmony_ci if (section_header->sh_type == SHT_HASH) 500e01aa904Sopenharmony_ci found_sysv_ht = true; 501e01aa904Sopenharmony_ci else if (section_header->sh_type == SHT_GNU_HASH) 502e01aa904Sopenharmony_ci found_gnu_ht = true; 503e01aa904Sopenharmony_ci } 504e01aa904Sopenharmony_ci 505e01aa904Sopenharmony_ci if (found_gnu_ht) 506e01aa904Sopenharmony_ci return GNU_HASH_TABLE_KIND; 507e01aa904Sopenharmony_ci else if (found_sysv_ht) 508e01aa904Sopenharmony_ci return SYSV_HASH_TABLE_KIND; 509e01aa904Sopenharmony_ci else 510e01aa904Sopenharmony_ci return NO_HASH_TABLE_KIND; 511e01aa904Sopenharmony_ci} 512e01aa904Sopenharmony_ci 513e01aa904Sopenharmony_ci/// Find and return the .text section. 514e01aa904Sopenharmony_ci/// 515e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use. 516e01aa904Sopenharmony_ci/// 517e01aa904Sopenharmony_ci/// @return the .text section found. 518e01aa904Sopenharmony_ciElf_Scn* 519e01aa904Sopenharmony_cifind_text_section(Elf* elf_handle) 520e01aa904Sopenharmony_ci{return find_section(elf_handle, ".text", SHT_PROGBITS);} 521e01aa904Sopenharmony_ci 522e01aa904Sopenharmony_ci/// Find and return the .bss section. 523e01aa904Sopenharmony_ci/// 524e01aa904Sopenharmony_ci/// @param elf_handle. 525e01aa904Sopenharmony_ci/// 526e01aa904Sopenharmony_ci/// @return the .bss section found. 527e01aa904Sopenharmony_ciElf_Scn* 528e01aa904Sopenharmony_cifind_bss_section(Elf* elf_handle) 529e01aa904Sopenharmony_ci{return find_section(elf_handle, ".bss", SHT_NOBITS);} 530e01aa904Sopenharmony_ci 531e01aa904Sopenharmony_ci/// Find and return the .rodata section. 532e01aa904Sopenharmony_ci/// 533e01aa904Sopenharmony_ci/// @param elf_handle. 534e01aa904Sopenharmony_ci/// 535e01aa904Sopenharmony_ci/// @return the .rodata section found. 536e01aa904Sopenharmony_ciElf_Scn* 537e01aa904Sopenharmony_cifind_rodata_section(Elf* elf_handle) 538e01aa904Sopenharmony_ci{return find_section(elf_handle, ".rodata", SHT_PROGBITS);} 539e01aa904Sopenharmony_ci 540e01aa904Sopenharmony_ci/// Find and return the .data section. 541e01aa904Sopenharmony_ci/// 542e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use. 543e01aa904Sopenharmony_ci/// 544e01aa904Sopenharmony_ci/// @return the .data section found. 545e01aa904Sopenharmony_ciElf_Scn* 546e01aa904Sopenharmony_cifind_data_section(Elf* elf_handle) 547e01aa904Sopenharmony_ci{return find_section(elf_handle, ".data", SHT_PROGBITS);} 548e01aa904Sopenharmony_ci 549e01aa904Sopenharmony_ci/// Find and return the .data1 section. 550e01aa904Sopenharmony_ci/// 551e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use. 552e01aa904Sopenharmony_ci/// 553e01aa904Sopenharmony_ci/// @return the .data1 section found. 554e01aa904Sopenharmony_ciElf_Scn* 555e01aa904Sopenharmony_cifind_data1_section(Elf* elf_handle) 556e01aa904Sopenharmony_ci{return find_section(elf_handle, ".data1", SHT_PROGBITS);} 557e01aa904Sopenharmony_ci 558e01aa904Sopenharmony_ci/// Return the "Official Procedure descriptors section." This 559e01aa904Sopenharmony_ci/// section is named .opd, and is usually present only on PPC64 560e01aa904Sopenharmony_ci/// ELFv1 binaries. 561e01aa904Sopenharmony_ci/// 562e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to consider. 563e01aa904Sopenharmony_ci/// 564e01aa904Sopenharmony_ci/// @return the .opd section, if found. Return nil otherwise. 565e01aa904Sopenharmony_ciElf_Scn* 566e01aa904Sopenharmony_cifind_opd_section(Elf* elf_handle) 567e01aa904Sopenharmony_ci{return find_section(elf_handle, ".opd", SHT_PROGBITS);} 568e01aa904Sopenharmony_ci 569e01aa904Sopenharmony_ci/// Return the SHT_GNU_versym, SHT_GNU_verdef and SHT_GNU_verneed 570e01aa904Sopenharmony_ci/// sections that are involved in symbol versionning. 571e01aa904Sopenharmony_ci/// 572e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use. 573e01aa904Sopenharmony_ci/// 574e01aa904Sopenharmony_ci/// @param versym_section the SHT_GNU_versym section found. If the 575e01aa904Sopenharmony_ci/// section wasn't found, this is set to nil. 576e01aa904Sopenharmony_ci/// 577e01aa904Sopenharmony_ci/// @param verdef_section the SHT_GNU_verdef section found. If the 578e01aa904Sopenharmony_ci/// section wasn't found, this is set to nil. 579e01aa904Sopenharmony_ci/// 580e01aa904Sopenharmony_ci/// @param verneed_section the SHT_GNU_verneed section found. If the 581e01aa904Sopenharmony_ci/// section wasn't found, this is set to nil. 582e01aa904Sopenharmony_ci/// 583e01aa904Sopenharmony_ci/// @return true iff at least one of the sections where found. 584e01aa904Sopenharmony_cibool 585e01aa904Sopenharmony_ciget_symbol_versionning_sections(Elf* elf_handle, 586e01aa904Sopenharmony_ci Elf_Scn*& versym_section, 587e01aa904Sopenharmony_ci Elf_Scn*& verdef_section, 588e01aa904Sopenharmony_ci Elf_Scn*& verneed_section) 589e01aa904Sopenharmony_ci{ 590e01aa904Sopenharmony_ci Elf_Scn* section = NULL; 591e01aa904Sopenharmony_ci GElf_Shdr mem; 592e01aa904Sopenharmony_ci Elf_Scn* versym = NULL, *verdef = NULL, *verneed = NULL; 593e01aa904Sopenharmony_ci 594e01aa904Sopenharmony_ci while ((section = elf_nextscn(elf_handle, section)) != NULL) 595e01aa904Sopenharmony_ci { 596e01aa904Sopenharmony_ci GElf_Shdr* h = gelf_getshdr(section, &mem); 597e01aa904Sopenharmony_ci if (h->sh_type == SHT_GNU_versym) 598e01aa904Sopenharmony_ci versym = section; 599e01aa904Sopenharmony_ci else if (h->sh_type == SHT_GNU_verdef) 600e01aa904Sopenharmony_ci verdef = section; 601e01aa904Sopenharmony_ci else if (h->sh_type == SHT_GNU_verneed) 602e01aa904Sopenharmony_ci verneed = section; 603e01aa904Sopenharmony_ci } 604e01aa904Sopenharmony_ci 605e01aa904Sopenharmony_ci if (versym || verdef || verneed) 606e01aa904Sopenharmony_ci { 607e01aa904Sopenharmony_ci // At least one the versionning sections was found. Return it. 608e01aa904Sopenharmony_ci versym_section = versym; 609e01aa904Sopenharmony_ci verdef_section = verdef; 610e01aa904Sopenharmony_ci verneed_section = verneed; 611e01aa904Sopenharmony_ci return true; 612e01aa904Sopenharmony_ci } 613e01aa904Sopenharmony_ci 614e01aa904Sopenharmony_ci return false; 615e01aa904Sopenharmony_ci} 616e01aa904Sopenharmony_ci 617e01aa904Sopenharmony_ci/// Return the __ksymtab section of a linux kernel ELF file (either 618e01aa904Sopenharmony_ci/// a vmlinux binary or a kernel module). 619e01aa904Sopenharmony_ci/// 620e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to consider. 621e01aa904Sopenharmony_ci/// 622e01aa904Sopenharmony_ci/// @return the __ksymtab section if found, nil otherwise. 623e01aa904Sopenharmony_ciElf_Scn* 624e01aa904Sopenharmony_cifind_ksymtab_section(Elf* elf_handle) 625e01aa904Sopenharmony_ci{return find_section(elf_handle, "__ksymtab", SHT_PROGBITS);} 626e01aa904Sopenharmony_ci 627e01aa904Sopenharmony_ci/// Return the __ksymtab_gpl section of a linux kernel ELF file (either 628e01aa904Sopenharmony_ci/// a vmlinux binary or a kernel module). 629e01aa904Sopenharmony_ci/// 630e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to consider. 631e01aa904Sopenharmony_ci/// 632e01aa904Sopenharmony_ci/// @return the __ksymtab section if found, nil otherwise. 633e01aa904Sopenharmony_ciElf_Scn* 634e01aa904Sopenharmony_cifind_ksymtab_gpl_section(Elf* elf_handle) 635e01aa904Sopenharmony_ci{return find_section(elf_handle, "__ksymtab_gpl", SHT_PROGBITS);} 636e01aa904Sopenharmony_ci 637e01aa904Sopenharmony_ci/// Find the __ksymtab_strings section of a Linux kernel binary. 638e01aa904Sopenharmony_ci/// 639e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use. 640e01aa904Sopenharmony_ci/// 641e01aa904Sopenharmony_ci/// @return the find_ksymtab_strings_section of the linux kernel 642e01aa904Sopenharmony_ci/// binary denoted by @p elf_handle, or nil if such a section could 643e01aa904Sopenharmony_ci/// not be found. 644e01aa904Sopenharmony_ciElf_Scn* 645e01aa904Sopenharmony_cifind_ksymtab_strings_section(Elf *elf_handle) 646e01aa904Sopenharmony_ci{ 647e01aa904Sopenharmony_ci if (is_linux_kernel(elf_handle)) 648e01aa904Sopenharmony_ci return find_section(elf_handle, "__ksymtab_strings", SHT_PROGBITS); 649e01aa904Sopenharmony_ci return 0; 650e01aa904Sopenharmony_ci} 651e01aa904Sopenharmony_ci 652e01aa904Sopenharmony_ci/// Return the .rel{a,} section corresponding to a given section. 653e01aa904Sopenharmony_ci/// 654e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to consider. 655e01aa904Sopenharmony_ci/// 656e01aa904Sopenharmony_ci/// @param target_section the section to search the relocation section for 657e01aa904Sopenharmony_ci/// 658e01aa904Sopenharmony_ci/// @return the .rel{a,} section if found, null otherwise. 659e01aa904Sopenharmony_ciElf_Scn* 660e01aa904Sopenharmony_cifind_relocation_section(Elf* elf_handle, Elf_Scn* target_section) 661e01aa904Sopenharmony_ci{ 662e01aa904Sopenharmony_ci if (target_section) 663e01aa904Sopenharmony_ci { 664e01aa904Sopenharmony_ci // the relo section we are searching for has this index as sh_info 665e01aa904Sopenharmony_ci size_t target_index = elf_ndxscn(target_section); 666e01aa904Sopenharmony_ci 667e01aa904Sopenharmony_ci // now iterate over all the sections, look for relocation sections and 668e01aa904Sopenharmony_ci // find the one that points to the section we are searching for 669e01aa904Sopenharmony_ci Elf_Scn* section = 0; 670e01aa904Sopenharmony_ci GElf_Shdr header_mem, *header; 671e01aa904Sopenharmony_ci while ((section = elf_nextscn(elf_handle, section)) != 0) 672e01aa904Sopenharmony_ci { 673e01aa904Sopenharmony_ci header = gelf_getshdr(section, &header_mem); 674e01aa904Sopenharmony_ci if (header == NULL 675e01aa904Sopenharmony_ci || (header->sh_type != SHT_RELA && header->sh_type != SHT_REL)) 676e01aa904Sopenharmony_ci continue; 677e01aa904Sopenharmony_ci 678e01aa904Sopenharmony_ci if (header->sh_info == target_index) 679e01aa904Sopenharmony_ci return section; 680e01aa904Sopenharmony_ci } 681e01aa904Sopenharmony_ci } 682e01aa904Sopenharmony_ci return NULL; 683e01aa904Sopenharmony_ci} 684e01aa904Sopenharmony_ci 685e01aa904Sopenharmony_ci/// Return the string table used by the given symbol table. 686e01aa904Sopenharmony_ci/// 687e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use. 688e01aa904Sopenharmony_ci/// 689e01aa904Sopenharmony_ci/// @param symtab_section section containing a symbol table. 690e01aa904Sopenharmony_ci/// 691e01aa904Sopenharmony_ci/// @return the string table linked by the symtab, if it is not NULL. 692e01aa904Sopenharmony_ciElf_Scn* 693e01aa904Sopenharmony_cifind_strtab_for_symtab_section(Elf* elf_handle, Elf_Scn* symtab_section) 694e01aa904Sopenharmony_ci{ 695e01aa904Sopenharmony_ci Elf_Scn *strtab_section = NULL; 696e01aa904Sopenharmony_ci 697e01aa904Sopenharmony_ci if (symtab_section) 698e01aa904Sopenharmony_ci { 699e01aa904Sopenharmony_ci GElf_Shdr symtab_shdr_mem, *symtab_shdr; 700e01aa904Sopenharmony_ci 701e01aa904Sopenharmony_ci symtab_shdr = gelf_getshdr(symtab_section, &symtab_shdr_mem); 702e01aa904Sopenharmony_ci strtab_section = elf_getscn(elf_handle, symtab_shdr->sh_link); 703e01aa904Sopenharmony_ci } 704e01aa904Sopenharmony_ci 705e01aa904Sopenharmony_ci return strtab_section; 706e01aa904Sopenharmony_ci} 707e01aa904Sopenharmony_ci 708e01aa904Sopenharmony_ci/// Get the version definition (from the SHT_GNU_verdef section) of a 709e01aa904Sopenharmony_ci/// given symbol represented by a pointer to GElf_Versym. 710e01aa904Sopenharmony_ci/// 711e01aa904Sopenharmony_ci/// @param elf_hande the elf handle to use. 712e01aa904Sopenharmony_ci/// 713e01aa904Sopenharmony_ci/// @param versym the symbol to get the version definition for. 714e01aa904Sopenharmony_ci/// 715e01aa904Sopenharmony_ci/// @param verdef_section the SHT_GNU_verdef section. 716e01aa904Sopenharmony_ci/// 717e01aa904Sopenharmony_ci/// @param version the resulting version definition. This is set iff 718e01aa904Sopenharmony_ci/// the function returns true. 719e01aa904Sopenharmony_ci/// 720e01aa904Sopenharmony_ci/// @return true upon successful completion, false otherwise. 721e01aa904Sopenharmony_cibool 722e01aa904Sopenharmony_ciget_version_definition_for_versym(Elf* elf_handle, 723e01aa904Sopenharmony_ci GElf_Versym* versym, 724e01aa904Sopenharmony_ci Elf_Scn* verdef_section, 725e01aa904Sopenharmony_ci elf_symbol::version& version) 726e01aa904Sopenharmony_ci{ 727e01aa904Sopenharmony_ci Elf_Data* verdef_data = elf_getdata(verdef_section, NULL); 728e01aa904Sopenharmony_ci GElf_Verdef verdef_mem; 729e01aa904Sopenharmony_ci GElf_Verdef* verdef = gelf_getverdef(verdef_data, 0, &verdef_mem); 730e01aa904Sopenharmony_ci size_t vd_offset = 0; 731e01aa904Sopenharmony_ci 732e01aa904Sopenharmony_ci for (;; vd_offset += verdef->vd_next) 733e01aa904Sopenharmony_ci { 734e01aa904Sopenharmony_ci for (;verdef != 0;) 735e01aa904Sopenharmony_ci { 736e01aa904Sopenharmony_ci if (verdef->vd_ndx == (*versym & 0x7fff)) 737e01aa904Sopenharmony_ci // Found the version of the symbol. 738e01aa904Sopenharmony_ci break; 739e01aa904Sopenharmony_ci vd_offset += verdef->vd_next; 740e01aa904Sopenharmony_ci verdef = (verdef->vd_next == 0 741e01aa904Sopenharmony_ci ? 0 742e01aa904Sopenharmony_ci : gelf_getverdef(verdef_data, vd_offset, &verdef_mem)); 743e01aa904Sopenharmony_ci } 744e01aa904Sopenharmony_ci 745e01aa904Sopenharmony_ci if (verdef != 0) 746e01aa904Sopenharmony_ci { 747e01aa904Sopenharmony_ci GElf_Verdaux verdaux_mem; 748e01aa904Sopenharmony_ci GElf_Verdaux *verdaux = gelf_getverdaux(verdef_data, 749e01aa904Sopenharmony_ci vd_offset + verdef->vd_aux, 750e01aa904Sopenharmony_ci &verdaux_mem); 751e01aa904Sopenharmony_ci GElf_Shdr header_mem; 752e01aa904Sopenharmony_ci GElf_Shdr* verdef_section_header = gelf_getshdr(verdef_section, 753e01aa904Sopenharmony_ci &header_mem); 754e01aa904Sopenharmony_ci size_t verdef_stridx = verdef_section_header->sh_link; 755e01aa904Sopenharmony_ci version.str(elf_strptr(elf_handle, verdef_stridx, verdaux->vda_name)); 756e01aa904Sopenharmony_ci if (*versym & 0x8000) 757e01aa904Sopenharmony_ci version.is_default(false); 758e01aa904Sopenharmony_ci else 759e01aa904Sopenharmony_ci version.is_default(true); 760e01aa904Sopenharmony_ci return true; 761e01aa904Sopenharmony_ci } 762e01aa904Sopenharmony_ci if (!verdef || verdef->vd_next == 0) 763e01aa904Sopenharmony_ci break; 764e01aa904Sopenharmony_ci } 765e01aa904Sopenharmony_ci return false; 766e01aa904Sopenharmony_ci} 767e01aa904Sopenharmony_ci 768e01aa904Sopenharmony_ci/// Get the version needed (from the SHT_GNU_verneed section) to 769e01aa904Sopenharmony_ci/// resolve an undefined symbol represented by a pointer to 770e01aa904Sopenharmony_ci/// GElf_Versym. 771e01aa904Sopenharmony_ci/// 772e01aa904Sopenharmony_ci/// @param elf_hande the elf handle to use. 773e01aa904Sopenharmony_ci/// 774e01aa904Sopenharmony_ci/// @param versym the symbol to get the version definition for. 775e01aa904Sopenharmony_ci/// 776e01aa904Sopenharmony_ci/// @param verneed_section the SHT_GNU_verneed section. 777e01aa904Sopenharmony_ci/// 778e01aa904Sopenharmony_ci/// @param version the resulting version definition. This is set iff 779e01aa904Sopenharmony_ci/// the function returns true. 780e01aa904Sopenharmony_ci/// 781e01aa904Sopenharmony_ci/// @return true upon successful completion, false otherwise. 782e01aa904Sopenharmony_cibool 783e01aa904Sopenharmony_ciget_version_needed_for_versym(Elf* elf_handle, 784e01aa904Sopenharmony_ci GElf_Versym* versym, 785e01aa904Sopenharmony_ci Elf_Scn* verneed_section, 786e01aa904Sopenharmony_ci elf_symbol::version& version) 787e01aa904Sopenharmony_ci{ 788e01aa904Sopenharmony_ci if (versym == 0 || elf_handle == 0 || verneed_section == 0) 789e01aa904Sopenharmony_ci return false; 790e01aa904Sopenharmony_ci 791e01aa904Sopenharmony_ci size_t vn_offset = 0; 792e01aa904Sopenharmony_ci Elf_Data* verneed_data = elf_getdata(verneed_section, NULL); 793e01aa904Sopenharmony_ci GElf_Verneed verneed_mem; 794e01aa904Sopenharmony_ci GElf_Verneed* verneed = gelf_getverneed(verneed_data, 0, &verneed_mem); 795e01aa904Sopenharmony_ci 796e01aa904Sopenharmony_ci for (;verneed; vn_offset += verneed->vn_next) 797e01aa904Sopenharmony_ci { 798e01aa904Sopenharmony_ci size_t vna_offset = vn_offset; 799e01aa904Sopenharmony_ci GElf_Vernaux vernaux_mem; 800e01aa904Sopenharmony_ci GElf_Vernaux *vernaux = gelf_getvernaux(verneed_data, 801e01aa904Sopenharmony_ci vn_offset + verneed->vn_aux, 802e01aa904Sopenharmony_ci &vernaux_mem); 803e01aa904Sopenharmony_ci for (;vernaux != 0 && verneed;) 804e01aa904Sopenharmony_ci { 805e01aa904Sopenharmony_ci if (vernaux->vna_other == *versym) 806e01aa904Sopenharmony_ci // Found the version of the symbol. 807e01aa904Sopenharmony_ci break; 808e01aa904Sopenharmony_ci vna_offset += verneed->vn_next; 809e01aa904Sopenharmony_ci verneed = (verneed->vn_next == 0 810e01aa904Sopenharmony_ci ? 0 811e01aa904Sopenharmony_ci : gelf_getverneed(verneed_data, vna_offset, &verneed_mem)); 812e01aa904Sopenharmony_ci } 813e01aa904Sopenharmony_ci 814e01aa904Sopenharmony_ci if (verneed != 0 && vernaux != 0 && vernaux->vna_other == *versym) 815e01aa904Sopenharmony_ci { 816e01aa904Sopenharmony_ci GElf_Shdr header_mem; 817e01aa904Sopenharmony_ci GElf_Shdr* verneed_section_header = gelf_getshdr(verneed_section, 818e01aa904Sopenharmony_ci &header_mem); 819e01aa904Sopenharmony_ci size_t verneed_stridx = verneed_section_header->sh_link; 820e01aa904Sopenharmony_ci version.str(elf_strptr(elf_handle, 821e01aa904Sopenharmony_ci verneed_stridx, 822e01aa904Sopenharmony_ci vernaux->vna_name)); 823e01aa904Sopenharmony_ci if (*versym & 0x8000) 824e01aa904Sopenharmony_ci version.is_default(false); 825e01aa904Sopenharmony_ci else 826e01aa904Sopenharmony_ci version.is_default(true); 827e01aa904Sopenharmony_ci return true; 828e01aa904Sopenharmony_ci } 829e01aa904Sopenharmony_ci 830e01aa904Sopenharmony_ci if (!verneed || verneed->vn_next == 0) 831e01aa904Sopenharmony_ci break; 832e01aa904Sopenharmony_ci } 833e01aa904Sopenharmony_ci return false; 834e01aa904Sopenharmony_ci} 835e01aa904Sopenharmony_ci 836e01aa904Sopenharmony_ci/// Return the version for a symbol that is at a given index in its 837e01aa904Sopenharmony_ci/// SHT_SYMTAB section. 838e01aa904Sopenharmony_ci/// 839e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use. 840e01aa904Sopenharmony_ci/// 841e01aa904Sopenharmony_ci/// @param symbol_index the index of the symbol to consider. 842e01aa904Sopenharmony_ci/// 843e01aa904Sopenharmony_ci/// @param get_def_version if this is true, it means that that we want 844e01aa904Sopenharmony_ci/// the version for a defined symbol; in that case, the version is 845e01aa904Sopenharmony_ci/// looked for in a section of type SHT_GNU_verdef. Otherwise, if 846e01aa904Sopenharmony_ci/// this parameter is false, this means that we want the version for 847e01aa904Sopenharmony_ci/// an undefined symbol; in that case, the version is the needed one 848e01aa904Sopenharmony_ci/// for the symbol to be resolved; so the version is looked fo in a 849e01aa904Sopenharmony_ci/// section of type SHT_GNU_verneed. 850e01aa904Sopenharmony_ci/// 851e01aa904Sopenharmony_ci/// @param version the version found for symbol at @p symbol_index. 852e01aa904Sopenharmony_ci/// 853e01aa904Sopenharmony_ci/// @return true iff a version was found for symbol at index @p 854e01aa904Sopenharmony_ci/// symbol_index. 855e01aa904Sopenharmony_cibool 856e01aa904Sopenharmony_ciget_version_for_symbol(Elf* elf_handle, 857e01aa904Sopenharmony_ci size_t symbol_index, 858e01aa904Sopenharmony_ci bool get_def_version, 859e01aa904Sopenharmony_ci elf_symbol::version& version) 860e01aa904Sopenharmony_ci{ 861e01aa904Sopenharmony_ci Elf_Scn *versym_section = NULL, 862e01aa904Sopenharmony_ci *verdef_section = NULL, 863e01aa904Sopenharmony_ci *verneed_section = NULL; 864e01aa904Sopenharmony_ci 865e01aa904Sopenharmony_ci if (!get_symbol_versionning_sections(elf_handle, 866e01aa904Sopenharmony_ci versym_section, 867e01aa904Sopenharmony_ci verdef_section, 868e01aa904Sopenharmony_ci verneed_section)) 869e01aa904Sopenharmony_ci return false; 870e01aa904Sopenharmony_ci 871e01aa904Sopenharmony_ci GElf_Versym versym_mem; 872e01aa904Sopenharmony_ci Elf_Data* versym_data = (versym_section) 873e01aa904Sopenharmony_ci ? elf_getdata(versym_section, NULL) 874e01aa904Sopenharmony_ci : NULL; 875e01aa904Sopenharmony_ci GElf_Versym* versym = (versym_data) 876e01aa904Sopenharmony_ci ? gelf_getversym(versym_data, symbol_index, &versym_mem) 877e01aa904Sopenharmony_ci : NULL; 878e01aa904Sopenharmony_ci 879e01aa904Sopenharmony_ci if (versym == 0 || *versym <= 1) 880e01aa904Sopenharmony_ci // I got these value from the code of readelf.c in elfutils. 881e01aa904Sopenharmony_ci // Apparently, if the symbol version entry has these values, the 882e01aa904Sopenharmony_ci // symbol must be discarded. This is not documented in the 883e01aa904Sopenharmony_ci // official specification. 884e01aa904Sopenharmony_ci return false; 885e01aa904Sopenharmony_ci 886e01aa904Sopenharmony_ci if (get_def_version) 887e01aa904Sopenharmony_ci { 888e01aa904Sopenharmony_ci if (*versym == 0x8001) 889e01aa904Sopenharmony_ci // I got this value from the code of readelf.c in elfutils 890e01aa904Sopenharmony_ci // too. It's not really documented in the official 891e01aa904Sopenharmony_ci // specification. 892e01aa904Sopenharmony_ci return false; 893e01aa904Sopenharmony_ci 894e01aa904Sopenharmony_ci if (verdef_section 895e01aa904Sopenharmony_ci && get_version_definition_for_versym(elf_handle, versym, 896e01aa904Sopenharmony_ci verdef_section, version)) 897e01aa904Sopenharmony_ci return true; 898e01aa904Sopenharmony_ci } 899e01aa904Sopenharmony_ci else 900e01aa904Sopenharmony_ci { 901e01aa904Sopenharmony_ci if (verneed_section 902e01aa904Sopenharmony_ci && get_version_needed_for_versym(elf_handle, versym, 903e01aa904Sopenharmony_ci verneed_section, version)) 904e01aa904Sopenharmony_ci return true; 905e01aa904Sopenharmony_ci } 906e01aa904Sopenharmony_ci 907e01aa904Sopenharmony_ci return false; 908e01aa904Sopenharmony_ci} 909e01aa904Sopenharmony_ci 910e01aa904Sopenharmony_ci/// Return the CRC from the "__crc_" symbol. 911e01aa904Sopenharmony_ci/// 912e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use. 913e01aa904Sopenharmony_ci/// 914e01aa904Sopenharmony_ci/// @param crc_symbol symbol containing CRC value. 915e01aa904Sopenharmony_ci/// 916e01aa904Sopenharmony_ci/// @param crc_value the CRC found for @p crc_symbol. 917e01aa904Sopenharmony_ci/// 918e01aa904Sopenharmony_ci/// @return true iff a CRC was found for given @p crc_symbol. 919e01aa904Sopenharmony_cibool 920e01aa904Sopenharmony_ciget_crc_for_symbol(Elf* elf_handle, GElf_Sym* crc_symbol, uint32_t& crc_value) 921e01aa904Sopenharmony_ci{ 922e01aa904Sopenharmony_ci size_t crc_section_index = crc_symbol->st_shndx; 923e01aa904Sopenharmony_ci uint64_t crc_symbol_value = crc_symbol->st_value; 924e01aa904Sopenharmony_ci if (crc_section_index == SHN_ABS) 925e01aa904Sopenharmony_ci { 926e01aa904Sopenharmony_ci crc_value = crc_symbol_value; 927e01aa904Sopenharmony_ci return true; 928e01aa904Sopenharmony_ci } 929e01aa904Sopenharmony_ci 930e01aa904Sopenharmony_ci Elf_Scn* kcrctab_section = elf_getscn(elf_handle, crc_section_index); 931e01aa904Sopenharmony_ci if (kcrctab_section == NULL) 932e01aa904Sopenharmony_ci return false; 933e01aa904Sopenharmony_ci 934e01aa904Sopenharmony_ci GElf_Shdr sheader_mem; 935e01aa904Sopenharmony_ci GElf_Shdr* sheader = gelf_getshdr(kcrctab_section, &sheader_mem); 936e01aa904Sopenharmony_ci if (sheader == NULL) 937e01aa904Sopenharmony_ci return false; 938e01aa904Sopenharmony_ci 939e01aa904Sopenharmony_ci Elf_Data* kcrctab_data = elf_rawdata(kcrctab_section, NULL); 940e01aa904Sopenharmony_ci if (kcrctab_data == NULL) 941e01aa904Sopenharmony_ci return false; 942e01aa904Sopenharmony_ci 943e01aa904Sopenharmony_ci if (crc_symbol_value < sheader->sh_addr) 944e01aa904Sopenharmony_ci return false; 945e01aa904Sopenharmony_ci 946e01aa904Sopenharmony_ci size_t offset = crc_symbol_value - sheader->sh_addr; 947e01aa904Sopenharmony_ci if (offset + sizeof(uint32_t) > kcrctab_data->d_size 948e01aa904Sopenharmony_ci || offset + sizeof(uint32_t) > sheader->sh_size) 949e01aa904Sopenharmony_ci return false; 950e01aa904Sopenharmony_ci 951e01aa904Sopenharmony_ci crc_value = *reinterpret_cast<uint32_t*>( 952e01aa904Sopenharmony_ci reinterpret_cast<char*>(kcrctab_data->d_buf) + offset); 953e01aa904Sopenharmony_ci 954e01aa904Sopenharmony_ci return true; 955e01aa904Sopenharmony_ci} 956e01aa904Sopenharmony_ci 957e01aa904Sopenharmony_ci/// Test if the architecture of the current binary is ppc64. 958e01aa904Sopenharmony_ci/// 959e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider. 960e01aa904Sopenharmony_ci/// 961e01aa904Sopenharmony_ci/// @return true iff the architecture of the current binary is ppc64. 962e01aa904Sopenharmony_cibool 963e01aa904Sopenharmony_ciarchitecture_is_ppc64(Elf* elf_handle) 964e01aa904Sopenharmony_ci{ 965e01aa904Sopenharmony_ci GElf_Ehdr eh_mem; 966e01aa904Sopenharmony_ci GElf_Ehdr* elf_header = gelf_getehdr(elf_handle, &eh_mem); 967e01aa904Sopenharmony_ci return (elf_header && elf_header->e_machine == EM_PPC64); 968e01aa904Sopenharmony_ci} 969e01aa904Sopenharmony_ci 970e01aa904Sopenharmony_ci/// Test if the architecture of the current binary is ppc32. 971e01aa904Sopenharmony_ci/// 972e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider. 973e01aa904Sopenharmony_ci/// 974e01aa904Sopenharmony_ci/// @return true iff the architecture of the current binary is ppc32. 975e01aa904Sopenharmony_cibool 976e01aa904Sopenharmony_ciarchitecture_is_ppc32(Elf* elf_handle) 977e01aa904Sopenharmony_ci{ 978e01aa904Sopenharmony_ci GElf_Ehdr eh_mem; 979e01aa904Sopenharmony_ci GElf_Ehdr* elf_header = gelf_getehdr(elf_handle, &eh_mem); 980e01aa904Sopenharmony_ci return (elf_header && elf_header->e_machine == EM_PPC); 981e01aa904Sopenharmony_ci} 982e01aa904Sopenharmony_ci 983e01aa904Sopenharmony_ci/// Test if the architecture of the current binary is arm32. 984e01aa904Sopenharmony_ci/// 985e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider. 986e01aa904Sopenharmony_ci/// 987e01aa904Sopenharmony_ci/// @return true iff the architecture of the current binary is arm32. 988e01aa904Sopenharmony_cibool 989e01aa904Sopenharmony_ciarchitecture_is_arm32(Elf* elf_handle) 990e01aa904Sopenharmony_ci{ 991e01aa904Sopenharmony_ci GElf_Ehdr eh_mem; 992e01aa904Sopenharmony_ci GElf_Ehdr* elf_header = gelf_getehdr(elf_handle, &eh_mem); 993e01aa904Sopenharmony_ci return (elf_header && elf_header->e_machine == EM_ARM); 994e01aa904Sopenharmony_ci} 995e01aa904Sopenharmony_ci 996e01aa904Sopenharmony_ci/// Test if the architecture of the current binary is arm64. 997e01aa904Sopenharmony_ci/// 998e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider. 999e01aa904Sopenharmony_ci/// 1000e01aa904Sopenharmony_ci/// @return true iff the architecture of the current binary is arm64. 1001e01aa904Sopenharmony_cibool 1002e01aa904Sopenharmony_ciarchitecture_is_arm64(Elf* elf_handle) 1003e01aa904Sopenharmony_ci{ 1004e01aa904Sopenharmony_ci#ifdef HAVE_EM_AARCH64_MACRO 1005e01aa904Sopenharmony_ci GElf_Ehdr eh_mem; 1006e01aa904Sopenharmony_ci GElf_Ehdr* elf_header = gelf_getehdr(elf_handle, &eh_mem); 1007e01aa904Sopenharmony_ci return (elf_header && elf_header->e_machine == EM_AARCH64); 1008e01aa904Sopenharmony_ci#else 1009e01aa904Sopenharmony_ci return false; 1010e01aa904Sopenharmony_ci#endif 1011e01aa904Sopenharmony_ci} 1012e01aa904Sopenharmony_ci 1013e01aa904Sopenharmony_ci/// Test if the endianness of the current binary is Big Endian. 1014e01aa904Sopenharmony_ci/// 1015e01aa904Sopenharmony_ci/// https://en.wikipedia.org/wiki/Endianness. 1016e01aa904Sopenharmony_ci/// 1017e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider. 1018e01aa904Sopenharmony_ci/// 1019e01aa904Sopenharmony_ci/// @return true iff the current binary is Big Endian. 1020e01aa904Sopenharmony_cibool 1021e01aa904Sopenharmony_ciarchitecture_is_big_endian(Elf* elf_handle) 1022e01aa904Sopenharmony_ci{ 1023e01aa904Sopenharmony_ci GElf_Ehdr elf_header; 1024e01aa904Sopenharmony_ci gelf_getehdr(elf_handle, &elf_header); 1025e01aa904Sopenharmony_ci 1026e01aa904Sopenharmony_ci bool is_big_endian = (elf_header.e_ident[EI_DATA] == ELFDATA2MSB); 1027e01aa904Sopenharmony_ci 1028e01aa904Sopenharmony_ci if (!is_big_endian) 1029e01aa904Sopenharmony_ci ABG_ASSERT(elf_header.e_ident[EI_DATA] == ELFDATA2LSB); 1030e01aa904Sopenharmony_ci 1031e01aa904Sopenharmony_ci return is_big_endian; 1032e01aa904Sopenharmony_ci} 1033e01aa904Sopenharmony_ci 1034e01aa904Sopenharmony_ci/// Read N bytes and convert their value into an integer type T. 1035e01aa904Sopenharmony_ci/// 1036e01aa904Sopenharmony_ci/// Note that N cannot be bigger than 8 for now. The type passed needs to be at 1037e01aa904Sopenharmony_ci/// least of the size of number_of_bytes. 1038e01aa904Sopenharmony_ci/// 1039e01aa904Sopenharmony_ci/// @param bytes the array of bytes to read the next 8 bytes from. 1040e01aa904Sopenharmony_ci/// Note that this array must be at least 8 bytes long. 1041e01aa904Sopenharmony_ci/// 1042e01aa904Sopenharmony_ci/// @param number_of_bytes the number of bytes to read. This number 1043e01aa904Sopenharmony_ci/// cannot be bigger than 8. 1044e01aa904Sopenharmony_ci/// 1045e01aa904Sopenharmony_ci/// @param is_big_endian if true, read the 8 bytes in Big Endian 1046e01aa904Sopenharmony_ci/// mode, otherwise, read them in Little Endian. 1047e01aa904Sopenharmony_ci/// 1048e01aa904Sopenharmony_ci/// @param result where to store the resuting integer that was read. 1049e01aa904Sopenharmony_ci/// 1050e01aa904Sopenharmony_ci/// 1051e01aa904Sopenharmony_ci/// @param true if the 8 bytes could be read, false otherwise. 1052e01aa904Sopenharmony_citemplate <typename T> 1053e01aa904Sopenharmony_cibool 1054e01aa904Sopenharmony_ciread_int_from_array_of_bytes(const uint8_t* bytes, 1055e01aa904Sopenharmony_ci unsigned char number_of_bytes, 1056e01aa904Sopenharmony_ci bool is_big_endian, 1057e01aa904Sopenharmony_ci T& result) 1058e01aa904Sopenharmony_ci{ 1059e01aa904Sopenharmony_ci if (!bytes) 1060e01aa904Sopenharmony_ci return false; 1061e01aa904Sopenharmony_ci 1062e01aa904Sopenharmony_ci ABG_ASSERT(number_of_bytes <= 8); 1063e01aa904Sopenharmony_ci ABG_ASSERT(number_of_bytes <= sizeof(T)); 1064e01aa904Sopenharmony_ci 1065e01aa904Sopenharmony_ci T res = 0; 1066e01aa904Sopenharmony_ci 1067e01aa904Sopenharmony_ci const uint8_t* cur = bytes; 1068e01aa904Sopenharmony_ci if (is_big_endian) 1069e01aa904Sopenharmony_ci { 1070e01aa904Sopenharmony_ci // In Big Endian, the most significant byte is at the lowest 1071e01aa904Sopenharmony_ci // address. 1072e01aa904Sopenharmony_ci const uint8_t* msb = cur; 1073e01aa904Sopenharmony_ci res = *msb; 1074e01aa904Sopenharmony_ci 1075e01aa904Sopenharmony_ci // Now read the remaining least significant bytes. 1076e01aa904Sopenharmony_ci for (uint i = 1; i < number_of_bytes; ++i) 1077e01aa904Sopenharmony_ci res = (res << 8) | ((T)msb[i]); 1078e01aa904Sopenharmony_ci } 1079e01aa904Sopenharmony_ci else 1080e01aa904Sopenharmony_ci { 1081e01aa904Sopenharmony_ci // In Little Endian, the least significant byte is at the 1082e01aa904Sopenharmony_ci // lowest address. 1083e01aa904Sopenharmony_ci const uint8_t* lsb = cur; 1084e01aa904Sopenharmony_ci res = *lsb; 1085e01aa904Sopenharmony_ci // Now read the remaining most significant bytes. 1086e01aa904Sopenharmony_ci for (uint i = 1; i < number_of_bytes; ++i) 1087e01aa904Sopenharmony_ci res = res | (((T)lsb[i]) << i * 8); 1088e01aa904Sopenharmony_ci } 1089e01aa904Sopenharmony_ci 1090e01aa904Sopenharmony_ci result = res; 1091e01aa904Sopenharmony_ci return true; 1092e01aa904Sopenharmony_ci} 1093e01aa904Sopenharmony_ci 1094e01aa904Sopenharmony_ci/// Read 8 bytes and convert their value into an uint64_t. 1095e01aa904Sopenharmony_ci/// 1096e01aa904Sopenharmony_ci/// @param bytes the array of bytes to read the next 8 bytes from. 1097e01aa904Sopenharmony_ci/// Note that this array must be at least 8 bytes long. 1098e01aa904Sopenharmony_ci/// 1099e01aa904Sopenharmony_ci/// @param result where to store the resuting uint64_t that was read. 1100e01aa904Sopenharmony_ci/// 1101e01aa904Sopenharmony_ci/// @param is_big_endian if true, read the 8 bytes in Big Endian 1102e01aa904Sopenharmony_ci/// mode, otherwise, read them in Little Endian. 1103e01aa904Sopenharmony_ci/// 1104e01aa904Sopenharmony_ci/// @param true if the 8 bytes could be read, false otherwise. 1105e01aa904Sopenharmony_cibool 1106e01aa904Sopenharmony_ciread_uint64_from_array_of_bytes(const uint8_t* bytes, 1107e01aa904Sopenharmony_ci bool is_big_endian, 1108e01aa904Sopenharmony_ci uint64_t& result) 1109e01aa904Sopenharmony_ci{ 1110e01aa904Sopenharmony_ci return read_int_from_array_of_bytes(bytes, 8, is_big_endian, result); 1111e01aa904Sopenharmony_ci} 1112e01aa904Sopenharmony_ci 1113e01aa904Sopenharmony_ci 1114e01aa904Sopenharmony_ci/// Lookup the address of the function entry point that corresponds 1115e01aa904Sopenharmony_ci/// to the address of a given function descriptor. 1116e01aa904Sopenharmony_ci/// 1117e01aa904Sopenharmony_ci/// On PPC64, a function pointer is the address of a function 1118e01aa904Sopenharmony_ci/// descriptor. Function descriptors are located in the .opd 1119e01aa904Sopenharmony_ci/// section. Each function descriptor is a triplet of three 1120e01aa904Sopenharmony_ci/// addresses, each one on 64 bits. Among those three address only 1121e01aa904Sopenharmony_ci/// the first one is of any interest to us: the address of the entry 1122e01aa904Sopenharmony_ci/// point of the function. 1123e01aa904Sopenharmony_ci/// 1124e01aa904Sopenharmony_ci/// This function returns the address of the entry point of the 1125e01aa904Sopenharmony_ci/// function whose descriptor's address is given. 1126e01aa904Sopenharmony_ci/// 1127e01aa904Sopenharmony_ci/// http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#FUNC-DES 1128e01aa904Sopenharmony_ci/// 1129e01aa904Sopenharmony_ci/// https://www.ibm.com/developerworks/community/blogs/5894415f-be62-4bc0-81c5-3956e82276f3/entry/deeply_understand_64_bit_powerpc_elf_abi_function_descriptors?lang=en 1130e01aa904Sopenharmony_ci/// 1131e01aa904Sopenharmony_ci/// @param fn_desc_address the address of the function descriptor to 1132e01aa904Sopenharmony_ci/// consider. 1133e01aa904Sopenharmony_ci/// 1134e01aa904Sopenharmony_ci/// @return the address of the entry point of the function whose 1135e01aa904Sopenharmony_ci/// descriptor has the address @p fn_desc_address. If there is no 1136e01aa904Sopenharmony_ci/// .opd section (e.g because we are not on ppc64) or more generally 1137e01aa904Sopenharmony_ci/// if the function descriptor could not be found then this function 1138e01aa904Sopenharmony_ci/// just returns the address of the fuction descriptor. 1139e01aa904Sopenharmony_ciGElf_Addr 1140e01aa904Sopenharmony_cilookup_ppc64_elf_fn_entry_point_address(Elf* elf_handle, GElf_Addr fn_desc_address) 1141e01aa904Sopenharmony_ci{ 1142e01aa904Sopenharmony_ci if (!elf_handle) 1143e01aa904Sopenharmony_ci return fn_desc_address; 1144e01aa904Sopenharmony_ci 1145e01aa904Sopenharmony_ci if (!architecture_is_ppc64(elf_handle)) 1146e01aa904Sopenharmony_ci return fn_desc_address; 1147e01aa904Sopenharmony_ci 1148e01aa904Sopenharmony_ci bool is_big_endian = architecture_is_big_endian(elf_handle); 1149e01aa904Sopenharmony_ci 1150e01aa904Sopenharmony_ci Elf_Scn* opd_section = find_opd_section(elf_handle); 1151e01aa904Sopenharmony_ci if (!opd_section) 1152e01aa904Sopenharmony_ci return fn_desc_address; 1153e01aa904Sopenharmony_ci 1154e01aa904Sopenharmony_ci GElf_Shdr header_mem; 1155e01aa904Sopenharmony_ci // The section header of the .opd section. 1156e01aa904Sopenharmony_ci GElf_Shdr* opd_sheader = gelf_getshdr(opd_section, &header_mem); 1157e01aa904Sopenharmony_ci 1158e01aa904Sopenharmony_ci // The offset of the function descriptor entry, in the .opd 1159e01aa904Sopenharmony_ci // section. 1160e01aa904Sopenharmony_ci size_t fn_desc_offset = fn_desc_address - opd_sheader->sh_addr; 1161e01aa904Sopenharmony_ci Elf_Data* elf_data = elf_rawdata(opd_section, 0); 1162e01aa904Sopenharmony_ci 1163e01aa904Sopenharmony_ci // Ensure that the opd_section has at least 8 bytes, starting from 1164e01aa904Sopenharmony_ci // the offset we want read the data from. 1165e01aa904Sopenharmony_ci if (elf_data->d_size <= fn_desc_offset + 8) 1166e01aa904Sopenharmony_ci return fn_desc_address; 1167e01aa904Sopenharmony_ci 1168e01aa904Sopenharmony_ci // A pointer to the data of the .opd section, that we can actually 1169e01aa904Sopenharmony_ci // do something with. 1170e01aa904Sopenharmony_ci uint8_t* bytes = (uint8_t*)elf_data->d_buf; 1171e01aa904Sopenharmony_ci 1172e01aa904Sopenharmony_ci // The resulting address we are looking for is going to be formed 1173e01aa904Sopenharmony_ci // in this variable. 1174e01aa904Sopenharmony_ci GElf_Addr result = 0; 1175e01aa904Sopenharmony_ci ABG_ASSERT(read_uint64_from_array_of_bytes(bytes + fn_desc_offset, 1176e01aa904Sopenharmony_ci is_big_endian, result)); 1177e01aa904Sopenharmony_ci 1178e01aa904Sopenharmony_ci return result; 1179e01aa904Sopenharmony_ci} 1180e01aa904Sopenharmony_ci 1181e01aa904Sopenharmony_ci/// Test if the ELF binary denoted by a given ELF handle is a Linux 1182e01aa904Sopenharmony_ci/// Kernel Module. 1183e01aa904Sopenharmony_ci/// 1184e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider. 1185e01aa904Sopenharmony_ci/// 1186e01aa904Sopenharmony_ci/// @return true iff the binary denoted by @p elf_handle is a Linux 1187e01aa904Sopenharmony_ci/// kernel module. 1188e01aa904Sopenharmony_cibool 1189e01aa904Sopenharmony_ciis_linux_kernel_module(Elf *elf_handle) 1190e01aa904Sopenharmony_ci{ 1191e01aa904Sopenharmony_ci return (find_section(elf_handle, ".modinfo", SHT_PROGBITS) 1192e01aa904Sopenharmony_ci && find_section(elf_handle, 1193e01aa904Sopenharmony_ci ".gnu.linkonce.this_module", 1194e01aa904Sopenharmony_ci SHT_PROGBITS)); 1195e01aa904Sopenharmony_ci} 1196e01aa904Sopenharmony_ci 1197e01aa904Sopenharmony_ci/// Test if the ELF binary denoted by a given ELF handle is a Linux 1198e01aa904Sopenharmony_ci/// Kernel binary (either vmlinux or a kernel module). 1199e01aa904Sopenharmony_ci/// 1200e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider. 1201e01aa904Sopenharmony_ci/// 1202e01aa904Sopenharmony_ci/// @return true iff the binary denoted by @p elf_handle is a Linux 1203e01aa904Sopenharmony_ci/// kernel binary 1204e01aa904Sopenharmony_cibool 1205e01aa904Sopenharmony_ciis_linux_kernel(Elf *elf_handle) 1206e01aa904Sopenharmony_ci{ 1207e01aa904Sopenharmony_ci return (find_section(elf_handle, 1208e01aa904Sopenharmony_ci "__ksymtab_strings", 1209e01aa904Sopenharmony_ci SHT_PROGBITS) 1210e01aa904Sopenharmony_ci || is_linux_kernel_module(elf_handle)); 1211e01aa904Sopenharmony_ci} 1212e01aa904Sopenharmony_ci 1213e01aa904Sopenharmony_ci/// Get the address at which a given binary is loaded in memory. 1214e01aa904Sopenharmony_ci/// 1215e01aa904Sopenharmony_ci/// @param elf_handle the elf handle for the binary to consider. 1216e01aa904Sopenharmony_ci/// 1217e01aa904Sopenharmony_ci/// @param load_address the address where the binary is loaded. This 1218e01aa904Sopenharmony_ci/// is set by the function iff it returns true. 1219e01aa904Sopenharmony_ci/// 1220e01aa904Sopenharmony_ci/// @return true if the function could get the binary load address 1221e01aa904Sopenharmony_ci/// and assign @p load_address to it. 1222e01aa904Sopenharmony_cibool 1223e01aa904Sopenharmony_ciget_binary_load_address(Elf* elf_handle, GElf_Addr& load_address) 1224e01aa904Sopenharmony_ci{ 1225e01aa904Sopenharmony_ci GElf_Ehdr elf_header; 1226e01aa904Sopenharmony_ci gelf_getehdr(elf_handle, &elf_header); 1227e01aa904Sopenharmony_ci size_t num_segments = elf_header.e_phnum; 1228e01aa904Sopenharmony_ci GElf_Phdr *program_header = NULL; 1229e01aa904Sopenharmony_ci GElf_Addr result; 1230e01aa904Sopenharmony_ci bool found_loaded_segment = false; 1231e01aa904Sopenharmony_ci GElf_Phdr ph_mem; 1232e01aa904Sopenharmony_ci 1233e01aa904Sopenharmony_ci for (unsigned i = 0; i < num_segments; ++i) 1234e01aa904Sopenharmony_ci { 1235e01aa904Sopenharmony_ci program_header = gelf_getphdr(elf_handle, i, &ph_mem); 1236e01aa904Sopenharmony_ci if (program_header && program_header->p_type == PT_LOAD) 1237e01aa904Sopenharmony_ci { 1238e01aa904Sopenharmony_ci if (!found_loaded_segment) 1239e01aa904Sopenharmony_ci { 1240e01aa904Sopenharmony_ci result = program_header->p_vaddr; 1241e01aa904Sopenharmony_ci found_loaded_segment = true; 1242e01aa904Sopenharmony_ci } 1243e01aa904Sopenharmony_ci 1244e01aa904Sopenharmony_ci if (program_header->p_vaddr < result) 1245e01aa904Sopenharmony_ci // The resulting load address we want is the lowest 1246e01aa904Sopenharmony_ci // load address of all the loaded segments. 1247e01aa904Sopenharmony_ci result = program_header->p_vaddr; 1248e01aa904Sopenharmony_ci } 1249e01aa904Sopenharmony_ci } 1250e01aa904Sopenharmony_ci 1251e01aa904Sopenharmony_ci if (found_loaded_segment) 1252e01aa904Sopenharmony_ci { 1253e01aa904Sopenharmony_ci load_address = result; 1254e01aa904Sopenharmony_ci return true; 1255e01aa904Sopenharmony_ci } 1256e01aa904Sopenharmony_ci return false; 1257e01aa904Sopenharmony_ci} 1258e01aa904Sopenharmony_ci 1259e01aa904Sopenharmony_ci/// Return the size of a word for the current architecture. 1260e01aa904Sopenharmony_ci/// 1261e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider. 1262e01aa904Sopenharmony_ci/// 1263e01aa904Sopenharmony_ci/// @return the size of a word. 1264e01aa904Sopenharmony_ciunsigned char 1265e01aa904Sopenharmony_ciget_architecture_word_size(Elf* elf_handle) 1266e01aa904Sopenharmony_ci{ 1267e01aa904Sopenharmony_ci unsigned char word_size = 0; 1268e01aa904Sopenharmony_ci GElf_Ehdr elf_header; 1269e01aa904Sopenharmony_ci gelf_getehdr(elf_handle, &elf_header); 1270e01aa904Sopenharmony_ci if (elf_header.e_ident[EI_CLASS] == ELFCLASS32) 1271e01aa904Sopenharmony_ci word_size = 4; 1272e01aa904Sopenharmony_ci else if (elf_header.e_ident[EI_CLASS] == ELFCLASS64) 1273e01aa904Sopenharmony_ci word_size = 8; 1274e01aa904Sopenharmony_ci else 1275e01aa904Sopenharmony_ci ABG_ASSERT_NOT_REACHED; 1276e01aa904Sopenharmony_ci return word_size; 1277e01aa904Sopenharmony_ci} 1278e01aa904Sopenharmony_ci 1279e01aa904Sopenharmony_ci/// Test if the elf file being read is an executable. 1280e01aa904Sopenharmony_ci/// 1281e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider. 1282e01aa904Sopenharmony_ci/// 1283e01aa904Sopenharmony_ci/// @return true iff the elf file being read is an / executable. 1284e01aa904Sopenharmony_cibool 1285e01aa904Sopenharmony_ciis_executable(Elf* elf_handle) 1286e01aa904Sopenharmony_ci{ 1287e01aa904Sopenharmony_ci GElf_Ehdr elf_header; 1288e01aa904Sopenharmony_ci gelf_getehdr(elf_handle, &elf_header); 1289e01aa904Sopenharmony_ci return elf_header.e_type == ET_EXEC; 1290e01aa904Sopenharmony_ci} 1291e01aa904Sopenharmony_ci 1292e01aa904Sopenharmony_ci/// Test if the elf file being read is a dynamic shared / object. 1293e01aa904Sopenharmony_ci/// 1294e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider. 1295e01aa904Sopenharmony_ci/// 1296e01aa904Sopenharmony_ci/// @return true iff the elf file being read is a / dynamic shared object. 1297e01aa904Sopenharmony_cibool 1298e01aa904Sopenharmony_ciis_dso(Elf* elf_handle) 1299e01aa904Sopenharmony_ci{ 1300e01aa904Sopenharmony_ci GElf_Ehdr elf_header; 1301e01aa904Sopenharmony_ci gelf_getehdr(elf_handle, &elf_header); 1302e01aa904Sopenharmony_ci return elf_header.e_type == ET_DYN; 1303e01aa904Sopenharmony_ci} 1304e01aa904Sopenharmony_ci 1305e01aa904Sopenharmony_ci/// Translate a section-relative symbol address (i.e, symbol value) 1306e01aa904Sopenharmony_ci/// into an absolute symbol address by adding the address of the 1307e01aa904Sopenharmony_ci/// section the symbol belongs to, to the address value. 1308e01aa904Sopenharmony_ci/// 1309e01aa904Sopenharmony_ci/// This is useful when looking at symbol values coming from 1310e01aa904Sopenharmony_ci/// relocatable files (of ET_REL kind). If the binary is not 1311e01aa904Sopenharmony_ci/// ET_REL, then the function does nothing and returns the input 1312e01aa904Sopenharmony_ci/// address unchanged. 1313e01aa904Sopenharmony_ci/// 1314e01aa904Sopenharmony_ci/// @param elf_handle the elf handle for the binary to consider. 1315e01aa904Sopenharmony_ci/// 1316e01aa904Sopenharmony_ci/// @param sym the symbol whose address to possibly needs to be 1317e01aa904Sopenharmony_ci/// translated. 1318e01aa904Sopenharmony_ci/// 1319e01aa904Sopenharmony_ci/// @return the section-relative address, translated into an 1320e01aa904Sopenharmony_ci/// absolute address, if @p sym is from an ET_REL binary. 1321e01aa904Sopenharmony_ci/// Otherwise, return the address of @p sym, unchanged. 1322e01aa904Sopenharmony_ciGElf_Addr 1323e01aa904Sopenharmony_cimaybe_adjust_et_rel_sym_addr_to_abs_addr(Elf* elf_handle, GElf_Sym* sym) 1324e01aa904Sopenharmony_ci{ 1325e01aa904Sopenharmony_ci Elf_Scn* symbol_section = elf_getscn(elf_handle, sym->st_shndx); 1326e01aa904Sopenharmony_ci GElf_Addr addr = sym->st_value; 1327e01aa904Sopenharmony_ci 1328e01aa904Sopenharmony_ci if (!symbol_section) 1329e01aa904Sopenharmony_ci return addr; 1330e01aa904Sopenharmony_ci 1331e01aa904Sopenharmony_ci GElf_Ehdr elf_header; 1332e01aa904Sopenharmony_ci if (!gelf_getehdr(elf_handle, &elf_header)) 1333e01aa904Sopenharmony_ci return addr; 1334e01aa904Sopenharmony_ci 1335e01aa904Sopenharmony_ci if (elf_header.e_type != ET_REL) 1336e01aa904Sopenharmony_ci return addr; 1337e01aa904Sopenharmony_ci 1338e01aa904Sopenharmony_ci GElf_Shdr section_header; 1339e01aa904Sopenharmony_ci if (!gelf_getshdr(symbol_section, §ion_header)) 1340e01aa904Sopenharmony_ci return addr; 1341e01aa904Sopenharmony_ci 1342e01aa904Sopenharmony_ci return addr + section_header.sh_addr; 1343e01aa904Sopenharmony_ci} 1344e01aa904Sopenharmony_ci 1345e01aa904Sopenharmony_ci/// Test if a given address is in a given section. 1346e01aa904Sopenharmony_ci/// 1347e01aa904Sopenharmony_ci/// @param addr the address to consider. 1348e01aa904Sopenharmony_ci/// 1349e01aa904Sopenharmony_ci/// @param section the section to consider. 1350e01aa904Sopenharmony_ci/// 1351e01aa904Sopenharmony_ci/// @return true iff @p addr is in section @p section. 1352e01aa904Sopenharmony_cibool 1353e01aa904Sopenharmony_ciaddress_is_in_section(Dwarf_Addr addr, Elf_Scn* section) 1354e01aa904Sopenharmony_ci{ 1355e01aa904Sopenharmony_ci if (!section) 1356e01aa904Sopenharmony_ci return false; 1357e01aa904Sopenharmony_ci 1358e01aa904Sopenharmony_ci GElf_Shdr sheader_mem; 1359e01aa904Sopenharmony_ci GElf_Shdr* sheader = gelf_getshdr(section, &sheader_mem); 1360e01aa904Sopenharmony_ci 1361e01aa904Sopenharmony_ci if (sheader->sh_addr <= addr && addr <= sheader->sh_addr + sheader->sh_size) 1362e01aa904Sopenharmony_ci return true; 1363e01aa904Sopenharmony_ci 1364e01aa904Sopenharmony_ci return false; 1365e01aa904Sopenharmony_ci} 1366e01aa904Sopenharmony_ci 1367e01aa904Sopenharmony_ci/// Return true if an address is in the ".opd" section that is 1368e01aa904Sopenharmony_ci/// present on the ppc64 platform. 1369e01aa904Sopenharmony_ci/// 1370e01aa904Sopenharmony_ci/// @param addr the address to consider. 1371e01aa904Sopenharmony_ci/// 1372e01aa904Sopenharmony_ci/// @return true iff @p addr designates a word that is in the ".opd" 1373e01aa904Sopenharmony_ci/// section. 1374e01aa904Sopenharmony_cibool 1375e01aa904Sopenharmony_ciaddress_is_in_opd_section(Elf* elf_handle, Dwarf_Addr addr) 1376e01aa904Sopenharmony_ci{ 1377e01aa904Sopenharmony_ci Elf_Scn * opd_section = find_opd_section(elf_handle); 1378e01aa904Sopenharmony_ci if (!opd_section) 1379e01aa904Sopenharmony_ci return false; 1380e01aa904Sopenharmony_ci if (address_is_in_section(addr, opd_section)) 1381e01aa904Sopenharmony_ci return true; 1382e01aa904Sopenharmony_ci return false; 1383e01aa904Sopenharmony_ci} 1384e01aa904Sopenharmony_ci 1385e01aa904Sopenharmony_ci/// Get data tag information of an ELF file by looking up into its 1386e01aa904Sopenharmony_ci/// dynamic segment 1387e01aa904Sopenharmony_ci/// 1388e01aa904Sopenharmony_ci/// @param elf the elf handle to use for the query. 1389e01aa904Sopenharmony_ci/// 1390e01aa904Sopenharmony_ci/// @param dt_tag data tag to look for in dynamic segment 1391e01aa904Sopenharmony_ci/// @param dt_tag_data vector of found information for a given @p data_tag 1392e01aa904Sopenharmony_ci/// 1393e01aa904Sopenharmony_ci/// @return true iff data tag @p data_tag was found 1394e01aa904Sopenharmony_cibool 1395e01aa904Sopenharmony_cilookup_data_tag_from_dynamic_segment(Elf* elf, 1396e01aa904Sopenharmony_ci Elf64_Sxword data_tag, 1397e01aa904Sopenharmony_ci vector<string>& dt_tag_data) 1398e01aa904Sopenharmony_ci{ 1399e01aa904Sopenharmony_ci size_t num_prog_headers = 0; 1400e01aa904Sopenharmony_ci bool found = false; 1401e01aa904Sopenharmony_ci if (elf_getphdrnum(elf, &num_prog_headers) < 0) 1402e01aa904Sopenharmony_ci return found; 1403e01aa904Sopenharmony_ci 1404e01aa904Sopenharmony_ci // Cycle through each program header. 1405e01aa904Sopenharmony_ci for (size_t i = 0; i < num_prog_headers; ++i) 1406e01aa904Sopenharmony_ci { 1407e01aa904Sopenharmony_ci GElf_Phdr phdr_mem; 1408e01aa904Sopenharmony_ci GElf_Phdr *phdr = gelf_getphdr(elf, i, &phdr_mem); 1409e01aa904Sopenharmony_ci if (phdr == NULL || phdr->p_type != PT_DYNAMIC) 1410e01aa904Sopenharmony_ci continue; 1411e01aa904Sopenharmony_ci 1412e01aa904Sopenharmony_ci // Poke at the dynamic segment like a section, so that we can 1413e01aa904Sopenharmony_ci // get its section header information; also we'd like to read 1414e01aa904Sopenharmony_ci // the data of the segment by using elf_getdata() but that 1415e01aa904Sopenharmony_ci // function needs a Elf_Scn data structure to act on. 1416e01aa904Sopenharmony_ci // Elfutils doesn't really have any particular function to 1417e01aa904Sopenharmony_ci // access segment data, other than the functions used to 1418e01aa904Sopenharmony_ci // access section data. 1419e01aa904Sopenharmony_ci Elf_Scn *dynamic_section = gelf_offscn(elf, phdr->p_offset); 1420e01aa904Sopenharmony_ci GElf_Shdr shdr_mem; 1421e01aa904Sopenharmony_ci GElf_Shdr *dynamic_section_header = gelf_getshdr(dynamic_section, 1422e01aa904Sopenharmony_ci &shdr_mem); 1423e01aa904Sopenharmony_ci if (dynamic_section_header == NULL 1424e01aa904Sopenharmony_ci || dynamic_section_header->sh_type != SHT_DYNAMIC) 1425e01aa904Sopenharmony_ci continue; 1426e01aa904Sopenharmony_ci 1427e01aa904Sopenharmony_ci // Get data of the dynamic segment (seen as a section). 1428e01aa904Sopenharmony_ci Elf_Data *data = elf_getdata(dynamic_section, NULL); 1429e01aa904Sopenharmony_ci if (data == NULL) 1430e01aa904Sopenharmony_ci continue; 1431e01aa904Sopenharmony_ci 1432e01aa904Sopenharmony_ci // Get the index of the section headers string table. 1433e01aa904Sopenharmony_ci size_t string_table_index = 0; 1434e01aa904Sopenharmony_ci ABG_ASSERT (elf_getshdrstrndx(elf, &string_table_index) >= 0); 1435e01aa904Sopenharmony_ci 1436e01aa904Sopenharmony_ci size_t dynamic_section_header_entry_size = gelf_fsize(elf, 1437e01aa904Sopenharmony_ci ELF_T_DYN, 1, 1438e01aa904Sopenharmony_ci EV_CURRENT); 1439e01aa904Sopenharmony_ci 1440e01aa904Sopenharmony_ci GElf_Shdr link_mem; 1441e01aa904Sopenharmony_ci GElf_Shdr *link = 1442e01aa904Sopenharmony_ci gelf_getshdr(elf_getscn(elf, 1443e01aa904Sopenharmony_ci dynamic_section_header->sh_link), 1444e01aa904Sopenharmony_ci &link_mem); 1445e01aa904Sopenharmony_ci ABG_ASSERT(link != NULL); 1446e01aa904Sopenharmony_ci 1447e01aa904Sopenharmony_ci size_t num_dynamic_section_entries = 1448e01aa904Sopenharmony_ci dynamic_section_header->sh_size / dynamic_section_header_entry_size; 1449e01aa904Sopenharmony_ci 1450e01aa904Sopenharmony_ci // Now walk through all the DT_* data tags that are in the 1451e01aa904Sopenharmony_ci // segment/section 1452e01aa904Sopenharmony_ci for (size_t j = 0; j < num_dynamic_section_entries; ++j) 1453e01aa904Sopenharmony_ci { 1454e01aa904Sopenharmony_ci GElf_Dyn dynamic_section_mem; 1455e01aa904Sopenharmony_ci GElf_Dyn *dynamic_section = gelf_getdyn(data, 1456e01aa904Sopenharmony_ci j, 1457e01aa904Sopenharmony_ci &dynamic_section_mem); 1458e01aa904Sopenharmony_ci if (dynamic_section->d_tag == data_tag) 1459e01aa904Sopenharmony_ci { 1460e01aa904Sopenharmony_ci dt_tag_data.push_back(elf_strptr(elf, 1461e01aa904Sopenharmony_ci dynamic_section_header->sh_link, 1462e01aa904Sopenharmony_ci dynamic_section->d_un.d_val)); 1463e01aa904Sopenharmony_ci found = true; 1464e01aa904Sopenharmony_ci } 1465e01aa904Sopenharmony_ci } 1466e01aa904Sopenharmony_ci } 1467e01aa904Sopenharmony_ci return found; 1468e01aa904Sopenharmony_ci} 1469e01aa904Sopenharmony_ci 1470e01aa904Sopenharmony_ciconst Dwfl_Callbacks& 1471e01aa904Sopenharmony_ciinitialize_dwfl_callbacks(Dwfl_Callbacks& cb, 1472e01aa904Sopenharmony_ci char** debug_info_root_path) 1473e01aa904Sopenharmony_ci{ 1474e01aa904Sopenharmony_ci cb.find_debuginfo = dwfl_standard_find_debuginfo; 1475e01aa904Sopenharmony_ci cb.section_address = dwfl_offline_section_address; 1476e01aa904Sopenharmony_ci cb.debuginfo_path = debug_info_root_path; 1477e01aa904Sopenharmony_ci return cb; 1478e01aa904Sopenharmony_ci} 1479e01aa904Sopenharmony_ci 1480e01aa904Sopenharmony_cidwfl_sptr 1481e01aa904Sopenharmony_cicreate_new_dwfl_handle(Dwfl_Callbacks& cb) 1482e01aa904Sopenharmony_ci{ 1483e01aa904Sopenharmony_ci dwfl_sptr handle(dwfl_begin(&cb), dwfl_deleter()); 1484e01aa904Sopenharmony_ci return handle; 1485e01aa904Sopenharmony_ci} 1486e01aa904Sopenharmony_ci 1487e01aa904Sopenharmony_ci/// Fetch the SONAME ELF property from an ELF binary file. 1488e01aa904Sopenharmony_ci/// 1489e01aa904Sopenharmony_ci/// @param path The path to the elf file to consider. 1490e01aa904Sopenharmony_ci/// 1491e01aa904Sopenharmony_ci/// @param soname out parameter. Set to the SONAME property of the 1492e01aa904Sopenharmony_ci/// binary file, if it present in the ELF file. 1493e01aa904Sopenharmony_ci/// 1494e01aa904Sopenharmony_ci/// return false if an error occured while looking for the SONAME 1495e01aa904Sopenharmony_ci/// property in the binary, true otherwise. 1496e01aa904Sopenharmony_cibool 1497e01aa904Sopenharmony_ciget_soname_of_elf_file(const string& path, string &soname) 1498e01aa904Sopenharmony_ci{ 1499e01aa904Sopenharmony_ci 1500e01aa904Sopenharmony_ci int fd = open(path.c_str(), O_RDONLY); 1501e01aa904Sopenharmony_ci if (fd == -1) 1502e01aa904Sopenharmony_ci return false; 1503e01aa904Sopenharmony_ci 1504e01aa904Sopenharmony_ci elf_version (EV_CURRENT); 1505e01aa904Sopenharmony_ci Elf* elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); 1506e01aa904Sopenharmony_ci 1507e01aa904Sopenharmony_ci GElf_Ehdr ehdr_mem; 1508e01aa904Sopenharmony_ci GElf_Ehdr* ehdr = gelf_getehdr (elf, &ehdr_mem); 1509e01aa904Sopenharmony_ci if (ehdr == NULL) 1510e01aa904Sopenharmony_ci return false; 1511e01aa904Sopenharmony_ci 1512e01aa904Sopenharmony_ci for (int i = 0; i < ehdr->e_phnum; ++i) 1513e01aa904Sopenharmony_ci { 1514e01aa904Sopenharmony_ci GElf_Phdr phdr_mem; 1515e01aa904Sopenharmony_ci GElf_Phdr* phdr = gelf_getphdr (elf, i, &phdr_mem); 1516e01aa904Sopenharmony_ci 1517e01aa904Sopenharmony_ci if (phdr != NULL && phdr->p_type == PT_DYNAMIC) 1518e01aa904Sopenharmony_ci { 1519e01aa904Sopenharmony_ci Elf_Scn* scn = gelf_offscn (elf, phdr->p_offset); 1520e01aa904Sopenharmony_ci GElf_Shdr shdr_mem; 1521e01aa904Sopenharmony_ci GElf_Shdr* shdr = gelf_getshdr (scn, &shdr_mem); 1522e01aa904Sopenharmony_ci size_t entsize = (shdr != NULL && shdr->sh_entsize != 0 1523e01aa904Sopenharmony_ci ? shdr->sh_entsize 1524e01aa904Sopenharmony_ci : gelf_fsize (elf, ELF_T_DYN, 1, EV_CURRENT)); 1525e01aa904Sopenharmony_ci int maxcnt = (shdr != NULL 1526e01aa904Sopenharmony_ci ? shdr->sh_size / entsize : INT_MAX); 1527e01aa904Sopenharmony_ci ABG_ASSERT (shdr == NULL || (shdr->sh_type == SHT_DYNAMIC 1528e01aa904Sopenharmony_ci || shdr->sh_type == SHT_PROGBITS)); 1529e01aa904Sopenharmony_ci Elf_Data* data = elf_getdata (scn, NULL); 1530e01aa904Sopenharmony_ci if (data == NULL) 1531e01aa904Sopenharmony_ci break; 1532e01aa904Sopenharmony_ci 1533e01aa904Sopenharmony_ci for (int cnt = 0; cnt < maxcnt; ++cnt) 1534e01aa904Sopenharmony_ci { 1535e01aa904Sopenharmony_ci GElf_Dyn dynmem; 1536e01aa904Sopenharmony_ci GElf_Dyn* dyn = gelf_getdyn (data, cnt, &dynmem); 1537e01aa904Sopenharmony_ci if (dyn == NULL) 1538e01aa904Sopenharmony_ci continue; 1539e01aa904Sopenharmony_ci 1540e01aa904Sopenharmony_ci if (dyn->d_tag == DT_NULL) 1541e01aa904Sopenharmony_ci break; 1542e01aa904Sopenharmony_ci 1543e01aa904Sopenharmony_ci if (dyn->d_tag != DT_SONAME) 1544e01aa904Sopenharmony_ci continue; 1545e01aa904Sopenharmony_ci 1546e01aa904Sopenharmony_ci soname = elf_strptr (elf, shdr->sh_link, dyn->d_un.d_val); 1547e01aa904Sopenharmony_ci break; 1548e01aa904Sopenharmony_ci } 1549e01aa904Sopenharmony_ci break; 1550e01aa904Sopenharmony_ci } 1551e01aa904Sopenharmony_ci } 1552e01aa904Sopenharmony_ci 1553e01aa904Sopenharmony_ci elf_end(elf); 1554e01aa904Sopenharmony_ci close(fd); 1555e01aa904Sopenharmony_ci 1556e01aa904Sopenharmony_ci return true; 1557e01aa904Sopenharmony_ci} 1558e01aa904Sopenharmony_ci 1559e01aa904Sopenharmony_ci} // end namespace elf_helpers 1560e01aa904Sopenharmony_ci} // end namespace abigail 1561