From eb0986586803d7e5b0df4498961fde3b4385b5a0 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Thu, 5 Dec 2024 19:22:12 -0600 Subject: [PATCH] scripts: Resolve DW_AT_abstract_origin during dwarf collection Sometimes I feel like dwarf-info is designed to be as error-prone as possible. In this case, DW_AT_abstract_origin indicates that one dwarf entry should inherit the attributes of another. If you don't know this, it's easy to miss relevant dwarf entries due to missing name fields, etc. Expanding DW_AT_abstract_origin lazily would be tricky due to how our DwarfInfo class is structured, so instead I am just expanding DW_AT_abstract_origins during collect_dwarf_info. Note this doesn't handle recursive DW_AT_abstract_origins, but there is at least an assert. --- It does seem like DW_AT_abstract_origin is intended to be limited to "Inline instances of inline subprograms" and "Out-of-line instances of inline subprograms" according to the DWARF5 spec, but it's unclear if this is a rule or suggestion... This hasn't been an issue for existing scripts, but is needed from some ongoing stack.py rework. Otherwise we don't find "out-of-line instances of inline subprograms" (optimized functions?) correctly. --- scripts/code.py | 12 ++++++++++++ scripts/ctx.py | 12 ++++++++++++ scripts/data.py | 12 ++++++++++++ scripts/structs.py | 12 ++++++++++++ 4 files changed, 48 insertions(+) diff --git a/scripts/code.py b/scripts/code.py index 8049e388..8b3f112d 100755 --- a/scripts/code.py +++ b/scripts/code.py @@ -507,6 +507,18 @@ def collect_dwarf_info(obj_path, tags=None, *, if proc.returncode != 0: raise sp.CalledProcessError(proc.returncode, proc.args) + # resolve abstract origins + for entry in info.values(): + if 'DW_AT_abstract_origin' in entry: + off = int(entry['DW_AT_abstract_origin'].strip('<>'), 0) + origin = info[off] + assert 'DW_AT_abstract_origin' not in origin, ( + "Recursive abstract origin?") + + for k, v in origin.ats.items(): + if k not in entry.ats: + entry.ats[k] = v + return DwarfInfo(info) def collect(obj_paths, *, diff --git a/scripts/ctx.py b/scripts/ctx.py index 9f52ba31..138990f9 100755 --- a/scripts/ctx.py +++ b/scripts/ctx.py @@ -516,6 +516,18 @@ def collect_dwarf_info(obj_path, tags=None, *, if proc.returncode != 0: raise sp.CalledProcessError(proc.returncode, proc.args) + # resolve abstract origins + for entry in info.values(): + if 'DW_AT_abstract_origin' in entry: + off = int(entry['DW_AT_abstract_origin'].strip('<>'), 0) + origin = info[off] + assert 'DW_AT_abstract_origin' not in origin, ( + "Recursive abstract origin?") + + for k, v in origin.ats.items(): + if k not in entry.ats: + entry.ats[k] = v + return DwarfInfo(info) def collect(obj_paths, *, diff --git a/scripts/data.py b/scripts/data.py index b9e0129c..91a101b0 100755 --- a/scripts/data.py +++ b/scripts/data.py @@ -507,6 +507,18 @@ def collect_dwarf_info(obj_path, tags=None, *, if proc.returncode != 0: raise sp.CalledProcessError(proc.returncode, proc.args) + # resolve abstract origins + for entry in info.values(): + if 'DW_AT_abstract_origin' in entry: + off = int(entry['DW_AT_abstract_origin'].strip('<>'), 0) + origin = info[off] + assert 'DW_AT_abstract_origin' not in origin, ( + "Recursive abstract origin?") + + for k, v in origin.ats.items(): + if k not in entry.ats: + entry.ats[k] = v + return DwarfInfo(info) def collect(obj_paths, *, diff --git a/scripts/structs.py b/scripts/structs.py index c30ff233..91b4e18f 100755 --- a/scripts/structs.py +++ b/scripts/structs.py @@ -378,6 +378,18 @@ def collect_dwarf_info(obj_path, tags=None, *, if proc.returncode != 0: raise sp.CalledProcessError(proc.returncode, proc.args) + # resolve abstract origins + for entry in info.values(): + if 'DW_AT_abstract_origin' in entry: + off = int(entry['DW_AT_abstract_origin'].strip('<>'), 0) + origin = info[off] + assert 'DW_AT_abstract_origin' not in origin, ( + "Recursive abstract origin?") + + for k, v in origin.ats.items(): + if k not in entry.ats: + entry.ats[k] = v + return DwarfInfo(info) def collect(obj_paths, *,