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