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