• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 Copyright (C) 2001-present by Serge Lamikhov-Center
3 
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22 
23 #ifndef ELFIO_SECTION_HPP
24 #define ELFIO_SECTION_HPP
25 
26 #include <string>
27 #include <iostream>
28 #include <new>
29 #include <limits>
30 
31 namespace ELFIO {
32 
33 class section
34 {
35     friend class elfio;
36 
37   public:
38     virtual ~section() = default;
39 
40     ELFIO_GET_ACCESS_DECL( Elf_Half, index );
41     ELFIO_GET_SET_ACCESS_DECL( std::string, name );
42     ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type );
43     ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, flags );
44     ELFIO_GET_SET_ACCESS_DECL( Elf_Word, info );
45     ELFIO_GET_SET_ACCESS_DECL( Elf_Word, link );
46     ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, addr_align );
47     ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, entry_size );
48     ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, address );
49     ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, size );
50     ELFIO_GET_SET_ACCESS_DECL( Elf_Word, name_string_offset );
51     ELFIO_GET_ACCESS_DECL( Elf64_Off, offset );
52 
53     virtual const char* get_data() const noexcept                           = 0;
54     virtual void   set_data( const char* raw_data, Elf_Word size ) noexcept = 0;
55     virtual void   set_data( const std::string& data ) noexcept             = 0;
56     virtual void   append_data( const char* raw_data,
57                                 Elf_Word    size ) noexcept                    = 0;
58     virtual void   append_data( const std::string& data ) noexcept          = 0;
59     virtual size_t get_stream_size() const noexcept                         = 0;
60     virtual void   set_stream_size( size_t value ) noexcept                 = 0;
61 
62   protected:
63     ELFIO_SET_ACCESS_DECL( Elf64_Off, offset );
64     ELFIO_SET_ACCESS_DECL( Elf_Half, index );
65 
66     virtual bool load( std::istream&  stream,
67                        std::streampos header_offset,
68                        bool           is_lazy ) noexcept               = 0;
69     virtual void save( std::ostream&  stream,
70                        std::streampos header_offset,
71                        std::streampos data_offset ) noexcept = 0;
72     virtual bool is_address_initialized() const noexcept     = 0;
73 };
74 
75 template <class T> class section_impl : public section
76 {
77   public:
78     //------------------------------------------------------------------------------
section_impl(const endianess_convertor * convertor,const address_translator * translator,const std::shared_ptr<compression_interface> & compression)79     section_impl( const endianess_convertor*                    convertor,
80                   const address_translator*                     translator,
81                   const std::shared_ptr<compression_interface>& compression )
82         : convertor( convertor ), translator( translator ),
83           compression( compression )
84     {
85     }
86 
87     //------------------------------------------------------------------------------
88     // Section info functions
89     ELFIO_GET_SET_ACCESS( Elf_Word, type, header.sh_type );
90     ELFIO_GET_SET_ACCESS( Elf_Xword, flags, header.sh_flags );
91     ELFIO_GET_SET_ACCESS( Elf_Xword, size, header.sh_size );
92     ELFIO_GET_SET_ACCESS( Elf_Word, link, header.sh_link );
93     ELFIO_GET_SET_ACCESS( Elf_Word, info, header.sh_info );
94     ELFIO_GET_SET_ACCESS( Elf_Xword, addr_align, header.sh_addralign );
95     ELFIO_GET_SET_ACCESS( Elf_Xword, entry_size, header.sh_entsize );
96     ELFIO_GET_SET_ACCESS( Elf_Word, name_string_offset, header.sh_name );
97     ELFIO_GET_ACCESS( Elf64_Addr, address, header.sh_addr );
98     //------------------------------------------------------------------------------
get_index() const99     Elf_Half get_index() const noexcept override { return index; }
100 
101     //------------------------------------------------------------------------------
get_name() const102     std::string get_name() const noexcept override { return name; }
103 
104     //------------------------------------------------------------------------------
set_name(const std::string & name_prm)105     void set_name( const std::string& name_prm ) noexcept override
106     {
107         this->name = name_prm;
108     }
109 
110     //------------------------------------------------------------------------------
set_address(const Elf64_Addr & value)111     void set_address( const Elf64_Addr& value ) noexcept override
112     {
113         header.sh_addr = decltype( header.sh_addr )( value );
114         header.sh_addr = ( *convertor )( header.sh_addr );
115         is_address_set = true;
116     }
117 
118     //------------------------------------------------------------------------------
is_address_initialized() const119     bool is_address_initialized() const noexcept override
120     {
121         return is_address_set;
122     }
123 
124     //------------------------------------------------------------------------------
get_data() const125     const char* get_data() const noexcept override
126     {
127         if ( is_lazy ) {
128             load_data();
129         }
130         return data.get();
131     }
132 
133     //------------------------------------------------------------------------------
set_data(const char * raw_data,Elf_Word size)134     void set_data( const char* raw_data, Elf_Word size ) noexcept override
135     {
136         if ( get_type() != SHT_NOBITS ) {
137             data = std::unique_ptr<char[]>( new ( std::nothrow ) char[size] );
138             if ( nullptr != data.get() && nullptr != raw_data ) {
139                 data_size = size;
140                 std::copy( raw_data, raw_data + size, data.get() );
141             }
142             else {
143                 data_size = 0;
144             }
145         }
146 
147         set_size( data_size );
148         if ( translator->empty() ) {
149             set_stream_size( data_size );
150         }
151     }
152 
153     //------------------------------------------------------------------------------
set_data(const std::string & str_data)154     void set_data( const std::string& str_data ) noexcept override
155     {
156         return set_data( str_data.c_str(), (Elf_Word)str_data.size() );
157     }
158 
159     //------------------------------------------------------------------------------
append_data(const char * raw_data,Elf_Word size)160     void append_data( const char* raw_data, Elf_Word size ) noexcept override
161     {
162         if ( get_type() != SHT_NOBITS ) {
163             if ( get_size() + size < data_size ) {
164                 std::copy( raw_data, raw_data + size, data.get() + get_size() );
165             }
166             else {
167                 data_size = 2 * ( data_size + size );
168                 std::unique_ptr<char[]> new_data(
169                     new ( std::nothrow ) char[data_size] );
170 
171                 if ( nullptr != new_data ) {
172                     std::copy( data.get(), data.get() + get_size(),
173                                new_data.get() );
174                     std::copy( raw_data, raw_data + size,
175                                new_data.get() + get_size() );
176                     data = std::move( new_data );
177                 }
178                 else {
179                     size = 0;
180                 }
181             }
182             set_size( get_size() + size );
183             if ( translator->empty() ) {
184                 set_stream_size( get_stream_size() + size );
185             }
186         }
187     }
188 
189     //------------------------------------------------------------------------------
append_data(const std::string & str_data)190     void append_data( const std::string& str_data ) noexcept override
191     {
192         return append_data( str_data.c_str(), (Elf_Word)str_data.size() );
193     }
194 
195     //------------------------------------------------------------------------------
get_stream_size() const196     size_t get_stream_size() const noexcept override { return stream_size; }
197 
198     //------------------------------------------------------------------------------
set_stream_size(size_t value)199     void set_stream_size( size_t value ) noexcept override
200     {
201         stream_size = value;
202     }
203 
204     //------------------------------------------------------------------------------
205   protected:
206     //------------------------------------------------------------------------------
207     ELFIO_GET_SET_ACCESS( Elf64_Off, offset, header.sh_offset );
208 
209     //------------------------------------------------------------------------------
set_index(const Elf_Half & value)210     void set_index( const Elf_Half& value ) noexcept override { index = value; }
211 
is_compressed() const212     bool is_compressed() const noexcept
213     {
214         return ( ( get_flags() & SHF_RPX_DEFLATE ) ||
215                  ( get_flags() & SHF_COMPRESSED ) ) &&
216                compression != nullptr;
217     }
218 
219     //------------------------------------------------------------------------------
load(std::istream & stream,std::streampos header_offset,bool is_lazy_)220     bool load( std::istream&  stream,
221                std::streampos header_offset,
222                bool           is_lazy_ ) noexcept override
223     {
224         pstream = &stream;
225         is_lazy = is_lazy_;
226         header  = { 0 };
227 
228         if ( translator->empty() ) {
229             stream.seekg( 0, std::istream::end );
230             set_stream_size( size_t( stream.tellg() ) );
231         }
232         else {
233             set_stream_size( std::numeric_limits<size_t>::max() );
234         }
235 
236         stream.seekg( ( *translator )[header_offset] );
237         stream.read( reinterpret_cast<char*>( &header ), sizeof( header ) );
238 
239         if ( !is_lazy || is_compressed() ) {
240 
241             bool ret = load_data();
242 
243             if ( is_compressed() ) {
244                 Elf_Xword size              = get_size();
245                 Elf_Xword uncompressed_size = 0;
246                 auto      decompressed_data = compression->inflate(
247                     data.get(), convertor, size, uncompressed_size );
248                 if ( decompressed_data != nullptr ) {
249                     set_size( uncompressed_size );
250                     data = std::move( decompressed_data );
251                 }
252             }
253 
254             return ret;
255         }
256 
257         return true;
258     }
259 
load_data() const260     bool load_data() const noexcept
261     {
262         is_lazy        = false;
263         Elf_Xword size = get_size();
264         if ( nullptr == data && SHT_NULL != get_type() &&
265              SHT_NOBITS != get_type() && size < get_stream_size() ) {
266             data.reset( new ( std::nothrow ) char[size_t( size ) + 1] );
267 
268             if ( ( 0 != size ) && ( nullptr != data ) ) {
269                 pstream->seekg(
270                     ( *translator )[( *convertor )( header.sh_offset )] );
271                 pstream->read( data.get(), size );
272                 if ( static_cast<Elf_Xword>( pstream->gcount() ) != size ) {
273                     data = nullptr;
274                     return false;
275                 }
276 
277                 // refresh size because it may have changed if we had to decompress data
278                 size = get_size();
279                 data.get()[size] =
280                     0; // Ensure data is ended with 0 to avoid oob read
281                 data_size = decltype( data_size )( size );
282             }
283             else {
284                 data_size = 0;
285             }
286         }
287 
288         return true;
289     }
290 
291     //------------------------------------------------------------------------------
save(std::ostream & stream,std::streampos header_offset,std::streampos data_offset)292     void save( std::ostream&  stream,
293                std::streampos header_offset,
294                std::streampos data_offset ) noexcept override
295     {
296         if ( 0 != get_index() ) {
297             header.sh_offset = decltype( header.sh_offset )( data_offset );
298             header.sh_offset = ( *convertor )( header.sh_offset );
299         }
300 
301         save_header( stream, header_offset );
302         if ( get_type() != SHT_NOBITS && get_type() != SHT_NULL &&
303              get_size() != 0 && data != nullptr ) {
304             save_data( stream, data_offset );
305         }
306     }
307 
308     //------------------------------------------------------------------------------
309   private:
310     //------------------------------------------------------------------------------
save_header(std::ostream & stream,std::streampos header_offset) const311     void save_header( std::ostream&  stream,
312                       std::streampos header_offset ) const noexcept
313     {
314         adjust_stream_size( stream, header_offset );
315         stream.write( reinterpret_cast<const char*>( &header ),
316                       sizeof( header ) );
317     }
318 
319     //------------------------------------------------------------------------------
save_data(std::ostream & stream,std::streampos data_offset)320     void save_data( std::ostream& stream, std::streampos data_offset ) noexcept
321     {
322         adjust_stream_size( stream, data_offset );
323 
324         if ( ( ( get_flags() & SHF_COMPRESSED ) ||
325                ( get_flags() & SHF_RPX_DEFLATE ) ) &&
326              compression != nullptr ) {
327             Elf_Xword decompressed_size = get_size();
328             Elf_Xword compressed_size   = 0;
329             auto      compressed_ptr    = compression->deflate(
330                 data.get(), convertor, decompressed_size, compressed_size );
331             stream.write( compressed_ptr.get(), compressed_size );
332         }
333         else {
334             stream.write( get_data(), get_size() );
335         }
336     }
337 
338     //------------------------------------------------------------------------------
339   private:
340     mutable std::istream*                        pstream = nullptr;
341     T                                            header  = {};
342     Elf_Half                                     index   = 0;
343     std::string                                  name;
344     mutable std::unique_ptr<char[]>              data;
345     mutable Elf_Word                             data_size      = 0;
346     const endianess_convertor*                   convertor      = nullptr;
347     const address_translator*                    translator     = nullptr;
348     const std::shared_ptr<compression_interface> compression    = nullptr;
349     bool                                         is_address_set = false;
350     size_t                                       stream_size    = 0;
351     mutable bool                                 is_lazy        = false;
352 };
353 
354 } // namespace ELFIO
355 
356 #endif // ELFIO_SECTION_HPP
357