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