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 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
|
"""
Test lldb Python commands.
"""
import sys
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
class CmdPythonTestCase(TestBase):
NO_DEBUG_INFO_TESTCASE = True
def test(self):
self.build()
self.pycmd_tests()
def pycmd_tests(self):
self.runCmd("command source py_import")
# Test that we did indeed add these commands as user commands:
interp = self.dbg.GetCommandInterpreter()
self.assertTrue(interp.UserCommandExists("foobar"), "foobar exists")
self.assertFalse(interp.CommandExists("foobar"), "It is not a builtin.")
# Test a bunch of different kinds of python callables with
# both 4 and 5 positional arguments.
self.expect("foobar", substrs=["All good"])
self.expect("foobar4", substrs=["All good"])
self.expect("vfoobar", substrs=["All good"])
self.expect("v5foobar", substrs=["All good"])
self.expect("sfoobar", substrs=["All good"])
self.expect("cfoobar", substrs=["All good"])
self.expect("ifoobar", substrs=["All good"])
self.expect("sfoobar4", substrs=["All good"])
self.expect("cfoobar4", substrs=["All good"])
self.expect("ifoobar4", substrs=["All good"])
self.expect("ofoobar", substrs=["All good"])
self.expect("ofoobar4", substrs=["All good"])
# Verify command that specifies eCommandRequiresTarget returns failure
# without a target.
self.expect("targetname", substrs=["a.out"], matching=False, error=True)
exe = self.getBuildArtifact("a.out")
self.expect("file " + exe, patterns=["Current executable set to .*a.out"])
self.expect("targetname", substrs=["a.out"], matching=True, error=False)
# This is the function to remove the custom commands in order to have a
# clean slate for the next test case.
def cleanup():
self.runCmd("command script delete welcome", check=False)
self.runCmd("command script delete targetname", check=False)
self.runCmd("command script delete longwait", check=False)
self.runCmd("command script delete mysto", check=False)
self.runCmd("command script delete tell_sync", check=False)
self.runCmd("command script delete tell_async", check=False)
self.runCmd("command script delete tell_curr", check=False)
self.runCmd("command script delete bug11569", check=False)
self.runCmd("command script delete takes_exe_ctx", check=False)
self.runCmd("command script delete decorated", check=False)
# Execute the cleanup function during test case tear down.
self.addTearDownHook(cleanup)
# Interact with debugger in synchronous mode
self.setAsync(False)
# We don't want to display the stdout if not in TraceOn() mode.
if not self.TraceOn():
self.HideStdout()
self.expect("welcome Enrico", substrs=["Hello Enrico, welcome to LLDB"])
self.expect(
"help welcome",
substrs=[
"Just a docstring for welcome_impl",
"A command that says hello to LLDB users",
],
)
decorated_commands = ["decorated" + str(n) for n in range(1, 5)]
for name in decorated_commands:
self.expect(name, substrs=["hello from " + name])
self.expect(
"help " + name, substrs=["Python command defined by @lldb.command"]
)
self.expect(
"help",
substrs=["For more information run"] + decorated_commands + ["welcome"],
)
self.expect(
"help -a",
substrs=["For more information run"] + decorated_commands + ["welcome"],
)
self.expect("help -u", matching=False, substrs=["For more information run"])
self.runCmd("command script delete welcome")
self.expect(
"welcome Enrico",
matching=False,
error=True,
substrs=["Hello Enrico, welcome to LLDB"],
)
self.expect(
"targetname fail", error=True, substrs=["a test for error in command"]
)
self.expect(
"command script list", substrs=["targetname", "For more information run"]
)
self.expect(
"help targetname",
substrs=["Expects", "'raw'", "input", "help", "raw-input"],
)
self.expect("longwait", substrs=["Done; if you saw the delays I am doing OK"])
self.runCmd("break set -f main.cpp -l 48")
self.runCmd("run")
self.runCmd("mysto 3")
self.expect(
"frame variable array",
substrs=["[0] = 79630", "[1] = 388785018", "[2] = 0"],
)
self.runCmd("mysto 3")
self.expect(
"frame variable array",
substrs=["[0] = 79630", "[4] = 388785018", "[5] = 0"],
)
# we cannot use the stepover command to check for async execution mode since LLDB
# seems to get confused when events start to queue up
self.expect("tell_sync", substrs=["running sync"])
self.expect("tell_async", substrs=["running async"])
self.expect("tell_curr", substrs=["I am running sync"])
# check that the execution context is passed in to commands that ask for it
self.expect("takes_exe_ctx", substrs=["a.out"])
# Test that a python command can redefine itself
self.expect('command script add -f foobar welcome -h "just some help"')
self.runCmd("command script clear")
# Test that re-defining an existing command works
self.runCmd("command script add my_command --class welcome.WelcomeCommand")
self.expect("my_command Blah", substrs=["Hello Blah, welcome to LLDB"])
self.runCmd(
"command script add my_command -o --class welcome.TargetnameCommand"
)
self.expect("my_command", substrs=["a.out"])
# Test that without --overwrite we are not allowed to redefine the command.
self.expect(
"command script add my_command --class welcome.TargetnameCommand",
substrs=[
(
'user command "my_command" already exists and force replace was'
" not set by --overwrite or 'settings set"
" interpreter.require-overwrite false'"
),
],
error=True,
)
self.runCmd("command script clear")
self.expect(
"command script list", matching=False, substrs=["targetname", "longwait"]
)
self.expect(
"command script add -f foobar frame",
error=True,
substrs=["cannot add command"],
)
# http://llvm.org/bugs/show_bug.cgi?id=11569
# LLDBSwigPythonCallCommand crashes when a command script returns an
# object
self.runCmd("command script add -f bug11569 bug11569")
# This should not crash.
self.runCmd("bug11569", check=False)
# Make sure that a reference to a non-existent class raises an error:
bad_class_name = "LLDBNoSuchModule.LLDBNoSuchClass"
self.expect(
"command script add wont-work --class {0}".format(bad_class_name),
error=True,
substrs=[bad_class_name],
)
def test_persistence(self):
"""
Ensure that function arguments meaningfully persist (and do not crash!)
even after the function terminates.
"""
self.runCmd("command script import persistence.py")
self.runCmd("command script add -f persistence.save_debugger save_debugger")
self.expect("save_debugger", substrs=[str(self.dbg)])
# After the command completes, the debugger object should still be
# valid.
self.expect("script str(persistence.debugger_copy)", substrs=[str(self.dbg)])
# The result object will be replaced by an empty result object (in the
# "Started" state).
self.expect("script str(persistence.result_copy)", substrs=["Started"])
def test_interactive(self):
"""
Test that we can add multiple lines interactively.
"""
interp = self.dbg.GetCommandInterpreter()
cmd_file = self.getSourcePath("cmd_file.lldb")
result = lldb.SBCommandReturnObject()
interp.HandleCommand(f"command source {cmd_file}", result)
self.assertCommandReturn(result, "Sourcing the command should cause no errors.")
self.assertTrue(interp.UserCommandExists("my_cmd"), "Command defined.")
interp.HandleCommand("my_cmd", result)
self.assertCommandReturn(result, "Running the command succeeds")
self.assertIn("My Command Result", result.GetOutput(), "Command was correct")
|