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]

Re: [RFC][patch 1/9] initial Python support


Zitat von Daniel Jacobowitz <drow@false.org>:
Looks generally good.

Good, I'm generally happy then. :-)


For the general syntax: Should we allow $() to always mean Python, or
are there other useful potential scripting interfaces or environment
variable access or anything, in which case we want $(python ) or $(P )
or $python( )?  There are only so many nice grouping specifiers.  $<>
is not so good but we still have $[] and ${}, plus $env().  I don't
remember if we discussed this before, but we may have.

This discussion is still being carried out. In the interest of having at least the very basic committed soon, I removed support for Python evalution inside expressions for this patch. This is now in a separate patch in the python-patches branch. There, you will also find another patch which Tromey is developing implementing his other proposal (i.e., registering functions and then using $(func args) syntax).

The downside is that this patch adds near zero value to the user.
But all other patches build on this one.

We've discussed already the configure options - I'd prefer to avoid
this issue and only have --with-python and maybe
--with-python-lib/--with-python-include.  Parallel to the top level
gmp/mpfr handling, for instance.

This patch now sports the shiny new --with-python code brought to you by Doug Evans.

I didn't know about python-config.  Is that new?  Could we specify a
path to python-config instead of messing with cflags/ldflags directly?

Yes we could, but I didn't experiment with the idea...


And we sorted this out on IRC.

Hooray for IRC. :-)


The special_processing argument to read_next_line / read_command_lines
is not commented and the name doesn't say much of anything about what
it's for.  It looks like this changes the behavior of document versus
define, probably deliberately if it does what I think it does.  So
this would be a good patch to split out separately.  In general, any
bits that can go in separately should; it makes the whole pile easier
to manage :-)

You are right, I didn't know why these changes were there as well but at the time I kept them in the patch anyway. They seem to be useful only to varobj/MI Python bindings by Vladimir, and I separated them in another patch (found in the python-patches branch).

There are too many #ifdef's in the rest of GDB in this patch, IMO.
Can python/python.h be included unconditionally, not include
python-internal.h, and have the exposed interfaces error() when Python
support is not compiled in?  That's the approach I took for
xml-support.h.

Similarly we should recognize python_control regardless of
HAVE_PYTHON.  That way we can parse a .gdbinit which defines Python
commands and give a sensible error only if they are invoked.

Done, courtesy of Tom Tromey.


In general I would prefer we not commit any FIXMEs.  We can decide now
what the right thing to do is and if there is room for future
enhancement, that's not a FIXME any more :-)

All FIXMEs in this patch are now gone (also by Tromey).


> +
> +void
> +eval_python_from_control_command (struct command_line *cmd)
> +{
> +  char *script;
> +
> +  if (cmd->body_count != 1)
> +    error (_("Invalid \"python\" block structure."));
> +
> +  demand_python ();
> +
> +  script = compute_python_string (cmd->body_list[0]);
> +  PyRun_SimpleString (script);
> +  xfree (script);
> +  if (PyErr_Occurred ())
> +    {
> +      PyErr_Print ();
> +      error ("error while executing Python code");
> +    }
> +}

_() around arguments to error.  Also, in general PyErr_Print is
probably dumping to stderr?  Output should go through GDB's error
mechanisms, and in this case probably be part of the argument to
error.  Can you get it to return an error string instead?

This is stillpending, I think.


> +static PyObject *
> +execute_gdb_command (PyObject *self, PyObject *args)
> +{
> +  struct cmd_list_element *alias, *prefix, *cmd;
> +  char *arg, *newarg;
> +  volatile struct gdb_exception except;
> +
> +  if (! PyArg_ParseTuple (args, "s", &arg))
> +    return NULL;
> +
> +  TRY_CATCH (except, RETURN_MASK_ALL)
> +    {
> +      execute_command (arg, 0);
> +    }
> +  GDB_PY_HANDLE_EXCEPTION (except);
> +
> +  /* gdbtk does bpstat_do_actions here... */

Please figure out if we need to or not.  It looks like we do; running
the command "continue" to a breakpoint with actions will test it.

I don't know much about bpstat_do_actions, and didn't do the experiment you mention (not sure I understood it), so I made a crude try at adding a call to bpstat_do_actions just to get this patch out.

Speaking of which... a testsuite? :-)

