1# Copyright (C) 2019-2024 Free Software Foundation, Inc. 2# This program is free software; you can redistribute it and/or modify 3# it under the terms of the GNU General Public License as published by 4# the Free Software Foundation; either version 3 of the License, or 5# (at your option) any later version. 6# 7# This program is distributed in the hope that it will be useful, 8# but WITHOUT ANY WARRANTY; without even the implied warranty of 9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10# GNU General Public License for more details. 11# 12# You should have received a copy of the GNU General Public License 13# along with this program. If not, see <http://www.gnu.org/licenses/>. 14 15# Test custom MI commands implemented in Python. 16 17load_lib gdb-python.exp 18load_lib mi-support.exp 19set MIFLAGS "-i=mi" 20 21gdb_exit 22if {[mi_gdb_start]} { 23 return 24} 25 26if {[lsearch -exact [mi_get_features] python] < 0} { 27 unsupported "python support is disabled" 28 return -1 29} 30 31standard_testfile 32 33mi_gdb_test "set python print-stack full" \ 34 ".*\\^done" \ 35 "set python print-stack full" 36 37mi_gdb_test "source ${srcdir}/${subdir}/${testfile}.py" \ 38 ".*\\^done" \ 39 "load python file" 40 41mi_gdb_test "python pycmd1('-pycmd')" \ 42 ".*\\^done" \ 43 "define -pycmd MI command" 44 45mi_gdb_test "-pycmd int" \ 46 "\\^done,result=\"42\"" \ 47 "-pycmd int" 48 49mi_gdb_test "-pycmd str" \ 50 "\\^done,result=\"Hello world!\"" \ 51 "-pycmd str" 52 53mi_gdb_test "-pycmd ary" \ 54 "\\^done,result=\\\[\"Hello\",\"42\"\\\]" \ 55 "-pycmd ary" 56 57set re_order1 "\\^done,result={hello=\"world\",times=\"42\"}" 58set re_order2 "\\^done,result={times=\"42\",hello=\"world\"}" 59mi_gdb_test "-pycmd dct" \ 60 "($re_order1|$re_order2)" \ 61 "-pycmd dct" 62 63mi_gdb_test "-pycmd bk1" \ 64 "\\^error,msg=\"Error occurred in Python: non-string object used as key: Bad Key\"" \ 65 "-pycmd bk1" 66 67mi_gdb_test "-pycmd bk2" \ 68 "\\^error,msg=\"Error occurred in Python: non-string object used as key: 1\"" \ 69 "-pycmd bk2" 70 71mi_gdb_test "-pycmd bk3" \ 72 [multi_line \ 73 "&\"TypeError.*: __repr__ returned non-string \\(type BadKey\\)..\"" \ 74 "\\^error,msg=\"Error occurred in Python: __repr__ returned non-string \\(type BadKey\\)\""] \ 75 "-pycmd bk3" 76 77mi_gdb_test "-pycmd tpl" \ 78 "\\^done,result=\\\[\"42\",\"Hello\"\\\]" \ 79 "-pycmd tpl" 80 81mi_gdb_test "-pycmd itr" \ 82 "\\^done,result=\\\[\"1\",\"2\",\"3\"\\\]" \ 83 "-pycmd itr" 84 85mi_gdb_test "-pycmd nn1" \ 86 "\\^done" \ 87 "-pycmd nn1" 88 89mi_gdb_test "-pycmd nn2" \ 90 "\\^done,result=\\\[\"None\"\\\]" \ 91 "-pycmd nn2" 92 93mi_gdb_test "-pycmd bogus" \ 94 "\\^error,msg=\"Invalid parameter: bogus\"" \ 95 "-pycmd bogus" 96 97# Check that the top-level result from 'invoke' must be a dictionary. 98foreach test_name { nd1 nd2 nd3 } { 99 mi_gdb_test "-pycmd ${test_name}" \ 100 "\\^error,msg=\"Error occurred in Python: Result from invoke must be a dictionary\"" 101} 102 103# Check for invalid strings in the result. 104foreach test_desc { {ik1 "xxx yyy"} {ik2 "xxx yyy"} {ik3 "xxx\\+yyy"} \ 105 {ik4 "xxx\\.yyy"} {ik5 "123xxxyyy"} } { 106 lassign $test_desc name pattern 107 108 mi_gdb_test "-pycmd ${name}" \ 109 "\\^error,msg=\"Error occurred in Python: Invalid key in MI result: ${pattern}\"" 110} 111 112mi_gdb_test "-pycmd empty_key" \ 113 "\\^error,msg=\"Error occurred in Python: Invalid empty key in MI result\"" 114 115# Check that a dash ('-') can be used in a key name. 116mi_gdb_test "-pycmd dash-key" \ 117 "\\^done,the-key=\"123\"" 118 119# With this argument the command raises a gdb.GdbError with no message 120# string. GDB considers this a bug in the user program, so prints a 121# backtrace, and a generic error message. 122mi_gdb_test "-pycmd exp" \ 123 [multi_line ".*&\"Traceback \\(most recent call last\\):..\"" \ 124 "&\"\[^\r\n\]+${testfile}.py\[^\r\n\]+\"" \ 125 "&\"\[^\r\n\]+raise gdb.GdbError\\(\\)..\"" \ 126 "&\"gdb.GdbError..\"" \ 127 "\\^error,msg=\"Error occurred in Python\\.\""] \ 128 "-pycmd exp" 129 130mi_gdb_test "python pycmd2('-pycmd')" \ 131 ".*\\^done" \ 132 "redefine -pycmd MI command from CLI command" 133 134mi_gdb_test "-pycmd str" \ 135 "\\^done,result=\"Ciao!\"" \ 136 "-pycmd str - redefined from CLI" 137 138mi_gdb_test "-pycmd int" \ 139 "\\^error,msg=\"Invalid parameter: int\"" \ 140 "-pycmd int - redefined from CLI" 141 142mi_gdb_test "-pycmd new" \ 143 "\\^done" \ 144 "Define new command -pycmd-new MI command from Python MI command" 145 146mi_gdb_test "-pycmd red" \ 147 "\\^error,msg=\"Command redefined but we failing anyway\"" \ 148 "redefine -pycmd MI command from Python MI command" 149 150mi_gdb_test "-pycmd int" \ 151 "\\^done,result=\"42\"" \ 152 "-pycmd int - redefined from MI" 153 154mi_gdb_test "-pycmd-new int" \ 155 "\\^done,result=\"42\"" \ 156 "-pycmd-new int - defined from MI" 157 158mi_gdb_test "python pycmd1('')" \ 159 ".*&\"ValueError.*: MI command name is empty\\...\".*\\^error,msg=\"Error occurred in Python.*\"" \ 160 "empty MI command name" 161 162mi_gdb_test "python pycmd1('-')" \ 163 [multi_line \ 164 ".*" \ 165 "&\"ValueError.*: MI command name does not start with '-' followed by at least one letter or digit\\...\"" \ 166 "&\"Error occurred in Python.*..\"" \ 167 "\\^error,msg=\"Error occurred in Python.*\""] \ 168 "invalid MI command name" 169 170mi_gdb_test "python pycmd1('-bad-character-@')" \ 171 [multi_line \ 172 ".*" \ 173 "&\"ValueError.*: MI command name contains invalid character: @\\...\"" \ 174 "&\"Error occurred in Python.*..\"" \ 175 "\\^error,msg=\"Error occurred in Python.*\""] \ 176 "invalid character in MI command name" 177 178mi_gdb_test "python cmd=pycmd1('-abc')" \ 179 ".*\\^done" \ 180 "create command -abc, stored in a python variable" 181 182mi_gdb_test "python print(cmd.name)" \ 183 ".*\r\n~\"-abc\\\\n\"\r\n\\^done" \ 184 "print the name of the stored mi command" 185 186mi_gdb_test "python print(cmd.installed)" \ 187 ".*\r\n~\"True\\\\n\"\r\n\\^done" \ 188 "print the installed status of the stored mi command" 189 190mi_gdb_test "-abc str" \ 191 "\\^done,result=\"Hello world!\"" \ 192 "-abc str" 193 194mi_gdb_test "python cmd.installed = False" \ 195 ".*\\^done" \ 196 "uninstall the mi command" 197 198mi_gdb_test "-abc str" \ 199 "\\^error,msg=\"Undefined MI command: abc\",code=\"undefined-command\"" \ 200 "-abc str, but now the command is gone" 201 202mi_gdb_test "python cmd.installed = True" \ 203 ".*\\^done" \ 204 "re-install the mi command" 205 206mi_gdb_test "-abc str" \ 207 "\\^done,result=\"Hello world!\"" \ 208 "-abc str, the command is back again" 209 210mi_gdb_test "python other=pycmd2('-abc')" \ 211 ".*\\^done" \ 212 "create another command called -abc, stored in a separate python variable" 213 214mi_gdb_test "python print(other.installed)" \ 215 ".*\r\n~\"True\\\\n\"\r\n\\^done" \ 216 "print the installed status of the other stored mi command" 217 218mi_gdb_test "python print(cmd.installed)" \ 219 ".*\r\n~\"False\\\\n\"\r\n\\^done" \ 220 "print the installed status of the original stored mi command" 221 222mi_gdb_test "-abc str" \ 223 "\\^done,result=\"Ciao!\"" \ 224 "-abc str, when the other command is in place" 225 226mi_gdb_test "python cmd.installed = True" \ 227 ".*\\^done" \ 228 "re-install the original mi command" 229 230mi_gdb_test "-abc str" \ 231 "\\^done,result=\"Hello world!\"" \ 232 "-abc str, the original command is back again" 233 234mi_gdb_test "python print(other.installed)" \ 235 ".*\r\n~\"False\\\\n\"\r\n\\^done" \ 236 "the other command is now not installed" 237 238mi_gdb_test "python print(cmd.installed)" \ 239 ".*\r\n~\"True\\\\n\"\r\n\\^done" \ 240 "the original command is now installed" 241 242mi_gdb_test "python aa = pycmd3('-aa', 'message one', 'xxx')" \ 243 ".*\\^done" \ 244 "created a new -aa command" 245 246mi_gdb_test "-aa" \ 247 ".*\\^done,xxx={msg=\"message one\"}" \ 248 "call the -aa command" 249 250mi_gdb_test "python aa.__init__('-aa', 'message two', 'yyy')" \ 251 ".*\\^done" \ 252 "reinitialise -aa command with a new message" 253 254mi_gdb_test "-aa" \ 255 ".*\\^done,yyy={msg=\"message two\"}" \ 256 "call the -aa command, get the new message" 257 258mi_gdb_test "python aa.__init__('-bb', 'message three', 'zzz')" \ 259 [multi_line \ 260 ".*" \ 261 "&\"ValueError.*: can't reinitialize object with a different command name..\"" \ 262 "&\"Error occurred in Python.*..\"" \ 263 "\\^error,msg=\"Error occurred in Python.*\""] \ 264 "attempt to reinitialise aa variable to a new command name" 265 266mi_gdb_test "-aa" \ 267 ".*\\^done,yyy={msg=\"message two\"}" \ 268 "check the aa object has not changed after failed initialization" 269 270mi_gdb_test "python aa.installed = False" \ 271 ".*\\^done" \ 272 "uninstall the -aa command" 273 274mi_gdb_test "python aa.__init__('-bb', 'message three', 'zzz')" \ 275 [multi_line \ 276 ".*" \ 277 "&\"ValueError.*: can't reinitialize object with a different command name..\"" \ 278 "&\"Error occurred in Python.*..\"" \ 279 "\\^error,msg=\"Error occurred in Python.*\""] \ 280 "attempt to reinitialise aa variable to a new command name while uninstalled" 281 282mi_gdb_test "python aa.__init__('-aa', 'message three', 'zzz')" \ 283 ".*\\^done" \ 284 "reinitialise -aa command with a new message while uninstalled" 285 286mi_gdb_test "python aa.installed = True" \ 287 ".*\\^done" \ 288 "install the -aa command" 289 290mi_gdb_test "-aa" \ 291 ".*\\^done,zzz={msg=\"message three\"}" \ 292 "call the -aa command looking for message three" 293 294# Try to register a command object that is missing an invoke method. 295# This is accepted, but will give an error when the user tries to run 296# the command. 297mi_gdb_test "python no_invoke('-no-invoke')" ".*\\^done" \ 298 "attempt to register command with no invoke method" 299mi_gdb_test "-no-invoke" \ 300 [multi_line \ 301 ".*" \ 302 "&\"AttributeError.*: 'no_invoke' object has no attribute 'invoke'..\"" \ 303 "\\^error,msg=\"Error occurred in Python: 'no_invoke' object has no attribute 'invoke'\""] \ 304 "execute -no-invoke command, which is missing the invoke method" 305 306# Register a command, then delete its invoke method. What is the user thinking!! 307mi_gdb_test "python setattr(no_invoke, 'invoke', free_invoke)" ".*\\^done" 308mi_gdb_test "python cmd = no_invoke('-hello')" ".*\\^done" 309mi_gdb_test "-hello" ".*\\^done,result=\\\[\\\]" \ 310 "execute no_invoke command, while it still has an invoke attribute" 311mi_gdb_test "python delattr(no_invoke, 'invoke')" ".*\\^done" 312mi_gdb_test "-hello" \ 313 [multi_line \ 314 ".*" \ 315 "&\"AttributeError.*: 'no_invoke' object has no attribute 'invoke'..\"" \ 316 "\\^error,msg=\"Error occurred in Python: 'no_invoke' object has no attribute 'invoke'\""] \ 317 "execute -hello command, that had its invoke method removed" 318mi_gdb_test "python cmd.invoke = 'string'" ".*\\^done" 319mi_gdb_test "-hello" \ 320 [multi_line \ 321 ".*" \ 322 "&\"TypeError.*: 'str' object is not callable..\"" \ 323 "\\^error,msg=\"Error occurred in Python: 'str' object is not callable\""] \ 324 "execute command with invoke set to a string" 325 326# Try to create a new MI command that uses the name of a builtin MI command. 327mi_gdb_test "python cmd = pycmd2('-data-disassemble')" \ 328 [multi_line \ 329 ".*" \ 330 "&\"RuntimeError.*: unable to add command, name is already in use..\"" \ 331 "&\"Error occurred in Python.*..\"" \ 332 "\\^error,msg=\"Error occurred in Python.*\""] \ 333 "try to register a command that replaces -data-disassemble" 334 335 336 337mi_gdb_test "python run_exception_tests()" \ 338 [multi_line \ 339 ".*" \ 340 "~\"PASS..\"" \ 341 "\\^done"] 342