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_UTILS_HPP
24 #define ELFIO_UTILS_HPP
25
26 #include <cstdint>
27 #include <ostream>
28
29 #define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) virtual TYPE get_##NAME() const = 0
30
31 #define ELFIO_SET_ACCESS_DECL( TYPE, NAME ) \
32 virtual void set_##NAME( const TYPE& value ) = 0
33
34 #define ELFIO_GET_SET_ACCESS_DECL( TYPE, NAME ) \
35 virtual TYPE get_##NAME() const = 0; \
36 virtual void set_##NAME( const TYPE& value ) = 0
37
38 #define ELFIO_GET_ACCESS( TYPE, NAME, FIELD ) \
39 TYPE get_##NAME() const override { return ( *convertor )( FIELD ); }
40
41 #define ELFIO_SET_ACCESS( TYPE, NAME, FIELD ) \
42 void set_##NAME( const TYPE& value ) override \
43 { \
44 FIELD = decltype( FIELD )( value ); \
45 FIELD = ( *convertor )( FIELD ); \
46 }
47 #define ELFIO_GET_SET_ACCESS( TYPE, NAME, FIELD ) \
48 TYPE get_##NAME() const override { return ( *convertor )( FIELD ); } \
49 void set_##NAME( const TYPE& value ) override \
50 { \
51 FIELD = decltype( FIELD )( value ); \
52 FIELD = ( *convertor )( FIELD ); \
53 }
54
55 namespace ELFIO {
56
57 //------------------------------------------------------------------------------
58 class endianess_convertor
59 {
60 public:
61 //------------------------------------------------------------------------------
setup(unsigned char elf_file_encoding)62 void setup( unsigned char elf_file_encoding )
63 {
64 need_conversion = ( elf_file_encoding != get_host_encoding() );
65 }
66
67 //------------------------------------------------------------------------------
operator ()(uint64_t value) const68 uint64_t operator()( uint64_t value ) const
69 {
70 if ( !need_conversion ) {
71 return value;
72 }
73 value = ( ( value & 0x00000000000000FFuLL ) << 56 ) |
74 ( ( value & 0x000000000000FF00uLL ) << 40 ) |
75 ( ( value & 0x0000000000FF0000uLL ) << 24 ) |
76 ( ( value & 0x00000000FF000000uLL ) << 8 ) |
77 ( ( value & 0x000000FF00000000uLL ) >> 8 ) |
78 ( ( value & 0x0000FF0000000000uLL ) >> 24 ) |
79 ( ( value & 0x00FF000000000000uLL ) >> 40 ) |
80 ( ( value & 0xFF00000000000000uLL ) >> 56 );
81
82 return value;
83 }
84
85 //------------------------------------------------------------------------------
operator ()(int64_t value) const86 int64_t operator()( int64_t value ) const
87 {
88 if ( !need_conversion ) {
89 return value;
90 }
91 return (int64_t)( *this )( (uint64_t)value );
92 }
93
94 //------------------------------------------------------------------------------
operator ()(uint32_t value) const95 uint32_t operator()( uint32_t value ) const
96 {
97 if ( !need_conversion ) {
98 return value;
99 }
100 value =
101 ( ( value & 0x000000FF ) << 24 ) | ( ( value & 0x0000FF00 ) << 8 ) |
102 ( ( value & 0x00FF0000 ) >> 8 ) | ( ( value & 0xFF000000 ) >> 24 );
103
104 return value;
105 }
106
107 //------------------------------------------------------------------------------
operator ()(int32_t value) const108 int32_t operator()( int32_t value ) const
109 {
110 if ( !need_conversion ) {
111 return value;
112 }
113 return (int32_t)( *this )( (uint32_t)value );
114 }
115
116 //------------------------------------------------------------------------------
operator ()(uint16_t value) const117 uint16_t operator()( uint16_t value ) const
118 {
119 if ( !need_conversion ) {
120 return value;
121 }
122 value =
123 (uint16_t)( ( value & 0x00FF ) << 8 ) | ( ( value & 0xFF00 ) >> 8 );
124
125 return value;
126 }
127
128 //------------------------------------------------------------------------------
operator ()(int16_t value) const129 int16_t operator()( int16_t value ) const
130 {
131 if ( !need_conversion ) {
132 return value;
133 }
134 return (int16_t)( *this )( (uint16_t)value );
135 }
136
137 //------------------------------------------------------------------------------
operator ()(int8_t value) const138 int8_t operator()( int8_t value ) const { return value; }
139
140 //------------------------------------------------------------------------------
operator ()(uint8_t value) const141 uint8_t operator()( uint8_t value ) const { return value; }
142
143 //------------------------------------------------------------------------------
144 private:
145 //------------------------------------------------------------------------------
get_host_encoding() const146 unsigned char get_host_encoding() const
147 {
148 static const int tmp = 1;
149 if ( 1 == *reinterpret_cast<const char*>( &tmp ) ) {
150 return ELFDATA2LSB;
151 }
152 else {
153 return ELFDATA2MSB;
154 }
155 }
156
157 //------------------------------------------------------------------------------
158 bool need_conversion = false;
159 };
160
161 //------------------------------------------------------------------------------
162 struct address_translation
163 {
address_translationELFIO::address_translation164 address_translation( uint64_t start, uint64_t size, uint64_t mapped_to )
165 : start( start ), size( size ), mapped_to( mapped_to ){};
166 std::streampos start;
167 std::streampos size;
168 std::streampos mapped_to;
169 };
170
171 //------------------------------------------------------------------------------
172 class address_translator
173 {
174 public:
175 //------------------------------------------------------------------------------
set_address_translation(std::vector<address_translation> & addr_trans)176 void set_address_translation( std::vector<address_translation>& addr_trans )
177 {
178 addr_translations = addr_trans;
179
180 std::sort( addr_translations.begin(), addr_translations.end(),
181 []( const address_translation& a,
182 const address_translation& b ) -> bool {
183 return a.start < b.start;
184 } );
185 }
186
187 //------------------------------------------------------------------------------
operator [](std::streampos value) const188 std::streampos operator[]( std::streampos value ) const
189 {
190 if ( addr_translations.empty() ) {
191 return value;
192 }
193
194 for ( auto& t : addr_translations ) {
195 if ( ( t.start <= value ) && ( ( value - t.start ) < t.size ) ) {
196 return value - t.start + t.mapped_to;
197 }
198 }
199
200 return value;
201 }
202
empty() const203 bool empty() const { return addr_translations.empty(); }
204
205 private:
206 std::vector<address_translation> addr_translations;
207 };
208
209 //------------------------------------------------------------------------------
elf_hash(const unsigned char * name)210 inline uint32_t elf_hash( const unsigned char* name )
211 {
212 uint32_t h = 0;
213 uint32_t g = 0;
214 while ( *name != '\0' ) {
215 h = ( h << 4 ) + *name++;
216 g = h & 0xf0000000;
217 if ( g != 0 )
218 h ^= g >> 24;
219 h &= ~g;
220 }
221 return h;
222 }
223
224 //------------------------------------------------------------------------------
elf_gnu_hash(const unsigned char * s)225 inline uint32_t elf_gnu_hash( const unsigned char* s )
226 {
227 uint32_t h = 0x1505;
228 for ( unsigned char c = *s; c != '\0'; c = *++s )
229 h = ( h << 5 ) + h + c;
230 return h;
231 }
232
233 //------------------------------------------------------------------------------
to_hex_string(uint64_t value)234 inline std::string to_hex_string( uint64_t value )
235 {
236 std::string str;
237
238 while ( value ) {
239 if ( auto digit = value & 0xF; digit < 0xA ) {
240 str = char( '0' + digit ) + str;
241 }
242 else {
243 str = char( 'A' + digit - 0xA ) + str;
244 }
245 value >>= 4;
246 }
247
248 return "0x" + str;
249 }
250
251 //------------------------------------------------------------------------------
adjust_stream_size(std::ostream & stream,std::streamsize offset)252 inline void adjust_stream_size( std::ostream& stream, std::streamsize offset )
253 {
254 stream.seekp( 0, std::ios_base::end );
255 if ( stream.tellp() < offset ) {
256 std::streamsize size = offset - stream.tellp();
257 stream.write( std::string( size_t( size ), '\0' ).c_str(), size );
258 }
259 stream.seekp( offset );
260 }
261
262 /**
263 * Consumers should write an implementation of this class and pass an instance of it to the ELFIO::elfio constructor.
264 */
265 class compression_interface
266 {
267 public:
268 virtual ~compression_interface() = default;
269 /**
270 * decompresses a compressed section
271 *
272 * @param data the buffer of compressed data
273 * @param endianness_convertor pointer to an endianness_convertor instance, used to convert numbers to/from the target endianness.
274 * @param compressed_size the size of the data buffer, in bytes
275 * @param decompressed_size a reference to a variable where the decompressed buffer size will be stored.
276 * @returns a smart pointer to the decompressed data.
277 */
278 virtual std::unique_ptr<char[]>
279 inflate( const char* data,
280 const endianess_convertor* convertor,
281 Elf_Xword compressed_size,
282 Elf_Xword& uncompressed_size ) const = 0;
283
284 /**
285 * compresses a section
286 *
287 * @param data the buffer of uncompressed data
288 * @param endianness_convertor pointer to an endianness_convertor instance, used to convert numbers to/from the target endianness.
289 * @param decompressed_size the size of the data buffer, in bytes
290 * @param compressed_size a reference to a variable where the compressed buffer size will be stored.
291 * @returns a smart pointer to the compressed data.
292 */
293 virtual std::unique_ptr<char[]>
294 deflate( const char* data,
295 const endianess_convertor* convertor,
296 Elf_Xword decompressed_size,
297 Elf_Xword& compressed_size ) const = 0;
298 };
299
300 } // namespace ELFIO
301
302 #endif // ELFIO_UTILS_HPP
303