Next in my list! -- []'s Thiago Jung Bauermann Software Engineer IBM Linux Technology Center




2008-06-15  Vladimir Prus  <vladimir@codesourcery.com>
	    Tom Tromey <tromey@redhat.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>
	    Doug Evans  <dje@google.com>

	* Makefile.in (SUBDIR_PYTHON_OBS, SUBDIR_PYTHON_SRCS,
	SUBDIR_PYTHON_DEPS, SUBDIR_PYTHON_LDFLAGS, SUBDIR_PYTHON_CFLAGS,
	PYTHON_CFLAGS): New.
	(python_h, python_internal_h): New.
	(COMMON_OBS): Add python.o.
	(INIT_FILES): Add python/python.c.
	(cli-script.o): Depend on python.h
	(python.o): New.
	* cli/cli-script.c (print_command_lines): Handle python_control.
	(execute_control_command): Handle python_control.
	(execute_control_command_suppressed): New function.
	(while_command): Call execute_control_command_suppressed.
	(if_command): Likewise.
	(get_command_line): Remove static attribute.
	(read_next_line): Handle "python".
	(recurse_read_control_structure): Handle python_control.
	(read_command_lines): Handle python_control.
	Include python.h.
	* cli/cli-script.h (get_command_line): Add prototype.
	(execute_control_command_suppressed): Likewise.
	* configure.ac: Add --with-python.
	* defs.h (enum command_control_type) <python_control>: New
	constant.
	* python/python-internal.h: New file.
	* python/python.c: New file.
	* python/python.h: New file.

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 9304bc2..09fdc34 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -254,6 +254,16 @@ SUBDIR_TUI_LDFLAGS=
 SUBDIR_TUI_CFLAGS= \
 	-DTUI=1
 
+#
+# python sub directory definitons
+#
+SUBDIR_PYTHON_OBS =
+SUBDIR_PYTHON_SRCS = \
+	python/python.c
+SUBDIR_PYTHON_DEPS =
+SUBDIR_PYTHON_LDFLAGS=
+SUBDIR_PYTHON_CFLAGS=
+
 
 # Opcodes currently live in one of two places.  Either they are in the
 # opcode library, typically ../opcodes, or they are in a header file
@@ -963,6 +973,13 @@ tui_wingeneral_h = $(srcdir)/tui/tui-wingeneral.h
 tui_win_h = $(srcdir)/tui/tui-win.h $(tui_data_h)
 tui_winsource_h = $(srcdir)/tui/tui-winsource.h $(tui_data_h)
 
+#
+# gdb/python/ headers
+#
+
+python_h = $(srcdir)/python/python.h $(value_h)
+python_internal_h = $(srcdir)/python/python-internal.h
+
 # gdb/features preparsed descriptions
 features_headers = $(defs_h) $(gdbtypes_h) $(target_descriptions_h)
 arm_with_iwmmxt_c = $(srcdir)/features/arm-with-iwmmxt.c $(features_headers)
@@ -1081,7 +1098,8 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	tramp-frame.o \
 	solib.o solib-null.o \
 	prologue-value.o memory-map.o xml-support.o \
-	target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o
+	target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
+	python.o
 
 TSOBS = inflow.o
 
@@ -1275,7 +1293,11 @@ test-cp-name-parser$(EXEEXT): test-cp-name-parser.o $(LIBIBERTY)
 # duplicates.  Files in the gdb/ directory can end up appearing in
 # COMMON_OBS (as a .o file) and CONFIG_SRCS (as a .c file).
 
