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 errno
12import os
13import re
14import sys
15import subprocess
16
17# Third-party modules
18from six import StringIO as SixStringIO
19import six
20
21# LLDB modules
22import lldb
23from . import lldbtest_config
24from . import configuration
25
26# How often failed simulator process launches are retried.
27SIMULATOR_RETRY = 3
28
29# ===================================================
30# Utilities for locating/checking executable programs
31# ===================================================
32
33def is_exe(fpath):
34    """Returns True if fpath is an executable."""
35    return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
36
37
38def which(program):
39    """Returns the full path to a program; None otherwise."""
40    fpath, fname = os.path.split(program)
41    if fpath:
42        if is_exe(program):
43            return program
44    else:
45        for path in os.environ["PATH"].split(os.pathsep):
46            exe_file = os.path.join(path, program)
47            if is_exe(exe_file):
48                return exe_file
49    return None
50
51def mkdir_p(path):
52    try:
53        os.makedirs(path)
54    except OSError as e:
55        if e.errno != errno.EEXIST:
56            raise
57    if not os.path.isdir(path):
58        raise OSError(errno.ENOTDIR, "%s is not a directory"%path)
59
60
61# ============================
62# Dealing with SDK and triples
63# ============================
64
65def get_xcode_sdk(os, env):
66    # Respect --apple-sdk <path> if it's specified. If the SDK is simply
67    # mounted from some disk image, and not actually installed, this is the
68    # only way to use it.
69    if configuration.apple_sdk:
70        return configuration.apple_sdk
71    if os == "ios":
72        if env == "simulator":
73            return "iphonesimulator"
74        if env == "macabi":
75            return "macosx"
76        return "iphoneos"
77    elif os == "tvos":
78        if env == "simulator":
79            return "appletvsimulator"
80        return "appletvos"
81    elif os == "watchos":
82        if env == "simulator":
83            return "watchsimulator"
84        return "watchos"
85    return os
86
87
88def get_xcode_sdk_version(sdk):
89    return subprocess.check_output(
90        ['xcrun', '--sdk', sdk, '--show-sdk-version']).rstrip().decode('utf-8')
91
92
93def get_xcode_sdk_root(sdk):
94    return subprocess.check_output(['xcrun', '--sdk', sdk, '--show-sdk-path'
95                                    ]).rstrip().decode('utf-8')
96
97
98def get_xcode_clang(sdk):
99    return subprocess.check_output(['xcrun', '-sdk', sdk, '-f', 'clang'
100                                    ]).rstrip().decode("utf-8")
101
102
103# ===================================================
104# Disassembly for an SBFunction or an SBSymbol object
105# ===================================================
106
107
108def disassemble(target, function_or_symbol):
109    """Disassemble the function or symbol given a target.
110
111    It returns the disassembly content in a string object.
112    """
113    buf = SixStringIO()
114    insts = function_or_symbol.GetInstructions(target)
115    for i in insts:
116        print(i, file=buf)
117    return buf.getvalue()
118
119# ==========================================================
120# Integer (byte size 1, 2, 4, and 8) to bytearray conversion
121# ==========================================================
122
123
124def int_to_bytearray(val, bytesize):
125    """Utility function to convert an integer into a bytearray.
126
127    It returns the bytearray in the little endian format.  It is easy to get the
128    big endian format, just do ba.reverse() on the returned object.
129    """
130    import struct
131
132    if bytesize == 1:
133        return bytearray([val])
134
135    # Little endian followed by a format character.
136    template = "<%c"
137    if bytesize == 2:
138        fmt = template % 'h'
139    elif bytesize == 4:
140        fmt = template % 'i'
141    elif bytesize == 4:
142        fmt = template % 'q'
143    else:
144        return None
145
146    packed = struct.pack(fmt, val)
147    return bytearray(packed)
148
149
150def bytearray_to_int(bytes, bytesize):
151    """Utility function to convert a bytearray into an integer.
152
153    It interprets the bytearray in the little endian format. For a big endian
154    bytearray, just do ba.reverse() on the object before passing it in.
155    """
156    import struct
157
158    if bytesize == 1:
159        return bytes[0]
160
161    # Little endian followed by a format character.
162    template = "<%c"
163    if bytesize == 2:
164        fmt = template % 'h'
165    elif bytesize == 4:
166        fmt = template % 'i'
167    elif bytesize == 4:
168        fmt = template % 'q'
169    else:
170        return None
171
172    unpacked = struct.unpack_from(fmt, bytes)
173    return unpacked[0]
174
175
176# ==============================================================
177# Get the description of an lldb object or None if not available
178# ==============================================================
179def get_description(obj, option=None):
180    """Calls lldb_obj.GetDescription() and returns a string, or None.
181
182    For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra
183    option can be passed in to describe the detailed level of description
184    desired:
185        o lldb.eDescriptionLevelBrief
186        o lldb.eDescriptionLevelFull
187        o lldb.eDescriptionLevelVerbose
188    """
189    method = getattr(obj, 'GetDescription')
190    if not method:
191        return None
192    tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint)
193    if isinstance(obj, tuple):
194        if option is None:
195            option = lldb.eDescriptionLevelBrief
196
197    stream = lldb.SBStream()
198    if option is None:
199        success = method(stream)
200    else:
201        success = method(stream, option)
202    if not success:
203        return None
204    return stream.GetData()
205
206
207# =================================================
208# Convert some enum value to its string counterpart
209# =================================================
210
211def state_type_to_str(enum):
212    """Returns the stateType string given an enum."""
213    if enum == lldb.eStateInvalid:
214        return "invalid"
215    elif enum == lldb.eStateUnloaded:
216        return "unloaded"
217    elif enum == lldb.eStateConnected:
218        return "connected"
219    elif enum == lldb.eStateAttaching:
220        return "attaching"
221    elif enum == lldb.eStateLaunching:
222        return "launching"
223    elif enum == lldb.eStateStopped:
224        return "stopped"
225    elif enum == lldb.eStateRunning:
226        return "running"
227    elif enum == lldb.eStateStepping:
228        return "stepping"
229    elif enum == lldb.eStateCrashed:
230        return "crashed"
231    elif enum == lldb.eStateDetached:
232        return "detached"
233    elif enum == lldb.eStateExited:
234        return "exited"
235    elif enum == lldb.eStateSuspended:
236        return "suspended"
237    else:
238        raise Exception("Unknown StateType enum: " + str(enum))
239
240
241def stop_reason_to_str(enum):
242    """Returns the stopReason string given an enum."""
243    if enum == lldb.eStopReasonInvalid:
244        return "invalid"
245    elif enum == lldb.eStopReasonNone:
246        return "none"
247    elif enum == lldb.eStopReasonTrace:
248        return "trace"
249    elif enum == lldb.eStopReasonBreakpoint:
250        return "breakpoint"
251    elif enum == lldb.eStopReasonWatchpoint:
252        return "watchpoint"
253    elif enum == lldb.eStopReasonExec:
254        return "exec"
255    elif enum == lldb.eStopReasonFork:
256        return "fork"
257    elif enum == lldb.eStopReasonVFork:
258        return "vfork"
259    elif enum == lldb.eStopReasonVForkDone:
260        return "vforkdone"
261    elif enum == lldb.eStopReasonSignal:
262        return "signal"
263    elif enum == lldb.eStopReasonException:
264        return "exception"
265    elif enum == lldb.eStopReasonPlanComplete:
266        return "plancomplete"
267    elif enum == lldb.eStopReasonThreadExiting:
268        return "threadexiting"
269    else:
270        raise Exception("Unknown StopReason enum")
271
272
273def symbol_type_to_str(enum):
274    """Returns the symbolType string given an enum."""
275    if enum == lldb.eSymbolTypeInvalid:
276        return "invalid"
277    elif enum == lldb.eSymbolTypeAbsolute:
278        return "absolute"
279    elif enum == lldb.eSymbolTypeCode:
280        return "code"
281    elif enum == lldb.eSymbolTypeData:
282        return "data"
283    elif enum == lldb.eSymbolTypeTrampoline:
284        return "trampoline"
285    elif enum == lldb.eSymbolTypeRuntime:
286        return "runtime"
287    elif enum == lldb.eSymbolTypeException:
288        return "exception"
289    elif enum == lldb.eSymbolTypeSourceFile:
290        return "sourcefile"
291    elif enum == lldb.eSymbolTypeHeaderFile:
292        return "headerfile"
293    elif enum == lldb.eSymbolTypeObjectFile:
294        return "objectfile"
295    elif enum == lldb.eSymbolTypeCommonBlock:
296        return "commonblock"
297    elif enum == lldb.eSymbolTypeBlock:
298        return "block"
299    elif enum == lldb.eSymbolTypeLocal:
300        return "local"
301    elif enum == lldb.eSymbolTypeParam:
302        return "param"
303    elif enum == lldb.eSymbolTypeVariable:
304        return "variable"
305    elif enum == lldb.eSymbolTypeVariableType:
306        return "variabletype"
307    elif enum == lldb.eSymbolTypeLineEntry:
308        return "lineentry"
309    elif enum == lldb.eSymbolTypeLineHeader:
310        return "lineheader"
311    elif enum == lldb.eSymbolTypeScopeBegin:
312        return "scopebegin"
313    elif enum == lldb.eSymbolTypeScopeEnd:
314        return "scopeend"
315    elif enum == lldb.eSymbolTypeAdditional:
316        return "additional"
317    elif enum == lldb.eSymbolTypeCompiler:
318        return "compiler"
319    elif enum == lldb.eSymbolTypeInstrumentation:
320        return "instrumentation"
321    elif enum == lldb.eSymbolTypeUndefined:
322        return "undefined"
323
324
325def value_type_to_str(enum):
326    """Returns the valueType string given an enum."""
327    if enum == lldb.eValueTypeInvalid:
328        return "invalid"
329    elif enum == lldb.eValueTypeVariableGlobal:
330        return "global_variable"
331    elif enum == lldb.eValueTypeVariableStatic:
332        return "static_variable"
333    elif enum == lldb.eValueTypeVariableArgument:
334        return "argument_variable"
335    elif enum == lldb.eValueTypeVariableLocal:
336        return "local_variable"
337    elif enum == lldb.eValueTypeRegister:
338        return "register"
339    elif enum == lldb.eValueTypeRegisterSet:
340        return "register_set"
341    elif enum == lldb.eValueTypeConstResult:
342        return "constant_result"
343    else:
344        raise Exception("Unknown ValueType enum")
345
346
347# ==================================================
348# Get stopped threads due to each stop reason.
349# ==================================================
350
351def sort_stopped_threads(process,
352                         breakpoint_threads=None,
353                         crashed_threads=None,
354                         watchpoint_threads=None,
355                         signal_threads=None,
356                         exiting_threads=None,
357                         other_threads=None):
358    """ Fills array *_threads with threads stopped for the corresponding stop
359        reason.
360    """
361    for lst in [breakpoint_threads,
362                watchpoint_threads,
363                signal_threads,
364                exiting_threads,
365                other_threads]:
366        if lst is not None:
367            lst[:] = []
368
369    for thread in process:
370        dispatched = False
371        for (reason, list) in [(lldb.eStopReasonBreakpoint, breakpoint_threads),
372                               (lldb.eStopReasonException, crashed_threads),
373                               (lldb.eStopReasonWatchpoint, watchpoint_threads),
374                               (lldb.eStopReasonSignal, signal_threads),
375                               (lldb.eStopReasonThreadExiting, exiting_threads),
376                               (None, other_threads)]:
377            if not dispatched and list is not None:
378                if thread.GetStopReason() == reason or reason is None:
379                    list.append(thread)
380                    dispatched = True
381
382# ==================================================
383# Utility functions for setting breakpoints
384# ==================================================
385
386def run_break_set_by_script(
387        test,
388        class_name,
389        extra_options=None,
390        num_expected_locations=1):
391    """Set a scripted breakpoint.  Check that it got the right number of locations."""
392    test.assertTrue(class_name is not None, "Must pass in a class name.")
393    command = "breakpoint set -P " + class_name
394    if extra_options is not None:
395        command += " " + extra_options
396
397    break_results = run_break_set_command(test, command)
398    check_breakpoint_result(test, break_results, num_locations=num_expected_locations)
399    return get_bpno_from_match(break_results)
400
401def run_break_set_by_file_and_line(
402        test,
403        file_name,
404        line_number,
405        extra_options=None,
406        num_expected_locations=1,
407        loc_exact=False,
408        module_name=None):
409    """Set a breakpoint by file and line, returning the breakpoint number.
410
411    If extra_options is not None, then we append it to the breakpoint set command.
412
413    If num_expected_locations is -1, we check that we got AT LEAST one location. If num_expected_locations is -2, we don't
414    check the actual number at all. Otherwise, we check that num_expected_locations equals the number of locations.
415
416    If loc_exact is true, we check that there is one location, and that location must be at the input file and line number."""
417
418    if file_name is None:
419        command = 'breakpoint set -l %d' % (line_number)
420    else:
421        command = 'breakpoint set -f "%s" -l %d' % (file_name, line_number)
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 and loc_exact:
432        check_breakpoint_result(
433            test,
434            break_results,
435            num_locations=num_expected_locations,
436            file_name=file_name,
437            line_number=line_number,
438            module_name=module_name)
439    else:
440        check_breakpoint_result(
441            test,
442            break_results,
443            num_locations=num_expected_locations)
444
445    return get_bpno_from_match(break_results)
446
447
448def run_break_set_by_symbol(
449        test,
450        symbol,
451        extra_options=None,
452        num_expected_locations=-1,
453        sym_exact=False,
454        module_name=None):
455    """Set a breakpoint by symbol name.  Common options are the same as run_break_set_by_file_and_line.
456
457    If sym_exact is true, then the output symbol must match the input exactly, otherwise we do a substring match."""
458    command = 'breakpoint set -n "%s"' % (symbol)
459
460    if module_name:
461        command += " --shlib '%s'" % (module_name)
462
463    if extra_options:
464        command += " " + extra_options
465
466    break_results = run_break_set_command(test, command)
467
468    if num_expected_locations == 1 and sym_exact:
469        check_breakpoint_result(
470            test,
471            break_results,
472            num_locations=num_expected_locations,
473            symbol_name=symbol,
474            module_name=module_name)
475    else:
476        check_breakpoint_result(
477            test,
478            break_results,
479            num_locations=num_expected_locations)
480
481    return get_bpno_from_match(break_results)
482
483
484def run_break_set_by_selector(
485        test,
486        selector,
487        extra_options=None,
488        num_expected_locations=-1,
489        module_name=None):
490    """Set a breakpoint by selector.  Common options are the same as run_break_set_by_file_and_line."""
491
492    command = 'breakpoint set -S "%s"' % (selector)
493
494    if module_name:
495        command += ' --shlib "%s"' % (module_name)
496
497    if extra_options:
498        command += " " + extra_options
499
500    break_results = run_break_set_command(test, command)
501
502    if num_expected_locations == 1:
503        check_breakpoint_result(
504            test,
505            break_results,
506            num_locations=num_expected_locations,
507            symbol_name=selector,
508            symbol_match_exact=False,
509            module_name=module_name)
510    else:
511        check_breakpoint_result(
512            test,
513            break_results,
514            num_locations=num_expected_locations)
515
516    return get_bpno_from_match(break_results)
517
518
519def run_break_set_by_regexp(
520        test,
521        regexp,
522        extra_options=None,
523        num_expected_locations=-1):
524    """Set a breakpoint by regular expression match on symbol name.  Common options are the same as run_break_set_by_file_and_line."""
525
526    command = 'breakpoint set -r "%s"' % (regexp)
527    if extra_options:
528        command += " " + extra_options
529
530    break_results = run_break_set_command(test, command)
531
532    check_breakpoint_result(
533        test,
534        break_results,
535        num_locations=num_expected_locations)
536
537    return get_bpno_from_match(break_results)
538
539
540def run_break_set_by_source_regexp(
541        test,
542        regexp,
543        extra_options=None,
544        num_expected_locations=-1):
545    """Set a breakpoint by source regular expression.  Common options are the same as run_break_set_by_file_and_line."""
546    command = 'breakpoint set -p "%s"' % (regexp)
547    if extra_options:
548        command += " " + extra_options
549
550    break_results = run_break_set_command(test, command)
551
552    check_breakpoint_result(
553        test,
554        break_results,
555        num_locations=num_expected_locations)
556
557    return get_bpno_from_match(break_results)
558
559def run_break_set_by_file_colon_line(
560        test,
561        specifier,
562        path,
563        line_number,
564        column_number = 0,
565        extra_options=None,
566        num_expected_locations=-1):
567    command = 'breakpoint set -y "%s"'%(specifier)
568    if extra_options:
569        command += " " + extra_options
570
571    print("About to run: '%s'", command)
572    break_results = run_break_set_command(test, command)
573    check_breakpoint_result(
574        test,
575        break_results,
576        num_locations = num_expected_locations,
577        file_name = path,
578        line_number = line_number,
579        column_number = column_number)
580
581    return get_bpno_from_match(break_results)
582
583def run_break_set_command(test, command):
584    """Run the command passed in - it must be some break set variant - and analyze the result.
585    Returns a dictionary of information gleaned from the command-line results.
586    Will assert if the breakpoint setting fails altogether.
587
588    Dictionary will contain:
589        bpno          - breakpoint of the newly created breakpoint, -1 on error.
590        num_locations - number of locations set for the breakpoint.
591
592    If there is only one location, the dictionary MAY contain:
593        file          - source file name
594        line_no       - source line number
595        column        - source column number
596        symbol        - symbol name
597        inline_symbol - inlined symbol name
598        offset        - offset from the original symbol
599        module        - module
600        address       - address at which the breakpoint was set."""
601
602    patterns = [
603        r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>[0-9]+) locations\.$",
604        r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>no) locations \(pending\)\.",
605        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]+)(?P<column>(:[0-9]+)?), address = (?P<address>0x[0-9a-fA-F]+)$",
606        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]+)$"]
607    match_object = test.match(command, patterns)
608    break_results = match_object.groupdict()
609
610    # We always insert the breakpoint number, setting it to -1 if we couldn't find it
611    # Also, make sure it gets stored as an integer.
612    if not 'bpno' in break_results:
613        break_results['bpno'] = -1
614    else:
615        break_results['bpno'] = int(break_results['bpno'])
616
617    # We always insert the number of locations
618    # If ONE location is set for the breakpoint, then the output doesn't mention locations, but it has to be 1...
619    # We also make sure it is an integer.
620
621    if not 'num_locations' in break_results:
622        num_locations = 1
623    else:
624        num_locations = break_results['num_locations']
625        if num_locations == 'no':
626            num_locations = 0
627        else:
628            num_locations = int(break_results['num_locations'])
629
630    break_results['num_locations'] = num_locations
631
632    if 'line_no' in break_results:
633        break_results['line_no'] = int(break_results['line_no'])
634
635    return break_results
636
637
638def get_bpno_from_match(break_results):
639    return int(break_results['bpno'])
640
641
642def check_breakpoint_result(
643        test,
644        break_results,
645        file_name=None,
646        line_number=-1,
647        column_number=0,
648        symbol_name=None,
649        symbol_match_exact=True,
650        module_name=None,
651        offset=-1,
652        num_locations=-1):
653
654    out_num_locations = break_results['num_locations']
655
656    if num_locations == -1:
657        test.assertTrue(out_num_locations > 0,
658                        "Expecting one or more locations, got none.")
659    elif num_locations != -2:
660        test.assertTrue(
661            num_locations == out_num_locations,
662            "Expecting %d locations, got %d." %
663            (num_locations,
664             out_num_locations))
665
666    if file_name:
667        out_file_name = ""
668        if 'file' in break_results:
669            out_file_name = break_results['file']
670        test.assertTrue(
671            file_name.endswith(out_file_name),
672            "Breakpoint file name '%s' doesn't match resultant name '%s'." %
673            (file_name,
674             out_file_name))
675
676    if line_number != -1:
677        out_line_number = -1
678        if 'line_no' in break_results:
679            out_line_number = break_results['line_no']
680
681        test.assertTrue(
682            line_number == out_line_number,
683            "Breakpoint line number %s doesn't match resultant line %s." %
684            (line_number,
685             out_line_number))
686
687    if column_number != 0:
688        out_column_number = 0
689        if 'column' in break_results:
690            out_column_number = break_results['column']
691
692        test.assertTrue(
693            column_number == out_column_number,
694            "Breakpoint column number %s doesn't match resultant column %s." %
695            (column_number,
696             out_column_number))
697
698    if symbol_name:
699        out_symbol_name = ""
700        # Look first for the inlined symbol name, otherwise use the symbol
701        # name:
702        if 'inline_symbol' in break_results and break_results['inline_symbol']:
703            out_symbol_name = break_results['inline_symbol']
704        elif 'symbol' in break_results:
705            out_symbol_name = break_results['symbol']
706
707        if symbol_match_exact:
708            test.assertTrue(
709                symbol_name == out_symbol_name,
710                "Symbol name '%s' doesn't match resultant symbol '%s'." %
711                (symbol_name,
712                 out_symbol_name))
713        else:
714            test.assertTrue(
715                out_symbol_name.find(symbol_name) != -
716                1,
717                "Symbol name '%s' isn't in resultant symbol '%s'." %
718                (symbol_name,
719                 out_symbol_name))
720
721    if module_name:
722        out_module_name = None
723        if 'module' in break_results:
724            out_module_name = break_results['module']
725
726        test.assertTrue(
727            module_name.find(out_module_name) != -
728            1,
729            "Symbol module name '%s' isn't in expected module name '%s'." %
730            (out_module_name,
731             module_name))
732
733def check_breakpoint(
734            test,
735            bpno,
736            expected_locations = None,
737            expected_resolved_count = None,
738            expected_hit_count = None,
739            location_id = None,
740            expected_location_resolved = True,
741            expected_location_hit_count = None):
742    """
743    Test breakpoint or breakpoint location.
744    Breakpoint resolved count is always checked. If not specified the assumption is that all locations
745    should be resolved.
746    To test a breakpoint location, breakpoint number (bpno) and location_id must be set. In this case
747    the resolved count for a breakpoint is not tested by default. The location is expected to be resolved,
748    unless expected_location_resolved is set to False.
749    test - test context
750    bpno - breakpoint number to test
751    expected_locations - expected number of locations for this breakpoint. If 'None' this parameter is not tested.
752    expected_resolved_count - expected resolved locations number for the breakpoint.  If 'None' - all locations should be resolved.
753    expected_hit_count - expected hit count for this breakpoint. If 'None' this parameter is not tested.
754    location_id - If not 'None' sets the location ID for the breakpoint to test.
755    expected_location_resolved - Extected resolved status for the location_id (True/False). Default - True.
756    expected_location_hit_count - Expected hit count for the breakpoint at location_id. Must be set if the location_id parameter is set.
757    """
758
759    if isinstance(test.target, lldb.SBTarget):
760        target = test.target
761    else:
762        target = test.target()
763    bkpt = target.FindBreakpointByID(bpno)
764
765    test.assertTrue(bkpt.IsValid(), "Breakpoint is not valid.")
766
767    if expected_locations is not None:
768        test.assertEquals(expected_locations, bkpt.GetNumLocations())
769
770    if expected_resolved_count is not None:
771        test.assertEquals(expected_resolved_count, bkpt.GetNumResolvedLocations())
772    else:
773        expected_resolved_count = bkpt.GetNumLocations()
774        if location_id is None:
775            test.assertEquals(expected_resolved_count, bkpt.GetNumResolvedLocations())
776
777    if expected_hit_count is not None:
778        test.assertEquals(expected_hit_count, bkpt.GetHitCount())
779
780    if location_id is not None:
781        loc_bkpt = bkpt.FindLocationByID(location_id)
782        test.assertTrue(loc_bkpt.IsValid(), "Breakpoint location is not valid.")
783        test.assertEquals(loc_bkpt.IsResolved(), expected_location_resolved)
784        if expected_location_hit_count is not None:
785            test.assertEquals(expected_location_hit_count, loc_bkpt.GetHitCount())
786
787
788
789# ==================================================
790# Utility functions related to Threads and Processes
791# ==================================================
792
793
794def get_stopped_threads(process, reason):
795    """Returns the thread(s) with the specified stop reason in a list.
796
797    The list can be empty if no such thread exists.
798    """
799    threads = []
800    for t in process:
801        if t.GetStopReason() == reason:
802            threads.append(t)
803    return threads
804
805
806def get_stopped_thread(process, reason):
807    """A convenience function which returns the first thread with the given stop
808    reason or None.
809
810    Example usages:
811
812    1. Get the stopped thread due to a breakpoint condition
813
814    ...
815        from lldbutil import get_stopped_thread
816        thread = get_stopped_thread(process, lldb.eStopReasonPlanComplete)
817        self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint condition")
818    ...
819
820    2. Get the thread stopped due to a breakpoint
821
822    ...
823        from lldbutil import get_stopped_thread
824        thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
825        self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint")
826    ...
827
828    """
829    threads = get_stopped_threads(process, reason)
830    if len(threads) == 0:
831        return None
832    return threads[0]
833
834
835def get_threads_stopped_at_breakpoint_id(process, bpid):
836    """ For a stopped process returns the thread stopped at the breakpoint passed in bkpt"""
837    stopped_threads = []
838    threads = []
839
840    stopped_threads = get_stopped_threads(process, lldb.eStopReasonBreakpoint)
841
842    if len(stopped_threads) == 0:
843        return threads
844
845    for thread in stopped_threads:
846        # Make sure we've hit our breakpoint...
847        break_id = thread.GetStopReasonDataAtIndex(0)
848        if break_id == bpid:
849            threads.append(thread)
850
851    return threads
852
853
854def get_threads_stopped_at_breakpoint(process, bkpt):
855    return get_threads_stopped_at_breakpoint_id(process, bkpt.GetID())
856
857
858def get_one_thread_stopped_at_breakpoint_id(
859        process, bpid, require_exactly_one=True):
860    threads = get_threads_stopped_at_breakpoint_id(process, bpid)
861    if len(threads) == 0:
862        return None
863    if require_exactly_one and len(threads) != 1:
864        return None
865
866    return threads[0]
867
868
869def get_one_thread_stopped_at_breakpoint(
870        process, bkpt, require_exactly_one=True):
871    return get_one_thread_stopped_at_breakpoint_id(
872        process, bkpt.GetID(), require_exactly_one)
873
874
875def is_thread_crashed(test, thread):
876    """In the test suite we dereference a null pointer to simulate a crash. The way this is
877    reported depends on the platform."""
878    if test.platformIsDarwin():
879        return thread.GetStopReason(
880        ) == lldb.eStopReasonException and "EXC_BAD_ACCESS" in thread.GetStopDescription(100)
881    elif test.getPlatform() == "linux":
882        return thread.GetStopReason() == lldb.eStopReasonSignal and thread.GetStopReasonDataAtIndex(
883            0) == thread.GetProcess().GetUnixSignals().GetSignalNumberFromName("SIGSEGV")
884    elif test.getPlatform() == "windows":
885        return "Exception 0xc0000005" in thread.GetStopDescription(200)
886    else:
887        return "invalid address" in thread.GetStopDescription(100)
888
889
890def get_crashed_threads(test, process):
891    threads = []
892    if process.GetState() != lldb.eStateStopped:
893        return threads
894    for thread in process:
895        if is_thread_crashed(test, thread):
896            threads.append(thread)
897    return threads
898
899# Helper functions for run_to_{source,name}_breakpoint:
900
901def run_to_breakpoint_make_target(test, exe_name = "a.out", in_cwd = True):
902    if in_cwd:
903        exe = test.getBuildArtifact(exe_name)
904
905    # Create the target
906    target = test.dbg.CreateTarget(exe)
907    test.assertTrue(target, "Target: %s is not valid."%(exe_name))
908
909    # Set environment variables for the inferior.
910    if lldbtest_config.inferior_env:
911        test.runCmd('settings set target.env-vars {}'.format(
912            lldbtest_config.inferior_env))
913
914    return target
915
916def run_to_breakpoint_do_run(test, target, bkpt, launch_info = None,
917                             only_one_thread = True, extra_images = None):
918
919    # Launch the process, and do not stop at the entry point.
920    if not launch_info:
921        launch_info = target.GetLaunchInfo()
922        launch_info.SetWorkingDirectory(test.get_process_working_directory())
923
924    if extra_images:
925        environ = test.registerSharedLibrariesWithTarget(target, extra_images)
926        launch_info.SetEnvironmentEntries(environ, True)
927
928    error = lldb.SBError()
929    process = target.Launch(launch_info, error)
930
931    # Unfortunate workaround for the iPhone simulator.
932    retry = SIMULATOR_RETRY
933    while (retry and error.Fail() and error.GetCString() and
934           "Unable to boot the Simulator" in error.GetCString()):
935        retry -= 1
936        print("** Simulator is unresponsive. Retrying %d more time(s)"%retry)
937        import time
938        time.sleep(60)
939        error = lldb.SBError()
940        process = target.Launch(launch_info, error)
941
942    test.assertTrue(process,
943                    "Could not create a valid process for %s: %s" %
944                    (target.GetExecutable().GetFilename(), error.GetCString()))
945    test.assertFalse(error.Fail(),
946                     "Process launch failed: %s" % (error.GetCString()))
947
948    def processStateInfo(process):
949        info = "state: {}".format(state_type_to_str(process.state))
950        if process.state == lldb.eStateExited:
951            info += ", exit code: {}".format(process.GetExitStatus())
952            if process.exit_description:
953                info += ", exit description: '{}'".format(process.exit_description)
954        stdout = process.GetSTDOUT(999)
955        if stdout:
956            info += ", stdout: '{}'".format(stdout)
957        stderr = process.GetSTDERR(999)
958        if stderr:
959            info += ", stderr: '{}'".format(stderr)
960        return info
961
962    if process.state != lldb.eStateStopped:
963        test.fail("Test process is not stopped at breakpoint: {}".format(processStateInfo(process)))
964
965    # Frame #0 should be at our breakpoint.
966    threads = get_threads_stopped_at_breakpoint(
967                process, bkpt)
968
969    num_threads = len(threads)
970    if only_one_thread:
971        test.assertEqual(num_threads, 1, "Expected 1 thread to stop at breakpoint, %d did."%(num_threads))
972    else:
973        test.assertGreater(num_threads, 0, "No threads stopped at breakpoint")
974
975    thread = threads[0]
976    return (target, process, thread, bkpt)
977
978def run_to_name_breakpoint (test, bkpt_name, launch_info = None,
979                            exe_name = "a.out",
980                            bkpt_module = None,
981                            in_cwd = True,
982                            only_one_thread = True,
983                            extra_images = None):
984    """Start up a target, using exe_name as the executable, and run it to
985       a breakpoint set by name on bkpt_name restricted to bkpt_module.
986
987       If you want to pass in launch arguments or environment
988       variables, you can optionally pass in an SBLaunchInfo.  If you
989       do that, remember to set the working directory as well.
990
991       If your executable isn't called a.out, you can pass that in.
992       And if your executable isn't in the CWD, pass in the absolute
993       path to the executable in exe_name, and set in_cwd to False.
994
995       If you need to restrict the breakpoint to a particular module,
996       pass the module name (a string not a FileSpec) in bkpt_module.  If
997       nothing is passed in setting will be unrestricted.
998
999       If the target isn't valid, the breakpoint isn't found, or hit, the
1000       function will cause a testsuite failure.
1001
1002       If successful it returns a tuple with the target process and
1003       thread that hit the breakpoint, and the breakpoint that we set
1004       for you.
1005
1006       If only_one_thread is true, we require that there be only one
1007       thread stopped at the breakpoint.  Otherwise we only require one
1008       or more threads stop there.  If there are more than one, we return
1009       the first thread that stopped.
1010    """
1011
1012    target = run_to_breakpoint_make_target(test, exe_name, in_cwd)
1013
1014    breakpoint = target.BreakpointCreateByName(bkpt_name, bkpt_module)
1015
1016
1017    test.assertTrue(breakpoint.GetNumLocations() > 0,
1018                    "No locations found for name breakpoint: '%s'."%(bkpt_name))
1019    return run_to_breakpoint_do_run(test, target, breakpoint, launch_info,
1020                                    only_one_thread, extra_images)
1021
1022def run_to_source_breakpoint(test, bkpt_pattern, source_spec,
1023                             launch_info = None, exe_name = "a.out",
1024                             bkpt_module = None,
1025                             in_cwd = True,
1026                             only_one_thread = True,
1027                             extra_images = None,
1028                             has_locations_before_run = True):
1029    """Start up a target, using exe_name as the executable, and run it to
1030       a breakpoint set by source regex bkpt_pattern.
1031
1032       The rest of the behavior is the same as run_to_name_breakpoint.
1033    """
1034
1035    target = run_to_breakpoint_make_target(test, exe_name, in_cwd)
1036    # Set the breakpoints
1037    breakpoint = target.BreakpointCreateBySourceRegex(
1038            bkpt_pattern, source_spec, bkpt_module)
1039    if has_locations_before_run:
1040        test.assertTrue(breakpoint.GetNumLocations() > 0,
1041                        'No locations found for source breakpoint: "%s", file: "%s", dir: "%s"'
1042                        %(bkpt_pattern, source_spec.GetFilename(), source_spec.GetDirectory()))
1043    return run_to_breakpoint_do_run(test, target, breakpoint, launch_info,
1044                                    only_one_thread, extra_images)
1045
1046def run_to_line_breakpoint(test, source_spec, line_number, column = 0,
1047                           launch_info = None, exe_name = "a.out",
1048                           bkpt_module = None,
1049                           in_cwd = True,
1050                           only_one_thread = True,
1051                           extra_images = None):
1052    """Start up a target, using exe_name as the executable, and run it to
1053       a breakpoint set by (source_spec, line_number(, column)).
1054
1055       The rest of the behavior is the same as run_to_name_breakpoint.
1056    """
1057
1058    target = run_to_breakpoint_make_target(test, exe_name, in_cwd)
1059    # Set the breakpoints
1060    breakpoint = target.BreakpointCreateByLocation(
1061        source_spec, line_number, column, 0, lldb.SBFileSpecList())
1062    test.assertTrue(breakpoint.GetNumLocations() > 0,
1063        'No locations found for line breakpoint: "%s:%d(:%d)", dir: "%s"'
1064        %(source_spec.GetFilename(), line_number, column,
1065          source_spec.GetDirectory()))
1066    return run_to_breakpoint_do_run(test, target, breakpoint, launch_info,
1067                                    only_one_thread, extra_images)
1068
1069
1070def continue_to_breakpoint(process, bkpt):
1071    """ Continues the process, if it stops, returns the threads stopped at bkpt; otherwise, returns None"""
1072    process.Continue()
1073    if process.GetState() != lldb.eStateStopped:
1074        return None
1075    else:
1076        return get_threads_stopped_at_breakpoint(process, bkpt)
1077
1078
1079def get_caller_symbol(thread):
1080    """
1081    Returns the symbol name for the call site of the leaf function.
1082    """
1083    depth = thread.GetNumFrames()
1084    if depth <= 1:
1085        return None
1086    caller = thread.GetFrameAtIndex(1).GetSymbol()
1087    if caller:
1088        return caller.GetName()
1089    else:
1090        return None
1091
1092
1093def get_function_names(thread):
1094    """
1095    Returns a sequence of function names from the stack frames of this thread.
1096    """
1097    def GetFuncName(i):
1098        return thread.GetFrameAtIndex(i).GetFunctionName()
1099
1100    return list(map(GetFuncName, list(range(thread.GetNumFrames()))))
1101
1102
1103def get_symbol_names(thread):
1104    """
1105    Returns a sequence of symbols for this thread.
1106    """
1107    def GetSymbol(i):
1108        return thread.GetFrameAtIndex(i).GetSymbol().GetName()
1109
1110    return list(map(GetSymbol, list(range(thread.GetNumFrames()))))
1111
1112
1113def get_pc_addresses(thread):
1114    """
1115    Returns a sequence of pc addresses for this thread.
1116    """
1117    def GetPCAddress(i):
1118        return thread.GetFrameAtIndex(i).GetPCAddress()
1119
1120    return list(map(GetPCAddress, list(range(thread.GetNumFrames()))))
1121
1122
1123def get_filenames(thread):
1124    """
1125    Returns a sequence of file names from the stack frames of this thread.
1126    """
1127    def GetFilename(i):
1128        return thread.GetFrameAtIndex(
1129            i).GetLineEntry().GetFileSpec().GetFilename()
1130
1131    return list(map(GetFilename, list(range(thread.GetNumFrames()))))
1132
1133
1134def get_line_numbers(thread):
1135    """
1136    Returns a sequence of line numbers from the stack frames of this thread.
1137    """
1138    def GetLineNumber(i):
1139        return thread.GetFrameAtIndex(i).GetLineEntry().GetLine()
1140
1141    return list(map(GetLineNumber, list(range(thread.GetNumFrames()))))
1142
1143
1144def get_module_names(thread):
1145    """
1146    Returns a sequence of module names from the stack frames of this thread.
1147    """
1148    def GetModuleName(i):
1149        return thread.GetFrameAtIndex(
1150            i).GetModule().GetFileSpec().GetFilename()
1151
1152    return list(map(GetModuleName, list(range(thread.GetNumFrames()))))
1153
1154
1155def get_stack_frames(thread):
1156    """
1157    Returns a sequence of stack frames for this thread.
1158    """
1159    def GetStackFrame(i):
1160        return thread.GetFrameAtIndex(i)
1161
1162    return list(map(GetStackFrame, list(range(thread.GetNumFrames()))))
1163
1164
1165def print_stacktrace(thread, string_buffer=False):
1166    """Prints a simple stack trace of this thread."""
1167
1168    output = SixStringIO() if string_buffer else sys.stdout
1169    target = thread.GetProcess().GetTarget()
1170
1171    depth = thread.GetNumFrames()
1172
1173    mods = get_module_names(thread)
1174    funcs = get_function_names(thread)
1175    symbols = get_symbol_names(thread)
1176    files = get_filenames(thread)
1177    lines = get_line_numbers(thread)
1178    addrs = get_pc_addresses(thread)
1179
1180    if thread.GetStopReason() != lldb.eStopReasonInvalid:
1181        desc = "stop reason=" + stop_reason_to_str(thread.GetStopReason())
1182    else:
1183        desc = ""
1184    print(
1185        "Stack trace for thread id={0:#x} name={1} queue={2} ".format(
1186            thread.GetThreadID(),
1187            thread.GetName(),
1188            thread.GetQueueName()) + desc,
1189        file=output)
1190
1191    for i in range(depth):
1192        frame = thread.GetFrameAtIndex(i)
1193        function = frame.GetFunction()
1194
1195        load_addr = addrs[i].GetLoadAddress(target)
1196        if not function:
1197            file_addr = addrs[i].GetFileAddress()
1198            start_addr = frame.GetSymbol().GetStartAddress().GetFileAddress()
1199            symbol_offset = file_addr - start_addr
1200            print(
1201                "  frame #{num}: {addr:#016x} {mod}`{symbol} + {offset}".format(
1202                    num=i,
1203                    addr=load_addr,
1204                    mod=mods[i],
1205                    symbol=symbols[i],
1206                    offset=symbol_offset),
1207                file=output)
1208        else:
1209            print(
1210                "  frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line} {args}".format(
1211                    num=i,
1212                    addr=load_addr,
1213                    mod=mods[i],
1214                    func='%s [inlined]' %
1215                    funcs[i] if frame.IsInlined() else funcs[i],
1216                    file=files[i],
1217                    line=lines[i],
1218                    args=get_args_as_string(
1219                        frame,
1220                        showFuncName=False) if not frame.IsInlined() else '()'),
1221                file=output)
1222
1223    if string_buffer:
1224        return output.getvalue()
1225
1226
1227def print_stacktraces(process, string_buffer=False):
1228    """Prints the stack traces of all the threads."""
1229
1230    output = SixStringIO() if string_buffer else sys.stdout
1231
1232    print("Stack traces for " + str(process), file=output)
1233
1234    for thread in process:
1235        print(print_stacktrace(thread, string_buffer=True), file=output)
1236
1237    if string_buffer:
1238        return output.getvalue()
1239
1240
1241def expect_state_changes(test, listener, process, states, timeout=30):
1242    """Listens for state changed events on the listener and makes sure they match what we
1243    expect. Stop-and-restart events (where GetRestartedFromEvent() returns true) are ignored."""
1244
1245    for expected_state in states:
1246        def get_next_event():
1247            event = lldb.SBEvent()
1248            if not listener.WaitForEventForBroadcasterWithType(
1249                    timeout,
1250                    process.GetBroadcaster(),
1251                    lldb.SBProcess.eBroadcastBitStateChanged,
1252                    event):
1253                test.fail(
1254                    "Timed out while waiting for a transition to state %s" %
1255                    lldb.SBDebugger.StateAsCString(expected_state))
1256            return event
1257
1258        event = get_next_event()
1259        while (lldb.SBProcess.GetStateFromEvent(event) == lldb.eStateStopped and
1260                lldb.SBProcess.GetRestartedFromEvent(event)):
1261            # Ignore restarted event and the subsequent running event.
1262            event = get_next_event()
1263            test.assertEqual(
1264                lldb.SBProcess.GetStateFromEvent(event),
1265                lldb.eStateRunning,
1266                "Restarted event followed by a running event")
1267            event = get_next_event()
1268
1269        test.assertEqual(
1270            lldb.SBProcess.GetStateFromEvent(event),
1271            expected_state)
1272
1273def start_listening_from(broadcaster, event_mask):
1274    """Creates a listener for a specific event mask and add it to the source broadcaster."""
1275
1276    listener = lldb.SBListener("lldb.test.listener")
1277    broadcaster.AddListener(listener, event_mask)
1278    return listener
1279
1280def fetch_next_event(test, listener, broadcaster, timeout=10):
1281    """Fetch one event from the listener and return it if it matches the provided broadcaster.
1282    Fails otherwise."""
1283
1284    event = lldb.SBEvent()
1285
1286    if listener.WaitForEvent(timeout, event):
1287        if event.BroadcasterMatchesRef(broadcaster):
1288            return event
1289
1290        test.fail("received event '%s' from unexpected broadcaster '%s'." %
1291                  (event.GetDescription(), event.GetBroadcaster().GetName()))
1292
1293    test.fail("couldn't fetch an event before reaching the timeout.")
1294
1295
1296# ===================================
1297# Utility functions related to Frames
1298# ===================================
1299
1300
1301def get_parent_frame(frame):
1302    """
1303    Returns the parent frame of the input frame object; None if not available.
1304    """
1305    thread = frame.GetThread()
1306    parent_found = False
1307    for f in thread:
1308        if parent_found:
1309            return f
1310        if f.GetFrameID() == frame.GetFrameID():
1311            parent_found = True
1312
1313    # If we reach here, no parent has been found, return None.
1314    return None
1315
1316
1317def get_args_as_string(frame, showFuncName=True):
1318    """
1319    Returns the args of the input frame object as a string.
1320    """
1321    # arguments     => True
1322    # locals        => False
1323    # statics       => False
1324    # in_scope_only => True
1325    vars = frame.GetVariables(True, False, False, True)  # type of SBValueList
1326    args = []  # list of strings
1327    for var in vars:
1328        args.append("(%s)%s=%s" % (var.GetTypeName(),
1329                                   var.GetName(),
1330                                   var.GetValue()))
1331    if frame.GetFunction():
1332        name = frame.GetFunction().GetName()
1333    elif frame.GetSymbol():
1334        name = frame.GetSymbol().GetName()
1335    else:
1336        name = ""
1337    if showFuncName:
1338        return "%s(%s)" % (name, ", ".join(args))
1339    else:
1340        return "(%s)" % (", ".join(args))
1341
1342
1343def print_registers(frame, string_buffer=False):
1344    """Prints all the register sets of the frame."""
1345
1346    output = SixStringIO() if string_buffer else sys.stdout
1347
1348    print("Register sets for " + str(frame), file=output)
1349
1350    registerSet = frame.GetRegisters()  # Return type of SBValueList.
1351    print("Frame registers (size of register set = %d):" %
1352          registerSet.GetSize(), file=output)
1353    for value in registerSet:
1354        #print(value, file=output)
1355        print("%s (number of children = %d):" %
1356              (value.GetName(), value.GetNumChildren()), file=output)
1357        for child in value:
1358            print(
1359                "Name: %s, Value: %s" %
1360                (child.GetName(),
1361                 child.GetValue()),
1362                file=output)
1363
1364    if string_buffer:
1365        return output.getvalue()
1366
1367
1368def get_registers(frame, kind):
1369    """Returns the registers given the frame and the kind of registers desired.
1370
1371    Returns None if there's no such kind.
1372    """
1373    registerSet = frame.GetRegisters()  # Return type of SBValueList.
1374    for value in registerSet:
1375        if kind.lower() in value.GetName().lower():
1376            return value
1377
1378    return None
1379
1380
1381def get_GPRs(frame):
1382    """Returns the general purpose registers of the frame as an SBValue.
1383
1384    The returned SBValue object is iterable.  An example:
1385        ...
1386        from lldbutil import get_GPRs
1387        regs = get_GPRs(frame)
1388        for reg in regs:
1389            print("%s => %s" % (reg.GetName(), reg.GetValue()))
1390        ...
1391    """
1392    return get_registers(frame, "general purpose")
1393
1394
1395def get_FPRs(frame):
1396    """Returns the floating point registers of the frame as an SBValue.
1397
1398    The returned SBValue object is iterable.  An example:
1399        ...
1400        from lldbutil import get_FPRs
1401        regs = get_FPRs(frame)
1402        for reg in regs:
1403            print("%s => %s" % (reg.GetName(), reg.GetValue()))
1404        ...
1405    """
1406    return get_registers(frame, "floating point")
1407
1408
1409def get_ESRs(frame):
1410    """Returns the exception state registers of the frame as an SBValue.
1411
1412    The returned SBValue object is iterable.  An example:
1413        ...
1414        from lldbutil import get_ESRs
1415        regs = get_ESRs(frame)
1416        for reg in regs:
1417            print("%s => %s" % (reg.GetName(), reg.GetValue()))
1418        ...
1419    """
1420    return get_registers(frame, "exception state")
1421
1422# ======================================
1423# Utility classes/functions for SBValues
1424# ======================================
1425
1426
1427class BasicFormatter(object):
1428    """The basic formatter inspects the value object and prints the value."""
1429
1430    def format(self, value, buffer=None, indent=0):
1431        if not buffer:
1432            output = SixStringIO()
1433        else:
1434            output = buffer
1435        # If there is a summary, it suffices.
1436        val = value.GetSummary()
1437        # Otherwise, get the value.
1438        if val is None:
1439            val = value.GetValue()
1440        if val is None and value.GetNumChildren() > 0:
1441            val = "%s (location)" % value.GetLocation()
1442        print("{indentation}({type}) {name} = {value}".format(
1443            indentation=' ' * indent,
1444            type=value.GetTypeName(),
1445            name=value.GetName(),
1446            value=val), file=output)
1447        return output.getvalue()
1448
1449
1450class ChildVisitingFormatter(BasicFormatter):
1451    """The child visiting formatter prints the value and its immediate children.
1452
1453    The constructor takes a keyword arg: indent_child, which defaults to 2.
1454    """
1455
1456    def __init__(self, indent_child=2):
1457        """Default indentation of 2 SPC's for the children."""
1458        self.cindent = indent_child
1459
1460    def format(self, value, buffer=None):
1461        if not buffer:
1462            output = SixStringIO()
1463        else:
1464            output = buffer
1465
1466        BasicFormatter.format(self, value, buffer=output)
1467        for child in value:
1468            BasicFormatter.format(
1469                self, child, buffer=output, indent=self.cindent)
1470
1471        return output.getvalue()
1472
1473
1474class RecursiveDecentFormatter(BasicFormatter):
1475    """The recursive decent formatter prints the value and the decendents.
1476
1477    The constructor takes two keyword args: indent_level, which defaults to 0,
1478    and indent_child, which defaults to 2.  The current indentation level is
1479    determined by indent_level, while the immediate children has an additional
1480    indentation by inden_child.
1481    """
1482
1483    def __init__(self, indent_level=0, indent_child=2):
1484        self.lindent = indent_level
1485        self.cindent = indent_child
1486
1487    def format(self, value, buffer=None):
1488        if not buffer:
1489            output = SixStringIO()
1490        else:
1491            output = buffer
1492
1493        BasicFormatter.format(self, value, buffer=output, indent=self.lindent)
1494        new_indent = self.lindent + self.cindent
1495        for child in value:
1496            if child.GetSummary() is not None:
1497                BasicFormatter.format(
1498                    self, child, buffer=output, indent=new_indent)
1499            else:
1500                if child.GetNumChildren() > 0:
1501                    rdf = RecursiveDecentFormatter(indent_level=new_indent)
1502                    rdf.format(child, buffer=output)
1503                else:
1504                    BasicFormatter.format(
1505                        self, child, buffer=output, indent=new_indent)
1506
1507        return output.getvalue()
1508
1509# ===========================================================
1510# Utility functions for path manipulation on remote platforms
1511# ===========================================================
1512
1513
1514def join_remote_paths(*paths):
1515    # TODO: update with actual platform name for remote windows once it exists
1516    if lldb.remote_platform.GetName() == 'remote-windows':
1517        return os.path.join(*paths).replace(os.path.sep, '\\')
1518    return os.path.join(*paths).replace(os.path.sep, '/')
1519
1520
1521def append_to_process_working_directory(test, *paths):
1522    remote = lldb.remote_platform
1523    if remote:
1524        return join_remote_paths(remote.GetWorkingDirectory(), *paths)
1525    return os.path.join(test.getBuildDir(), *paths)
1526
1527# ==================================================
1528# Utility functions to get the correct signal number
1529# ==================================================
1530
1531import signal
1532
1533
1534def get_signal_number(signal_name):
1535    platform = lldb.remote_platform
1536    if platform and platform.IsValid():
1537        signals = platform.GetUnixSignals()
1538        if signals.IsValid():
1539            signal_number = signals.GetSignalNumberFromName(signal_name)
1540            if signal_number > 0:
1541                return signal_number
1542    # No remote platform; fall back to using local python signals.
1543    return getattr(signal, signal_name)
1544
1545def get_actions_for_signal(testcase, signal_name, from_target=False, expected_absent=False):
1546    """Returns a triple of (pass, stop, notify)"""
1547    return_obj = lldb.SBCommandReturnObject()
1548    command = "process handle {0}".format(signal_name)
1549    if from_target:
1550        command += " -t"
1551    testcase.dbg.GetCommandInterpreter().HandleCommand(
1552        command, return_obj)
1553    match = re.match(
1554        'NAME *PASS *STOP *NOTIFY.*(false|true|not set) *(false|true|not set) *(false|true|not set)',
1555        return_obj.GetOutput(),
1556        re.IGNORECASE | re.DOTALL)
1557    if match and expected_absent:
1558        testcase.fail('Signal "{0}" was supposed to be absent'.format(signal_name))
1559    if not match:
1560        if expected_absent:
1561            return (None, None, None)
1562        testcase.fail('Unable to retrieve default signal disposition.')
1563    return (match.group(1), match.group(2), match.group(3))
1564
1565
1566
1567def set_actions_for_signal(testcase, signal_name, pass_action, stop_action, notify_action, expect_success=True):
1568        return_obj = lldb.SBCommandReturnObject()
1569        command = "process handle {0}".format(signal_name)
1570        if pass_action != None:
1571            command += " -p {0}".format(pass_action)
1572        if stop_action != None:
1573            command += " -s {0}".format(stop_action)
1574        if notify_action != None:
1575            command +=" -n {0}".format(notify_action)
1576
1577        testcase.dbg.GetCommandInterpreter().HandleCommand(command, return_obj)
1578        testcase.assertEqual(expect_success,
1579            return_obj.Succeeded(),
1580            "Setting signal handling for {0} worked as expected".format(signal_name))
1581
1582class PrintableRegex(object):
1583
1584    def __init__(self, text):
1585        self.regex = re.compile(text)
1586        self.text = text
1587
1588    def match(self, str):
1589        return self.regex.match(str)
1590
1591    def __str__(self):
1592        return "%s" % (self.text)
1593
1594    def __repr__(self):
1595        return "re.compile(%s) -> %s" % (self.text, self.regex)
1596
1597
1598def skip_if_callable(test, mycallable, reason):
1599    if six.callable(mycallable):
1600        if mycallable(test):
1601            test.skipTest(reason)
1602            return True
1603    return False
1604
1605
1606def skip_if_library_missing(test, target, library):
1607    def find_library(target, library):
1608        for module in target.modules:
1609            filename = module.file.GetFilename()
1610            if isinstance(library, str):
1611                if library == filename:
1612                    return False
1613            elif hasattr(library, 'match'):
1614                if library.match(filename):
1615                    return False
1616        return True
1617
1618    def find_library_callable(test):
1619        return find_library(target, library)
1620    return skip_if_callable(
1621        test,
1622        find_library_callable,
1623        "could not find library matching '%s' in target %s" %
1624        (library,
1625         target))
1626
1627
1628def read_file_on_target(test, remote):
1629    if lldb.remote_platform:
1630        local = test.getBuildArtifact("file_from_target")
1631        error = lldb.remote_platform.Get(lldb.SBFileSpec(remote, False),
1632                    lldb.SBFileSpec(local, True))
1633        test.assertTrue(error.Success(), "Reading file {0} failed: {1}".format(remote, error))
1634    else:
1635        local = remote
1636    with open(local, 'r') as f:
1637        return f.read()
1638
1639def read_file_from_process_wd(test, name):
1640    path = append_to_process_working_directory(test, name)
1641    return read_file_on_target(test, path)
1642
1643def wait_for_file_on_target(testcase, file_path, max_attempts=6):
1644    for i in range(max_attempts):
1645        err, retcode, msg = testcase.run_platform_command("ls %s" % file_path)
1646        if err.Success() and retcode == 0:
1647            break
1648        if i < max_attempts:
1649            # Exponential backoff!
1650            import time
1651            time.sleep(pow(2, i) * 0.25)
1652    else:
1653        testcase.fail(
1654            "File %s not found even after %d attempts." %
1655            (file_path, max_attempts))
1656
1657    return read_file_on_target(testcase, file_path)
1658
1659def packetlog_get_process_info(log):
1660    """parse a gdb-remote packet log file and extract the response to qProcessInfo"""
1661    process_info = dict()
1662    with open(log, "r") as logfile:
1663        process_info_ostype = None
1664        expect_process_info_response = False
1665        for line in logfile:
1666            if expect_process_info_response:
1667                for pair in line.split(';'):
1668                    keyval = pair.split(':')
1669                    if len(keyval) == 2:
1670                        process_info[keyval[0]] = keyval[1]
1671                break
1672            if 'send packet: $qProcessInfo#' in line:
1673                expect_process_info_response = True
1674    return process_info
1675
1676def packetlog_get_dylib_info(log):
1677    """parse a gdb-remote packet log file and extract the *last* complete
1678    (=> fetch_all_solibs=true) response to jGetLoadedDynamicLibrariesInfos"""
1679    import json
1680    dylib_info = None
1681    with open(log, "r") as logfile:
1682        dylib_info = None
1683        expect_dylib_info_response = False
1684        for line in logfile:
1685            if expect_dylib_info_response:
1686                while line[0] != '$':
1687                    line = line[1:]
1688                line = line[1:]
1689                # Unescape '}'.
1690                dylib_info = json.loads(line.replace('}]','}')[:-4])
1691                expect_dylib_info_response = False
1692            if 'send packet: $jGetLoadedDynamicLibrariesInfos:{"fetch_all_solibs":true}' in line:
1693                expect_dylib_info_response = True
1694
1695    return dylib_info
1696