Home | History | Annotate | Line # | Download | only in gdb.python
      1 # Copyright (C) 2009-2025 Free Software Foundation, Inc.
      2 
      3 # This program is free software; you can redistribute it and/or modify
      4 # it under the terms of the GNU General Public License as published by
      5 # the Free Software Foundation; either version 3 of the License, or
      6 # (at your option) any later version.
      7 #
      8 # This program is distributed in the hope that it will be useful,
      9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11 # GNU General Public License for more details.
     12 #
     13 # You should have received a copy of the GNU General Public License
     14 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
     15 
     16 # This file is part of the GDB testsuite.  It tests the mechanism
     17 # for defining new GDB commands in Python.
     18 
     19 load_lib gdb-python.exp
     20 
     21 require allow_python_tests
     22 
     23 standard_testfile
     24 
     25 if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
     26     return -1
     27 }
     28 
     29 if {![runto_main]} {
     30     return 0
     31 }
     32 
     33 # Test a simple command.
     34 
     35 gdb_test_multiline "input simple command" \
     36   "python" "" \
     37   "class test_cmd (gdb.Command):" "" \
     38   "  def __init__ (self):" "" \
     39   "    super (test_cmd, self).__init__ (\"test_cmd\", gdb.COMMAND_OBSCURE)" "" \
     40   "  def invoke (self, arg, from_tty):" "" \
     41   "    print (\"test_cmd output, arg = %s\" % arg)" "" \
     42   "test_cmd ()" "" \
     43   "end" ""
     44 
     45 gdb_test "test_cmd ugh" "test_cmd output, arg = ugh" "call simple command"
     46 
     47 # Test a prefix command, and a subcommand within it.
     48 
     49 gdb_test_multiline "input prefix command" \
     50   "python" "" \
     51   "class prefix_cmd (gdb.Command):" "" \
     52   "  def __init__ (self):" "" \
     53   "    super (prefix_cmd, self).__init__ (\"prefix_cmd\", gdb.COMMAND_OBSCURE, gdb.COMPLETE_NONE, True)" "" \
     54   "  def invoke (self, arg, from_tty):" "" \
     55   "    print (\"prefix_cmd output, arg = %s\" % arg)" "" \
     56   "prefix_cmd ()" "" \
     57   "end" ""
     58 
     59 gdb_test "prefix_cmd ugh" "prefix_cmd output, arg = ugh" "call prefix command"
     60 
     61 gdb_test_multiline "input subcommand" \
     62   "python" "" \
     63   "class subcmd (gdb.Command):" "" \
     64   "  def __init__ (self):" "" \
     65   "    super (subcmd, self).__init__ (\"prefix_cmd subcmd\", gdb.COMMAND_OBSCURE)" "" \
     66   "  def invoke (self, arg, from_tty):" "" \
     67   "    print (\"subcmd output, arg = %s\" % arg)" "" \
     68   "subcmd ()" "" \
     69   "end" ""
     70 
     71 gdb_test "prefix_cmd subcmd ugh" "subcmd output, arg = ugh" "call subcmd"
     72 
     73 # Test prefix command using keyword arguments.
     74 
     75 gdb_test_multiline "input prefix command, keyword arguments" \
     76   "python" "" \
     77   "class prefix_cmd2 (gdb.Command):" "" \
     78   "  def __init__ (self):" "" \
     79   "    super (prefix_cmd2, self).__init__ (\"prefix_cmd2\", gdb.COMMAND_OBSCURE, prefix = True, completer_class = gdb.COMPLETE_FILENAME)" "" \
     80   "  def invoke (self, arg, from_tty):" "" \
     81   "    print (\"prefix_cmd2 output, arg = %s\" % arg)" "" \
     82   "prefix_cmd2 ()" "" \
     83   "end" ""
     84 
     85 gdb_test "prefix_cmd2 argh" "prefix_cmd2 output, arg = argh" "call prefix command, keyword arguments"
     86 
     87 gdb_test_multiline "input subcommand under prefix_cmd2" \
     88   "python" "" \
     89   "class subcmd (gdb.Command):" "" \
     90   "  def __init__ (self):" "" \
     91   "    super (subcmd, self).__init__ (\"prefix_cmd2 subcmd\", gdb.COMMAND_OBSCURE)" "" \
     92   "  def invoke (self, arg, from_tty):" "" \
     93   "    print (\"subcmd output, arg = %s\" % arg)" "" \
     94   "subcmd ()" "" \
     95   "end" ""
     96 
     97 gdb_test "prefix_cmd2 subcmd ugh" "subcmd output, arg = ugh" "call subcmd under prefix_cmd2"
     98 
     99 # Test a subcommand in an existing GDB prefix.
    100 
    101 gdb_test_multiline "input new subcommand" \
    102   "python" "" \
    103   "class newsubcmd (gdb.Command):" "" \
    104   "  def __init__ (self):" "" \
    105   "    super (newsubcmd, self).__init__ (\"info newsubcmd\", gdb.COMMAND_OBSCURE)" "" \
    106   "  def invoke (self, arg, from_tty):" "" \
    107   "    print (\"newsubcmd output, arg = %s\" % arg)" "" \
    108   "newsubcmd ()" "" \
    109   "end" ""
    110 
    111 gdb_test "info newsubcmd ugh" "newsubcmd output, arg = ugh" "call newsubcmd"
    112 
    113 # Test a command that throws gdb.GdbError.
    114 
    115 gdb_test_multiline "input command to throw error" \
    116   "python" "" \
    117   "class test_error_cmd (gdb.Command):" "" \
    118   "  def __init__ (self):" "" \
    119   "    super (test_error_cmd, self).__init__ (\"test_error_cmd\", gdb.COMMAND_OBSCURE)" "" \
    120   "  def invoke (self, arg, from_tty):" "" \
    121   "    raise gdb.GdbError ('you lose!')" "" \
    122   "test_error_cmd ()" "" \
    123   "end" ""
    124 
    125 gdb_test "test_error_cmd ugh" "you lose!" "call error command"
    126 
    127 # Test gdb.string_to_argv.
    128 
    129 gdb_test "python print (gdb.string_to_argv (\"1 2 3\"))" \
    130   {\['1', '2', '3'\]} \
    131   "string_to_argv (\"1 2 3\"), case 1"
    132 
    133 gdb_test "python print (gdb.string_to_argv (\"'1 2' 3\"))" \
    134   {\['1 2', '3'\]} \
    135   "string_to_argv (\"'1 2' 3\"), case 2"
    136 
    137 gdb_test "python print (gdb.string_to_argv ('\"1 2\" 3'))" \
    138   {\['1 2', '3'\]} \
    139   "string_to_argv ('\"1 2\" 3'), case 3"
    140 
    141 gdb_test "python print (gdb.string_to_argv ('1\\ 2 3'))" \
    142   {\['1 2', '3'\]} \
    143     "string_to_argv ('1\\ 2 3'), case 4"
    144 
    145 # Test user-defined python commands.
    146 gdb_test_multiline "input simple user-defined command" \
    147   "python" "" \
    148   "class test_help (gdb.Command):" "" \
    149   "  \"\"\"Docstring\"\"\"" "" \
    150   "  def __init__ (self):" "" \
    151   "    super (test_help, self).__init__ (\"test_help\", gdb.COMMAND_USER)" "" \
    152   "  def invoke (self, arg, from_tty):" "" \
    153   "    print (\"test_cmd output, arg = %s\" % arg)" "" \
    154   "test_help ()" "" \
    155   "end" ""
    156 
    157 gdb_test "test_help ugh" "test_cmd output, arg = ugh" "call simple user-defined command"
    158 
    159 # Make sure the command shows up in `help user-defined`.
    160 test_user_defined_class_help {"test_help -- Docstring[\r\n]"}
    161 
    162 # Make sure the command does not show up in `show user`.
    163 gdb_test "show user test_help" "Not a user command\." \
    164     "don't show user-defined python command in `show user command`"
    165 
    166 # Test expression completion on fields
    167 gdb_test_multiline "expression completion command" \
    168   "python" "" \
    169   "class expr_test (gdb.Command):" "" \
    170   "  def __init__ (self):" "" \
    171   "    super (expr_test, self).__init__ (\"expr_test\", gdb.COMMAND_USER, gdb.COMPLETE_EXPRESSION)" "" \
    172   "  def invoke (self, arg, from_tty):" "" \
    173   "    print (\"invoked on = %s\" % arg)" "" \
    174   "expr_test ()" "" \
    175   "end" ""
    176 
    177 
    178 gdb_test "complete expr_test bar\." \
    179     "expr_test bar\.bc.*expr_test bar\.ij.*" \
    180     "test completion through complete command"
    181 
    182 # Test that the "python" command is correctly recognized as
    183 # inline/multi-line when entering a sequence of commands.
    184 #
    185 # This proc tests PR cli/21688.  The PR is not language-specific, but
    186 # the easiest way is just to test with Python.
    187 proc test_python_inline_or_multiline { } {
    188     global gdb_prompt
    189     set end "\r\n$gdb_prompt $"
    190 
    191     set define_cmd_not_inline [ list \
    192 	[ list "if 1"                 " >$"            "multi-line if 1" ] \
    193 	[ list "python"               " >$"            "multi-line python command" ] \
    194 	[ list "print ('hello')"      "  >$"           "multi-line print" ] \
    195 	[ list "end"                  " >$"            "multi-line first end" ] \
    196 	[ list "end"                  "hello$end"      "multi-line last end" ] ]
    197 
    198     # This also tests trailing whitespace on the command.
    199     set define_cmd_alias_not_inline [ list \
    200 	[ list "if 1"                 " >$"            "multi-line if 1 alias" ] \
    201 	[ list "py    "               " >$"            "multi-line python command alias" ] \
    202 	[ list "print ('hello')"      "  >$"           "multi-line print alias" ] \
    203 	[ list "end"                  " >$"            "multi-line first end alias" ] \
    204 	[ list "end"                  "hello$end"      "multi-line last end alias" ] ]
    205 
    206     set define_cmd_alias_foo_not_inline [ list \
    207 	[ list "alias foo=python"     "$end"           "multi-line alias foo" ] \
    208 	[ list "if 1"                 " >$"            "multi-line if 1 alias foo" ] \
    209 	[ list "foo    "              " >$"            "multi-line python command alias foo" ] \
    210 	[ list "print ('hello')"      "  >$"           "multi-line print alias foo" ] \
    211 	[ list "end"                  " >$"            "multi-line first end alias foo" ] \
    212 	[ list "end"                  "hello$end"      "multi-line last end alias foo" ] ]
    213 
    214     set define_cmd_inline [ list \
    215 	[ list "if 1"                      " >$"          "inline if 1" ] \
    216 	[ list "python print ('hello')"    " >$"          "inline python command" ] \
    217 	[ list "end"                       "hello$end"    "inline end" ] ]
    218 
    219     set define_cmd_alias_inline [ list \
    220 	[ list "if 1"                      " >$"          "inline if 1 alias" ] \
    221 	[ list "py print ('hello')"        " >$"          "inline python command alias" ] \
    222 	[ list "end"                       "hello$end"    "inline end alias" ] ]
    223 
    224     set define_cmd_alias_foo_inline [ list \
    225 	[ list "if 1"                      " >$"          "inline if 1 alias foo" ] \
    226 	[ list "foo print ('hello')"       " >$"          "inline python command alias foo" ] \
    227 	[ list "end"                       "hello$end"    "inline end alias foo" ] ]
    228 
    229     foreach t [list $define_cmd_not_inline \
    230 	       $define_cmd_alias_not_inline \
    231 	       $define_cmd_alias_foo_not_inline \
    232 	       $define_cmd_inline \
    233 	       $define_cmd_alias_inline \
    234 	       $define_cmd_alias_foo_inline] {
    235 	foreach l $t {
    236 	    lassign $l command regex testmsg
    237 	    gdb_test_multiple "$command" "$testmsg" {
    238 		-re "$regex" {
    239 		    pass "$testmsg"
    240 		}
    241 	    }
    242 	}
    243     }
    244 }
    245 
    246 test_python_inline_or_multiline
    247 
    248 if { [readline_is_used] } {
    249     set test "complete 'expr_test bar.i'"
    250     send_gdb "expr_test bar\.i\t\t"
    251     gdb_test_multiple "" "$test" {
    252 	-re "expr_test bar\.ij \\\x07$" {
    253 	    send_gdb "\n"
    254 	    gdb_test_multiple "" $test {
    255 		-re "invoked on = bar.ij.*$gdb_prompt $" {
    256 		    pass "$test"
    257 		}
    258 	    }
    259 	}
    260     }
    261 }
    262 
    263 
    264 # Test that interrupting pagination throws a gdb quit.
    265 gdb_test_no_output "set height 10"
    266 
    267 gdb_test_multiline "input multi-line-output command" \
    268   "python" "" \
    269   "class test_mline (gdb.Command):" "" \
    270   "  \"\"\"Docstring\"\"\"" "" \
    271   "  def __init__ (self):" "" \
    272   "    super (test_mline, self).__init__ (\"test_multiline\", gdb.COMMAND_USER)" "" \
    273   "  def invoke (self, arg, from_tty):" "" \
    274   "    for f in range(20):" "" \
    275   "      print (\"test_multiline output\")" "" \
    276   "test_mline ()" "" \
    277   "end" ""
    278 
    279 set test "verify pagination from test_multiline"
    280 gdb_test_multiple "test_multiline" $test {
    281     -re "$pagination_prompt$" {
    282 	pass $test
    283     }
    284 }
    285 
    286 send_gdb "q\n"
    287 set test "verify pagination from test_multiline: q"
    288 gdb_test_multiple "" $test {
    289     -re "Error occurred in Python" {
    290 	fail $test
    291     }
    292     -re "Quit" {
    293 	pass $test
    294     }
    295 }
    296 
    297 # Test command redefining itself
    298 
    299 proc_with_prefix test_command_redefining_itself {} {
    300     # Start with a fresh gdb
    301     clean_restart
    302 
    303 
    304     gdb_test_multiline "input command redefining itself" \
    305 	"python" "" \
    306 	"class redefine_cmd (gdb.Command):" "" \
    307 	"  def __init__ (self, msg):" "" \
    308 	"    super (redefine_cmd, self).__init__ (\"redefine_cmd\", gdb.COMMAND_OBSCURE)" "" \
    309 	"    self._msg = msg" "" \
    310 	"  def invoke (self, arg, from_tty):" "" \
    311 	"    print (\"redefine_cmd output, msg = %s\" % self._msg)" "" \
    312 	"    redefine_cmd (arg)" "" \
    313 	"redefine_cmd (\"XXX\")" "" \
    314 	"end" ""
    315 
    316     gdb_test "redefine_cmd AAA" \
    317 	"redefine_cmd output, msg = XXX" \
    318 	"call command redefining itself 1"
    319 
    320     gdb_test "redefine_cmd BBB" \
    321 	"redefine_cmd output, msg = AAA" \
    322 	"call command redefining itself 2"
    323 }
    324 
    325 # Try to create commands using unknown prefixes and check GDB gives an
    326 # error.  There's also a test in here for an ambiguous prefix, which
    327 # gives the same error.
    328 proc_with_prefix test_unknown_prefix {} {
    329     clean_restart
    330 
    331     gdb_test_no_output "python gdb.Command('foo1', gdb.COMMAND_NONE, prefix=True)"
    332     gdb_test_no_output "python gdb.Command('foo cmd', gdb.COMMAND_NONE)"
    333 
    334     foreach prefix { "xxx" "foo xxx" "foo1 xxx" } {
    335 	gdb_test "python gdb.Command('$prefix cmd', gdb.COMMAND_NONE)" \
    336 	    [multi_line \
    337 		 "Python Exception <class 'RuntimeError'>: Could not find command prefix $prefix\\." \
    338 		 "Error occurred in Python: Could not find command prefix $prefix\\."]
    339     }
    340 
    341     gdb_test_no_output "python gdb.Command('foo2', gdb.COMMAND_NONE, prefix=True)"
    342 
    343     foreach prefix { "foo" "foo xxx" "foo1 xxx" "foo2 xxx" } {
    344 	gdb_test "python gdb.Command('$prefix cmd2', gdb.COMMAND_NONE)" \
    345 	    [multi_line \
    346 		 "Python Exception <class 'RuntimeError'>: Could not find command prefix $prefix\\." \
    347 		 "Error occurred in Python: Could not find command prefix $prefix\\."]
    348     }
    349 }
    350 
    351 # Check what happens if a command object is called without an 'invoke'
    352 # method.
    353 proc_with_prefix test_deleting_invoke_methods {} {
    354     clean_restart
    355 
    356     gdb_test_multiline "create 'foo' prefix command" \
    357 	"python" "" \
    358 	"class test_prefix(gdb.Command):" "" \
    359 	"  def __init__ (self):" "" \
    360 	"    super().__init__ (\"foo\", gdb.COMMAND_USER, prefix=True)" "" \
    361 	"  def invoke (self, arg, from_tty):" "" \
    362 	"    print(\"In 'foo' invoke: %s\" % arg)" "" \
    363 	"foo = test_prefix()" "" \
    364 	"end" ""
    365 
    366     gdb_test_multiline "create 'foo bar' command" \
    367 	"python" "" \
    368 	"class test_cmd(gdb.Command):" "" \
    369 	"  def __init__ (self):" "" \
    370 	"    super().__init__ (\"foo bar\", gdb.COMMAND_USER)" "" \
    371 	"  def invoke (self, arg, from_tty):" "" \
    372 	"    print(\"In 'foo bar' invoke: %s\" % arg)" "" \
    373 	"foo_bar = test_cmd()" "" \
    374 	"end" ""
    375 
    376     gdb_test "foo def" "In 'foo' invoke: def" \
    377 	"call 'foo' with an unknown sub-command"
    378 
    379     gdb_test "foo bar def" "In 'foo bar' invoke: def" \
    380 	"call 'foo bar' with arguments"
    381 
    382     gdb_test_no_output "python del(foo_bar.__class__.invoke)" \
    383 	"delete invoke from test_cmd class"
    384 
    385     with_test_prefix "after deleting test_cmd.invoke" {
    386 	gdb_test "foo def" "In 'foo' invoke: def" \
    387 	    "call 'foo' with an unknown sub-command"
    388 
    389 	gdb_test "foo bar def" \
    390 	    "^Python command object missing 'invoke' method\\." \
    391 	    "call 'foo bar' with arguments"
    392     }
    393 
    394     gdb_test_no_output "python del(foo.__class__.invoke)" \
    395 	"delete invoke from test_prefix class"
    396 
    397     with_test_prefix "after deleting test_prefix.invoke" {
    398 	gdb_test "foo def" \
    399 	    "^Python command object missing 'invoke' method\\." \
    400 	    "call 'foo' with an unknown sub-command"
    401 
    402 	gdb_test "foo bar def" \
    403 	    "^Python command object missing 'invoke' method\\." \
    404 	    "call 'foo bar' with arguments"
    405     }
    406 }
    407 
    408 test_command_redefining_itself
    409 test_unknown_prefix
    410 test_deleting_invoke_methods
    411