brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.1 KiB · 1f1f477 Raw
390 lines · python
1# This implements the "diagnose-unwind" command, usually installed2# in the debug session like3#   command script import lldb.diagnose4# it is used when lldb's backtrace fails -- it collects and prints5# information about the stack frames, and tries an alternate unwind6# algorithm, that will help to understand why lldb's unwind algorithm7# did not succeed.8 9import optparse10import lldb11import re12import shlex13 14# Print the frame number, pc, frame pointer, module UUID and function name15# Returns the SBModule that contains the PC, if it could be found16 17 18def backtrace_print_frame(target, frame_num, addr, fp):19    process = target.GetProcess()20    addr_for_printing = addr21    addr_width = process.GetAddressByteSize() * 222    if frame_num > 0:23        addr = addr - 124 25    sbaddr = lldb.SBAddress()26    try:27        sbaddr.SetLoadAddress(addr, target)28        module_description = ""29        if sbaddr.GetModule():30            module_filename = ""31            module_uuid_str = sbaddr.GetModule().GetUUIDString()32            if module_uuid_str is None:33                module_uuid_str = ""34            if sbaddr.GetModule().GetFileSpec():35                module_filename = sbaddr.GetModule().GetFileSpec().GetFilename()36                if module_filename is None:37                    module_filename = ""38            if module_uuid_str != "" or module_filename != "":39                module_description = "%s %s" % (module_filename, module_uuid_str)40    except Exception:41        print(42            "%2d: pc==0x%-*x fp==0x%-*x"43            % (frame_num, addr_width, addr_for_printing, addr_width, fp)44        )45        return46 47    sym_ctx = target.ResolveSymbolContextForAddress(48        sbaddr, lldb.eSymbolContextEverything49    )50    if sym_ctx.IsValid() and sym_ctx.GetSymbol().IsValid():51        function_start = sym_ctx.GetSymbol().GetStartAddress().GetLoadAddress(target)52        offset = addr - function_start53        print(54            "%2d: pc==0x%-*x fp==0x%-*x %s %s + %d"55            % (56                frame_num,57                addr_width,58                addr_for_printing,59                addr_width,60                fp,61                module_description,62                sym_ctx.GetSymbol().GetName(),63                offset,64            )65        )66    else:67        print(68            "%2d: pc==0x%-*x fp==0x%-*x %s"69            % (70                frame_num,71                addr_width,72                addr_for_printing,73                addr_width,74                fp,75                module_description,76            )77        )78    return sbaddr.GetModule()79 80 81# A simple stack walk algorithm that follows the frame chain.82# Returns a two-element list; the first element is a list of modules83# seen and the second element is a list of addresses seen during the backtrace.84 85 86def simple_backtrace(debugger):87    target = debugger.GetSelectedTarget()88    process = target.GetProcess()89    cur_thread = process.GetSelectedThread()90 91    initial_fp = cur_thread.GetFrameAtIndex(0).GetFP()92 93    # If the pseudoreg "fp" isn't recognized, on arm hardcode to r7 which is94    # correct for Darwin programs.95    if initial_fp == lldb.LLDB_INVALID_ADDRESS and target.triple[0:3] == "arm":96        for reggroup in cur_thread.GetFrameAtIndex(1).registers:97            if reggroup.GetName() == "General Purpose Registers":98                for reg in reggroup:99                    if reg.GetName() == "r7":100                        initial_fp = int(reg.GetValue(), 16)101 102    module_list = []103    address_list = [cur_thread.GetFrameAtIndex(0).GetPC()]104    this_module = backtrace_print_frame(105        target, 0, cur_thread.GetFrameAtIndex(0).GetPC(), initial_fp106    )107    print_stack_frame(process, initial_fp)108    print("")109    if this_module is not None:110        module_list.append(this_module)111    if cur_thread.GetNumFrames() < 2:112        return [module_list, address_list]113 114    cur_fp = process.ReadPointerFromMemory(initial_fp, lldb.SBError())115    cur_pc = process.ReadPointerFromMemory(116        initial_fp + process.GetAddressByteSize(), lldb.SBError()117    )118 119    frame_num = 1120 121    while (122        cur_pc != 0123        and cur_fp != 0124        and cur_pc != lldb.LLDB_INVALID_ADDRESS125        and cur_fp != lldb.LLDB_INVALID_ADDRESS126    ):127        address_list.append(cur_pc)128        this_module = backtrace_print_frame(target, frame_num, cur_pc, cur_fp)129        print_stack_frame(process, cur_fp)130        print("")131        if this_module is not None:132            module_list.append(this_module)133        frame_num = frame_num + 1134        next_pc = 0135        next_fp = 0136        if (137            target.triple[0:6] == "x86_64"138            or target.triple[0:4] == "i386"139            or target.triple[0:3] == "arm"140        ):141            error = lldb.SBError()142            next_pc = process.ReadPointerFromMemory(143                cur_fp + process.GetAddressByteSize(), error144            )145            if not error.Success():146                next_pc = 0147            next_fp = process.ReadPointerFromMemory(cur_fp, error)148            if not error.Success():149                next_fp = 0150        # Clear the 0th bit for arm frames - this indicates it is a thumb frame151        if target.triple[0:3] == "arm" and (next_pc & 1) == 1:152            next_pc = next_pc & ~1153        cur_pc = next_pc154        cur_fp = next_fp155    this_module = backtrace_print_frame(target, frame_num, cur_pc, cur_fp)156    print_stack_frame(process, cur_fp)157    print("")158    if this_module is not None:159        module_list.append(this_module)160    return [module_list, address_list]161 162 163def print_stack_frame(process, fp):164    if fp == 0 or fp == lldb.LLDB_INVALID_ADDRESS or fp == 1:165        return166    addr_size = process.GetAddressByteSize()167    addr = fp - (2 * addr_size)168    i = 0169    outline = "Stack frame from $fp-%d: " % (2 * addr_size)170    error = lldb.SBError()171    try:172        while i < 5 and error.Success():173            address = process.ReadPointerFromMemory(addr + (i * addr_size), error)174            outline += " 0x%x" % address175            i += 1176        print(outline)177    except Exception:178        return179 180 181def diagnose_unwind(debugger, command, result, dict):182    """183    Gather diagnostic information to help debug incorrect unwind (backtrace)184    behavior in lldb.  When there is a backtrace that doesn't look185    correct, run this command with the correct thread selected and a186    large amount of diagnostic information will be printed, it is likely187    to be helpful when reporting the problem.188    """189 190    command_args = shlex.split(command)191    parser = create_diagnose_unwind_options()192    try:193        (options, args) = parser.parse_args(command_args)194    except:195        return196    target = debugger.GetSelectedTarget()197    if target:198        process = target.GetProcess()199        if process:200            thread = process.GetSelectedThread()201            if thread:202                lldb_versions_match = re.search(203                    r"[lL][lL][dD][bB]-(\d+)([.](\d+))?([.](\d+))?",204                    debugger.GetVersionString(),205                )206                lldb_version = 0207                lldb_minor = 0208                if (209                    len(lldb_versions_match.groups()) >= 1210                    and lldb_versions_match.groups()[0]211                ):212                    lldb_major = int(lldb_versions_match.groups()[0])213                if (214                    len(lldb_versions_match.groups()) >= 5215                    and lldb_versions_match.groups()[4]216                ):217                    lldb_minor = int(lldb_versions_match.groups()[4])218 219                modules_seen = []220                addresses_seen = []221 222                print("LLDB version %s" % debugger.GetVersionString())223                print("Unwind diagnostics for thread %d" % thread.GetIndexID())224                print("")225                print(226                    "============================================================================================="227                )228                print("")229                print("OS plugin setting:")230                debugger.HandleCommand(231                    "settings show target.process.python-os-plugin-path"232                )233                print("")234                print("Live register context:")235                thread.SetSelectedFrame(0)236                debugger.HandleCommand("register read")237                print("")238                print(239                    "============================================================================================="240                )241                print("")242                print("lldb's unwind algorithm:")243                print("")244                frame_num = 0245                for frame in thread.frames:246                    if not frame.IsInlined():247                        this_module = backtrace_print_frame(248                            target, frame_num, frame.GetPC(), frame.GetFP()249                        )250                        print_stack_frame(process, frame.GetFP())251                        print("")252                        if this_module is not None:253                            modules_seen.append(this_module)254                        addresses_seen.append(frame.GetPC())255                        frame_num = frame_num + 1256                print("")257                print(258                    "============================================================================================="259                )260                print("")261                print("Simple stack walk algorithm:")262                print("")263                (module_list, address_list) = simple_backtrace(debugger)264                if module_list and module_list is not None:265                    modules_seen += module_list266                if address_list and address_list is not None:267                    addresses_seen = set(addresses_seen)268                    addresses_seen.update(set(address_list))269 270                print("")271                print(272                    "============================================================================================="273                )274                print("")275                print("Modules seen in stack walks:")276                print("")277                modules_already_seen = set()278                for module in modules_seen:279                    if (280                        module is not None281                        and module.GetFileSpec().GetFilename() is not None282                    ):283                        if (284                            not module.GetFileSpec().GetFilename()285                            in modules_already_seen286                        ):287                            debugger.HandleCommand(288                                "image list %s" % module.GetFileSpec().GetFilename()289                            )290                            modules_already_seen.add(module.GetFileSpec().GetFilename())291 292                print("")293                print(294                    "============================================================================================="295                )296                print("")297                print("Disassembly ofaddresses seen in stack walks:")298                print("")299                additional_addresses_to_disassemble = addresses_seen300                for frame in thread.frames:301                    if not frame.IsInlined():302                        print(303                            "--------------------------------------------------------------------------------------"304                        )305                        print("")306                        print(307                            "Disassembly of %s, frame %d, address 0x%x"308                            % (309                                frame.GetFunctionName(),310                                frame.GetFrameID(),311                                frame.GetPC(),312                            )313                        )314                        print("")315                        if (316                            target.triple[0:6] == "x86_64"317                            or target.triple[0:4] == "i386"318                        ):319                            debugger.HandleCommand(320                                "disassemble -F att -a 0x%x" % frame.GetPC()321                            )322                        else:323                            debugger.HandleCommand(324                                "disassemble -a 0x%x" % frame.GetPC()325                            )326                        if frame.GetPC() in additional_addresses_to_disassemble:327                            additional_addresses_to_disassemble.remove(frame.GetPC())328 329                for address in list(additional_addresses_to_disassemble):330                    print(331                        "--------------------------------------------------------------------------------------"332                    )333                    print("")334                    print("Disassembly of 0x%x" % address)335                    print("")336                    if target.triple[0:6] == "x86_64" or target.triple[0:4] == "i386":337                        debugger.HandleCommand("disassemble -F att -a 0x%x" % address)338                    else:339                        debugger.HandleCommand("disassemble -a 0x%x" % address)340 341                print("")342                print(343                    "============================================================================================="344                )345                print("")346                additional_addresses_to_show_unwind = addresses_seen347                for frame in thread.frames:348                    if not frame.IsInlined():349                        print(350                            "--------------------------------------------------------------------------------------"351                        )352                        print("")353                        print(354                            "Unwind instructions for %s, frame %d"355                            % (frame.GetFunctionName(), frame.GetFrameID())356                        )357                        print("")358                        debugger.HandleCommand(359                            'image show-unwind -a "0x%x"' % frame.GetPC()360                        )361                        if frame.GetPC() in additional_addresses_to_show_unwind:362                            additional_addresses_to_show_unwind.remove(frame.GetPC())363 364                for address in list(additional_addresses_to_show_unwind):365                    print(366                        "--------------------------------------------------------------------------------------"367                    )368                    print("")369                    print("Unwind instructions for 0x%x" % address)370                    print("")371                    debugger.HandleCommand('image show-unwind -a "0x%x"' % address)372 373 374def create_diagnose_unwind_options():375    usage = "usage: %prog"376    description = """Print diagnostic information about a thread backtrace which will help to debug unwind problems"""377    parser = optparse.OptionParser(378        description=description, prog="diagnose_unwind", usage=usage379    )380    return parser381 382 383def __lldb_init_module(debugger, internal_dict):384    debugger.HandleCommand(385        "command script add -o -f %s.diagnose_unwind diagnose-unwind" % __name__386    )387    print(388        'The "diagnose-unwind" command has been installed, type "help diagnose-unwind" for detailed help.'389    )390