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