From patchwork Tue Apr 21 06:35:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Matthias_M=C3=A4nnich?= X-Patchwork-Id: 39109 From: maennich@google.com (Matthias Maennich) Date: Tue, 21 Apr 2020 08:35:45 +0200 Subject: [PATCH v2 2/8] abg-elf-helpers: move some elf helpers from abg-dwarf-reader In-Reply-To: <20200421063551.222511-1-maennich@google.com> References: <20200420110846.218792-1-maennich@google.com> <20200421063551.222511-1-maennich@google.com> Message-ID: <20200421063551.222511-3-maennich@google.com> Move some definitions from abg-dwarf-reader to abg-elf-helpers that are strictly only related to ELF. * abg-dwarf-reader.cc(stt_to_elf_symbol_type): Move function out. (stb_to_elf_symbol_binding): Likewise. (stv_to_elf_symbol_visibility): Likewise. (e_machine_to_string): Likewise. (find_section): Likewise. (find_symbol_table_section): Likewise. (find_symbol_table_section_index): Likewise. (enum hash_table_kind): Likewise. (find_hash_table_section_index): Likewise. (get_symbol_versionning_sections): Likewise. (find_text_section): Likewise. (find_bss_section): Likewise. (find_rodata_section): Likewise. (find_data_section): Likewise. (find_data1_section): Likewise. * abg-elf-helpers.cc(stt_to_elf_symbol_type): Move function in. (stb_to_elf_symbol_binding): Likewise. (stv_to_elf_symbol_visibility): Likewise. (e_machine_to_string): Likewise. (find_section): Likewise. (find_symbol_table_section): Likewise. (find_symbol_table_section_index): Likewise. (enum hash_table_kind): Likewise. (find_hash_table_section_index): Likewise. (get_symbol_versionning_sections): Likewise. (find_text_section): Likewise. (find_bss_section): Likewise. (find_rodata_section): Likewise. (find_data_section): Likewise. (find_data1_section): Likewise. * abg-elf-helpers.h(stt_to_elf_symbol_type): Add declaration. (stb_to_elf_symbol_binding): Likewise. (stv_to_elf_symbol_visibility): Likewise. (e_machine_to_string): Likewise. (find_section): Likewise. (find_symbol_table_section): Likewise. (find_symbol_table_section_index): Likewise. (enum hash_table_kind): Likewise. (find_hash_table_section_index): Likewise. (get_symbol_versionning_sections): Likewise. (find_text_section): Likewise. (find_bss_section): Likewise. (find_rodata_section): Likewise. (find_data_section): Likewise. (find_data1_section): Likewise. Reviewed-by: Giuliano Procida Signed-off-by: Matthias Maennich --- src/abg-dwarf-reader.cc | 594 +--------------------------------------- src/abg-elf-helpers.cc | 471 +++++++++++++++++++++++++++++++ src/abg-elf-helpers.h | 65 +++++ 3 files changed, 540 insertions(+), 590 deletions(-) diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc index 1c0d6ea0353f..6ec7e4b6e968 100644 --- a/src/abg-dwarf-reader.cc +++ b/src/abg-dwarf-reader.cc @@ -50,6 +50,8 @@ #include "abg-suppression-priv.h" #include "abg-corpus-priv.h" +#include "abg-elf-helpers.h" + #include "abg-internal.h" // ABG_BEGIN_EXPORT_DECLARATIONS @@ -84,6 +86,8 @@ using std::stack; using std::deque; using std::list; +using namespace elf_helpers; // TODO: avoid using namespace + /// Where a DIE comes from. For instance, a DIE can come from the main /// debug info section, the alternate debug info section or from the /// type unit section. @@ -290,9 +294,6 @@ static void add_symbol_to_map(const elf_symbol_sptr& sym, string_elf_symbols_map_type& map); -static bool -find_symbol_table_section(Elf* elf_handle, Elf_Scn*& section); - static bool get_symbol_versionning_sections(Elf* elf_handle, Elf_Scn*& versym_section, @@ -546,548 +547,6 @@ compare_dies(const read_context& ctxt, const Dwarf_Die *l, const Dwarf_Die *r, bool update_canonical_dies_on_the_fly); -/// Convert an elf symbol type (given by the ELF{32,64}_ST_TYPE -/// macros) into an elf_symbol::type value. -/// -/// Note that this function aborts when given an unexpected value. -/// -/// @param the symbol type value to convert. -/// -/// @return the converted value. -static elf_symbol::type -stt_to_elf_symbol_type(unsigned char stt) -{ - elf_symbol::type t = elf_symbol::NOTYPE_TYPE; - - switch (stt) - { - case STT_NOTYPE: - t = elf_symbol::NOTYPE_TYPE; - break; - case STT_OBJECT: - t = elf_symbol::OBJECT_TYPE; - break; - case STT_FUNC: - t = elf_symbol::FUNC_TYPE; - break; - case STT_SECTION: - t = elf_symbol::SECTION_TYPE; - break; - case STT_FILE: - t = elf_symbol::FILE_TYPE; - break; - case STT_COMMON: - t = elf_symbol::COMMON_TYPE; - break; - case STT_TLS: - t = elf_symbol::TLS_TYPE; - break; - case STT_GNU_IFUNC: - t = elf_symbol::GNU_IFUNC_TYPE; - break; - default: - // An unknown value that probably ought to be supported? Let's - // abort right here rather than yielding garbage. - ABG_ASSERT_NOT_REACHED; - } - - return t; -} - -/// Convert an elf symbol binding (given by the ELF{32,64}_ST_BIND -/// macros) into an elf_symbol::binding value. -/// -/// Note that this function aborts when given an unexpected value. -/// -/// @param the symbol binding value to convert. -/// -/// @return the converted value. -static elf_symbol::binding -stb_to_elf_symbol_binding(unsigned char stb) -{ - elf_symbol::binding b = elf_symbol::GLOBAL_BINDING; - - switch (stb) - { - case STB_LOCAL: - b = elf_symbol::LOCAL_BINDING; - break; - case STB_GLOBAL: - b = elf_symbol::GLOBAL_BINDING; - break; - case STB_WEAK: - b = elf_symbol::WEAK_BINDING; - break; - case STB_GNU_UNIQUE: - b = elf_symbol::GNU_UNIQUE_BINDING; - break; - default: - ABG_ASSERT_NOT_REACHED; - } - - return b; - -} - -/// Convert an ELF symbol visiblity given by the symbols ->st_other -/// data member as returned by the GELF_ST_VISIBILITY macro into a -/// elf_symbol::visiblity value. -/// -/// @param stv the value of the ->st_other data member of the ELF -/// symbol. -/// -/// @return the converted elf_symbol::visiblity value. -static elf_symbol::visibility -stv_to_elf_symbol_visibility(unsigned char stv) -{ - - elf_symbol::visibility v = elf_symbol::DEFAULT_VISIBILITY; - - switch (stv) - { - case STV_DEFAULT: - v = elf_symbol::DEFAULT_VISIBILITY; - break; - case STV_INTERNAL: - v = elf_symbol::INTERNAL_VISIBILITY; - break; - case STV_HIDDEN: - v = elf_symbol::HIDDEN_VISIBILITY; - break; - case STV_PROTECTED: - v = elf_symbol::PROTECTED_VISIBILITY; - break; - default: - ABG_ASSERT_NOT_REACHED; - } - - return v; -} - -/// Convert the value of the e_machine field of GElf_Ehdr into a -/// string. This is to get a string representing the architecture of -/// the elf file at hand. -/// -/// @param e_machine the value of GElf_Ehdr::e_machine. -/// -/// @return the string representation of GElf_Ehdr::e_machine. -static string -e_machine_to_string(GElf_Half e_machine) -{ - string result; - switch (e_machine) - { - case EM_NONE: - result = "elf-no-arch"; - break; - case EM_M32: - result = "elf-att-we-32100"; - break; - case EM_SPARC: - result = "elf-sun-sparc"; - break; - case EM_386: - result = "elf-intel-80386"; - break; - case EM_68K: - result = "elf-motorola-68k"; - break; - case EM_88K: - result = "elf-motorola-88k"; - break; - case EM_860: - result = "elf-intel-80860"; - break; - case EM_MIPS: - result = "elf-mips-r3000-be"; - break; - case EM_S370: - result = "elf-ibm-s370"; - break; - case EM_MIPS_RS3_LE: - result = "elf-mips-r3000-le"; - break; - case EM_PARISC: - result = "elf-hp-parisc"; - break; - case EM_VPP500: - result = "elf-fujitsu-vpp500"; - break; - case EM_SPARC32PLUS: - result = "elf-sun-sparc-v8plus"; - break; - case EM_960: - result = "elf-intel-80960"; - break; - case EM_PPC: - result = "elf-powerpc"; - break; - case EM_PPC64: - result = "elf-powerpc-64"; - break; - case EM_S390: - result = "elf-ibm-s390"; - break; - case EM_V800: - result = "elf-nec-v800"; - break; - case EM_FR20: - result = "elf-fujitsu-fr20"; - break; - case EM_RH32: - result = "elf-trw-rh32"; - break; - case EM_RCE: - result = "elf-motorola-rce"; - break; - case EM_ARM: - result = "elf-arm"; - break; - case EM_FAKE_ALPHA: - result = "elf-digital-alpha"; - break; - case EM_SH: - result = "elf-hitachi-sh"; - break; - case EM_SPARCV9: - result = "elf-sun-sparc-v9-64"; - break; - case EM_TRICORE: - result = "elf-siemens-tricore"; - break; - case EM_ARC: - result = "elf-argonaut-risc-core"; - break; - case EM_H8_300: - result = "elf-hitachi-h8-300"; - break; - case EM_H8_300H: - result = "elf-hitachi-h8-300h"; - break; - case EM_H8S: - result = "elf-hitachi-h8s"; - break; - case EM_H8_500: - result = "elf-hitachi-h8-500"; - break; - case EM_IA_64: - result = "elf-intel-ia-64"; - break; - case EM_MIPS_X: - result = "elf-stanford-mips-x"; - break; - case EM_COLDFIRE: - result = "elf-motorola-coldfire"; - break; - case EM_68HC12: - result = "elf-motorola-68hc12"; - break; - case EM_MMA: - result = "elf-fujitsu-mma"; - break; - case EM_PCP: - result = "elf-siemens-pcp"; - break; - case EM_NCPU: - result = "elf-sony-ncpu"; - break; - case EM_NDR1: - result = "elf-denso-ndr1"; - break; - case EM_STARCORE: - result = "elf-motorola-starcore"; - break; - case EM_ME16: - result = "elf-toyota-me16"; - break; - case EM_ST100: - result = "elf-stm-st100"; - break; - case EM_TINYJ: - result = "elf-alc-tinyj"; - break; - case EM_X86_64: - result = "elf-amd-x86_64"; - break; - case EM_PDSP: - result = "elf-sony-pdsp"; - break; - case EM_FX66: - result = "elf-siemens-fx66"; - break; - case EM_ST9PLUS: - result = "elf-stm-st9+"; - break; - case EM_ST7: - result = "elf-stm-st7"; - break; - case EM_68HC16: - result = "elf-motorola-68hc16"; - break; - case EM_68HC11: - result = "elf-motorola-68hc11"; - break; - case EM_68HC08: - result = "elf-motorola-68hc08"; - break; - case EM_68HC05: - result = "elf-motorola-68hc05"; - break; - case EM_SVX: - result = "elf-sg-svx"; - break; - case EM_ST19: - result = "elf-stm-st19"; - break; - case EM_VAX: - result = "elf-digital-vax"; - break; - case EM_CRIS: - result = "elf-axis-cris"; - break; - case EM_JAVELIN: - result = "elf-infineon-javelin"; - break; - case EM_FIREPATH: - result = "elf-firepath"; - break; - case EM_ZSP: - result = "elf-lsi-zsp"; - break; - case EM_MMIX: - result = "elf-don-knuth-mmix"; - break; - case EM_HUANY: - result = "elf-harvard-huany"; - break; - case EM_PRISM: - result = "elf-sitera-prism"; - break; - case EM_AVR: - result = "elf-atmel-avr"; - break; - case EM_FR30: - result = "elf-fujistu-fr30"; - break; - case EM_D10V: - result = "elf-mitsubishi-d10v"; - break; - case EM_D30V: - result = "elf-mitsubishi-d30v"; - break; - case EM_V850: - result = "elf-nec-v850"; - break; - case EM_M32R: - result = "elf-mitsubishi-m32r"; - break; - case EM_MN10300: - result = "elf-matsushita-mn10300"; - break; - case EM_MN10200: - result = "elf-matsushita-mn10200"; - break; - case EM_PJ: - result = "elf-picojava"; - break; - case EM_OPENRISC: - result = "elf-openrisc-32"; - break; - case EM_ARC_A5: - result = "elf-arc-a5"; - break; - case EM_XTENSA: - result = "elf-tensilica-xtensa"; - break; - -#ifdef HAVE_EM_AARCH64_MACRO - case EM_AARCH64: - result = "elf-arm-aarch64"; - break; -#endif - -#ifdef HAVE_EM_TILEPRO_MACRO - case EM_TILEPRO: - result = "elf-tilera-tilepro"; - break; -#endif - -#ifdef HAVE_EM_TILEGX_MACRO - case EM_TILEGX: - result = "elf-tilera-tilegx"; - break; -#endif - - case EM_NUM: - result = "elf-last-arch-number"; - break; - case EM_ALPHA: - result = "elf-non-official-alpha"; - break; - default: - { - std::ostringstream o; - o << "elf-unknown-arch-value-" << e_machine; - result = o.str(); - } - break; - } - return result; -} - -/// The kind of ELF hash table found by the function -/// find_hash_table_section_index. -enum hash_table_kind -{ - NO_HASH_TABLE_KIND = 0, - SYSV_HASH_TABLE_KIND, - GNU_HASH_TABLE_KIND -}; - -/// Get the offset offset of the hash table section. -/// -/// @param elf_handle the elf handle to use. -/// -/// @param ht_section_offset this is set to the resulting offset -/// of the hash table section. This is set iff the function returns true. -/// -/// @param symtab_section_offset the offset of the section of the -/// symbol table the hash table refers to. -static hash_table_kind -find_hash_table_section_index(Elf* elf_handle, - size_t& ht_section_index, - size_t& symtab_section_index) -{ - if (!elf_handle) - return NO_HASH_TABLE_KIND; - - GElf_Shdr header_mem, *section_header; - bool found_sysv_ht = false, found_gnu_ht = false; - for (Elf_Scn* section = elf_nextscn(elf_handle, 0); - section != 0; - section = elf_nextscn(elf_handle, section)) - { - section_header= gelf_getshdr(section, &header_mem); - if (section_header->sh_type != SHT_HASH - && section_header->sh_type != SHT_GNU_HASH) - continue; - - ht_section_index = elf_ndxscn(section); - symtab_section_index = section_header->sh_link; - - if (section_header->sh_type == SHT_HASH) - found_sysv_ht = true; - else if (section_header->sh_type == SHT_GNU_HASH) - found_gnu_ht = true; - } - - if (found_gnu_ht) - return GNU_HASH_TABLE_KIND; - else if (found_sysv_ht) - return SYSV_HASH_TABLE_KIND; - else - return NO_HASH_TABLE_KIND; -} - -/// Find the symbol table. -/// -/// If we are looking at a relocatable or executable file, this -/// function will return the .symtab symbol table (of type -/// SHT_SYMTAB). But if we are looking at a DSO it returns the -/// .dynsym symbol table (of type SHT_DYNSYM). -/// -/// @param elf_handle the elf handle to consider. -/// -/// @param symtab the symbol table found. -/// -/// @return true iff the symbol table is found. -static bool -find_symbol_table_section(Elf* elf_handle, Elf_Scn*& symtab) -{ - Elf_Scn* section = 0, *dynsym = 0, *sym_tab = 0; - while ((section = elf_nextscn(elf_handle, section)) != 0) - { - GElf_Shdr header_mem, *header; - header = gelf_getshdr(section, &header_mem); - if (header->sh_type == SHT_DYNSYM) - dynsym = section; - else if (header->sh_type == SHT_SYMTAB) - sym_tab = section; - } - - if (dynsym || sym_tab) - { - GElf_Ehdr eh_mem; - GElf_Ehdr* elf_header = gelf_getehdr(elf_handle, &eh_mem); - if (elf_header->e_type == ET_REL - || elf_header->e_type == ET_EXEC) - symtab = sym_tab ? sym_tab : dynsym; - else - symtab = dynsym ? dynsym : sym_tab; - return true; - } - return false; -} - -/// Find the index (in the section headers table) of the symbol table -/// section. -/// -/// If we are looking at a relocatable or executable file, this -/// function will return the index for the .symtab symbol table (of -/// type SHT_SYMTAB). But if we are looking at a DSO it returns the -/// index for the .dynsym symbol table (of type SHT_DYNSYM). -/// -/// @param elf_handle the elf handle to use. -/// -/// @param symtab_index the index of the symbol_table, that was found. -/// -/// @return true iff the symbol table section index was found. -static bool -find_symbol_table_section_index(Elf* elf_handle, - size_t& symtab_index) -{ - Elf_Scn* section = 0; - if (!find_symbol_table_section(elf_handle, section)) - return false; - - symtab_index = elf_ndxscn(section); - return true; -} - -/// Find and return a section by its name and its type. -/// -/// @param elf_handle the elf handle to use. -/// -/// @param name the name of the section. -/// -/// @param section_type the type of the section. This is the -/// Elf32_Shdr::sh_type (or Elf64_Shdr::sh_type) data member. -/// Examples of values of this parameter are SHT_PROGBITS or SHT_NOBITS. -/// -/// @return the section found, nor nil if none was found. -static Elf_Scn* -find_section(Elf* elf_handle, const string& name, Elf64_Word section_type) -{ - size_t section_header_string_index = 0; - if (elf_getshdrstrndx (elf_handle, §ion_header_string_index) < 0) - return 0; - - Elf_Scn* section = 0; - GElf_Shdr header_mem, *header; - while ((section = elf_nextscn(elf_handle, section)) != 0) - { - header = gelf_getshdr(section, &header_mem); - if (header == NULL || header->sh_type != section_type) - continue; - - const char* section_name = - elf_strptr(elf_handle, section_header_string_index, header->sh_name); - if (section_name && name == section_name) - return section; - } - - return 0; -} /// Test if the ELF binary denoted by a given ELF handle is a Linux /// Kernel Module. @@ -1121,51 +580,6 @@ binary_is_linux_kernel(Elf *elf_handle) || binary_is_linux_kernel_module(elf_handle)); } -/// Find and return the .text section. -/// -/// @param elf_handle the elf handle to use. -/// -/// @return the .text section found. -static Elf_Scn* -find_text_section(Elf* elf_handle) -{return find_section(elf_handle, ".text", SHT_PROGBITS);} - -/// Find and return the .bss section. -/// -/// @param elf_handle. -/// -/// @return the .bss section found. -static Elf_Scn* -find_bss_section(Elf* elf_handle) -{return find_section(elf_handle, ".bss", SHT_NOBITS);} - -/// Find and return the .rodata section. -/// -/// @param elf_handle. -/// -/// @return the .rodata section found. -static Elf_Scn* -find_rodata_section(Elf* elf_handle) -{return find_section(elf_handle, ".rodata", SHT_PROGBITS);} - -/// Find and return the .data section. -/// -/// @param elf_handle the elf handle to use. -/// -/// @return the .data section found. -static Elf_Scn* -find_data_section(Elf* elf_handle) -{return find_section(elf_handle, ".data", SHT_PROGBITS);} - -/// Find and return the .data1 section. -/// -/// @param elf_handle the elf handle to use. -/// -/// @return the .data1 section found. -static Elf_Scn* -find_data1_section(Elf* elf_handle) -{return find_section(elf_handle, ".data1", SHT_PROGBITS);} - /// Find the __ksymtab_strings section of a Linux kernel binary. /// /// diff --git a/src/abg-elf-helpers.cc b/src/abg-elf-helpers.cc index e99fe4a5c306..b0113a4efd2c 100644 --- a/src/abg-elf-helpers.cc +++ b/src/abg-elf-helpers.cc @@ -24,11 +24,482 @@ #include "abg-elf-helpers.h" +#include + +#include "abg-tools-utils.h" + namespace abigail { namespace elf_helpers { +/// Convert an elf symbol type (given by the ELF{32,64}_ST_TYPE +/// macros) into an elf_symbol::type value. +/// +/// Note that this function aborts when given an unexpected value. +/// +/// @param the symbol type value to convert. +/// +/// @return the converted value. +elf_symbol::type +stt_to_elf_symbol_type(unsigned char stt) +{ + switch (stt) + { + case STT_NOTYPE: + return elf_symbol::NOTYPE_TYPE; + case STT_OBJECT: + return elf_symbol::OBJECT_TYPE; + case STT_FUNC: + return elf_symbol::FUNC_TYPE; + case STT_SECTION: + return elf_symbol::SECTION_TYPE; + case STT_FILE: + return elf_symbol::FILE_TYPE; + case STT_COMMON: + return elf_symbol::COMMON_TYPE; + case STT_TLS: + return elf_symbol::TLS_TYPE; + case STT_GNU_IFUNC: + return elf_symbol::GNU_IFUNC_TYPE; + default: + // An unknown value that probably ought to be supported? Let's + // abort right here rather than yielding garbage. + ABG_ASSERT_NOT_REACHED; + } +} + +/// Convert an elf symbol binding (given by the ELF{32,64}_ST_BIND +/// macros) into an elf_symbol::binding value. +/// +/// Note that this function aborts when given an unexpected value. +/// +/// @param the symbol binding value to convert. +/// +/// @return the converted value. +elf_symbol::binding +stb_to_elf_symbol_binding(unsigned char stb) +{ + switch (stb) + { + case STB_LOCAL: + return elf_symbol::LOCAL_BINDING; + case STB_GLOBAL: + return elf_symbol::GLOBAL_BINDING; + case STB_WEAK: + return elf_symbol::WEAK_BINDING; + case STB_GNU_UNIQUE: + return elf_symbol::GNU_UNIQUE_BINDING; + default: + ABG_ASSERT_NOT_REACHED; + } +} + +/// Convert an ELF symbol visiblity given by the symbols ->st_other +/// data member as returned by the GELF_ST_VISIBILITY macro into a +/// elf_symbol::visiblity value. +/// +/// @param stv the value of the ->st_other data member of the ELF +/// symbol. +/// +/// @return the converted elf_symbol::visiblity value. +elf_symbol::visibility +stv_to_elf_symbol_visibility(unsigned char stv) +{ + switch (stv) + { + case STV_DEFAULT: + return elf_symbol::DEFAULT_VISIBILITY; + case STV_INTERNAL: + return elf_symbol::INTERNAL_VISIBILITY; + case STV_HIDDEN: + return elf_symbol::HIDDEN_VISIBILITY; + case STV_PROTECTED: + return elf_symbol::PROTECTED_VISIBILITY; + default: + ABG_ASSERT_NOT_REACHED; + } +} + +/// Convert the value of the e_machine field of GElf_Ehdr into a +/// string. This is to get a string representing the architecture of +/// the elf file at hand. +/// +/// @param e_machine the value of GElf_Ehdr::e_machine. +/// +/// @return the string representation of GElf_Ehdr::e_machine. +std::string +e_machine_to_string(GElf_Half e_machine) +{ + switch (e_machine) + { + case EM_NONE: + return "elf-no-arch"; + case EM_M32: + return "elf-att-we-32100"; + case EM_SPARC: + return "elf-sun-sparc"; + case EM_386: + return "elf-intel-80386"; + case EM_68K: + return "elf-motorola-68k"; + case EM_88K: + return "elf-motorola-88k"; + case EM_860: + return "elf-intel-80860"; + case EM_MIPS: + return "elf-mips-r3000-be"; + case EM_S370: + return "elf-ibm-s370"; + case EM_MIPS_RS3_LE: + return "elf-mips-r3000-le"; + case EM_PARISC: + return "elf-hp-parisc"; + case EM_VPP500: + return "elf-fujitsu-vpp500"; + case EM_SPARC32PLUS: + return "elf-sun-sparc-v8plus"; + case EM_960: + return "elf-intel-80960"; + case EM_PPC: + return "elf-powerpc"; + case EM_PPC64: + return "elf-powerpc-64"; + case EM_S390: + return "elf-ibm-s390"; + case EM_V800: + return "elf-nec-v800"; + case EM_FR20: + return "elf-fujitsu-fr20"; + case EM_RH32: + return "elf-trw-rh32"; + case EM_RCE: + return "elf-motorola-rce"; + case EM_ARM: + return "elf-arm"; + case EM_FAKE_ALPHA: + return "elf-digital-alpha"; + case EM_SH: + return "elf-hitachi-sh"; + case EM_SPARCV9: + return "elf-sun-sparc-v9-64"; + case EM_TRICORE: + return "elf-siemens-tricore"; + case EM_ARC: + return "elf-argonaut-risc-core"; + case EM_H8_300: + return "elf-hitachi-h8-300"; + case EM_H8_300H: + return "elf-hitachi-h8-300h"; + case EM_H8S: + return "elf-hitachi-h8s"; + case EM_H8_500: + return "elf-hitachi-h8-500"; + case EM_IA_64: + return "elf-intel-ia-64"; + case EM_MIPS_X: + return "elf-stanford-mips-x"; + case EM_COLDFIRE: + return "elf-motorola-coldfire"; + case EM_68HC12: + return "elf-motorola-68hc12"; + case EM_MMA: + return "elf-fujitsu-mma"; + case EM_PCP: + return "elf-siemens-pcp"; + case EM_NCPU: + return "elf-sony-ncpu"; + case EM_NDR1: + return "elf-denso-ndr1"; + case EM_STARCORE: + return "elf-motorola-starcore"; + case EM_ME16: + return "elf-toyota-me16"; + case EM_ST100: + return "elf-stm-st100"; + case EM_TINYJ: + return "elf-alc-tinyj"; + case EM_X86_64: + return "elf-amd-x86_64"; + case EM_PDSP: + return "elf-sony-pdsp"; + case EM_FX66: + return "elf-siemens-fx66"; + case EM_ST9PLUS: + return "elf-stm-st9+"; + case EM_ST7: + return "elf-stm-st7"; + case EM_68HC16: + return "elf-motorola-68hc16"; + case EM_68HC11: + return "elf-motorola-68hc11"; + case EM_68HC08: + return "elf-motorola-68hc08"; + case EM_68HC05: + return "elf-motorola-68hc05"; + case EM_SVX: + return "elf-sg-svx"; + case EM_ST19: + return "elf-stm-st19"; + case EM_VAX: + return "elf-digital-vax"; + case EM_CRIS: + return "elf-axis-cris"; + case EM_JAVELIN: + return "elf-infineon-javelin"; + case EM_FIREPATH: + return "elf-firepath"; + case EM_ZSP: + return "elf-lsi-zsp"; + case EM_MMIX: + return "elf-don-knuth-mmix"; + case EM_HUANY: + return "elf-harvard-huany"; + case EM_PRISM: + return "elf-sitera-prism"; + case EM_AVR: + return "elf-atmel-avr"; + case EM_FR30: + return "elf-fujistu-fr30"; + case EM_D10V: + return "elf-mitsubishi-d10v"; + case EM_D30V: + return "elf-mitsubishi-d30v"; + case EM_V850: + return "elf-nec-v850"; + case EM_M32R: + return "elf-mitsubishi-m32r"; + case EM_MN10300: + return "elf-matsushita-mn10300"; + case EM_MN10200: + return "elf-matsushita-mn10200"; + case EM_PJ: + return "elf-picojava"; + case EM_OPENRISC: + return "elf-openrisc-32"; + case EM_ARC_A5: + return "elf-arc-a5"; + case EM_XTENSA: + return "elf-tensilica-xtensa"; + +#ifdef HAVE_EM_AARCH64_MACRO + case EM_AARCH64: + return "elf-arm-aarch64"; +#endif + +#ifdef HAVE_EM_TILEPRO_MACRO + case EM_TILEPRO: + return "elf-tilera-tilepro"; +#endif + +#ifdef HAVE_EM_TILEGX_MACRO + case EM_TILEGX: + return "elf-tilera-tilegx"; +#endif + + case EM_NUM: + return "elf-last-arch-number"; + case EM_ALPHA: + return "elf-non-official-alpha"; + default: + { + std::ostringstream o; + o << "elf-unknown-arch-value-" << e_machine; + return o.str(); + } + } +} + +/// Find and return a section by its name and its type. +/// +/// @param elf_handle the elf handle to use. +/// +/// @param name the name of the section. +/// +/// @param section_type the type of the section. This is the +/// Elf32_Shdr::sh_type (or Elf64_Shdr::sh_type) data member. +/// Examples of values of this parameter are SHT_PROGBITS or SHT_NOBITS. +/// +/// @return the section found, nor nil if none was found. +Elf_Scn* +find_section(Elf* elf_handle, const std::string& name, Elf64_Word section_type) +{ + size_t section_header_string_index = 0; + if (elf_getshdrstrndx (elf_handle, §ion_header_string_index) < 0) + return 0; + + Elf_Scn* section = 0; + GElf_Shdr header_mem, *header; + while ((section = elf_nextscn(elf_handle, section)) != 0) + { + header = gelf_getshdr(section, &header_mem); + if (header == NULL || header->sh_type != section_type) + continue; + + const char* section_name = + elf_strptr(elf_handle, section_header_string_index, header->sh_name); + if (section_name && name == section_name) + return section; + } + + return 0; +} + +/// Find the symbol table. +/// +/// If we are looking at a relocatable or executable file, this +/// function will return the .symtab symbol table (of type +/// SHT_SYMTAB). But if we are looking at a DSO it returns the +/// .dynsym symbol table (of type SHT_DYNSYM). +/// +/// @param elf_handle the elf handle to consider. +/// +/// @param symtab the symbol table found. +/// +/// @return true iff the symbol table is found. +bool +find_symbol_table_section(Elf* elf_handle, Elf_Scn*& symtab) +{ + Elf_Scn* section = 0, *dynsym = 0, *sym_tab = 0; + while ((section = elf_nextscn(elf_handle, section)) != 0) + { + GElf_Shdr header_mem, *header; + header = gelf_getshdr(section, &header_mem); + if (header->sh_type == SHT_DYNSYM) + dynsym = section; + else if (header->sh_type == SHT_SYMTAB) + sym_tab = section; + } + + if (dynsym || sym_tab) + { + GElf_Ehdr eh_mem; + GElf_Ehdr* elf_header = gelf_getehdr(elf_handle, &eh_mem); + if (elf_header->e_type == ET_REL + || elf_header->e_type == ET_EXEC) + symtab = sym_tab ? sym_tab : dynsym; + else + symtab = dynsym ? dynsym : sym_tab; + return true; + } + return false; +} + +/// Find the index (in the section headers table) of the symbol table +/// section. +/// +/// If we are looking at a relocatable or executable file, this +/// function will return the index for the .symtab symbol table (of +/// type SHT_SYMTAB). But if we are looking at a DSO it returns the +/// index for the .dynsym symbol table (of type SHT_DYNSYM). +/// +/// @param elf_handle the elf handle to use. +/// +/// @param symtab_index the index of the symbol_table, that was found. +/// +/// @return true iff the symbol table section index was found. +bool +find_symbol_table_section_index(Elf* elf_handle, size_t& symtab_index) +{ + Elf_Scn* section = 0; + if (!find_symbol_table_section(elf_handle, section)) + return false; + + symtab_index = elf_ndxscn(section); + return true; +} + +/// Get the offset offset of the hash table section. +/// +/// @param elf_handle the elf handle to use. +/// +/// @param ht_section_offset this is set to the resulting offset +/// of the hash table section. This is set iff the function returns true. +/// +/// @param symtab_section_offset the offset of the section of the +/// symbol table the hash table refers to. +hash_table_kind +find_hash_table_section_index(Elf* elf_handle, + size_t& ht_section_index, + size_t& symtab_section_index) +{ + if (!elf_handle) + return NO_HASH_TABLE_KIND; + + GElf_Shdr header_mem, *section_header; + bool found_sysv_ht = false, found_gnu_ht = false; + for (Elf_Scn* section = elf_nextscn(elf_handle, 0); + section != 0; + section = elf_nextscn(elf_handle, section)) + { + section_header= gelf_getshdr(section, &header_mem); + if (section_header->sh_type != SHT_HASH + && section_header->sh_type != SHT_GNU_HASH) + continue; + + ht_section_index = elf_ndxscn(section); + symtab_section_index = section_header->sh_link; + + if (section_header->sh_type == SHT_HASH) + found_sysv_ht = true; + else if (section_header->sh_type == SHT_GNU_HASH) + found_gnu_ht = true; + } + + if (found_gnu_ht) + return GNU_HASH_TABLE_KIND; + else if (found_sysv_ht) + return SYSV_HASH_TABLE_KIND; + else + return NO_HASH_TABLE_KIND; +} + +/// Find and return the .text section. +/// +/// @param elf_handle the elf handle to use. +/// +/// @return the .text section found. +Elf_Scn* +find_text_section(Elf* elf_handle) +{return find_section(elf_handle, ".text", SHT_PROGBITS);} + +/// Find and return the .bss section. +/// +/// @param elf_handle. +/// +/// @return the .bss section found. +Elf_Scn* +find_bss_section(Elf* elf_handle) +{return find_section(elf_handle, ".bss", SHT_NOBITS);} + +/// Find and return the .rodata section. +/// +/// @param elf_handle. +/// +/// @return the .rodata section found. +Elf_Scn* +find_rodata_section(Elf* elf_handle) +{return find_section(elf_handle, ".rodata", SHT_PROGBITS);} + +/// Find and return the .data section. +/// +/// @param elf_handle the elf handle to use. +/// +/// @return the .data section found. +Elf_Scn* +find_data_section(Elf* elf_handle) +{return find_section(elf_handle, ".data", SHT_PROGBITS);} + +/// Find and return the .data1 section. +/// +/// @param elf_handle the elf handle to use. +/// +/// @return the .data1 section found. +Elf_Scn* +find_data1_section(Elf* elf_handle) +{return find_section(elf_handle, ".data1", SHT_PROGBITS);} + + } // end namespace elf_helpers } // end namespace abigail diff --git a/src/abg-elf-helpers.h b/src/abg-elf-helpers.h index bffa46cc3c2d..58720da0fa9e 100644 --- a/src/abg-elf-helpers.h +++ b/src/abg-elf-helpers.h @@ -25,12 +25,77 @@ #ifndef __ABG_ELF_HELPERS_H__ #define __ABG_ELF_HELPERS_H__ +#include "config.h" + +#include +#include + +#include "abg-ir.h" + namespace abigail { namespace elf_helpers { +// +// ELF Value Converters +// + +elf_symbol::type +stt_to_elf_symbol_type(unsigned char stt); + +elf_symbol::binding +stb_to_elf_symbol_binding(unsigned char stb); + +elf_symbol::visibility +stv_to_elf_symbol_visibility(unsigned char stv); + +std::string +e_machine_to_string(GElf_Half e_machine); + +// +// ELF section helpers +// + +Elf_Scn* +find_section(Elf* elf_handle, + const std::string& name, + Elf64_Word section_type); + +bool +find_symbol_table_section(Elf* elf_handle, Elf_Scn*& symtab); + +bool +find_symbol_table_section_index(Elf* elf_handle, size_t& symtab_index); + +enum hash_table_kind +{ + NO_HASH_TABLE_KIND = 0, + SYSV_HASH_TABLE_KIND, + GNU_HASH_TABLE_KIND +}; + +hash_table_kind +find_hash_table_section_index(Elf* elf_handle, + size_t& ht_section_index, + size_t& symtab_section_index); + +Elf_Scn* +find_text_section(Elf* elf_handle); + +Elf_Scn* +find_bss_section(Elf* elf_handle); + +Elf_Scn* +find_rodata_section(Elf* elf_handle); + +Elf_Scn* +find_data_section(Elf* elf_handle); + +Elf_Scn* +find_data1_section(Elf* elf_handle); + } // end namespace elf_helpers } // end namespace abigail