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.
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.
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/>.
15 # Test custom MI commands implemented in Python.
17 load_lib gdb-python.exp
18 load_lib mi-support.exp
26 if {[lsearch -exact [mi_get_features] python] < 0} {
27 unsupported "python support is disabled"
33 mi_gdb_test "set python print-stack full" \
35 "set python print-stack full"
37 mi_gdb_test "source ${srcdir}/${subdir}/${testfile}.py" \
41 mi_gdb_test "python pycmd1('-pycmd')" \
43 "define -pycmd MI command"
45 mi_gdb_test "-pycmd int" \
46 "\\^done,result=\"42\"" \
49 mi_gdb_test "-pycmd str" \
50 "\\^done,result=\"Hello world!\"" \
53 mi_gdb_test "-pycmd ary" \
54 "\\^done,result=\\\[\"Hello\",\"42\"\\\]" \
57 set re_order1 "\\^done,result={hello=\"world\",times=\"42\"}"
58 set re_order2 "\\^done,result={times=\"42\",hello=\"world\"}"
59 mi_gdb_test "-pycmd dct" \
60 "($re_order1|$re_order2)" \
63 mi_gdb_test "-pycmd bk1" \
64 "\\^error,msg=\"Error occurred in Python: non-string object used as key: Bad Key\"" \
67 mi_gdb_test "-pycmd bk2" \
68 "\\^error,msg=\"Error occurred in Python: non-string object used as key: 1\"" \
71 mi_gdb_test "-pycmd bk3" \
73 "&\"TypeError.*: __repr__ returned non-string \\(type BadKey\\)..\"" \
74 "\\^error,msg=\"Error occurred in Python: __repr__ returned non-string \\(type BadKey\\)\""] \
77 mi_gdb_test "-pycmd tpl" \
78 "\\^done,result=\\\[\"42\",\"Hello\"\\\]" \
81 mi_gdb_test "-pycmd itr" \
82 "\\^done,result=\\\[\"1\",\"2\",\"3\"\\\]" \
85 mi_gdb_test "-pycmd nn1" \
89 mi_gdb_test "-pycmd nn2" \
90 "\\^done,result=\\\[\"None\"\\\]" \
93 mi_gdb_test "-pycmd bogus" \
94 "\\^error,msg=\"Invalid parameter: bogus\"" \
97 # Check that the top-level result from 'invoke' must be a dictionary.
98 foreach 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\""
103 # Check for invalid strings in the result.
104 foreach test_desc { {ik1 "xxx yyy"} {ik2 "xxx yyy"} {ik3 "xxx\\+yyy"} \
105 {ik4 "xxx\\.yyy"} {ik5 "123xxxyyy"} } {
106 lassign $test_desc name pattern
108 mi_gdb_test "-pycmd ${name}" \
109 "\\^error,msg=\"Error occurred in Python: Invalid key in MI result: ${pattern}\""
112 mi_gdb_test "-pycmd empty_key" \
113 "\\^error,msg=\"Error occurred in Python: Invalid empty key in MI result\""
115 # Check that a dash ('-') can be used in a key name.
116 mi_gdb_test "-pycmd dash-key" \
117 "\\^done,the-key=\"123\""
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.
122 mi_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\\.\""] \
130 mi_gdb_test "python pycmd2('-pycmd')" \
132 "redefine -pycmd MI command from CLI command"
134 mi_gdb_test "-pycmd str" \
135 "\\^done,result=\"Ciao!\"" \
136 "-pycmd str - redefined from CLI"
138 mi_gdb_test "-pycmd int" \
139 "\\^error,msg=\"Invalid parameter: int\"" \
140 "-pycmd int - redefined from CLI"
142 mi_gdb_test "-pycmd new" \
144 "Define new command -pycmd-new MI command from Python MI command"
146 mi_gdb_test "-pycmd red" \
147 "\\^error,msg=\"Command redefined but we failing anyway\"" \
148 "redefine -pycmd MI command from Python MI command"
150 mi_gdb_test "-pycmd int" \
151 "\\^done,result=\"42\"" \
152 "-pycmd int - redefined from MI"
154 mi_gdb_test "-pycmd-new int" \
155 "\\^done,result=\"42\"" \
156 "-pycmd-new int - defined from MI"
158 mi_gdb_test "python pycmd1('')" \
159 ".*&\"ValueError.*: MI command name is empty\\...\".*\\^error,msg=\"Error occurred in Python.*\"" \
160 "empty MI command name"
162 mi_gdb_test "python pycmd1('-')" \
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"
170 mi_gdb_test "python pycmd1('-bad-character-@')" \
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"
178 mi_gdb_test "python cmd=pycmd1('-abc')" \
180 "create command -abc, stored in a python variable"
182 mi_gdb_test "python print(cmd.name)" \
183 ".*\r\n~\"-abc\\\\n\"\r\n\\^done" \
184 "print the name of the stored mi command"
186 mi_gdb_test "python print(cmd.installed)" \
187 ".*\r\n~\"True\\\\n\"\r\n\\^done" \
188 "print the installed status of the stored mi command"
190 mi_gdb_test "-abc str" \
191 "\\^done,result=\"Hello world!\"" \
194 mi_gdb_test "python cmd.installed = False" \
196 "uninstall the mi command"
198 mi_gdb_test "-abc str" \
199 "\\^error,msg=\"Undefined MI command: abc\",code=\"undefined-command\"" \
200 "-abc str, but now the command is gone"
202 mi_gdb_test "python cmd.installed = True" \
204 "re-install the mi command"
206 mi_gdb_test "-abc str" \
207 "\\^done,result=\"Hello world!\"" \
208 "-abc str, the command is back again"
210 mi_gdb_test "python other=pycmd2('-abc')" \
212 "create another command called -abc, stored in a separate python variable"
214 mi_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"
218 mi_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"
222 mi_gdb_test "-abc str" \
223 "\\^done,result=\"Ciao!\"" \
224 "-abc str, when the other command is in place"
226 mi_gdb_test "python cmd.installed = True" \
228 "re-install the original mi command"
230 mi_gdb_test "-abc str" \
231 "\\^done,result=\"Hello world!\"" \
232 "-abc str, the original command is back again"
234 mi_gdb_test "python print(other.installed)" \
235 ".*\r\n~\"False\\\\n\"\r\n\\^done" \
236 "the other command is now not installed"
238 mi_gdb_test "python print(cmd.installed)" \
239 ".*\r\n~\"True\\\\n\"\r\n\\^done" \
240 "the original command is now installed"
242 mi_gdb_test "python aa = pycmd3('-aa', 'message one', 'xxx')" \
244 "created a new -aa command"
247 ".*\\^done,xxx={msg=\"message one\"}" \
248 "call the -aa command"
250 mi_gdb_test "python aa.__init__('-aa', 'message two', 'yyy')" \
252 "reinitialise -aa command with a new message"
255 ".*\\^done,yyy={msg=\"message two\"}" \
256 "call the -aa command, get the new message"
258 mi_gdb_test "python aa.__init__('-bb', 'message three', 'zzz')" \
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"
267 ".*\\^done,yyy={msg=\"message two\"}" \
268 "check the aa object has not changed after failed initialization"
270 mi_gdb_test "python aa.installed = False" \
272 "uninstall the -aa command"
274 mi_gdb_test "python aa.__init__('-bb', 'message three', 'zzz')" \
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"
282 mi_gdb_test "python aa.__init__('-aa', 'message three', 'zzz')" \
284 "reinitialise -aa command with a new message while uninstalled"
286 mi_gdb_test "python aa.installed = True" \
288 "install the -aa command"
291 ".*\\^done,zzz={msg=\"message three\"}" \
292 "call the -aa command looking for message three"
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
297 mi_gdb_test "python no_invoke('-no-invoke')" ".*\\^done" \
298 "attempt to register command with no invoke method"
299 mi_gdb_test "-no-invoke" \
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"
306 # Register a command, then delete its invoke method. What is the user thinking!!
307 mi_gdb_test "python setattr(no_invoke, 'invoke', free_invoke)" ".*\\^done"
308 mi_gdb_test "python cmd = no_invoke('-hello')" ".*\\^done"
309 mi_gdb_test "-hello" ".*\\^done,result=\\\[\\\]" \
310 "execute no_invoke command, while it still has an invoke attribute"
311 mi_gdb_test "python delattr(no_invoke, 'invoke')" ".*\\^done"
312 mi_gdb_test "-hello" \
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"
318 mi_gdb_test "python cmd.invoke = 'string'" ".*\\^done"
319 mi_gdb_test "-hello" \
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"
326 # Try to create a new MI command that uses the name of a builtin MI command.
327 mi_gdb_test "python cmd = pycmd2('-data-disassemble')" \
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"
337 mi_gdb_test "python run_exception_tests()" \