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