From 7ba15e054941f1039e9d0936c385d6e2de1a1694 Mon Sep 17 00:00:00 2001 From: Serge Lamikhov-Center Date: Wed, 1 Dec 2021 17:10:22 +0200 Subject: [PATCH] Version Requirements accessor (reader) was added --- elfio/elf_types.hpp | 21 +++++- elfio/elfio.hpp | 1 + elfio/elfio_versym.hpp | 153 +++++++++++++++++++++++++++++++++++++++++ tests/ELFIOTest2.cpp | 76 ++++++++++++-------- 4 files changed, 220 insertions(+), 31 deletions(-) create mode 100644 elfio/elfio_versym.hpp diff --git a/elfio/elf_types.hpp b/elfio/elf_types.hpp index e667260..68248d8 100644 --- a/elfio/elf_types.hpp +++ b/elfio/elf_types.hpp @@ -550,7 +550,6 @@ constexpr unsigned char STB_MULTIDEF = 13; constexpr unsigned char STB_LOPROC = 13; constexpr unsigned char STB_HIPROC = 15; - // Values of note segment descriptor types for core files constexpr Elf_Word NT_PRSTATUS = 1; // Contains copy of prstatus struct constexpr Elf_Word NT_FPREGSET = 2; // Contains copy of fpregset struct @@ -568,7 +567,7 @@ constexpr Elf_Word NT_LWPSTATUS = 16; // Has a struct lwpstatus_t constexpr Elf_Word NT_LWPSINFO = 17; // Has a struct lwpsinfo_t constexpr Elf_Word NT_WIN32PSTATUS = 18; // Has a struct win32_pstatus -// clang-format off +// clang-format off // Note name must be "LINUX" constexpr Elf_Word NT_PRXFPREG = 0x46e62b7f; // Contains a user_xfpregs_struct; @@ -1056,6 +1055,24 @@ struct Elf64_Dyn } d_un; }; +struct Elfxx_Verneed +{ + Elf_Half vn_version; + Elf_Half vn_cnt; + Elf_Word vn_file; + Elf_Word vn_aux; + Elf_Word vn_next; +}; + +struct Elfxx_Vernaux +{ + Elf_Word vna_hash; + Elf_Half vna_flags; + Elf_Half vna_other; + Elf_Word vna_name; + Elf_Word vna_next; +}; + #ifdef __cplusplus } // namespace ELFIO #endif diff --git a/elfio/elfio.hpp b/elfio/elfio.hpp index f0064e9..9dcc05a 100644 --- a/elfio/elfio.hpp +++ b/elfio/elfio.hpp @@ -1050,6 +1050,7 @@ class elfio #include #include #include +#include #ifdef _MSC_VER #pragma warning( pop ) diff --git a/elfio/elfio_versym.hpp b/elfio/elfio_versym.hpp new file mode 100644 index 0000000..f073b6c --- /dev/null +++ b/elfio/elfio_versym.hpp @@ -0,0 +1,153 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_VERSYM_HPP +#define ELFIO_VERSYM_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +template class versym_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + versym_section_accessor_template( S* section ) : versym_section( section ) + { + if ( section ) { + entries_num = section->get_size() / sizeof( Elf_Half ); + } + } + + //------------------------------------------------------------------------------ + Elf_Word get_entries_num() const + { + if ( versym_section ) { + return entries_num; + } + return 0; + } + + //------------------------------------------------------------------------------ + bool get_entry( Elf_Word no, Elf_Half& value ) const + { + if ( versym_section && ( no < get_entries_num() ) ) { + value = ( (Elf_Half*)versym_section->get_data() )[no]; + return true; + } + + return false; + } + + //------------------------------------------------------------------------------ + private: + S* versym_section; + Elf_Word entries_num; +}; + +using versym_section_accessor = versym_section_accessor_template
; +using const_versym_section_accessor = + versym_section_accessor_template; + +//------------------------------------------------------------------------------ +template class versym_r_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + versym_r_section_accessor_template( const elfio& elf_file, + S* versym_r_section ) + : elf_file( elf_file ), versym_r_section( versym_r_section ), + entries_num( 0 ) + { + // Find .dynamic section + const section* dynamic_section = elf_file.sections[".dynamic"]; + + if ( dynamic_section == nullptr ) { + return; + } + + const_dynamic_section_accessor dynamic_section_acc( elf_file, + dynamic_section ); + Elf_Xword dyn_sec_num = dynamic_section_acc.get_entries_num(); + for ( Elf_Xword i = 0; i < dyn_sec_num; ++i ) { + Elf_Xword tag; + Elf_Xword value; + std::string str; + + if ( dynamic_section_acc.get_entry( i, tag, value, str ) && + tag == DT_VERNEEDNUM ) { + entries_num = value; + break; + } + } + } + + //------------------------------------------------------------------------------ + Elf_Word get_entries_num() const { return entries_num; } + + //------------------------------------------------------------------------------ + bool get_entry( Elf_Word no, + Elf_Half& version, + std::string& file_name, + Elf_Word& hash, + Elf_Half& flags, + Elf_Half& other, + std::string& dep_name ) const + { + if ( versym_r_section == nullptr || ( no >= get_entries_num() ) ) { + return false; + } + + const_string_section_accessor string_section_acc( + elf_file.sections[versym_r_section->get_link()] ); + + Elfxx_Verneed* verneed = (Elfxx_Verneed*)versym_r_section->get_data(); + Elfxx_Vernaux* veraux = + (Elfxx_Vernaux*)( (char*)verneed + verneed->vn_aux ); + for ( Elf_Word i = 0; i < no; ++i ) { + verneed = (Elfxx_Verneed*)( (char*)verneed + verneed->vn_next ); + veraux = (Elfxx_Vernaux*)( (char*)verneed + verneed->vn_aux ); + } + + version = verneed->vn_version; + file_name = string_section_acc.get_string( verneed->vn_file ); + hash = veraux->vna_hash; + flags = veraux->vna_flags; + other = veraux->vna_other; + dep_name = string_section_acc.get_string( veraux->vna_name ); + + return true; + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* versym_r_section; + Elf_Word entries_num; +}; + +using versym_r_section_accessor = versym_r_section_accessor_template
; +using const_versym_r_section_accessor = + versym_r_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_VERSYM_HPP diff --git a/tests/ELFIOTest2.cpp b/tests/ELFIOTest2.cpp index 7e7ecab..19d3454 100644 --- a/tests/ELFIOTest2.cpp +++ b/tests/ELFIOTest2.cpp @@ -364,46 +364,64 @@ BOOST_AUTO_TEST_CASE( gnu_version_64_le ) BOOST_REQUIRE_EQUAL( reader.load( "elf_examples/hello_64" ), true ); - std::string name; - Elf64_Addr value; - Elf_Xword size; - unsigned char bind; - unsigned char type; - Elf_Half section_index; - unsigned char other; - section* symsec = reader.sections[".dynsym"]; - const_symbol_section_accessor dynsym( reader, symsec ); + std::string name; + Elf64_Addr value; + Elf_Xword size; + unsigned char bind; + unsigned char type; + Elf_Half section_index; + unsigned char other; - section* versec = reader.sections[".gnu.version"]; - const_array_section_accessor vers( reader, versec ); + section* dynsym = reader.sections[".dynsym"]; + const_symbol_section_accessor dynsym_acc( reader, dynsym ); - section* verneed = reader.sections[".gnu.version_r"]; - const_array_section_accessor vern( reader, verneed ); + section* gnu_version = reader.sections[".gnu.version"]; + const_versym_section_accessor gnu_version_arr( gnu_version ); + + section* gnu_version_r = reader.sections[".gnu.version_r"]; + const_versym_r_section_accessor gnu_version_r_arr( reader, gnu_version_r ); section* dynstr = reader.sections[".dynstr"]; - BOOST_CHECK_EQUAL( versec->get_link(), symsec->get_index() ); - BOOST_CHECK_EQUAL( verneed->get_link(), dynstr->get_index() ); + BOOST_CHECK_EQUAL( gnu_version->get_link(), dynsym->get_index() ); + BOOST_CHECK_EQUAL( gnu_version_r->get_link(), dynstr->get_index() ); - for ( int i = 0; i < dynsym.get_symbols_num(); i++ ) { - BOOST_REQUIRE_EQUAL( dynsym.get_symbol( i, name, value, size, bind, - type, section_index, other ), + BOOST_CHECK_EQUAL( dynsym_acc.get_symbols_num(), + gnu_version_arr.get_entries_num() ); + + for ( Elf64_Word i = 0; i < dynsym_acc.get_symbols_num(); i++ ) { + BOOST_REQUIRE_EQUAL( dynsym_acc.get_symbol( i, name, value, size, bind, + type, section_index, + other ), true ); - Elf64_Addr verindex = 0; - - vers.get_entry( i, verindex ); - BOOST_CHECK_EQUAL( verindex, ( i / 2 ) * 2 ); - - const char* ptr = verneed->get_data(); - if ( verindex > 1 ) { - Elf64_Addr value = 0; - vern.get_entry( verindex * 8, value ); - // std::cout << value << std::endl; - } + Elf64_Half verindex = 0; + gnu_version_arr.get_entry( i, verindex ); + if ( i < 2 ) + BOOST_CHECK_EQUAL( 0, verindex ); + else + BOOST_CHECK_EQUAL( 2, verindex ); } + + BOOST_CHECK_EQUAL( gnu_version_r_arr.get_entries_num(), 1 ); + + Elf_Half version; + std::string file_name; + Elf_Word hash; + Elf_Half flags; + Elf_Half vna_other; + std::string dep_name; + gnu_version_r_arr.get_entry( 0, version, file_name, hash, flags, vna_other, + dep_name ); + BOOST_CHECK_EQUAL( version, 1 ); + BOOST_CHECK_EQUAL( file_name, "libc.so.6" ); + BOOST_CHECK_EQUAL( hash, 0x09691a75 ); + BOOST_CHECK_EQUAL( flags, 0 ); + BOOST_CHECK_EQUAL( vna_other, 2 ); + BOOST_CHECK_EQUAL( dep_name, "GLIBC_2.2.5" ); } + //////////////////////////////////////////////////////////////////////////////// BOOST_AUTO_TEST_CASE( move_constructor_and_assignment ) {