• 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 #ifdef _MSC_VER
24 #define _SCL_SECURE_NO_WARNINGS
25 #define ELFIO_NO_INTTYPES
26 #endif
27 
28 #include <boost/test/unit_test.hpp>
29 #include <boost/test/tools/output_test_stream.hpp>
30 using boost::test_tools::output_test_stream;
31 
32 #include <elfio/elfio.hpp>
33 
34 using namespace ELFIO;
35 
36 enum Tests
37 {
38     SEG_ALIGN = 1
39 };
40 
41 ////////////////////////////////////////////////////////////////////////////////
write_obj_i386(bool is64bit)42 bool write_obj_i386( bool is64bit )
43 {
44     elfio writer;
45 
46     writer.create( is64bit ? ELFCLASS64 : ELFCLASS32, ELFDATA2LSB );
47     writer.set_type( ET_REL );
48     writer.set_os_abi( ELFOSABI_LINUX );
49     writer.set_machine( is64bit ? EM_X86_64 : EM_386 );
50 
51     // Create code section*
52     section* text_sec = writer.sections.add( ".text" );
53     text_sec->set_type( SHT_PROGBITS );
54     text_sec->set_flags( SHF_ALLOC | SHF_EXECINSTR );
55     text_sec->set_addr_align( 0x10 );
56 
57     // Add data into it
58     char text[] = {
59         '\xB8', '\x04', '\x00', '\x00', '\x00', // mov eax, 4
60         '\xBB', '\x01', '\x00', '\x00', '\x00', // mov ebx, 1
61         '\xB9', '\x00', '\x00', '\x00', '\x00', // mov ecx, msg
62         '\xBA', '\x0E', '\x00', '\x00', '\x00', // mov edx, 14
63         '\xCD', '\x80',                         // int 0x80
64         '\xB8', '\x01', '\x00', '\x00', '\x00', // mov eax, 1
65         '\xCD', '\x80'                          // int 0x80
66     };
67     text_sec->set_data( text, sizeof( text ) );
68 
69     // Create data section*
70     section* data_sec = writer.sections.add( ".data" );
71     data_sec->set_type( SHT_PROGBITS );
72     data_sec->set_flags( SHF_ALLOC | SHF_WRITE );
73     data_sec->set_addr_align( 4 );
74 
75     char data[] = {
76         '\x48', '\x65', '\x6C', '\x6C', '\x6F', // msg: db   'Hello, World!', 10
77         '\x2C', '\x20', '\x57', '\x6F', '\x72',
78         '\x6C', '\x64', '\x21', '\x0A' };
79     data_sec->set_data( data, sizeof( data ) );
80 
81     section* str_sec = writer.sections.add( ".strtab" );
82     str_sec->set_type( SHT_STRTAB );
83     str_sec->set_addr_align( 0x1 );
84 
85     string_section_accessor str_writer( str_sec );
86     Elf_Word                nStrIndex = str_writer.add_string( "msg" );
87 
88     section* sym_sec = writer.sections.add( ".symtab" );
89     sym_sec->set_type( SHT_SYMTAB );
90     sym_sec->set_info( 2 );
91     sym_sec->set_link( str_sec->get_index() );
92     sym_sec->set_addr_align( 4 );
93     sym_sec->set_entry_size( writer.get_default_entry_size( SHT_SYMTAB ) );
94 
95     symbol_section_accessor symbol_writer( writer, sym_sec );
96     Elf_Word                nSymIndex = symbol_writer.add_symbol(
97         nStrIndex, 0, 0, STB_LOCAL, STT_NOTYPE, 0, data_sec->get_index() );
98 
99     // Another way to add symbol
100     symbol_writer.add_symbol( str_writer, "_start", 0x00000000, 0, STB_WEAK,
101                               STT_FUNC, 0, text_sec->get_index() );
102 
103     // Create relocation table section*
104     section* rel_sec = writer.sections.add( ".rel.text" );
105     rel_sec->set_type( SHT_REL );
106     rel_sec->set_info( text_sec->get_index() );
107     rel_sec->set_link( sym_sec->get_index() );
108     rel_sec->set_addr_align( 4 );
109     rel_sec->set_entry_size( writer.get_default_entry_size( SHT_REL ) );
110 
111     relocation_section_accessor rel_writer( writer, rel_sec );
112     rel_writer.add_entry( 11, nSymIndex, (unsigned char)R_386_RELATIVE );
113 
114     // Another method to add the same relocation entry
115     // pRelWriter->AddEntry( pStrWriter, "msg",
116     //                       pSymWriter, 29, 0,
117     //                       ELF32_ST_INFO( STB_GLOBAL, STT_OBJECT ), 0,
118     //                       data_sec->GetIndex(),
119     //                       0, (unsigned char)R_386_RELATIVE );
120 
121     // Create note section*
122     section* note_sec = writer.sections.add( ".note" );
123     note_sec->set_type( SHT_NOTE );
124     note_sec->set_addr_align( 1 );
125 
126     // Create notes writer
127     note_section_accessor note_writer( writer, note_sec );
128     note_writer.add_note( 0x77, "Created by ELFIO", 0, 0 );
129 
130     // Create ELF file
131     writer.save( is64bit ? "elf_examples/write_obj_i386_64.o"
132                          : "elf_examples/write_obj_i386_32.o" );
133 
134     return true;
135 }
136 
137 ////////////////////////////////////////////////////////////////////////////////
write_exe_i386(const std::string & filename,bool is64bit,bool set_addr=false,Elf64_Addr addr=0)138 bool write_exe_i386( const std::string& filename,
139                      bool               is64bit,
140                      bool               set_addr = false,
141                      Elf64_Addr         addr     = 0 )
142 {
143     elfio writer;
144 
145     writer.create( is64bit ? ELFCLASS64 : ELFCLASS32, ELFDATA2LSB );
146     writer.set_os_abi( ELFOSABI_LINUX );
147     writer.set_type( ET_EXEC );
148     writer.set_machine( is64bit ? EM_X86_64 : EM_386 );
149 
150     // Create code section*
151     section* text_sec = writer.sections.add( ".text" );
152     text_sec->set_type( SHT_PROGBITS );
153     text_sec->set_flags( SHF_ALLOC | SHF_EXECINSTR );
154     text_sec->set_addr_align( 0x10 );
155     if ( set_addr ) {
156         text_sec->set_address( addr );
157     }
158 
159     // Add data into it
160     char text[] = {
161         '\xB8', '\x04', '\x00', '\x00', '\x00', // mov eax, 4
162         '\xBB', '\x01', '\x00', '\x00', '\x00', // mov ebx, 1
163         '\xB9', '\x20', '\x80', '\x04', '\x08', // mov ecx, msg
164         '\xBA', '\x0E', '\x00', '\x00', '\x00', // mov edx, 14
165         '\xCD', '\x80',                         // int 0x80
166         '\xB8', '\x01', '\x00', '\x00', '\x00', // mov eax, 1
167         '\xCD', '\x80'                          // int 0x80
168     };
169     text_sec->set_data( text, sizeof( text ) );
170 
171     segment* text_seg = writer.segments.add();
172     text_seg->set_type( PT_LOAD );
173     text_seg->set_virtual_address( 0x08048000 );
174     text_seg->set_physical_address( 0x08048000 );
175     text_seg->set_flags( PF_X | PF_R );
176     text_seg->set_align( 0x1000 );
177     text_seg->add_section_index( text_sec->get_index(),
178                                  text_sec->get_addr_align() );
179 
180     // Create data section*
181     section* data_sec = writer.sections.add( ".data" );
182     data_sec->set_type( SHT_PROGBITS );
183     data_sec->set_flags( SHF_ALLOC | SHF_WRITE );
184     data_sec->set_addr_align( 0x4 );
185 
186     char data[] = {
187         '\x48', '\x65', '\x6C', '\x6C', '\x6F', // msg: db   'Hello, World!', 10
188         '\x2C', '\x20', '\x57', '\x6F', '\x72',
189         '\x6C', '\x64', '\x21', '\x0A' };
190     data_sec->set_data( data, sizeof( data ) );
191 
192     segment* data_seg = writer.segments.add();
193     data_seg->set_type( PT_LOAD );
194     data_seg->set_virtual_address( 0x08048020 );
195     data_seg->set_physical_address( 0x08048020 );
196     data_seg->set_flags( PF_W | PF_R );
197     data_seg->set_align( 0x10 );
198     data_seg->add_section_index( data_sec->get_index(),
199                                  data_sec->get_addr_align() );
200 
201     section* note_sec = writer.sections.add( ".note" );
202     note_sec->set_type( SHT_NOTE );
203     note_sec->set_addr_align( 1 );
204     note_section_accessor note_writer( writer, note_sec );
205     note_writer.add_note( 0x01, "Created by ELFIO", 0, 0 );
206     char descr[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 };
207     note_writer.add_note( 0x01, "Never easier!", descr, sizeof( descr ) );
208 
209     // Create ELF file
210     writer.set_entry( 0x08048000 );
211 
212     writer.save( filename );
213 
214     return true;
215 }
216 
217 ////////////////////////////////////////////////////////////////////////////////
checkObjestsAreEqual(std::string file_name1,std::string file_name2)218 void checkObjestsAreEqual( std::string file_name1, std::string file_name2 )
219 {
220     elfio file1;
221     elfio file2;
222     BOOST_REQUIRE_EQUAL( file1.load( file_name1 ), true );
223     BOOST_CHECK_EQUAL( file1.save( file_name2 ), true );
224     BOOST_REQUIRE_EQUAL( file1.load( file_name1 ), true );
225     BOOST_REQUIRE_EQUAL( file2.load( file_name2 ), true );
226 
227     for ( int i = 0; i < file1.sections.size(); ++i ) {
228         BOOST_CHECK_EQUAL( file1.sections[i]->get_address(),
229                            file2.sections[i]->get_address() );
230         BOOST_CHECK_EQUAL( file1.sections[i]->get_addr_align(),
231                            file2.sections[i]->get_addr_align() );
232         BOOST_CHECK_EQUAL( file1.sections[i]->get_entry_size(),
233                            file2.sections[i]->get_entry_size() );
234         BOOST_CHECK_EQUAL( file1.sections[i]->get_flags(),
235                            file2.sections[i]->get_flags() );
236         BOOST_CHECK_EQUAL( file1.sections[i]->get_index(),
237                            file2.sections[i]->get_index() );
238         BOOST_CHECK_EQUAL( file1.sections[i]->get_info(),
239                            file2.sections[i]->get_info() );
240         BOOST_CHECK_EQUAL( file1.sections[i]->get_link(),
241                            file2.sections[i]->get_link() );
242         BOOST_CHECK_EQUAL( file1.sections[i]->get_name(),
243                            file2.sections[i]->get_name() );
244         BOOST_CHECK_EQUAL( file1.sections[i]->get_name_string_offset(),
245                            file2.sections[i]->get_name_string_offset() );
246         BOOST_CHECK_EQUAL( file1.sections[i]->get_size(),
247                            file2.sections[i]->get_size() );
248         BOOST_CHECK_EQUAL( file1.sections[i]->get_type(),
249                            file2.sections[i]->get_type() );
250 
251         if ( file1.sections[i]->get_type() == SHT_NULL ||
252              file1.sections[i]->get_type() == SHT_NOBITS ) {
253             continue;
254         }
255         BOOST_REQUIRE_NE( file1.sections[i]->get_data(), (const char*)0 );
256         BOOST_REQUIRE_NE( file2.sections[i]->get_data(), (const char*)0 );
257         std::string pdata1( file1.sections[i]->get_data(),
258                             file1.sections[i]->get_data() +
259                                 file1.sections[i]->get_size() );
260         std::string pdata2( file2.sections[i]->get_data(),
261                             file2.sections[i]->get_data() +
262                                 file2.sections[i]->get_size() );
263 
264         BOOST_CHECK_EQUAL( file1.sections[i]->get_size(),
265                            file2.sections[i]->get_size() );
266         if ( ( file2.sections[i]->get_type() != SHT_NULL ) &&
267              ( file2.sections[i]->get_type() != SHT_NOBITS ) ) {
268             BOOST_CHECK_EQUAL_COLLECTIONS( pdata1.begin(), pdata1.end(),
269                                            pdata2.begin(), pdata2.end() );
270         }
271     }
272 }
273 
274 ////////////////////////////////////////////////////////////////////////////////
checkExeAreEqual(std::string file_name1,std::string file_name2,int skipTests=0)275 void checkExeAreEqual( std::string file_name1,
276                        std::string file_name2,
277                        int         skipTests = 0 )
278 {
279     checkObjestsAreEqual( file_name1, file_name2 );
280 
281     elfio file1;
282     elfio file2;
283 
284     BOOST_REQUIRE_EQUAL( file1.load( file_name1 ), true );
285     BOOST_REQUIRE_EQUAL( file2.load( file_name2 ), true );
286 
287     for ( int i = 0; i < file1.segments.size(); ++i ) {
288         if ( !( skipTests & SEG_ALIGN ) )
289             BOOST_CHECK_EQUAL( file1.segments[i]->get_align(),
290                                file2.segments[i]->get_align() );
291         BOOST_CHECK_EQUAL( file1.segments[i]->get_file_size(),
292                            file2.segments[i]->get_file_size() );
293         BOOST_CHECK_EQUAL( file1.segments[i]->get_memory_size(),
294                            file2.segments[i]->get_memory_size() );
295         BOOST_CHECK_EQUAL( file1.segments[i]->get_type(),
296                            file2.segments[i]->get_type() );
297 
298         // skip data comparisons of the program header and of empty segments
299         if ( file1.segments[i]->get_type() == PT_PHDR ||
300              !file1.segments[i]->get_file_size() )
301             continue;
302 
303         BOOST_REQUIRE_NE( file1.segments[i]->get_data(), (const char*)0 );
304         BOOST_REQUIRE_NE( file2.segments[i]->get_data(), (const char*)0 );
305 
306         std::string pdata1( file1.segments[i]->get_data(),
307                             file1.segments[i]->get_data() +
308                                 file1.segments[i]->get_file_size() );
309         std::string pdata2( file2.segments[i]->get_data(),
310                             file2.segments[i]->get_data() +
311                                 file2.segments[i]->get_file_size() );
312 
313         // truncate the data if the header and the segment table is
314         // part of the segment
315         Elf64_Off afterPHDR =
316             file1.get_segments_offset() +
317             file1.get_segment_entry_size() * (Elf64_Off)file1.segments.size();
318         if ( file1.segments[i]->get_offset() < afterPHDR ) {
319             pdata1 = pdata1.substr( (unsigned int)afterPHDR );
320             pdata2 = pdata2.substr( (unsigned int)afterPHDR );
321         }
322 
323         BOOST_CHECK_EQUAL_COLLECTIONS( pdata1.begin(), pdata1.end(),
324                                        pdata2.begin(), pdata2.end() );
325     }
326 }
327 
328 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(write_obj_i386_32)329 BOOST_AUTO_TEST_CASE( write_obj_i386_32 )
330 {
331     BOOST_CHECK_EQUAL( true, write_obj_i386( false ) );
332     output_test_stream output( "elf_examples/write_obj_i386_32_match.o", true,
333                                false );
334     std::ifstream input( "elf_examples/write_obj_i386_32.o", std::ios::binary );
335     output << input.rdbuf();
336     BOOST_CHECK( output.match_pattern() );
337 }
338 
339 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(write_obj_i386_64)340 BOOST_AUTO_TEST_CASE( write_obj_i386_64 )
341 {
342     BOOST_CHECK_EQUAL( true, write_obj_i386( true ) );
343     output_test_stream output( "elf_examples/write_obj_i386_64_match.o", true,
344                                false );
345     std::ifstream input( "elf_examples/write_obj_i386_64.o", std::ios::binary );
346     output << input.rdbuf();
347     BOOST_CHECK( output.match_pattern() );
348 }
349 
350 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(write_exe_i386_32)351 BOOST_AUTO_TEST_CASE( write_exe_i386_32 )
352 {
353     const std::string generated_file( "elf_examples/write_exe_i386_32" );
354     const std::string reference_file( "elf_examples/write_exe_i386_32_match" );
355     BOOST_CHECK_EQUAL( true, write_exe_i386( generated_file, false ) );
356     output_test_stream output( reference_file, true, false );
357     std::ifstream      input( generated_file, std::ios::binary );
358     output << input.rdbuf();
359     BOOST_CHECK_MESSAGE( output.match_pattern(), "Comparing " + generated_file +
360                                                      " and " + reference_file );
361 }
362 
363 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(elf_object_copy_32)364 BOOST_AUTO_TEST_CASE( elf_object_copy_32 )
365 {
366     checkObjestsAreEqual( "elf_examples/hello_32.o",
367                           "elf_examples/hello_32_copy.o" );
368     checkObjestsAreEqual( "elf_examples/hello_64.o",
369                           "elf_examples/hello_64_copy.o" );
370     checkObjestsAreEqual( "elf_examples/test_ppc.o",
371                           "elf_examples/test_ppc_copy.o" );
372     checkObjestsAreEqual( "elf_examples/write_obj_i386_32.o",
373                           "elf_examples/write_obj_i386_32_copy.o" );
374     checkObjestsAreEqual( "elf_examples/write_obj_i386_64.o",
375                           "elf_examples/write_obj_i386_64_copy.o" );
376 }
377 
378 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(section_header_address_update)379 BOOST_AUTO_TEST_CASE( section_header_address_update )
380 {
381     elfio reader;
382 
383     const std::string file_w_addr( "elf_examples/write_exe_i386_32_w_addr" );
384     write_exe_i386( file_w_addr, false, true, 0x08048100 );
385     reader.load( file_w_addr );
386     section* sec = reader.sections[".text"];
387     BOOST_REQUIRE_NE( sec, (section*)0 );
388     BOOST_CHECK_EQUAL( sec->get_address(), 0x08048100 );
389 
390     const std::string file_wo_addr( "elf_examples/write_exe_i386_32_wo_addr" );
391     write_exe_i386( file_wo_addr, false, false, 0 );
392     reader.load( file_wo_addr );
393     sec = reader.sections[".text"];
394     BOOST_REQUIRE_NE( sec, (section*)0 );
395     BOOST_CHECK_EQUAL( sec->get_address(), 0x08048000 );
396 }
397 
398 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(elfio_copy)399 BOOST_AUTO_TEST_CASE( elfio_copy )
400 {
401     elfio e;
402 
403     const std::string filename(
404         "elf_examples/write_exe_i386_32_section_added" );
405     write_exe_i386( filename, false, true, 0x08048100 );
406 
407     e.load( filename );
408     Elf_Half num = e.sections.size();
409     //section* new_sec =
410     e.sections.add( "new" );
411     e.save( filename );
412     BOOST_CHECK_EQUAL( num + 1, e.sections.size() );
413 }
414 
415 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(elf_exe_copy_64)416 BOOST_AUTO_TEST_CASE( elf_exe_copy_64 )
417 {
418     checkExeAreEqual( "elf_examples/64bitLOAD.elf",
419                       "elf_examples/64bitLOAD_copy.elf" );
420     checkExeAreEqual( "elf_examples/asm64", "elf_examples/asm64_copy" );
421     checkExeAreEqual( "elf_examples/hello_64", "elf_examples/hello_64_copy" );
422 
423     // The last segment (GNU_RELRO) is bigger than necessary.
424     // I don't see why but it contains a few bits of the .got.plt section.
425     // -> load, store, compare cycle fails
426     //    checkExeAreEqual( "elf_examples/main",
427     //                      "elf_examples/main_copy" );
428     //    checkExeAreEqual( "elf_examples/ls",
429     //                      "elf_examples/ls_copy" );
430 }
431 
432 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(elf_exe_copy_32)433 BOOST_AUTO_TEST_CASE( elf_exe_copy_32 )
434 {
435     checkExeAreEqual( "elf_examples/asm", "elf_examples/asm_copy" );
436     checkExeAreEqual( "elf_examples/arm_v7m_test_debug.elf",
437                       "elf_examples/arm_v7m_test_debug_copy.elf" );
438     checkExeAreEqual( "elf_examples/arm_v7m_test_release.elf",
439                       "elf_examples/arm_v7m_test_release_copy.elf" );
440     checkExeAreEqual( "elf_examples/hello_32", "elf_examples/hello_32_copy" );
441     checkExeAreEqual( "elf_examples/hello_arm", "elf_examples/hello_arm_copy" );
442     checkExeAreEqual( "elf_examples/hello_arm_stripped",
443                       "elf_examples/hello_arm_stripped_copy" );
444     checkExeAreEqual( "elf_examples/read_write_arm_elf32_input",
445                       "elf_examples/read_write_arm_elf32_input_copy" );
446     checkExeAreEqual( "elf_examples/test_ppc", "elf_examples/test_ppc_copy" );
447 }
448 
449 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(elf_exe_loadsave_ppc32big3)450 BOOST_AUTO_TEST_CASE( elf_exe_loadsave_ppc32big3 )
451 {
452     std::string in  = "elf_examples/ppc-32bit-specimen3.elf";
453     std::string out = "elf_examples/ppc-32bit-testcopy3.elf";
454     elfio       elf;
455     BOOST_REQUIRE_EQUAL( elf.load( in ), true );
456     BOOST_REQUIRE_EQUAL( elf.save( out ), true );
457 
458     checkObjestsAreEqual( in, out );
459     checkExeAreEqual( in, out, SEG_ALIGN );
460 }
461 
462 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(get_symbol_32)463 BOOST_AUTO_TEST_CASE( get_symbol_32 )
464 {
465     elfio            elf;
466     std::string      name;
467     ELFIO::Elf_Xword size;
468     unsigned char    bind;
469     unsigned char    type;
470     ELFIO::Elf_Half  section_index;
471     unsigned char    other;
472     std::string      in = "elf_examples/hello_32";
473 
474     BOOST_REQUIRE_EQUAL( elf.load( in ), true );
475     section*                      psymsec = elf.sections[".symtab"];
476     const symbol_section_accessor symbols( elf, psymsec );
477 
478     BOOST_CHECK_EQUAL( true, symbols.get_symbol( 0x08048478, name, size, bind,
479                                                  type, section_index, other ) );
480     BOOST_CHECK_EQUAL( "_IO_stdin_used", name );
481     BOOST_CHECK_EQUAL( 14, section_index );
482     BOOST_CHECK_EQUAL( 4, size );
483 }
484 
485 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(get_symbol_64)486 BOOST_AUTO_TEST_CASE( get_symbol_64 )
487 {
488     elfio            elf;
489     std::string      name;
490     ELFIO::Elf_Xword size;
491     unsigned char    bind;
492     unsigned char    type;
493     ELFIO::Elf_Half  section_index;
494     unsigned char    other;
495     std::string      in = "elf_examples/hello_64";
496 
497     BOOST_REQUIRE_EQUAL( elf.load( in ), true );
498     section*                      psymsec = elf.sections[".symtab"];
499     const symbol_section_accessor symbols( elf, psymsec );
500 
501     BOOST_CHECK_EQUAL( true, symbols.get_symbol( 0x00400498, name, size, bind,
502                                                  type, section_index, other ) );
503     BOOST_CHECK_EQUAL( "main", name );
504     BOOST_CHECK_EQUAL( 12, section_index );
505     BOOST_CHECK_EQUAL( 21, size );
506 }
507 
508 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(null_section_inside_segment)509 BOOST_AUTO_TEST_CASE( null_section_inside_segment )
510 {
511     // This test case checks the load/save of SHT_NULL sections in a segment
512     // See https://github.com/serge1/ELFIO/issues/19
513     //
514     // Note: The test case checking the load/save of a segment containing no section
515     // is covered by elf_object_copy_32: elf_examples/hello_32 has empty segments
516 
517     // Create an ELF file with SHT_NULL sections at the beginning/middle/end of a segment
518     elfio writer;
519     writer.create( ELFCLASS32, ELFDATA2LSB );
520     writer.set_os_abi( ELFOSABI_LINUX );
521     writer.set_type( ET_EXEC );
522     writer.set_machine( EM_386 );
523     // Create code section 1
524     section* text_sec1 = writer.sections.add( ".text1" );
525     text_sec1->set_type( SHT_PROGBITS );
526     text_sec1->set_flags( SHF_ALLOC | SHF_EXECINSTR );
527     text_sec1->set_addr_align( 0x10 );
528     text_sec1->set_address( 0x08048000 );
529     char text[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
530     text_sec1->set_data( text, sizeof( text ) );
531     // Create code section 2
532     section* text_sec2 = writer.sections.add( ".text2" );
533     text_sec2->set_type( SHT_PROGBITS );
534     text_sec2->set_flags( SHF_ALLOC | SHF_EXECINSTR );
535     text_sec2->set_addr_align( 0x10 );
536     text_sec2->set_address( 0x08048010 );
537     text_sec2->set_data( text, sizeof( text ) );
538     // Create null sections
539     section* null_sec1 = writer.sections.add( "null" );
540     null_sec1->set_type( SHT_NULL );
541     null_sec1->set_flags( SHF_ALLOC | SHF_EXECINSTR );
542     null_sec1->set_address( 0x08048000 );
543     section* null_sec2 = writer.sections.add( "null" );
544     null_sec2->set_type( SHT_NULL );
545     null_sec2->set_flags( SHF_ALLOC | SHF_EXECINSTR );
546     null_sec2->set_address( 0x08048010 );
547     section* null_sec3 = writer.sections.add( "null" );
548     null_sec3->set_type( SHT_NULL );
549     null_sec3->set_flags( SHF_ALLOC | SHF_EXECINSTR );
550     null_sec3->set_address( 0x08048020 );
551     // Create a loadable segment
552     segment* text_seg = writer.segments.add();
553     text_seg->set_type( PT_LOAD );
554     text_seg->set_virtual_address( 0x08048000 );
555     text_seg->set_physical_address( 0x08048000 );
556     text_seg->set_flags( PF_X | PF_R );
557     text_seg->set_align( 0x1000 );
558     // Add sections into the loadable segment
559     text_seg->add_section_index( null_sec1->get_index(),
560                                  null_sec1->get_addr_align() );
561     text_seg->add_section_index( text_sec1->get_index(),
562                                  text_sec1->get_addr_align() );
563     text_seg->add_section_index( null_sec2->get_index(),
564                                  null_sec2->get_addr_align() );
565     text_seg->add_section_index( text_sec2->get_index(),
566                                  text_sec2->get_addr_align() );
567     text_seg->add_section_index( null_sec3->get_index(),
568                                  null_sec3->get_addr_align() );
569     // Setup entry point
570     writer.set_entry( 0x08048000 );
571     // Create ELF file
572     std::string f1 = "elf_examples/null_section_inside_segment1";
573     std::string f2 = "elf_examples/null_section_inside_segment2";
574     BOOST_CHECK_EQUAL( writer.save( f1 ), true );
575 
576     // Load and check the ELF file created above
577     elfio elf;
578     BOOST_CHECK_EQUAL( elf.load( f1 ), true );
579     BOOST_CHECK_EQUAL( elf.save( f2 ), true );
580 }
581 
582 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(invalid_file)583 BOOST_AUTO_TEST_CASE( invalid_file )
584 {
585     elfio             elf;
586     std::string       name;
587     ELFIO::Elf64_Addr value;
588     ELFIO::Elf_Xword  size;
589     unsigned char     bind;
590     unsigned char     type;
591     ELFIO::Elf_Half   section_index;
592     unsigned char     other;
593     std::string       in = "elf_examples/crash.elf";
594 
595     BOOST_REQUIRE_EQUAL( elf.load( in ), true );
596     section* psymsec = elf.sections[".symtab"];
597     BOOST_REQUIRE_NE( psymsec, (void*)0 );
598     const symbol_section_accessor symbols( elf, psymsec );
599 
600     BOOST_CHECK_EQUAL( true, symbols.get_symbol( "main", value, size, bind,
601                                                  type, section_index, other ) );
602     BOOST_CHECK_EQUAL( 0x402560, value );
603 
604     BOOST_CHECK_EQUAL( true,
605                        symbols.get_symbol( "frame_dummy", value, size, bind,
606                                            type, section_index, other ) );
607     BOOST_CHECK_EQUAL( 0x402550, value );
608 
609     BOOST_CHECK_EQUAL( false,
610                        symbols.get_symbol( 0x00400498, name, size, bind, type,
611                                            section_index, other ) );
612 }
613 
614 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(rearrange_local_symbols)615 BOOST_AUTO_TEST_CASE( rearrange_local_symbols )
616 {
617     std::string       name          = "";
618     ELFIO::Elf64_Addr value         = 0;
619     ELFIO::Elf_Xword  size          = 0;
620     unsigned char     bind          = STB_LOCAL;
621     unsigned char     type          = STT_FUNC;
622     ELFIO::Elf_Half   section_index = 0;
623     unsigned char     other         = 0;
624     const std::string file_name     = "elf_examples/test_symbols_order.elf";
625 
626     elfio writer;
627     writer.create( ELFCLASS64, ELFDATA2LSB );
628     writer.set_os_abi( ELFOSABI_LINUX );
629     writer.set_type( ET_EXEC );
630     writer.set_machine( EM_X86_64 );
631 
632     section* str_sec = writer.sections.add( ".strtab" );
633     str_sec->set_type( SHT_STRTAB );
634     str_sec->set_addr_align( 0x1 );
635     string_section_accessor str_writer( str_sec );
636 
637     section* sym_sec = writer.sections.add( ".symtab" );
638     sym_sec->set_type( SHT_SYMTAB );
639     sym_sec->set_info( 0 );
640     sym_sec->set_link( str_sec->get_index() );
641     sym_sec->set_addr_align( 4 );
642     sym_sec->set_entry_size( writer.get_default_entry_size( SHT_SYMTAB ) );
643     symbol_section_accessor symbols( writer, sym_sec );
644 
645     name  = "Str1";
646     bind  = STB_GLOBAL;
647     value = 1;
648     symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type,
649                         other, section_index );
650     name  = "Str2";
651     bind  = STB_LOCAL;
652     value = 2;
653     symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type,
654                         other, section_index );
655     name  = "Str3";
656     bind  = STB_WEAK;
657     value = 3;
658     symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type,
659                         other, section_index );
660     name  = "Str4";
661     bind  = STB_LOCAL;
662     value = 4;
663     symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type,
664                         other, section_index );
665     name  = "Str5";
666     bind  = STB_LOCAL;
667     value = 5;
668     symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type,
669                         other, section_index );
670     name  = "Str6";
671     bind  = STB_GLOBAL;
672     value = 6;
673     symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type,
674                         other, section_index );
675     name  = "Str7";
676     bind  = STB_LOCAL;
677     value = 7;
678     symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type,
679                         other, section_index );
680     name  = "Str8";
681     bind  = STB_WEAK;
682     value = 8;
683     symbols.add_symbol( str_writer, name.c_str(), value, size, bind, type,
684                         other, section_index );
685 
686     symbols.arrange_local_symbols( [&]( Elf_Xword first, Elf_Xword ) -> void {
687         static int counter = 0;
688         BOOST_CHECK_EQUAL( first, ++counter );
689         // std::string name              = "";
690         // ELFIO::Elf64_Addr value       = 0;
691         // ELFIO::Elf_Xword size         = 0;
692         // unsigned char bind            = STB_LOCAL;
693         // unsigned char type            = STT_FUNC;
694         // ELFIO::Elf_Half section_index = 0;
695         // unsigned char other           = 0;
696 
697         // std::cout << first << " " << second << std::endl;
698         // symbols.get_symbol(first, name, value, size, bind, type, section_index, other);
699         // std::cout << "  " << name;
700         // symbols.get_symbol(second, name, value, size, bind, type, section_index, other);
701         // std::cout << "  " << name << std::endl;
702     } );
703 
704     BOOST_REQUIRE_EQUAL( writer.save( file_name ), true );
705 
706     // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
707 
708     elfio reader;
709     BOOST_REQUIRE_EQUAL( reader.load( file_name ), true );
710 
711     auto psymsec = reader.sections[".symtab"];
712     BOOST_REQUIRE_NE( psymsec, nullptr );
713 
714     const_symbol_section_accessor rsymbols( reader, psymsec );
715 
716     auto bound = psymsec->get_info();
717     auto num   = rsymbols.get_symbols_num();
718 
719     BOOST_CHECK_LE( (Elf_Xword)bound, num );
720 
721     // Check that all symbols are LOCAL until the bound value
722     for ( Elf_Word i = 0; i < bound; i++ ) {
723         rsymbols.get_symbol( i, name, value, size, bind, type, section_index,
724                              other );
725         BOOST_CHECK_EQUAL( bind, (unsigned char)STB_LOCAL );
726     }
727     BOOST_CHECK_EQUAL( name, "Str7" );
728 
729     // Check that all symbols are not LOCAL after the bound value
730     for ( Elf_Word i = bound; i < num; i++ ) {
731         rsymbols.get_symbol( i, name, value, size, bind, type, section_index,
732                              other );
733 
734         BOOST_CHECK_NE( bind, (unsigned char)STB_LOCAL );
735     }
736     BOOST_CHECK_EQUAL( name, "Str8" );
737 }
738 
739 ////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE(rearrange_local_symbols_with_reallocation)740 BOOST_AUTO_TEST_CASE( rearrange_local_symbols_with_reallocation )
741 {
742     std::string       name          = "";
743     ELFIO::Elf64_Addr value         = 0;
744     ELFIO::Elf_Xword  size          = 0;
745     unsigned char     bind          = STB_LOCAL;
746     unsigned char     type          = STT_FUNC;
747     ELFIO::Elf_Half   section_index = 0;
748     unsigned char     other         = 0;
749     const std::string file_name     = "elf_examples/test_symbols_order.elf";
750 
751     elfio writer;
752     writer.create( ELFCLASS64, ELFDATA2LSB );
753     writer.set_os_abi( ELFOSABI_LINUX );
754     writer.set_type( ET_EXEC );
755     writer.set_machine( EM_X86_64 );
756 
757     section* text_sec = writer.sections.add( ".text" );
758     text_sec->set_type( SHT_PROGBITS );
759     text_sec->set_flags( SHF_ALLOC | SHF_EXECINSTR );
760     text_sec->set_addr_align( 0x10 );
761 
762     section* str_sec = writer.sections.add( ".strtab" );
763     str_sec->set_type( SHT_STRTAB );
764     str_sec->set_addr_align( 0x1 );
765     string_section_accessor str_writer( str_sec );
766 
767     section* sym_sec = writer.sections.add( ".symtab" );
768     sym_sec->set_type( SHT_SYMTAB );
769     sym_sec->set_info( 0 );
770     sym_sec->set_link( str_sec->get_index() );
771     sym_sec->set_addr_align( 4 );
772     sym_sec->set_entry_size( writer.get_default_entry_size( SHT_SYMTAB ) );
773     symbol_section_accessor symbols( writer, sym_sec );
774 
775     name          = "Str1";
776     bind          = STB_GLOBAL;
777     value         = 1;
778     Elf_Word sym1 = symbols.add_symbol( str_writer, name.c_str(), value, size,
779                                         bind, type, other, section_index );
780     name          = "Str2";
781     bind          = STB_LOCAL;
782     value         = 2;
783     Elf_Word sym2 = symbols.add_symbol( str_writer, name.c_str(), value, size,
784                                         bind, type, other, section_index );
785     name          = "Str3";
786     bind          = STB_WEAK;
787     value         = 3;
788     Elf_Word sym3 = symbols.add_symbol( str_writer, name.c_str(), value, size,
789                                         bind, type, other, section_index );
790     name          = "Str4";
791     bind          = STB_LOCAL;
792     value         = 4;
793     Elf_Word sym4 = symbols.add_symbol( str_writer, name.c_str(), value, size,
794                                         bind, type, other, section_index );
795     name          = "Str5";
796     bind          = STB_LOCAL;
797     value         = 5;
798     Elf_Word sym5 = symbols.add_symbol( str_writer, name.c_str(), value, size,
799                                         bind, type, other, section_index );
800     name          = "Str6";
801     bind          = STB_GLOBAL;
802     value         = 6;
803     Elf_Word sym6 = symbols.add_symbol( str_writer, name.c_str(), value, size,
804                                         bind, type, other, section_index );
805     name          = "Str7";
806     bind          = STB_LOCAL;
807     value         = 7;
808     Elf_Word sym7 = symbols.add_symbol( str_writer, name.c_str(), value, size,
809                                         bind, type, other, section_index );
810     name          = "Str8";
811     bind          = STB_WEAK;
812     value         = 8;
813     Elf_Word sym8 = symbols.add_symbol( str_writer, name.c_str(), value, size,
814                                         bind, type, other, section_index );
815 
816     section* rel_sec = writer.sections.add( ".rel.text" );
817     rel_sec->set_type( SHT_REL );
818     rel_sec->set_info( text_sec->get_index() );
819     rel_sec->set_addr_align( 0x4 );
820     rel_sec->set_entry_size( writer.get_default_entry_size( SHT_REL ) );
821     rel_sec->set_link( sym_sec->get_index() );
822 
823     relocation_section_accessor rela( writer, rel_sec );
824     // Add relocation entry (adjust address at offset 11)
825     rela.add_entry( 1, sym1, (unsigned char)R_386_RELATIVE );
826     rela.add_entry( 8, sym8, (unsigned char)R_386_RELATIVE );
827     rela.add_entry( 6, sym6, (unsigned char)R_386_RELATIVE );
828     rela.add_entry( 2, sym2, (unsigned char)R_386_RELATIVE );
829     rela.add_entry( 3, sym3, (unsigned char)R_386_RELATIVE );
830     rela.add_entry( 8, sym8, (unsigned char)R_386_RELATIVE );
831     rela.add_entry( 7, sym7, (unsigned char)R_386_RELATIVE );
832     rela.add_entry( 2, sym2, (unsigned char)R_386_RELATIVE );
833     rela.add_entry( 11, sym1, (unsigned char)R_386_RELATIVE );
834     rela.add_entry( 18, sym8, (unsigned char)R_386_RELATIVE );
835     rela.add_entry( 16, sym6, (unsigned char)R_386_RELATIVE );
836     rela.add_entry( 12, sym2, (unsigned char)R_386_RELATIVE );
837     rela.add_entry( 13, sym3, (unsigned char)R_386_RELATIVE );
838     rela.add_entry( 17, sym7, (unsigned char)R_386_RELATIVE );
839     rela.add_entry( 14, sym4, (unsigned char)R_386_RELATIVE );
840     rela.add_entry( 15, sym5, (unsigned char)R_386_RELATIVE );
841 
842     std::vector<std::string> before;
843 
844     for ( Elf_Word i = 0; i < rela.get_entries_num(); i++ ) {
845         Elf64_Addr offset;
846         Elf_Word   symbol;
847         Elf_Word   rtype;
848         Elf_Sxword addend;
849 
850         rela.get_entry( i, offset, symbol, rtype, addend );
851         symbols.get_symbol( symbol, name, value, size, bind, type,
852                             section_index, other );
853         before.push_back( name );
854     }
855 
856     symbols.arrange_local_symbols( [&]( Elf_Xword first, Elf_Xword second ) {
857         rela.swap_symbols( first, second );
858     } );
859 
860     BOOST_REQUIRE_EQUAL( writer.save( file_name ), true );
861 
862     // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
863 
864     elfio reader;
865     BOOST_REQUIRE_EQUAL( reader.load( file_name ), true );
866 
867     auto prelsec = reader.sections[".rel.text"];
868     auto psyms   = reader.sections[".symtab"];
869 
870     BOOST_REQUIRE_NE( prelsec, nullptr );
871     BOOST_REQUIRE_NE( psyms, nullptr );
872 
873     const_relocation_section_accessor rel( reader, prelsec );
874     const_symbol_section_accessor     syms( reader, psyms );
875 
876     std::vector<std::string> after;
877 
878     for ( Elf_Word i = 0; i < rel.get_entries_num(); i++ ) {
879         Elf64_Addr offset;
880         Elf_Word   symbol;
881         Elf_Word   rtype;
882         Elf_Sxword addend;
883 
884         rel.get_entry( i, offset, symbol, rtype, addend );
885         syms.get_symbol( symbol, name, value, size, bind, type, section_index,
886                          other );
887         after.push_back( name );
888     }
889 
890     BOOST_CHECK_EQUAL_COLLECTIONS( before.begin(), before.end(), after.begin(),
891                                    after.end() );
892 }
893 
BOOST_AUTO_TEST_CASE(detect_mismatched_section_segment_tables)894 BOOST_AUTO_TEST_CASE( detect_mismatched_section_segment_tables )
895 {
896     /*  This file is a hacked copy of hello_32
897      *  The error introduced is:
898      *     Virtual address of segment 3 (0x804948c) conflicts
899      *     with address of section .ctors (0x804948e) at offset 0x48e
900      */
901     std::string in = "elf_examples/mismatched_segments.elf";
902     elfio       elf;
903     BOOST_REQUIRE_EQUAL( elf.load( in ), true );
904     BOOST_REQUIRE( elf.validate().length() > 0 );
905 }
906