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