Use unique_ptr instead of raw pointers

This commit is contained in:
Serge Lamikhov-Center 2022-08-27 15:57:14 +03:00
parent a3e2a1f07f
commit af080f739e
5 changed files with 173 additions and 170 deletions

3
.vscode/launch.json vendored
View File

@ -10,8 +10,7 @@
"request": "launch",
"program": "${workspaceFolder}/build/tests/ELFIOTest",
"args": [
"-r",
"short"
"--gtest_filter=ELFIOTest.load32",
],
"stopAtEntry": false,
"cwd": "${workspaceFolder}/build/tests",

View File

@ -30,6 +30,7 @@ THE SOFTWARE.
#include <algorithm>
#include <vector>
#include <deque>
#include <memory>
#include <elfio/elf_types.hpp>
#include <elfio/elfio_version.hpp>
@ -63,19 +64,18 @@ class elfio
//------------------------------------------------------------------------------
elfio() noexcept : sections( this ), segments( this )
{
header = nullptr;
current_file_pos = 0;
create( ELFCLASS32, ELFDATA2LSB );
}
elfio( elfio&& other ) noexcept : sections( this ), segments( this )
elfio( elfio&& other ) noexcept
: sections( this ), segments( this ),
current_file_pos( other.current_file_pos )
{
header = std::move( other.header );
sections_ = std::move( other.sections_ );
segments_ = std::move( other.segments_ );
convertor = std::move( other.convertor );
addr_translator = std::move( other.addr_translator );
current_file_pos = std::move( other.current_file_pos );
header = std::move( other.header );
sections_ = std::move( other.sections_ );
segments_ = std::move( other.segments_ );
convertor = std::move( other.convertor );
addr_translator = std::move( other.addr_translator );
other.header = nullptr;
other.sections_.clear();
@ -85,16 +85,15 @@ class elfio
elfio& operator=( elfio&& other ) noexcept
{
if ( this != &other ) {
clean();
header = std::move( other.header );
sections_ = std::move( other.sections_ );
segments_ = std::move( other.segments_ );
convertor = std::move( other.convertor );
addr_translator = std::move( other.addr_translator );
current_file_pos = std::move( other.current_file_pos );
current_file_pos = other.current_file_pos;
other.header = nullptr;
other.current_file_pos = 0;
other.header = nullptr;
other.sections_.clear();
other.segments_.clear();
}
@ -105,15 +104,14 @@ class elfio
// clang-format off
elfio( const elfio& ) = delete;
elfio& operator=( const elfio& ) = delete;
~elfio() = default;
// clang-format on
//------------------------------------------------------------------------------
~elfio() { clean(); }
//------------------------------------------------------------------------------
void create( unsigned char file_class, unsigned char encoding )
{
clean();
sections_.clear();
segments_.clear();
convertor.setup( encoding );
header = create_header( file_class, encoding );
create_mandatory_sections();
@ -139,7 +137,8 @@ class elfio
//------------------------------------------------------------------------------
bool load( std::istream& stream )
{
clean();
sections_.clear();
segments_.clear();
unsigned char e_ident[EI_NIDENT] = { 0 };
// Read ELF file signature
@ -361,45 +360,30 @@ class elfio
//------------------------------------------------------------------------------
const section* find_prog_section_for_offset( Elf64_Off offset ) const
{
for ( auto* sec : sections ) {
for ( const auto& sec : sections ) {
if ( sec->get_type() == SHT_PROGBITS &&
is_offset_in_section( offset, sec ) ) {
return sec;
is_offset_in_section( offset, sec.get() ) ) {
return sec.get();
}
}
return nullptr;
}
//------------------------------------------------------------------------------
void clean()
std::unique_ptr<elf_header> create_header( unsigned char file_class,
unsigned char encoding )
{
delete header;
header = nullptr;
for ( auto* it : sections_ ) {
delete it;
}
sections_.clear();
for ( auto* it : segments_ ) {
delete it;
}
segments_.clear();
}
//------------------------------------------------------------------------------
elf_header* create_header( unsigned char file_class,
unsigned char encoding )
{
elf_header* new_header = nullptr;
std::unique_ptr<elf_header> new_header;
if ( file_class == ELFCLASS64 ) {
new_header = new elf_header_impl<Elf64_Ehdr>( &convertor, encoding,
&addr_translator );
new_header =
std::unique_ptr<elf_header>( new elf_header_impl<Elf64_Ehdr>(
&convertor, encoding, &addr_translator ) );
}
else if ( file_class == ELFCLASS32 ) {
new_header = new elf_header_impl<Elf32_Ehdr>( &convertor, encoding,
&addr_translator );
new_header =
std::unique_ptr<elf_header>( new elf_header_impl<Elf32_Ehdr>(
&convertor, encoding, &addr_translator ) );
}
else {
return nullptr;
@ -492,7 +476,6 @@ class elfio
sec->load( stream,
static_cast<std::streamoff>( offset ) +
static_cast<std::streampos>( i ) * entry_size );
sec->set_index( i );
// To mark that the section is not permitted to reassign address
// during layout calculation
sec->set_address( sec->get_address() );
@ -548,7 +531,6 @@ class elfio
for ( Elf_Half i = 0; i < num; ++i ) {
segment* seg = nullptr;
unsigned char file_class = header->get_class();
if ( file_class == ELFCLASS64 ) {
seg = new segment_impl<Elf64_Phdr>( &convertor,
@ -578,7 +560,7 @@ class elfio
Elf64_Off segEndOffset = segBaseOffset + seg->get_file_size();
Elf64_Off segVBaseAddr = seg->get_virtual_address();
Elf64_Off segVEndAddr = segVBaseAddr + seg->get_memory_size();
for ( auto* psec : sections ) {
for ( const auto& psec : sections ) {
// SHF_ALLOC sections are matched based on the virtual address
// otherwise the file offset is matched
if ( ( ( psec->get_flags() & SHF_ALLOC ) == SHF_ALLOC )
@ -606,7 +588,7 @@ class elfio
//------------------------------------------------------------------------------
bool save_sections( std::ostream& stream )
{
for ( auto* sec : sections_ ) {
for ( const auto& sec : sections_ ) {
std::streampos headerPosition =
static_cast<std::streamoff>( header->get_sections_offset() ) +
static_cast<std::streampos>(
@ -621,7 +603,7 @@ class elfio
//------------------------------------------------------------------------------
bool save_segments( std::ostream& stream )
{
for ( auto* seg : segments_ ) {
for ( const auto& seg : segments_ ) {
std::streampos headerPosition =
static_cast<std::streamoff>( header->get_segments_offset() ) +
static_cast<std::streampos>(
@ -639,7 +621,7 @@ class elfio
bool found = false;
for ( unsigned int j = 0; !found && ( j < segments.size() ); ++j ) {
for ( unsigned int k = 0;
for ( Elf_Half k = 0;
!found && ( k < segments[j]->get_sections_num() ); ++k ) {
found = segments[j]->get_section_index_at( k ) == section_index;
}
@ -649,7 +631,7 @@ class elfio
}
//------------------------------------------------------------------------------
static bool is_subsequence_of( segment* seg1, segment* seg2 )
static bool is_subsequence_of( const segment* seg1, const segment* seg2 )
{
// Return 'true' if sections of seg1 are a subset of sections in seg2
const std::vector<Elf_Half>& sections1 = seg1->get_sections();
@ -671,8 +653,9 @@ class elfio
std::deque<segment*> worklist;
res.reserve( segments.size() );
std::copy( segments_.begin(), segments_.end(),
std::back_inserter( worklist ) );
for ( const auto& seg : segments ) {
worklist.emplace_back( seg.get() );
}
// Bring the segments which start at address 0 to the front
size_t nextSlot = 0;
@ -714,7 +697,7 @@ class elfio
{
for ( unsigned int i = 0; i < sections_.size(); ++i ) {
if ( is_section_without_segment( i ) ) {
section* sec = sections_[i];
const auto& sec = sections_[i];
Elf_Xword section_align = sec->get_addr_align();
if ( section_align > 1 &&
@ -740,9 +723,9 @@ class elfio
//------------------------------------------------------------------------------
void calc_segment_alignment()
{
for ( auto* seg : segments_ ) {
for ( int i = 0; i < seg->get_sections_num(); ++i ) {
section* sect = sections_[seg->get_section_index_at( i )];
for ( const auto& seg : segments_ ) {
for ( Elf_Half i = 0; i < seg->get_sections_num(); ++i ) {
const auto& sect = sections_[seg->get_section_index_at( i )];
if ( sect->get_addr_align() > seg->get_align() ) {
seg->set_align( sect->get_addr_align() );
}
@ -798,87 +781,9 @@ class elfio
}
// Write segment's data
for ( auto j = 0; j < seg->get_sections_num(); ++j ) {
Elf_Half index = seg->get_section_index_at( j );
section* sec = sections[index];
// The NULL section is always generated
if ( SHT_NULL == sec->get_type() ) {
section_generated[index] = true;
continue;
}
Elf_Xword section_align = 0;
// Fix up the alignment
if ( !section_generated[index] &&
sec->is_address_initialized() &&
SHT_NOBITS != sec->get_type() &&
SHT_NULL != sec->get_type() && 0 != sec->get_size() ) {
// Align the sections based on the virtual addresses
// when possible (this is what matters for execution)
Elf64_Off req_offset =
sec->get_address() - seg->get_virtual_address();
Elf64_Off cur_offset = current_file_pos - seg_start_pos;
if ( req_offset < cur_offset ) {
// something has gone awfully wrong, abort!
// section_align would turn out negative, seeking backwards and overwriting previous data
return false;
}
section_align = req_offset - cur_offset;
}
else if ( !section_generated[index] &&
!sec->is_address_initialized() ) {
// If no address has been specified then only the section
// alignment constraint has to be matched
Elf_Xword align = sec->get_addr_align();
if ( align == 0 ) {
align = 1;
}
Elf64_Off error = current_file_pos % align;
section_align = ( align - error ) % align;
}
else if ( section_generated[index] ) {
// Alignment for already generated sections
section_align =
sec->get_offset() - seg_start_pos - segment_filesize;
}
// Determine the segment file and memory sizes
// Special case .tbss section (NOBITS) in non TLS segment
if ( ( ( sec->get_flags() & SHF_ALLOC ) == SHF_ALLOC ) &&
!( ( ( sec->get_flags() & SHF_TLS ) == SHF_TLS ) &&
( seg->get_type() != PT_TLS ) &&
( SHT_NOBITS == sec->get_type() ) ) ) {
segment_memory += sec->get_size() + section_align;
}
if ( SHT_NOBITS != sec->get_type() ) {
segment_filesize += sec->get_size() + section_align;
}
// Nothing to be done when generating nested segments
if ( section_generated[index] ) {
continue;
}
current_file_pos += section_align;
// Set the section addresses when missing
if ( !sec->is_address_initialized() ) {
sec->set_address( seg->get_virtual_address() +
current_file_pos - seg_start_pos );
}
if ( 0 != sec->get_index() ) {
sec->set_offset( current_file_pos );
}
if ( SHT_NOBITS != sec->get_type() ) {
current_file_pos += sec->get_size();
}
section_generated[index] = true;
if ( !write_segment_data( seg, section_generated, segment_memory,
segment_filesize, seg_start_pos ) ) {
return false;
}
seg->set_file_size( segment_filesize );
@ -907,6 +812,98 @@ class elfio
return true;
}
//------------------------------------------------------------------------------
bool write_segment_data( const segment* seg,
std::vector<bool>& section_generated,
Elf_Xword& segment_memory,
Elf_Xword& segment_filesize,
const Elf_Xword& seg_start_pos )
{
for ( Elf_Half j = 0; j < seg->get_sections_num(); ++j ) {
Elf_Half index = seg->get_section_index_at( j );
section* sec = sections[index];
// The NULL section is always generated
if ( SHT_NULL == sec->get_type() ) {
section_generated[index] = true;
continue;
}
Elf_Xword section_align = 0;
// Fix up the alignment
if ( !section_generated[index] && sec->is_address_initialized() &&
SHT_NOBITS != sec->get_type() && SHT_NULL != sec->get_type() &&
0 != sec->get_size() ) {
// Align the sections based on the virtual addresses
// when possible (this is what matters for execution)
Elf64_Off req_offset =
sec->get_address() - seg->get_virtual_address();
Elf64_Off cur_offset = current_file_pos - seg_start_pos;
if ( req_offset < cur_offset ) {
// something has gone awfully wrong, abort!
// section_align would turn out negative, seeking backwards and overwriting previous data
return false;
}
section_align = req_offset - cur_offset;
}
else if ( !section_generated[index] &&
!sec->is_address_initialized() ) {
// If no address has been specified then only the section
// alignment constraint has to be matched
Elf_Xword align = sec->get_addr_align();
if ( align == 0 ) {
align = 1;
}
Elf64_Off error = current_file_pos % align;
section_align = ( align - error ) % align;
}
else if ( section_generated[index] ) {
// Alignment for already generated sections
section_align =
sec->get_offset() - seg_start_pos - segment_filesize;
}
// Determine the segment file and memory sizes
// Special case .tbss section (NOBITS) in non TLS segment
if ( ( ( sec->get_flags() & SHF_ALLOC ) == SHF_ALLOC ) &&
!( ( ( sec->get_flags() & SHF_TLS ) == SHF_TLS ) &&
( seg->get_type() != PT_TLS ) &&
( SHT_NOBITS == sec->get_type() ) ) ) {
segment_memory += sec->get_size() + section_align;
}
if ( SHT_NOBITS != sec->get_type() ) {
segment_filesize += sec->get_size() + section_align;
}
// Nothing to be done when generating nested segments
if ( section_generated[index] ) {
continue;
}
current_file_pos += section_align;
// Set the section addresses when missing
if ( !sec->is_address_initialized() ) {
sec->set_address( seg->get_virtual_address() +
current_file_pos - seg_start_pos );
}
if ( 0 != sec->get_index() ) {
sec->set_offset( current_file_pos );
}
if ( SHT_NOBITS != sec->get_type() ) {
current_file_pos += sec->get_size();
}
section_generated[index] = true;
}
return true;
}
//------------------------------------------------------------------------------
public:
friend class Sections;
@ -928,7 +925,7 @@ class elfio
section* sec = nullptr;
if ( index < parent->sections_.size() ) {
sec = parent->sections_[index];
sec = parent->sections_[index].get();
}
return sec;
@ -939,9 +936,9 @@ class elfio
{
section* sec = nullptr;
for ( auto* it : parent->sections_ ) {
for ( const auto& it : parent->sections_ ) {
if ( it->get_name() == name ) {
sec = it;
sec = it.get();
break;
}
}
@ -956,7 +953,7 @@ class elfio
new_section->set_name( name );
Elf_Half str_index = parent->get_section_name_str_index();
section* string_table( parent->sections_[str_index] );
section* string_table( parent->sections_[str_index].get() );
string_section_accessor str_writer( string_table );
Elf_Word pos = str_writer.add_string( name );
new_section->set_name_string_offset( pos );
@ -965,25 +962,25 @@ class elfio
}
//------------------------------------------------------------------------------
std::vector<section*>::iterator begin()
std::vector<std::unique_ptr<section>>::iterator begin()
{
return parent->sections_.begin();
}
//------------------------------------------------------------------------------
std::vector<section*>::iterator end()
std::vector<std::unique_ptr<section>>::iterator end()
{
return parent->sections_.end();
}
//------------------------------------------------------------------------------
std::vector<section*>::const_iterator begin() const
std::vector<std::unique_ptr<section>>::const_iterator begin() const
{
return parent->sections_.cbegin();
}
//------------------------------------------------------------------------------
std::vector<section*>::const_iterator end() const
std::vector<std::unique_ptr<section>>::const_iterator end() const
{
return parent->sections_.cend();
}
@ -991,7 +988,8 @@ class elfio
//------------------------------------------------------------------------------
private:
elfio* parent;
} sections;
};
Sections sections;
//------------------------------------------------------------------------------
friend class Segments;
@ -1010,32 +1008,32 @@ class elfio
//------------------------------------------------------------------------------
segment* operator[]( unsigned int index ) const
{
return parent->segments_[index];
return parent->segments_[index].get();
}
//------------------------------------------------------------------------------
segment* add() { return parent->create_segment(); }
//------------------------------------------------------------------------------
std::vector<segment*>::iterator begin()
std::vector<std::unique_ptr<segment>>::iterator begin()
{
return parent->segments_.begin();
}
//------------------------------------------------------------------------------
std::vector<segment*>::iterator end()
std::vector<std::unique_ptr<segment>>::iterator end()
{
return parent->segments_.end();
}
//------------------------------------------------------------------------------
std::vector<segment*>::const_iterator begin() const
std::vector<std::unique_ptr<segment>>::const_iterator begin() const
{
return parent->segments_.cbegin();
}
//------------------------------------------------------------------------------
std::vector<segment*>::const_iterator end() const
std::vector<std::unique_ptr<segment>>::const_iterator end() const
{
return parent->segments_.cend();
}
@ -1043,17 +1041,18 @@ class elfio
//------------------------------------------------------------------------------
private:
elfio* parent;
} segments;
};
Segments segments;
//------------------------------------------------------------------------------
private:
elf_header* header;
std::vector<section*> sections_;
std::vector<segment*> segments_;
endianess_convertor convertor;
address_translator addr_translator;
std::unique_ptr<elf_header> header = nullptr;
std::vector<std::unique_ptr<section>> sections_;
std::vector<std::unique_ptr<segment>> segments_;
endianess_convertor convertor;
address_translator addr_translator;
Elf_Xword current_file_pos;
Elf_Xword current_file_pos = 0;
};
} // namespace ELFIO

View File

@ -108,7 +108,7 @@ template <class T> class section_impl : public section
std::string get_name() const override { return name; }
//------------------------------------------------------------------------------
void set_name( std::string name ) override { this->name = name; }
void set_name( std::string name_prm ) override { this->name = name_prm; }
//------------------------------------------------------------------------------
void set_address( Elf64_Addr value ) override
@ -207,7 +207,7 @@ template <class T> class section_impl : public section
'\0' );
if ( translator->empty() ) {
stream.seekg( 0, stream.end );
stream.seekg( 0, std::istream::end );
set_stream_size( size_t( stream.tellg() ) );
}
else {

View File

@ -51,7 +51,7 @@ using namespace ELFIO;
void overwrite_data( const std::string& filename,
Elf64_Off offset,
std::string& str )
const std::string& str )
{
std::ofstream file( filename,
std::ios::in | std::ios::out | std::ios::binary );
@ -92,12 +92,11 @@ int main( int argc, char** argv )
return 1;
}
for ( auto section = reader.sections.begin();
section != reader.sections.end(); ++section ) {
if ( ( *section )->get_type() == SHT_STRTAB &&
std::string( ( *section )->get_name() ) ==
for ( const auto& section : reader.sections ) {
if ( section->get_type() == SHT_STRTAB &&
std::string( section->get_name() ) ==
std::string( ".strtab" ) ) {
process_string_table( *section, filename );
process_string_table( section.get(), filename );
}
}
return 0;

View File

@ -224,6 +224,12 @@ TEST( ELFIOTest, load32 )
sec = reader.sections[27];
checkSection( sec, 27, ".strtab", SHT_STRTAB, 0, 0x0, 0x259, 0, 0, 1, 0 );
for ( Elf_Half i = 0; i < reader.sections.size(); ++i )
{
sec = reader.sections[i];
EXPECT_EQ( sec->get_index(), i );
}
const section* sec1 = reader.sections[".strtab"];
EXPECT_EQ( sec->get_index(), sec1->get_index() );