This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC][patch 5/9] permit GDB commands implemented in Python


2008-04-29  Tom Tromey <tromey@redhat.com>

	* Makefile.in (SUBDIR_PYTHON_OBS): Add python-cmd.o.
	(SUBDIR_PYTHON_SRCS): Add python/cmd.c.
	(python-cmd.o): New target.
	* cli/cli-cmds.c (edit_command): Delete log10 code.
	* cli/cli-decode.c (delete_cmd): Rewrote.  Handle 'destroyer'
	field.
	(add_cmd): Initialize 'destroyer'.
	* cli/cli-decode.h (struct cmd_list_element): Added 'destroyer'
	field.
	* python/cmd.c: New file.
	* python/python-internal.h (gdbpy_initialize_commands): Declare.
	* python/python.c (demand_python): Call gdbpy_initialize_commands.

Index: tromey.git/gdb/Makefile.in
===================================================================
--- tromey.git.orig/gdb/Makefile.in	2008-04-29 11:05:15.000000000 -0300
+++ tromey.git/gdb/Makefile.in	2008-04-29 11:05:20.000000000 -0300
@@ -263,11 +263,13 @@ SUBDIR_TUI_CFLAGS= \
 SUBDIR_PYTHON_OBS = \
 	python.o \
 	python-breakpoint.o \
+	python-cmd.o \
 	python-hooks.o \
 	python-value.o
 SUBDIR_PYTHON_SRCS = \
 	python/python.c \
 	python/breakpoint.c \
+	python/cmd.c \
 	python/hooks.c \
 	python/value.c
 SUBDIR_PYTHON_DEPS =
@@ -3422,6 +3424,11 @@ python-breakpoint.o: $(srcdir)/python/br
 	$(breakpoint_h) $(gdbcmd_h)
 	$(CC) -c $(INTERNAL_CFLAGS) $(PYTHON_CFLAGS) \
 	$(srcdir)/python/breakpoint.c -o python-breakpoint.o
+python-cmd.o: $(srcdir)/python/cmd.c $(defs_h) $(python_h) $(value_h) \
+	$(exceptions_h) $(python_internal_h) $(charset_h) \
+	$(gdbcmd_h) $(cli_decode_h)
+	$(CC) -c $(INTERNAL_CFLAGS) $(PYTHON_CFLAGS) \
+	$(srcdir)/python/cmd.c -o python-cmd.o
 python-hooks.o: $(srcdir)/python/hooks.c $(defs_h) $(cli_decode_h) \
 	$(charset_h) $(gdb_events_h) $(python_h) $(python_internal_h)
 	$(CC) -c $(INTERNAL_CFLAGS) $(PYTHON_CFLAGS) \
Index: tromey.git/gdb/cli/cli-cmds.c
===================================================================
--- tromey.git.orig/gdb/cli/cli-cmds.c	2008-04-29 10:57:39.000000000 -0300
+++ tromey.git/gdb/cli/cli-cmds.c	2008-04-29 11:05:20.000000000 -0300
@@ -615,8 +615,7 @@ edit_command (char *arg, int from_tty)
   struct symtab_and_line sal;
   struct symbol *sym;
   char *arg1;
-  int cmdlen, log10;
-  unsigned m;
+  int cmdlen;
   char *editor;
   char *p, *fn;
 
@@ -692,10 +691,6 @@ edit_command (char *arg, int from_tty)
   if ((editor = (char *) getenv ("EDITOR")) == NULL)
       editor = "/bin/ex";
 
-  /* Approximate base-10 log of line to 1 unit for digit count */
-  for(log10=32, m=0x80000000; !(sal.line & m) && log10>0; log10--, m=m>>1);
-  log10 = 1 + (int)((log10 + (0 == ((m-1) & sal.line)))/3.32192809);
-
   /* If we don't already know the full absolute file name of the
      source file, find it now.  */
   if (!sal.symtab->fullname)
