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