diff --git a/.gitignore b/.gitignore index f2522ff..8c650fc 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,8 @@ tests/elf_examples/ppc-32bit-testcopy*.elf tests/elf_examples/null_section_inside_segment* tests/elf_examples/segment_containing_no_section* tests/elf_examples/test_symbols_order.elf +tests/elf_examples/zavl_gen.ko + examples/writer/hello_x86_64 examples/write_obj/hello diff --git a/elfio/elfio.hpp b/elfio/elfio.hpp index d8c2225..f260ee1 100644 --- a/elfio/elfio.hpp +++ b/elfio/elfio.hpp @@ -946,6 +946,7 @@ class elfio #include #include #include +#include #ifdef _MSC_VER #pragma warning( pop ) diff --git a/elfio/elfio_modinfo.hpp b/elfio/elfio_modinfo.hpp new file mode 100644 index 0000000..be83e05 --- /dev/null +++ b/elfio/elfio_modinfo.hpp @@ -0,0 +1,126 @@ +/* +Copyright (C) 2001-2020 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_MODINFO_HPP +#define ELFIO_MODINFO_HPP + +#include +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +template class modinfo_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + modinfo_section_accessor_template( S* section_ ) + : modinfo_section( section_ ) + { + process_section(); + } + + //------------------------------------------------------------------------------ + Elf_Word get_attribute_num() const { return content.size(); } + + //------------------------------------------------------------------------------ + bool + get_attribute( Elf_Word no, std::string& field, std::string& value ) const + { + if ( no < content.size() ) { + field = content[no].first; + value = content[no].second; + return true; + } + + return false; + } + + //------------------------------------------------------------------------------ + bool get_attribute( std::string field_name, std::string& value ) const + { + for ( auto i = content.begin(); i != content.end(); i++ ) { + if ( field_name == i->first ) { + value = i->second; + return true; + } + } + + return false; + } + + //------------------------------------------------------------------------------ + Elf_Word add_attribute( std::string field_name, std::string value ) + { + Elf_Word current_position = 0; + + if ( modinfo_section ) { + // Strings are addeded to the end of the current section data + current_position = (Elf_Word)modinfo_section->get_size(); + + std::string attribute = field_name + "=" + value; + + modinfo_section->append_data( attribute + '\0' ); + content.push_back( + std::pair( field_name, value ) ); + } + + return current_position; + } + + //------------------------------------------------------------------------------ + private: + void process_section() + { + const char* pdata = modinfo_section->get_data(); + if ( pdata ) { + ELFIO::Elf_Xword i = 0; + while ( i < modinfo_section->get_size() ) { + while ( i < modinfo_section->get_size() && !pdata[i] ) + i++; + if ( i < modinfo_section->get_size() ) { + std::string info = pdata + i; + size_t loc = info.find( '=' ); + std::pair attribute( + info.substr( 0, loc ), info.substr( loc + 1 ) ); + + content.push_back( attribute ); + + i += info.length(); + } + } + } + } + + //------------------------------------------------------------------------------ + private: + S* modinfo_section; + std::vector> content; +}; + +using modinfo_section_accessor = modinfo_section_accessor_template
; +using const_modinfo_section_accessor = + modinfo_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_MODINFO_HPP diff --git a/tests/ELFIOTest2.cpp b/tests/ELFIOTest2.cpp new file mode 100644 index 0000000..505404d --- /dev/null +++ b/tests/ELFIOTest2.cpp @@ -0,0 +1,122 @@ +#ifdef _MSC_VER +#define _SCL_SECURE_NO_WARNINGS +#define ELFIO_NO_INTTYPES +#endif + +#include +#include +using boost::test_tools::output_test_stream; + +#include + +using namespace ELFIO; + +//////////////////////////////////////////////////////////////////////////////// +BOOST_AUTO_TEST_CASE( modinfo_read ) +{ + elfio reader; + BOOST_REQUIRE_EQUAL( reader.load( "elf_examples/zavl.ko" ), true ); + + section* modinfo_sec = reader.sections[".modinfo"]; + BOOST_REQUIRE_NE( modinfo_sec, nullptr ); + + const_modinfo_section_accessor modinfo( modinfo_sec ); + BOOST_REQUIRE_EQUAL( modinfo.get_attribute_num(), 9 ); + + struct + { + std::string field; + std::string value; + } attributes[] = { { "version", "0.8.3-1ubuntu12.1" }, + { "license", "CDDL" }, + { "author", "OpenZFS on Linux" }, + { "description", "Generic AVL tree implementation" }, + { "srcversion", "98E85778E754CF75DEF9E8E" }, + { "depends", "spl" }, + { "retpoline", "Y" }, + { "name", "zavl" }, + { "vermagic", "5.4.0-42-generic SMP mod_unload " } }; + + for ( auto i = 0; i < sizeof( attributes ) / sizeof( attributes[0] ); + i++ ) { + std::string field; + std::string value; + modinfo.get_attribute( i, field, value ); + + BOOST_CHECK_EQUAL( field, attributes[i].field ); + BOOST_CHECK_EQUAL( value, attributes[i].value ); + } + + for ( auto i = 0; i < sizeof( attributes ) / sizeof( attributes[0] ); + i++ ) { + std::string field = attributes[i].field; + std::string value; + modinfo.get_attribute( field, value ); + + BOOST_CHECK_EQUAL( value, attributes[i].value ); + } +} + +//////////////////////////////////////////////////////////////////////////////// +BOOST_AUTO_TEST_CASE( modinfo_write ) +{ + elfio writer; + BOOST_REQUIRE_EQUAL( writer.load( "elf_examples/zavl.ko" ), true ); + + section* modinfo_sec = writer.sections[".modinfo"]; + BOOST_REQUIRE_NE( modinfo_sec, nullptr ); + + modinfo_section_accessor modinfo( modinfo_sec ); + BOOST_REQUIRE_EQUAL( modinfo.get_attribute_num(), 9 ); + + modinfo.add_attribute( "test1", "value1" ); + modinfo.add_attribute( "test2", "value2" ); + + BOOST_REQUIRE_EQUAL( modinfo.get_attribute_num(), 11 ); + + BOOST_REQUIRE_EQUAL( writer.save( "elf_examples/zavl_gen.ko" ), true ); + + elfio reader; + BOOST_REQUIRE_EQUAL( reader.load( "elf_examples/zavl_gen.ko" ), true ); + + modinfo_sec = reader.sections[".modinfo"]; + BOOST_REQUIRE_NE( modinfo_sec, nullptr ); + + const_modinfo_section_accessor modinfo1( modinfo_sec ); + BOOST_REQUIRE_EQUAL( modinfo1.get_attribute_num(), 11 ); + + struct + { + std::string field; + std::string value; + } attributes[] = { { "version", "0.8.3-1ubuntu12.1" }, + { "license", "CDDL" }, + { "author", "OpenZFS on Linux" }, + { "description", "Generic AVL tree implementation" }, + { "srcversion", "98E85778E754CF75DEF9E8E" }, + { "depends", "spl" }, + { "retpoline", "Y" }, + { "name", "zavl" }, + { "vermagic", "5.4.0-42-generic SMP mod_unload " }, + { "test1", "value1" }, + { "test2", "value2" } }; + + for ( auto i = 0; i < sizeof( attributes ) / sizeof( attributes[0] ); + i++ ) { + std::string field; + std::string value; + modinfo.get_attribute( i, field, value ); + + BOOST_CHECK_EQUAL( field, attributes[i].field ); + BOOST_CHECK_EQUAL( value, attributes[i].value ); + } + + for ( auto i = 0; i < sizeof( attributes ) / sizeof( attributes[0] ); + i++ ) { + std::string field = attributes[i].field; + std::string value; + modinfo.get_attribute( field, value ); + + BOOST_CHECK_EQUAL( value, attributes[i].value ); + } +} diff --git a/tests/Makefile.am b/tests/Makefile.am index 2b79b28..60bd5a2 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,5 +1,5 @@ AM_CPPFLAGS = -I$(top_srcdir)/.. bin_PROGRAMS = ELFIOTest -ELFIOTest_SOURCES = ELFIOTest.cpp ELFIOTest1.cpp +ELFIOTest_SOURCES = ELFIOTest.cpp ELFIOTest1.cpp ELFIOTest2.cpp TESTS=runELFtests diff --git a/tests/Makefile.in b/tests/Makefile.in index 66f3c02..f22720a 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -101,7 +101,8 @@ CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) -am_ELFIOTest_OBJECTS = ELFIOTest.$(OBJEXT) ELFIOTest1.$(OBJEXT) +am_ELFIOTest_OBJECTS = ELFIOTest.$(OBJEXT) ELFIOTest1.$(OBJEXT) \ + ELFIOTest2.$(OBJEXT) ELFIOTest_OBJECTS = $(am_ELFIOTest_OBJECTS) ELFIOTest_LDADD = $(LDADD) AM_V_P = $(am__v_P_@AM_V@) @@ -120,7 +121,7 @@ DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/../depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/ELFIOTest.Po \ - ./$(DEPDIR)/ELFIOTest1.Po + ./$(DEPDIR)/ELFIOTest1.Po ./$(DEPDIR)/ELFIOTest2.Po am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) @@ -472,7 +473,7 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I$(top_srcdir)/.. -ELFIOTest_SOURCES = ELFIOTest.cpp ELFIOTest1.cpp +ELFIOTest_SOURCES = ELFIOTest.cpp ELFIOTest1.cpp ELFIOTest2.cpp TESTS = runELFtests all: all-am @@ -566,6 +567,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ELFIOTest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ELFIOTest1.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ELFIOTest2.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @@ -1024,6 +1026,7 @@ distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f ./$(DEPDIR)/ELFIOTest.Po -rm -f ./$(DEPDIR)/ELFIOTest1.Po + -rm -f ./$(DEPDIR)/ELFIOTest2.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags @@ -1073,6 +1076,7 @@ maintainer-clean: maintainer-clean-am -rm -rf $(top_srcdir)/autom4te.cache -rm -f ./$(DEPDIR)/ELFIOTest.Po -rm -f ./$(DEPDIR)/ELFIOTest1.Po + -rm -f ./$(DEPDIR)/ELFIOTest2.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic diff --git a/tests/elf_examples/zavl.ko b/tests/elf_examples/zavl.ko new file mode 100644 index 0000000..a8e96b8 Binary files /dev/null and b/tests/elf_examples/zavl.ko differ