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