''' 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 -- []". There is a utility available in SWIFT_BINARY_DIR/bin/lldb-check-expect which automates this, e.g: ./bin/lldb-check-expect ... 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')