3 # Parsing dwarfdump's output to determine whether the location list for the
4 # parameter "b" covers all of the function. The script searches for information
5 # in the input file to determine the [prologue, epilogue) range for the
6 # function, the location list range for "b", and checks that the latter covers
7 # the entirety of the former.
11 DebugInfoPattern
= r
"\.debug_info contents:"
12 DebugLinePattern
= r
"\.debug_line contents:"
13 ProloguePattern
= r
"^\s*0x([0-9a-f]+)\s.+prologue_end"
14 EpiloguePattern
= r
"^\s*0x([0-9a-f]+)\s.+epilogue_begin"
15 FormalPattern
= r
"^0x[0-9a-f]+:\s+DW_TAG_formal_parameter"
16 LocationPattern
= r
"DW_AT_location\s+\[DW_FORM_([a-z_]+)\](?:.*0x([a-f0-9]+))"
17 DebugLocPattern
= r
'\[0x([a-f0-9]+),\s+0x([a-f0-9]+)\) ".text": (.+)$'
25 # The dwarfdump output should contain the DW_AT_location for "b" first, then the
26 # line table which should contain prologue_end and epilogue_begin entries.
27 with
open(sys
.argv
[1], "r") as dwarf_dump_file
:
28 dwarf_iter
= iter(dwarf_dump_file
)
29 for line
in dwarf_iter
:
30 if not SeenDebugInfo
and re
.match(DebugInfoPattern
, line
):
32 if not SeenDebugLine
and re
.match(DebugLinePattern
, line
):
34 # Get the range of DW_AT_location for "b".
35 if LocationRanges
is None:
36 if match
:= re
.match(FormalPattern
, line
):
37 # Go until we either find DW_AT_location or reach the end of this entry.
39 while location_match
is None:
40 if (line
:= next(dwarf_iter
, "")) == "\n":
42 ".debug_info output is missing DW_AT_location for 'b'"
44 location_match
= re
.search(LocationPattern
, line
)
45 # Variable has whole-scope location, represented by an empty tuple.
46 if location_match
.group(1) == "exprloc":
49 if location_match
.group(1) != "sec_offset":
51 f
"Unhandled form for DW_AT_location: DW_FORM_{location_match.group(1)}"
53 # Variable has location range list.
55 debug_loc_match
:= re
.search(DebugLocPattern
, next(dwarf_iter
, ""))
57 raise RuntimeError(f
"Invalid location range list for 'b'")
59 int(debug_loc_match
.group(1), 16),
60 int(debug_loc_match
.group(2), 16),
63 debug_loc_match
:= re
.search(DebugLocPattern
, next(dwarf_iter
, ""))
65 match_loc_start
= int(debug_loc_match
.group(1), 16)
66 match_loc_end
= int(debug_loc_match
.group(2), 16)
67 match_expr
= debug_loc_match
.group(3)
68 if match_loc_start
!= LocationRanges
[1]:
70 f
"Location list for 'b' is discontinuous from [0x{LocationRanges[1]:x}, 0x{match_loc_start:x})"
72 if "stack_value" in match_expr
:
74 f
"Location list for 'b' contains a stack_value expression: {match_expr}"
76 LocationRanges
= (LocationRanges
[0], match_loc_end
)
77 # Get the prologue_end address.
78 elif PrologueEnd
is None:
79 if match
:= re
.match(ProloguePattern
, line
):
80 PrologueEnd
= int(match
.group(1), 16)
81 # Get the epilogue_begin address.
82 elif EpilogueBegin
is None:
83 if match
:= re
.match(EpiloguePattern
, line
):
84 EpilogueBegin
= int(match
.group(1), 16)
88 raise RuntimeError(".debug_info section not found.")
90 raise RuntimeError(".debug_line section not found.")
92 if LocationRanges
is None:
93 raise RuntimeError(".debug_info output is missing parameter 'b'")
94 if PrologueEnd
is None:
95 raise RuntimeError(".debug_line output is missing prologue_end")
96 if EpilogueBegin
is None:
97 raise RuntimeError(".debug_line output is missing epilogue_begin")
99 if len(LocationRanges
) == 2 and (
100 LocationRanges
[0] > PrologueEnd
or LocationRanges
[1] < EpilogueBegin
103 f
"""Location list for 'b' does not cover the whole function:")
104 Prologue to Epilogue = [0x{PrologueEnd:x}, 0x{EpilogueBegin:x})
105 Location range = [0x{LocationRanges[0]:x}, 0x{LocationRanges[1]:x})