brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.8 KiB · 7797e10 Raw
108 lines · python
1#!/usr/bin/python32 3# Parsing dwarfdump's output to determine whether the location list for the4# parameter "b" covers all of the function. The script searches for information5# in the input file to determine the [prologue, epilogue) range for the6# function, the location list range for "b", and checks that the latter covers7# the entirety of the former.8import re9import sys10 11DebugInfoPattern = r"\.debug_info contents:"12DebugLinePattern = r"\.debug_line contents:"13ProloguePattern = r"^\s*0x([0-9a-f]+)\s.+prologue_end"14EpiloguePattern = r"^\s*0x([0-9a-f]+)\s.+epilogue_begin"15FormalPattern = r"^0x[0-9a-f]+:\s+DW_TAG_formal_parameter"16LocationPattern = r"DW_AT_location\s+\[DW_FORM_([a-z_]+)\](?:.*0x([a-f0-9]+))"17DebugLocPattern = r'\[0x([a-f0-9]+),\s+0x([a-f0-9]+)\) ".text": (.+)$'18 19SeenDebugInfo = False20SeenDebugLine = False21LocationRanges = None22PrologueEnd = None23EpilogueBegin = None24 25# The dwarfdump output should contain the DW_AT_location for "b" first, then the26# line table which should contain prologue_end and epilogue_begin entries.27with 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):31            SeenDebugInfo = True32        if not SeenDebugLine and re.match(DebugLinePattern, line):33            SeenDebugLine = True34        # 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.38                location_match = None39                while location_match is None:40                    if (line := next(dwarf_iter, "")) == "\n":41                        raise RuntimeError(42                            ".debug_info output is missing DW_AT_location for 'b'"43                        )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":47                    LocationRanges = ()48                    continue49                if location_match.group(1) != "sec_offset":50                    raise RuntimeError(51                        f"Unhandled form for DW_AT_location: DW_FORM_{location_match.group(1)}"52                    )53                # Variable has location range list.54                if (55                    debug_loc_match := re.search(DebugLocPattern, next(dwarf_iter, ""))56                ) is None:57                    raise RuntimeError(f"Invalid location range list for 'b'")58                LocationRanges = (59                    int(debug_loc_match.group(1), 16),60                    int(debug_loc_match.group(2), 16),61                )62                while (63                    debug_loc_match := re.search(DebugLocPattern, next(dwarf_iter, ""))64                ) is not None: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]:69                        raise RuntimeError(70                            f"Location list for 'b' is discontinuous from [0x{LocationRanges[1]:x}, 0x{match_loc_start:x})"71                        )72                    if "stack_value" in match_expr:73                        raise RuntimeError(74                            f"Location list for 'b' contains a stack_value expression: {match_expr}"75                        )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)85                break86 87if not SeenDebugInfo:88    raise RuntimeError(".debug_info section not found.")89if not SeenDebugLine:90    raise RuntimeError(".debug_line section not found.")91 92if LocationRanges is None:93    raise RuntimeError(".debug_info output is missing parameter 'b'")94if PrologueEnd is None:95    raise RuntimeError(".debug_line output is missing prologue_end")96if EpilogueBegin is None:97    raise RuntimeError(".debug_line output is missing epilogue_begin")98 99if len(LocationRanges) == 2 and (100    LocationRanges[0] > PrologueEnd or LocationRanges[1] < EpilogueBegin101):102    raise RuntimeError(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})106"""107    )108