-INIT_FILES = $(COMMON_OBS) $(TSOBS) $(CONFIG_SRCS)
+# NOTE: bauermann/2008-06-15: python.c needs to be explicitly included
+# because the generation of init.c does not work for .c files which
+# result in differently named objects (i.e., python/python -> python.o).
+
+INIT_FILES = $(COMMON_OBS) $(TSOBS) $(CONFIG_SRCS) python/python.c
 init.c: $(INIT_FILES)
 	@echo Making init.c
 	@rm -f init.c-tmp init.l-tmp
@@ -3051,7 +3073,8 @@ cli-logging.o: $(srcdir)/cli/cli-logging.c $(defs_h) $(gdbcmd_h) $(ui_out_h) \
 	$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/cli/cli-logging.c
 cli-script.o: $(srcdir)/cli/cli-script.c $(defs_h) $(value_h) $(language_h) \
 	$(ui_out_h) $(gdb_string_h) $(exceptions_h) $(top_h) $(cli_cmds_h) \
-	$(cli_decode_h) $(cli_script_h) $(gdb_assert_h) $(breakpoint_h)
+	$(cli_decode_h) $(cli_script_h) $(gdb_assert_h) $(breakpoint_h) \
+	$(python_h)
 	$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/cli/cli-script.c
 cli-setshow.o: $(srcdir)/cli/cli-setshow.c $(defs_h) $(readline_tilde_h) \
 	$(value_h) $(gdb_string_h) $(ui_out_h) $(cli_decode_h) $(cli_cmds_h) \
@@ -3375,4 +3398,19 @@ tui-winsource.o: $(srcdir)/tui/tui-winsource.c $(defs_h) $(symtab_h) \
 	$(gdb_curses_h) $(gdb_assert_h)
 	$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/tui/tui-winsource.c
 
+#
+# gdb/python/ dependencies
+#
+# Need to explicitly specify the compile rule as make will do nothing
+# or try to compile the object file into the sub-directory.
+
+# Flags needed to compile Python code (taken from python-config --cflags)
+PYTHON_CFLAGS=-fno-strict-aliasing -DNDEBUG -fwrapv
+
+python.o: $(srcdir)/python/python.c $(defs_h) $(python_h) \
+	$(command_h) $(libiberty_h) $(cli_decode_h) $(charset_h) $(top_h) \
+	$(exceptions_h) $(python_internal_h) $(version_h) $(cli_script_h) \
+	$(ui_out_h)
+	$(CC) -c $(INTERNAL_CFLAGS) $(PYTHON_CFLAGS) $(srcdir)/python/python.c
+
 ### end of the gdb Makefile.in.
diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
index e6fbe3f..69fd3c7 100644
--- a/gdb/cli/cli-script.c
+++ b/gdb/cli/cli-script.c
@@ -34,6 +34,8 @@
 #include "cli/cli-script.h"
 #include "gdb_assert.h"
 
+#include "python/python.h"
+
 /* Prototypes for local functions */
 
 static enum command_control_type
@@ -102,7 +104,7 @@ build_command_line (enum command_control_type type, char *args)
 /* Build and return a new command structure for the control commands
    such as "if" and "while".  */
 
-static struct command_line *
+struct command_line *
 get_command_line (enum command_control_type type, char *arg)
 {
   struct command_line *cmd;
@@ -225,6 +227,18 @@ print_command_lines (struct ui_out *uiout, struct command_line *cmd,
 	  continue;
 	}
 
+      if (list->control_type == python_control)
+	{
+	  ui_out_field_string (uiout, NULL, "python");
+	  print_command_lines (uiout, *list->body_list, depth + 1);
+	  if (depth)
+	    ui_out_spaces (uiout, 2 * depth);
+	  ui_out_field_string (uiout, NULL, "end");
+	  ui_out_text (uiout, "\n");
+	  list = list->next;
+	  continue;
+	}
+
       /* ignore illegal command type and try next */
       list = list->next;
     }				/* while (list) */
