dwarf_format=32,
address_size=4)
- # Populate the list with CUs found in debug_info. For each CU only its
- # header is parsed immediately (the abbrev table isn't loaded before
- # it's being referenced by one of the CU's DIEs).
- # Since there usually aren't many CUs in a single object, this
- # shouldn't present a performance problem.
- #
- self._CU = self._parse_CUs()
+ # A list of CUs. Populated lazily when they're actually requested.
+ self._CUs = None
# Cache for abbrev tables: a dict keyed by offset
self._abbrevtable_cache = {}
def iter_CUs(self):
""" Yield all the compile units (CompileUnit objects) in the debug info
"""
- return iter(self._CU)
-
+ if self._CUs is None:
+ self._CUs = self._parse_CUs()
+ return iter(self._CUs)
+
def get_abbrev_table(self, offset):
""" Get an AbbrevTable from the given offset in the debug_abbrev
section.
"""
return parse_cstring_from_stream(self.debug_str_sec.stream, offset)
+ def line_program_for_CU(self, CU):
+ """ Given a CU object, fetch the line program it points to from the
+ .debug_line section.
+ If the CU doesn't point to a line program, return None.
+ """
+ # The line program is pointed to by the DW_AT_stmt_list attribute of
+ # the top DIE of a CU.
+ top_DIE = CU.get_top_DIE()
+ if 'DW_AT_stmt_list' in top_DIE.attributes:
+ return self._parse_line_program_at_offset(
+ top_DIE.attributes['DW_AT_stmt_list'].value, CU.structs)
+ else:
+ return None
+
#------ PRIVATE ------#
def _parse_CUs(self):
"""
return 2 <= version <= 3
- def _parse_line_programs(self):
- """ Parse line programs from debug_line
+ def _parse_line_program_at_offset(self, debug_line_offset, structs):
+ """ Given an offset to the .debug_line section, parse the line program
+ starting at this offset in the section and return it.
+ structs is the DWARFStructs object used to do this parsing.
"""
- offset = 0
- lineprograms = []
- while offset < self.debug_line_sec.size:
- # Similarly to CU parsing, peek at the initial_length field of the
- # header to figure out the DWARF format for it.
- initial_length = struct_parse(
- self.structs.Dwarf_uint32(''), self.debug_line_sec, offset)
- dwarf_format = 64 if initial_length == 0xFFFFFFFF else 32
+ lineprog_header = struct_parse(
+ structs.Dwarf_lineprog_header,
+ self.debug_line_sec.stream,
+ debug_line_offset)
- # Prepare the structs for this line program, based on its format
- # and the default endianness. The address_size plays no role for
- # line programs so we just give it a default value.
- lineprog_structs = DWARFStructs(
- little_endian=self.little_endian,
- dwarf_format=dwarf_format,
- address_size=4)
-
- lineprog_header = struct_parse(
- lineprog_structs.Dwarf_lineprog_header,
- self.debug_line_sec.stream,
- offset)
-
- lineprograms.append(LineProgram(
- header=lineprog_header,
- dwarfinfo=self,
- structs=lineprog_structs))
+ # Calculate the offset to the next line program (see DWARF 6.2.4)
+ end_offset = ( debug_line_offset + lineprog_header['unit_length'] +
+ structs.initial_length_field_size())
- # Calculate the offset to the next line program (see DWARF 6.2.4)
- offset += ( lineprog_header['unit_length'] +
- lineprog_structs.initial_length_field_size())
- return lineprograms
+ return LineProgram(
+ header=lineprog_header,
+ stream=self.debug_line_sec.stream,
+ structs=structs,
+ program_start_offset=self.debug_line_sec.stream.tell(),
+ program_end_offset=end_offset)