Home | History | Annotate | Line # | Download | only in gdb.python
      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 import gdb
     16 
     17 
     18 class BadKey:
     19     def __repr__(self):
     20         return "Bad Key"
     21 
     22 
     23 class ReallyBadKey:
     24     def __repr__(self):
     25         return BadKey()
     26 
     27 
     28 class pycmd1(gdb.MICommand):
     29     def invoke(self, argv):
     30         if argv[0] == "int":
     31             return {"result": 42}
     32         elif argv[0] == "str":
     33             return {"result": "Hello world!"}
     34         elif argv[0] == "ary":
     35             return {"result": ["Hello", 42]}
     36         elif argv[0] == "dct":
     37             return {"result": {"hello": "world", "times": 42}}
     38         elif argv[0] == "bk1":
     39             return {"result": {BadKey(): "world"}}
     40         elif argv[0] == "bk2":
     41             return {"result": {1: "world"}}
     42         elif argv[0] == "bk3":
     43             return {"result": {ReallyBadKey(): "world"}}
     44         elif argv[0] == "tpl":
     45             return {"result": (42, "Hello")}
     46         elif argv[0] == "itr":
     47             return {"result": iter([1, 2, 3])}
     48         elif argv[0] == "nn1":
     49             return None
     50         elif argv[0] == "nn2":
     51             return {"result": [None]}
     52         elif argv[0] == "red":
     53             pycmd2("-pycmd")
     54             return None
     55         elif argv[0] == "nd1":
     56             return [1, 2, 3]
     57         elif argv[0] == "nd2":
     58             return 123
     59         elif argv[0] == "nd3":
     60             return "abc"
     61         elif argv[0] == "ik1":
     62             return {"xxx yyy": 123}
     63         elif argv[0] == "ik2":
     64             return {"result": {"xxx yyy": 123}}
     65         elif argv[0] == "ik3":
     66             return {"xxx+yyy": 123}
     67         elif argv[0] == "ik4":
     68             return {"xxx.yyy": 123}
     69         elif argv[0] == "ik5":
     70             return {"123xxxyyy": 123}
     71         elif argv[0] == "empty_key":
     72             return {"": 123}
     73         elif argv[0] == "dash-key":
     74             return {"the-key": 123}
     75         elif argv[0] == "exp":
     76             raise gdb.GdbError()
     77         else:
     78             raise gdb.GdbError("Invalid parameter: %s" % argv[0])
     79 
     80 
     81 class pycmd2(gdb.MICommand):
     82     def invoke(self, argv):
     83         if argv[0] == "str":
     84             return {"result": "Ciao!"}
     85         elif argv[0] == "red":
     86             pycmd1("-pycmd")
     87             raise gdb.GdbError("Command redefined but we failing anyway")
     88         elif argv[0] == "new":
     89             pycmd1("-pycmd-new")
     90             return None
     91         else:
     92             raise gdb.GdbError("Invalid parameter: %s" % argv[0])
     93 
     94 
     95 # This class creates a command that returns a string, which is passed
     96 # when the command is created.
     97 class pycmd3(gdb.MICommand):
     98     def __init__(self, name, msg, top_level):
     99         super(pycmd3, self).__init__(name)
    100         self._msg = msg
    101         self._top_level = top_level
    102 
    103     def invoke(self, args):
    104         return {self._top_level: {"msg": self._msg}}
    105 
    106 
    107 # A command that is missing it's invoke method.
    108 class no_invoke(gdb.MICommand):
    109     def __init__(self, name):
    110         super(no_invoke, self).__init__(name)
    111 
    112 
    113 def free_invoke(obj, args):
    114     return {"result": args}
    115 
    116 
    117 # Run some test involving catching exceptions.  It's easier to write
    118 # these as a Python function which is then called from the exp script.
    119 def run_exception_tests():
    120     print("PASS")
    121 
    122 
    123 # Run some execute_mi tests.  This is easier to do from Python.
    124 def run_execute_mi_tests():
    125     # Install the command.
    126     cmd = pycmd1("-pycmd")
    127     # Pass in a representative subset of the pycmd1 keys, and then
    128     # check that the result via MI is the same as the result via a
    129     # direct Python call.  Note that some results won't compare as
    130     # equal -- for example, a Python MI command can return a tuple,
    131     # but that will be translated to a Python list.
    132     for name in ("int", "str", "dct"):
    133         expect = cmd.invoke([name])
    134         got = gdb.execute_mi("-pycmd", name)
    135         if expect != got:
    136             print("FAIL: saw " + repr(got) + ", but expected " + repr(expect))
    137             return
    138     ok = False
    139     try:
    140         gdb.execute_mi("-pycmd", "exp")
    141     # Due to the "denaturation" problem, we have to expect a gdb.error
    142     # here and not a gdb.GdbError.
    143     except gdb.error:
    144         ok = True
    145     if not ok:
    146         print("FAIL: did not throw exception")
    147     print("PASS")
    148