@@ -527,6 +541,12 @@ execute_control_command (struct command_line *cmd)
 	ret = commands_from_control_command (new_line, cmd);
 	break;
       }
+    case python_control:
+      {
+	eval_python_from_control_command (cmd);
+	ret = simple_control;
+	break;
+      }
 
     default:
       warning (_("Invalid control type in canned commands structure."));
@@ -538,6 +558,17 @@ execute_control_command (struct command_line *cmd)
   return ret;
 }
 
+/* Like execute_control_command, but first set
+   suppress_next_print_command_trace.   */
+
+enum command_control_type
+execute_control_command_suppressed (struct command_line *cmd)
+{
+  suppress_next_print_command_trace = 1;
+  return execute_control_command (cmd);
+}
+
+
 /* "while" command support.  Executes a body of statements while the
    loop condition is nonzero.  */
 
@@ -552,8 +583,7 @@ while_command (char *arg, int from_tty)
   if (command == NULL)
     return;
 
-  suppress_next_print_command_trace = 1;
-  execute_control_command (command);
+  execute_control_command_suppressed (command);
   free_command_lines (&command);
 }
 
@@ -571,8 +601,7 @@ if_command (char *arg, int from_tty)
   if (command == NULL)
     return;
 
-  suppress_next_print_command_trace = 1;
-  execute_control_command (command);
+  execute_control_command_suppressed (command);
   free_command_lines (&command);
 }
 
@@ -886,6 +915,12 @@ read_next_line (struct command_line **command)
         first_arg++;
       *command = build_command_line (commands_control, first_arg);
     }
