-
Notifications
You must be signed in to change notification settings - Fork 512
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
dwarf v4 debug types support #530
Open
driftregion
wants to merge
5
commits into
eliben:main
Choose a base branch
from
driftregion:dinkar/dwarf-v4-debug-types-support
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
eaf1174
Support for parsing .debug_types section introduced in DWARF version 4
c2a905c
add TI Code Composer Studio generated elf
driftregion 5df81dd
tweak dwarfdump to support TI DWARF4
driftregion 91f3e13
achieve dwarfdump consistency on new TI binaries
driftregion a612ffe
revert 'test/run_dwarfdump_tests.py'
driftregion File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,7 @@ | |
# This code is in the public domain | ||
#------------------------------------------------------------------------------- | ||
import os | ||
from collections import namedtuple | ||
from collections import namedtuple, OrderedDict | ||
from bisect import bisect_right | ||
|
||
from ..construct.lib.container import Container | ||
|
@@ -16,6 +16,7 @@ | |
parse_cstring_from_stream) | ||
from .structs import DWARFStructs | ||
from .compileunit import CompileUnit | ||
from .typeunit import TypeUnit | ||
from .abbrevtable import AbbrevTable | ||
from .lineprogram import LineProgram | ||
from .callframe import CallFrameInfo | ||
|
@@ -81,7 +82,8 @@ def __init__(self, | |
debug_loclists_sec, | ||
debug_rnglists_sec, | ||
debug_sup_sec, | ||
gnu_debugaltlink_sec | ||
gnu_debugaltlink_sec, | ||
debug_types_sec | ||
): | ||
""" config: | ||
A DwarfConfig object | ||
|
@@ -110,6 +112,7 @@ def __init__(self, | |
self.debug_rnglists_sec = debug_rnglists_sec | ||
self.debug_sup_sec = debug_sup_sec | ||
self.gnu_debugaltlink_sec = gnu_debugaltlink_sec | ||
self.debug_types_sec = debug_types_sec | ||
|
||
# Sets the supplementary_dwarfinfo to None. Client code can set this | ||
# to something else, typically a DWARFInfo file read from an ELFFile | ||
|
@@ -134,6 +137,9 @@ def __init__(self, | |
self._cu_cache = [] | ||
self._cu_offsets_map = [] | ||
|
||
# DWARF v4 type units by sig8 - OrderedDict created on Reference | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not sure what Do you mean to say it's lazily initialized the first time it's referenced? |
||
self._type_units_by_sig = None | ||
|
||
@property | ||
def has_debug_info(self): | ||
""" Return whether this contains debug information. | ||
|
@@ -167,6 +173,35 @@ def get_DIE_from_refaddr(self, refaddr, cu=None): | |
cu = self.get_CU_containing(refaddr) | ||
return cu.get_DIE_from_refaddr(refaddr) | ||
|
||
def get_DIE_by_sig8(self, sig8): | ||
""" Find and return a DIE referenced by its type signature. | ||
sig8: | ||
The 8 byte signature (as a 64-bit unsigned integer) | ||
|
||
Returns the DIE with the given type signature by searching | ||
for the Type Unit with the matching signature then finding | ||
the DIE at the offset given by the type_die field in the | ||
|
||
Type Unit header. | ||
Signatures are an 64-bit unsigned integers computed by the | ||
DWARF producer as specified in the DWARF standard. Each | ||
Type Unit contains one signature and the offset to the | ||
corresponding DW_AT_type DIE in its unit header. | ||
Describing a type can generate several DIEs. By moving | ||
a DIE and its related DIEs to a Type Unit and generating | ||
a hash of the DIEs and attributes in a flattened form | ||
multiple Compile Units in a linked object can reference | ||
the same DIE in the overall DWARF structure. | ||
|
||
In DWARF v4 type units are identified by their appearance in the | ||
.debug_types section. | ||
""" | ||
self._parse_debug_types() | ||
tu = self._type_units_by_sig.get(sig8) | ||
if tu is None: | ||
raise KeyError("Signature %016x not found in .debug_types" % sig8) | ||
return tu._get_cached_DIE(tu.tu_offset + tu['type_offset']) | ||
|
||
def get_CU_containing(self, refaddr): | ||
""" Find the CU that includes the given reference address in the | ||
.debug_info section. | ||
|
@@ -226,6 +261,11 @@ def iter_CUs(self): | |
""" | ||
return self._parse_CUs_iter() | ||
|
||
def iter_TUs(self): | ||
"""Yield all the compile units (CompileUnit objects) in the debug_types | ||
""" | ||
return self.parse_TUs_iter() | ||
|
||
def get_abbrev_table(self, offset): | ||
""" Get an AbbrevTable from the given offset in the debug_abbrev | ||
section. | ||
|
@@ -414,11 +454,49 @@ def _parse_CUs_iter(self, offset=0): | |
# Compute the offset of the next CU in the section. The unit_length | ||
# field of the CU header contains its size not including the length | ||
# field itself. | ||
offset = ( offset + | ||
cu['unit_length'] + | ||
cu.structs.initial_length_field_size()) | ||
offset = (offset + | ||
cu['unit_length'] + | ||
cu.structs.initial_length_field_size()) | ||
yield cu | ||
|
||
def parse_TUs_iter(self, offset=0): | ||
if self.debug_types_sec is None: | ||
return | ||
|
||
while offset < self.debug_types_sec.size: | ||
tu = self._parse_TU_at_offset(offset) | ||
# Compute the offset of the next CU in the section. The unit_length | ||
# field of the CU header contains its size not including the length | ||
# field itself. | ||
offset = (offset + | ||
tu['unit_length'] + | ||
tu.structs.initial_length_field_size()) | ||
|
||
yield tu | ||
|
||
def _parse_debug_types(self): | ||
""" Parse all the TU entries in the .debug_types section. | ||
Place units into an OrderedDict keyed by type signature. | ||
""" | ||
if self._type_units_by_sig is not None: | ||
return | ||
self._type_units_by_sig = OrderedDict() | ||
|
||
if self.debug_types_sec is None: | ||
return | ||
|
||
# Parse all the Type Units in the types section for access by sig8 | ||
offset = 0 | ||
while offset < self.debug_types_sec.size: | ||
tu = self._parse_TU_at_offset(offset) | ||
# Compute the offset of the next TU in the section. The unit_length | ||
# field of the TU header contains its size not including the length | ||
# field itself. | ||
offset = (offset + | ||
tu['unit_length'] + | ||
tu.structs.initial_length_field_size()) | ||
self._type_units_by_sig[tu['signature']] = tu | ||
|
||
def _cached_CU_at_offset(self, offset): | ||
""" Return the CU with unit header at the given offset into the | ||
debug_info section from the cache. If not present, the unit is | ||
|
@@ -491,6 +569,51 @@ def _parse_CU_at_offset(self, offset): | |
cu_offset=offset, | ||
cu_die_offset=cu_die_offset) | ||
|
||
def _parse_TU_at_offset(self, offset): | ||
""" Parse and return a Type Unit (TU) at the given offset in the debug_types stream. | ||
""" | ||
# Section 7.4 (32-bit and 64-bit DWARF Formats) of the DWARF spec v3 | ||
# states that the first 32-bit word of the TU header determines | ||
# whether the TU is represented with 32-bit or 64-bit DWARF format. | ||
# | ||
# So we peek at the first word in the TU header to determine its | ||
# dwarf format. Based on it, we then create a new DWARFStructs | ||
# instance suitable for this TU and use it to parse the rest. | ||
# | ||
initial_length = struct_parse( | ||
self.structs.Dwarf_uint32(''), self.debug_types_sec.stream, offset) | ||
dwarf_format = 64 if initial_length == 0xFFFFFFFF else 32 | ||
|
||
# Temporary structs for parsing the header | ||
# The structs for the rest of the TU depend on the header data. | ||
# | ||
tu_structs = DWARFStructs( | ||
little_endian=self.config.little_endian, | ||
dwarf_format=dwarf_format, | ||
address_size=4, | ||
dwarf_version=2) | ||
|
||
tu_header = struct_parse( | ||
tu_structs.Dwarf_TU_header, self.debug_types_sec.stream, offset) | ||
|
||
# structs for the rest of the TU, taking into account bit-width and DWARF version | ||
tu_structs = DWARFStructs( | ||
little_endian=self.config.little_endian, | ||
dwarf_format=dwarf_format, | ||
address_size=tu_header['address_size'], | ||
dwarf_version=tu_header['version']) | ||
|
||
tu_die_offset = self.debug_types_sec.stream.tell() | ||
dwarf_assert( | ||
self._is_supported_version(tu_header['version']), | ||
"Expected supported DWARF version. Got '%s'" % tu_header['version']) | ||
return TypeUnit( | ||
header=tu_header, | ||
dwarfinfo=self, | ||
structs=tu_structs, | ||
tu_offset=offset, | ||
tu_die_offset=tu_die_offset) | ||
|
||
def _is_supported_version(self, version): | ||
""" DWARF version supported by this parser | ||
""" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: just return this directly, no need for a local
die