Index: tromey.git/gdb/cli/cli-decode.c
===================================================================
--- tromey.git.orig/gdb/cli/cli-decode.c	2008-04-29 10:57:39.000000000 -0300
+++ tromey.git/gdb/cli/cli-decode.c	2008-04-29 11:05:20.000000000 -0300
@@ -190,6 +190,7 @@ add_cmd (char *name, enum command_class 
   c->allow_unknown = 0;
   c->abbrev_flag = 0;
   set_cmd_completer (c, make_symbol_completion_list);
+  c->destroyer = NULL;
   c->type = not_set_cmd;
   c->var = NULL;
   c->var_type = var_boolean;
@@ -614,37 +615,32 @@ add_setshow_zinteger_cmd (char *name, en
 void
 delete_cmd (char *name, struct cmd_list_element **list)
 {
-  struct cmd_list_element *c;
-  struct cmd_list_element *p;
+  struct cmd_list_element *iter;
+  struct cmd_list_element **previous_chain_ptr;
+
+  previous_chain_ptr = list;
 
-  while (*list && strcmp ((*list)->name, name) == 0)
+  for (iter = *previous_chain_ptr; iter; iter = *previous_chain_ptr)
     {
-      if ((*list)->hookee_pre)
-      (*list)->hookee_pre->hook_pre = 0;   /* Hook slips out of its mouth */
-      if ((*list)->hookee_post)
-      (*list)->hookee_post->hook_post = 0; /* Hook slips out of its bottom  */
-      p = (*list)->next;
-      xfree (* list);
-      *list = p;
-    }
+      if (strcmp (iter->name, name) == 0)
+	{
+	  if (iter->destroyer)
+	    iter->destroyer (iter, iter->context);
+	  if (iter->hookee_pre)
+	    iter->hookee_pre->hook_pre = 0;
+	  if (iter->hookee_post)
+	    iter->hookee_post->hook_post = 0;
+
+	  /* Update the link.  Note that we don't change
+	     previous_chain_ptr; next time through the loop this must
+	     stay the same.  */
+	  *previous_chain_ptr = iter->next;
 
-  if (*list)
-    for (c = *list; c->next;)
-      {
-	if (strcmp (c->next->name, name) == 0)
-	  {
-          if (c->next->hookee_pre)
-            c->next->hookee_pre->hook_pre = 0; /* hooked cmd gets away.  */
-          if (c->next->hookee_post)
-            c->next->hookee_post->hook_post = 0; /* remove post hook */
-                                               /* :( no fishing metaphore */
-	    p = c->next->next;
-	    xfree (c->next);
-	    c->next = p;
-	  }
-	else
-	  c = c->next;
-      }
+	  xfree (iter);
+	}
+      else
+	previous_chain_ptr = &iter->next;
+    }
 }
 
 /* Shorthands to the commands above. */
Index: tromey.git/gdb/cli/cli-decode.h
===================================================================
--- tromey.git.orig/gdb/cli/cli-decode.h	2008-04-29 10:57:39.000000000 -0300
+++ tromey.git/gdb/cli/cli-decode.h	2008-04-29 11:05:20.000000000 -0300
@@ -168,6 +168,11 @@ struct cmd_list_element
        "oobar"; if WORD is "baz/foo", return "baz/foobar".  */
     char **(*completer) (char *text, char *word);
 
+    /* Destruction routine for this command.  If non-NULL, this is
+       called when this command instance is destroyed.  This may be
+       used to finalize the CONTEXT field, if needed.  */
+    void (*destroyer) (struct cmd_list_element *self, void *context);
+
     /* Type of "set" or "show" command (or SET_NOT_SET if not "set"
        or "show").  */
     cmd_types type;
Index: tromey.git/gdb/python/cmd.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ tromey.git/gdb/python/cmd.c	2008-04-29 11:05:40.000000000 -0300
@@ -0,0 +1,255 @@
+/* gdb commands implemented in Python
+
+   Copyright (C) 2008 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+#include "defs.h"
+#include "value.h"
+#include "exceptions.h"
+#include "python-internal.h"
+#include "charset.h"
+#include "gdbcmd.h"
+#include "cli/cli-decode.h"
+
+/* A gdb command.  For the time being only ordinary commands (not
+   set/show commands) are allowed.  */
+struct cmdpy_object
+{
+  PyObject_HEAD
+
+  /* The corresponding gdb command object, or NULL if the command is
+     no longer installed.  */
+  /* It isn't clear if we will ever care about this.  */
+  struct cmd_list_element *command;
+};
+
+typedef struct cmdpy_object cmdpy_object;
+
+static PyObject *cmdpy_dont_repeat (PyObject *self, PyObject *args);
+
+static PyMethodDef cmdpy_object_methods[] =
+{
+  { "dont_repeat", cmdpy_dont_repeat, METH_NOARGS,
+    "Prevent command repetition when user enters empty line." },
+
+  { 0 }
+};
+
+static PyTypeObject cmdpy_object_type =
+{
+  PyObject_HEAD_INIT (NULL)
+  0,				  /*ob_size*/
+  "gdb.Command",		  /*tp_name*/
+  sizeof (cmdpy_object),	  /*tp_basicsize*/
+  0,				  /*tp_itemsize*/
+  0,				  /*tp_dealloc*/
+  0,				  /*tp_print*/
+  0,				  /*tp_getattr*/
+  0,				  /*tp_setattr*/
+  0,				  /*tp_compare*/
+  0,				  /*tp_repr*/
+  0,				  /*tp_as_number*/
+  0,				  /*tp_as_sequence*/
+  0,				  /*tp_as_mapping*/
+  0,				  /*tp_hash */
+  0,				  /*tp_call*/
+  0,				  /*tp_str*/
+  0,				  /*tp_getattro*/
+  0,				  /*tp_setattro*/
+  0,				  /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  "GDB command object",		  /* tp_doc */
+  0,				  /* tp_traverse */
+  0,				  /* tp_clear */
+  0,				  /* tp_richcompare */
+  0,				  /* tp_weaklistoffset */
+  0,				  /* tp_iter */
+  0,				  /* tp_iternext */
+  cmdpy_object_methods		  /* tp_methods */
+};
+
+
+
+static PyObject *
+cmdpy_dont_repeat (PyObject *self, PyObject *args)
+{
+  dont_repeat ();
+  Py_RETURN_NONE;
+}
+
+
+
+
+/* Called if the gdb cmd_list_element is destroyed.  */
+static void
+cmdpy_destroyer (struct cmd_list_element *self, void *context)
+{
+  /* Release our hold on the command object.  */
+  cmdpy_object *cmd = (cmdpy_object *) context;
+  cmd->command = NULL;
+  Py_DECREF (cmd);
+
+  /* We allocated the name and doc string.  */
+  xfree (self->name);
+  xfree (self->doc);
+}
+
+/* Called by gdb to invoke the command.  */
+static void
+cmdpy_function (struct cmd_list_element *command, char *args, int from_tty)
+{
+  cmdpy_object *obj = (cmdpy_object *) get_cmd_context (command);
+  PyObject *method, *argobj, *ttyobj, *result;
+
+  if (! obj)
+    error ("Invalid invocation of Python command object");
+  if (! PyObject_HasAttrString ((PyObject *) obj, "invoke"))
+    error ("Python command object missing 'invoke' method");
+
+  method = PyString_FromString ("invoke");
+  if (! args)
+    {
+      argobj = Py_None;
+      Py_INCREF (argobj);
+    }
+  else
+    {
+      argobj = PyString_FromString (args);
+      if (! argobj)
+	error ("Couldn't convert arguments to Python string");
+    }
+  ttyobj = from_tty ? Py_True : Py_False;
+  Py_INCREF (ttyobj);
+  result = PyObject_CallMethodObjArgs ((PyObject *) obj, method, argobj,
+				       ttyobj, NULL);
+  Py_DECREF (method);
+  Py_DECREF (argobj);
+  Py_DECREF (ttyobj);
+  if (! result)
+    {
+      /* FIXME: pretty lame.  */
+      PyErr_Print ();
+      error ("Error occurred in Python command");
+    }
+  Py_DECREF (result);
+}
+
+/* Object initializer; sets up gdb-side structures for command.
+
+   Use: __init__(NAME, CMDCLASS).
+
+   NAME is the name of the command; spaces in the name mean to look up
+   initial segments as prefixes.
+
+   CMDCLASS is the kind of command.  It should be one of the COMMAND_*
+   constants defined in the gdb module.
+
+   The documentation for the command is taken from the doc string for
+   the python class.
+
+*/
+static int
+cmdpy_init (PyObject *self, PyObject *args, PyObject *kwds)
+{
+  cmdpy_object *obj = (cmdpy_object *) self;
+  char *name;
+  int cmdtype;
+  volatile struct gdb_exception except;
+
+  if (obj->command)
+    {
+      /* Note: this is apparently not documented in Python.  We return
+	 0 for success, -1 for failure.  */
+      PyErr_Format (PyExc_RuntimeError, "Command object already initialized");
+      return -1;
+    }
+
+  if (! PyArg_ParseTuple (args, "si", &name, &cmdtype))
+    return -1;
+
+  if (cmdtype != no_class && cmdtype != class_run
+      && cmdtype != class_vars && cmdtype != class_stack
+      && cmdtype != class_files && cmdtype != class_support
+      && cmdtype != class_info && cmdtype != class_breakpoint
+      && cmdtype != class_trace && cmdtype != class_obscure
+      && cmdtype != class_maintenance)
+    {
+      PyErr_Format (PyExc_RuntimeError, "invalid command class argument");
+      return -1;
+    }
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      /* FIXME: decoding NAME if it has spaces.  Also, how to add new
+	 prefix commands?  */
+      struct cmd_list_element *cmd = add_cmd (xstrdup (name),
+					      (enum command_class) cmdtype,
+					      NULL,
+					      xstrdup ("FIXME: docstring"),
+					      &cmdlist /* FIXME */);
+      /* There appears to be no API to set this.  */
+      cmd->func = cmdpy_function;
+      /* FIXME: route completion requests through user object.  */
+
+      obj->command = cmd;
+      Py_INCREF (self);
+      set_cmd_context (cmd, self);
+    }
+  if (except.reason < 0)
+    {
+      PyErr_Format (except.reason == RETURN_QUIT
+		    ? PyExc_KeyboardInterrupt : PyExc_RuntimeError,
+		    "%s", except.message);
+      return -1;
+    }
+  return 0;
+}
+
+
+
+void
+gdbpy_initialize_commands (void)
+{
+  cmdpy_object_type.tp_new = PyType_GenericNew;
+  cmdpy_object_type.tp_init = cmdpy_init;
+  if (PyType_Ready (&cmdpy_object_type) < 0)
+    return;
+
+  /* Note: alias and user seem to be special; pseudo appears to be
+     unused, and there is no reason to expose tui or xdb, I think.  */
+  if (PyModule_AddIntConstant (gdb_module, "COMMAND_NONE", no_class) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_RUN", class_run) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_VARS", class_vars) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_STACK", class_stack) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_FILES", class_files) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_SUPPORT",
+				  class_support) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_INFO", class_info) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_BREAKPOINT",
+				  class_breakpoint) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_TRACE", class_trace) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_OBSCURE",
+				  class_obscure) < 0
+      || PyModule_AddIntConstant (gdb_module, "COMMAND_MAINTENANCE",
+				  class_maintenance) < 0)
+    return;
+
+  Py_INCREF (&cmdpy_object_type);
+  PyModule_AddObject (gdb_module, "Command",
+		      (PyObject *) &cmdpy_object_type);
+}
Index: tromey.git/gdb/python/python-internal.h
===================================================================
--- tromey.git.orig/gdb/python/python-internal.h	2008-04-29 11:05:15.000000000 -0300
+++ tromey.git/gdb/python/python-internal.h	2008-04-29 11:05:20.000000000 -0300
@@ -44,6 +44,7 @@ PyObject *gdbpy_get_hook_function (const
 void gdbpy_initialize_values (void);
 void gdbpy_initialize_hooks (void);
 void gdbpy_initialize_breakpoints (void);
+void gdbpy_initialize_commands (void);
 
 /* Use this after a TRY_EXCEPT to throw the appropriate Python
    exception.  FIXME: throw different errors depending on
Index: tromey.git/gdb/python/python.c
===================================================================
--- tromey.git.orig/gdb/python/python.c	2008-04-29 11:05:15.000000000 -0300
+++ tromey.git/gdb/python/python.c	2008-04-29 11:05:20.000000000 -0300
@@ -70,6 +70,7 @@ demand_python ()
       gdbpy_initialize_hooks ();
       gdbpy_initialize_values ();
       gdbpy_initialize_breakpoints ();
+      gdbpy_initialize_commands ();
 
       PyRun_SimpleString ("import gdb");
 

-- 
-- 
[]'s
Thiago Jung Bauermann
Software Engineer
IBM Linux Technology Center


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]