File: lldbCheckExpect.py

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (100 lines) | stat: -rw-r--r-- 3,182 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
'''
lldbCheckExpect.py

This is a driver script for testing lldb expression evaluation. It installs a
breakpoint command which executes tests inserted by the instrumentation pass,
and launches a target.

To use it, compile a target program with these flags:

    -g -Xfrontend -debugger-testing-transform

Make sure the swift standard library is built with debug info. Then, launch
swift-lldb with "-o path/to/this/script -- <program> [<args>]". There is a
utility available in SWIFT_BINARY_DIR/bin/lldb-check-expect which automates
this, e.g:

    ./bin/lldb-check-expect <program>
    ...
    Evaluating check-expect in closure #2 () -> () in CAPITest.swapTwoValues
      Checked variable: a
      Expected value  : 98
      Actual value    : ...
'''


def unwrap(s):
    '''
    Strip non-essential character sequences from a string.

    >>> unwrap('(String) value = "42\\\\n"')
    '42'
    >>> unwrap('(Int) $R0 = 42')
    '42'
    >>> unwrap('\\\\"foo\\"')
    'foo'
    >>> unwrap('foo\\nbar')
    'foo\\nbar'
    >>> unwrap(' foo ')
    'foo'
    '''
    s = s[s.find('=') + 1:]
    s = s.lstrip(' "')
    s = s.rstrip('"')
    if s.endswith('\\n'):
        s = s[:-2]
    if s.endswith('\\"'):
        s = s[:-2]
    if s.startswith('\\"'):
        s = s[2:]
    s = s.replace('\\n', '\n')
    s = s.strip()
    return s


def on_check_expect(frame, bp_loc, session):
    parent_frame = frame.get_parent_frame()
    parent_name = parent_frame.GetFunctionName()
    print("Evaluating check-expect in", parent_name)

    # Note: If we fail to stringify the arguments in the check-expect frame,
    # the standard library has probably not been compiled with debug info.
    wrapped_var_name, wrapped_expected_value = map(str, frame.arguments)

    var_name = unwrap(wrapped_var_name)
    expected_value = unwrap(wrapped_expected_value)

    # Evaluate the variable in the parent frame of the check-expect.
    frame.thread.SetSelectedFrame(1)
    expr_result = parent_frame.FindVariable(var_name).GetObjectDescription()
    eval_result = unwrap(str(expr_result))

    print("  Checked variable:", var_name)
    print("  Expected value  :", expected_value)
    print("  Actual value    :", eval_result)

    if eval_result == expected_value:
        # Do not stop execution.
        return False

    print("Found a possible expression evaluation failure.")

    for i, (c1, c2) in enumerate(zip(expected_value, eval_result)):
        if c1 == c2:
            continue
        print(" -> Character difference at index", i)
        print(" -> Expected", c1, "but found", c2)
        break
    else:
        print(" -> Expected string has length", len(expected_value))
        print(" -> Actual string has length", len(eval_result))
    return True


def __lldb_init_module(debugger, internal_dict):
    debugger.HandleCommand('breakpoint set -n _debuggerTestingCheckExpect '
                           '--breakpoint-name check_expect_bkpt')
    debugger.HandleCommand('breakpoint command add --python-function '
                           'lldbCheckExpect.on_check_expect '
                           '--stop-on-error true check_expect_bkpt')
    debugger.HandleCommand('run')