--- /dev/null
+#!/usr/bin/env python
+#-------------------------------------------------------------------------------
+# tests/run_all_unittests.py
+#
+# Run all unit tests (alternative to running 'python -m unittest discover ...')
+#
+# Eli Bendersky (eliben@gmail.com)
+# This code is in the public domain
+#-------------------------------------------------------------------------------
+from unittest import TestLoader, TextTestRunner
+
+
+if __name__ == '__main__':
+ try:
+ tests = TestLoader().discover('tests', 'test*.py', 'tests')
+ TextTestRunner().run(tests)
+ except ImportError as err:
+ print err
+ print '!! Please execute from the root directory of pyelfutils'
+
--- /dev/null
+#!/usr/bin/env python
+#-------------------------------------------------------------------------------
+# tests/run_readelf_tests.py
+#
+# Automatic test runner for elftools & readelf
+#
+# Eli Bendersky (eliben@gmail.com)
+# This code is in the public domain
+#-------------------------------------------------------------------------------
+import os, sys
+import re
+from difflib import SequenceMatcher
+import logging
+import subprocess
+import tempfile
+import platform
+
+
+# Create a global logger object
+#
+testlog = logging.getLogger('run_tests')
+testlog.setLevel(logging.DEBUG)
+testlog.addHandler(logging.StreamHandler(sys.stdout))
+
+
+def discover_testfiles(rootdir):
+ """ Discover test files in the given directory. Yield them one by one.
+ """
+ for filename in os.listdir(rootdir):
+ _, ext = os.path.splitext(filename)
+ if ext == '.elf':
+ yield os.path.join(rootdir, filename)
+
+
+def run_exe(exe_path, args):
+ """ Runs the given executable as a subprocess, given the
+ list of arguments. Captures its return code (rc) and stdout and
+ returns a pair: rc, stdout_str
+ """
+ popen_cmd = [exe_path] + args
+ if os.path.splitext(exe_path)[1] == '.py':
+ popen_cmd.insert(0, 'python')
+ proc = subprocess.Popen(popen_cmd, stdout=subprocess.PIPE)
+ proc_stdout = proc.communicate()[0]
+ return proc.returncode, proc_stdout
+
+
+def run_test_on_file(filename):
+ """ Runs a test on the given input filename. Return True if all test
+ runs succeeded.
+ """
+ success = True
+ testlog.info("Running test on file '%s'" % filename)
+ for option in [
+ '-e', '-s', '-r', '-x.text', '-p.shstrtab',
+ '--debug-dump=info', '--debug-dump=decodedline',
+ '--debug-dump=frames', '--debug-dump=frames-interp']:
+ testlog.info("..option='%s'" % option)
+ # stdouts will be a 2-element list: output of readelf and output
+ # of scripts/readelf.py
+ stdouts = []
+ for exe_path in ['readelf', 'scripts/readelf.py']:
+ args = [option, filename]
+ testlog.info("....executing: '%s %s'" % (
+ exe_path, ' '.join(args)))
+ rc, stdout = run_exe(exe_path, args)
+ if rc != 0:
+ testlog.error("@@ aborting - '%s' returned '%s'" % (exe_path, rc))
+ return False
+ stdouts.append(stdout)
+ testlog.info('....comparing output...')
+ rc, errmsg = compare_output(*stdouts)
+ if rc:
+ testlog.info('.......................SUCCESS')
+ else:
+ success = False
+ testlog.info('.......................FAIL')
+ testlog.info('@@ ' + errmsg)
+ dump_output_to_temp_files(*stdouts)
+ return success
+
+
+def compare_output(s1, s2):
+ """ Compare stdout strings s1 and s2.
+ s1 is from readelf, s2 from elftools readelf.py
+ Return pair success, errmsg. If comparison succeeds, success is True
+ and errmsg is empty. Otherwise success is False and errmsg holds a
+ description of the mismatch.
+
+ Note: this function contains some rather horrible hacks to ignore
+ differences which are not important for the verification of pyelftools.
+ This is due to some intricacies of binutils's readelf which pyelftools
+ doesn't currently implement, or silly inconsistencies in the output of
+ readelf, which I was reluctant to replicate.
+ Read the documentation for more details.
+ """
+ def prepare_lines(s):
+ return [line for line in s.lower().splitlines() if line.strip() != '']
+ def filter_readelf_lines(lines):
+ filter_out = False
+ for line in lines:
+ if 'of the .eh_frame section' in line:
+ filter_out = True
+ elif 'of the .debug_frame section' in line:
+ filter_out = False
+ if not filter_out:
+ if not line.startswith('unknown: length'):
+ yield line
+
+ lines1 = prepare_lines(s1)
+ lines2 = prepare_lines(s2)
+
+ lines1 = list(filter_readelf_lines(lines1))
+
+ flag_after_symtable = False
+
+ if len(lines1) != len(lines2):
+ return False, 'Number of lines different: %s vs %s' % (
+ len(lines1), len(lines2))
+
+ for i in range(len(lines1)):
+ if 'symbol table' in lines1[i]:
+ flag_after_symtable = True
+
+ # Compare ignoring whitespace
+ lines1_parts = lines1[i].split()
+ lines2_parts = lines2[i].split()
+ if ''.join(lines1_parts) != ''.join(lines2_parts):
+ ok = False
+ sm = SequenceMatcher()
+ sm.set_seqs(lines1[i], lines2[i])
+ changes = sm.get_opcodes()
+ if flag_after_symtable:
+ # Detect readelf's adding @ with lib and version after
+ # symbol name.
+ if ( len(changes) == 2 and changes[1][0] == 'delete' and
+ lines1[i][changes[1][1]] == '@'):
+ ok = True
+ elif 'at_const_value' in lines1[i]:
+ # On 32-bit machines, readelf doesn't correctly represent
+ # some boundary LEB128 numbers
+ num2 = int(lines2_parts[-1])
+ if num2 <= -2**31 and '32' in platform.architecture()[0]:
+ ok = True
+ elif 'os/abi' in lines1[i]:
+ if 'unix - gnu' in lines1[i] and 'unix - linux' in lines2[i]:
+ ok = True
+ else:
+ for s in ('t (tls)', 'l (large)'):
+ if s in lines1[i] or s in lines2[i]:
+ ok = True
+ break
+ if not ok:
+ errmsg = 'Mismatch on line #%s:\n>>%s<<\n>>%s<<\n' % (
+ i, lines1[i], lines2[i])
+ return False, errmsg
+ return True, ''
+
+
+def dump_output_to_temp_files(*args):
+ """ Dumps the output strings given in 'args' to temp files: one for each
+ arg.
+ """
+ for i, s in enumerate(args):
+ fd, path = tempfile.mkstemp(
+ prefix='out' + str(i + 1) + '_',
+ suffix='.stdout')
+ file = os.fdopen(fd, 'w')
+ file.write(s)
+ file.close()
+ testlog.info('@@ Output #%s dumped to file: %s' % (i + 1, path))
+
+
+def die(msg):
+ testlog.error('Error: %s' % msg)
+ sys.exit(1)
+
+
+def is_in_rootdir():
+ """ Check whether the current dir is the root dir of pyelftools
+ """
+ dirstuff = os.listdir('.')
+ return 'test' in dirstuff and 'elftools' in dirstuff
+
+
+def main():
+ if not is_in_rootdir():
+ die('Please run me from the root dir of pyelftools!')
+
+ # If file names are given as command-line arguments, only these files
+ # are taken as inputs. Otherwise, autodiscovery is performed.
+ #
+ if len(sys.argv) > 1:
+ filenames = sys.argv[1:]
+ else:
+ filenames = list(discover_testfiles('test/testfiles'))
+
+ success = True
+ for filename in filenames:
+ success = success and run_test_on_file(filename)
+
+ if success:
+ testlog.info('\nConclusion: SUCCESS')
+ else:
+ testlog.info('\nConclusion: FAIL')
+
+
+if __name__ == '__main__':
+ main()
+
+
+
+
--- /dev/null
+import sys, unittest
+from cStringIO import StringIO
+
+sys.path.extend(['.', '..'])
+from elftools.dwarf.callframe import (
+ CallFrameInfo, CIE, FDE, instruction_name, CallFrameInstruction,
+ RegisterRule)
+from elftools.dwarf.structs import DWARFStructs
+from elftools.dwarf.descriptions import (describe_CFI_instructions,
+ set_global_machine_arch)
+
+
+class TestCallFrame(unittest.TestCase):
+ def assertInstruction(self, instr, name, args):
+ self.assertIsInstance(instr, CallFrameInstruction)
+ self.assertEqual(instruction_name(instr.opcode), name)
+ self.assertEqual(instr.args, args)
+
+ def test_spec_sample_d6(self):
+ # D.6 sample in DWARFv3
+ s = StringIO()
+ data = ('' +
+ # first comes the CIE
+ '\x20\x00\x00\x00' + # length
+ '\xff\xff\xff\xff' + # CIE_id
+ '\x03\x00\x04\x7c' + # version, augmentation, caf, daf
+ '\x08' + # return address
+ '\x0c\x07\x00' +
+ '\x08\x00' +
+ '\x07\x01' +
+ '\x07\x02' +
+ '\x07\x03' +
+ '\x08\x04' +
+ '\x08\x05' +
+ '\x08\x06' +
+ '\x08\x07' +
+ '\x09\x08\x01' +
+ '\x00' +
+
+ # then comes the FDE
+ '\x28\x00\x00\x00' + # length
+ '\x00\x00\x00\x00' + # CIE_pointer (to CIE at 0)
+ '\x44\x33\x22\x11' + # initial_location
+ '\x54\x00\x00\x00' + # address range
+ '\x41' +
+ '\x0e\x0c' + '\x41' +
+ '\x88\x01' + '\x41' +
+ '\x86\x02' + '\x41' +
+ '\x0d\x06' + '\x41' +
+ '\x84\x03' + '\x4b' +
+ '\xc4' + '\x41' +
+ '\xc6' +
+ '\x0d\x07' + '\x41' +
+ '\xc8' + '\x41' +
+ '\x0e\x00' +
+ '\x00\x00'
+ )
+ s.write(data)
+
+ structs = DWARFStructs(little_endian=True, dwarf_format=32, address_size=4)
+ cfi = CallFrameInfo(s, len(data), structs)
+ entries = cfi.get_entries()
+
+ self.assertEqual(len(entries), 2)
+ self.assertIsInstance(entries[0], CIE)
+ self.assertEqual(entries[0]['length'], 32)
+ self.assertEqual(entries[0]['data_alignment_factor'], -4)
+ self.assertEqual(entries[0]['return_address_register'], 8)
+ self.assertEqual(len(entries[0].instructions), 11)
+ self.assertInstruction(entries[0].instructions[0],
+ 'DW_CFA_def_cfa', [7, 0])
+ self.assertInstruction(entries[0].instructions[8],
+ 'DW_CFA_same_value', [7])
+ self.assertInstruction(entries[0].instructions[9],
+ 'DW_CFA_register', [8, 1])
+
+ self.assertTrue(isinstance(entries[1], FDE))
+ self.assertEqual(entries[1]['length'], 40)
+ self.assertEqual(entries[1]['CIE_pointer'], 0)
+ self.assertEqual(entries[1]['address_range'], 84)
+ self.assertIs(entries[1].cie, entries[0])
+ self.assertEqual(len(entries[1].instructions), 21)
+ self.assertInstruction(entries[1].instructions[0],
+ 'DW_CFA_advance_loc', [1])
+ self.assertInstruction(entries[1].instructions[1],
+ 'DW_CFA_def_cfa_offset', [12])
+ self.assertInstruction(entries[1].instructions[9],
+ 'DW_CFA_offset', [4, 3])
+ self.assertInstruction(entries[1].instructions[18],
+ 'DW_CFA_def_cfa_offset', [0])
+ self.assertInstruction(entries[1].instructions[20],
+ 'DW_CFA_nop', [])
+
+ # Now let's decode it...
+ decoded_CIE = entries[0].get_decoded()
+ self.assertEqual(decoded_CIE.reg_order, list(range(9)))
+ self.assertEqual(len(decoded_CIE.table), 1)
+ self.assertEqual(decoded_CIE.table[0]['cfa'].reg, 7)
+ self.assertEqual(decoded_CIE.table[0]['pc'], 0)
+ self.assertEqual(decoded_CIE.table[0]['cfa'].offset, 0)
+ self.assertEqual(decoded_CIE.table[0][4].type, RegisterRule.SAME_VALUE)
+ self.assertEqual(decoded_CIE.table[0][8].type, RegisterRule.REGISTER)
+ self.assertEqual(decoded_CIE.table[0][8].arg, 1)
+
+ decoded_FDE = entries[1].get_decoded()
+ self.assertEqual(decoded_FDE.reg_order, list(range(9)))
+ self.assertEqual(decoded_FDE.table[0]['cfa'].reg, 7)
+ self.assertEqual(decoded_FDE.table[0]['cfa'].offset, 0)
+ self.assertEqual(decoded_FDE.table[0]['pc'], 0x11223344)
+ self.assertEqual(decoded_FDE.table[0][8].type, RegisterRule.REGISTER)
+ self.assertEqual(decoded_FDE.table[0][8].arg, 1)
+ self.assertEqual(decoded_FDE.table[1]['cfa'].reg, 7)
+ self.assertEqual(decoded_FDE.table[1]['cfa'].offset, 12)
+ self.assertEqual(decoded_FDE.table[2][8].type, RegisterRule.OFFSET)
+ self.assertEqual(decoded_FDE.table[2][8].arg, -4)
+ self.assertEqual(decoded_FDE.table[2][4].type, RegisterRule.SAME_VALUE)
+ self.assertEqual(decoded_FDE.table[5]['pc'], 0x11223344 + 20)
+ self.assertEqual(decoded_FDE.table[5][4].type, RegisterRule.OFFSET)
+ self.assertEqual(decoded_FDE.table[5][4].arg, -12)
+ self.assertEqual(decoded_FDE.table[6]['pc'], 0x11223344 + 64)
+ self.assertEqual(decoded_FDE.table[9]['pc'], 0x11223344 + 76)
+
+ def test_describe_CFI_instructions(self):
+ # The data here represents a single CIE
+ data = ('' +
+ '\x16\x00\x00\x00' + # length
+ '\xff\xff\xff\xff' + # CIE_id
+ '\x03\x00\x04\x7c' + # version, augmentation, caf, daf
+ '\x08' + # return address
+ '\x0c\x07\x02' +
+ '\x10\x02\x07\x03\x01\x02\x00\x00\x06\x06')
+ s = StringIO(data)
+
+ structs = DWARFStructs(little_endian=True, dwarf_format=32, address_size=4)
+ cfi = CallFrameInfo(s, len(data), structs)
+ entries = cfi.get_entries()
+
+ set_global_machine_arch('x86')
+ self.assertEqual(describe_CFI_instructions(entries[0]),
+ ( ' DW_CFA_def_cfa: r7 (edi) ofs 2\n' +
+ ' DW_CFA_expression: r2 (edx) (DW_OP_addr: 201; DW_OP_deref; DW_OP_deref)\n'))
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+
--- /dev/null
+import sys, unittest
+from cStringIO import StringIO
+
+sys.path.extend(('..', '.'))
+from elftools.dwarf.descriptions import ExprDumper, set_global_machine_arch
+from elftools.dwarf.structs import DWARFStructs
+
+
+class TestExprDumper(unittest.TestCase):
+ structs32 = DWARFStructs(
+ little_endian=True,
+ dwarf_format=32,
+ address_size=4)
+
+ def setUp(self):
+ self.visitor = ExprDumper(self.structs32)
+ set_global_machine_arch('x64')
+
+ def test_basic_single(self):
+ self.visitor.process_expr([0x1b])
+ self.assertEqual(self.visitor.get_str(),
+ 'DW_OP_div')
+
+ self.setUp()
+ self.visitor.process_expr([0x74, 0x82, 0x01])
+ self.assertEqual(self.visitor.get_str(),
+ 'DW_OP_breg4 (rsi): 130')
+
+ self.setUp()
+ self.visitor.process_expr([0x91, 0x82, 0x01])
+ self.assertEqual(self.visitor.get_str(),
+ 'DW_OP_fbreg: 130')
+
+ self.setUp()
+ self.visitor.process_expr([0x51])
+ self.assertEqual(self.visitor.get_str(),
+ 'DW_OP_reg1 (rdx)')
+
+ self.setUp()
+ self.visitor.process_expr([0x90, 16])
+ self.assertEqual(self.visitor.get_str(),
+ 'DW_OP_regx: 16 (rip)')
+
+ self.setUp()
+ self.visitor.process_expr([0x9d, 0x8f, 0x0A, 0x90, 0x01])
+ self.assertEqual(self.visitor.get_str(),
+ 'DW_OP_bit_piece: 1295 144')
+
+ def test_basic_sequence(self):
+ self.visitor.process_expr([0x03, 0x01, 0x02, 0, 0, 0x06, 0x06])
+ self.assertEqual(self.visitor.get_str(),
+ 'DW_OP_addr: 201; DW_OP_deref; DW_OP_deref')
+
+ self.setUp()
+ self.visitor.process_expr([0x15, 0xFF, 0x0b, 0xf1, 0xff])
+ self.assertEqual(self.visitor.get_str(),
+ 'DW_OP_pick: 255; DW_OP_const2s: -15')
+
+ self.setUp()
+ self.visitor.process_expr([0x1d, 0x1e, 0x1d, 0x1e, 0x1d, 0x1e])
+ self.assertEqual(self.visitor.get_str(),
+ 'DW_OP_mod; DW_OP_mul; DW_OP_mod; DW_OP_mul; DW_OP_mod; DW_OP_mul')
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+
--- /dev/null
+import sys, unittest
+from cStringIO import StringIO
+
+sys.path.extend(['.', '..'])
+from elftools.dwarf.lineprogram import LineProgram, LineState, LineProgramEntry
+from elftools.dwarf.structs import DWARFStructs
+from elftools.dwarf.constants import *
+
+
+class TestLineProgram(unittest.TestCase):
+ def _make_program_in_stream(self, stream):
+ """ Create a LineProgram from the given program encoded in a stream
+ """
+ ds = DWARFStructs(little_endian=True, dwarf_format=32, address_size=4)
+ header = ds.Dwarf_lineprog_header.parse(
+ '\x04\x10\x00\x00' + # initial lenght
+ '\x03\x00' + # version
+ '\x20\x00\x00\x00' + # header length
+ '\x01\x01\x01\x0F' + # flags
+ '\x0A' + # opcode_base
+ '\x00\x01\x04\x08\x0C\x01\x01\x01\x00' + # standard_opcode_lengths
+ # 2 dir names followed by a NULL
+ '\x61\x62\x00\x70\x00\x00' +
+ # a file entry
+ '\x61\x72\x00\x0C\x0D\x0F' +
+ # and another entry
+ '\x45\x50\x51\x00\x86\x12\x07\x08' +
+ # followed by NULL
+ '\x00')
+
+ lp = LineProgram(header, stream, ds, 0, len(stream.getvalue()))
+ return lp
+
+ def assertLineState(self, state, **kwargs):
+ """ Assert that the state attributes specified in kwargs have the given
+ values (the rest are default).
+ """
+ for k, v in kwargs.iteritems():
+ self.assertEqual(getattr(state, k), v)
+
+ def test_spec_sample_59(self):
+ # Sample in figure 59 of DWARFv3
+ s = StringIO()
+ s.write(
+ '\x02\xb9\x04' +
+ '\x0b' +
+ '\x38' +
+ '\x82' +
+ '\x73' +
+ '\x02\x02' +
+ '\x00\x01\x01')
+
+ lp = self._make_program_in_stream(s)
+ linetable = lp.get_entries()
+
+ self.assertEqual(len(linetable), 7)
+ self.assertIs(linetable[0].state, None) # doesn't modify state
+ self.assertEqual(linetable[0].command, DW_LNS_advance_pc)
+ self.assertEqual(linetable[0].args, [0x239])
+ self.assertLineState(linetable[1].state, address=0x239, line=3)
+ self.assertEqual(linetable[1].command, 0xb)
+ self.assertEqual(linetable[1].args, [2, 0])
+ self.assertLineState(linetable[2].state, address=0x23c, line=5)
+ self.assertLineState(linetable[3].state, address=0x244, line=6)
+ self.assertLineState(linetable[4].state, address=0x24b, line=7, end_sequence=False)
+ self.assertEqual(linetable[5].command, DW_LNS_advance_pc)
+ self.assertEqual(linetable[5].args, [2])
+ self.assertLineState(linetable[6].state, address=0x24d, line=7, end_sequence=True)
+
+ def test_spec_sample_60(self):
+ # Sample in figure 60 of DWARFv3
+ s = StringIO()
+ s.write(
+ '\x09\x39\x02' +
+ '\x0b' +
+ '\x09\x03\x00' +
+ '\x0b' +
+ '\x09\x08\x00' +
+ '\x0a' +
+ '\x09\x07\x00' +
+ '\x0a' +
+ '\x09\x02\x00' +
+ '\x00\x01\x01')
+
+ lp = self._make_program_in_stream(s)
+ linetable = lp.get_entries()
+
+ self.assertEqual(len(linetable), 10)
+ self.assertIs(linetable[0].state, None) # doesn't modify state
+ self.assertEqual(linetable[0].command, DW_LNS_fixed_advance_pc)
+ self.assertEqual(linetable[0].args, [0x239])
+ self.assertLineState(linetable[1].state, address=0x239, line=3)
+ self.assertLineState(linetable[3].state, address=0x23c, line=5)
+ self.assertLineState(linetable[5].state, address=0x244, line=6)
+ self.assertLineState(linetable[7].state, address=0x24b, line=7, end_sequence=False)
+ self.assertLineState(linetable[9].state, address=0x24d, line=7, end_sequence=True)
+
+
+if __name__ == '__main__':
+ unittest.main()
+
--- /dev/null
+import sys, unittest
+
+sys.path.extend(['.', '..'])
+from elftools.dwarf.structs import DWARFStructs
+
+
+class TestDWARFStructs(unittest.TestCase):
+ def test_lineprog_header(self):
+ ds = DWARFStructs(little_endian=True, dwarf_format=32, address_size=4)
+
+ c = ds.Dwarf_lineprog_header.parse(
+ '\x04\x10\x00\x00' + # initial lenght
+ '\x05\x02' + # version
+ '\x20\x00\x00\x00' + # header length
+ '\x05\x10\x40\x50' + # until and including line_range
+ '\x06' + # opcode_base
+ '\x00\x01\x04\x08\x0C' + # standard_opcode_lengths
+ # 2 dir names followed by a NULL
+ '\x61\x62\x00\x70\x00\x00' +
+ # a file entry
+ '\x61\x72\x00\x0C\x0D\x0F' +
+ # and another entry
+ '\x45\x50\x51\x00\x86\x12\x07\x08' +
+ # followed by NULL
+ '\x00')
+
+ self.assertEqual(c.version, 0x205)
+ self.assertEqual(c.opcode_base, 6)
+ self.assertEqual(c.standard_opcode_lengths, [0, 1, 4, 8, 12])
+ self.assertEqual(c.include_directory, ['ab', 'p'])
+ self.assertEqual(len(c.file_entry), 2)
+ self.assertEqual(c.file_entry[0].name, 'ar')
+ self.assertEqual(c.file_entry[1].name, 'EPQ')
+ self.assertEqual(c.file_entry[1].dir_index, 0x12 * 128 + 6)
+
+
+if __name__ == '__main__':
+ unittest.main()
+
--- /dev/null
+import sys, unittest
+from cStringIO import StringIO
+from random import randint
+
+sys.path.extend(['.', '..'])
+from elftools.common.utils import (parse_cstring_from_stream,
+ preserve_stream_pos)
+
+
+class Test_parse_cstring_from_stream(unittest.TestCase):
+ def _make_random_string(self, n):
+ return ''.join(chr(randint(32, 127)) for i in range(n))
+
+ def test_small1(self):
+ sio = StringIO('abcdefgh\x0012345')
+ self.assertEqual(parse_cstring_from_stream(sio), 'abcdefgh')
+ self.assertEqual(parse_cstring_from_stream(sio, 2), 'cdefgh')
+ self.assertEqual(parse_cstring_from_stream(sio, 8), '')
+
+ def test_small2(self):
+ sio = StringIO('12345\x006789\x00abcdefg\x00iii')
+ self.assertEqual(parse_cstring_from_stream(sio), '12345')
+ self.assertEqual(parse_cstring_from_stream(sio, 5), '')
+ self.assertEqual(parse_cstring_from_stream(sio, 6), '6789')
+
+ def test_large1(self):
+ text = 'i' * 400 + '\x00' + 'bb'
+ sio = StringIO(text)
+ self.assertEqual(parse_cstring_from_stream(sio), 'i' * 400)
+ self.assertEqual(parse_cstring_from_stream(sio, 150), 'i' * 250)
+
+ def test_large2(self):
+ text = self._make_random_string(5000) + '\x00' + 'jujajaja'
+ sio = StringIO(text)
+ self.assertEqual(parse_cstring_from_stream(sio), text[:5000])
+ self.assertEqual(parse_cstring_from_stream(sio, 2348), text[2348:5000])
+
+
+class Test_preserve_stream_pos(object):
+ def test_basic(self):
+ sio = StringIO('abcdef')
+ with preserve_stream_pos(sio):
+ sio.seek(4)
+ self.assertEqual(stream.tell(), 0)
+
+ sio.seek(5)
+ with preserve_stream_pos(sio):
+ sio.seek(0)
+ self.assertEqual(stream.tell(), 5)
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+
+
--- /dev/null
+CFLAGS = -Wall --std=c99
+# This is where `make install` from libelf places its stuff
+LIBELF_HEADERS = /usr/local/include/libelf/
+LIBELF_LIBS = /usr/local/lib/
+
+all: elf_creator
+
+elf_creator: elf_creator.c
+ gcc $(CFLAGS) -o elf_creator elf_creator.c \
+ -I$(LIBELF_HEADERS) -L$(LIBELF_LIBS) -Wl,-rpath,$(LIBELF_LIBS) -lelf
+
+clean:
+ rm -f *.o
+ rm -f *.so
+ rm -f *.a
+ rm -f elf_creator
+
+
--- /dev/null
+Some utilities that use libelf to create synthetic ELF files
+
--- /dev/null
+/* Loosely based on the code in a Knol by Roberto Garcia Lopez:
+**
+** http://knol.google.com/k/roberto-garca-lpez/creating-elf-relocatable-object-files/1ohwel4gqkcn2/3#
+**
+** Note: This file is released under the terms of the LGPL2 license.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libelf.h>
+#include <err.h>
+#include <sysexits.h>
+
+
+const char* OUTFILE = "generated.o";
+
+// Definition of the default string table section ".shstrtab"
+const char defaultStrTable[] =
+{
+ /* offset 00 */ '\0', // The NULL section
+ /* offset 01 */ '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', '\0',
+ /* offset 11 */ '.', 's', 't', 'r', 't', 'a', 'b', '\0',
+ /* offset 19 */ '.', 's', 'y', 'm', 't', 'a', 'b', '\0',
+ /* offset 27 */ '.', 'c', 'o', 'm', 'm', 'e', 'n', 't', '\0',
+ /* offset 36 */ '.', 'b', 's', 's', '\0',
+ /* offset 41 */ '.', 'd', 'a', 't', 'a', '\0',
+ /* offset 47 */ '.', 'r', 'e', 'l', '.', 't', 'e', 'x', 't', '\0',
+ /* offset 57 */ '.', 't', 'e', 'x', 't', '\0'
+};
+
+const char defaultStrTableLen = sizeof(defaultStrTable);
+
+// Offsets of section names in the string table
+const char _shstrtab_offset = 1;
+const char _strtab_offset = 11;
+const char _symtab_offset = 19;
+const char _text_offset = 57;
+
+// Position of sections within the object file
+const char _shstrtab = 1;
+const char _strtab = 2;
+const char _symtab = 3;
+const char _text = 4;
+
+const char TEXT_CONTENTS[] = {0x91, 0x92, 0x93, 0x94};
+
+
+//----------------------------------------------------------------------------
+
+int main()
+{
+ int FileDes;
+ Elf *pElf;
+ Elf32_Ehdr *pEhdr;
+ Elf32_Shdr *pShdr;
+ Elf_Scn *pScn;
+ Elf_Data *pData;
+
+ // Create the ELF header
+ if (elf_version(EV_CURRENT) == EV_NONE) // It must appear before "elf_begin()"
+ errx(EX_SOFTWARE, "ELF library initialization failed: %s", elf_errmsg(-1));
+
+ if ((FileDes = open(OUTFILE, O_CREAT | O_WRONLY | O_TRUNC, 0777)) < 0)
+ errx(EX_OSERR, "open \"%s\" failed", "compiled.o");
+
+ if ((pElf = elf_begin(FileDes, ELF_C_WRITE, NULL)) == NULL) // 3rd argument is ignored for "ELF_C_WRITE"
+ errx(EX_SOFTWARE, "elf_begin() failed: %s.", elf_errmsg(-1));
+
+ if ((pEhdr = elf32_newehdr(pElf)) == NULL)
+ errx(EX_SOFTWARE, "elf32_newehdr() failed: %s", elf_errmsg(-1));
+
+ pEhdr->e_ident[EI_CLASS] = ELFCLASS32; // Defined by Intel architecture
+ pEhdr->e_ident[EI_DATA] = ELFDATA2LSB; // Defined by Intel architecture
+ pEhdr->e_machine = EM_386; // Intel architecture
+ pEhdr->e_type = ET_REL; // Relocatable file (object file)
+ pEhdr->e_shstrndx = _shstrtab; // Point to the shstrtab section
+
+ // Create the section "default section header string table (.shstrtab)"
+ if ((pScn = elf_newscn(pElf)) == NULL)
+ errx(EX_SOFTWARE, "elf_newdata() failed: %s.", elf_errmsg(-1));
+ if ((pData = elf_newdata(pScn)) == NULL)
+ errx(EX_SOFTWARE, "elf_newdata() failed: %s.", elf_errmsg(-1));
+
+ pData->d_align = 1;
+ pData->d_buf = (void *) defaultStrTable;
+ pData->d_type = ELF_T_BYTE;
+ pData->d_size = defaultStrTableLen;
+
+ if ((pShdr = elf32_getshdr(pScn)) == NULL)
+ errx(EX_SOFTWARE, "elf32_etshdr() failed: %s.", elf_errmsg(-1));
+
+ pShdr->sh_name = _shstrtab_offset; // Point to the name of the section
+ pShdr->sh_type = SHT_STRTAB;
+ pShdr->sh_flags = 0;
+
+ // Create the section ".strtab"
+ if ((pScn = elf_newscn(pElf)) == NULL)
+ errx(EX_SOFTWARE, "elf_newdata() failed: %s.", elf_errmsg(-1));
+ if ((pData = elf_newdata(pScn)) == NULL)
+ errx(EX_SOFTWARE, "elf_newdata() failed: %s.", elf_errmsg(-1));
+
+ const char strtab[] = {0, 'g', 'e', 'n', 'e', 'r', 'a', 't', 'e', 'd', '.','x', 0, '_', 's', 't', 'a', 'r', 't', 0};
+
+ pData->d_align = 1;
+ pData->d_buf = (void *) strtab;
+ pData->d_type = ELF_T_BYTE;
+ pData->d_size = sizeof(strtab);
+
+ if ((pShdr = elf32_getshdr(pScn)) == NULL)
+ errx(EX_SOFTWARE, "elf32_etshdr() failed: %s.", elf_errmsg(-1));
+
+ pShdr->sh_name = _strtab_offset;
+ pShdr->sh_type = SHT_STRTAB;
+ pShdr->sh_flags = 0;
+
+ // Create the section ".symtab"
+ if ((pScn = elf_newscn(pElf)) == NULL)
+ errx(EX_SOFTWARE, "elf_newdata() failed: %s.", elf_errmsg(-1));
+ if ((pData = elf_newdata(pScn)) == NULL)
+ errx(EX_SOFTWARE, "elf_newdata() failed: %s.", elf_errmsg(-1));
+
+ Elf32_Sym x[4];
+
+ // Definition of the undefined section (this must be the first item by the definition of TIS ELF)
+ x[0].st_name = 0;
+ x[0].st_value = 0;
+ x[0].st_size = 0;
+ x[0].st_info = 0;
+ x[0].st_other = 0;
+ x[0].st_shndx = SHN_UNDEF;
+
+ // Definition of the name of the source file (this must be the second item by the definition in TIS ELF)
+ x[1].st_name = 1;
+ x[1].st_value = 0;
+ x[1].st_size = 0;
+ x[1].st_info = ELF32_ST_INFO(STB_LOCAL, STT_FILE); // This is the value that st_info must have (because of TIS ELF)
+ x[1].st_other = 0;
+ x[1].st_shndx = SHN_ABS; // The section where the symbol is
+
+ // Definition of the ".text" section as a section in the ".symtab" section
+ x[2].st_name = 0;
+ x[2].st_value = 0;
+ x[2].st_size = 0;
+ x[2].st_info = ELF32_ST_INFO(STB_LOCAL, STT_SECTION);
+ x[2].st_other = 0;
+ x[2].st_shndx = _text; // The section where the symbol is
+
+ // Definition of the "_start" symbol
+ x[3].st_name = 13; // Offset in the "strtab" section where the name start
+ x[3].st_value = 0;
+ x[3].st_size = 0;
+ x[3].st_info = ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE);
+ x[3].st_other = 0;
+ x[3].st_shndx = _text; // The section where the symbol is
+
+ pData->d_align = 4;
+ pData->d_buf = (void *) x;
+ pData->d_type = ELF_T_BYTE;
+ pData->d_size = sizeof(x);
+
+ if ((pShdr = elf32_getshdr(pScn)) == NULL)
+ errx(EX_SOFTWARE, "elf32_etshdr() failed: %s.", elf_errmsg(-1));
+
+ pShdr->sh_name = _symtab_offset; // Point to the name of the section
+ pShdr->sh_type = SHT_SYMTAB;
+ pShdr->sh_flags = 0;
+ pShdr->sh_link = _strtab; // point to the section .strtab (the section that contain the strings)
+ pShdr->sh_info = ELF32_ST_INFO(STB_LOCAL, 3); // the second argument is beause of TIS ELF (One greater than the symbol table index of the last local symbol (binding STB_LOCAL))
+
+ // Create many sections named .text
+ for (int i = 0; i < 70000; ++i) {
+ if ((pScn = elf_newscn(pElf)) == NULL)
+ errx(EX_SOFTWARE, "elf_newdata() failed: %s.", elf_errmsg(-1));
+ if ((pData = elf_newdata(pScn)) == NULL)
+ errx(EX_SOFTWARE, "elf_newdata() failed: %s.", elf_errmsg(-1));
+
+ pData->d_align = 4;
+ pData->d_buf = (void *)TEXT_CONTENTS;
+ pData->d_type = ELF_T_BYTE;
+ pData->d_size = sizeof(TEXT_CONTENTS);
+
+ if ((pShdr = elf32_getshdr(pScn)) == NULL)
+ errx(EX_SOFTWARE, "elf32_etshdr() failed: %s.", elf_errmsg(-1));
+
+ pShdr->sh_name = _text_offset;
+ pShdr->sh_type = SHT_PROGBITS;
+ pShdr->sh_flags = SHF_ALLOC | SHF_EXECINSTR;
+ }
+
+ // Update the sections internally
+ if (elf_update(pElf, ELF_C_NULL) < 0)
+ errx(EX_SOFTWARE, "elf_update(NULL) failed: %s.", elf_errmsg(-1));
+ // Write the object file
+ if (elf_update(pElf, ELF_C_WRITE) < 0)
+ errx(EX_SOFTWARE, "elf_update() failed: %s.", elf_errmsg(-1));
+ // Close all handles
+ elf_end(pElf);
+ close(FileDes);
+ printf("Generated file: %s\n", OUTFILE);
+
+ return 0;
+}
+
+++ /dev/null
-#!/usr/bin/env python
-#-------------------------------------------------------------------------------
-# tests/run_all_unittests.py
-#
-# Run all unit tests (alternative to running 'python -m unittest discover ...')
-#
-# Eli Bendersky (eliben@gmail.com)
-# This code is in the public domain
-#-------------------------------------------------------------------------------
-from unittest import TestLoader, TextTestRunner
-
-
-if __name__ == '__main__':
- try:
- tests = TestLoader().discover('tests', 'test*.py', 'tests')
- TextTestRunner().run(tests)
- except ImportError as err:
- print err
- print '!! Please execute from the root directory of pyelfutils'
-
+++ /dev/null
-#!/usr/bin/env python
-#-------------------------------------------------------------------------------
-# tests/run_readelf_tests.py
-#
-# Automatic test runner for elftools & readelf
-#
-# Eli Bendersky (eliben@gmail.com)
-# This code is in the public domain
-#-------------------------------------------------------------------------------
-import os, sys
-import re
-from difflib import SequenceMatcher
-import logging
-import subprocess
-import tempfile
-import platform
-
-
-# Create a global logger object
-#
-testlog = logging.getLogger('run_tests')
-testlog.setLevel(logging.DEBUG)
-testlog.addHandler(logging.StreamHandler(sys.stdout))
-
-
-def discover_testfiles(rootdir):
- """ Discover test files in the given directory. Yield them one by one.
- """
- for filename in os.listdir(rootdir):
- _, ext = os.path.splitext(filename)
- if ext == '.elf':
- yield os.path.join(rootdir, filename)
-
-
-def run_exe(exe_path, args):
- """ Runs the given executable as a subprocess, given the
- list of arguments. Captures its return code (rc) and stdout and
- returns a pair: rc, stdout_str
- """
- popen_cmd = [exe_path] + args
- if os.path.splitext(exe_path)[1] == '.py':
- popen_cmd.insert(0, 'python')
- proc = subprocess.Popen(popen_cmd, stdout=subprocess.PIPE)
- proc_stdout = proc.communicate()[0]
- return proc.returncode, proc_stdout
-
-
-def run_test_on_file(filename):
- """ Runs a test on the given input filename. Return True if all test
- runs succeeded.
- """
- success = True
- testlog.info("Running test on file '%s'" % filename)
- for option in [
- '-e', '-s', '-r', '-x.text', '-p.shstrtab',
- '--debug-dump=info', '--debug-dump=decodedline',
- '--debug-dump=frames', '--debug-dump=frames-interp']:
- testlog.info("..option='%s'" % option)
- # stdouts will be a 2-element list: output of readelf and output
- # of scripts/readelf.py
- stdouts = []
- for exe_path in ['readelf', 'scripts/readelf.py']:
- args = [option, filename]
- testlog.info("....executing: '%s %s'" % (
- exe_path, ' '.join(args)))
- rc, stdout = run_exe(exe_path, args)
- if rc != 0:
- testlog.error("@@ aborting - '%s' returned '%s'" % (exe_path, rc))
- return False
- stdouts.append(stdout)
- testlog.info('....comparing output...')
- rc, errmsg = compare_output(*stdouts)
- if rc:
- testlog.info('.......................SUCCESS')
- else:
- success = False
- testlog.info('.......................FAIL')
- testlog.info('@@ ' + errmsg)
- dump_output_to_temp_files(*stdouts)
- return success
-
-
-def compare_output(s1, s2):
- """ Compare stdout strings s1 and s2.
- s1 is from readelf, s2 from elftools readelf.py
- Return pair success, errmsg. If comparison succeeds, success is True
- and errmsg is empty. Otherwise success is False and errmsg holds a
- description of the mismatch.
-
- Note: this function contains some rather horrible hacks to ignore
- differences which are not important for the verification of pyelftools.
- This is due to some intricacies of binutils's readelf which pyelftools
- doesn't currently implement, or silly inconsistencies in the output of
- readelf, which I was reluctant to replicate.
- Read the documentation for more details.
- """
- def prepare_lines(s):
- return [line for line in s.lower().splitlines() if line.strip() != '']
- def filter_readelf_lines(lines):
- filter_out = False
- for line in lines:
- if 'of the .eh_frame section' in line:
- filter_out = True
- elif 'of the .debug_frame section' in line:
- filter_out = False
- if not filter_out:
- if not line.startswith('unknown: length'):
- yield line
-
- lines1 = prepare_lines(s1)
- lines2 = prepare_lines(s2)
-
- lines1 = list(filter_readelf_lines(lines1))
-
- flag_after_symtable = False
-
- if len(lines1) != len(lines2):
- return False, 'Number of lines different: %s vs %s' % (
- len(lines1), len(lines2))
-
- for i in range(len(lines1)):
- if 'symbol table' in lines1[i]:
- flag_after_symtable = True
-
- # Compare ignoring whitespace
- lines1_parts = lines1[i].split()
- lines2_parts = lines2[i].split()
- if ''.join(lines1_parts) != ''.join(lines2_parts):
- ok = False
- sm = SequenceMatcher()
- sm.set_seqs(lines1[i], lines2[i])
- changes = sm.get_opcodes()
- if flag_after_symtable:
- # Detect readelf's adding @ with lib and version after
- # symbol name.
- if ( len(changes) == 2 and changes[1][0] == 'delete' and
- lines1[i][changes[1][1]] == '@'):
- ok = True
- elif 'at_const_value' in lines1[i]:
- # On 32-bit machines, readelf doesn't correctly represent
- # some boundary LEB128 numbers
- num2 = int(lines2_parts[-1])
- if num2 <= -2**31 and '32' in platform.architecture()[0]:
- ok = True
- elif 'os/abi' in lines1[i]:
- if 'unix - gnu' in lines1[i] and 'unix - linux' in lines2[i]:
- ok = True
- else:
- for s in ('t (tls)', 'l (large)'):
- if s in lines1[i] or s in lines2[i]:
- ok = True
- break
- if not ok:
- errmsg = 'Mismatch on line #%s:\n>>%s<<\n>>%s<<\n' % (
- i, lines1[i], lines2[i])
- return False, errmsg
- return True, ''
-
-
-def dump_output_to_temp_files(*args):
- """ Dumps the output strings given in 'args' to temp files: one for each
- arg.
- """
- for i, s in enumerate(args):
- fd, path = tempfile.mkstemp(
- prefix='out' + str(i + 1) + '_',
- suffix='.stdout')
- file = os.fdopen(fd, 'w')
- file.write(s)
- file.close()
- testlog.info('@@ Output #%s dumped to file: %s' % (i + 1, path))
-
-
-def die(msg):
- testlog.error('Error: %s' % msg)
- sys.exit(1)
-
-
-def is_in_rootdir():
- """ Check whether the current dir is the root dir of pyelftools
- """
- dirstuff = os.listdir('.')
- return 'tests' in dirstuff and 'elftools' in dirstuff
-
-
-def main():
- if not is_in_rootdir():
- die('Please run me from the root dir of pyelftools!')
-
- # If file names are given as command-line arguments, only these files
- # are taken as inputs. Otherwise, autodiscovery is performed.
- #
- if len(sys.argv) > 1:
- filenames = sys.argv[1:]
- else:
- filenames = list(discover_testfiles('tests/testfiles'))
-
- success = True
- for filename in filenames:
- success = success and run_test_on_file(filename)
-
- if success:
- testlog.info('\nConclusion: SUCCESS')
- else:
- testlog.info('\nConclusion: FAIL')
-
-
-if __name__ == '__main__':
- #import os
- #os.chdir('..')
- main()
- #testlog.info(list(discover_testfiles('tests/testfiles')))
- #print run_exe('scripts/readelf.py', ['-h', 'tests/testfiles/z32.o.elf'])
-
-
-
-
+++ /dev/null
-import sys, unittest
-from cStringIO import StringIO
-
-sys.path.extend(['.', '..'])
-from elftools.dwarf.callframe import (
- CallFrameInfo, CIE, FDE, instruction_name, CallFrameInstruction,
- RegisterRule)
-from elftools.dwarf.structs import DWARFStructs
-from elftools.dwarf.descriptions import (describe_CFI_instructions,
- set_global_machine_arch)
-
-
-class TestCallFrame(unittest.TestCase):
- def assertInstruction(self, instr, name, args):
- self.assertIsInstance(instr, CallFrameInstruction)
- self.assertEqual(instruction_name(instr.opcode), name)
- self.assertEqual(instr.args, args)
-
- def test_spec_sample_d6(self):
- # D.6 sample in DWARFv3
- s = StringIO()
- data = ('' +
- # first comes the CIE
- '\x20\x00\x00\x00' + # length
- '\xff\xff\xff\xff' + # CIE_id
- '\x03\x00\x04\x7c' + # version, augmentation, caf, daf
- '\x08' + # return address
- '\x0c\x07\x00' +
- '\x08\x00' +
- '\x07\x01' +
- '\x07\x02' +
- '\x07\x03' +
- '\x08\x04' +
- '\x08\x05' +
- '\x08\x06' +
- '\x08\x07' +
- '\x09\x08\x01' +
- '\x00' +
-
- # then comes the FDE
- '\x28\x00\x00\x00' + # length
- '\x00\x00\x00\x00' + # CIE_pointer (to CIE at 0)
- '\x44\x33\x22\x11' + # initial_location
- '\x54\x00\x00\x00' + # address range
- '\x41' +
- '\x0e\x0c' + '\x41' +
- '\x88\x01' + '\x41' +
- '\x86\x02' + '\x41' +
- '\x0d\x06' + '\x41' +
- '\x84\x03' + '\x4b' +
- '\xc4' + '\x41' +
- '\xc6' +
- '\x0d\x07' + '\x41' +
- '\xc8' + '\x41' +
- '\x0e\x00' +
- '\x00\x00'
- )
- s.write(data)
-
- structs = DWARFStructs(little_endian=True, dwarf_format=32, address_size=4)
- cfi = CallFrameInfo(s, len(data), structs)
- entries = cfi.get_entries()
-
- self.assertEqual(len(entries), 2)
- self.assertIsInstance(entries[0], CIE)
- self.assertEqual(entries[0]['length'], 32)
- self.assertEqual(entries[0]['data_alignment_factor'], -4)
- self.assertEqual(entries[0]['return_address_register'], 8)
- self.assertEqual(len(entries[0].instructions), 11)
- self.assertInstruction(entries[0].instructions[0],
- 'DW_CFA_def_cfa', [7, 0])
- self.assertInstruction(entries[0].instructions[8],
- 'DW_CFA_same_value', [7])
- self.assertInstruction(entries[0].instructions[9],
- 'DW_CFA_register', [8, 1])
-
- self.assertTrue(isinstance(entries[1], FDE))
- self.assertEqual(entries[1]['length'], 40)
- self.assertEqual(entries[1]['CIE_pointer'], 0)
- self.assertEqual(entries[1]['address_range'], 84)
- self.assertIs(entries[1].cie, entries[0])
- self.assertEqual(len(entries[1].instructions), 21)
- self.assertInstruction(entries[1].instructions[0],
- 'DW_CFA_advance_loc', [1])
- self.assertInstruction(entries[1].instructions[1],
- 'DW_CFA_def_cfa_offset', [12])
- self.assertInstruction(entries[1].instructions[9],
- 'DW_CFA_offset', [4, 3])
- self.assertInstruction(entries[1].instructions[18],
- 'DW_CFA_def_cfa_offset', [0])
- self.assertInstruction(entries[1].instructions[20],
- 'DW_CFA_nop', [])
-
- # Now let's decode it...
- decoded_CIE = entries[0].get_decoded()
- self.assertEqual(decoded_CIE.reg_order, list(range(9)))
- self.assertEqual(len(decoded_CIE.table), 1)
- self.assertEqual(decoded_CIE.table[0]['cfa'].reg, 7)
- self.assertEqual(decoded_CIE.table[0]['pc'], 0)
- self.assertEqual(decoded_CIE.table[0]['cfa'].offset, 0)
- self.assertEqual(decoded_CIE.table[0][4].type, RegisterRule.SAME_VALUE)
- self.assertEqual(decoded_CIE.table[0][8].type, RegisterRule.REGISTER)
- self.assertEqual(decoded_CIE.table[0][8].arg, 1)
-
- decoded_FDE = entries[1].get_decoded()
- self.assertEqual(decoded_FDE.reg_order, list(range(9)))
- self.assertEqual(decoded_FDE.table[0]['cfa'].reg, 7)
- self.assertEqual(decoded_FDE.table[0]['cfa'].offset, 0)
- self.assertEqual(decoded_FDE.table[0]['pc'], 0x11223344)
- self.assertEqual(decoded_FDE.table[0][8].type, RegisterRule.REGISTER)
- self.assertEqual(decoded_FDE.table[0][8].arg, 1)
- self.assertEqual(decoded_FDE.table[1]['cfa'].reg, 7)
- self.assertEqual(decoded_FDE.table[1]['cfa'].offset, 12)
- self.assertEqual(decoded_FDE.table[2][8].type, RegisterRule.OFFSET)
- self.assertEqual(decoded_FDE.table[2][8].arg, -4)
- self.assertEqual(decoded_FDE.table[2][4].type, RegisterRule.SAME_VALUE)
- self.assertEqual(decoded_FDE.table[5]['pc'], 0x11223344 + 20)
- self.assertEqual(decoded_FDE.table[5][4].type, RegisterRule.OFFSET)
- self.assertEqual(decoded_FDE.table[5][4].arg, -12)
- self.assertEqual(decoded_FDE.table[6]['pc'], 0x11223344 + 64)
- self.assertEqual(decoded_FDE.table[9]['pc'], 0x11223344 + 76)
-
- def test_describe_CFI_instructions(self):
- # The data here represents a single CIE
- data = ('' +
- '\x16\x00\x00\x00' + # length
- '\xff\xff\xff\xff' + # CIE_id
- '\x03\x00\x04\x7c' + # version, augmentation, caf, daf
- '\x08' + # return address
- '\x0c\x07\x02' +
- '\x10\x02\x07\x03\x01\x02\x00\x00\x06\x06')
- s = StringIO(data)
-
- structs = DWARFStructs(little_endian=True, dwarf_format=32, address_size=4)
- cfi = CallFrameInfo(s, len(data), structs)
- entries = cfi.get_entries()
-
- set_global_machine_arch('x86')
- self.assertEqual(describe_CFI_instructions(entries[0]),
- ( ' DW_CFA_def_cfa: r7 (edi) ofs 2\n' +
- ' DW_CFA_expression: r2 (edx) (DW_OP_addr: 201; DW_OP_deref; DW_OP_deref)\n'))
-
-
-if __name__ == '__main__':
- unittest.main()
-
-
+++ /dev/null
-import sys, unittest
-from cStringIO import StringIO
-
-sys.path.extend(('..', '.'))
-from elftools.dwarf.descriptions import ExprDumper, set_global_machine_arch
-from elftools.dwarf.structs import DWARFStructs
-
-
-class TestExprDumper(unittest.TestCase):
- structs32 = DWARFStructs(
- little_endian=True,
- dwarf_format=32,
- address_size=4)
-
- def setUp(self):
- self.visitor = ExprDumper(self.structs32)
- set_global_machine_arch('x64')
-
- def test_basic_single(self):
- self.visitor.process_expr([0x1b])
- self.assertEqual(self.visitor.get_str(),
- 'DW_OP_div')
-
- self.setUp()
- self.visitor.process_expr([0x74, 0x82, 0x01])
- self.assertEqual(self.visitor.get_str(),
- 'DW_OP_breg4 (rsi): 130')
-
- self.setUp()
- self.visitor.process_expr([0x91, 0x82, 0x01])
- self.assertEqual(self.visitor.get_str(),
- 'DW_OP_fbreg: 130')
-
- self.setUp()
- self.visitor.process_expr([0x51])
- self.assertEqual(self.visitor.get_str(),
- 'DW_OP_reg1 (rdx)')
-
- self.setUp()
- self.visitor.process_expr([0x90, 16])
- self.assertEqual(self.visitor.get_str(),
- 'DW_OP_regx: 16 (rip)')
-
- self.setUp()
- self.visitor.process_expr([0x9d, 0x8f, 0x0A, 0x90, 0x01])
- self.assertEqual(self.visitor.get_str(),
- 'DW_OP_bit_piece: 1295 144')
-
- def test_basic_sequence(self):
- self.visitor.process_expr([0x03, 0x01, 0x02, 0, 0, 0x06, 0x06])
- self.assertEqual(self.visitor.get_str(),
- 'DW_OP_addr: 201; DW_OP_deref; DW_OP_deref')
-
- self.setUp()
- self.visitor.process_expr([0x15, 0xFF, 0x0b, 0xf1, 0xff])
- self.assertEqual(self.visitor.get_str(),
- 'DW_OP_pick: 255; DW_OP_const2s: -15')
-
- self.setUp()
- self.visitor.process_expr([0x1d, 0x1e, 0x1d, 0x1e, 0x1d, 0x1e])
- self.assertEqual(self.visitor.get_str(),
- 'DW_OP_mod; DW_OP_mul; DW_OP_mod; DW_OP_mul; DW_OP_mod; DW_OP_mul')
-
-
-if __name__ == '__main__':
- unittest.main()
-
-
+++ /dev/null
-import sys, unittest
-from cStringIO import StringIO
-
-sys.path.extend(['.', '..'])
-from elftools.dwarf.lineprogram import LineProgram, LineState, LineProgramEntry
-from elftools.dwarf.structs import DWARFStructs
-from elftools.dwarf.constants import *
-
-
-class TestLineProgram(unittest.TestCase):
- def _make_program_in_stream(self, stream):
- """ Create a LineProgram from the given program encoded in a stream
- """
- ds = DWARFStructs(little_endian=True, dwarf_format=32, address_size=4)
- header = ds.Dwarf_lineprog_header.parse(
- '\x04\x10\x00\x00' + # initial lenght
- '\x03\x00' + # version
- '\x20\x00\x00\x00' + # header length
- '\x01\x01\x01\x0F' + # flags
- '\x0A' + # opcode_base
- '\x00\x01\x04\x08\x0C\x01\x01\x01\x00' + # standard_opcode_lengths
- # 2 dir names followed by a NULL
- '\x61\x62\x00\x70\x00\x00' +
- # a file entry
- '\x61\x72\x00\x0C\x0D\x0F' +
- # and another entry
- '\x45\x50\x51\x00\x86\x12\x07\x08' +
- # followed by NULL
- '\x00')
-
- lp = LineProgram(header, stream, ds, 0, len(stream.getvalue()))
- return lp
-
- def assertLineState(self, state, **kwargs):
- """ Assert that the state attributes specified in kwargs have the given
- values (the rest are default).
- """
- for k, v in kwargs.iteritems():
- self.assertEqual(getattr(state, k), v)
-
- def test_spec_sample_59(self):
- # Sample in figure 59 of DWARFv3
- s = StringIO()
- s.write(
- '\x02\xb9\x04' +
- '\x0b' +
- '\x38' +
- '\x82' +
- '\x73' +
- '\x02\x02' +
- '\x00\x01\x01')
-
- lp = self._make_program_in_stream(s)
- linetable = lp.get_entries()
-
- self.assertEqual(len(linetable), 7)
- self.assertIs(linetable[0].state, None) # doesn't modify state
- self.assertEqual(linetable[0].command, DW_LNS_advance_pc)
- self.assertEqual(linetable[0].args, [0x239])
- self.assertLineState(linetable[1].state, address=0x239, line=3)
- self.assertEqual(linetable[1].command, 0xb)
- self.assertEqual(linetable[1].args, [2, 0])
- self.assertLineState(linetable[2].state, address=0x23c, line=5)
- self.assertLineState(linetable[3].state, address=0x244, line=6)
- self.assertLineState(linetable[4].state, address=0x24b, line=7, end_sequence=False)
- self.assertEqual(linetable[5].command, DW_LNS_advance_pc)
- self.assertEqual(linetable[5].args, [2])
- self.assertLineState(linetable[6].state, address=0x24d, line=7, end_sequence=True)
-
- def test_spec_sample_60(self):
- # Sample in figure 60 of DWARFv3
- s = StringIO()
- s.write(
- '\x09\x39\x02' +
- '\x0b' +
- '\x09\x03\x00' +
- '\x0b' +
- '\x09\x08\x00' +
- '\x0a' +
- '\x09\x07\x00' +
- '\x0a' +
- '\x09\x02\x00' +
- '\x00\x01\x01')
-
- lp = self._make_program_in_stream(s)
- linetable = lp.get_entries()
-
- self.assertEqual(len(linetable), 10)
- self.assertIs(linetable[0].state, None) # doesn't modify state
- self.assertEqual(linetable[0].command, DW_LNS_fixed_advance_pc)
- self.assertEqual(linetable[0].args, [0x239])
- self.assertLineState(linetable[1].state, address=0x239, line=3)
- self.assertLineState(linetable[3].state, address=0x23c, line=5)
- self.assertLineState(linetable[5].state, address=0x244, line=6)
- self.assertLineState(linetable[7].state, address=0x24b, line=7, end_sequence=False)
- self.assertLineState(linetable[9].state, address=0x24d, line=7, end_sequence=True)
-
-
-if __name__ == '__main__':
- unittest.main()
-
+++ /dev/null
-import sys, unittest
-
-sys.path.extend(['.', '..'])
-from elftools.dwarf.structs import DWARFStructs
-
-
-class TestDWARFStructs(unittest.TestCase):
- def test_lineprog_header(self):
- ds = DWARFStructs(little_endian=True, dwarf_format=32, address_size=4)
-
- c = ds.Dwarf_lineprog_header.parse(
- '\x04\x10\x00\x00' + # initial lenght
- '\x05\x02' + # version
- '\x20\x00\x00\x00' + # header length
- '\x05\x10\x40\x50' + # until and including line_range
- '\x06' + # opcode_base
- '\x00\x01\x04\x08\x0C' + # standard_opcode_lengths
- # 2 dir names followed by a NULL
- '\x61\x62\x00\x70\x00\x00' +
- # a file entry
- '\x61\x72\x00\x0C\x0D\x0F' +
- # and another entry
- '\x45\x50\x51\x00\x86\x12\x07\x08' +
- # followed by NULL
- '\x00')
-
- self.assertEqual(c.version, 0x205)
- self.assertEqual(c.opcode_base, 6)
- self.assertEqual(c.standard_opcode_lengths, [0, 1, 4, 8, 12])
- self.assertEqual(c.include_directory, ['ab', 'p'])
- self.assertEqual(len(c.file_entry), 2)
- self.assertEqual(c.file_entry[0].name, 'ar')
- self.assertEqual(c.file_entry[1].name, 'EPQ')
- self.assertEqual(c.file_entry[1].dir_index, 0x12 * 128 + 6)
-
-
-if __name__ == '__main__':
- unittest.main()
-
+++ /dev/null
-import sys, unittest
-from cStringIO import StringIO
-from random import randint
-
-sys.path.extend(['.', '..'])
-from elftools.common.utils import (parse_cstring_from_stream,
- preserve_stream_pos)
-
-
-class Test_parse_cstring_from_stream(unittest.TestCase):
- def _make_random_string(self, n):
- return ''.join(chr(randint(32, 127)) for i in range(n))
-
- def test_small1(self):
- sio = StringIO('abcdefgh\x0012345')
- self.assertEqual(parse_cstring_from_stream(sio), 'abcdefgh')
- self.assertEqual(parse_cstring_from_stream(sio, 2), 'cdefgh')
- self.assertEqual(parse_cstring_from_stream(sio, 8), '')
-
- def test_small2(self):
- sio = StringIO('12345\x006789\x00abcdefg\x00iii')
- self.assertEqual(parse_cstring_from_stream(sio), '12345')
- self.assertEqual(parse_cstring_from_stream(sio, 5), '')
- self.assertEqual(parse_cstring_from_stream(sio, 6), '6789')
-
- def test_large1(self):
- text = 'i' * 400 + '\x00' + 'bb'
- sio = StringIO(text)
- self.assertEqual(parse_cstring_from_stream(sio), 'i' * 400)
- self.assertEqual(parse_cstring_from_stream(sio, 150), 'i' * 250)
-
- def test_large2(self):
- text = self._make_random_string(5000) + '\x00' + 'jujajaja'
- sio = StringIO(text)
- self.assertEqual(parse_cstring_from_stream(sio), text[:5000])
- self.assertEqual(parse_cstring_from_stream(sio, 2348), text[2348:5000])
-
-
-class Test_preserve_stream_pos(object):
- def test_basic(self):
- sio = StringIO('abcdef')
- with preserve_stream_pos(sio):
- sio.seek(4)
- self.assertEqual(stream.tell(), 0)
-
- sio.seek(5)
- with preserve_stream_pos(sio):
- sio.seek(0)
- self.assertEqual(stream.tell(), 5)
-
-
-if __name__ == '__main__':
- unittest.main()
-
-
-
+++ /dev/null
-CFLAGS = -Wall --std=c99
-# This is where `make install` from libelf places its stuff
-LIBELF_HEADERS = /usr/local/include/libelf/
-LIBELF_LIBS = /usr/local/lib/
-
-all: elf_creator
-
-elf_creator: elf_creator.c
- gcc $(CFLAGS) -o elf_creator elf_creator.c \
- -I$(LIBELF_HEADERS) -L$(LIBELF_LIBS) -Wl,-rpath,$(LIBELF_LIBS) -lelf
-
-clean:
- rm -f *.o
- rm -f *.so
- rm -f *.a
- rm -f elf_creator
-
-
+++ /dev/null
-Some utilities that use libelf to create synthetic ELF files
-
+++ /dev/null
-/* Loosely based on the code in a Knol by Roberto Garcia Lopez:
-**
-** http://knol.google.com/k/roberto-garca-lpez/creating-elf-relocatable-object-files/1ohwel4gqkcn2/3#
-**
-** Note: This file is released under the terms of the LGPL2 license.
-*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <libelf.h>
-#include <err.h>
-#include <sysexits.h>
-
-
-const char* OUTFILE = "generated.o";
-
-// Definition of the default string table section ".shstrtab"
-const char defaultStrTable[] =
-{
- /* offset 00 */ '\0', // The NULL section
- /* offset 01 */ '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', '\0',
- /* offset 11 */ '.', 's', 't', 'r', 't', 'a', 'b', '\0',
- /* offset 19 */ '.', 's', 'y', 'm', 't', 'a', 'b', '\0',
- /* offset 27 */ '.', 'c', 'o', 'm', 'm', 'e', 'n', 't', '\0',
- /* offset 36 */ '.', 'b', 's', 's', '\0',
- /* offset 41 */ '.', 'd', 'a', 't', 'a', '\0',
- /* offset 47 */ '.', 'r', 'e', 'l', '.', 't', 'e', 'x', 't', '\0',
- /* offset 57 */ '.', 't', 'e', 'x', 't', '\0'
-};
-
-const char defaultStrTableLen = sizeof(defaultStrTable);
-
-// Offsets of section names in the string table
-const char _shstrtab_offset = 1;
-const char _strtab_offset = 11;
-const char _symtab_offset = 19;
-const char _text_offset = 57;
-
-// Position of sections within the object file
-const char _shstrtab = 1;
-const char _strtab = 2;
-const char _symtab = 3;
-const char _text = 4;
-
-const char TEXT_CONTENTS[] = {0x91, 0x92, 0x93, 0x94};
-
-
-//----------------------------------------------------------------------------
-
-int main()
-{
- int FileDes;
- Elf *pElf;
- Elf32_Ehdr *pEhdr;
- Elf32_Shdr *pShdr;
- Elf_Scn *pScn;
- Elf_Data *pData;
-
- // Create the ELF header
- if (elf_version(EV_CURRENT) == EV_NONE) // It must appear before "elf_begin()"
- errx(EX_SOFTWARE, "ELF library initialization failed: %s", elf_errmsg(-1));
-
- if ((FileDes = open(OUTFILE, O_CREAT | O_WRONLY | O_TRUNC, 0777)) < 0)
- errx(EX_OSERR, "open \"%s\" failed", "compiled.o");
-
- if ((pElf = elf_begin(FileDes, ELF_C_WRITE, NULL)) == NULL) // 3rd argument is ignored for "ELF_C_WRITE"
- errx(EX_SOFTWARE, "elf_begin() failed: %s.", elf_errmsg(-1));
-
- if ((pEhdr = elf32_newehdr(pElf)) == NULL)
- errx(EX_SOFTWARE, "elf32_newehdr() failed: %s", elf_errmsg(-1));
-
- pEhdr->e_ident[EI_CLASS] = ELFCLASS32; // Defined by Intel architecture
- pEhdr->e_ident[EI_DATA] = ELFDATA2LSB; // Defined by Intel architecture
- pEhdr->e_machine = EM_386; // Intel architecture
- pEhdr->e_type = ET_REL; // Relocatable file (object file)
- pEhdr->e_shstrndx = _shstrtab; // Point to the shstrtab section
-
- // Create the section "default section header string table (.shstrtab)"
- if ((pScn = elf_newscn(pElf)) == NULL)
- errx(EX_SOFTWARE, "elf_newdata() failed: %s.", elf_errmsg(-1));
- if ((pData = elf_newdata(pScn)) == NULL)
- errx(EX_SOFTWARE, "elf_newdata() failed: %s.", elf_errmsg(-1));
-
- pData->d_align = 1;
- pData->d_buf = (void *) defaultStrTable;
- pData->d_type = ELF_T_BYTE;
- pData->d_size = defaultStrTableLen;
-
- if ((pShdr = elf32_getshdr(pScn)) == NULL)
- errx(EX_SOFTWARE, "elf32_etshdr() failed: %s.", elf_errmsg(-1));
-
- pShdr->sh_name = _shstrtab_offset; // Point to the name of the section
- pShdr->sh_type = SHT_STRTAB;
- pShdr->sh_flags = 0;
-
- // Create the section ".strtab"
- if ((pScn = elf_newscn(pElf)) == NULL)
- errx(EX_SOFTWARE, "elf_newdata() failed: %s.", elf_errmsg(-1));
- if ((pData = elf_newdata(pScn)) == NULL)
- errx(EX_SOFTWARE, "elf_newdata() failed: %s.", elf_errmsg(-1));
-
- const char strtab[] = {0, 'g', 'e', 'n', 'e', 'r', 'a', 't', 'e', 'd', '.','x', 0, '_', 's', 't', 'a', 'r', 't', 0};
-
- pData->d_align = 1;
- pData->d_buf = (void *) strtab;
- pData->d_type = ELF_T_BYTE;
- pData->d_size = sizeof(strtab);
-
- if ((pShdr = elf32_getshdr(pScn)) == NULL)
- errx(EX_SOFTWARE, "elf32_etshdr() failed: %s.", elf_errmsg(-1));
-
- pShdr->sh_name = _strtab_offset;
- pShdr->sh_type = SHT_STRTAB;
- pShdr->sh_flags = 0;
-
- // Create the section ".symtab"
- if ((pScn = elf_newscn(pElf)) == NULL)
- errx(EX_SOFTWARE, "elf_newdata() failed: %s.", elf_errmsg(-1));
- if ((pData = elf_newdata(pScn)) == NULL)
- errx(EX_SOFTWARE, "elf_newdata() failed: %s.", elf_errmsg(-1));
-
- Elf32_Sym x[4];
-
- // Definition of the undefined section (this must be the first item by the definition of TIS ELF)
- x[0].st_name = 0;
- x[0].st_value = 0;
- x[0].st_size = 0;
- x[0].st_info = 0;
- x[0].st_other = 0;
- x[0].st_shndx = SHN_UNDEF;
-
- // Definition of the name of the source file (this must be the second item by the definition in TIS ELF)
- x[1].st_name = 1;
- x[1].st_value = 0;
- x[1].st_size = 0;
- x[1].st_info = ELF32_ST_INFO(STB_LOCAL, STT_FILE); // This is the value that st_info must have (because of TIS ELF)
- x[1].st_other = 0;
- x[1].st_shndx = SHN_ABS; // The section where the symbol is
-
- // Definition of the ".text" section as a section in the ".symtab" section
- x[2].st_name = 0;
- x[2].st_value = 0;
- x[2].st_size = 0;
- x[2].st_info = ELF32_ST_INFO(STB_LOCAL, STT_SECTION);
- x[2].st_other = 0;
- x[2].st_shndx = _text; // The section where the symbol is
-
- // Definition of the "_start" symbol
- x[3].st_name = 13; // Offset in the "strtab" section where the name start
- x[3].st_value = 0;
- x[3].st_size = 0;
- x[3].st_info = ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE);
- x[3].st_other = 0;
- x[3].st_shndx = _text; // The section where the symbol is
-
- pData->d_align = 4;
- pData->d_buf = (void *) x;
- pData->d_type = ELF_T_BYTE;
- pData->d_size = sizeof(x);
-
- if ((pShdr = elf32_getshdr(pScn)) == NULL)
- errx(EX_SOFTWARE, "elf32_etshdr() failed: %s.", elf_errmsg(-1));
-
- pShdr->sh_name = _symtab_offset; // Point to the name of the section
- pShdr->sh_type = SHT_SYMTAB;
- pShdr->sh_flags = 0;
- pShdr->sh_link = _strtab; // point to the section .strtab (the section that contain the strings)
- pShdr->sh_info = ELF32_ST_INFO(STB_LOCAL, 3); // the second argument is beause of TIS ELF (One greater than the symbol table index of the last local symbol (binding STB_LOCAL))
-
- // Create many sections named .text
- for (int i = 0; i < 70000; ++i) {
- if ((pScn = elf_newscn(pElf)) == NULL)
- errx(EX_SOFTWARE, "elf_newdata() failed: %s.", elf_errmsg(-1));
- if ((pData = elf_newdata(pScn)) == NULL)
- errx(EX_SOFTWARE, "elf_newdata() failed: %s.", elf_errmsg(-1));
-
- pData->d_align = 4;
- pData->d_buf = (void *)TEXT_CONTENTS;
- pData->d_type = ELF_T_BYTE;
- pData->d_size = sizeof(TEXT_CONTENTS);
-
- if ((pShdr = elf32_getshdr(pScn)) == NULL)
- errx(EX_SOFTWARE, "elf32_etshdr() failed: %s.", elf_errmsg(-1));
-
- pShdr->sh_name = _text_offset;
- pShdr->sh_type = SHT_PROGBITS;
- pShdr->sh_flags = SHF_ALLOC | SHF_EXECINSTR;
- }
-
- // Update the sections internally
- if (elf_update(pElf, ELF_C_NULL) < 0)
- errx(EX_SOFTWARE, "elf_update(NULL) failed: %s.", elf_errmsg(-1));
- // Write the object file
- if (elf_update(pElf, ELF_C_WRITE) < 0)
- errx(EX_SOFTWARE, "elf_update() failed: %s.", elf_errmsg(-1));
- // Close all handles
- elf_end(pElf);
- close(FileDes);
- printf("Generated file: %s\n", OUTFILE);
-
- return 0;
-}
-