ea01db64da0fd2939a182bee3835833b136de7d0
1 #------------------------------------------------------------------------------
4 # Seva Alekseyev (sevaa@sprynet.com)
5 # This code is in the public domain
7 # The error that motivated this fix was in an iOS binary in Mach-O format. It
8 # had v2 DWARF data, but it was targeting a 64 bit architecture. Before the fix,
9 # pyelftools would assume that DW_FORM_ref_addr attribute took 4 bytes and
10 # misparse the DWARF data in the binary.
12 # Since pyelftools doesn't work with Mach-O files, I've taken a sample binary
13 # apart, and saved the three relevant sections - info, abbrev, and str as flat
14 # files. The metadata (the fact that it's targeting ARM64) is hard-coded, since
15 # the Mach-O header isn't preserved.
16 #------------------------------------------------------------------------------
21 from elftools
.dwarf
.dwarfinfo
import DWARFInfo
, DebugSectionDescriptor
, DwarfConfig
23 class TestRefAddrOnDWARFv2With64BitTarget(unittest
.TestCase
):
25 # Read the three saved sections as bytestreams
26 with
open(os
.path
.join('test', 'testfiles_for_unittests', 'arm64_on_dwarfv2.info.dat'), 'rb') as f
:
28 with
open(os
.path
.join('test', 'testfiles_for_unittests', 'arm64_on_dwarfv2.abbrev.dat'), 'rb') as f
:
30 with
open(os
.path
.join('test', 'testfiles_for_unittests', 'arm64_on_dwarfv2.str.dat'), 'rb') as f
:
33 # Parse the DWARF info
35 config
= DwarfConfig(little_endian
= True, default_address_size
= 8, machine_arch
= "ARM64"),
36 debug_info_sec
= DebugSectionDescriptor(io
.BytesIO(info
), '__debug_info', None, len(info
), 0),
37 debug_aranges_sec
= None,
38 debug_abbrev_sec
= DebugSectionDescriptor(io
.BytesIO(abbrev
), '__debug_abbrev', None, len(abbrev
), 0),
39 debug_frame_sec
= None,
41 debug_str_sec
= DebugSectionDescriptor(io
.BytesIO(str), '__debug_str', None, len(str), 0),
43 debug_ranges_sec
= None,
44 debug_line_sec
= None,
45 debug_pubtypes_sec
= None,
46 debug_pubnames_sec
= None,
48 debug_str_offsets_sec
=None,
49 debug_line_str_sec
=None,
52 CUs
= [cu
for cu
in di
.iter_CUs()]
53 # Locate a CU that I know has a reference in DW_FORM_ref_addr form
55 self
.assertEqual(CU
['version'], 2)
56 # Make sure pyelftools appreciates the difference between the target address size and DWARF inter-DIE offset size
57 self
.assertEqual(CU
.structs
.dwarf_format
, 32)
58 self
.assertEqual(CU
['address_size'], 8)
59 DIEs
= [die
for die
in CU
.iter_DIEs()]
60 # Before the patch, DIE #2 is misparsed, the current offset is off, the rest are misparsed too
61 self
.assertEqual(len(DIEs
), 15)
62 # It was 9 before the patch, which was wrong.
64 if __name__
== '__main__':