xref: /llvm-project/lldb/utils/lui/lldbutil.py (revision 602e47c5f9fd2e14c7bfb6111e6558fa0d27c87f)
1##===-- lldbutil.py ------------------------------------------*- Python -*-===##
2##
3# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4# See https://llvm.org/LICENSE.txt for license information.
5# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6##
7##===----------------------------------------------------------------------===##
8
9"""
10This LLDB module contains miscellaneous utilities.
11Some of the test suite takes advantage of the utility functions defined here.
12They can also be useful for general purpose lldb scripting.
13"""
14
15import lldb
16import os
17import sys
18import io
19
20# ===================================================
21# Utilities for locating/checking executable programs
22# ===================================================
23
24
25def is_exe(fpath):
26    """Returns True if fpath is an executable."""
27    return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
28
29
30def which(program):
31    """Returns the full path to a program; None otherwise."""
32    fpath, fname = os.path.split(program)
33    if fpath:
34        if is_exe(program):
35            return program
36    else:
37        for path in os.environ["PATH"].split(os.pathsep):
38            exe_file = os.path.join(path, program)
39            if is_exe(exe_file):
40                return exe_file
41    return None
42
43
44# ===================================================
45# Disassembly for an SBFunction or an SBSymbol object
46# ===================================================
47
48
49def disassemble(target, function_or_symbol):
50    """Disassemble the function or symbol given a target.
51
52    It returns the disassembly content in a string object.
53    """
54    buf = io.StringIO()
55    insts = function_or_symbol.GetInstructions(target)
56    for i in insts:
57        print(i, file=buf)
58    return buf.getvalue()
59
60
61# ==========================================================
62# Integer (byte size 1, 2, 4, and 8) to bytearray conversion
63# ==========================================================
64
65
66def int_to_bytearray(val, bytesize):
67    """Utility function to convert an integer into a bytearray.
68
69    It returns the bytearray in the little endian format.  It is easy to get the
70    big endian format, just do ba.reverse() on the returned object.
71    """
72    import struct
73
74    if bytesize == 1:
75        return bytearray([val])
76
77    # Little endian followed by a format character.
78    template = "<%c"
79    if bytesize == 2:
80        fmt = template % "h"
81    elif bytesize == 4:
82        fmt = template % "i"
83    elif bytesize == 4:
84        fmt = template % "q"
85    else:
86        return None
87
88    packed = struct.pack(fmt, val)
89    return bytearray(ord(x) for x in packed)
90
91
92def bytearray_to_int(bytes, bytesize):
93    """Utility function to convert a bytearray into an integer.
94
95    It interprets the bytearray in the little endian format. For a big endian
96    bytearray, just do ba.reverse() on the object before passing it in.
97    """
98    import struct
99
100    if bytesize == 1:
101        return bytes[0]
102
103    # Little endian followed by a format character.
104    template = "<%c"
105    if bytesize == 2:
106        fmt = template % "h"
107    elif bytesize == 4:
108        fmt = template % "i"
109    elif bytesize == 4:
110        fmt = template % "q"
111    else:
112        return None
113
114    unpacked = struct.unpack(fmt, str(bytes))
115    return unpacked[0]
116
117
118# ==============================================================
119# Get the description of an lldb object or None if not available
120# ==============================================================
121def get_description(obj, option=None):
122    """Calls lldb_obj.GetDescription() and returns a string, or None.
123
124    For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra
125    option can be passed in to describe the detailed level of description
126    desired:
127        o lldb.eDescriptionLevelBrief
128        o lldb.eDescriptionLevelFull
129        o lldb.eDescriptionLevelVerbose
130    """
131    method = getattr(obj, "GetDescription")
132    if not method:
133        return None
134    tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint)
135    if isinstance(obj, tuple):
136        if option is None:
137            option = lldb.eDescriptionLevelBrief
138
139    stream = lldb.SBStream()
140    if option is None:
141        success = method(stream)
142    else:
143        success = method(stream, option)
144    if not success:
145        return None
146    return stream.GetData()
147
148
149# =================================================
150# Convert some enum value to its string counterpart
151# =================================================
152
153
154def state_type_to_str(enum):
155    """Returns the stateType string given an enum."""
156    if enum == lldb.eStateInvalid:
157        return "invalid"
158    elif enum == lldb.eStateUnloaded:
159        return "unloaded"
160    elif enum == lldb.eStateConnected:
161        return "connected"
162    elif enum == lldb.eStateAttaching:
163        return "attaching"
164    elif enum == lldb.eStateLaunching:
165        return "launching"
166    elif enum == lldb.eStateStopped:
167        return "stopped"
168    elif enum == lldb.eStateRunning:
169        return "running"
170    elif enum == lldb.eStateStepping:
171        return "stepping"
172    elif enum == lldb.eStateCrashed:
173        return "crashed"
174    elif enum == lldb.eStateDetached:
175        return "detached"
176    elif enum == lldb.eStateExited:
177        return "exited"
178    elif enum == lldb.eStateSuspended:
179        return "suspended"
180    else:
181        raise Exception("Unknown StateType enum")
182
183
184def stop_reason_to_str(enum):
185    """Returns the stopReason string given an enum."""
186    if enum == lldb.eStopReasonInvalid:
187        return "invalid"
188    elif enum == lldb.eStopReasonNone:
189        return "none"
190    elif enum == lldb.eStopReasonTrace:
191        return "trace"
192    elif enum == lldb.eStopReasonBreakpoint:
193        return "breakpoint"
194    elif enum == lldb.eStopReasonWatchpoint:
195        return "watchpoint"
196    elif enum == lldb.eStopReasonSignal:
197        return "signal"
198    elif enum == lldb.eStopReasonException:
199        return "exception"
200    elif enum == lldb.eStopReasonPlanComplete:
201        return "plancomplete"
202    elif enum == lldb.eStopReasonThreadExiting:
203        return "threadexiting"
204    else:
205        raise Exception("Unknown StopReason enum")
206
207
208def symbol_type_to_str(enum):
209    """Returns the symbolType string given an enum."""
210    if enum == lldb.eSymbolTypeInvalid:
211        return "invalid"
212    elif enum == lldb.eSymbolTypeAbsolute:
213        return "absolute"
214    elif enum == lldb.eSymbolTypeCode:
215        return "code"
216    elif enum == lldb.eSymbolTypeData:
217        return "data"
218    elif enum == lldb.eSymbolTypeTrampoline:
219        return "trampoline"
220    elif enum == lldb.eSymbolTypeRuntime:
221        return "runtime"
222    elif enum == lldb.eSymbolTypeException:
223        return "exception"
224    elif enum == lldb.eSymbolTypeSourceFile:
225        return "sourcefile"
226    elif enum == lldb.eSymbolTypeHeaderFile:
227        return "headerfile"
228    elif enum == lldb.eSymbolTypeObjectFile:
229        return "objectfile"
230    elif enum == lldb.eSymbolTypeCommonBlock:
231        return "commonblock"
232    elif enum == lldb.eSymbolTypeBlock:
233        return "block"
234    elif enum == lldb.eSymbolTypeLocal:
235        return "local"
236    elif enum == lldb.eSymbolTypeParam:
237        return "param"
238    elif enum == lldb.eSymbolTypeVariable:
239        return "variable"
240    elif enum == lldb.eSymbolTypeVariableType:
241        return "variabletype"
242    elif enum == lldb.eSymbolTypeLineEntry:
243        return "lineentry"
244    elif enum == lldb.eSymbolTypeLineHeader:
245        return "lineheader"
246    elif enum == lldb.eSymbolTypeScopeBegin:
247        return "scopebegin"
248    elif enum == lldb.eSymbolTypeScopeEnd:
249        return "scopeend"
250    elif enum == lldb.eSymbolTypeAdditional:
251        return "additional"
252    elif enum == lldb.eSymbolTypeCompiler:
253        return "compiler"
254    elif enum == lldb.eSymbolTypeInstrumentation:
255        return "instrumentation"
256    elif enum == lldb.eSymbolTypeUndefined:
257        return "undefined"
258
259
260def value_type_to_str(enum):
261    """Returns the valueType string given an enum."""
262    if enum == lldb.eValueTypeInvalid:
263        return "invalid"
264    elif enum == lldb.eValueTypeVariableGlobal:
265        return "global_variable"
266    elif enum == lldb.eValueTypeVariableStatic:
267        return "static_variable"
268    elif enum == lldb.eValueTypeVariableArgument:
269        return "argument_variable"
270    elif enum == lldb.eValueTypeVariableLocal:
271        return "local_variable"
272    elif enum == lldb.eValueTypeRegister:
273        return "register"
274    elif enum == lldb.eValueTypeRegisterSet:
275        return "register_set"
276    elif enum == lldb.eValueTypeConstResult:
277        return "constant_result"
278    else:
279        raise Exception("Unknown ValueType enum")
280
281
282# ==================================================
283# Get stopped threads due to each stop reason.
284# ==================================================
285
286
287def sort_stopped_threads(
288    process,
289    breakpoint_threads=None,
290    crashed_threads=None,
291    watchpoint_threads=None,
292    signal_threads=None,
293    exiting_threads=None,
294    other_threads=None,
295):
296    """Fills array *_threads with threads stopped for the corresponding stop
297    reason.
298    """
299    for lst in [
300        breakpoint_threads,
301        watchpoint_threads,
302        signal_threads,
303        exiting_threads,
304        other_threads,
305    ]:
306        if lst is not None:
307            lst[:] = []
308
309    for thread in process:
310        dispatched = False
311        for reason, list in [
312            (lldb.eStopReasonBreakpoint, breakpoint_threads),
313            (lldb.eStopReasonException, crashed_threads),
314            (lldb.eStopReasonWatchpoint, watchpoint_threads),
315            (lldb.eStopReasonSignal, signal_threads),
316            (lldb.eStopReasonThreadExiting, exiting_threads),
317            (None, other_threads),
318        ]:
319            if not dispatched and list is not None:
320                if thread.GetStopReason() == reason or reason is None:
321                    list.append(thread)
322                    dispatched = True
323
324
325# ==================================================
326# Utility functions for setting breakpoints
327# ==================================================
328
329
330def run_break_set_by_file_and_line(
331    test,
332    file_name,
333    line_number,
334    extra_options=None,
335    num_expected_locations=1,
336    loc_exact=False,
337    module_name=None,
338):
339    """Set a breakpoint by file and line, returning the breakpoint number.
340
341    If extra_options is not None, then we append it to the breakpoint set command.
342
343    If num_expected_locations is -1 we check that we got AT LEAST one location, otherwise we check that num_expected_locations equals the number of locations.
344
345    If loc_exact is true, we check that there is one location, and that location must be at the input file and line number.
346    """
347
348    if file_name is None:
349        command = "breakpoint set -l %d" % (line_number)
350    else:
351        command = 'breakpoint set -f "%s" -l %d' % (file_name, line_number)
352
353    if module_name:
354        command += " --shlib '%s'" % (module_name)
355
356    if extra_options:
357        command += " " + extra_options
358
359    break_results = run_break_set_command(test, command)
360
361    if num_expected_locations == 1 and loc_exact:
362        check_breakpoint_result(
363            test,
364            break_results,
365            num_locations=num_expected_locations,
366            file_name=file_name,
367            line_number=line_number,
368            module_name=module_name,
369        )
370    else:
371        check_breakpoint_result(
372            test, break_results, num_locations=num_expected_locations
373        )
374
375    return get_bpno_from_match(break_results)
376
377
378def run_break_set_by_symbol(
379    test,
380    symbol,
381    extra_options=None,
382    num_expected_locations=-1,
383    sym_exact=False,
384    module_name=None,
385):
386    """Set a breakpoint by symbol name.  Common options are the same as run_break_set_by_file_and_line.
387
388    If sym_exact is true, then the output symbol must match the input exactly, otherwise we do a substring match.
389    """
390    command = 'breakpoint set -n "%s"' % (symbol)
391
392    if module_name:
393        command += " --shlib '%s'" % (module_name)
394
395    if extra_options:
396        command += " " + extra_options
397
398    break_results = run_break_set_command(test, command)
399
400    if num_expected_locations == 1 and sym_exact:
401        check_breakpoint_result(
402            test,
403            break_results,
404            num_locations=num_expected_locations,
405            symbol_name=symbol,
406            module_name=module_name,
407        )
408    else:
409        check_breakpoint_result(
410            test, break_results, num_locations=num_expected_locations
411        )
412
413    return get_bpno_from_match(break_results)
414
415
416def run_break_set_by_selector(
417    test, selector, extra_options=None, num_expected_locations=-1, module_name=None
418):
419    """Set a breakpoint by selector.  Common options are the same as run_break_set_by_file_and_line."""
420
421    command = 'breakpoint set -S "%s"' % (selector)
422
423    if module_name:
424        command += ' --shlib "%s"' % (module_name)
425
426    if extra_options:
427        command += " " + extra_options
428
429    break_results = run_break_set_command(test, command)
430
431    if num_expected_locations == 1:
432        check_breakpoint_result(
433            test,
434            break_results,
435            num_locations=num_expected_locations,
436            symbol_name=selector,
437            symbol_match_exact=False,
438            module_name=module_name,
439        )
440    else:
441        check_breakpoint_result(
442            test, break_results, num_locations=num_expected_locations
443        )
444
445    return get_bpno_from_match(break_results)
446
447
448def run_break_set_by_regexp(
449    test, regexp, extra_options=None, num_expected_locations=-1
450):
451    """Set a breakpoint by regular expression match on symbol name.  Common options are the same as run_break_set_by_file_and_line."""
452
453    command = 'breakpoint set -r "%s"' % (regexp)
454    if extra_options:
455        command += " " + extra_options
456
457    break_results = run_break_set_command(test, command)
458
459    check_breakpoint_result(test, break_results, num_locations=num_expected_locations)
460
461    return get_bpno_from_match(break_results)
462
463
464def run_break_set_by_source_regexp(
465    test, regexp, extra_options=None, num_expected_locations=-1
466):
467    """Set a breakpoint by source regular expression.  Common options are the same as run_break_set_by_file_and_line."""
468    command = 'breakpoint set -p "%s"' % (regexp)
469    if extra_options:
470        command += " " + extra_options
471
472    break_results = run_break_set_command(test, command)
473
474    check_breakpoint_result(test, break_results, num_locations=num_expected_locations)
475
476    return get_bpno_from_match(break_results)
477
478
479def run_break_set_command(test, command):
480    """Run the command passed in - it must be some break set variant - and analyze the result.
481    Returns a dictionary of information gleaned from the command-line results.
482    Will assert if the breakpoint setting fails altogether.
483
484    Dictionary will contain:
485        bpno          - breakpoint of the newly created breakpoint, -1 on error.
486        num_locations - number of locations set for the breakpoint.
487
488    If there is only one location, the dictionary MAY contain:
489        file          - source file name
490        line_no       - source line number
491        symbol        - symbol name
492        inline_symbol - inlined symbol name
493        offset        - offset from the original symbol
494        module        - module
495        address       - address at which the breakpoint was set."""
496
497    patterns = [
498        r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>[0-9]+) locations\.$",
499        r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>no) locations \(pending\)\.",
500        r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>[+\-]{0,1}[^+]+)( \+ (?P<offset>[0-9]+)){0,1}( \[inlined\] (?P<inline_symbol>.*)){0,1} at (?P<file>[^:]+):(?P<line_no>[0-9]+), address = (?P<address>0x[0-9a-fA-F]+)$",
501        r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>.*)( \+ (?P<offset>[0-9]+)){0,1}, address = (?P<address>0x[0-9a-fA-F]+)$",
502    ]
503    match_object = test.match(command, patterns)
504    break_results = match_object.groupdict()
505
506    # We always insert the breakpoint number, setting it to -1 if we couldn't find it
507    # Also, make sure it gets stored as an integer.
508    if not "bpno" in break_results:
509        break_results["bpno"] = -1
510    else:
511        break_results["bpno"] = int(break_results["bpno"])
512
513    # We always insert the number of locations
514    # If ONE location is set for the breakpoint, then the output doesn't mention locations, but it has to be 1...
515    # We also make sure it is an integer.
516
517    if not "num_locations" in break_results:
518        num_locations = 1
519    else:
520        num_locations = break_results["num_locations"]
521        if num_locations == "no":
522            num_locations = 0
523        else:
524            num_locations = int(break_results["num_locations"])
525
526    break_results["num_locations"] = num_locations
527
528    if "line_no" in break_results:
529        break_results["line_no"] = int(break_results["line_no"])
530
531    return break_results
532
533
534def get_bpno_from_match(break_results):
535    return int(break_results["bpno"])
536
537
538def check_breakpoint_result(
539    test,
540    break_results,
541    file_name=None,
542    line_number=-1,
543    symbol_name=None,
544    symbol_match_exact=True,
545    module_name=None,
546    offset=-1,
547    num_locations=-1,
548):
549    out_num_locations = break_results["num_locations"]
550
551    if num_locations == -1:
552        test.assertTrue(
553            out_num_locations > 0, "Expecting one or more locations, got none."
554        )
555    else:
556        test.assertTrue(
557            num_locations == out_num_locations,
558            "Expecting %d locations, got %d." % (num_locations, out_num_locations),
559        )
560
561    if file_name:
562        out_file_name = ""
563        if "file" in break_results:
564            out_file_name = break_results["file"]
565        test.assertTrue(
566            file_name == out_file_name,
567            "Breakpoint file name '%s' doesn't match resultant name '%s'."
568            % (file_name, out_file_name),
569        )
570
571    if line_number != -1:
572        out_file_line = -1
573        if "line_no" in break_results:
574            out_line_number = break_results["line_no"]
575
576        test.assertTrue(
577            line_number == out_line_number,
578            "Breakpoint line number %s doesn't match resultant line %s."
579            % (line_number, out_line_number),
580        )
581
582    if symbol_name:
583        out_symbol_name = ""
584        # Look first for the inlined symbol name, otherwise use the symbol
585        # name:
586        if "inline_symbol" in break_results and break_results["inline_symbol"]:
587            out_symbol_name = break_results["inline_symbol"]
588        elif "symbol" in break_results:
589            out_symbol_name = break_results["symbol"]
590
591        if symbol_match_exact:
592            test.assertTrue(
593                symbol_name == out_symbol_name,
594                "Symbol name '%s' doesn't match resultant symbol '%s'."
595                % (symbol_name, out_symbol_name),
596            )
597        else:
598            test.assertTrue(
599                out_symbol_name.find(symbol_name) != -1,
600                "Symbol name '%s' isn't in resultant symbol '%s'."
601                % (symbol_name, out_symbol_name),
602            )
603
604    if module_name:
605        out_nodule_name = None
606        if "module" in break_results:
607            out_module_name = break_results["module"]
608
609        test.assertTrue(
610            module_name.find(out_module_name) != -1,
611            "Symbol module name '%s' isn't in expected module name '%s'."
612            % (out_module_name, module_name),
613        )
614
615
616# ==================================================
617# Utility functions related to Threads and Processes
618# ==================================================
619
620
621def get_stopped_threads(process, reason):
622    """Returns the thread(s) with the specified stop reason in a list.
623
624    The list can be empty if no such thread exists.
625    """
626    threads = []
627    for t in process:
628        if t.GetStopReason() == reason:
629            threads.append(t)
630    return threads
631
632
633def get_stopped_thread(process, reason):
634    """A convenience function which returns the first thread with the given stop
635    reason or None.
636
637    Example usages:
638
639    1. Get the stopped thread due to a breakpoint condition
640
641    ...
642        from lldbutil import get_stopped_thread
643        thread = get_stopped_thread(process, lldb.eStopReasonPlanComplete)
644        self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint condition")
645    ...
646
647    2. Get the thread stopped due to a breakpoint
648
649    ...
650        from lldbutil import get_stopped_thread
651        thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
652        self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint")
653    ...
654
655    """
656    threads = get_stopped_threads(process, reason)
657    if len(threads) == 0:
658        return None
659    return threads[0]
660
661
662def get_threads_stopped_at_breakpoint(process, bkpt):
663    """For a stopped process returns the thread stopped at the breakpoint passed in bkpt"""
664    stopped_threads = []
665    threads = []
666
667    stopped_threads = get_stopped_threads(process, lldb.eStopReasonBreakpoint)
668
669    if len(stopped_threads) == 0:
670        return threads
671
672    for thread in stopped_threads:
673        # Make sure we've hit our breakpoint...
674        break_id = thread.GetStopReasonDataAtIndex(0)
675        if break_id == bkpt.GetID():
676            threads.append(thread)
677
678    return threads
679
680
681def continue_to_breakpoint(process, bkpt):
682    """Continues the process, if it stops, returns the threads stopped at bkpt; otherwise, returns None"""
683    process.Continue()
684    if process.GetState() != lldb.eStateStopped:
685        return None
686    else:
687        return get_threads_stopped_at_breakpoint(process, bkpt)
688
689
690def get_caller_symbol(thread):
691    """
692    Returns the symbol name for the call site of the leaf function.
693    """
694    depth = thread.GetNumFrames()
695    if depth <= 1:
696        return None
697    caller = thread.GetFrameAtIndex(1).GetSymbol()
698    if caller:
699        return caller.GetName()
700    else:
701        return None
702
703
704def get_function_names(thread):
705    """
706    Returns a sequence of function names from the stack frames of this thread.
707    """
708
709    def GetFuncName(i):
710        return thread.GetFrameAtIndex(i).GetFunctionName()
711
712    return [GetFuncName(i) for i in range(thread.GetNumFrames())]
713
714
715def get_symbol_names(thread):
716    """
717    Returns a sequence of symbols for this thread.
718    """
719
720    def GetSymbol(i):
721        return thread.GetFrameAtIndex(i).GetSymbol().GetName()
722
723    return [GetSymbol(i) for i in range(thread.GetNumFrames())]
724
725
726def get_pc_addresses(thread):
727    """
728    Returns a sequence of pc addresses for this thread.
729    """
730
731    def GetPCAddress(i):
732        return thread.GetFrameAtIndex(i).GetPCAddress()
733
734    return [GetPCAddress(i) for i in range(thread.GetNumFrames())]
735
736
737def get_filenames(thread):
738    """
739    Returns a sequence of file names from the stack frames of this thread.
740    """
741
742    def GetFilename(i):
743        return thread.GetFrameAtIndex(i).GetLineEntry().GetFileSpec().GetFilename()
744
745    return [GetFilename(i) for i in range(thread.GetNumFrames())]
746
747
748def get_line_numbers(thread):
749    """
750    Returns a sequence of line numbers from the stack frames of this thread.
751    """
752
753    def GetLineNumber(i):
754        return thread.GetFrameAtIndex(i).GetLineEntry().GetLine()
755
756    return [GetLineNumber(i) for i in range(thread.GetNumFrames())]
757
758
759def get_module_names(thread):
760    """
761    Returns a sequence of module names from the stack frames of this thread.
762    """
763
764    def GetModuleName(i):
765        return thread.GetFrameAtIndex(i).GetModule().GetFileSpec().GetFilename()
766
767    return [GetModuleName(i) for i in range(thread.GetNumFrames())]
768
769
770def get_stack_frames(thread):
771    """
772    Returns a sequence of stack frames for this thread.
773    """
774
775    def GetStackFrame(i):
776        return thread.GetFrameAtIndex(i)
777
778    return [GetStackFrame(i) for i in range(thread.GetNumFrames())]
779
780
781def print_stacktrace(thread, string_buffer=False):
782    """Prints a simple stack trace of this thread."""
783
784    output = io.StringIO() if string_buffer else sys.stdout
785    target = thread.GetProcess().GetTarget()
786
787    depth = thread.GetNumFrames()
788
789    mods = get_module_names(thread)
790    funcs = get_function_names(thread)
791    symbols = get_symbol_names(thread)
792    files = get_filenames(thread)
793    lines = get_line_numbers(thread)
794    addrs = get_pc_addresses(thread)
795
796    if thread.GetStopReason() != lldb.eStopReasonInvalid:
797        desc = "stop reason=" + stop_reason_to_str(thread.GetStopReason())
798    else:
799        desc = ""
800    print(
801        "Stack trace for thread id={0:#x} name={1} queue={2} ".format(
802            thread.GetThreadID(), thread.GetName(), thread.GetQueueName()
803        )
804        + desc,
805        file=output,
806    )
807
808    for i in range(depth):
809        frame = thread.GetFrameAtIndex(i)
810        function = frame.GetFunction()
811
812        load_addr = addrs[i].GetLoadAddress(target)
813        if not function:
814            file_addr = addrs[i].GetFileAddress()
815            start_addr = frame.GetSymbol().GetStartAddress().GetFileAddress()
816            symbol_offset = file_addr - start_addr
817            print(
818                "  frame #{num}: {addr:#016x} {mod}`{symbol} + {offset}".format(
819                    num=i,
820                    addr=load_addr,
821                    mod=mods[i],
822                    symbol=symbols[i],
823                    offset=symbol_offset,
824                ),
825                file=output,
826            )
827        else:
828            print(
829                "  frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line} {args}".format(
830                    num=i,
831                    addr=load_addr,
832                    mod=mods[i],
833                    func="%s [inlined]" % funcs[i] if frame.IsInlined() else funcs[i],
834                    file=files[i],
835                    line=lines[i],
836                    args=get_args_as_string(frame, showFuncName=False)
837                    if not frame.IsInlined()
838                    else "()",
839                ),
840                file=output,
841            )
842
843    if string_buffer:
844        return output.getvalue()
845
846
847def print_stacktraces(process, string_buffer=False):
848    """Prints the stack traces of all the threads."""
849
850    output = io.StringIO() if string_buffer else sys.stdout
851
852    print("Stack traces for " + str(process), file=output)
853
854    for thread in process:
855        print(print_stacktrace(thread, string_buffer=True), file=output)
856
857    if string_buffer:
858        return output.getvalue()
859
860
861# ===================================
862# Utility functions related to Frames
863# ===================================
864
865
866def get_parent_frame(frame):
867    """
868    Returns the parent frame of the input frame object; None if not available.
869    """
870    thread = frame.GetThread()
871    parent_found = False
872    for f in thread:
873        if parent_found:
874            return f
875        if f.GetFrameID() == frame.GetFrameID():
876            parent_found = True
877
878    # If we reach here, no parent has been found, return None.
879    return None
880
881
882def get_args_as_string(frame, showFuncName=True):
883    """
884    Returns the args of the input frame object as a string.
885    """
886    # arguments     => True
887    # locals        => False
888    # statics       => False
889    # in_scope_only => True
890    vars = frame.GetVariables(True, False, False, True)  # type of SBValueList
891    args = []  # list of strings
892    for var in vars:
893        args.append("(%s)%s=%s" % (var.GetTypeName(), var.GetName(), var.GetValue()))
894    if frame.GetFunction():
895        name = frame.GetFunction().GetName()
896    elif frame.GetSymbol():
897        name = frame.GetSymbol().GetName()
898    else:
899        name = ""
900    if showFuncName:
901        return "%s(%s)" % (name, ", ".join(args))
902    else:
903        return "(%s)" % (", ".join(args))
904
905
906def print_registers(frame, string_buffer=False):
907    """Prints all the register sets of the frame."""
908
909    output = io.StringIO() if string_buffer else sys.stdout
910
911    print("Register sets for " + str(frame), file=output)
912
913    registerSet = frame.GetRegisters()  # Return type of SBValueList.
914    print(
915        "Frame registers (size of register set = %d):" % registerSet.GetSize(),
916        file=output,
917    )
918    for value in registerSet:
919        # print >> output, value
920        print(
921            "%s (number of children = %d):" % (value.GetName(), value.GetNumChildren()),
922            file=output,
923        )
924        for child in value:
925            print(
926                "Name: %s, Value: %s" % (child.GetName(), child.GetValue()), file=output
927            )
928
929    if string_buffer:
930        return output.getvalue()
931
932
933def get_registers(frame, kind):
934    """Returns the registers given the frame and the kind of registers desired.
935
936    Returns None if there's no such kind.
937    """
938    registerSet = frame.GetRegisters()  # Return type of SBValueList.
939    for value in registerSet:
940        if kind.lower() in value.GetName().lower():
941            return value
942
943    return None
944
945
946def get_GPRs(frame):
947    """Returns the general purpose registers of the frame as an SBValue.
948
949    The returned SBValue object is iterable.  An example:
950        ...
951        from lldbutil import get_GPRs
952        regs = get_GPRs(frame)
953        for reg in regs:
954            print "%s => %s" % (reg.GetName(), reg.GetValue())
955        ...
956    """
957    return get_registers(frame, "general purpose")
958
959
960def get_FPRs(frame):
961    """Returns the floating point registers of the frame as an SBValue.
962
963    The returned SBValue object is iterable.  An example:
964        ...
965        from lldbutil import get_FPRs
966        regs = get_FPRs(frame)
967        for reg in regs:
968            print "%s => %s" % (reg.GetName(), reg.GetValue())
969        ...
970    """
971    return get_registers(frame, "floating point")
972
973
974def get_ESRs(frame):
975    """Returns the exception state registers of the frame as an SBValue.
976
977    The returned SBValue object is iterable.  An example:
978        ...
979        from lldbutil import get_ESRs
980        regs = get_ESRs(frame)
981        for reg in regs:
982            print "%s => %s" % (reg.GetName(), reg.GetValue())
983        ...
984    """
985    return get_registers(frame, "exception state")
986
987
988# ======================================
989# Utility classes/functions for SBValues
990# ======================================
991
992
993class BasicFormatter(object):
994    """The basic formatter inspects the value object and prints the value."""
995
996    def format(self, value, buffer=None, indent=0):
997        if not buffer:
998            output = io.StringIO()
999        else:
1000            output = buffer
1001        # If there is a summary, it suffices.
1002        val = value.GetSummary()
1003        # Otherwise, get the value.
1004        if val is None:
1005            val = value.GetValue()
1006        if val is None and value.GetNumChildren() > 0:
1007            val = "%s (location)" % value.GetLocation()
1008        print(
1009            "{indentation}({type}) {name} = {value}".format(
1010                indentation=" " * indent,
1011                type=value.GetTypeName(),
1012                name=value.GetName(),
1013                value=val,
1014            ),
1015            file=output,
1016        )
1017        return output.getvalue()
1018
1019
1020class ChildVisitingFormatter(BasicFormatter):
1021    """The child visiting formatter prints the value and its immediate children.
1022
1023    The constructor takes a keyword arg: indent_child, which defaults to 2.
1024    """
1025
1026    def __init__(self, indent_child=2):
1027        """Default indentation of 2 SPC's for the children."""
1028        self.cindent = indent_child
1029
1030    def format(self, value, buffer=None):
1031        if not buffer:
1032            output = io.StringIO()
1033        else:
1034            output = buffer
1035
1036        BasicFormatter.format(self, value, buffer=output)
1037        for child in value:
1038            BasicFormatter.format(self, child, buffer=output, indent=self.cindent)
1039
1040        return output.getvalue()
1041
1042
1043class RecursiveDecentFormatter(BasicFormatter):
1044    """The recursive decent formatter prints the value and the decendents.
1045
1046    The constructor takes two keyword args: indent_level, which defaults to 0,
1047    and indent_child, which defaults to 2.  The current indentation level is
1048    determined by indent_level, while the immediate children has an additional
1049    indentation by inden_child.
1050    """
1051
1052    def __init__(self, indent_level=0, indent_child=2):
1053        self.lindent = indent_level
1054        self.cindent = indent_child
1055
1056    def format(self, value, buffer=None):
1057        if not buffer:
1058            output = io.StringIO()
1059        else:
1060            output = buffer
1061
1062        BasicFormatter.format(self, value, buffer=output, indent=self.lindent)
1063        new_indent = self.lindent + self.cindent
1064        for child in value:
1065            if child.GetSummary() is not None:
1066                BasicFormatter.format(self, child, buffer=output, indent=new_indent)
1067            else:
1068                if child.GetNumChildren() > 0:
1069                    rdf = RecursiveDecentFormatter(indent_level=new_indent)
1070                    rdf.format(child, buffer=output)
1071                else:
1072                    BasicFormatter.format(self, child, buffer=output, indent=new_indent)
1073
1074        return output.getvalue()
1075