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