• 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                                   = 0;
54     virtual void        set_data( const char* raw_data, Elf_Word size )    = 0;
55     virtual void        set_data( const std::string& data )                = 0;
56     virtual void        append_data( const char* raw_data, Elf_Word size ) = 0;
57     virtual void        append_data( const std::string& data )             = 0;
58     virtual void
59     insert_data( Elf_Xword pos, const char* raw_data, Elf_Word size )    = 0;
60     virtual void   insert_data( Elf_Xword pos, const std::string& data ) = 0;
61     virtual size_t get_stream_size() const                               = 0;
62     virtual void   set_stream_size( size_t value )                       = 0;
63 
64   protected:
65     ELFIO_SET_ACCESS_DECL( Elf64_Off, offset );
66     ELFIO_SET_ACCESS_DECL( Elf_Half, index );
67 
68     virtual bool load( std::istream&  stream,
69                        std::streampos header_offset,
70                        bool           is_lazy )               = 0;
71     virtual void save( std::ostream&  stream,
72                        std::streampos header_offset,
73                        std::streampos data_offset ) = 0;
74     virtual bool is_address_initialized() const     = 0;
75 };
76 
77 template <class T> class section_impl : public section
78 {
79   public:
80     //------------------------------------------------------------------------------
section_impl(const endianess_convertor * convertor,const address_translator * translator,const std::shared_ptr<compression_interface> & compression)81     section_impl( const endianess_convertor*                    convertor,
82                   const address_translator*                     translator,
83                   const std::shared_ptr<compression_interface>& compression )
84         : convertor( convertor ), translator( translator ),
85           compression( compression )
86     {
87     }
88 
89     //------------------------------------------------------------------------------
90     // Section info functions
91     ELFIO_GET_SET_ACCESS( Elf_Word, type, header.sh_type );
92     ELFIO_GET_SET_ACCESS( Elf_Xword, flags, header.sh_flags );
93     ELFIO_GET_SET_ACCESS( Elf_Xword, size, header.sh_size );
94     ELFIO_GET_SET_ACCESS( Elf_Word, link, header.sh_link );
95     ELFIO_GET_SET_ACCESS( Elf_Word, info, header.sh_info );
96     ELFIO_GET_SET_ACCESS( Elf_Xword, addr_align, header.sh_addralign );
97     ELFIO_GET_SET_ACCESS( Elf_Xword, entry_size, header.sh_entsize );
98     ELFIO_GET_SET_ACCESS( Elf_Word, name_string_offset, header.sh_name );
99     ELFIO_GET_ACCESS( Elf64_Addr, address, header.sh_addr );
100     //------------------------------------------------------------------------------
get_index() const101     Elf_Half get_index() const override { return index; }
102 
103     //------------------------------------------------------------------------------
get_name() const104     std::string get_name() const override { return name; }
105 
106     //------------------------------------------------------------------------------
set_name(const std::string & name_prm)107     void set_name( const std::string& name_prm ) override
108     {
109         this->name = name_prm;
110     }
111 
112     //------------------------------------------------------------------------------
set_address(const Elf64_Addr & value)113     void set_address( const Elf64_Addr& value ) override
114     {
115         header.sh_addr = decltype( header.sh_addr )( value );
116         header.sh_addr = ( *convertor )( header.sh_addr );
117         is_address_set = true;
118     }
119 
120     //------------------------------------------------------------------------------
is_address_initialized() const121     bool is_address_initialized() const override { return is_address_set; }
122 
123     //------------------------------------------------------------------------------
get_data() const124     const char* get_data() const override
125     {
126         if ( is_lazy ) {
127             load_data();
128         }
129         return data.get();
130     }
131 
132     //------------------------------------------------------------------------------
set_data(const char * raw_data,Elf_Word size)133     void set_data( const char* raw_data, Elf_Word size ) override
134     {
135         if ( get_type() != SHT_NOBITS ) {
136             data = std::unique_ptr<char[]>( new ( std::nothrow ) char[size] );
137             if ( nullptr != data.get() && nullptr != raw_data ) {
138                 data_size = size;
139                 std::copy( raw_data, raw_data + size, data.get() );
140             }
141             else {
142                 data_size = 0;
143             }
144         }
145 
146         set_size( data_size );
147         if ( translator->empty() ) {
148             set_stream_size( data_size );
149         }
150     }
151 
152     //------------------------------------------------------------------------------
set_data(const std::string & str_data)153     void set_data( const std::string& str_data ) override
154     {
155         return set_data( str_data.c_str(), (Elf_Word)str_data.size() );
156     }
157 
158     //------------------------------------------------------------------------------
append_data(const char * raw_data,Elf_Word size)159     void append_data( const char* raw_data, Elf_Word size ) override
160     {
161         insert_data( get_size(), raw_data, size );
162     }
163 
164     //------------------------------------------------------------------------------
append_data(const std::string & str_data)165     void append_data( const std::string& str_data ) override
166     {
167         return append_data( str_data.c_str(), (Elf_Word)str_data.size() );
168     }
169 
170     //------------------------------------------------------------------------------
171     void
insert_data(Elf_Xword pos,const char * raw_data,Elf_Word size)172     insert_data( Elf_Xword pos, const char* raw_data, Elf_Word size ) override
173     {
174         if ( get_type() != SHT_NOBITS ) {
175             if ( get_size() + size < data_size ) {
176                 char* d = data.get();
177                 std::copy_backward( d + pos, d + get_size(),
178                                     d + get_size() + size );
179                 std::copy( raw_data, raw_data + size, d + pos );
180             }
181             else {
182                 data_size = 2 * ( data_size + size );
183                 std::unique_ptr<char[]> new_data(
184                     new ( std::nothrow ) char[data_size] );
185 
186                 if ( nullptr != new_data ) {
187                     char* d = data.get();
188                     std::copy( d, d + pos, new_data.get() );
189                     std::copy( raw_data, raw_data + size,
190                                new_data.get() + pos );
191                     std::copy( d + pos, d + get_size(),
192                                new_data.get() + pos + size );
193                     data = std::move( new_data );
194                 }
195                 else {
196                     size = 0;
197                 }
198             }
199             set_size( get_size() + size );
200             if ( translator->empty() ) {
201                 set_stream_size( get_stream_size() + size );
202             }
203         }
204     }
205 
206     //------------------------------------------------------------------------------
insert_data(Elf_Xword pos,const std::string & str_data)207     void insert_data( Elf_Xword pos, const std::string& str_data ) override
208     {
209         return insert_data( pos, str_data.c_str(), (Elf_Word)str_data.size() );
210     }
211 
get_stream_size() const212     size_t get_stream_size() const override { return stream_size; }
213 
214     //------------------------------------------------------------------------------
set_stream_size(size_t value)215     void set_stream_size( size_t value ) override { stream_size = value; }
216 
217     //------------------------------------------------------------------------------
218   protected:
219     //------------------------------------------------------------------------------
220     ELFIO_GET_SET_ACCESS( Elf64_Off, offset, header.sh_offset );
221 
222     //------------------------------------------------------------------------------
set_index(const Elf_Half & value)223     void set_index( const Elf_Half& value ) override { index = value; }
224 
is_compressed() const225     bool is_compressed() const
226     {
227         return ( ( get_flags() & SHF_RPX_DEFLATE ) ||
228                  ( get_flags() & SHF_COMPRESSED ) ) &&
229                compression != nullptr;
230     }
231 
232     //------------------------------------------------------------------------------
load(std::istream & stream,std::streampos header_offset,bool is_lazy_)233     bool load( std::istream&  stream,
234                std::streampos header_offset,
235                bool           is_lazy_ ) override
236     {
237         pstream = &stream;
238         is_lazy = is_lazy_;
239 
240         if ( translator->empty() ) {
241             stream.seekg( 0, std::istream::end );
242             set_stream_size( size_t( stream.tellg() ) );
243         }
244         else {
245             set_stream_size( std::numeric_limits<size_t>::max() );
246         }
247 
248         stream.seekg( ( *translator )[header_offset] );
249         stream.read( reinterpret_cast<char*>( &header ), sizeof( header ) );
250 
251         if ( !is_lazy || is_compressed() ) {
252 
253             bool ret = load_data();
254 
255             if ( is_compressed() ) {
256                 Elf_Xword size              = get_size();
257                 Elf_Xword uncompressed_size = 0;
258                 auto      decompressed_data = compression->inflate(
259                          data.get(), convertor, size, uncompressed_size );
260                 if ( decompressed_data != nullptr ) {
261                     set_size( uncompressed_size );
262                     data = std::move( decompressed_data );
263                 }
264             }
265 
266             return ret;
267         }
268 
269         return true;
270     }
271 
load_data() const272     bool load_data() const
273     {
274         is_lazy        = false;
275         Elf_Xword size = get_size();
276         if ( nullptr == data && SHT_NULL != get_type() &&
277              SHT_NOBITS != get_type() && size < get_stream_size() ) {
278             data.reset( new ( std::nothrow ) char[size_t( size ) + 1] );
279 
280             if ( ( 0 != size ) && ( nullptr != data ) ) {
281                 pstream->seekg(
282                     ( *translator )[( *convertor )( header.sh_offset )] );
283                 pstream->read( data.get(), size );
284                 if ( static_cast<Elf_Xword>( pstream->gcount() ) != size ) {
285                     data = nullptr;
286                     return false;
287                 }
288 
289                 // refresh size because it may have changed if we had to decompress data
290                 size = get_size();
291                 data.get()[size] =
292                     0; // Ensure data is ended with 0 to avoid oob read
293                 data_size = decltype( data_size )( size );
294             }
295             else {
296                 data_size = 0;
297             }
298         }
299 
300         return true;
301     }
302 
303     //------------------------------------------------------------------------------
save(std::ostream & stream,std::streampos header_offset,std::streampos data_offset)304     void save( std::ostream&  stream,
305                std::streampos header_offset,
306                std::streampos data_offset ) override
307     {
308         if ( 0 != get_index() ) {
309             header.sh_offset = decltype( header.sh_offset )( data_offset );
310             header.sh_offset = ( *convertor )( header.sh_offset );
311         }
312 
313         save_header( stream, header_offset );
314         if ( get_type() != SHT_NOBITS && get_type() != SHT_NULL &&
315              get_size() != 0 && data != nullptr ) {
316             save_data( stream, data_offset );
317         }
318     }
319 
320     //------------------------------------------------------------------------------
321   private:
322     //------------------------------------------------------------------------------
save_header(std::ostream & stream,std::streampos header_offset) const323     void save_header( std::ostream& stream, std::streampos header_offset ) const
324     {
325         adjust_stream_size( stream, header_offset );
326         stream.write( reinterpret_cast<const char*>( &header ),
327                       sizeof( header ) );
328     }
329 
330     //------------------------------------------------------------------------------
save_data(std::ostream & stream,std::streampos data_offset)331     void save_data( std::ostream& stream, std::streampos data_offset )
332     {
333         adjust_stream_size( stream, data_offset );
334 
335         if ( ( ( get_flags() & SHF_COMPRESSED ) ||
336                ( get_flags() & SHF_RPX_DEFLATE ) ) &&
337              compression != nullptr ) {
338             Elf_Xword decompressed_size = get_size();
339             Elf_Xword compressed_size   = 0;
340             auto      compressed_ptr    = compression->deflate(
341                         data.get(), convertor, decompressed_size, compressed_size );
342             stream.write( compressed_ptr.get(), compressed_size );
343         }
344         else {
345             stream.write( get_data(), get_size() );
346         }
347     }
348 
349     //------------------------------------------------------------------------------
350   private:
351     mutable std::istream*                        pstream = nullptr;
352     T                                            header  = {};
353     Elf_Half                                     index   = 0;
354     std::string                                  name;
355     mutable std::unique_ptr<char[]>              data;
356     mutable Elf_Word                             data_size      = 0;
357     const endianess_convertor*                   convertor      = nullptr;
358     const address_translator*                    translator     = nullptr;
359     const std::shared_ptr<compression_interface> compression    = nullptr;
360     bool                                         is_address_set = false;
361     size_t                                       stream_size    = 0;
362     mutable bool                                 is_lazy        = false;
363 };
364 
365 } // namespace ELFIO
366 
367 #endif // ELFIO_SECTION_HPP
368