From eeb00b60b29b38103e5f40e567a944b8ce57f5e7 Mon Sep 17 00:00:00 2001 From: Serge Lamikhov-Center Date: Fri, 11 Feb 2022 10:00:32 +0200 Subject: [PATCH] Initial attempt for lazy load - segment loading --- elfio/elfio.hpp | 24 ++++++-------- elfio/elfio_dump.hpp | 21 ++++++------ elfio/elfio_segment.hpp | 58 +++++++++++++++++++++++----------- examples/proc_mem/proc_mem.cpp | 2 +- 4 files changed, 60 insertions(+), 45 deletions(-) diff --git a/elfio/elfio.hpp b/elfio/elfio.hpp index 1be8e08..0e3c02a 100644 --- a/elfio/elfio.hpp +++ b/elfio/elfio.hpp @@ -125,7 +125,7 @@ class elfio } //------------------------------------------------------------------------------ - bool load( const std::string& file_name ) + bool load( const std::string& file_name, bool is_lazy = false ) { std::ifstream stream; stream.open( file_name.c_str(), std::ios::in | std::ios::binary ); @@ -133,11 +133,11 @@ class elfio return false; } - return load( stream ); + return load( stream, is_lazy ); } //------------------------------------------------------------------------------ - bool load( std::istream& stream ) + bool load( std::istream& stream, bool is_lazy = false ) { clean(); @@ -172,8 +172,8 @@ class elfio return false; } - bool is_still_good = load_sections( stream ); - is_still_good = is_still_good && load_segments( stream ); + load_sections( stream ); + bool is_still_good = load_segments( stream, is_lazy ); return is_still_good; } @@ -532,7 +532,7 @@ class elfio } //------------------------------------------------------------------------------ - bool load_segments( std::istream& stream ) + bool load_segments( std::istream& stream, bool is_lazy ) { unsigned char file_class = header->get_class(); Elf_Half entry_size = header->get_segment_entry_size(); @@ -562,15 +562,9 @@ class elfio return false; } - if ( !seg->load( stream, static_cast( offset ) + - static_cast( i ) * - entry_size ) || - stream.fail() ) { - delete seg; - seg = nullptr; - return false; - } - + seg->load( stream, + static_cast( offset ) + + static_cast( i ) * entry_size, is_lazy ); seg->set_index( i ); // Add sections to the segments (similar to readelfs algorithm) diff --git a/elfio/elfio_dump.hpp b/elfio/elfio_dump.hpp index 34d6fd9..c12b4f6 100644 --- a/elfio/elfio_dump.hpp +++ b/elfio/elfio_dump.hpp @@ -835,7 +835,7 @@ class dump << std::endl << " Name" << std::endl; } - for ( Elf_Xword i = 0; i < sym_no; ++i ) { + for ( Elf_Xword j = 0; j < sym_no; ++j ) { std::string name; Elf64_Addr value = 0; Elf_Xword size = 0; @@ -843,9 +843,9 @@ class dump unsigned char type = 0; Elf_Half section = 0; unsigned char other = 0; - symbols.get_symbol( i, name, value, size, bind, type, + symbols.get_symbol( j, name, value, size, bind, type, section, other ); - symbol_table( out, i, name, value, size, bind, type, + symbol_table( out, j, name, value, size, bind, type, section, reader.get_class() ); } @@ -931,8 +931,7 @@ class dump note_segment_accessor notes( reader, seg ); Elf_Word no_notes = notes.get_notes_num(); if ( no > 0 ) { - out << "Note segment (" << i << ")" - << std::endl + out << "Note segment (" << i << ")" << std::endl << " No Name Data size Description" << std::endl; for ( Elf_Word j = 0; j < no_notes; ++j ) { // For all notes @@ -993,7 +992,7 @@ class dump if ( descsz != 0 ) { for ( Elf_Word i = 0; i < descsz; ++i ) { - if ( i % 16 == 0 ) { + if ( i % 48 == 0 ) { out << std::endl << " "; } out << DUMP_HEX_FORMAT( 2 ) @@ -1012,10 +1011,10 @@ class dump out << "Section .modinfo" << std::endl; const_modinfo_section_accessor modinfo( sec ); - for ( Elf_Word i = 0; i < modinfo.get_attribute_num(); i++ ) { + for ( Elf_Word j = 0; j < modinfo.get_attribute_num(); j++ ) { std::string field; std::string value; - if ( modinfo.get_attribute( i, field, value ) ) { + if ( modinfo.get_attribute( j, field, value ) ) { out << " " << std::setw( 20 ) << field << std::setw( 0 ) << " = " << value << std::endl; } @@ -1041,12 +1040,12 @@ class dump out << "Dynamic section (" << sec->get_name() << ")" << std::endl; out << "[ Nr ] Tag Name/Value" << std::endl; - for ( Elf_Xword i = 0; i < dyn_no; ++i ) { + for ( Elf_Xword j = 0; j < dyn_no; ++j ) { Elf_Xword tag = 0; Elf_Xword value = 0; std::string str; - dynamic.get_entry( i, tag, value, str ); - dynamic_tag( out, i, tag, value, str, + dynamic.get_entry( j, tag, value, str ); + dynamic_tag( out, j, tag, value, str, reader.get_class() ); if ( DT_NULL == tag ) { break; diff --git a/elfio/elfio_segment.hpp b/elfio/elfio_segment.hpp index b8b9809..11a5966 100644 --- a/elfio/elfio_segment.hpp +++ b/elfio/elfio_segment.hpp @@ -60,11 +60,14 @@ class segment ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); ELFIO_SET_ACCESS_DECL( Elf_Half, index ); - virtual const std::vector& get_sections() const = 0; - virtual bool load( std::istream& stream, std::streampos header_offset ) = 0; + virtual const std::vector& get_sections() const = 0; + + virtual bool load( std::istream& stream, + std::streampos header_offset, + bool is_lazy = false ) = 0; virtual void save( std::ostream& stream, std::streampos header_offset, - std::streampos data_offset ) = 0; + std::streampos data_offset ) = 0; }; //------------------------------------------------------------------------------ @@ -72,10 +75,11 @@ template class segment_impl : public segment { public: //------------------------------------------------------------------------------ - segment_impl( const endianess_convertor* convertor, - const address_translator* translator ) - : index( 0 ), data( nullptr ), convertor( convertor ), - translator( translator ), stream_size( 0 ), is_offset_set( false ) + segment_impl( const endianess_convertor* convertor_, + const address_translator* translator_ ) + : pstream( nullptr ), index( 0 ), data( nullptr ), + convertor( convertor_ ), translator( translator_ ), stream_size( 0 ), + is_offset_set( false ), is_lazy( false ) { std::fill_n( reinterpret_cast( &ph ), sizeof( ph ), '\0' ); } @@ -98,7 +102,14 @@ template class segment_impl : public segment Elf_Half get_index() const override { return index; } //------------------------------------------------------------------------------ - const char* get_data() const override { return data; } + const char* get_data() const override + { + if ( is_lazy ) { + load_data(); + is_lazy = false; + } + return data; + } //------------------------------------------------------------------------------ Elf_Half add_section_index( Elf_Half sec_index, @@ -159,8 +170,13 @@ template class segment_impl : public segment void set_index( Elf_Half value ) override { index = value; } //------------------------------------------------------------------------------ - bool load( std::istream& stream, std::streampos header_offset ) override + bool load( std::istream& stream, + std::streampos header_offset, + bool is_lazy_ = false ) override { + pstream = &stream; + is_lazy = is_lazy_; + if ( translator->empty() ) { stream.seekg( 0, stream.end ); set_stream_size( size_t( stream.tellg() ) ); @@ -173,23 +189,27 @@ template class segment_impl : public segment stream.read( reinterpret_cast( &ph ), sizeof( ph ) ); is_offset_set = true; + if ( !is_lazy ) { + return load_data(); + } + + return true; + } + + bool load_data() const + { if ( PT_NULL != get_type() && 0 != get_file_size() ) { - stream.seekg( ( *translator )[( *convertor )( ph.p_offset )] ); + pstream->seekg( ( *translator )[( *convertor )( ph.p_offset )] ); Elf_Xword size = get_file_size(); - if ( size > get_stream_size() ) { + if ( size > get_stream_size() || is_lazy ) { data = nullptr; } else { data = new ( std::nothrow ) char[(size_t)size + 1]; if ( nullptr != data ) { - stream.read( data, size ); - if (stream.gcount() != size) { - delete[] data; - data = nullptr; - return false; - } + pstream->read( data, size ); data[size] = 0; } } @@ -217,14 +237,16 @@ template class segment_impl : public segment //------------------------------------------------------------------------------ private: + mutable std::istream* pstream; T ph; Elf_Half index; - char* data; + mutable char* data; std::vector sections; const endianess_convertor* convertor; const address_translator* translator; size_t stream_size; bool is_offset_set; + mutable bool is_lazy; }; } // namespace ELFIO diff --git a/examples/proc_mem/proc_mem.cpp b/examples/proc_mem/proc_mem.cpp index 96963be..3cd50f6 100644 --- a/examples/proc_mem/proc_mem.cpp +++ b/examples/proc_mem/proc_mem.cpp @@ -82,7 +82,7 @@ int main( int argc, char** argv ) elffile.set_address_translation( ranges ); // The 'load' will use the provided address translation now - if ( elffile.load( std::string( "/proc/" ) + argv[1] + "/mem" ) ) { + if ( elffile.load( std::string( "/proc/" ) + argv[1] + "/mem", true ) ) { dump::header( std::cout, elffile ); dump::segment_headers( std::cout, elffile ); dump::segment_datas( std::cout, elffile );