Lazy load segment data - load data upon request

This commit is contained in:
Serge Lamikhov-Center 2022-11-11 17:29:11 +02:00
commit ad8b641f96
3 changed files with 50 additions and 24 deletions

View File

@ -138,7 +138,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 );
@ -146,11 +146,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 )
{
sections_.clear();
segments_.clear();
@ -186,8 +186,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;
}
@ -535,7 +535,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();
@ -567,7 +567,7 @@ class elfio
if ( !seg->load( stream, static_cast<std::streamoff>( offset ) +
static_cast<std::streampos>( i ) *
entry_size ) ||
entry_size, is_lazy ) ||
stream.fail() ) {
segments_.pop_back();
return false;

View File

@ -60,11 +60,14 @@ class segment
ELFIO_SET_ACCESS_DECL( Elf64_Off, offset );
ELFIO_SET_ACCESS_DECL( Elf_Half, index );
virtual const std::vector<Elf_Half>& get_sections() const = 0;
virtual bool load( std::istream& stream, std::streampos header_offset ) = 0;
virtual const std::vector<Elf_Half>& 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;
};
//------------------------------------------------------------------------------
@ -93,7 +96,14 @@ template <class T> class segment_impl : public segment
Elf_Half get_index() const override { return index; }
//------------------------------------------------------------------------------
const char* get_data() const override { return data.get(); }
const char* get_data() const override
{
if ( is_lazy ) {
load_data();
is_lazy = false;
}
return data.get();
}
//------------------------------------------------------------------------------
Elf_Half add_section_index( Elf_Half sec_index,
@ -154,8 +164,13 @@ template <class T> class segment_impl : public segment
void set_index( const 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, std::istream::end );
set_stream_size( size_t( stream.tellg() ) );
@ -168,20 +183,29 @@ template <class T> class segment_impl : public segment
stream.read( reinterpret_cast<char*>( &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() ) {
return true;
}
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.reset( new ( std::nothrow ) char[(size_t)size + 1] );
if ( nullptr != data.get() && stream.read( data.get(), size ) ) {
if ( nullptr != data.get() && pstream->read( data.get(), size ) ) {
data.get()[size] = 0;
}
else {
@ -212,14 +236,16 @@ template <class T> class segment_impl : public segment
//------------------------------------------------------------------------------
private:
T ph = { 0 };
Elf_Half index = 0;
std::unique_ptr<char[]> data;
std::vector<Elf_Half> sections;
const endianess_convertor* convertor = nullptr;
const address_translator* translator = nullptr;
size_t stream_size = 0;
bool is_offset_set = false;
mutable std::istream* pstream = nullptr;
T ph = { 0 };
Elf_Half index = 0;
mutable std::unique_ptr<char[]> data;
std::vector<Elf_Half> sections;
const endianess_convertor* convertor = nullptr;
const address_translator* translator = nullptr;
size_t stream_size = 0;
bool is_offset_set = false;
mutable bool is_lazy = false;
};
} // namespace ELFIO

View File

@ -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 );