+  else if (p1 - p == 6 && !strncmp (p, "python", 6))
+    {
+      /* Note that we ignore the inline "python command" form
+	 here.  */
+      *command = build_command_line (python_control, "");
+    }
   else if (p1 - p == 10 && !strncmp (p, "loop_break", 10))
     {
       *command = (struct command_line *)
@@ -962,6 +997,7 @@ recurse_read_control_structure (struct command_line *current_cmd)
 	{
 	  if (current_cmd->control_type == while_control
 	      || current_cmd->control_type == if_control
+	      || current_cmd->control_type == python_control
 	      || current_cmd->control_type == commands_control)
 	    {
 	      /* Success reading an entire canned sequence of commands.  */
@@ -1013,6 +1049,7 @@ recurse_read_control_structure (struct command_line *current_cmd)
          on it.  */
       if (next->control_type == while_control
 	  || next->control_type == if_control
+	  || next->control_type == python_control
 	  || next->control_type == commands_control)
 	{
 	  control_level++;
@@ -1086,6 +1123,7 @@ read_command_lines (char *prompt_arg, int from_tty)
 
       if (next->control_type == while_control
 	  || next->control_type == if_control
+	  || next->control_type == python_control
 	  || next->control_type == commands_control)
 	{
 	  control_level++;
diff --git a/gdb/cli/cli-script.h b/gdb/cli/cli-script.h
index 42663dd..7416e1c 100644
--- a/gdb/cli/cli-script.h
+++ b/gdb/cli/cli-script.h
@@ -40,6 +40,12 @@ extern void show_user_1 (struct cmd_list_element *c, struct ui_file *stream);
 extern enum command_control_type
 	execute_control_command (struct command_line *cmd);
 
+extern enum command_control_type
+	execute_control_command_suppressed (struct command_line *cmd);
+
+extern struct command_line *get_command_line (enum command_control_type,
+					      char *);
+
 extern void print_command_lines (struct ui_out *,
 				 struct command_line *, unsigned int);
 
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 101dedf..0adc9fd 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -485,6 +485,99 @@ else
   fi
 fi
 
+dnl Utility to simplify finding libpython.
+AC_DEFUN([AC_TRY_LIBPYTHON],
+[
+  version=$1
+  define([have_libpython_var],$2)
+  define([VERSION],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+                                  [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+  [HAVE_LIB]VERSION=no
+  AC_MSG_CHECKING([for ${version}])
+  save_LIBS=$LIBS
+  LIBS="$LIBS -l${version}"
+  AC_LINK_IFELSE(AC_LANG_PROGRAM([[#include "${version}/Python.h"]],
+                                 [[Py_Initialize ();]]),
+                 [[HAVE_LIB]VERSION=yes
+                  have_libpython_var=yes],
+                 [LIBS=$save_LIBS])
+  AC_MSG_RESULT([$[HAVE_LIB]VERSION])
+])
+
+AC_ARG_WITH(python,
+  AS_HELP_STRING([--with-python], [include python support (auto/yes/no/<path>)]),
+  [], [with_python=auto])
+AC_MSG_CHECKING([whether to use python])
+AC_MSG_RESULT([$with_python])
+
+if test "${with_python}" = no; then
+  AC_MSG_WARN([python support disabled; some features may be unavailable.])
+  have_libpython=no
+else
+  case "${with_python}" in
+  yes | auto)
+    # Leave as empty, use defaults.
+    python_includes=
+    python_libs=
+    ;;
+  /*)
+    python_includes="-I${with_python}/include"
+    python_libs="-L${with_python}/lib"
+    ;;
+  *)
+    AC_ERROR(invalid value for --with-python)
+    ;;
+  esac
+
+  save_CPPFLAGS=$CPPFLAGS
+  CPPFLAGS="$CPPFLAGS ${python_includes}"
+  save_LIBS=$LIBS
+  LIBS="$LIBS ${python_libs}"
+  have_libpython=no
+  if test "${have_libpython}" = no; then
+    AC_TRY_LIBPYTHON(python2.6, have_libpython)
+    if test "${HAVE_LIBPYTHON2_6}" = yes; then
+      AC_DEFINE(HAVE_LIBPYTHON2_6, 1, [Define if Python 2.6 is being used.])
+    fi
+  fi
+  if test ${have_libpython} = no; then
+    AC_TRY_LIBPYTHON(python2.5, have_libpython)
+    if test "${HAVE_LIBPYTHON2_5}" = yes; then
+      AC_DEFINE(HAVE_LIBPYTHON2_5, 1, [Define if Python 2.5 is being used.])
+    fi
+  fi
+  if test ${have_libpython} = no; then
+    AC_TRY_LIBPYTHON(python2.4, have_libpython)
+    if test "${HAVE_LIBPYTHON2_4}" = yes; then
+      AC_DEFINE(HAVE_LIBPYTHON2_4, 1, [Define if Python 2.4 is being used.])
+    fi
+  fi
+  if test ${have_libpython} = no; then
+    case "${with_python}" in
+    yes)
+      AC_MSG_ERROR([python is missing or unusable])
+      ;;
+    auto)
+      AC_MSG_WARN([python is missing or unusable; some features may be unavailable.])
+      ;;
+    *)
+      AC_MSG_ERROR([no usable python found at ${with_python}])
+      ;;
+    esac
+    CPPFLAGS=$save_CPPFLAGS
+    LIBS=$save_LIBS
+  fi
+fi
+
+if test "${have_libpython}" = yes; then
+  AC_DEFINE(HAVE_PYTHON, 1, [Define if Python interpreter is being linked in.])
+  CONFIG_OBS="$CONFIG_OBS \$(SUBDIR_PYTHON_OBS)"
+  CONFIG_DEPS="$CONFIG_DEPS \$(SUBDIR_PYTHON_DEPS)"
+  CONFIG_SRCS="$CONFIG_SRCS \$(SUBDIR_PYTHON_SRCS)"
+  CONFIG_INITS="$CONFIG_INITS \$(SUBDIR_PYTHON_INITS)"
+  ENABLE_CFLAGS="$ENABLE_CFLAGS \$(SUBDIR_PYTHON_CFLAGS)"
+fi
+
 # ------------------------- #
 # Checks for header files.  #
 # ------------------------- #
diff --git a/gdb/defs.h b/gdb/defs.h
index 2af40ab..98d3f7c 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -642,6 +642,7 @@ enum command_control_type
     while_control,
     if_control,
     commands_control,
+    python_control,
     invalid_control
   };
 
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
new file mode 100644
index 0000000..d39724c
--- /dev/null
+++ b/gdb/python/python-internal.h
@@ -0,0 +1,60 @@
+/* Gdb/Python header for private use by Python module.
+
+   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/>.  */
+
+#ifndef GDB_PYTHON_INTERNAL_H
+#define GDB_PYTHON_INTERNAL_H
+
+/* Python 2.4 doesn't include stdint.h soon enough to get {u,}intptr_t
+   needed by pyport.h.  */
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+/* /usr/include/features.h on linux systems will define _POSIX_C_SOURCE
+   if it sees _GNU_SOURCE (which config.h will define).
+   pyconfig.h defines _POSIX_C_SOURCE to a different value than
+   /usr/include/features.h does causing compilation to fail.
+   To work around this, undef _POSIX_C_SOURCE before we include Python.h.  */
+#undef _POSIX_C_SOURCE
+
+#if HAVE_LIBPYTHON2_4
+#include "python2.4/Python.h"
+/* Py_ssize_t is not defined until 2.5.  */
+typedef Py_intptr_t Py_ssize_t;
+#elif HAVE_LIBPYTHON2_5
+#include "python2.5/Python.h"
+#elif HAVE_LIBPYTHON2_6
+#include "python2.6/Python.h"
+#else
+#error "Unable to find usable Python.h"
+#endif
+
+extern PyObject *gdb_module;
+
+/* Use this after a TRY_EXCEPT to throw the appropriate Python
+   exception.  */
+#define GDB_PY_HANDLE_EXCEPTION(Exception)				\
+    do {								\
+      if (Exception.reason < 0)						\
+	return PyErr_Format (Exception.reason == RETURN_QUIT		\
+			     ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, \
+			     "%s", Exception.message);			\
+    } while (0)
+
+#endif /* GDB_PYTHON_INTERNAL_H */
diff --git a/gdb/python/python.c b/gdb/python/python.c
new file mode 100644
index 0000000..89e136c
--- /dev/null
+++ b/gdb/python/python.c
@@ -0,0 +1,324 @@
+/* General python/gdb code
+
+   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 "command.h"
+#include "ui-out.h"
+#include "cli/cli-script.h"
+
+#include <ctype.h>
+
+#ifdef HAVE_PYTHON
+
+#include "python.h"
+#include "libiberty.h"
+#include "cli/cli-decode.h"
+#include "charset.h"
+#include "top.h"
+#include "exceptions.h"
+#include "python-internal.h"
+#include "version.h"
+
+
+PyObject *gdb_module;
+
+static PyObject *get_show_variable (PyObject *, PyObject *);
+static PyObject *execute_gdb_command (PyObject *, PyObject *);
+
+static PyMethodDef GdbMethods[] =
+{
+  { "execute", execute_gdb_command, METH_VARARGS,
+    "Execute a gdb command" },
+  { "show", get_show_variable, METH_VARARGS,
+    "Return a gdb setting's value" },
+
+  {NULL, NULL, 0, NULL}
+};
+
+/* Given a command_line, return a command string suitable for passing
+   to Python.  Lines in the string are separated by newlines.  The
+   return value is allocated using xmalloc and the caller is
+   responsible for freeing it.  */
+
+static char *
+compute_python_string (struct command_line *l)
+{
+  struct command_line *iter;
+  char *script = NULL;
+  int size = 0;
+  int here;
+
+  for (iter = l; iter; iter = iter->next)
+    size += strlen (iter->line) + 1;
+
+  script = xmalloc (size + 1);
+  here = 0;
+  for (iter = l; iter; iter = iter->next)
+    {
+      int len = strlen (iter->line) + 1;
+      strcpy (&script[here], iter->line);
+      here += len;
+      script[here++] = '\n';
+    }
+  script[here] = '\0';
+  return script;
+}
+
+void
+eval_python_from_control_command (struct command_line *cmd)
+{
+  char *script;
+
+  if (cmd->body_count != 1)
+    error (_("Invalid \"python\" block structure."));
+
+  script = compute_python_string (cmd->body_list[0]);
+  PyRun_SimpleString (script);
+  xfree (script);
+  if (PyErr_Occurred ())
+    {
+      PyErr_Print ();
+      error (_("error while executing Python code"));
+    }
+}
+
+/* Implementation of the gdb "python" command.  */
+
+static void
+python_command (char *arg, int from_tty)
+{
+  while (arg && *arg && isspace (*arg))
+    ++arg;
+  if (arg && *arg)
+    {
+      PyRun_SimpleString (arg);
+      if (PyErr_Occurred ())
+	{
+	  PyErr_Print ();
+	  error (_("error while executing Python code"));
+	}
+    }
+  else
+    {
+      char *tmpbuf = xstrprintf ("Type python script");
+      struct cleanup *cleanups = make_cleanup (xfree, tmpbuf);
+      struct command_line *l = get_command_line (python_control, "");
+      cleanups = make_cleanup_free_command_lines (&l);
+      execute_control_command_suppressed (l);
+      do_cleanups (cleanups);
+    }
+}
+
+
+
+/* Transform a gdb variable's value into a Python value.  May return
+   NULL (and set a Python exception) on error.  Helper function for
+   get_show_variable.  */
+
+static PyObject *
+variable_to_python (struct cmd_list_element *cmd)
+{
+  switch (cmd->var_type)
+    {
+    case var_string:
+    case var_string_noescape:
+    case var_optional_filename:
+    case var_filename:
+    case var_enum:
+      {
+	char *str = * (char **) cmd->var;
+	if (! str)
+	  str = "";
+	return PyString_Decode (str, strlen (str), host_charset (), NULL);
+      }
+
+    case var_boolean:
+      {
+	if (* (int *) cmd->var)
+	  Py_RETURN_TRUE;
+	else
+	  Py_RETURN_FALSE;
+      }
+
+    case var_auto_boolean:
+      {
+	enum auto_boolean ab = * (enum auto_boolean *) cmd->var;
+	if (ab == AUTO_BOOLEAN_TRUE)
+	  Py_RETURN_TRUE;
+	else if (ab == AUTO_BOOLEAN_FALSE)
+	  Py_RETURN_FALSE;
+	else
+	  Py_RETURN_NONE;
+      }
+
+    case var_integer:
+      if ((* (int *) cmd->var) == INT_MAX)
+	Py_RETURN_NONE;
+      /* Fall through.  */
+    case var_zinteger:
+      return PyLong_FromLong (* (int *) cmd->var);
+
+    case var_uinteger:
+      {
+	unsigned int val = * (unsigned int *) cmd->var;
+	if (val == UINT_MAX)
+	  Py_RETURN_NONE;
+	return PyLong_FromUnsignedLong (val);
+      }
+    }
+
+  return PyErr_Format (PyExc_RuntimeError, "programmer error: unhandled type");
+}
+
+/* A Python function which returns a gdb variable's value as a Python
+   value.  */
+
+static PyObject *
+get_show_variable (PyObject *self, PyObject *args)
+{
+  struct cmd_list_element *alias, *prefix, *cmd;
+  char *arg, *newarg;
+  volatile struct gdb_exception except;
+
+  if (! PyArg_ParseTuple (args, "s", &arg))
+    return NULL;
+
+  newarg = concat ("show ", arg, (char *) NULL);
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      if (! lookup_cmd_composition (newarg, &alias, &prefix, &cmd))
+	{
+	  xfree (newarg);
+	  return PyErr_Format (PyExc_RuntimeError,
+			       "could not find variable `%s'", arg);
+	}
+    }
+  xfree (newarg);
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  if (! cmd->var)
+    return PyErr_Format (PyExc_RuntimeError, "`%s' is not a variable", arg);
+  return variable_to_python (cmd);
+}
+
+/* A Python function which evaluates a string using the gdb CLI.  */
+
+static PyObject *
+execute_gdb_command (PyObject *self, PyObject *args)
+{
+  struct cmd_list_element *alias, *prefix, *cmd;
+  char *arg, *newarg;
+  volatile struct gdb_exception except;
+  struct cleanup *old_chain;
+
+  if (! PyArg_ParseTuple (args, "s", &arg))
+    return NULL;
+
+  old_chain = make_cleanup (null_cleanup, 0);
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      execute_command (arg, 0);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
+
+  /* Do any commands attached to breakpoint we stopped at. Only if we
+     are always running synchronously. Or if we have just executed a
+     command that doesn't start the target. */
+  if (!target_can_async_p () || !target_executing)
+    {
+      bpstat_do_actions (&stop_bpstat);
+      do_cleanups (old_chain);
+    }
+
+  Py_RETURN_NONE;
+}
+
+
+
+/* Initialize the Python code.  */
+
+void
+_initialize_python (void)
+{
+  add_com ("python", class_obscure, python_command, _("\
+Evaluate a Python command.\n\
+\n\
+The command can be given as an argument, for instance:\n\
+\n\
+    python print 23\n\
+\n\
+If no argument is given, the following lines are read and used\n\
+as the Python commands.  Type a line containing \"end\" to indicate\n\
+the end of the command."));
+
+  Py_Initialize ();
+
+  gdb_module = Py_InitModule ("gdb", GdbMethods);
+
+  /* The casts to (char*) are for python 2.4.  */
+  PyModule_AddStringConstant (gdb_module, "VERSION", (char*) version);
+  PyModule_AddStringConstant (gdb_module, "HOST_CONFIG", (char*) host_name);
+  PyModule_AddStringConstant (gdb_module, "TARGET_CONFIG", (char*) target_name);
+
+  PyRun_SimpleString ("import gdb");
+}
+
+#else /* HAVE_PYTHON */
+
+/* Dummy implementation of the gdb "python" command.  */
+
+static void
+python_command (char *arg, int from_tty)
+{
+  while (arg && *arg && isspace (*arg))
+    ++arg;
+  if (arg && *arg)
+    error (_("Python scripting is not supported in this copy of GDB."));
+  else
+    {
+      char *tmpbuf = xstrprintf ("Type python script");
+      struct cleanup *cleanups = make_cleanup (xfree, tmpbuf);
+      struct command_line *l = get_command_line (python_control, "");
+      cleanups = make_cleanup_free_command_lines (&l);
+      execute_control_command_suppressed (l);
+      do_cleanups (cleanups);
+    }
+}
+
+void
+eval_python_from_control_command (struct command_line *cmd)
+{
+  error (_("Python scripting is not supported in this copy of GDB."));
+}
+
+/* Initialize dummy Python code.  */
+
+void
+_initialize_python (void)
+{
+  add_com ("python", class_obscure, python_command, _("\
+Evaluate a Python command.\n\
+\n\
+Python scripting is not supported in this copy of GDB.\n\
+This command is only a placeholder."));
+}
+
+#endif /* HAVE_PYTHON */
diff --git a/gdb/python/python.h b/gdb/python/python.h
new file mode 100644
index 0000000..00ff159
--- /dev/null
+++ b/gdb/python/python.h
@@ -0,0 +1,27 @@
+/* Python/gdb header for generic use in gdb
+
+   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/>.  */
+
+#ifndef GDB_PYTHON_H
+#define GDB_PYTHON_H
+
+#include "value.h"
+
+void eval_python_from_control_command (struct command_line *);
+
+#endif /* GDB_PYTHON_H */

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