Home | History | Annotate | Line # | Download | only in python
      1 /* MI Command Set for GDB, the GNU debugger.
      2 
      3    Copyright (C) 2019-2024 Free Software Foundation, Inc.
      4 
      5    This file is part of GDB.
      6 
      7    This program is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19 
     20 /* GDB/MI commands implemented in Python.  */
     21 
     22 #include "python-internal.h"
     23 #include "arch-utils.h"
     24 #include "charset.h"
     25 #include "language.h"
     26 #include "mi/mi-cmds.h"
     27 #include "mi/mi-parse.h"
     28 #include "cli/cli-cmds.h"
     29 #include <string>
     30 
     31 /* Debugging of Python MI commands.  */
     32 
     33 static bool pymicmd_debug;
     34 
     35 /* Implementation of "show debug py-micmd".  */
     36 
     37 static void
     38 show_pymicmd_debug (struct ui_file *file, int from_tty,
     39 		    struct cmd_list_element *c, const char *value)
     40 {
     41   gdb_printf (file, _("Python MI command debugging is %s.\n"), value);
     42 }
     43 
     44 /* Print a "py-micmd" debug statement.  */
     45 
     46 #define pymicmd_debug_printf(fmt, ...) \
     47   debug_prefixed_printf_cond (pymicmd_debug, "py-micmd", fmt, ##__VA_ARGS__)
     48 
     49 /* Print a "py-micmd" enter/exit debug statements.  */
     50 
     51 #define PYMICMD_SCOPED_DEBUG_ENTER_EXIT \
     52   scoped_debug_enter_exit (pymicmd_debug, "py-micmd")
     53 
     54 struct mi_command_py;
     55 
     56 /* Representation of a Python gdb.MICommand object.  */
     57 
     58 struct micmdpy_object
     59 {
     60   PyObject_HEAD
     61 
     62   /* The object representing this command in the MI command table.  This
     63      pointer can be nullptr if the command is not currently installed into
     64      the MI command table (see gdb.MICommand.installed property).  */
     65   struct mi_command_py *mi_command;
     66 
     67   /* The string representing the name of this command, without the leading
     68      dash.  This string is never nullptr once the Python object has been
     69      initialised.
     70 
     71      The memory for this string was allocated with malloc, and needs to be
     72      deallocated with free when the Python object is deallocated.
     73 
     74      When the MI_COMMAND field is not nullptr, then the mi_command_py
     75      object's name will point back to this string.  */
     76   char *mi_command_name;
     77 };
     78 
     79 /* The MI command implemented in Python.  */
     80 
     81 struct mi_command_py : public mi_command
     82 {
     83   /* Constructs a new mi_command_py object.  NAME is command name without
     84      leading dash.  OBJECT is a reference to a Python object implementing
     85      the command.  This object must inherit from gdb.MICommand and must
     86      implement the invoke method.  */
     87 
     88   mi_command_py (const char *name, micmdpy_object *object)
     89     : mi_command (name, nullptr),
     90       m_pyobj (gdbpy_ref<micmdpy_object>::new_reference (object))
     91   {
     92     pymicmd_debug_printf ("this = %p", this);
     93     m_pyobj->mi_command = this;
     94   }
     95 
     96   ~mi_command_py ()
     97   {
     98     /* The Python object representing a MI command contains a pointer back
     99        to this c++ object.  We can safely set this pointer back to nullptr
    100        now, to indicate the Python object no longer references a valid c++
    101        object.
    102 
    103        However, the Python object also holds the storage for our name
    104        string.  We can't clear that here as our parent's destructor might
    105        still want to reference that string.  Instead we rely on the Python
    106        object deallocator to free that memory, and reset the pointer.  */
    107     m_pyobj->mi_command = nullptr;
    108 
    109     pymicmd_debug_printf ("this = %p", this);
    110   };
    111 
    112   /* Validate that CMD_OBJ, a non-nullptr pointer, is installed into the MI
    113      command table correctly.  This function looks up the command in the MI
    114      command table and checks that the object we get back references
    115      CMD_OBJ.  This function is only intended for calling within a
    116      gdb_assert.  This function performs many assertions internally, and
    117      then always returns true.  */
    118   static void validate_installation (micmdpy_object *cmd_obj);
    119 
    120   /* Update M_PYOBJ to NEW_PYOBJ.  The pointer from M_PYOBJ that points
    121      back to this object is swapped with the pointer in NEW_PYOBJ, which
    122      must be nullptr, so that NEW_PYOBJ now points back to this object.
    123      Additionally our parent's name string is stored in M_PYOBJ, so we
    124      swap the name string with NEW_PYOBJ.
    125 
    126      Before this call M_PYOBJ is the Python object representing this MI
    127      command object.  After this call has completed, NEW_PYOBJ now
    128      represents this MI command object.  */
    129   void swap_python_object (micmdpy_object *new_pyobj)
    130   {
    131     /* Current object has a backlink, new object doesn't have a backlink.  */
    132     gdb_assert (m_pyobj->mi_command != nullptr);
    133     gdb_assert (new_pyobj->mi_command == nullptr);
    134 
    135     /* Clear the current M_PYOBJ's backlink, set NEW_PYOBJ's backlink.  */
    136     std::swap (new_pyobj->mi_command, m_pyobj->mi_command);
    137 
    138     /* Both object have names.  */
    139     gdb_assert (m_pyobj->mi_command_name != nullptr);
    140     gdb_assert (new_pyobj->mi_command_name != nullptr);
    141 
    142     /* mi_command::m_name is the string owned by the current object.  */
    143     gdb_assert (m_pyobj->mi_command_name == this->name ());
    144 
    145     /* The name in mi_command::m_name is owned by the current object.  Rather
    146        than changing the value of mi_command::m_name (which is not accessible
    147        from here) to point to the name owned by the new object, swap the names
    148        of the two objects, since we know they are identical strings.  */
    149     gdb_assert (strcmp (new_pyobj->mi_command_name,
    150 			m_pyobj->mi_command_name) == 0);
    151     std::swap (new_pyobj->mi_command_name, m_pyobj->mi_command_name);
    152 
    153     /* Take a reference to the new object, drop the reference to the current
    154        object.  */
    155     m_pyobj = gdbpy_ref<micmdpy_object>::new_reference (new_pyobj);
    156   }
    157 
    158   /* Called when the MI command is invoked.  */
    159   virtual void invoke(struct mi_parse *parse) const override;
    160 
    161 private:
    162   /* The Python object representing this MI command.  */
    163   gdbpy_ref<micmdpy_object> m_pyobj;
    164 };
    165 
    166 using mi_command_py_up = std::unique_ptr<mi_command_py>;
    167 
    168 extern PyTypeObject micmdpy_object_type
    169 	CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("micmdpy_object");
    170 
    171 /* Holds a Python object containing the string 'invoke'.  */
    172 
    173 static PyObject *invoke_cst;
    174 
    175 /* Called when the MI command is invoked.  PARSE contains the parsed
    176    command line arguments from the user.  */
    177 
    178 void
    179 mi_command_py::invoke (struct mi_parse *parse) const
    180 {
    181   PYMICMD_SCOPED_DEBUG_ENTER_EXIT;
    182 
    183   pymicmd_debug_printf ("this = %p, name = %s", this, name ());
    184 
    185   parse->parse_argv ();
    186 
    187   if (parse->argv == nullptr)
    188     error (_("Problem parsing arguments: %s %s"), parse->command.get (),
    189 	   parse->args ());
    190 
    191 
    192   gdbpy_enter enter_py;
    193 
    194   /* Place all the arguments into a list which we pass as a single argument
    195      to the MI command's invoke method.  */
    196   gdbpy_ref<> argobj (PyList_New (parse->argc));
    197   if (argobj == nullptr)
    198     gdbpy_handle_exception ();
    199 
    200   for (int i = 0; i < parse->argc; ++i)
    201     {
    202       gdbpy_ref<> str (PyUnicode_Decode (parse->argv[i],
    203 					 strlen (parse->argv[i]),
    204 					 host_charset (), nullptr));
    205       if (PyList_SetItem (argobj.get (), i, str.release ()) < 0)
    206 	gdbpy_handle_exception ();
    207     }
    208 
    209   gdb_assert (this->m_pyobj != nullptr);
    210   gdb_assert (PyErr_Occurred () == nullptr);
    211   gdbpy_ref<> results
    212     (PyObject_CallMethodObjArgs ((PyObject *) this->m_pyobj.get (), invoke_cst,
    213 				 argobj.get (), nullptr));
    214   if (results == nullptr)
    215     gdbpy_handle_exception ();
    216 
    217   if (results != Py_None)
    218     {
    219       /* At the top-level, the results must be a dictionary.  */
    220       if (!PyDict_Check (results.get ()))
    221 	gdbpy_error (_("Result from invoke must be a dictionary"));
    222       serialize_mi_results (results.get ());
    223     }
    224 }
    225 
    226 /* See declaration above.  */
    227 
    228 void
    229 mi_command_py::validate_installation (micmdpy_object *cmd_obj)
    230 {
    231   gdb_assert (cmd_obj != nullptr);
    232   mi_command_py *cmd = cmd_obj->mi_command;
    233   gdb_assert (cmd != nullptr);
    234   const char *name = cmd_obj->mi_command_name;
    235   gdb_assert (name != nullptr);
    236   gdb_assert (name == cmd->name ());
    237   mi_command *mi_cmd = mi_cmd_lookup (name);
    238   gdb_assert (mi_cmd == cmd);
    239   gdb_assert (cmd->m_pyobj == cmd_obj);
    240 }
    241 
    242 /* Return CMD as an mi_command_py if it is a Python MI command, else
    243    nullptr.  */
    244 
    245 static mi_command_py *
    246 as_mi_command_py (mi_command *cmd)
    247 {
    248   return dynamic_cast<mi_command_py *> (cmd);
    249 }
    250 
    251 /* Uninstall OBJ, making the MI command represented by OBJ unavailable for
    252    use by the user.  On success 0 is returned, otherwise -1 is returned
    253    and a Python exception will be set.  */
    254 
    255 static int
    256 micmdpy_uninstall_command (micmdpy_object *obj)
    257 {
    258   PYMICMD_SCOPED_DEBUG_ENTER_EXIT;
    259 
    260   gdb_assert (obj->mi_command != nullptr);
    261   gdb_assert (obj->mi_command_name != nullptr);
    262 
    263   pymicmd_debug_printf ("name = %s", obj->mi_command_name);
    264 
    265   /* Remove the command from the internal MI table of commands.  This will
    266      cause the mi_command_py object to be deleted, which will clear the
    267      backlink in OBJ.  */
    268   bool removed = remove_mi_cmd_entry (obj->mi_command->name ());
    269   gdb_assert (removed);
    270   gdb_assert (obj->mi_command == nullptr);
    271 
    272   return 0;
    273 }
    274 
    275 /* Install OBJ as a usable MI command.  Return 0 on success, and -1 on
    276    error, in which case, a Python error will have been set.
    277 
    278    After successful completion the command name associated with OBJ will
    279    be installed in the MI command table (so it can be found if the user
    280    enters that command name), additionally, OBJ will have been added to
    281    the gdb._mi_commands dictionary (using the command name as its key),
    282    this will ensure that OBJ remains live even if the user gives up all
    283    references.  */
    284 
    285 static int
    286 micmdpy_install_command (micmdpy_object *obj)
    287 {
    288   PYMICMD_SCOPED_DEBUG_ENTER_EXIT;
    289 
    290   gdb_assert (obj->mi_command == nullptr);
    291   gdb_assert (obj->mi_command_name != nullptr);
    292 
    293   pymicmd_debug_printf ("name = %s", obj->mi_command_name);
    294 
    295   /* Look up this command name in MI_COMMANDS, a command with this name may
    296      already exist.  */
    297   mi_command *cmd = mi_cmd_lookup (obj->mi_command_name);
    298   mi_command_py *cmd_py = as_mi_command_py (cmd);
    299 
    300   if (cmd != nullptr && cmd_py == nullptr)
    301     {
    302       /* There is already an MI command registered with that name, and it's not
    303 	 a Python one.  Forbid replacing a non-Python MI command.  */
    304       PyErr_SetString (PyExc_RuntimeError,
    305 		       _("unable to add command, name is already in use"));
    306       return -1;
    307     }
    308 
    309   if (cmd_py != nullptr)
    310     {
    311       /* There is already a Python MI command registered with that name, swap
    312 	 in the new gdb.MICommand implementation.  */
    313       cmd_py->swap_python_object (obj);
    314     }
    315   else
    316     {
    317       /* There's no MI command registered with that name at all, create one.  */
    318       mi_command_py_up mi_cmd (new mi_command_py (obj->mi_command_name, obj));
    319 
    320       /* Add the command to the gdb internal MI command table.  */
    321       bool result = insert_mi_cmd_entry (std::move (mi_cmd));
    322       gdb_assert (result);
    323     }
    324 
    325   return 0;
    326 }
    327 
    328 /* Implement gdb.MICommand.__init__.  The init method takes the name of
    329    the MI command as the first argument, which must be a string, starting
    330    with a single dash.  */
    331 
    332 static int
    333 micmdpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
    334 {
    335   PYMICMD_SCOPED_DEBUG_ENTER_EXIT;
    336 
    337   micmdpy_object *cmd = (micmdpy_object *) self;
    338 
    339   static const char *keywords[] = { "name", nullptr };
    340   const char *name;
    341 
    342   if (!gdb_PyArg_ParseTupleAndKeywords (args, kwargs, "s", keywords,
    343 					&name))
    344     return -1;
    345 
    346   /* Validate command name */
    347   const int name_len = strlen (name);
    348   if (name_len == 0)
    349     {
    350       PyErr_SetString (PyExc_ValueError, _("MI command name is empty."));
    351       return -1;
    352     }
    353   else if ((name_len < 2) || (name[0] != '-') || !isalnum (name[1]))
    354     {
    355       PyErr_SetString (PyExc_ValueError,
    356 		       _("MI command name does not start with '-'"
    357 			 " followed by at least one letter or digit."));
    358       return -1;
    359     }
    360   else
    361     {
    362       for (int i = 2; i < name_len; i++)
    363 	{
    364 	  if (!isalnum (name[i]) && name[i] != '-')
    365 	    {
    366 	      PyErr_Format
    367 		(PyExc_ValueError,
    368 		 _("MI command name contains invalid character: %c."),
    369 		 name[i]);
    370 	      return -1;
    371 	    }
    372 	}
    373 
    374       /* Skip over the leading dash.  For the rest of this function the
    375 	 dash is not important.  */
    376       ++name;
    377     }
    378 
    379   /* If this object already has a name set, then this object has been
    380      initialized before.  We handle this case a little differently.  */
    381   if (cmd->mi_command_name != nullptr)
    382     {
    383       /* First, we don't allow the user to change the MI command name.
    384 	 Supporting this would be tricky as we would need to delete the
    385 	 mi_command_py from the MI command table, however, the user might
    386 	 be trying to perform this reinitialization from within the very
    387 	 command we're about to delete... it all gets very messy.
    388 
    389 	 So, for now at least, we don't allow this.  This doesn't seem like
    390 	 an excessive restriction.  */
    391       if (strcmp (cmd->mi_command_name, name) != 0)
    392 	{
    393 	  PyErr_SetString
    394 	    (PyExc_ValueError,
    395 	     _("can't reinitialize object with a different command name"));
    396 	  return -1;
    397 	}
    398 
    399       /* If there's already an object registered with the MI command table,
    400 	 then we're done.  That object must be a mi_command_py, which
    401 	 should reference back to this micmdpy_object.  */
    402       if (cmd->mi_command != nullptr)
    403 	{
    404 	  mi_command_py::validate_installation (cmd);
    405 	  return 0;
    406 	}
    407     }
    408   else
    409     cmd->mi_command_name = xstrdup (name);
    410 
    411   /* Now we can install this mi_command_py in the MI command table.  */
    412   return micmdpy_install_command (cmd);
    413 }
    414 
    415 /* Called when a gdb.MICommand object is deallocated.  */
    416 
    417 static void
    418 micmdpy_dealloc (PyObject *obj)
    419 {
    420   PYMICMD_SCOPED_DEBUG_ENTER_EXIT;
    421 
    422   micmdpy_object *cmd = (micmdpy_object *) obj;
    423 
    424   /* If the Python object failed to initialize, then the name field might
    425      be nullptr.  */
    426   pymicmd_debug_printf ("obj = %p, name = %s", cmd,
    427 			(cmd->mi_command_name == nullptr
    428 			 ? "(null)" : cmd->mi_command_name));
    429 
    430   /* As the mi_command_py object holds a reference to the micmdpy_object,
    431      the only way the dealloc function can be called is if the mi_command_py
    432      object has been deleted, in which case the following assert will
    433      hold.  */
    434   gdb_assert (cmd->mi_command == nullptr);
    435 
    436   /* Free the memory that holds the command name.  */
    437   xfree (cmd->mi_command_name);
    438   cmd->mi_command_name = nullptr;
    439 
    440   /* Finally, free the memory for this Python object.  */
    441   Py_TYPE (obj)->tp_free (obj);
    442 }
    443 
    444 /* Python initialization for the MI commands components.  */
    445 
    446 static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
    447 gdbpy_initialize_micommands ()
    448 {
    449   micmdpy_object_type.tp_new = PyType_GenericNew;
    450   if (PyType_Ready (&micmdpy_object_type) < 0)
    451     return -1;
    452 
    453   if (gdb_pymodule_addobject (gdb_module, "MICommand",
    454 			      (PyObject *) &micmdpy_object_type)
    455       < 0)
    456     return -1;
    457 
    458   invoke_cst = PyUnicode_FromString ("invoke");
    459   if (invoke_cst == nullptr)
    460     return -1;
    461 
    462   return 0;
    463 }
    464 
    465 /* Cleanup just before GDB shuts down the Python interpreter.  */
    466 
    467 static void
    468 gdbpy_finalize_micommands ()
    469 {
    470   /* mi_command_py objects hold references to micmdpy_object objects.  They must
    471      be dropped before the Python interpreter is finalized.  Do so by removing
    472      those MI command entries, thus deleting the mi_command_py objects.  */
    473   remove_mi_cmd_entries ([] (mi_command *cmd)
    474     {
    475       return as_mi_command_py (cmd) != nullptr;
    476     });
    477 }
    478 
    479 /* Get the gdb.MICommand.name attribute, returns a string, the name of this
    480    MI command.  */
    481 
    482 static PyObject *
    483 micmdpy_get_name (PyObject *self, void *closure)
    484 {
    485   struct micmdpy_object *micmd_obj = (struct micmdpy_object *) self;
    486 
    487   gdb_assert (micmd_obj->mi_command_name != nullptr);
    488   std::string name_str = string_printf ("-%s", micmd_obj->mi_command_name);
    489   return PyUnicode_FromString (name_str.c_str ());
    490 }
    491 
    492 /* Get the gdb.MICommand.installed property.  Returns true if this MI
    493    command is installed into the MI command table, otherwise returns
    494    false.  */
    495 
    496 static PyObject *
    497 micmdpy_get_installed (PyObject *self, void *closure)
    498 {
    499   struct micmdpy_object *micmd_obj = (struct micmdpy_object *) self;
    500 
    501   if (micmd_obj->mi_command == nullptr)
    502     Py_RETURN_FALSE;
    503   Py_RETURN_TRUE;
    504 }
    505 
    506 /* Set the gdb.MICommand.installed property.  The property can be set to
    507    either true or false.  Setting the property to true will cause the
    508    command to be installed into the MI command table (if it isn't
    509    already), while setting this property to false will cause the command
    510    to be removed from the MI command table (if it is present).  */
    511 
    512 static int
    513 micmdpy_set_installed (PyObject *self, PyObject *newvalue, void *closure)
    514 {
    515   struct micmdpy_object *micmd_obj = (struct micmdpy_object *) self;
    516 
    517   bool installed_p = PyObject_IsTrue (newvalue);
    518   if (installed_p == (micmd_obj->mi_command != nullptr))
    519     return 0;
    520 
    521   if (installed_p)
    522     return micmdpy_install_command (micmd_obj);
    523   else
    524     return micmdpy_uninstall_command (micmd_obj);
    525 }
    526 
    527 /* The gdb.MICommand properties.   */
    528 
    529 static gdb_PyGetSetDef micmdpy_object_getset[] = {
    530   { "name", micmdpy_get_name, nullptr, "The command's name.", nullptr },
    531   { "installed", micmdpy_get_installed, micmdpy_set_installed,
    532     "Is this command installed for use.", nullptr },
    533   { nullptr }	/* Sentinel.  */
    534 };
    535 
    536 /* The gdb.MICommand descriptor.  */
    537 
    538 PyTypeObject micmdpy_object_type = {
    539   PyVarObject_HEAD_INIT (nullptr, 0) "gdb.MICommand", /*tp_name */
    540   sizeof (micmdpy_object),			   /*tp_basicsize */
    541   0,						   /*tp_itemsize */
    542   micmdpy_dealloc,				   /*tp_dealloc */
    543   0,						   /*tp_print */
    544   0,						   /*tp_getattr */
    545   0,						   /*tp_setattr */
    546   0,						   /*tp_compare */
    547   0,						   /*tp_repr */
    548   0,						   /*tp_as_number */
    549   0,						   /*tp_as_sequence */
    550   0,						   /*tp_as_mapping */
    551   0,						   /*tp_hash */
    552   0,						   /*tp_call */
    553   0,						   /*tp_str */
    554   0,						   /*tp_getattro */
    555   0,						   /*tp_setattro */
    556   0,						   /*tp_as_buffer */
    557   Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,	/*tp_flags */
    558   "GDB mi-command object",			   /* tp_doc */
    559   0,						   /* tp_traverse */
    560   0,						   /* tp_clear */
    561   0,						   /* tp_richcompare */
    562   0,						   /* tp_weaklistoffset */
    563   0,						   /* tp_iter */
    564   0,						   /* tp_iternext */
    565   0,						   /* tp_methods */
    566   0,						   /* tp_members */
    567   micmdpy_object_getset,			   /* tp_getset */
    568   0,						   /* tp_base */
    569   0,						   /* tp_dict */
    570   0,						   /* tp_descr_get */
    571   0,						   /* tp_descr_set */
    572   0,						   /* tp_dictoffset */
    573   micmdpy_init,					   /* tp_init */
    574   0,						   /* tp_alloc */
    575 };
    576 
    577 void _initialize_py_micmd ();
    578 void
    579 _initialize_py_micmd ()
    580 {
    581   add_setshow_boolean_cmd
    582     ("py-micmd", class_maintenance, &pymicmd_debug,
    583      _("Set Python micmd debugging."),
    584      _("Show Python micmd debugging."),
    585      _("When on, Python micmd debugging is enabled."),
    586      nullptr,
    587      show_pymicmd_debug,
    588      &setdebuglist, &showdebuglist);
    589 }
    590 
    591 GDBPY_INITIALIZE_FILE (gdbpy_initialize_micommands, gdbpy_finalize_micommands);
    592