From patchwork Tue Apr 21 06:35:44 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: 39108 From: maennich@google.com (Matthias Maennich) Date: Tue, 21 Apr 2020 08:35:44 +0200 Subject: [PATCH v2 1/8] abg-dwarf-reader split: create abg-elf-helpers.{h, cc} and test case 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-2-maennich@google.com> abg-elf-helpers.{h,cc} shall contain the ELF related parts of the abg-dwarf-reader. Create the stub files, an empty unit test and hook everything up in the make system. * src/Makefile.am: Add new source files abg-elf-helpers.{h,cc}. * src/abg-elf-helpers.cc: New source file. * src/abg-elf-helpers.h: New header file. * tests/.gitignore: Exclude runtestelfhelpers from being committed. * tests/Makefile.am: Add new test case runtestelfhelpers. * tests/test-elf-helpers.cc: New test source file. Reviewed-by: Giuliano Procida Signed-off-by: Matthias Maennich --- src/Makefile.am | 2 ++ src/abg-elf-helpers.cc | 34 ++++++++++++++++++++++++++++++++++ src/abg-elf-helpers.h | 37 +++++++++++++++++++++++++++++++++++++ tests/.gitignore | 1 + tests/Makefile.am | 6 +++++- tests/test-elf-helpers.cc | 30 ++++++++++++++++++++++++++++++ 6 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 src/abg-elf-helpers.cc create mode 100644 src/abg-elf-helpers.h create mode 100644 tests/test-elf-helpers.cc diff --git a/src/Makefile.am b/src/Makefile.am index 1d0e2dcecdee..fafab853b520 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -39,6 +39,8 @@ abg-config.cc \ abg-ini.cc \ abg-workers.cc \ abg-tools-utils.cc \ +abg-elf-helpers.h \ +abg-elf-helpers.cc \ $(CXX11_SOURCES) libabigail_la_LIBADD = $(DEPS_LIBS) diff --git a/src/abg-elf-helpers.cc b/src/abg-elf-helpers.cc new file mode 100644 index 000000000000..e99fe4a5c306 --- /dev/null +++ b/src/abg-elf-helpers.cc @@ -0,0 +1,34 @@ +// -*- Mode: C++ -*- +// +// Copyright (C) 2020 Google, Inc. +// +// This file is part of the GNU Application Binary Interface Generic +// Analysis and Instrumentation Library (libabigail). This library is +// free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) any +// later version. + +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Lesser Public License for more details. + +// You should have received a copy of the GNU Lesser General Public +// License along with this program; see the file COPYING-LGPLV3. If +// not, see . + +/// @file +/// +/// This contains the definitions of the ELF utilities for the dwarf reader. + +#include "abg-elf-helpers.h" + +namespace abigail +{ + +namespace elf_helpers +{ + +} // end namespace elf_helpers +} // end namespace abigail diff --git a/src/abg-elf-helpers.h b/src/abg-elf-helpers.h new file mode 100644 index 000000000000..bffa46cc3c2d --- /dev/null +++ b/src/abg-elf-helpers.h @@ -0,0 +1,37 @@ +// -*- Mode: C++ -*- +// +// Copyright (C) 2020 Google, Inc. +// +// This file is part of the GNU Application Binary Interface Generic +// Analysis and Instrumentation Library (libabigail). This library is +// free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) any +// later version. + +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Lesser Public License for more details. + +// You should have received a copy of the GNU Lesser General Public +// License along with this program; see the file COPYING-LGPLV3. If +// not, see . + +/// @file +/// +/// This contains a set of ELF utilities used by the dwarf reader. + +#ifndef __ABG_ELF_HELPERS_H__ +#define __ABG_ELF_HELPERS_H__ + +namespace abigail +{ + +namespace elf_helpers +{ + +} // end namespace elf_helpers +} // end namespace abigail + +#endif // __ABG_ELF_HELPERS_H__ diff --git a/tests/.gitignore b/tests/.gitignore index f05e295db260..ebe7b9cc9e13 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -22,6 +22,7 @@ runtestdiffdwarfabixml runtestdifffilter runtestdiffpkg runtestdiffsuppr +runtestelfhelpers runtestini runtestkmiwhitelist runtestlookupsyms diff --git a/tests/Makefile.am b/tests/Makefile.am index 823e0db50c37..c1b187051377 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -46,6 +46,7 @@ runtestabidiffexit \ runtestini \ runtesttoolsutils \ runtestkmiwhitelist \ +runtestelfhelpers \ $(CXX11_TESTS) if ENABLE_RUNNING_TESTS_WITH_PY3 @@ -142,6 +143,9 @@ runtesttoolsutils_LDADD = libtestutils.la $(top_builddir)/src/libabigail.la runtestkmiwhitelist_SOURCES = test-kmi-whitelist.cc runtestkmiwhitelist_LDADD = libtestutils.la libcatch.la $(top_builddir)/src/libabigail.la +runtestelfhelpers_SOURCES = test-elf-helpers.cc +runtestelfhelpers_LDADD = libcatch.la $(top_builddir)/src/libabigail.la + runtestsvg_SOURCES=test-svg.cc runtestsvg_LDADD=$(top_builddir)/src/libabigail.la @@ -172,7 +176,7 @@ runtestfedabipkgdiffpy3.sh$(EXEEXT): runtestdefaultsupprspy3_sh_SOURCES = runtestdefaultsupprspy3.sh$(EXEEXT): -AM_CPPFLAGS=-I${abs_top_srcdir}/include \ +AM_CPPFLAGS=-I${abs_top_srcdir}/include -I${abs_top_srcdir}/src \ -I${abs_top_builddir}/include -I${abs_top_srcdir}/tools -fPIC clean-local: clean-local-check diff --git a/tests/test-elf-helpers.cc b/tests/test-elf-helpers.cc new file mode 100644 index 000000000000..1b36ee2f122a --- /dev/null +++ b/tests/test-elf-helpers.cc @@ -0,0 +1,30 @@ +// -*- Mode: C++ -*- +// +// Copyright (C) 2020 Google, Inc. +// +// This file is part of the GNU Application Binary Interface Generic +// Analysis and Instrumentation Library (libabigail). This library is +// free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) any +// later version. + +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Lesser Public License for more details. + +// You should have received a copy of the GNU Lesser General Public +// License along with this program; see the file COPYING-LGPLV3. If +// not, see . + +// Author: Matthias Maennich + +/// @file +/// +/// This program tests libabigail's ELF helpers. + +#include "lib/catch.hpp" + +#include "abg-elf-helpers.h" + 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 From patchwork Tue Apr 21 06:35:46 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: 39110 From: maennich@google.com (Matthias Maennich) Date: Tue, 21 Apr 2020 08:35:46 +0200 Subject: [PATCH v2 3/8] abg-elf-helpers: move some versioning 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-4-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(get_symbol_versionning_sections): Move function out. (get_version_definition_for_versym): Likewise. (get_version_needed_for_versym): Likewise. (get_version_for_symbol): Likewise. * abg-elf-helpers.cc(get_symbol_versionning_sections): Move function in. (get_version_definition_for_versym): Likewise. (get_version_needed_for_versym): Likewise. (get_version_for_symbol): Likewise. * abg-elf-helpers.cc(get_symbol_versionning_sections): Add declaration. (get_version_definition_for_versym): Likewise. (get_version_needed_for_versym): Likewise. (get_version_for_symbol): Likewise. Reviewed-by: Giuliano Procida Signed-off-by: Matthias Maennich --- src/abg-dwarf-reader.cc | 256 ---------------------------------------- src/abg-elf-helpers.cc | 251 +++++++++++++++++++++++++++++++++++++++ src/abg-elf-helpers.h | 28 +++++ 3 files changed, 279 insertions(+), 256 deletions(-) diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc index 6ec7e4b6e968..303c1f8df4c2 100644 --- a/src/abg-dwarf-reader.cc +++ b/src/abg-dwarf-reader.cc @@ -294,12 +294,6 @@ static void add_symbol_to_map(const elf_symbol_sptr& sym, string_elf_symbols_map_type& map); -static bool -get_symbol_versionning_sections(Elf* elf_handle, - Elf_Scn*& versym_section, - Elf_Scn*& verdef_section, - Elf_Scn*& verneed_section); - static bool get_parent_die(const read_context& ctxt, const Dwarf_Die* die, @@ -867,256 +861,6 @@ compare_symbol_name(const string& symbol_name, return symbol_name == name; } -/// Return the SHT_GNU_versym, SHT_GNU_verdef and SHT_GNU_verneed -/// sections that are involved in symbol versionning. -/// -/// @param elf_handle the elf handle to use. -/// -/// @param versym_section the SHT_GNU_versym section found. If the -/// section wasn't found, this is set to nil. -/// -/// @param verdef_section the SHT_GNU_verdef section found. If the -/// section wasn't found, this is set to nil. -/// -/// @param verneed_section the SHT_GNU_verneed section found. If the -/// section wasn't found, this is set to nil. -/// -/// @return true iff at least one of the sections where found. -static bool -get_symbol_versionning_sections(Elf* elf_handle, - Elf_Scn*& versym_section, - Elf_Scn*& verdef_section, - Elf_Scn*& verneed_section) -{ - Elf_Scn* section = NULL; - GElf_Shdr mem; - Elf_Scn* versym = NULL, *verdef = NULL, *verneed = NULL; - - while ((section = elf_nextscn(elf_handle, section)) != NULL) - { - GElf_Shdr* h = gelf_getshdr(section, &mem); - if (h->sh_type == SHT_GNU_versym) - versym = section; - else if (h->sh_type == SHT_GNU_verdef) - verdef = section; - else if (h->sh_type == SHT_GNU_verneed) - verneed = section; - } - - if (versym || verdef || verneed) - { - // At least one the versionning sections was found. Return it. - versym_section = versym; - verdef_section = verdef; - verneed_section = verneed; - return true; - } - - return false; -} - -/// Get the version definition (from the SHT_GNU_verdef section) of a -/// given symbol represented by a pointer to GElf_Versym. -/// -/// @param elf_hande the elf handle to use. -/// -/// @param versym the symbol to get the version definition for. -/// -/// @param verdef_section the SHT_GNU_verdef section. -/// -/// @param version the resulting version definition. This is set iff -/// the function returns true. -/// -/// @return true upon successful completion, false otherwise. -static bool -get_version_definition_for_versym(Elf* elf_handle, - GElf_Versym* versym, - Elf_Scn* verdef_section, - elf_symbol::version& version) -{ - Elf_Data* verdef_data = elf_getdata(verdef_section, NULL); - GElf_Verdef verdef_mem; - GElf_Verdef* verdef = gelf_getverdef(verdef_data, 0, &verdef_mem); - size_t vd_offset = 0; - - for (;; vd_offset += verdef->vd_next) - { - for (;verdef != 0;) - { - if (verdef->vd_ndx == (*versym & 0x7fff)) - // Found the version of the symbol. - break; - vd_offset += verdef->vd_next; - verdef = (verdef->vd_next == 0 - ? 0 - : gelf_getverdef(verdef_data, vd_offset, &verdef_mem)); - } - - if (verdef != 0) - { - GElf_Verdaux verdaux_mem; - GElf_Verdaux *verdaux = gelf_getverdaux(verdef_data, - vd_offset + verdef->vd_aux, - &verdaux_mem); - GElf_Shdr header_mem; - GElf_Shdr* verdef_section_header = gelf_getshdr(verdef_section, - &header_mem); - size_t verdef_stridx = verdef_section_header->sh_link; - version.str(elf_strptr(elf_handle, verdef_stridx, verdaux->vda_name)); - if (*versym & 0x8000) - version.is_default(false); - else - version.is_default(true); - return true; - } - if (!verdef || verdef->vd_next == 0) - break; - } - return false; -} - -/// Get the version needed (from the SHT_GNU_verneed section) to -/// resolve an undefined symbol represented by a pointer to -/// GElf_Versym. -/// -/// @param elf_hande the elf handle to use. -/// -/// @param versym the symbol to get the version definition for. -/// -/// @param verneed_section the SHT_GNU_verneed section. -/// -/// @param version the resulting version definition. This is set iff -/// the function returns true. -/// -/// @return true upon successful completion, false otherwise. -static bool -get_version_needed_for_versym(Elf* elf_handle, - GElf_Versym* versym, - Elf_Scn* verneed_section, - elf_symbol::version& version) -{ - if (versym == 0 || elf_handle == 0 || verneed_section == 0) - return false; - - size_t vn_offset = 0; - Elf_Data* verneed_data = elf_getdata(verneed_section, NULL); - GElf_Verneed verneed_mem; - GElf_Verneed* verneed = gelf_getverneed(verneed_data, 0, &verneed_mem); - - for (;verneed; vn_offset += verneed->vn_next) - { - size_t vna_offset = vn_offset; - GElf_Vernaux vernaux_mem; - GElf_Vernaux *vernaux = gelf_getvernaux(verneed_data, - vn_offset + verneed->vn_aux, - &vernaux_mem); - for (;vernaux != 0 && verneed;) - { - if (vernaux->vna_other == *versym) - // Found the version of the symbol. - break; - vna_offset += verneed->vn_next; - verneed = (verneed->vn_next == 0 - ? 0 - : gelf_getverneed(verneed_data, vna_offset, &verneed_mem)); - } - - if (verneed != 0 && vernaux != 0 && vernaux->vna_other == *versym) - { - GElf_Shdr header_mem; - GElf_Shdr* verneed_section_header = gelf_getshdr(verneed_section, - &header_mem); - size_t verneed_stridx = verneed_section_header->sh_link; - version.str(elf_strptr(elf_handle, - verneed_stridx, - vernaux->vna_name)); - if (*versym & 0x8000) - version.is_default(false); - else - version.is_default(true); - return true; - } - - if (!verneed || verneed->vn_next == 0) - break; - } - return false; -} - -/// Return the version for a symbol that is at a given index in its -/// SHT_SYMTAB section. -/// -/// @param elf_handle the elf handle to use. -/// -/// @param symbol_index the index of the symbol to consider. -/// -/// @param get_def_version if this is true, it means that that we want -/// the version for a defined symbol; in that case, the version is -/// looked for in a section of type SHT_GNU_verdef. Otherwise, if -/// this parameter is false, this means that we want the version for -/// an undefined symbol; in that case, the version is the needed one -/// for the symbol to be resolved; so the version is looked fo in a -/// section of type SHT_GNU_verneed. -/// -/// @param version the version found for symbol at @p symbol_index. -/// -/// @return true iff a version was found for symbol at index @p -/// symbol_index. -static bool -get_version_for_symbol(Elf* elf_handle, - size_t symbol_index, - bool get_def_version, - elf_symbol::version& version) -{ - Elf_Scn *versym_section = NULL, - *verdef_section = NULL, - *verneed_section = NULL; - - if (!get_symbol_versionning_sections(elf_handle, - versym_section, - verdef_section, - verneed_section)) - return false; - - GElf_Versym versym_mem; - Elf_Data* versym_data = (versym_section) - ? elf_getdata(versym_section, NULL) - : NULL; - GElf_Versym* versym = (versym_data) - ? gelf_getversym(versym_data, symbol_index, &versym_mem) - : NULL; - - if (versym == 0 || *versym <= 1) - // I got these value from the code of readelf.c in elfutils. - // Apparently, if the symbol version entry has these values, the - // symbol must be discarded. This is not documented in the - // official specification. - return false; - - if (get_def_version) - { - if (*versym == 0x8001) - // I got this value from the code of readelf.c in elfutils - // too. It's not really documented in the official - // specification. - return false; - - if (verdef_section - && get_version_definition_for_versym(elf_handle, versym, - verdef_section, version)) - return true; - } - else - { - if (verneed_section - && get_version_needed_for_versym(elf_handle, versym, - verneed_section, version)) - return true; - } - - return false; -} - /// Lookup a symbol using the SysV ELF hash table. /// /// Note that this function hasn't been tested. So it hasn't been diff --git a/src/abg-elf-helpers.cc b/src/abg-elf-helpers.cc index b0113a4efd2c..b7b868a332ec 100644 --- a/src/abg-elf-helpers.cc +++ b/src/abg-elf-helpers.cc @@ -500,6 +500,257 @@ Elf_Scn* find_data1_section(Elf* elf_handle) {return find_section(elf_handle, ".data1", SHT_PROGBITS);} +/// Return the SHT_GNU_versym, SHT_GNU_verdef and SHT_GNU_verneed +/// sections that are involved in symbol versionning. +/// +/// @param elf_handle the elf handle to use. +/// +/// @param versym_section the SHT_GNU_versym section found. If the +/// section wasn't found, this is set to nil. +/// +/// @param verdef_section the SHT_GNU_verdef section found. If the +/// section wasn't found, this is set to nil. +/// +/// @param verneed_section the SHT_GNU_verneed section found. If the +/// section wasn't found, this is set to nil. +/// +/// @return true iff at least one of the sections where found. +bool +get_symbol_versionning_sections(Elf* elf_handle, + Elf_Scn*& versym_section, + Elf_Scn*& verdef_section, + Elf_Scn*& verneed_section) +{ + Elf_Scn* section = NULL; + GElf_Shdr mem; + Elf_Scn* versym = NULL, *verdef = NULL, *verneed = NULL; + + while ((section = elf_nextscn(elf_handle, section)) != NULL) + { + GElf_Shdr* h = gelf_getshdr(section, &mem); + if (h->sh_type == SHT_GNU_versym) + versym = section; + else if (h->sh_type == SHT_GNU_verdef) + verdef = section; + else if (h->sh_type == SHT_GNU_verneed) + verneed = section; + } + + if (versym || verdef || verneed) + { + // At least one the versionning sections was found. Return it. + versym_section = versym; + verdef_section = verdef; + verneed_section = verneed; + return true; + } + + return false; +} + +/// Get the version definition (from the SHT_GNU_verdef section) of a +/// given symbol represented by a pointer to GElf_Versym. +/// +/// @param elf_hande the elf handle to use. +/// +/// @param versym the symbol to get the version definition for. +/// +/// @param verdef_section the SHT_GNU_verdef section. +/// +/// @param version the resulting version definition. This is set iff +/// the function returns true. +/// +/// @return true upon successful completion, false otherwise. +bool +get_version_definition_for_versym(Elf* elf_handle, + GElf_Versym* versym, + Elf_Scn* verdef_section, + elf_symbol::version& version) +{ + Elf_Data* verdef_data = elf_getdata(verdef_section, NULL); + GElf_Verdef verdef_mem; + GElf_Verdef* verdef = gelf_getverdef(verdef_data, 0, &verdef_mem); + size_t vd_offset = 0; + + for (;; vd_offset += verdef->vd_next) + { + for (;verdef != 0;) + { + if (verdef->vd_ndx == (*versym & 0x7fff)) + // Found the version of the symbol. + break; + vd_offset += verdef->vd_next; + verdef = (verdef->vd_next == 0 + ? 0 + : gelf_getverdef(verdef_data, vd_offset, &verdef_mem)); + } + + if (verdef != 0) + { + GElf_Verdaux verdaux_mem; + GElf_Verdaux *verdaux = gelf_getverdaux(verdef_data, + vd_offset + verdef->vd_aux, + &verdaux_mem); + GElf_Shdr header_mem; + GElf_Shdr* verdef_section_header = gelf_getshdr(verdef_section, + &header_mem); + size_t verdef_stridx = verdef_section_header->sh_link; + version.str(elf_strptr(elf_handle, verdef_stridx, verdaux->vda_name)); + if (*versym & 0x8000) + version.is_default(false); + else + version.is_default(true); + return true; + } + if (!verdef || verdef->vd_next == 0) + break; + } + return false; +} + +/// Get the version needed (from the SHT_GNU_verneed section) to +/// resolve an undefined symbol represented by a pointer to +/// GElf_Versym. +/// +/// @param elf_hande the elf handle to use. +/// +/// @param versym the symbol to get the version definition for. +/// +/// @param verneed_section the SHT_GNU_verneed section. +/// +/// @param version the resulting version definition. This is set iff +/// the function returns true. +/// +/// @return true upon successful completion, false otherwise. +bool +get_version_needed_for_versym(Elf* elf_handle, + GElf_Versym* versym, + Elf_Scn* verneed_section, + elf_symbol::version& version) +{ + if (versym == 0 || elf_handle == 0 || verneed_section == 0) + return false; + + size_t vn_offset = 0; + Elf_Data* verneed_data = elf_getdata(verneed_section, NULL); + GElf_Verneed verneed_mem; + GElf_Verneed* verneed = gelf_getverneed(verneed_data, 0, &verneed_mem); + + for (;verneed; vn_offset += verneed->vn_next) + { + size_t vna_offset = vn_offset; + GElf_Vernaux vernaux_mem; + GElf_Vernaux *vernaux = gelf_getvernaux(verneed_data, + vn_offset + verneed->vn_aux, + &vernaux_mem); + for (;vernaux != 0 && verneed;) + { + if (vernaux->vna_other == *versym) + // Found the version of the symbol. + break; + vna_offset += verneed->vn_next; + verneed = (verneed->vn_next == 0 + ? 0 + : gelf_getverneed(verneed_data, vna_offset, &verneed_mem)); + } + + if (verneed != 0 && vernaux != 0 && vernaux->vna_other == *versym) + { + GElf_Shdr header_mem; + GElf_Shdr* verneed_section_header = gelf_getshdr(verneed_section, + &header_mem); + size_t verneed_stridx = verneed_section_header->sh_link; + version.str(elf_strptr(elf_handle, + verneed_stridx, + vernaux->vna_name)); + if (*versym & 0x8000) + version.is_default(false); + else + version.is_default(true); + return true; + } + + if (!verneed || verneed->vn_next == 0) + break; + } + return false; +} + +/// Return the version for a symbol that is at a given index in its +/// SHT_SYMTAB section. +/// +/// @param elf_handle the elf handle to use. +/// +/// @param symbol_index the index of the symbol to consider. +/// +/// @param get_def_version if this is true, it means that that we want +/// the version for a defined symbol; in that case, the version is +/// looked for in a section of type SHT_GNU_verdef. Otherwise, if +/// this parameter is false, this means that we want the version for +/// an undefined symbol; in that case, the version is the needed one +/// for the symbol to be resolved; so the version is looked fo in a +/// section of type SHT_GNU_verneed. +/// +/// @param version the version found for symbol at @p symbol_index. +/// +/// @return true iff a version was found for symbol at index @p +/// symbol_index. +bool +get_version_for_symbol(Elf* elf_handle, + size_t symbol_index, + bool get_def_version, + elf_symbol::version& version) +{ + Elf_Scn *versym_section = NULL, + *verdef_section = NULL, + *verneed_section = NULL; + + if (!get_symbol_versionning_sections(elf_handle, + versym_section, + verdef_section, + verneed_section)) + return false; + + GElf_Versym versym_mem; + Elf_Data* versym_data = (versym_section) + ? elf_getdata(versym_section, NULL) + : NULL; + GElf_Versym* versym = (versym_data) + ? gelf_getversym(versym_data, symbol_index, &versym_mem) + : NULL; + + if (versym == 0 || *versym <= 1) + // I got these value from the code of readelf.c in elfutils. + // Apparently, if the symbol version entry has these values, the + // symbol must be discarded. This is not documented in the + // official specification. + return false; + + if (get_def_version) + { + if (*versym == 0x8001) + // I got this value from the code of readelf.c in elfutils + // too. It's not really documented in the official + // specification. + return false; + + if (verdef_section + && get_version_definition_for_versym(elf_handle, versym, + verdef_section, version)) + return true; + } + else + { + if (verneed_section + && get_version_needed_for_versym(elf_handle, versym, + verneed_section, version)) + return true; + } + + return false; +} + + } // end namespace elf_helpers } // end namespace abigail diff --git a/src/abg-elf-helpers.h b/src/abg-elf-helpers.h index 58720da0fa9e..7e1c231ccc4e 100644 --- a/src/abg-elf-helpers.h +++ b/src/abg-elf-helpers.h @@ -96,6 +96,34 @@ find_data_section(Elf* elf_handle); Elf_Scn* find_data1_section(Elf* elf_handle); +bool +get_symbol_versionning_sections(Elf* elf_handle, + Elf_Scn*& versym_section, + Elf_Scn*& verdef_section, + Elf_Scn*& verneed_section); + +// +// Helpers for symbol versioning +// + +bool +get_version_definition_for_versym(Elf* elf_handle, + GElf_Versym* versym, + Elf_Scn* verdef_section, + elf_symbol::version& version); + +bool +get_version_needed_for_versym(Elf* elf_handle, + GElf_Versym* versym, + Elf_Scn* verneed_section, + elf_symbol::version& version); + +bool +get_version_for_symbol(Elf* elf_handle, + size_t symbol_index, + bool get_def_version, + elf_symbol::version& version); + } // end namespace elf_helpers } // end namespace abigail From patchwork Tue Apr 21 06:35:47 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: 39111 From: maennich@google.com (Matthias Maennich) Date: Tue, 21 Apr 2020 08:35:47 +0200 Subject: [PATCH v2 4/8] abg-elf-helpers: move some kernel 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-5-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(binary_is_linux_kernel): Move function out. (binary_is_linux_kernel_module): Likewise. (find_ksymtab_strings_section): Likewise. * abg-elf-helpers.cc(binary_is_linux_kernel): Move function in. (binary_is_linux_kernel_module): Likewise. (find_ksymtab_strings_section): Likewise. * abg-elf-helpers.h(binary_is_linux_kernel): Add declaration. (binary_is_linux_kernel_module): Likewise. (find_ksymtab_strings_section): Likewise. Reviewed-by: Giuliano Procida Signed-off-by: Matthias Maennich --- src/abg-dwarf-reader.cc | 46 ----------------------------------------- src/abg-elf-helpers.cc | 45 ++++++++++++++++++++++++++++++++++++++++ src/abg-elf-helpers.h | 14 +++++++++++++ 3 files changed, 59 insertions(+), 46 deletions(-) diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc index 303c1f8df4c2..3adb978b784b 100644 --- a/src/abg-dwarf-reader.cc +++ b/src/abg-dwarf-reader.cc @@ -542,52 +542,6 @@ compare_dies(const read_context& ctxt, bool update_canonical_dies_on_the_fly); -/// Test if the ELF binary denoted by a given ELF handle is a Linux -/// Kernel Module. -/// -/// @param elf_handle the ELF handle to consider. -/// -/// @return true iff the binary denoted by @p elf_handle is a Linux -/// kernel module. -static bool -binary_is_linux_kernel_module(Elf *elf_handle) -{ - return (find_section(elf_handle, ".modinfo", SHT_PROGBITS) - && find_section(elf_handle, - ".gnu.linkonce.this_module", - SHT_PROGBITS)); -} - -/// Test if the ELF binary denoted by a given ELF handle is a Linux -/// Kernel binary (either vmlinux or a kernel module). -/// -/// @param elf_handle the ELF handle to consider. -/// -/// @return true iff the binary denoted by @p elf_handle is a Linux -/// kernel binary -static bool -binary_is_linux_kernel(Elf *elf_handle) -{ - return (find_section(elf_handle, - "__ksymtab_strings", - SHT_PROGBITS) - || binary_is_linux_kernel_module(elf_handle)); -} - -/// Find the __ksymtab_strings section of a Linux kernel binary. -/// -/// -/// @return the find_ksymtab_strings_section of the linux kernel -/// binary denoted by @p elf_handle, or nil if such a section could -/// not be found. -static Elf_Scn* -find_ksymtab_strings_section(Elf *elf_handle) -{ - if (binary_is_linux_kernel(elf_handle)) - return find_section(elf_handle, "__ksymtab_strings", SHT_PROGBITS); - return 0; -} - /// Get the address at which a given binary is loaded in memory? /// /// @param elf_handle the elf handle for the binary to consider. diff --git a/src/abg-elf-helpers.cc b/src/abg-elf-helpers.cc index b7b868a332ec..ff0941dc6536 100644 --- a/src/abg-elf-helpers.cc +++ b/src/abg-elf-helpers.cc @@ -548,6 +548,21 @@ get_symbol_versionning_sections(Elf* elf_handle, return false; } +/// Find the __ksymtab_strings section of a Linux kernel binary. +/// +/// @param elf_handle the elf handle to use. +/// +/// @return the find_ksymtab_strings_section of the linux kernel +/// binary denoted by @p elf_handle, or nil if such a section could +/// not be found. +Elf_Scn* +find_ksymtab_strings_section(Elf *elf_handle) +{ + if (binary_is_linux_kernel(elf_handle)) + return find_section(elf_handle, "__ksymtab_strings", SHT_PROGBITS); + return 0; +} + /// Get the version definition (from the SHT_GNU_verdef section) of a /// given symbol represented by a pointer to GElf_Versym. /// @@ -750,7 +765,37 @@ get_version_for_symbol(Elf* elf_handle, return false; } +/// Test if the ELF binary denoted by a given ELF handle is a Linux +/// Kernel Module. +/// +/// @param elf_handle the ELF handle to consider. +/// +/// @return true iff the binary denoted by @p elf_handle is a Linux +/// kernel module. +bool +binary_is_linux_kernel_module(Elf *elf_handle) +{ + return (find_section(elf_handle, ".modinfo", SHT_PROGBITS) + && find_section(elf_handle, + ".gnu.linkonce.this_module", + SHT_PROGBITS)); +} +/// Test if the ELF binary denoted by a given ELF handle is a Linux +/// Kernel binary (either vmlinux or a kernel module). +/// +/// @param elf_handle the ELF handle to consider. +/// +/// @return true iff the binary denoted by @p elf_handle is a Linux +/// kernel binary +bool +binary_is_linux_kernel(Elf *elf_handle) +{ + return (find_section(elf_handle, + "__ksymtab_strings", + SHT_PROGBITS) + || binary_is_linux_kernel_module(elf_handle)); +} } // end namespace elf_helpers } // end namespace abigail diff --git a/src/abg-elf-helpers.h b/src/abg-elf-helpers.h index 7e1c231ccc4e..33348126028c 100644 --- a/src/abg-elf-helpers.h +++ b/src/abg-elf-helpers.h @@ -102,6 +102,9 @@ get_symbol_versionning_sections(Elf* elf_handle, Elf_Scn*& verdef_section, Elf_Scn*& verneed_section); +Elf_Scn* +find_ksymtab_strings_section(Elf *elf_handle); + // // Helpers for symbol versioning // @@ -124,6 +127,17 @@ get_version_for_symbol(Elf* elf_handle, bool get_def_version, elf_symbol::version& version); +// +// Helpers for Linux Kernel Binaries +// + +bool +binary_is_linux_kernel_module(Elf *elf_handle); + +bool +binary_is_linux_kernel(Elf *elf_handle); + + } // end namespace elf_helpers } // end namespace abigail From patchwork Tue Apr 21 06:35:48 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: 39112 From: maennich@google.com (Matthias Maennich) Date: Tue, 21 Apr 2020 08:35:48 +0200 Subject: [PATCH v2 5/8] abg-elf-helpers: consolidate the is_linux_kernel* helpers 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-6-maennich@google.com> This consistently names the is_linux_kernel* helpers and keeps only the copy in the elf-helpers. All users are adjusted. * src/abg-dwarf-reader.cc (read_context::function_symbol_is_exported): use is_linux_kernel from elf_helpers. (read_context::variable_is_exported): Likewise. (read_context::get_symtab_format): Likewise. (read_context::load_symbol_maps): Likewise. (read_debug_info_into_corpus): Likewise. (read_context::is_linux_kernel_binary): Drop function. (read_context::is_linux_kernel_module): Drop function. * src/abg-elf-helpers.cc (binary_is_linux_kernel): rename to is_linux_kernel (binary_is_linux_kernel_module): rename to is_linux_kernel_module (find_ksymtab_strings_section): Adjust to function renames. * src/abg-elf-helpers.h (binary_is_linux_kernel): rename to is_linux_kernel (binary_is_linux_kernel_module): rename to is_linux_kernel_module Reviewed-by: Giuliano Procida Signed-off-by: Matthias Maennich --- src/abg-dwarf-reader.cc | 37 +++++++------------------------------ src/abg-elf-helpers.cc | 8 ++++---- src/abg-elf-helpers.h | 4 ++-- 3 files changed, 13 insertions(+), 36 deletions(-) diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc index 3adb978b784b..ec1f9f3fe8f3 100644 --- a/src/abg-dwarf-reader.cc +++ b/src/abg-dwarf-reader.cc @@ -5939,7 +5939,7 @@ public: address_set_sptr set; bool looking_at_linux_kernel_binary = - load_in_linux_kernel_mode() && is_linux_kernel_binary(); + load_in_linux_kernel_mode() && is_linux_kernel(elf_handle()); if (looking_at_linux_kernel_binary) { @@ -5979,7 +5979,7 @@ public: address_set_sptr set; bool looking_at_linux_kernel_binary = - load_in_linux_kernel_mode() && is_linux_kernel_binary(); + load_in_linux_kernel_mode() && is_linux_kernel(elf_handle()); if (looking_at_linux_kernel_binary) { @@ -6920,7 +6920,7 @@ public: { // Since Linux kernel modules are relocatable, we can first try // using a heuristic based on relocations to guess the ksymtab format. - if (is_linux_kernel_module()) + if (is_linux_kernel_module(elf_handle())) { ksymtab_format_ = get_ksymtab_format_module(); if (ksymtab_format_ != UNDEFINED_KSYMTAB_FORMAT) @@ -7467,7 +7467,7 @@ public: load_undefined_fun_map, load_undefined_var_map)) { - if (load_in_linux_kernel_mode() && is_linux_kernel_binary()) + if (load_in_linux_kernel_mode() && is_linux_kernel(elf_handle())) return load_linux_specific_exported_symbol_maps(); return true; } @@ -8166,30 +8166,6 @@ public: load_in_linux_kernel_mode(bool f) {options_.load_in_linux_kernel_mode = f;} - /// Guess if the current binary is a Linux Kernel or a Linux Kernel module. - /// - /// To guess that, the function looks for the presence of the - /// special "__ksymtab_strings" section in the binary. - /// - bool - is_linux_kernel_binary() const - { - return find_section(elf_handle(), "__ksymtab_strings", SHT_PROGBITS) - || is_linux_kernel_module(); - } - - /// Guess if the current binary is a Linux Kernel module. - /// - /// To guess that, the function looks for the presence of the special - /// ".modinfo" and ".gnu.linkonce.this_module" sections in the binary. - /// - bool - is_linux_kernel_module() const - { - return find_section(elf_handle(), ".modinfo", SHT_PROGBITS) - && find_section(elf_handle(), ".gnu.linkonce.this_module", SHT_PROGBITS); - } - /// Getter of the "show_stats" flag. /// /// This flag tells if we should emit statistics about various @@ -16322,7 +16298,7 @@ read_debug_info_into_corpus(read_context& ctxt) // First set some mundane properties of the corpus gathered from // ELF. ctxt.current_corpus()->set_path(ctxt.elf_path()); - if (ctxt.is_linux_kernel_binary()) + if (is_linux_kernel(ctxt.elf_handle())) ctxt.current_corpus()->set_origin(corpus::LINUX_KERNEL_BINARY_ORIGIN); else ctxt.current_corpus()->set_origin(corpus::DWARF_ORIGIN); @@ -16335,7 +16311,8 @@ read_debug_info_into_corpus(read_context& ctxt) // Set symbols information to the corpus. if (!get_ignore_symbol_table(ctxt)) { - if (ctxt.load_in_linux_kernel_mode() && ctxt.is_linux_kernel_binary()) + if (ctxt.load_in_linux_kernel_mode() + && is_linux_kernel(ctxt.elf_handle())) { string_elf_symbols_map_sptr exported_fn_symbols_map (new string_elf_symbols_map_type); diff --git a/src/abg-elf-helpers.cc b/src/abg-elf-helpers.cc index ff0941dc6536..ede191014369 100644 --- a/src/abg-elf-helpers.cc +++ b/src/abg-elf-helpers.cc @@ -558,7 +558,7 @@ get_symbol_versionning_sections(Elf* elf_handle, Elf_Scn* find_ksymtab_strings_section(Elf *elf_handle) { - if (binary_is_linux_kernel(elf_handle)) + if (is_linux_kernel(elf_handle)) return find_section(elf_handle, "__ksymtab_strings", SHT_PROGBITS); return 0; } @@ -773,7 +773,7 @@ get_version_for_symbol(Elf* elf_handle, /// @return true iff the binary denoted by @p elf_handle is a Linux /// kernel module. bool -binary_is_linux_kernel_module(Elf *elf_handle) +is_linux_kernel_module(Elf *elf_handle) { return (find_section(elf_handle, ".modinfo", SHT_PROGBITS) && find_section(elf_handle, @@ -789,12 +789,12 @@ binary_is_linux_kernel_module(Elf *elf_handle) /// @return true iff the binary denoted by @p elf_handle is a Linux /// kernel binary bool -binary_is_linux_kernel(Elf *elf_handle) +is_linux_kernel(Elf *elf_handle) { return (find_section(elf_handle, "__ksymtab_strings", SHT_PROGBITS) - || binary_is_linux_kernel_module(elf_handle)); + || is_linux_kernel_module(elf_handle)); } } // end namespace elf_helpers diff --git a/src/abg-elf-helpers.h b/src/abg-elf-helpers.h index 33348126028c..7ddd887de959 100644 --- a/src/abg-elf-helpers.h +++ b/src/abg-elf-helpers.h @@ -132,10 +132,10 @@ get_version_for_symbol(Elf* elf_handle, // bool -binary_is_linux_kernel_module(Elf *elf_handle); +is_linux_kernel_module(Elf *elf_handle); bool -binary_is_linux_kernel(Elf *elf_handle); +is_linux_kernel(Elf *elf_handle); } // end namespace elf_helpers From patchwork Tue Apr 21 06:35:49 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: 39113 From: maennich@google.com (Matthias Maennich) Date: Tue, 21 Apr 2020 08:35:49 +0200 Subject: [PATCH v2 6/8] abg-dwarf-reader: migrate more ELF helpers to elf-helpers 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-7-maennich@google.com> This change migrates all ELF helpers related to section lookup to abg-elf-helpers.{cc,h}. It also homogenizes the interface of those to always return Elf_Scn* and NULL in case that section can't be found. Though this smells like a functional change, this latter change is purely cosmetic. * src/abg-dwarf-reader.cc (read_context::find_symbol_table_section): adjust to new interface of elf_helpers::find_symbol_table_section. (find_opd_section): use elf_helpers::find_opd_section for lookup. (find_ksymtab_section): use elf_helpers::find_ksymtab_section. (find_ksymtab_gpl_section): use elf_helpers::find_ksymtab_gpl_section. (find_relocation_section): Move out function. (get_binary_load_address): Move out function. (find_ksymtab_reloc_section): use elf_helpers::find_relocation_section (find_ksymtab_gpl_reloc_section): use elf_helpers::find_relocation_section * src/elf-helpers.cc (find_symbol_table_section): change interface to match other find_*_section functions. (find_symbol_table_section_index): Adjust for the new interface of find_symbol_table_section. (find_opd_section): New function. (find_ksymtab_section): New function. (find_ksymtab_gpl_section): New function. (find_relocation_section): New function. (get_binary_load_address): New function. * src/elf-helpers.h (find_symbol_table_section): Change declaration. (find_opd_section): New function declation. (find_ksymtab_section): New function declation. (find_ksymtab_gpl_section): New function declation. (find_relocation_section): New function declation. (get_binary_load_address): New function declation. Signed-off-by: Matthias Maennich --- src/abg-dwarf-reader.cc | 112 ++++++---------------------------- src/abg-elf-helpers.cc | 129 +++++++++++++++++++++++++++++++++++++--- src/abg-elf-helpers.h | 22 ++++++- 3 files changed, 157 insertions(+), 106 deletions(-) diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc index ec1f9f3fe8f3..56da03a60940 100644 --- a/src/abg-dwarf-reader.cc +++ b/src/abg-dwarf-reader.cc @@ -542,53 +542,6 @@ compare_dies(const read_context& ctxt, bool update_canonical_dies_on_the_fly); -/// Get the address at which a given binary is loaded in memory? -/// -/// @param elf_handle the elf handle for the binary to consider. -/// -/// @param load_address the address where the binary is loaded. This -/// is set by the function iff it returns true. -/// -/// @return true if the function could get the binary load address -/// and assign @p load_address to it. -static bool -get_binary_load_address(Elf *elf_handle, - GElf_Addr &load_address) -{ - GElf_Ehdr eh_mem; - GElf_Ehdr *elf_header = gelf_getehdr(elf_handle, &eh_mem); - size_t num_segments = elf_header->e_phnum; - GElf_Phdr *program_header = 0; - GElf_Addr result; - bool found_loaded_segment = false; - GElf_Phdr ph_mem; - - for (unsigned i = 0; i < num_segments; ++i) - { - program_header = gelf_getphdr(elf_handle, i, &ph_mem); - if (program_header && program_header->p_type == PT_LOAD) - { - if (!found_loaded_segment) - { - result = program_header->p_vaddr; - found_loaded_segment = true; - } - - if (program_header->p_vaddr < result) - // The resulting load address we want is the lowest - // load address of all the loaded segments. - result = program_header->p_vaddr; - } - } - - if (found_loaded_segment) - { - load_address = result; - return true; - } - return false; -} - /// Find the file name of the alternate debug info file. /// /// @param elf_module the elf module to consider. @@ -5282,8 +5235,8 @@ public: find_symbol_table_section() const { if (!symtab_section_) - dwarf_reader::find_symbol_table_section(elf_handle(), - const_cast(this)->symtab_section_); + const_cast(this)->symtab_section_ = + elf_helpers::find_symbol_table_section(elf_handle()); return symtab_section_; } @@ -5296,8 +5249,8 @@ public: find_opd_section() const { if (!opd_section_) - const_cast(this)->opd_section_= - find_section(elf_handle(), ".opd", SHT_PROGBITS); + const_cast(this)->opd_section_ = + elf_helpers::find_opd_section(elf_handle()); return opd_section_; } @@ -5310,39 +5263,21 @@ public: { if (!ksymtab_section_) const_cast(this)->ksymtab_section_ = - find_section(elf_handle(), "__ksymtab", SHT_PROGBITS); + elf_helpers::find_ksymtab_section(elf_handle()); return ksymtab_section_; } - /// Return the .rel{a,} section corresponding to a given section. - /// - /// @param target_section the section to search the relocation section for + /// Return the __ksymtab_gpl section of a linux kernel ELF file + /// (either a vmlinux binary or a kernel module). /// - /// @return the .rel{a,} section if found, null otherwise. + /// @return the __ksymtab_gpl section if found, nil otherwise. Elf_Scn* - find_relocation_section(Elf_Scn* target_section) const + find_ksymtab_gpl_section() const { - if (target_section) - { - // the relo section we are searching for has this index as sh_info - size_t target_index = elf_ndxscn(target_section); - - // now iterate over all the sections, look for relocation sections and - // find the one that points to the section we are searching for - 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 != SHT_RELA && header->sh_type != SHT_REL)) - continue; - - if (header->sh_info == target_index) - return section; - } - } - return NULL; + if (!ksymtab_gpl_section_) + const_cast(this)->ksymtab_gpl_section_ = + elf_helpers::find_ksymtab_gpl_section(elf_handle()); + return ksymtab_gpl_section_; } /// Return the .rel{a,}__ksymtab section of a linux kernel ELF file (either @@ -5354,25 +5289,12 @@ public: { if (!ksymtab_reloc_section_) { - const_cast(this)->ksymtab_reloc_section_ - = find_relocation_section(find_ksymtab_section()); + const_cast(this)->ksymtab_reloc_section_ = + find_relocation_section(elf_handle(), find_ksymtab_section()); } return ksymtab_reloc_section_; } - /// Return the __ksymtab_gpl section of a linux kernel ELF file - /// (either a vmlinux binary or a kernel module). - /// - /// @return the __ksymtab_gpl section if found, nil otherwise. - Elf_Scn* - find_ksymtab_gpl_section() const - { - if (!ksymtab_gpl_section_) - const_cast(this)->ksymtab_gpl_section_ = - find_section(elf_handle(), "__ksymtab_gpl", SHT_PROGBITS); - return ksymtab_gpl_section_; - } - /// Return the .rel{a,}__ksymtab_gpl section of a linux kernel ELF file /// (either a vmlinux binary or a kernel module). /// @@ -5382,8 +5304,8 @@ public: { if (!ksymtab_gpl_reloc_section_) { - const_cast(this)->ksymtab_gpl_reloc_section_ - = find_relocation_section(find_ksymtab_gpl_section()); + const_cast(this)->ksymtab_gpl_reloc_section_ = + find_relocation_section(elf_handle(), find_ksymtab_gpl_section()); } return ksymtab_gpl_reloc_section_; } diff --git a/src/abg-elf-helpers.cc b/src/abg-elf-helpers.cc index ede191014369..b77440206fb0 100644 --- a/src/abg-elf-helpers.cc +++ b/src/abg-elf-helpers.cc @@ -357,9 +357,9 @@ find_section(Elf* elf_handle, const std::string& name, Elf64_Word section_type) /// /// @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) +/// @return the symbol table section +Elf_Scn* +find_symbol_table_section(Elf* elf_handle) { Elf_Scn* section = 0, *dynsym = 0, *sym_tab = 0; while ((section = elf_nextscn(elf_handle, section)) != 0) @@ -378,12 +378,11 @@ find_symbol_table_section(Elf* elf_handle, Elf_Scn*& symtab) 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; + return sym_tab ? sym_tab : dynsym; else - symtab = dynsym ? dynsym : sym_tab; - return true; + return dynsym ? dynsym : sym_tab; } - return false; + return NULL; } /// Find the index (in the section headers table) of the symbol table @@ -402,8 +401,9 @@ find_symbol_table_section(Elf* elf_handle, Elf_Scn*& symtab) 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)) + Elf_Scn* section = find_symbol_table_section(elf_handle); + + if (!section) return false; symtab_index = elf_ndxscn(section); @@ -500,6 +500,17 @@ Elf_Scn* find_data1_section(Elf* elf_handle) {return find_section(elf_handle, ".data1", SHT_PROGBITS);} +/// Return the "Official Procedure descriptors section." This +/// section is named .opd, and is usually present only on PPC64 +/// ELFv1 binaries. +/// +/// @param elf_handle the elf handle to consider. +/// +/// @return the .opd section, if found. Return nil otherwise. +Elf_Scn* +find_opd_section(Elf* elf_handle) +{return find_section(elf_handle, ".opd", SHT_PROGBITS);} + /// Return the SHT_GNU_versym, SHT_GNU_verdef and SHT_GNU_verneed /// sections that are involved in symbol versionning. /// @@ -548,6 +559,26 @@ get_symbol_versionning_sections(Elf* elf_handle, return false; } +/// Return the __ksymtab section of a linux kernel ELF file (either +/// a vmlinux binary or a kernel module). +/// +/// @param elf_handle the elf handle to consider. +/// +/// @return the __ksymtab section if found, nil otherwise. +Elf_Scn* +find_ksymtab_section(Elf* elf_handle) +{return find_section(elf_handle, "__ksymtab", SHT_PROGBITS);} + +/// Return the __ksymtab_gpl section of a linux kernel ELF file (either +/// a vmlinux binary or a kernel module). +/// +/// @param elf_handle the elf handle to consider. +/// +/// @return the __ksymtab section if found, nil otherwise. +Elf_Scn* +find_ksymtab_gpl_section(Elf* elf_handle) +{return find_section(elf_handle, "__ksymtab_gpl", SHT_PROGBITS);} + /// Find the __ksymtab_strings section of a Linux kernel binary. /// /// @param elf_handle the elf handle to use. @@ -563,6 +594,39 @@ find_ksymtab_strings_section(Elf *elf_handle) return 0; } +/// Return the .rel{a,} section corresponding to a given section. +/// +/// @param elf_handle the elf handle to consider. +/// +/// @param target_section the section to search the relocation section for +/// +/// @return the .rel{a,} section if found, null otherwise. +Elf_Scn* +find_relocation_section(Elf* elf_handle, Elf_Scn* target_section) +{ + if (target_section) + { + // the relo section we are searching for has this index as sh_info + size_t target_index = elf_ndxscn(target_section); + + // now iterate over all the sections, look for relocation sections and + // find the one that points to the section we are searching for + 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 != SHT_RELA && header->sh_type != SHT_REL)) + continue; + + if (header->sh_info == target_index) + return section; + } + } + return NULL; +} + /// Get the version definition (from the SHT_GNU_verdef section) of a /// given symbol represented by a pointer to GElf_Versym. /// @@ -797,5 +861,52 @@ is_linux_kernel(Elf *elf_handle) || is_linux_kernel_module(elf_handle)); } +/// Get the address at which a given binary is loaded in memory? +/// +/// @param elf_handle the elf handle for the binary to consider. +/// +/// @param load_address the address where the binary is loaded. This +/// is set by the function iff it returns true. +/// +/// @return true if the function could get the binary load address +/// and assign @p load_address to it. +bool +get_binary_load_address(Elf* elf_handle, GElf_Addr& load_address) +{ + GElf_Ehdr elf_header; + gelf_getehdr(elf_handle, &elf_header); + size_t num_segments = elf_header.e_phnum; + GElf_Phdr *program_header = NULL; + GElf_Addr result; + bool found_loaded_segment = false; + GElf_Phdr ph_mem; + + for (unsigned i = 0; i < num_segments; ++i) + { + program_header = gelf_getphdr(elf_handle, i, &ph_mem); + if (program_header && program_header->p_type == PT_LOAD) + { + if (!found_loaded_segment) + { + result = program_header->p_vaddr; + found_loaded_segment = true; + } + + if (program_header->p_vaddr < result) + // The resulting load address we want is the lowest + // load address of all the loaded segments. + result = program_header->p_vaddr; + } + } + + if (found_loaded_segment) + { + load_address = result; + return true; + } + return false; +} + + } // end namespace elf_helpers } // end namespace abigail diff --git a/src/abg-elf-helpers.h b/src/abg-elf-helpers.h index 7ddd887de959..8a83bb4f2e95 100644 --- a/src/abg-elf-helpers.h +++ b/src/abg-elf-helpers.h @@ -63,8 +63,8 @@ find_section(Elf* elf_handle, const std::string& name, Elf64_Word section_type); -bool -find_symbol_table_section(Elf* elf_handle, Elf_Scn*& symtab); +Elf_Scn* +find_symbol_table_section(Elf* elf_handle); bool find_symbol_table_section_index(Elf* elf_handle, size_t& symtab_index); @@ -96,15 +96,27 @@ find_data_section(Elf* elf_handle); Elf_Scn* find_data1_section(Elf* elf_handle); +Elf_Scn* +find_opd_section(Elf* elf_handle); + bool get_symbol_versionning_sections(Elf* elf_handle, Elf_Scn*& versym_section, Elf_Scn*& verdef_section, Elf_Scn*& verneed_section); +Elf_Scn* +find_ksymtab_section(Elf* elf_handle); + +Elf_Scn* +find_ksymtab_gpl_section(Elf* elf_handle); + Elf_Scn* find_ksymtab_strings_section(Elf *elf_handle); +Elf_Scn* +find_relocation_section(Elf* elf_handle, Elf_Scn* target_section); + // // Helpers for symbol versioning // @@ -137,6 +149,12 @@ is_linux_kernel_module(Elf *elf_handle); bool is_linux_kernel(Elf *elf_handle); +// +// Misc Helpers +// + +bool +get_binary_load_address(Elf* elf_handle, GElf_Addr& load_address); } // end namespace elf_helpers } // end namespace abigail From patchwork Tue Apr 21 06:35:50 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: 39114 From: maennich@google.com (Matthias Maennich) Date: Tue, 21 Apr 2020 08:35:50 +0200 Subject: [PATCH v2 7/8] abg-elf-helpers: migrate more elf helpers (architecture specific helpers) 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-8-maennich@google.com> This migrates more architecture specific helpers over to the elf-helpers. No functional change intended. * src/abg-dwarf-reader.cc(elf_architecture_is_ppc64): Move function out and adjust callers to call the migrated functions. (elf_architecture_is_big_endian): Likewise. (architecture_word_size): Likewise. (current_elf_file_is_executable): Likewise. (current_elf_file_is_dso): Likewise. * src/abg-elf-helpers.cc (architecture_is_ppc64): Add new function. (architecture_is_big_endian): Likewise. (get_architecture_word_size): Likewise. (is_executable): Likewise. (is_dso): Likewise. * src/abg-elf-helpers.h (architecture_is_ppc64): Add new declaration. (architecture_is_big_endian): Likewise. (get_architecture_word_size): Likewise. (is_executable): Likewise. (is_dso): Likewise. Reviewed-by: Giuliano Procida Signed-off-by: Matthias Maennich --- src/abg-dwarf-reader.cc | 91 ++++------------------------------------- src/abg-elf-helpers.cc | 79 +++++++++++++++++++++++++++++++++++ src/abg-elf-helpers.h | 18 ++++++++ 3 files changed, 106 insertions(+), 82 deletions(-) diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc index 56da03a60940..dc3332410b1e 100644 --- a/src/abg-dwarf-reader.cc +++ b/src/abg-dwarf-reader.cc @@ -5700,10 +5700,10 @@ public: if (!elf_handle()) return fn_desc_address; - if (!elf_architecture_is_ppc64()) + if (!architecture_is_ppc64(elf_handle())) return fn_desc_address; - bool is_big_endian = elf_architecture_is_big_endian(); + bool is_big_endian = architecture_is_big_endian(elf_handle()); Elf_Scn *opd_section = find_opd_section(); if (!opd_section) @@ -5979,7 +5979,7 @@ public: { if (!fun_entry_addr_sym_map_ && !fun_addr_sym_map_) maybe_load_symbol_maps(); - if (elf_architecture_is_ppc64()) + if (architecture_is_ppc64(elf_handle())) return fun_entry_addr_sym_map_; return fun_addr_sym_map_; } @@ -6335,79 +6335,6 @@ public: elf_architecture() const {return elf_architecture_;} - /// Return the size of a word for the current architecture. - /// @return the size of a word. - unsigned char - architecture_word_size() const - { - unsigned char word_size = 0; - GElf_Ehdr eh_mem; - GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem); - if (elf_header->e_ident[EI_CLASS] == ELFCLASS32) - word_size = 4; - else if (elf_header->e_ident[EI_CLASS] == ELFCLASS64) - word_size = 8; - else - ABG_ASSERT_NOT_REACHED; - return word_size; - } - - /// Test if the architecture of the current binary is ppc64. - /// - /// @return true iff the architecture of the current binary is ppc64. - bool - elf_architecture_is_ppc64() const - { - GElf_Ehdr eh_mem; - GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem); - - return (elf_header && elf_header->e_machine == EM_PPC64); - } - - /// Test if the endianness of the current binary is Big Endian. - /// - /// https://en.wikipedia.org/wiki/Endianness. - /// - /// @return true iff the current binary is Big Endian. - bool - elf_architecture_is_big_endian() const - { - GElf_Ehdr eh_mem; - GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem); - - bool is_big_endian = (elf_header->e_ident[EI_DATA] == ELFDATA2MSB); - - if (!is_big_endian) - ABG_ASSERT(elf_header->e_ident[EI_DATA] == ELFDATA2LSB); - - return is_big_endian; - } - - /// Test if the current elf file being read is an executable. - /// - /// @return true iff the current elf file being read is an - /// executable. - bool - current_elf_file_is_executable() const - { - GElf_Ehdr eh_mem; - GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem); - return elf_header->e_type == ET_EXEC; - } - - /// Test if the current elf file being read is a dynamic shared - /// object. - /// - /// @return true iff the current elf file being read is a - /// dynamic shared object. - bool - current_elf_file_is_dso() const - { - GElf_Ehdr eh_mem; - GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem); - return elf_header->e_type == ET_DYN; - } - /// Getter for the map of global variables symbol address -> global /// variable symbol index. /// @@ -6471,7 +6398,7 @@ public: GElf_Ehdr elf_header; ABG_ASSERT(gelf_getehdr(elf_handle(), &elf_header)); - bool is_ppc64 = elf_architecture_is_ppc64(); + bool is_ppc64 = architecture_is_ppc64(elf_handle()); for (size_t i = 0; i < nb_syms; ++i) { @@ -6688,7 +6615,7 @@ public: { Elf_Data* elf_data = elf_rawdata(section, 0); uint8_t* bytes = reinterpret_cast(elf_data->d_buf); - bool is_big_endian = elf_architecture_is_big_endian(); + bool is_big_endian = architecture_is_big_endian(elf_handle()); elf_symbol_sptr symbol; GElf_Addr symbol_address = 0; @@ -6696,7 +6623,7 @@ public: if (position_relative_relocations) symbol_value_size = sizeof(int32_t); else - symbol_value_size = architecture_word_size(); + symbol_value_size = get_architecture_word_size(elf_handle()); const int read_offset = (symbol_offset * symbol_value_size); bytes += read_offset; @@ -6886,7 +6813,7 @@ public: if (format == UNDEFINED_KSYMTAB_FORMAT) ; else if (format == PRE_V4_19_KSYMTAB_FORMAT) - result = architecture_word_size(); + result = get_architecture_word_size(elf_handle()); else if (format == V4_19_KSYMTAB_FORMAT) result = 4; else @@ -7065,7 +6992,7 @@ public: // // Lets thus walk the array of entries, and let's read just the // symbol address part of each entry. - bool is_big_endian = elf_architecture_is_big_endian(); + bool is_big_endian = architecture_is_big_endian(elf_handle()); elf_symbol_sptr symbol; unsigned char symbol_value_size = get_ksymtab_symbol_value_size(); @@ -7367,7 +7294,7 @@ public: if (!fun_addr_sym_map_) fun_addr_sym_map_.reset(new addr_elf_symbol_sptr_map_type); - if (!fun_entry_addr_sym_map_ && elf_architecture_is_ppc64()) + if (!fun_entry_addr_sym_map_ && architecture_is_ppc64(elf_handle())) fun_entry_addr_sym_map_.reset(new addr_elf_symbol_sptr_map_type); if (!var_syms_) diff --git a/src/abg-elf-helpers.cc b/src/abg-elf-helpers.cc index b77440206fb0..895feb6f7768 100644 --- a/src/abg-elf-helpers.cc +++ b/src/abg-elf-helpers.cc @@ -829,6 +829,40 @@ get_version_for_symbol(Elf* elf_handle, return false; } +/// Test if the architecture of the current binary is ppc64. +/// +/// @param elf_handle the ELF handle to consider. +/// +/// @return true iff the architecture of the current binary is ppc64. +bool +architecture_is_ppc64(Elf* elf_handle) +{ + GElf_Ehdr eh_mem; + GElf_Ehdr* elf_header = gelf_getehdr(elf_handle, &eh_mem); + return (elf_header && elf_header->e_machine == EM_PPC64); +} + +/// Test if the endianness of the current binary is Big Endian. +/// +/// https://en.wikipedia.org/wiki/Endianness. +/// +/// @param elf_handle the ELF handle to consider. +/// +/// @return true iff the current binary is Big Endian. +bool +architecture_is_big_endian(Elf* elf_handle) +{ + GElf_Ehdr elf_header; + gelf_getehdr(elf_handle, &elf_header); + + bool is_big_endian = (elf_header.e_ident[EI_DATA] == ELFDATA2MSB); + + if (!is_big_endian) + ABG_ASSERT(elf_header.e_ident[EI_DATA] == ELFDATA2LSB); + + return is_big_endian; +} + /// Test if the ELF binary denoted by a given ELF handle is a Linux /// Kernel Module. /// @@ -907,6 +941,51 @@ get_binary_load_address(Elf* elf_handle, GElf_Addr& load_address) return false; } +/// Return the size of a word for the current architecture. +/// +/// @param elf_handle the ELF handle to consider. +/// +/// @return the size of a word. +unsigned char +get_architecture_word_size(Elf* elf_handle) +{ + unsigned char word_size = 0; + GElf_Ehdr elf_header; + gelf_getehdr(elf_handle, &elf_header); + if (elf_header.e_ident[EI_CLASS] == ELFCLASS32) + word_size = 4; + else if (elf_header.e_ident[EI_CLASS] == ELFCLASS64) + word_size = 8; + else + ABG_ASSERT_NOT_REACHED; + return word_size; +} + +/// Test if the elf file being read is an executable. +/// +/// @param elf_handle the ELF handle to consider. +/// +/// @return true iff the elf file being read is an / executable. +bool +is_executable(Elf* elf_handle) +{ + GElf_Ehdr elf_header; + gelf_getehdr(elf_handle, &elf_header); + return elf_header.e_type == ET_EXEC; +} + +/// Test if the elf file being read is a dynamic shared / object. +/// +/// @param elf_handle the ELF handle to consider. +/// +/// @return true iff the elf file being read is a / dynamic shared object. +bool +is_dso(Elf* elf_handle) +{ + GElf_Ehdr elf_header; + gelf_getehdr(elf_handle, &elf_header); + return elf_header.e_type == ET_DYN; +} } // end namespace elf_helpers } // end namespace abigail diff --git a/src/abg-elf-helpers.h b/src/abg-elf-helpers.h index 8a83bb4f2e95..6eff245a6a30 100644 --- a/src/abg-elf-helpers.h +++ b/src/abg-elf-helpers.h @@ -139,6 +139,15 @@ get_version_for_symbol(Elf* elf_handle, bool get_def_version, elf_symbol::version& version); +// +// Architecture specific helpers +// +bool +architecture_is_ppc64(Elf* elf_handle); + +bool +architecture_is_big_endian(Elf* elf_handle); + // // Helpers for Linux Kernel Binaries // @@ -156,6 +165,15 @@ is_linux_kernel(Elf *elf_handle); bool get_binary_load_address(Elf* elf_handle, GElf_Addr& load_address); +unsigned char +get_architecture_word_size(Elf* elf_handle); + +bool +is_executable(Elf* elf_handle); + +bool +is_dso(Elf* elf_handle); + } // end namespace elf_helpers } // end namespace abigail From patchwork Tue Apr 21 06:35:51 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: 39115 From: maennich@google.com (Matthias Maennich) Date: Tue, 21 Apr 2020 08:35:51 +0200 Subject: [PATCH v2 8/8] abg-elf-helpers: migrate maybe_adjust_et_rel_sym_addr_to_abs_addr 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-9-maennich@google.com> Move maybe_adjust_et_rel_sym_addr_to_abs_addr to the elf-helpers. This function had two overloads GElf_Addr maybe_adjust_et_rel_sym_addr_to_abs_addr(GElf_Addr addr, Elf_Scn *section); GElf_Addr maybe_adjust_et_rel_sym_addr_to_abs_addr(GElf_Sym *sym); The former one is only ever called by the latter. Hence consolidate them into GElf_Addr maybe_adjust_et_rel_sym_addr_to_abs_addr(Elf* elf_handle, GElf_Sym* sym); to combine their functionality and preserve the outer interface. Just we add the Elf* handle argument as usual as we are out of read_context now. * src/abg-dwarf-reader.cc(maybe_adjust_et_rel_sym_addr_to_abs_addr): Move out functions (drop the wrapped overload completely). * src/abg-elf-helpers.cc(maybe_adjust_et_rel_sym_addr_to_abs_addr): New function. * src/abg-elf-helpers.h(maybe_adjust_et_rel_sym_addr_to_abs_addr): New function declaration. Reviewed-by: Giuliano Procida Signed-off-by: Matthias Maennich --- src/abg-dwarf-reader.cc | 73 ++++------------------------------------- src/abg-elf-helpers.cc | 40 ++++++++++++++++++++++ src/abg-elf-helpers.h | 3 ++ 3 files changed, 49 insertions(+), 67 deletions(-) diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc index dc3332410b1e..c65c01776398 100644 --- a/src/abg-dwarf-reader.cc +++ b/src/abg-dwarf-reader.cc @@ -6425,7 +6425,8 @@ public: { GElf_Addr symbol_value = - maybe_adjust_et_rel_sym_addr_to_abs_addr(sym); + maybe_adjust_et_rel_sym_addr_to_abs_addr(elf_handle(), + sym); addr_elf_symbol_sptr_map_type::const_iterator it = fun_addr_sym_map_->find(symbol_value); @@ -6563,7 +6564,8 @@ public: else { GElf_Addr symbol_value = - maybe_adjust_et_rel_sym_addr_to_abs_addr(sym); + maybe_adjust_et_rel_sym_addr_to_abs_addr(elf_handle(), + sym); addr_elf_symbol_sptr_map_type::const_iterator it = var_addr_sym_map_->find(symbol_value); if (it == var_addr_sym_map_->end()) @@ -7147,8 +7149,8 @@ public: // the symbol value of native_symbol is relative to the // section that symbol is defined in. We need to translate it // into an absolute (okay, binary-relative, rather) address. - GElf_Addr symbol_address = - maybe_adjust_et_rel_sym_addr_to_abs_addr (&native_symbol); + GElf_Addr symbol_address = maybe_adjust_et_rel_sym_addr_to_abs_addr( + elf_handle(), &native_symbol); address_set_sptr set; if (symbol->is_function()) @@ -7523,69 +7525,6 @@ public: return addr; } - /// Translate a section-relative symbol address (i.e, symbol value) - /// into an absolute symbol address by adding the address of the - /// section the symbol belongs to, to the address value. - /// - /// This is useful when looking at symbol values coming from - /// relocatable files (of ET_REL kind). If the binary is not - /// ET_REL, then the function does nothing and returns the input - /// address unchanged. - /// - /// @param addr the symbol address to possibly translate. - /// - /// @param section the section the symbol which value is @p addr - /// belongs to. - /// - /// @return the section-relative address, translated into an - /// absolute address, if @p section is an ET_REL binary. Otherwise, - /// return @p addr, unchanged. - GElf_Addr - maybe_adjust_et_rel_sym_addr_to_abs_addr(GElf_Addr addr, Elf_Scn *section) - { - if (!section) - return addr; - - Elf* elf = elf_handle(); - GElf_Ehdr elf_header; - - if (!gelf_getehdr(elf, &elf_header)) - return addr; - - if (elf_header.e_type != ET_REL) - return addr; - - GElf_Shdr section_header; - if (!gelf_getshdr(section, §ion_header)) - return addr; - - return addr + section_header.sh_addr; - } - - /// Translate a section-relative symbol address (i.e, symbol value) - /// into an absolute symbol address by adding the address of the - /// section the symbol belongs to, to the address value. - /// - /// This is useful when looking at symbol values coming from - /// relocatable files (of ET_REL kind). If the binary is not - /// ET_REL, then the function does nothing and returns the input - /// address unchanged. - /// - /// @param sym the symbol whose address to possibly needs to be - /// translated. - /// - /// @return the section-relative address, translated into an - /// absolute address, if @p sym is from an ET_REL binary. - /// Otherwise, return the address of @p sym, unchanged. - GElf_Addr - maybe_adjust_et_rel_sym_addr_to_abs_addr(GElf_Sym *sym) - { - Elf_Scn *symbol_section = elf_getscn(elf_handle(), sym->st_shndx); - GElf_Addr result = sym->st_value; - result = maybe_adjust_et_rel_sym_addr_to_abs_addr(result, symbol_section); - return result; - } - /// Test if a given address is in a given section. /// /// @param addr the address to consider. diff --git a/src/abg-elf-helpers.cc b/src/abg-elf-helpers.cc index 895feb6f7768..02ecbcf250ed 100644 --- a/src/abg-elf-helpers.cc +++ b/src/abg-elf-helpers.cc @@ -987,5 +987,45 @@ is_dso(Elf* elf_handle) return elf_header.e_type == ET_DYN; } +/// Translate a section-relative symbol address (i.e, symbol value) +/// into an absolute symbol address by adding the address of the +/// section the symbol belongs to, to the address value. +/// +/// This is useful when looking at symbol values coming from +/// relocatable files (of ET_REL kind). If the binary is not +/// ET_REL, then the function does nothing and returns the input +/// address unchanged. +/// +/// @param elf_handle the elf handle for the binary to consider. +/// +/// @param sym the symbol whose address to possibly needs to be +/// translated. +/// +/// @return the section-relative address, translated into an +/// absolute address, if @p sym is from an ET_REL binary. +/// Otherwise, return the address of @p sym, unchanged. +GElf_Addr +maybe_adjust_et_rel_sym_addr_to_abs_addr(Elf* elf_handle, GElf_Sym* sym) +{ + Elf_Scn* symbol_section = elf_getscn(elf_handle, sym->st_shndx); + GElf_Addr addr = sym->st_value; + + if (!symbol_section) + return addr; + + GElf_Ehdr elf_header; + if (!gelf_getehdr(elf_handle, &elf_header)) + return addr; + + if (elf_header.e_type != ET_REL) + return addr; + + GElf_Shdr section_header; + if (!gelf_getshdr(symbol_section, §ion_header)) + return addr; + + return addr + section_header.sh_addr; +} + } // end namespace elf_helpers } // end namespace abigail diff --git a/src/abg-elf-helpers.h b/src/abg-elf-helpers.h index 6eff245a6a30..647c92703dfa 100644 --- a/src/abg-elf-helpers.h +++ b/src/abg-elf-helpers.h @@ -174,6 +174,9 @@ is_executable(Elf* elf_handle); bool is_dso(Elf* elf_handle); +GElf_Addr +maybe_adjust_et_rel_sym_addr_to_abs_addr(Elf* elf_handle, GElf_Sym* sym); + } // end namespace elf_helpers } // end namespace abigail