diff options
author | Thiago Jung Bauermann <bauerman@br.ibm.com> | 2008-08-06 19:41:33 +0000 |
---|---|---|
committer | Thiago Jung Bauermann <bauerman@br.ibm.com> | 2008-08-06 19:41:33 +0000 |
commit | d57a3c85f6eee87b04852e98cce75af080969951 (patch) | |
tree | 6758be339bdf45930c2d61e4d447ce308bb82ec5 /gdb/python | |
parent | 5141027dd033490b4866bea973206985b8a0cab4 (diff) | |
download | gdb-d57a3c85f6eee87b04852e98cce75af080969951.zip gdb-d57a3c85f6eee87b04852e98cce75af080969951.tar.gz gdb-d57a3c85f6eee87b04852e98cce75af080969951.tar.bz2 |
Initial python support.
gdb/
2008-08-06 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.
(cli-script.o): Depend on python.h
(python.o, python-utils.o): New.
* cli/cli-script.c (print_command_lines): Handle python_control.
(execute_control_command): Handle python_control.
(execute_control_command_untraced): New function.
(while_command): Call execute_control_command_untraced.
(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_untraced): 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.
* python/python-utils.c: New file.
* NEWS: Mention Python scripting support and its new commands.
gdb/doc/
2008-08-06 Tom Tromey <tromey@redhat.com>
* gdb.texinfo (Extending GDB): New chapter.
(Sequences): Demoted chapter, now a section under the new
Extending GDB chapter.
(Python): New section.
gdb/testsuite/
2008-08-06 Tom Tromey <tromey@redhat.com>
* gdb.python/python.exp: New file.
Diffstat (limited to 'gdb/python')
-rw-r--r-- | gdb/python/python-internal.h | 71 | ||||
-rw-r--r-- | gdb/python/python-utils.c | 117 | ||||
-rw-r--r-- | gdb/python/python.c | 438 | ||||
-rw-r--r-- | gdb/python/python.h | 27 |
4 files changed, 653 insertions, 0 deletions
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h new file mode 100644 index 0000000..f850448 --- /dev/null +++ b/gdb/python/python-internal.h @@ -0,0 +1,71 @@ +/* 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. */ +#include <stdint.h> + +/* /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 + +struct block; +struct symbol; +struct symtab_and_line; + +extern PyObject *gdb_module; + +struct cleanup *make_cleanup_py_decref (PyObject *py); + +/* 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) + + +void gdbpy_print_stack (void); + +PyObject *python_string_to_unicode (PyObject *obj); +char *unicode_to_target_string (PyObject *unicode_str); +char *python_string_to_target_string (PyObject *obj); + +#endif /* GDB_PYTHON_INTERNAL_H */ diff --git a/gdb/python/python-utils.c b/gdb/python/python-utils.c new file mode 100644 index 0000000..912845f --- /dev/null +++ b/gdb/python/python-utils.c @@ -0,0 +1,117 @@ +/* General utility routines for GDB/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 "charset.h" +#include "python-internal.h" + + +/* This is a cleanup function which decrements the refcount on a + Python object. */ + +static void +py_decref (void *p) +{ + PyObject *py = p; + /* Note that we need the extra braces in this 'if' to avoid a + warning from gcc. */ + if (py) + { + Py_DECREF (py); + } +} + +/* Return a new cleanup which will decrement the Python object's + refcount when run. */ + +struct cleanup * +make_cleanup_py_decref (PyObject *py) +{ + return make_cleanup (py_decref, (void *) py); +} + +/* Converts a Python 8-bit string to a unicode string object. Assumes the + 8-bit string is in the host charset. If an error occurs during conversion, + returns NULL with a python exception set. + + As an added bonus, the functions accepts a unicode string and returns it + right away, so callers don't need to check which kind of string they've + got. + + If the given object is not one of the mentioned string types, NULL is + returned, with the TypeError python exception set. */ +PyObject * +python_string_to_unicode (PyObject *obj) +{ + PyObject *unicode_str; + + /* If obj is already a unicode string, just return it. + I wish life was always that simple... */ + if (PyUnicode_Check (obj)) + unicode_str = obj; + else if (PyString_Check (obj)) + unicode_str = PyUnicode_FromEncodedObject (obj, host_charset (), NULL); + else + { + PyErr_SetString (PyExc_TypeError, + _("Expected a string or unicode object.")); + unicode_str = NULL; + } + + return unicode_str; +} + +/* Returns a newly allocated string with the contents of the given unicode + string object converted to the target's charset. If an error occurs during + the conversion, NULL will be returned and a python exception will be set. + + The caller is responsible for xfree'ing the string. */ +char * +unicode_to_target_string (PyObject *unicode_str) +{ + char *target_string; + PyObject *string; + + /* Translate string to target's charset. */ + string = PyUnicode_AsEncodedString (unicode_str, target_charset (), NULL); + if (string == NULL) + return NULL; + + target_string = xstrdup (PyString_AsString (string)); + + Py_DECREF (string); + + return target_string; +} + +/* Converts a python string (8-bit or unicode) to a target string in + the target's charset. Returns NULL on error, with a python exception set. + + The caller is responsible for xfree'ing the string. */ +char * +python_string_to_target_string (PyObject *obj) +{ + PyObject *str; + + str = python_string_to_unicode (obj); + if (str == NULL) + return NULL; + + return unicode_to_target_string (str); +} diff --git a/gdb/python/python.c b/gdb/python/python.c new file mode 100644 index 0000000..a560290 --- /dev/null +++ b/gdb/python/python.c @@ -0,0 +1,438 @@ +/* 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 "gdbcmd.h" + +#include <ctype.h> + +/* True if we should print the stack when catching a Python error, + false otherwise. */ +static int gdbpy_should_print_stack = 1; + +#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" +#include "target.h" +#include "gdbthread.h" + + +PyObject *gdb_module; + +static PyObject *get_parameter (PyObject *, PyObject *); +static PyObject *execute_gdb_command (PyObject *, PyObject *); +static PyObject *gdbpy_write (PyObject *, PyObject *); +static PyObject *gdbpy_flush (PyObject *, PyObject *); + +static PyMethodDef GdbMethods[] = +{ + { "execute", execute_gdb_command, METH_VARARGS, + "Execute a gdb command" }, + { "get_parameter", get_parameter, METH_VARARGS, + "Return a gdb parameter's value" }, + + { "write", gdbpy_write, METH_VARARGS, + "Write a string using gdb's filtered stream." }, + { "flush", gdbpy_flush, METH_NOARGS, + "Flush gdb's filtered stdout stream." }, + + {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); + strcpy (&script[here], iter->line); + here += len; + script[here++] = '\n'; + } + script[here] = '\0'; + return script; +} + +/* Take a command line structure representing a 'python' command, and + evaluate its body using the Python interpreter. */ + +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 ()) + { + gdbpy_print_stack (); + 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 ()) + { + gdbpy_print_stack (); + error (_("error while executing Python code")); + } + } + else + { + struct command_line *l = get_command_line (python_control, ""); + struct cleanup *cleanups = make_cleanup_free_command_lines (&l); + execute_control_command_untraced (l); + do_cleanups (cleanups); + } +} + + + +/* Transform a gdb parameters's value into a Python value. May return + NULL (and set a Python exception) on error. Helper function for + get_parameter. */ + +static PyObject * +parameter_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 parameter's value as a Python + value. */ + +static PyObject * +get_parameter (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 parameter_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 () || !is_running (inferior_ptid)) + { + bpstat_do_actions (&stop_bpstat); + do_cleanups (old_chain); + } + + Py_RETURN_NONE; +} + + + +/* Printing. */ + +/* A python function to write a single string using gdb's filtered + output stream. */ +static PyObject * +gdbpy_write (PyObject *self, PyObject *args) +{ + char *arg; + if (! PyArg_ParseTuple (args, "s", &arg)) + return NULL; + printf_filtered ("%s", arg); + Py_RETURN_NONE; +} + +/* A python function to flush gdb's filtered output stream. */ +static PyObject * +gdbpy_flush (PyObject *self, PyObject *args) +{ + gdb_flush (gdb_stdout); + Py_RETURN_NONE; +} + +/* Print a python exception trace, or print nothing and clear the + python exception, depending on gdbpy_should_print_stack. Only call + this if a python exception is set. */ +void +gdbpy_print_stack (void) +{ + if (gdbpy_should_print_stack) + PyErr_Print (); + else + PyErr_Clear (); +} + +#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 + { + struct command_line *l = get_command_line (python_control, ""); + struct cleanup *cleanups = make_cleanup_free_command_lines (&l); + execute_control_command_untraced (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.")); +} + +#endif /* HAVE_PYTHON */ + + + +/* Lists for 'maint set python' commands. */ + +static struct cmd_list_element *set_python_list; +static struct cmd_list_element *show_python_list; + +/* Function for use by 'maint set python' prefix command. */ + +static void +set_python (char *args, int from_tty) +{ + help_list (set_python_list, "maintenance set python ", -1, gdb_stdout); +} + +/* Function for use by 'maint show python' prefix command. */ + +static void +show_python (char *args, int from_tty) +{ + cmd_show_list (show_python_list, from_tty, ""); +} + +/* Initialize the Python code. */ + +void +_initialize_python (void) +{ + add_com ("python", class_obscure, python_command, +#ifdef HAVE_PYTHON + _("\ +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.") +#else /* HAVE_PYTHON */ + _("\ +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 */ + ); + + add_prefix_cmd ("python", no_class, show_python, + _("Prefix command for python maintenance settings."), + &show_python_list, "maint show python ", 0, + &maintenance_show_cmdlist); + add_prefix_cmd ("python", no_class, set_python, + _("Prefix command for python maintenance settings."), + &set_python_list, "maint set python ", 0, + &maintenance_set_cmdlist); + + add_setshow_boolean_cmd ("print-stack", class_maintenance, + &gdbpy_should_print_stack, _("\ +Enable or disable printing of Python stack dump on error."), _("\ +Show whether Python stack will be printed on error."), _("\ +Enables or disables printing of Python stack traces."), + NULL, NULL, + &set_python_list, + &show_python_list); + +#ifdef HAVE_PYTHON + 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"); + + /* Create a couple objects which are used for Python's stdout and + stderr. */ + PyRun_SimpleString ("\ +import sys\n\ +class GdbOutputFile:\n\ + def close(self):\n\ + # Do nothing.\n\ + return None\n\ +\n\ + def isatty(self):\n\ + return False\n\ +\n\ + def write(self, s):\n\ + gdb.write(s)\n\ +\n\ + def writelines(self, iterable):\n\ + for line in iterable:\n\ + self.write(line)\n\ +\n\ + def flush(self):\n\ + gdb.flush()\n\ +\n\ +sys.stderr = GdbOutputFile()\n\ +sys.stdout = GdbOutputFile()\n\ +"); +#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 */ |