* DWARFInfo now doesn't receive a "dwarf class" argument, since it must infer it...
[pyelftools.git] / elftools / dwarf / dwarfinfo.py
1 #-------------------------------------------------------------------------------
2 # elftools: dwarf/dwarfinfo.py
3 #
4 # DWARFInfo - Main class for accessing DWARF debug information
5 #
6 # Eli Bendersky (eliben@gmail.com)
7 # This code is in the public domain
8 #-------------------------------------------------------------------------------
9 from collections import namedtuple
10
11 from ..common.exceptions import DWARFError
12 from ..common.utils import struct_parse, dwarf_assert
13 from .structs import DWARFStructs
14 from .compileunit import CompileUnit
15
16
17 # Describes a debug section in a stream: offset and size
18 #
19 DebugSectionLocator = namedtuple('DebugSectionLocator', 'offset size')
20
21
22 class DWARFInfo(object):
23 """ Creation: the constructor accepts a stream (file-like object) that
24 contains debug sections, along with locators (DebugSectionLocator)
25 of the required sections. In addition, little_endian is a boolean
26 parameter specifying endianity.
27 """
28 def __init__(self,
29 stream,
30 little_endian,
31 debug_info_loc,
32 debug_abbrev_loc,
33 debug_str_loc,
34 debug_line_loc):
35 self.stream = stream
36 self.debug_info_loc = debug_info_loc
37 self.debug_abbrev_loc = debug_abbrev_loc
38 self.debug_str_loc = debug_str_loc
39 self.debug_line_loc = debug_line_loc
40
41 self.little_endian = little_endian
42 self.dwarf_format = 32
43 self.structs = DWARFStructs(
44 little_endian=self.little_endian,
45 dwarf_format=self.dwarf_format)
46
47 # Populate the list with CUs found in debug_info
48 self._CU = self._parse_CUs()
49
50 def _parse_CUs(self):
51 """ Parse CU entries from debug_info.
52 """
53 offset = self.debug_info_loc.offset
54 section_boundary = self.debug_info_loc.offset + self.debug_info_loc.size
55 CUlist = []
56 while offset < section_boundary:
57 # Section 7.4 (32-bit and 64-bit DWARF Formats) of the DWARF spec v3
58 # states that the first 32-bit word of the CU header determines
59 # whether the CU is represented with 32-bit or 64-bit DWARF format.
60 #
61 # So we peek at the first byte in the CU header to determine its
62 # dwarf format. Based on it, we then create a new DWARFStructs
63 # instance suitable for this CU and use it to parse the rest.
64 #
65 initial_length = struct_parse(
66 self.structs.Dwarf_uint32(''), self.stream, offset)
67 if initial_length == 0xFFFFFFFF:
68 self.dwarf_format = 64
69 cu_structs = DWARFStructs(
70 little_endian=self.little_endian,
71 dwarf_format=self.dwarf_format)
72
73 cu_header = struct_parse(
74 self.structs.Dwarf_CU_header, self.stream, offset)
75 dwarf_assert(
76 self._is_supported_version(cu_header['version']),
77 "Expected supported DWARF version. Got '%s'" % cu_header['version'])
78 CUlist.append(CompileUnit(cu_header, cu_structs, None))
79 # Compute the offset of the next CU in the section. The unit_length
80 # field of the CU header contains its size not including the length
81 # field itself.
82 offset = ( offset +
83 cu_header['unit_length'] +
84 cu_structs.initial_lenght_field_size())
85 return CUlist
86
87 def _is_supported_version(self, version):
88 """ DWARF version supported by this parser
89 """
90 return 2 <= version <= 3
91