From: Joel Brobecker Date: Wed, 9 Sep 2009 17:45:42 +0000 (+0000) Subject: Checking in this patch for Thiago: Rename python-* files into py-*, X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=5172aecbd2b65e71aedbd21c46253ca6a20227aa;p=binutils-gdb.git Checking in this patch for Thiago: Rename python-* files into py-*, more 8+3 friendly. gdb/ * Makefile.in (py-cmd.o): Renamed from python-cmd.o. Updated references. (py-frame.o): Renamed from python-frame.o. Updated references. (py-function.o): Renamed from python-function.o. Updated references. (py-objfile.o): Renamed from python-objfile.o. Updated references. (py-prettyprint.o): Renamed from python-prettyprint.o. Updated +references. (py-type.o): Renamed from python-type.o. Updated references. (py-utils.o): Renamed from python-utils.o. Updated references. (py-value.o): Renamed from python-value.o. Updated references. * py-cmd.o: Renamed from python-cmd.o. * py-frame.o: Renamed from python-frame.o. * py-function.o: Renamed from python-function.o. * py-objfile.o: Renamed from python-objfile.o. * py-prettyprint.o: Renamed from python-prettyprint.o. * py-type.o: Renamed from python-type.o. * py-utils.o: Renamed from python-utils.o. * py-value.o: Renamed from python-value.o. gdb/testsuite/ * gdb.python/Makefile.in (EXECUTABLES): Adjust to new executable names, add missing ones. * gdb.python/py-cmd.exp: Rename from python-cmd.exp. * gdb.python/py-frame.c: Rename from python-frame.c. * gdb.python/py-frame.exp: Rename from python-frame.exp. Adjust testfile name. * gdb.python/py-function.exp: Rename from python-function.exp. * gdb.python/py-mi.exp: Rename from python-mi.exp. Adjust testfile name. * gdb.python/py-prettyprint.c: Rename from python-prettyprint.c. * gdb.python/py-prettyprint.exp: Rename from python-prettyprint.exp. Adjust testfile name. * gdb.python/py-prettyprint.py: Rename from python-prettyprint.py. * gdb.python/py-template.cc: Rename from python-template.cc. * gdb.python/py-template.exp: Rename from python-template.exp. Adjust testfile name. * gdb.python/py-value.c: Rename from python-value.c. * gdb.python/py-value.exp: Rename from python-value.exp. Adjust testfile name. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 52d87232916..82d6704f5b7 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,24 @@ +2009-09-08 Thiago Jung Bauermann + + * Makefile.in (py-cmd.o): Renamed from python-cmd.o. Updated + references. + (py-frame.o): Renamed from python-frame.o. Updated references. + (py-function.o): Renamed from python-function.o. Updated references. + (py-objfile.o): Renamed from python-objfile.o. Updated references. + (py-prettyprint.o): Renamed from python-prettyprint.o. Updated + references. + (py-type.o): Renamed from python-type.o. Updated references. + (py-utils.o): Renamed from python-utils.o. Updated references. + (py-value.o): Renamed from python-value.o. Updated references. + * py-cmd.c: Renamed from python-cmd.c. + * py-frame.c: Renamed from python-frame.c. + * py-function.c: Renamed from python-function.c. + * py-objfile.c: Renamed from python-objfile.c. + * py-prettyprint.c: Renamed from python-prettyprint.c. + * py-type.c: Renamed from python-type.c. + * py-utils.c: Renamed from python-utils.c. + * py-value.c: Renamed from python-value.c. + 2009-09-08 Joel Brobecker Avoid quadratic behavior when computing the value of a register. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 7bc02cd8b1d..7f2fe5889c3 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -264,24 +264,24 @@ SUBDIR_TUI_CFLAGS= \ # SUBDIR_PYTHON_OBS = \ python.o \ - python-cmd.o \ - python-frame.o \ - python-function.o \ - python-objfile.o \ - python-prettyprint.o \ - python-type.o \ - python-utils.o \ - python-value.o + py-cmd.o \ + py-frame.o \ + py-function.o \ + py-objfile.o \ + py-prettyprint.o \ + py-type.o \ + py-utils.o \ + py-value.o SUBDIR_PYTHON_SRCS = \ python/python.c \ - python/python-cmd.c \ - python/python-frame.c \ - python/python-function.c \ - python/python-objfile.c \ - python/python-prettyprint.c \ - python/python-type.c \ - python/python-utils.c \ - python/python-value.c + python/py-cmd.c \ + python/py-frame.c \ + python/py-function.c \ + python/py-objfile.c \ + python/py-prettyprint.c \ + python/py-type.c \ + python/py-utils.c \ + python/py-value.c SUBDIR_PYTHON_DEPS = SUBDIR_PYTHON_LDFLAGS= SUBDIR_PYTHON_CFLAGS= @@ -1920,36 +1920,36 @@ python.o: $(srcdir)/python/python.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python.c $(POSTCOMPILE) -python-cmd.o: $(srcdir)/python/python-cmd.c - $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-cmd.c +py-cmd.o: $(srcdir)/python/py-cmd.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-cmd.c $(POSTCOMPILE) -python-frame.o: $(srcdir)/python/python-frame.c - $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-frame.c +py-frame.o: $(srcdir)/python/py-frame.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-frame.c $(POSTCOMPILE) -python-function.o: $(srcdir)/python/python-function.c - $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-function.c +py-function.o: $(srcdir)/python/py-function.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-function.c $(POSTCOMPILE) -python-objfile.o: $(srcdir)/python/python-objfile.c - $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-objfile.c +py-objfile.o: $(srcdir)/python/py-objfile.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-objfile.c $(POSTCOMPILE) -python-prettyprint.o: $(srcdir)/python/python-prettyprint.c - $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-prettyprint.c +py-prettyprint.o: $(srcdir)/python/py-prettyprint.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-prettyprint.c $(POSTCOMPILE) -python-type.o: $(srcdir)/python/python-type.c - $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-type.c +py-type.o: $(srcdir)/python/py-type.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-type.c $(POSTCOMPILE) -python-utils.o: $(srcdir)/python/python-utils.c - $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-utils.c +py-utils.o: $(srcdir)/python/py-utils.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-utils.c $(POSTCOMPILE) -python-value.o: $(srcdir)/python/python-value.c - $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-value.c +py-value.o: $(srcdir)/python/py-value.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-value.c $(POSTCOMPILE) # diff --git a/gdb/python/py-cmd.c b/gdb/python/py-cmd.c new file mode 100644 index 00000000000..528aca6ffda --- /dev/null +++ b/gdb/python/py-cmd.c @@ -0,0 +1,585 @@ +/* gdb commands implemented in Python + + Copyright (C) 2008, 2009 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 . */ + + +#include "defs.h" +#include "arch-utils.h" +#include "value.h" +#include "exceptions.h" +#include "python-internal.h" +#include "charset.h" +#include "gdbcmd.h" +#include "cli/cli-decode.h" +#include "completer.h" +#include "language.h" + +/* Struct representing built-in completion types. */ +struct cmdpy_completer +{ + /* Python symbol name. */ + char *name; + /* Completion function. */ + char **(*completer) (struct cmd_list_element *, char *, char *); +}; + +static struct cmdpy_completer completers[] = +{ + { "COMPLETE_NONE", noop_completer }, + { "COMPLETE_FILENAME", filename_completer }, + { "COMPLETE_LOCATION", location_completer }, + { "COMPLETE_COMMAND", command_completer }, + { "COMPLETE_SYMBOL", make_symbol_completion_list_fn }, +}; + +#define N_COMPLETERS (sizeof (completers) / sizeof (completers[0])) + +/* 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. */ + struct cmd_list_element *command; + + /* A prefix command requires storage for a list of its sub-commands. + A pointer to this is passed to add_prefix_command, and to add_cmd + for sub-commands of that prefix. If this Command is not a prefix + command, then this field is unused. */ + struct cmd_list_element *sub_list; +}; + +typedef struct cmdpy_object cmdpy_object; + +static PyTypeObject cmdpy_object_type; + + +/* Constants used by this module. */ +static PyObject *invoke_cst; +static PyObject *complete_cst; + + + +/* Python function which wraps dont_repeat. */ +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) +{ + cmdpy_object *cmd; + struct cleanup *cleanup; + + cleanup = ensure_python_env (get_current_arch (), current_language); + + /* Release our hold on the command object. */ + cmd = (cmdpy_object *) context; + cmd->command = NULL; + Py_DECREF (cmd); + + /* We allocated the name, doc string, and perhaps the prefix + name. */ + xfree (self->name); + xfree (self->doc); + xfree (self->prefixname); + + do_cleanups (cleanup); +} + +/* 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 *argobj, *ttyobj, *result; + struct cleanup *cleanup; + + cleanup = ensure_python_env (get_current_arch (), current_language); + + if (! obj) + error (_("Invalid invocation of Python command object.")); + if (! PyObject_HasAttr ((PyObject *) obj, invoke_cst)) + { + if (obj->command->prefixname) + { + /* A prefix command does not need an invoke method. */ + do_cleanups (cleanup); + return; + } + error (_("Python command object missing 'invoke' method.")); + } + + if (! args) + args = ""; + argobj = PyUnicode_Decode (args, strlen (args), host_charset (), NULL); + if (! argobj) + error (_("Could not convert arguments to Python string.")); + + ttyobj = from_tty ? Py_True : Py_False; + Py_INCREF (ttyobj); + result = PyObject_CallMethodObjArgs ((PyObject *) obj, invoke_cst, argobj, + ttyobj, NULL); + Py_DECREF (argobj); + Py_DECREF (ttyobj); + if (! result) + { + PyObject *ptype, *pvalue, *ptraceback; + char *s, *str; + + PyErr_Fetch (&ptype, &pvalue, &ptraceback); + + if (pvalue && PyString_Check (pvalue)) + { + /* Make a temporary copy of the string data. */ + char *s = PyString_AsString (pvalue); + char *copy = alloca (strlen (s) + 1); + strcpy (copy, s); + + PyErr_Restore (ptype, pvalue, ptraceback); + gdbpy_print_stack (); + error (_("Error occurred in Python command: %s"), copy); + } + else + { + PyErr_Restore (ptype, pvalue, ptraceback); + gdbpy_print_stack (); + error (_("Error occurred in Python command.")); + } + } + Py_DECREF (result); + do_cleanups (cleanup); +} + +/* Called by gdb for command completion. */ +static char ** +cmdpy_completer (struct cmd_list_element *command, char *text, char *word) +{ + cmdpy_object *obj = (cmdpy_object *) get_cmd_context (command); + PyObject *textobj, *wordobj, *resultobj = NULL; + char **result = NULL; + struct cleanup *cleanup; + + cleanup = ensure_python_env (get_current_arch (), current_language); + + if (! obj) + error (_("Invalid invocation of Python command object.")); + if (! PyObject_HasAttr ((PyObject *) obj, complete_cst)) + { + /* If there is no complete method, don't error -- instead, just + say that there are no completions. */ + goto done; + } + + textobj = PyUnicode_Decode (text, strlen (text), host_charset (), NULL); + if (! textobj) + error (_("Could not convert argument to Python string.")); + wordobj = PyUnicode_Decode (word, strlen (word), host_charset (), NULL); + if (! wordobj) + error (_("Could not convert argument to Python string.")); + + resultobj = PyObject_CallMethodObjArgs ((PyObject *) obj, complete_cst, + textobj, wordobj, NULL); + Py_DECREF (textobj); + Py_DECREF (wordobj); + if (! resultobj) + { + /* Just swallow errors here. */ + PyErr_Clear (); + goto done; + } + make_cleanup_py_decref (resultobj); + + result = NULL; + if (PySequence_Check (resultobj)) + { + Py_ssize_t i, len = PySequence_Size (resultobj); + Py_ssize_t out; + if (len < 0) + goto done; + + result = (char **) xmalloc ((len + 1) * sizeof (char *)); + for (i = out = 0; i < len; ++i) + { + int l; + PyObject *elt = PySequence_GetItem (resultobj, i); + if (elt == NULL || ! gdbpy_is_string (elt)) + { + /* Skip problem elements. */ + PyErr_Clear (); + continue; + } + result[out] = python_string_to_host_string (elt); + ++out; + } + result[out] = NULL; + } + else if (PyInt_Check (resultobj)) + { + /* User code may also return one of the completion constants, + thus requesting that sort of completion. */ + long value = PyInt_AsLong (resultobj); + if (value >= 0 && value < (long) N_COMPLETERS) + result = completers[value].completer (command, text, word); + } + + done: + + do_cleanups (cleanup); + + return result; +} + +/* Helper for cmdpy_init which locates the command list to use and + pulls out the command name. + + TEXT is the command name list. The final word in the list is the + name of the new command. All earlier words must be existing prefix + commands. + + *BASE_LIST is set to the final prefix command's list of + *sub-commands. + + This function returns the xmalloc()d name of the new command. On + error sets the Python error and returns NULL. */ +static char * +parse_command_name (char *text, struct cmd_list_element ***base_list) +{ + struct cmd_list_element *elt; + int len = strlen (text); + int i, lastchar; + char *prefix_text; + char *result; + + /* Skip trailing whitespace. */ + for (i = len - 1; i >= 0 && (text[i] == ' ' || text[i] == '\t'); --i) + ; + if (i < 0) + { + PyErr_SetString (PyExc_RuntimeError, _("no command name found")); + return NULL; + } + lastchar = i; + + /* Find first character of the final word. */ + for (; i > 0 && (isalnum (text[i - 1]) + || text[i - 1] == '-' + || text[i - 1] == '_'); + --i) + ; + result = xmalloc (lastchar - i + 2); + memcpy (result, &text[i], lastchar - i + 1); + result[lastchar - i + 1] = '\0'; + + /* Skip whitespace again. */ + for (--i; i >= 0 && (text[i] == ' ' || text[i] == '\t'); --i) + ; + if (i < 0) + { + *base_list = &cmdlist; + return result; + } + + prefix_text = xmalloc (i + 2); + memcpy (prefix_text, text, i + 1); + prefix_text[i + 1] = '\0'; + + text = prefix_text; + elt = lookup_cmd_1 (&text, cmdlist, NULL, 1); + if (!elt || elt == (struct cmd_list_element *) -1) + { + PyErr_Format (PyExc_RuntimeError, _("could not find command prefix %s"), + prefix_text); + xfree (prefix_text); + xfree (result); + return NULL; + } + + if (elt->prefixlist) + { + xfree (prefix_text); + *base_list = elt->prefixlist; + return result; + } + + PyErr_Format (PyExc_RuntimeError, _("'%s' is not a prefix command"), + prefix_text); + xfree (prefix_text); + xfree (result); + return NULL; +} + +/* Object initializer; sets up gdb-side structures for command. + + Use: __init__(NAME, COMMAND_CLASS [, COMPLETER_CLASS][, PREFIX]]). + + NAME is the name of the command. It may consist of multiple words, + in which case the final word is the name of the new command, and + earlier words must be prefix commands. + + COMMAND_CLASS is the kind of command. It should be one of the COMMAND_* + constants defined in the gdb module. + + COMPLETER_CLASS is the kind of completer. If not given, the + "complete" method will be used. Otherwise, it should be one of the + COMPLETE_* constants defined in the gdb module. + + If PREFIX is True, then this command is a prefix command. + + The documentation for the command is taken from the doc string for + the python class. + +*/ +static int +cmdpy_init (PyObject *self, PyObject *args, PyObject *kw) +{ + cmdpy_object *obj = (cmdpy_object *) self; + char *name; + int cmdtype; + int completetype = -1; + char *docstring = NULL; + volatile struct gdb_exception except; + struct cmd_list_element **cmd_list; + char *cmd_name, *pfx_name; + static char *keywords[] = { "name", "command_class", "completer_class", + "prefix", NULL }; + PyObject *is_prefix = NULL; + int cmp; + + 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_ParseTupleAndKeywords (args, kw, "si|iO", keywords, &name, &cmdtype, + &completetype, &is_prefix)) + 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; + } + + if (completetype < -1 || completetype >= (int) N_COMPLETERS) + { + PyErr_Format (PyExc_RuntimeError, _("invalid completion type argument")); + return -1; + } + + cmd_name = parse_command_name (name, &cmd_list); + if (! cmd_name) + return -1; + + pfx_name = NULL; + if (is_prefix != NULL) + { + cmp = PyObject_IsTrue (is_prefix); + if (cmp == 1) + { + int i, out; + + /* Make a normalized form of the command name. */ + pfx_name = xmalloc (strlen (name) + 2); + + i = 0; + out = 0; + while (name[i]) + { + /* Skip whitespace. */ + while (name[i] == ' ' || name[i] == '\t') + ++i; + /* Copy non-whitespace characters. */ + while (name[i] && name[i] != ' ' && name[i] != '\t') + pfx_name[out++] = name[i++]; + /* Add a single space after each word -- including the final + word. */ + pfx_name[out++] = ' '; + } + pfx_name[out] = '\0'; + } + else if (cmp < 0) + return -1; + } + if (PyObject_HasAttr (self, gdbpy_doc_cst)) + { + PyObject *ds_obj = PyObject_GetAttr (self, gdbpy_doc_cst); + if (ds_obj && gdbpy_is_string (ds_obj)) + docstring = python_string_to_host_string (ds_obj); + } + if (! docstring) + docstring = xstrdup (_("This command is not documented.")); + + Py_INCREF (self); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + struct cmd_list_element *cmd; + + if (pfx_name) + { + int allow_unknown; + + /* If we have our own "invoke" method, then allow unknown + sub-commands. */ + allow_unknown = PyObject_HasAttr (self, invoke_cst); + cmd = add_prefix_cmd (cmd_name, (enum command_class) cmdtype, + NULL, docstring, &obj->sub_list, + pfx_name, allow_unknown, cmd_list); + } + else + cmd = add_cmd (cmd_name, (enum command_class) cmdtype, NULL, + docstring, cmd_list); + + /* There appears to be no API to set this. */ + cmd->func = cmdpy_function; + cmd->destroyer = cmdpy_destroyer; + + obj->command = cmd; + set_cmd_context (cmd, self); + set_cmd_completer (cmd, ((completetype == -1) ? cmdpy_completer + : completers[completetype].completer)); + } + if (except.reason < 0) + { + xfree (cmd_name); + xfree (docstring); + xfree (pfx_name); + Py_DECREF (self); + PyErr_Format (except.reason == RETURN_QUIT + ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, + "%s", except.message); + return -1; + } + return 0; +} + + + +/* Initialize the 'commands' code. */ +void +gdbpy_initialize_commands (void) +{ + int i; + + if (PyType_Ready (&cmdpy_object_type) < 0) + return; + + /* Note: alias and user are 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_RUNNING", class_run) < 0 + || PyModule_AddIntConstant (gdb_module, "COMMAND_DATA", 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_STATUS", class_info) < 0 + || PyModule_AddIntConstant (gdb_module, "COMMAND_BREAKPOINTS", + class_breakpoint) < 0 + || PyModule_AddIntConstant (gdb_module, "COMMAND_TRACEPOINTS", + class_trace) < 0 + || PyModule_AddIntConstant (gdb_module, "COMMAND_OBSCURE", + class_obscure) < 0 + || PyModule_AddIntConstant (gdb_module, "COMMAND_MAINTENANCE", + class_maintenance) < 0) + return; + + for (i = 0; i < N_COMPLETERS; ++i) + { + if (PyModule_AddIntConstant (gdb_module, completers[i].name, i) < 0) + return; + } + + Py_INCREF (&cmdpy_object_type); + PyModule_AddObject (gdb_module, "Command", + (PyObject *) &cmdpy_object_type); + + invoke_cst = PyString_FromString ("invoke"); + complete_cst = PyString_FromString ("complete"); +} + + + +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 */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + cmdpy_init, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew /* tp_new */ +}; diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c new file mode 100644 index 00000000000..279415c6eeb --- /dev/null +++ b/gdb/python/py-frame.c @@ -0,0 +1,539 @@ +/* Python interface to stack frames + + Copyright (C) 2008, 2009 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 . */ + +#include "defs.h" +#include "charset.h" +#include "block.h" +#include "frame.h" +#include "exceptions.h" +#include "symtab.h" +#include "stack.h" +#include "value.h" +#include "python-internal.h" + +typedef struct { + PyObject_HEAD + struct frame_id frame_id; + struct gdbarch *gdbarch; + + /* Marks that the FRAME_ID member actually holds the ID of the frame next + to this, and not this frames' ID itself. This is a hack to permit Python + frame objects which represent invalid frames (i.e., the last frame_info + in a corrupt stack). The problem arises from the fact that this code + relies on FRAME_ID to uniquely identify a frame, which is not always true + for the last "frame" in a corrupt stack (it can have a null ID, or the same + ID as the previous frame). Whenever get_prev_frame returns NULL, we + record the frame_id of the next frame and set FRAME_ID_IS_NEXT to 1. */ + int frame_id_is_next; +} frame_object; + +/* Require a valid frame. This must be called inside a TRY_CATCH, or + another context in which a gdb exception is allowed. */ +#define FRAPY_REQUIRE_VALID(frame_obj, frame) \ + do { \ + frame = frame_object_to_frame_info (frame_obj); \ + if (frame == NULL) \ + error ("Frame is invalid."); \ + } while (0) + +static PyTypeObject frame_object_type; + +/* Returns the frame_info object corresponding to the given Python Frame + object. If the frame doesn't exist anymore (the frame id doesn't + correspond to any frame in the inferior), returns NULL. */ + +static struct frame_info * +frame_object_to_frame_info (frame_object *frame_obj) +{ + struct frame_info *frame; + + frame = frame_find_by_id (frame_obj->frame_id); + if (frame == NULL) + return NULL; + + if (frame_obj->frame_id_is_next) + frame = get_prev_frame (frame); + + return frame; +} + +/* Called by the Python interpreter to obtain string representation + of the object. */ + +static PyObject * +frapy_str (PyObject *self) +{ + char *s; + PyObject *result; + struct ui_file *strfile; + + strfile = mem_fileopen (); + fprint_frame_id (strfile, ((frame_object *) self)->frame_id); + s = ui_file_xstrdup (strfile, NULL); + result = PyString_FromString (s); + xfree (s); + + return result; +} + +/* Implementation of gdb.Frame.is_valid (self) -> Boolean. + Returns True if the frame corresponding to the frame_id of this + object still exists in the inferior. */ + +static PyObject * +frapy_is_valid (PyObject *self, PyObject *args) +{ + struct frame_info *frame; + + frame = frame_object_to_frame_info ((frame_object *) self); + if (frame == NULL) + Py_RETURN_FALSE; + + Py_RETURN_TRUE; +} + +/* Implementation of gdb.Frame.name (self) -> String. + Returns the name of the function corresponding to this frame. */ + +static PyObject * +frapy_name (PyObject *self, PyObject *args) +{ + struct frame_info *frame; + char *name; + enum language lang; + PyObject *result; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + find_frame_funname (frame, &name, &lang); + } + GDB_PY_HANDLE_EXCEPTION (except); + + if (name) + result = PyUnicode_Decode (name, strlen (name), host_charset (), NULL); + else + { + result = Py_None; + Py_INCREF (Py_None); + } + + return result; +} + +/* Implementation of gdb.Frame.type (self) -> Integer. + Returns the frame type, namely one of the gdb.*_FRAME constants. */ + +static PyObject * +frapy_type (PyObject *self, PyObject *args) +{ + struct frame_info *frame; + enum frame_type type = NORMAL_FRAME;/* Initialize to appease gcc warning. */ + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + type = get_frame_type (frame); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return PyInt_FromLong (type); +} + +/* Implementation of gdb.Frame.unwind_stop_reason (self) -> Integer. + Returns one of the gdb.FRAME_UNWIND_* constants. */ + +static PyObject * +frapy_unwind_stop_reason (PyObject *self, PyObject *args) +{ + struct frame_info *frame = NULL; /* Initialize to appease gcc warning. */ + volatile struct gdb_exception except; + enum unwind_stop_reason stop_reason; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + } + GDB_PY_HANDLE_EXCEPTION (except); + + stop_reason = get_frame_unwind_stop_reason (frame); + + return PyInt_FromLong (stop_reason); +} + +/* Implementation of gdb.Frame.pc (self) -> Long. + Returns the frame's resume address. */ + +static PyObject * +frapy_pc (PyObject *self, PyObject *args) +{ + CORE_ADDR pc = 0; /* Initialize to appease gcc warning. */ + struct frame_info *frame; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + pc = get_frame_pc (frame); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return PyLong_FromUnsignedLongLong (pc); +} + +/* Convert a frame_info struct to a Python Frame object. + Sets a Python exception and returns NULL on error. */ + +static frame_object * +frame_info_to_frame_object (struct frame_info *frame) +{ + frame_object *frame_obj; + + frame_obj = PyObject_New (frame_object, &frame_object_type); + if (frame_obj == NULL) + { + PyErr_SetString (PyExc_MemoryError, "Could not allocate frame object."); + return NULL; + } + + /* Try to get the previous frame, to determine if this is the last frame + in a corrupt stack. If so, we need to store the frame_id of the next + frame and not of this one (which is possibly invalid). */ + if (get_prev_frame (frame) == NULL + && get_frame_unwind_stop_reason (frame) != UNWIND_NO_REASON + && get_next_frame (frame) != NULL) + { + frame_obj->frame_id = get_frame_id (get_next_frame (frame)); + frame_obj->frame_id_is_next = 1; + } + else + { + frame_obj->frame_id = get_frame_id (frame); + frame_obj->frame_id_is_next = 0; + } + + frame_obj->gdbarch = get_frame_arch (frame); + + return frame_obj; +} + +/* Implementation of gdb.Frame.older (self) -> gdb.Frame. + Returns the frame immediately older (outer) to this frame, or None if + there isn't one. */ + +static PyObject * +frapy_older (PyObject *self, PyObject *args) +{ + struct frame_info *frame, *prev; + volatile struct gdb_exception except; + PyObject *prev_obj = NULL; /* Initialize to appease gcc warning. */ + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + prev = get_prev_frame (frame); + if (prev) + prev_obj = (PyObject *) frame_info_to_frame_object (prev); + else + { + Py_INCREF (Py_None); + prev_obj = Py_None; + } + } + GDB_PY_HANDLE_EXCEPTION (except); + + return prev_obj; +} + +/* Implementation of gdb.Frame.newer (self) -> gdb.Frame. + Returns the frame immediately newer (inner) to this frame, or None if + there isn't one. */ + +static PyObject * +frapy_newer (PyObject *self, PyObject *args) +{ + struct frame_info *frame, *next; + volatile struct gdb_exception except; + PyObject *next_obj = NULL; /* Initialize to appease gcc warning. */ + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + next = get_next_frame (frame); + if (next) + next_obj = (PyObject *) frame_info_to_frame_object (next); + else + { + Py_INCREF (Py_None); + next_obj = Py_None; + } + } + GDB_PY_HANDLE_EXCEPTION (except); + + return next_obj; +} + +/* Implementation of gdb.Frame.read_var_value (self, variable) -> gdb.Value. + Returns the value of the given variable in this frame. The argument must be + a string. Returns None if GDB can't find the specified variable. */ + +static PyObject * +frapy_read_var (PyObject *self, PyObject *args) +{ + struct frame_info *frame; + PyObject *sym_obj; + struct symbol *var = NULL; /* gcc-4.3.2 false warning. */ + struct value *val = NULL; + volatile struct gdb_exception except; + + if (!PyArg_ParseTuple (args, "O", &sym_obj)) + return NULL; + + if (gdbpy_is_string (sym_obj)) + { + char *var_name; + struct block *block = NULL; + struct cleanup *cleanup; + volatile struct gdb_exception except; + + var_name = python_string_to_target_string (sym_obj); + if (!var_name) + return NULL; + cleanup = make_cleanup (xfree, var_name); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + block = block_for_pc (get_frame_address_in_block (frame)); + var = lookup_symbol (var_name, block, VAR_DOMAIN, NULL); + } + GDB_PY_HANDLE_EXCEPTION (except); + + if (!var) + { + PyErr_Format (PyExc_ValueError, + _("variable '%s' not found"), var_name); + do_cleanups (cleanup); + + return NULL; + } + + do_cleanups (cleanup); + } + else + { + PyErr_SetString (PyExc_TypeError, + _("argument must be a symbol or string")); + return NULL; + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + val = read_var_value (var, frame); + } + GDB_PY_HANDLE_EXCEPTION (except); + + if (val) + return value_to_value_object (val); + + Py_RETURN_NONE; +} + +/* Implementation of gdb.selected_frame () -> gdb.Frame. + Returns the selected frame object. */ + +PyObject * +gdbpy_selected_frame (PyObject *self, PyObject *args) +{ + struct frame_info *frame; + frame_object *frame_obj = NULL; /* Initialize to appease gcc warning. */ + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + frame = get_selected_frame ("No frame is currently selected."); + frame_obj = frame_info_to_frame_object (frame); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return (PyObject *) frame_obj; +} + +/* Implementation of gdb.stop_reason_string (Integer) -> String. + Return a string explaining the unwind stop reason. */ + +PyObject * +gdbpy_frame_stop_reason_string (PyObject *self, PyObject *args) +{ + int reason; + const char *str; + + if (!PyArg_ParseTuple (args, "i", &reason)) + return NULL; + + if (reason < 0 || reason > UNWIND_NO_SAVED_PC) + { + PyErr_SetString (PyExc_ValueError, "Invalid frame stop reason."); + return NULL; + } + + str = frame_stop_reason_string (reason); + return PyUnicode_Decode (str, strlen (str), host_charset (), NULL); +} + +/* Implements the equality comparison for Frame objects. + All other comparison operators will throw a TypeError Python exception, + as they aren't valid for frames. */ + +static PyObject * +frapy_richcompare (PyObject *self, PyObject *other, int op) +{ + int result; + + if (!PyObject_TypeCheck (other, &frame_object_type) + || (op != Py_EQ && op != Py_NE)) + { + Py_INCREF (Py_NotImplemented); + return Py_NotImplemented; + } + + if (frame_id_eq (((frame_object *) self)->frame_id, + ((frame_object *) other)->frame_id)) + result = Py_EQ; + else + result = Py_NE; + + if (op == result) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + +/* Sets up the Frame API in the gdb module. */ + +void +gdbpy_initialize_frames (void) +{ + if (PyType_Ready (&frame_object_type) < 0) + return; + + /* Note: These would probably be best exposed as class attributes of Frame, + but I don't know how to do it except by messing with the type's dictionary. + That seems too messy. */ + PyModule_AddIntConstant (gdb_module, "NORMAL_FRAME", NORMAL_FRAME); + PyModule_AddIntConstant (gdb_module, "DUMMY_FRAME", DUMMY_FRAME); + PyModule_AddIntConstant (gdb_module, "SIGTRAMP_FRAME", SIGTRAMP_FRAME); + PyModule_AddIntConstant (gdb_module, "SENTINEL_FRAME", SENTINEL_FRAME); + PyModule_AddIntConstant (gdb_module, + "FRAME_UNWIND_NO_REASON", UNWIND_NO_REASON); + PyModule_AddIntConstant (gdb_module, + "FRAME_UNWIND_NULL_ID", UNWIND_NULL_ID); + PyModule_AddIntConstant (gdb_module, + "FRAME_UNWIND_FIRST_ERROR", UNWIND_FIRST_ERROR); + PyModule_AddIntConstant (gdb_module, + "FRAME_UNWIND_INNER_ID", UNWIND_INNER_ID); + PyModule_AddIntConstant (gdb_module, + "FRAME_UNWIND_SAME_ID", UNWIND_SAME_ID); + PyModule_AddIntConstant (gdb_module, + "FRAME_UNWIND_NO_SAVED_PC", UNWIND_NO_SAVED_PC); + + Py_INCREF (&frame_object_type); + PyModule_AddObject (gdb_module, "Frame", (PyObject *) &frame_object_type); +} + + + +static PyMethodDef frame_object_methods[] = { + { "is_valid", frapy_is_valid, METH_NOARGS, + "is_valid () -> Boolean.\n\ +Return true if this frame is valid, false if not." }, + { "name", frapy_name, METH_NOARGS, + "name () -> String.\n\ +Return the function name of the frame, or None if it can't be determined." }, + { "type", frapy_type, METH_NOARGS, + "type () -> Integer.\n\ +Return the type of the frame." }, + { "unwind_stop_reason", frapy_unwind_stop_reason, METH_NOARGS, + "unwind_stop_reason () -> Integer.\n\ +Return the reason why it's not possible to find frames older than this." }, + { "pc", frapy_pc, METH_NOARGS, + "pc () -> Long.\n\ +Return the frame's resume address." }, + { "older", frapy_older, METH_NOARGS, + "older () -> gdb.Frame.\n\ +Return the frame that called this frame." }, + { "newer", frapy_newer, METH_NOARGS, + "newer () -> gdb.Frame.\n\ +Return the frame called by this frame." }, + { "read_var", frapy_read_var, METH_VARARGS, + "read_var (variable) -> gdb.Value.\n\ +Return the value of the variable in this frame." }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject frame_object_type = { + PyObject_HEAD_INIT (NULL) + 0, /* ob_size */ + "gdb.Frame", /* tp_name */ + sizeof (frame_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 */ + frapy_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "GDB frame object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + frapy_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + frame_object_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew /* tp_new */ +}; diff --git a/gdb/python/py-function.c b/gdb/python/py-function.c new file mode 100644 index 00000000000..8a5abaff9d0 --- /dev/null +++ b/gdb/python/py-function.c @@ -0,0 +1,180 @@ +/* Convenience functions implemented in Python. + + Copyright (C) 2008, 2009 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 . */ + + +#include "defs.h" +#include "value.h" +#include "exceptions.h" +#include "python-internal.h" +#include "charset.h" +#include "gdbcmd.h" +#include "cli/cli-decode.h" +#include "completer.h" +#include "expression.h" +#include "language.h" + +static PyTypeObject fnpy_object_type; + + + +static PyObject * +convert_values_to_python (int argc, struct value **argv) +{ + int i; + PyObject *result = PyTuple_New (argc); + for (i = 0; i < argc; ++i) + { + PyObject *elt = value_to_value_object (argv[i]); + if (! elt) + { + Py_DECREF (result); + error (_("Could not convert value to Python object.")); + } + PyTuple_SetItem (result, i, elt); + } + return result; +} + +/* Call a Python function object's invoke method. */ + +static struct value * +fnpy_call (struct gdbarch *gdbarch, const struct language_defn *language, + void *cookie, int argc, struct value **argv) +{ + int i; + struct value *value = NULL; + PyObject *result, *callable, *args; + struct cleanup *cleanup; + + cleanup = ensure_python_env (gdbarch, language); + + args = convert_values_to_python (argc, argv); + + callable = PyObject_GetAttrString ((PyObject *) cookie, "invoke"); + if (! callable) + { + Py_DECREF (args); + error (_("No method named 'invoke' in object.")); + } + + result = PyObject_Call (callable, args, NULL); + Py_DECREF (callable); + Py_DECREF (args); + + if (!result) + { + gdbpy_print_stack (); + error (_("Error while executing Python code.")); + } + + value = convert_value_from_python (result); + if (value == NULL) + { + Py_DECREF (result); + gdbpy_print_stack (); + error (_("Error while executing Python code.")); + } + + Py_DECREF (result); + do_cleanups (cleanup); + + return value; +} + +/* Initializer for a Function object. It takes one argument, the name + of the function. */ + +static int +fnpy_init (PyObject *self, PyObject *args, PyObject *kwds) +{ + char *name, *docstring = NULL; + if (! PyArg_ParseTuple (args, "s", &name)) + return -1; + Py_INCREF (self); + + if (PyObject_HasAttrString (self, "__doc__")) + { + PyObject *ds_obj = PyObject_GetAttrString (self, "__doc__"); + if (ds_obj && gdbpy_is_string (ds_obj)) + /* Nothing ever frees this. */ + docstring = python_string_to_host_string (ds_obj); + } + if (! docstring) + docstring = _("This function is not documented."); + + add_internal_function (name, docstring, fnpy_call, self); + return 0; +} + +/* Initialize internal function support. */ + +void +gdbpy_initialize_functions (void) +{ + if (PyType_Ready (&fnpy_object_type) < 0) + return; + + Py_INCREF (&fnpy_object_type); + PyModule_AddObject (gdb_module, "Function", (PyObject *) &fnpy_object_type); +} + + + +static PyTypeObject fnpy_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Function", /*tp_name*/ + sizeof (PyObject), /*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 function object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + fnpy_init, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew /* tp_new */ +}; diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c new file mode 100644 index 00000000000..a483d3371a1 --- /dev/null +++ b/gdb/python/py-objfile.c @@ -0,0 +1,230 @@ +/* Python interface to objfiles. + + Copyright (C) 2008, 2009 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 . */ + +#include "defs.h" +#include "python-internal.h" +#include "charset.h" +#include "objfiles.h" +#include "language.h" + +typedef struct +{ + PyObject_HEAD + + /* The corresponding objfile. */ + struct objfile *objfile; + + /* The pretty-printer list of functions. */ + PyObject *printers; +} objfile_object; + +static PyTypeObject objfile_object_type; + +static const struct objfile_data *objfpy_objfile_data_key; + + + +/* An Objfile method which returns the objfile's file name, or None. */ +static PyObject * +objfpy_get_filename (PyObject *self, void *closure) +{ + objfile_object *obj = (objfile_object *) self; + if (obj->objfile && obj->objfile->name) + return PyString_Decode (obj->objfile->name, strlen (obj->objfile->name), + host_charset (), NULL); + Py_RETURN_NONE; +} + +static void +objfpy_dealloc (PyObject *o) +{ + objfile_object *self = (objfile_object *) o; + Py_XDECREF (self->printers); + self->ob_type->tp_free ((PyObject *) self); +} + +static PyObject * +objfpy_new (PyTypeObject *type, PyObject *args, PyObject *keywords) +{ + objfile_object *self = (objfile_object *) type->tp_alloc (type, 0); + if (self) + { + self->objfile = NULL; + + self->printers = PyList_New (0); + if (!self->printers) + { + Py_DECREF (self); + return NULL; + } + } + return (PyObject *) self; +} + +PyObject * +objfpy_get_printers (PyObject *o, void *ignore) +{ + objfile_object *self = (objfile_object *) o; + Py_INCREF (self->printers); + return self->printers; +} + +static int +objfpy_set_printers (PyObject *o, PyObject *value, void *ignore) +{ + PyObject *tmp; + objfile_object *self = (objfile_object *) o; + if (! value) + { + PyErr_SetString (PyExc_TypeError, + "cannot delete the pretty_printers attribute"); + return -1; + } + + if (! PyList_Check (value)) + { + PyErr_SetString (PyExc_TypeError, + "the pretty_printers attribute must be a list"); + return -1; + } + + /* Take care in case the LHS and RHS are related somehow. */ + tmp = self->printers; + Py_INCREF (value); + self->printers = value; + Py_XDECREF (tmp); + + return 0; +} + + + +/* Clear the OBJFILE pointer in an Objfile object and remove the + reference. */ +static void +clean_up_objfile (struct objfile *objfile, void *datum) +{ + struct cleanup *cleanup; + objfile_object *object = datum; + + cleanup = ensure_python_env (get_objfile_arch (objfile), current_language); + object->objfile = NULL; + Py_DECREF ((PyObject *) object); + do_cleanups (cleanup); +} + +/* Return a borrowed reference to the Python object of type Objfile + representing OBJFILE. If the object has already been created, + return it. Otherwise, create it. Return NULL and set the Python + error on failure. */ +PyObject * +objfile_to_objfile_object (struct objfile *objfile) +{ + objfile_object *object; + + object = objfile_data (objfile, objfpy_objfile_data_key); + if (!object) + { + object = PyObject_New (objfile_object, &objfile_object_type); + if (object) + { + PyObject *dict; + + object->objfile = objfile; + + object->printers = PyList_New (0); + if (!object->printers) + { + Py_DECREF (object); + return NULL; + } + + set_objfile_data (objfile, objfpy_objfile_data_key, object); + } + } + + return (PyObject *) object; +} + +void +gdbpy_initialize_objfile (void) +{ + objfpy_objfile_data_key + = register_objfile_data_with_cleanup (clean_up_objfile); + + if (PyType_Ready (&objfile_object_type) < 0) + return; + + Py_INCREF (&objfile_object_type); + PyModule_AddObject (gdb_module, "Objfile", (PyObject *) &objfile_object_type); +} + + + +static PyGetSetDef objfile_getset[] = +{ + { "filename", objfpy_get_filename, NULL, + "The objfile's filename, or None.", NULL }, + { "pretty_printers", objfpy_get_printers, objfpy_set_printers, + "Pretty printers.", NULL }, + { NULL } +}; + +static PyTypeObject objfile_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Objfile", /*tp_name*/ + sizeof (objfile_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + objfpy_dealloc, /*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, /*tp_flags*/ + "GDB objfile object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + objfile_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + objfpy_new, /* tp_new */ +}; diff --git a/gdb/python/py-prettyprint.c b/gdb/python/py-prettyprint.c new file mode 100644 index 00000000000..5d696c86d3d --- /dev/null +++ b/gdb/python/py-prettyprint.c @@ -0,0 +1,612 @@ +/* Python pretty-printing + + Copyright (C) 2008, 2009 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 . */ + +#include "defs.h" +#include "exceptions.h" +#include "objfiles.h" +#include "symtab.h" +#include "language.h" +#include "valprint.h" + +#include "python.h" + +#ifdef HAVE_PYTHON +#include "python-internal.h" + + +/* Helper function for find_pretty_printer which iterates over a list, + calls each function and inspects output. This will return a + printer object if one recognizes VALUE. If no printer is found, it + will return None. On error, it will set the Python error and + return NULL. */ +static PyObject * +search_pp_list (PyObject *list, PyObject *value) +{ + Py_ssize_t pp_list_size, list_index; + PyObject *function, *printer = NULL; + + pp_list_size = PyList_Size (list); + for (list_index = 0; list_index < pp_list_size; list_index++) + { + function = PyList_GetItem (list, list_index); + if (! function) + return NULL; + + printer = PyObject_CallFunctionObjArgs (function, value, NULL); + if (! printer) + return NULL; + else if (printer != Py_None) + return printer; + + Py_DECREF (printer); + } + + Py_RETURN_NONE; +} + +/* Find the pretty-printing constructor function for VALUE. If no + pretty-printer exists, return None. If one exists, return a new + reference. On error, set the Python error and return NULL. */ +static PyObject * +find_pretty_printer (PyObject *value) +{ + PyObject *pp_list = NULL; + PyObject *function = NULL; + struct objfile *obj; + volatile struct gdb_exception except; + + /* Look at the pretty-printer dictionary for each objfile. */ + ALL_OBJFILES (obj) + { + PyObject *objf = objfile_to_objfile_object (obj); + if (!objf) + { + /* Ignore the error and continue. */ + PyErr_Clear (); + continue; + } + + pp_list = objfpy_get_printers (objf, NULL); + function = search_pp_list (pp_list, value); + + /* If there is an error in any objfile list, abort the search and + exit. */ + if (! function) + { + Py_XDECREF (pp_list); + return NULL; + } + + if (function != Py_None) + goto done; + + Py_DECREF (function); + Py_XDECREF (pp_list); + } + + pp_list = NULL; + /* Fetch the global pretty printer dictionary. */ + if (! PyObject_HasAttrString (gdb_module, "pretty_printers")) + { + function = Py_None; + Py_INCREF (function); + goto done; + } + pp_list = PyObject_GetAttrString (gdb_module, "pretty_printers"); + if (! pp_list) + goto done; + if (! PyList_Check (pp_list)) + goto done; + + function = search_pp_list (pp_list, value); + + done: + Py_XDECREF (pp_list); + + return function; +} +/* Pretty-print a single value, via the printer object PRINTER. + If the function returns a string, a PyObject containing the string + is returned. Otherwise, if the function returns a value, + *OUT_VALUE is set to the value, and NULL is returned. On error, + *OUT_VALUE is set to NULL, and NULL is returned. */ +static PyObject * +pretty_print_one_value (PyObject *printer, struct value **out_value) +{ + volatile struct gdb_exception except; + PyObject *result = NULL; + + *out_value = NULL; + TRY_CATCH (except, RETURN_MASK_ALL) + { + result = PyObject_CallMethodObjArgs (printer, gdbpy_to_string_cst, NULL); + if (result) + { + if (! gdbpy_is_string (result)) + { + *out_value = convert_value_from_python (result); + if (PyErr_Occurred ()) + *out_value = NULL; + Py_DECREF (result); + result = NULL; + } + } + } + + return result; +} + +/* Return the display hint for the object printer, PRINTER. Return + NULL if there is no display_hint method, or if the method did not + return a string. On error, print stack trace and return NULL. On + success, return an xmalloc()d string. */ +char * +gdbpy_get_display_hint (PyObject *printer) +{ + PyObject *hint; + char *result = NULL; + + if (! PyObject_HasAttr (printer, gdbpy_display_hint_cst)) + return NULL; + + hint = PyObject_CallMethodObjArgs (printer, gdbpy_display_hint_cst, NULL); + if (gdbpy_is_string (hint)) + result = python_string_to_host_string (hint); + if (hint) + Py_DECREF (hint); + else + gdbpy_print_stack (); + + return result; +} + +/* Helper for apply_val_pretty_printer which calls to_string and + formats the result. */ +static void +print_string_repr (PyObject *printer, const char *hint, + struct ui_file *stream, int recurse, + const struct value_print_options *options, + const struct language_defn *language, + struct gdbarch *gdbarch) +{ + struct value *replacement = NULL; + PyObject *py_str = NULL; + + py_str = pretty_print_one_value (printer, &replacement); + if (py_str) + { + PyObject *string = python_string_to_target_python_string (py_str); + if (string) + { + gdb_byte *output = PyString_AsString (string); + int len = PyString_Size (string); + + if (hint && !strcmp (hint, "string")) + LA_PRINT_STRING (stream, builtin_type (gdbarch)->builtin_char, + output, len, 0, options); + else + fputs_filtered (output, stream); + Py_DECREF (string); + } + else + gdbpy_print_stack (); + Py_DECREF (py_str); + } + else if (replacement) + common_val_print (replacement, stream, recurse, options, language); + else + gdbpy_print_stack (); +} + +static void +py_restore_tstate (void *p) +{ + PyFrameObject *frame = p; + PyThreadState *tstate = PyThreadState_GET (); + tstate->frame = frame; +} + +/* Create a dummy PyFrameObject, needed to work around + a Python-2.4 bug with generators. */ +static PyObject * +push_dummy_python_frame () +{ + PyObject *empty_string, *null_tuple, *globals; + PyCodeObject *code; + PyFrameObject *frame; + PyThreadState *tstate; + + empty_string = PyString_FromString (""); + if (!empty_string) + return NULL; + + null_tuple = PyTuple_New (0); + if (!null_tuple) + { + Py_DECREF (empty_string); + return NULL; + } + + code = PyCode_New (0, /* argcount */ + 0, /* nlocals */ + 0, /* stacksize */ + 0, /* flags */ + empty_string, /* code */ + null_tuple, /* consts */ + null_tuple, /* names */ + null_tuple, /* varnames */ +#if PYTHON_API_VERSION >= 1010 + null_tuple, /* freevars */ + null_tuple, /* cellvars */ +#endif + empty_string, /* filename */ + empty_string, /* name */ + 1, /* firstlineno */ + empty_string /* lnotab */ + ); + + Py_DECREF (empty_string); + Py_DECREF (null_tuple); + + if (!code) + return NULL; + + globals = PyDict_New (); + if (!globals) + { + Py_DECREF (code); + return NULL; + } + + tstate = PyThreadState_GET (); + + frame = PyFrame_New (tstate, code, globals, NULL); + + Py_DECREF (globals); + Py_DECREF (code); + + if (!frame) + return NULL; + + tstate->frame = frame; + make_cleanup (py_restore_tstate, frame->f_back); + return (PyObject *) frame; +} + +/* Helper for apply_val_pretty_printer that formats children of the + printer, if any exist. */ +static void +print_children (PyObject *printer, const char *hint, + struct ui_file *stream, int recurse, + const struct value_print_options *options, + const struct language_defn *language) +{ + int is_map, is_array, done_flag, pretty; + unsigned int i; + PyObject *children, *iter, *frame; + struct cleanup *cleanups; + + if (! PyObject_HasAttr (printer, gdbpy_children_cst)) + return; + + /* If we are printing a map or an array, we want some special + formatting. */ + is_map = hint && ! strcmp (hint, "map"); + is_array = hint && ! strcmp (hint, "array"); + + children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst, + NULL); + if (! children) + { + gdbpy_print_stack (); + return; + } + + cleanups = make_cleanup_py_decref (children); + + iter = PyObject_GetIter (children); + if (!iter) + { + gdbpy_print_stack (); + goto done; + } + make_cleanup_py_decref (iter); + + /* Use the prettyprint_arrays option if we are printing an array, + and the pretty option otherwise. */ + pretty = is_array ? options->prettyprint_arrays : options->pretty; + + /* Manufacture a dummy Python frame to work around Python 2.4 bug, + where it insists on having a non-NULL tstate->frame when + a generator is called. */ + frame = push_dummy_python_frame (); + if (!frame) + { + gdbpy_print_stack (); + goto done; + } + make_cleanup_py_decref (frame); + + done_flag = 0; + for (i = 0; i < options->print_max; ++i) + { + PyObject *py_v, *item = PyIter_Next (iter); + char *name; + struct cleanup *inner_cleanup; + + if (! item) + { + if (PyErr_Occurred ()) + gdbpy_print_stack (); + /* Set a flag so we can know whether we printed all the + available elements. */ + else + done_flag = 1; + break; + } + + if (! PyArg_ParseTuple (item, "sO", &name, &py_v)) + { + gdbpy_print_stack (); + Py_DECREF (item); + continue; + } + inner_cleanup = make_cleanup_py_decref (item); + + /* Print initial "{". For other elements, there are three + cases: + 1. Maps. Print a "," after each value element. + 2. Arrays. Always print a ",". + 3. Other. Always print a ",". */ + if (i == 0) + fputs_filtered (" = {", stream); + else if (! is_map || i % 2 == 0) + fputs_filtered (pretty ? "," : ", ", stream); + + /* In summary mode, we just want to print "= {...}" if there is + a value. */ + if (options->summary) + { + /* This increment tricks the post-loop logic to print what + we want. */ + ++i; + /* Likewise. */ + pretty = 0; + break; + } + + if (! is_map || i % 2 == 0) + { + if (pretty) + { + fputs_filtered ("\n", stream); + print_spaces_filtered (2 + 2 * recurse, stream); + } + else + wrap_here (n_spaces (2 + 2 *recurse)); + } + + if (is_map && i % 2 == 0) + fputs_filtered ("[", stream); + else if (is_array) + { + /* We print the index, not whatever the child method + returned as the name. */ + if (options->print_array_indexes) + fprintf_filtered (stream, "[%d] = ", i); + } + else if (! is_map) + { + fputs_filtered (name, stream); + fputs_filtered (" = ", stream); + } + + if (gdbpy_is_string (py_v)) + { + char *text = python_string_to_host_string (py_v); + if (! text) + gdbpy_print_stack (); + else + { + fputs_filtered (text, stream); + xfree (text); + } + } + else + { + struct value *value = convert_value_from_python (py_v); + + if (value == NULL) + { + gdbpy_print_stack (); + error (_("Error while executing Python code.")); + } + else + common_val_print (value, stream, recurse + 1, options, language); + } + + if (is_map && i % 2 == 0) + fputs_filtered ("] = ", stream); + + do_cleanups (inner_cleanup); + } + + if (i) + { + if (!done_flag) + { + if (pretty) + { + fputs_filtered ("\n", stream); + print_spaces_filtered (2 + 2 * recurse, stream); + } + fputs_filtered ("...", stream); + } + if (pretty) + { + fputs_filtered ("\n", stream); + print_spaces_filtered (2 * recurse, stream); + } + fputs_filtered ("}", stream); + } + + done: + do_cleanups (cleanups); +} + +int +apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr, + int embedded_offset, CORE_ADDR address, + struct ui_file *stream, int recurse, + const struct value_print_options *options, + const struct language_defn *language) +{ + struct gdbarch *gdbarch = get_type_arch (type); + PyObject *printer = NULL; + PyObject *val_obj = NULL; + struct value *value; + char *hint = NULL; + struct cleanup *cleanups; + int result = 0; + + cleanups = ensure_python_env (gdbarch, language); + + /* Instantiate the printer. */ + if (valaddr) + valaddr += embedded_offset; + value = value_from_contents_and_address (type, valaddr, address); + + val_obj = value_to_value_object (value); + if (! val_obj) + goto done; + + /* Find the constructor. */ + printer = find_pretty_printer (val_obj); + Py_DECREF (val_obj); + make_cleanup_py_decref (printer); + if (! printer || printer == Py_None) + goto done; + + /* If we are printing a map, we want some special formatting. */ + hint = gdbpy_get_display_hint (printer); + make_cleanup (free_current_contents, &hint); + + /* Print the section */ + print_string_repr (printer, hint, stream, recurse, options, language, + gdbarch); + print_children (printer, hint, stream, recurse, options, language); + result = 1; + + + done: + if (PyErr_Occurred ()) + gdbpy_print_stack (); + do_cleanups (cleanups); + return result; +} + + +/* Apply a pretty-printer for the varobj code. PRINTER_OBJ is the + print object. It must have a 'to_string' method (but this is + checked by varobj, not here) which takes no arguments and + returns a string. The printer will return a value and in the case + of a Python string being returned, this function will return a + PyObject containing the string. For any other type, *REPLACEMENT is + set to the replacement value and this function returns NULL. On + error, *REPLACEMENT is set to NULL and this function also returns + NULL. */ +PyObject * +apply_varobj_pretty_printer (PyObject *printer_obj, + struct value **replacement) +{ + int size = 0; + PyObject *py_str = NULL; + + *replacement = NULL; + py_str = pretty_print_one_value (printer_obj, replacement); + + if (*replacement == NULL && py_str == NULL) + gdbpy_print_stack (); + + return py_str; +} + +/* Find a pretty-printer object for the varobj module. Returns a new + reference to the object if successful; returns NULL if not. VALUE + is the value for which a printer tests to determine if it + can pretty-print the value. */ +PyObject * +gdbpy_get_varobj_pretty_printer (struct value *value) +{ + PyObject *val_obj; + PyObject *pretty_printer = NULL; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + value = value_copy (value); + } + GDB_PY_HANDLE_EXCEPTION (except); + + val_obj = value_to_value_object (value); + if (! val_obj) + return NULL; + + pretty_printer = find_pretty_printer (val_obj); + Py_DECREF (val_obj); + return pretty_printer; +} + +/* A Python function which wraps find_pretty_printer and instantiates + the resulting class. This accepts a Value argument and returns a + pretty printer instance, or None. This function is useful as an + argument to the MI command -var-set-visualizer. */ +PyObject * +gdbpy_default_visualizer (PyObject *self, PyObject *args) +{ + PyObject *val_obj; + PyObject *cons, *printer = NULL; + struct value *value; + + if (! PyArg_ParseTuple (args, "O", &val_obj)) + return NULL; + value = value_object_to_value (val_obj); + if (! value) + { + PyErr_SetString (PyExc_TypeError, "argument must be a gdb.Value"); + return NULL; + } + + cons = find_pretty_printer (val_obj); + return cons; +} + +#else /* HAVE_PYTHON */ + +int +apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr, + int embedded_offset, CORE_ADDR address, + struct ui_file *stream, int recurse, + const struct value_print_options *options, + const struct language_defn *language) +{ + return 0; +} + +#endif /* HAVE_PYTHON */ diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c new file mode 100644 index 00000000000..f23248c607b --- /dev/null +++ b/gdb/python/py-type.c @@ -0,0 +1,799 @@ +/* Python interface to types. + + Copyright (C) 2008, 2009 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 . */ + +#include "defs.h" +#include "value.h" +#include "exceptions.h" +#include "python-internal.h" +#include "charset.h" +#include "gdbtypes.h" +#include "cp-support.h" +#include "demangle.h" +#include "objfiles.h" +#include "language.h" + +typedef struct pyty_type_object +{ + PyObject_HEAD + struct type *type; + + /* If a Type object is associated with an objfile, it is kept on a + doubly-linked list, rooted in the objfile. This lets us copy the + underlying struct type when the objfile is deleted. */ + struct pyty_type_object *prev; + struct pyty_type_object *next; +} type_object; + +static PyTypeObject type_object_type; + +/* A Field object. */ +typedef struct pyty_field_object +{ + PyObject_HEAD + + /* Dictionary holding our attributes. */ + PyObject *dict; +} field_object; + +static PyTypeObject field_object_type; + +/* This is used to initialize various gdb.TYPE_ constants. */ +struct pyty_code +{ + /* The code. */ + enum type_code code; + /* The name. */ + const char *name; +}; + +#define ENTRY(X) { X, #X } + +static struct pyty_code pyty_codes[] = +{ + ENTRY (TYPE_CODE_PTR), + ENTRY (TYPE_CODE_ARRAY), + ENTRY (TYPE_CODE_STRUCT), + ENTRY (TYPE_CODE_UNION), + ENTRY (TYPE_CODE_ENUM), + ENTRY (TYPE_CODE_FLAGS), + ENTRY (TYPE_CODE_FUNC), + ENTRY (TYPE_CODE_INT), + ENTRY (TYPE_CODE_FLT), + ENTRY (TYPE_CODE_VOID), + ENTRY (TYPE_CODE_SET), + ENTRY (TYPE_CODE_RANGE), + ENTRY (TYPE_CODE_STRING), + ENTRY (TYPE_CODE_BITSTRING), + ENTRY (TYPE_CODE_ERROR), + ENTRY (TYPE_CODE_METHOD), + ENTRY (TYPE_CODE_METHODPTR), + ENTRY (TYPE_CODE_MEMBERPTR), + ENTRY (TYPE_CODE_REF), + ENTRY (TYPE_CODE_CHAR), + ENTRY (TYPE_CODE_BOOL), + ENTRY (TYPE_CODE_COMPLEX), + ENTRY (TYPE_CODE_TYPEDEF), + ENTRY (TYPE_CODE_NAMESPACE), + ENTRY (TYPE_CODE_DECFLOAT), + ENTRY (TYPE_CODE_INTERNAL_FUNCTION), + { TYPE_CODE_UNDEF, NULL } +}; + + + +static void +field_dealloc (PyObject *obj) +{ + field_object *f = (field_object *) obj; + Py_XDECREF (f->dict); + f->ob_type->tp_free (obj); +} + +static PyObject * +field_new (void) +{ + field_object *result = PyObject_New (field_object, &field_object_type); + if (result) + { + result->dict = PyDict_New (); + if (!result->dict) + { + Py_DECREF (result); + result = NULL; + } + } + return (PyObject *) result; +} + + + +/* Return the code for this type. */ +static PyObject * +typy_get_code (PyObject *self, void *closure) +{ + struct type *type = ((type_object *) self)->type; + return PyInt_FromLong (TYPE_CODE (type)); +} + +/* Helper function for typy_fields which converts a single field to a + dictionary. Returns NULL on error. */ +static PyObject * +convert_field (struct type *type, int field) +{ + PyObject *result = field_new (); + PyObject *arg; + + if (!result) + return NULL; + + if (!field_is_static (&TYPE_FIELD (type, field))) + { + arg = PyLong_FromLong (TYPE_FIELD_BITPOS (type, field)); + if (!arg) + goto fail; + + if (PyObject_SetAttrString (result, "bitpos", arg) < 0) + goto failarg; + } + + if (TYPE_FIELD_NAME (type, field)) + arg = PyString_FromString (TYPE_FIELD_NAME (type, field)); + else + { + arg = Py_None; + Py_INCREF (arg); + } + if (!arg) + goto fail; + if (PyObject_SetAttrString (result, "name", arg) < 0) + goto failarg; + + arg = TYPE_FIELD_ARTIFICIAL (type, field) ? Py_True : Py_False; + Py_INCREF (arg); + if (PyObject_SetAttrString (result, "artificial", arg) < 0) + goto failarg; + + arg = PyLong_FromLong (TYPE_FIELD_BITSIZE (type, field)); + if (!arg) + goto fail; + if (PyObject_SetAttrString (result, "bitsize", arg) < 0) + goto failarg; + + /* A field can have a NULL type in some situations. */ + if (TYPE_FIELD_TYPE (type, field) == NULL) + { + arg = Py_None; + Py_INCREF (arg); + } + else + arg = type_to_type_object (TYPE_FIELD_TYPE (type, field)); + if (!arg) + goto fail; + if (PyObject_SetAttrString (result, "type", arg) < 0) + goto failarg; + + return result; + + failarg: + Py_DECREF (arg); + fail: + Py_DECREF (result); + return NULL; +} + +/* Return a sequence of all fields. Each field is a dictionary with + some pre-defined keys. */ +static PyObject * +typy_fields (PyObject *self, PyObject *args) +{ + PyObject *result; + int i; + struct type *type = ((type_object *) self)->type; + + /* We would like to make a tuple here, make fields immutable, and + then memoize the result (and perhaps make Field.type() lazy). + However, that can lead to cycles. */ + result = PyList_New (0); + + for (i = 0; i < TYPE_NFIELDS (type); ++i) + { + PyObject *dict = convert_field (type, i); + if (!dict) + { + Py_DECREF (result); + return NULL; + } + if (PyList_Append (result, dict)) + { + Py_DECREF (dict); + Py_DECREF (result); + return NULL; + } + } + + return result; +} + +/* Return the type's tag, or None. */ +static PyObject * +typy_get_tag (PyObject *self, void *closure) +{ + struct type *type = ((type_object *) self)->type; + if (!TYPE_TAG_NAME (type)) + Py_RETURN_NONE; + return PyString_FromString (TYPE_TAG_NAME (type)); +} + +/* Return the type, stripped of typedefs. */ +static PyObject * +typy_strip_typedefs (PyObject *self, PyObject *args) +{ + struct type *type = ((type_object *) self)->type; + + return type_to_type_object (check_typedef (type)); +} + +/* Return a Type object which represents a pointer to SELF. */ +static PyObject * +typy_pointer (PyObject *self, PyObject *args) +{ + struct type *type = ((type_object *) self)->type; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + type = lookup_pointer_type (type); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return type_to_type_object (type); +} + +/* Return a Type object which represents a reference to SELF. */ +static PyObject * +typy_reference (PyObject *self, PyObject *args) +{ + struct type *type = ((type_object *) self)->type; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + type = lookup_reference_type (type); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return type_to_type_object (type); +} + +/* Return a Type object which represents the target type of SELF. */ +static PyObject * +typy_target (PyObject *self, PyObject *args) +{ + struct type *type = ((type_object *) self)->type; + + if (!TYPE_TARGET_TYPE (type)) + { + PyErr_SetString (PyExc_RuntimeError, "type does not have a target"); + return NULL; + } + + return type_to_type_object (TYPE_TARGET_TYPE (type)); +} + +/* Return a const-qualified type variant. */ +static PyObject * +typy_const (PyObject *self, PyObject *args) +{ + struct type *type = ((type_object *) self)->type; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + type = make_cv_type (1, 0, type, NULL); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return type_to_type_object (type); +} + +/* Return a volatile-qualified type variant. */ +static PyObject * +typy_volatile (PyObject *self, PyObject *args) +{ + struct type *type = ((type_object *) self)->type; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + type = make_cv_type (0, 1, type, NULL); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return type_to_type_object (type); +} + +/* Return an unqualified type variant. */ +static PyObject * +typy_unqualified (PyObject *self, PyObject *args) +{ + struct type *type = ((type_object *) self)->type; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + type = make_cv_type (0, 0, type, NULL); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return type_to_type_object (type); +} + +/* Return the size of the type represented by SELF, in bytes. */ +static PyObject * +typy_get_sizeof (PyObject *self, void *closure) +{ + struct type *type = ((type_object *) self)->type; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + check_typedef (type); + } + /* Ignore exceptions. */ + + return PyLong_FromLong (TYPE_LENGTH (type)); +} + +static struct type * +typy_lookup_typename (char *type_name) +{ + struct type *type = NULL; + volatile struct gdb_exception except; + TRY_CATCH (except, RETURN_MASK_ALL) + { + if (!strncmp (type_name, "struct ", 7)) + type = lookup_struct (type_name + 7, NULL); + else if (!strncmp (type_name, "union ", 6)) + type = lookup_union (type_name + 6, NULL); + else if (!strncmp (type_name, "enum ", 5)) + type = lookup_enum (type_name + 5, NULL); + else + type = lookup_typename (python_language, python_gdbarch, + type_name, NULL, 0); + } + if (except.reason < 0) + { + PyErr_Format (except.reason == RETURN_QUIT + ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, + "%s", except.message); + return NULL; + } + + return type; +} + +static struct type * +typy_lookup_type (struct demangle_component *demangled) +{ + struct type *type; + char *type_name; + enum demangle_component_type demangled_type; + + /* Save the type: typy_lookup_type() may (indirectly) overwrite + memory pointed by demangled. */ + demangled_type = demangled->type; + + if (demangled_type == DEMANGLE_COMPONENT_POINTER + || demangled_type == DEMANGLE_COMPONENT_REFERENCE + || demangled_type == DEMANGLE_COMPONENT_CONST + || demangled_type == DEMANGLE_COMPONENT_VOLATILE) + { + type = typy_lookup_type (demangled->u.s_binary.left); + if (! type) + return NULL; + + switch (demangled_type) + { + case DEMANGLE_COMPONENT_REFERENCE: + return lookup_reference_type (type); + case DEMANGLE_COMPONENT_POINTER: + return lookup_pointer_type (type); + case DEMANGLE_COMPONENT_CONST: + return make_cv_type (1, 0, type, NULL); + case DEMANGLE_COMPONENT_VOLATILE: + return make_cv_type (0, 1, type, NULL); + } + } + + type_name = cp_comp_to_string (demangled, 10); + type = typy_lookup_typename (type_name); + xfree (type_name); + + return type; +} + +static PyObject * +typy_template_argument (PyObject *self, PyObject *args) +{ + int i, argno, n_pointers; + struct type *type = ((type_object *) self)->type; + struct demangle_component *demangled; + const char *err; + struct type *argtype; + + if (! PyArg_ParseTuple (args, "i", &argno)) + return NULL; + + type = check_typedef (type); + if (TYPE_CODE (type) == TYPE_CODE_REF) + type = check_typedef (TYPE_TARGET_TYPE (type)); + + if (TYPE_NAME (type) == NULL) + { + PyErr_SetString (PyExc_RuntimeError, "null type name"); + return NULL; + } + + /* Note -- this is not thread-safe. */ + demangled = cp_demangled_name_to_comp (TYPE_NAME (type), &err); + if (! demangled) + { + PyErr_SetString (PyExc_RuntimeError, err); + return NULL; + } + + /* Strip off component names. */ + while (demangled->type == DEMANGLE_COMPONENT_QUAL_NAME + || demangled->type == DEMANGLE_COMPONENT_LOCAL_NAME) + demangled = demangled->u.s_binary.right; + + if (demangled->type != DEMANGLE_COMPONENT_TEMPLATE) + { + PyErr_SetString (PyExc_RuntimeError, "type is not a template"); + return NULL; + } + + /* Skip from the template to the arguments. */ + demangled = demangled->u.s_binary.right; + + for (i = 0; demangled && i < argno; ++i) + demangled = demangled->u.s_binary.right; + + if (! demangled) + { + PyErr_Format (PyExc_RuntimeError, "no argument %d in template", + argno); + return NULL; + } + + argtype = typy_lookup_type (demangled->u.s_binary.left); + if (! argtype) + return NULL; + + return type_to_type_object (argtype); +} + +static PyObject * +typy_str (PyObject *self) +{ + volatile struct gdb_exception except; + char *thetype = NULL; + long length = 0; + PyObject *result; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + struct cleanup *old_chain; + struct ui_file *stb; + + stb = mem_fileopen (); + old_chain = make_cleanup_ui_file_delete (stb); + + type_print (type_object_to_type (self), "", stb, -1); + + thetype = ui_file_xstrdup (stb, &length); + do_cleanups (old_chain); + } + if (except.reason < 0) + { + xfree (thetype); + GDB_PY_HANDLE_EXCEPTION (except); + } + + result = PyUnicode_Decode (thetype, length, host_charset (), NULL); + xfree (thetype); + + return result; +} + + + +static const struct objfile_data *typy_objfile_data_key; + +static void +clean_up_objfile_types (struct objfile *objfile, void *datum) +{ + type_object *obj = datum; + htab_t copied_types; + struct cleanup *cleanup; + + /* This prevents another thread from freeing the objects we're + operating on. */ + cleanup = ensure_python_env (get_objfile_arch (objfile), current_language); + + copied_types = create_copied_types_hash (objfile); + + while (obj) + { + type_object *next = obj->next; + + htab_empty (copied_types); + + obj->type = copy_type_recursive (objfile, obj->type, copied_types); + + obj->next = NULL; + obj->prev = NULL; + + obj = next; + } + + htab_delete (copied_types); + + do_cleanups (cleanup); +} + +static void +set_type (type_object *obj, struct type *type) +{ + obj->type = type; + obj->prev = NULL; + if (type && TYPE_OBJFILE (type)) + { + struct objfile *objfile = TYPE_OBJFILE (type); + + obj->next = objfile_data (objfile, typy_objfile_data_key); + if (obj->next) + obj->next->prev = obj; + set_objfile_data (objfile, typy_objfile_data_key, obj); + } + else + obj->next = NULL; +} + +static void +typy_dealloc (PyObject *obj) +{ + type_object *type = (type_object *) obj; + + if (type->prev) + type->prev->next = type->next; + else if (type->type && TYPE_OBJFILE (type->type)) + { + /* Must reset head of list. */ + struct objfile *objfile = TYPE_OBJFILE (type->type); + if (objfile) + set_objfile_data (objfile, typy_objfile_data_key, type->next); + } + if (type->next) + type->next->prev = type->prev; + + type->ob_type->tp_free (type); +} + +/* Create a new Type referring to TYPE. */ +PyObject * +type_to_type_object (struct type *type) +{ + type_object *type_obj; + + type_obj = PyObject_New (type_object, &type_object_type); + if (type_obj) + set_type (type_obj, type); + + return (PyObject *) type_obj; +} + +struct type * +type_object_to_type (PyObject *obj) +{ + if (! PyObject_TypeCheck (obj, &type_object_type)) + return NULL; + return ((type_object *) obj)->type; +} + + + +/* Implementation of gdb.lookup_type. */ +PyObject * +gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw) +{ + static char *keywords[] = { "name", NULL }; + char *type_name = NULL; + struct type *type = NULL; + + if (! PyArg_ParseTupleAndKeywords (args, kw, "s", keywords, &type_name)) + return NULL; + + type = typy_lookup_typename (type_name); + if (! type) + return NULL; + + return (PyObject *) type_to_type_object (type); +} + +void +gdbpy_initialize_types (void) +{ + int i; + + typy_objfile_data_key + = register_objfile_data_with_cleanup (clean_up_objfile_types); + + if (PyType_Ready (&type_object_type) < 0) + return; + if (PyType_Ready (&field_object_type) < 0) + return; + + for (i = 0; pyty_codes[i].name; ++i) + { + if (PyModule_AddIntConstant (gdb_module, + /* Cast needed for Python 2.4. */ + (char *) pyty_codes[i].name, + pyty_codes[i].code) < 0) + return; + } + + Py_INCREF (&type_object_type); + PyModule_AddObject (gdb_module, "Type", (PyObject *) &type_object_type); + + Py_INCREF (&field_object_type); + PyModule_AddObject (gdb_module, "Field", (PyObject *) &field_object_type); +} + + + +static PyGetSetDef type_object_getset[] = +{ + { "code", typy_get_code, NULL, + "The code for this type.", NULL }, + { "sizeof", typy_get_sizeof, NULL, + "The size of this type, in bytes.", NULL }, + { "tag", typy_get_tag, NULL, + "The tag name for this type, or None.", NULL }, + { NULL } +}; + +static PyMethodDef type_object_methods[] = +{ + { "const", typy_const, METH_NOARGS, + "const () -> Type\n\ +Return a const variant of this type." }, + { "fields", typy_fields, METH_NOARGS, + "field () -> list\n\ +Return a sequence holding all the fields of this type.\n\ +Each field is a dictionary." }, + { "pointer", typy_pointer, METH_NOARGS, + "pointer () -> Type\n\ +Return a type of pointer to this type." }, + { "reference", typy_reference, METH_NOARGS, + "reference () -> Type\n\ +Return a type of reference to this type." }, + { "strip_typedefs", typy_strip_typedefs, METH_NOARGS, + "strip_typedefs () -> Type\n\ +Return a type formed by stripping this type of all typedefs."}, + { "target", typy_target, METH_NOARGS, + "target () -> Type\n\ +Return the target type of this type." }, + { "template_argument", typy_template_argument, METH_VARARGS, + "template_argument (arg) -> Type\n\ +Return the type of a template argument." }, + { "unqualified", typy_unqualified, METH_NOARGS, + "unqualified () -> Type\n\ +Return a variant of this type without const or volatile attributes." }, + { "volatile", typy_volatile, METH_NOARGS, + "volatile () -> Type\n\ +Return a volatile variant of this type" }, + { NULL } +}; + +static PyTypeObject type_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Type", /*tp_name*/ + sizeof (type_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + typy_dealloc, /*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*/ + typy_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ + "GDB type object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + type_object_methods, /* tp_methods */ + 0, /* tp_members */ + type_object_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; + +static PyTypeObject field_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Field", /*tp_name*/ + sizeof (field_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + field_dealloc, /*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_HAVE_ITER, /*tp_flags*/ + "GDB field object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof (field_object, dict), /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; diff --git a/gdb/python/py-utils.c b/gdb/python/py-utils.c new file mode 100644 index 00000000000..49c0437c138 --- /dev/null +++ b/gdb/python/py-utils.c @@ -0,0 +1,221 @@ +/* General utility routines for GDB/Python. + + Copyright (C) 2008, 2009 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 . */ + +#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; + Py_INCREF (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 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. */ +static char * +unicode_to_encoded_string (PyObject *unicode_str, const char *charset) +{ + char *result; + PyObject *string; + + /* Translate string to named charset. */ + string = PyUnicode_AsEncodedString (unicode_str, charset, NULL); + if (string == NULL) + return NULL; + + result = xstrdup (PyString_AsString (string)); + + Py_DECREF (string); + + return result; +} + +/* Returns a PyObject with the contents of the given unicode string + object converted to a named charset. If an error occurs during + the conversion, NULL will be returned and a python exception will + be set. */ +static PyObject * +unicode_to_encoded_python_string (PyObject *unicode_str, const char *charset) +{ + PyObject *string; + + /* Translate string to named charset. */ + string = PyUnicode_AsEncodedString (unicode_str, charset, NULL); + if (string == NULL) + return NULL; + + return string; +} + +/* 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) +{ + return unicode_to_encoded_string (unicode_str, target_charset ()); +} + +/* Returns a PyObject 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. */ +PyObject * +unicode_to_target_python_string (PyObject *unicode_str) +{ + return unicode_to_encoded_python_string (unicode_str, target_charset ()); +} + +/* 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; + char *result; + + str = python_string_to_unicode (obj); + if (str == NULL) + return NULL; + + result = unicode_to_target_string (str); + Py_DECREF (str); + return result; +} + +/* 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. */ +PyObject * +python_string_to_target_python_string (PyObject *obj) +{ + PyObject *str; + PyObject *result; + + str = python_string_to_unicode (obj); + if (str == NULL) + return NULL; + + result = unicode_to_target_python_string (str); + Py_DECREF (str); + return result; +} + +/* Converts a python string (8-bit or unicode) to a target string in + the host's charset. Returns NULL on error, with a python exception set. + + The caller is responsible for xfree'ing the string. */ +char * +python_string_to_host_string (PyObject *obj) +{ + PyObject *str; + char *result; + + str = python_string_to_unicode (obj); + if (str == NULL) + return NULL; + + result = unicode_to_encoded_string (str, host_charset ()); + Py_DECREF (str); + return result; +} + +/* Converts a target string of LENGTH bytes in the target's charset to a + Python Unicode string. If LENGTH is -1, convert until a null byte is found. + + Returns NULL on error, with a python exception set. */ +PyObject * +target_string_to_unicode (const gdb_byte *str, int length) +{ + if (length == -1) + length = strlen (str); + + return PyUnicode_Decode (str, length, target_charset (), NULL); +} + +/* Return true if OBJ is a Python string or unicode object, false + otherwise. */ + +int +gdbpy_is_string (PyObject *obj) +{ + return PyString_Check (obj) || PyUnicode_Check (obj); +} diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c new file mode 100644 index 00000000000..3d88aa31f8b --- /dev/null +++ b/gdb/python/py-value.c @@ -0,0 +1,1068 @@ +/* Python interface to values. + + Copyright (C) 2008, 2009 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 . */ + +#include "defs.h" +#include "gdb_assert.h" +#include "charset.h" +#include "value.h" +#include "exceptions.h" +#include "language.h" +#include "dfp.h" +#include "valprint.h" + +#ifdef HAVE_PYTHON + +#include "python-internal.h" + +/* Even though Python scalar types directly map to host types, we use + target types here to remain consistent with the the values system in + GDB (which uses target arithmetic). */ + +/* Python's integer type corresponds to C's long type. */ +#define builtin_type_pyint builtin_type (python_gdbarch)->builtin_long + +/* Python's float type corresponds to C's double type. */ +#define builtin_type_pyfloat builtin_type (python_gdbarch)->builtin_double + +/* Python's long type corresponds to C's long long type. */ +#define builtin_type_pylong builtin_type (python_gdbarch)->builtin_long_long + +#define builtin_type_pybool \ + language_bool_type (python_language, python_gdbarch) + +#define builtin_type_pychar \ + language_string_char_type (python_language, python_gdbarch) + +typedef struct value_object { + PyObject_HEAD + struct value_object *next; + struct value_object *prev; + struct value *value; + PyObject *address; + PyObject *type; +} value_object; + +/* List of all values which are currently exposed to Python. It is + maintained so that when an objfile is discarded, preserve_values + can copy the values' types if needed. */ +/* This variable is unnecessarily initialized to NULL in order to + work around a linker bug on MacOS. */ +static value_object *values_in_python = NULL; + +/* Called by the Python interpreter when deallocating a value object. */ +static void +valpy_dealloc (PyObject *obj) +{ + value_object *self = (value_object *) obj; + + /* Remove SELF from the global list. */ + if (self->prev) + self->prev->next = self->next; + else + { + gdb_assert (values_in_python == self); + values_in_python = self->next; + } + if (self->next) + self->next->prev = self->prev; + + value_free (self->value); + + if (self->address) + /* Use braces to appease gcc warning. *sigh* */ + { + Py_DECREF (self->address); + } + + if (self->type) + { + Py_DECREF (self->type); + } + + self->ob_type->tp_free (self); +} + +/* Helper to push a Value object on the global list. */ +static void +note_value (value_object *value_obj) +{ + value_obj->next = values_in_python; + if (value_obj->next) + value_obj->next->prev = value_obj; + value_obj->prev = NULL; + values_in_python = value_obj; +} + +/* Called when a new gdb.Value object needs to be allocated. */ +static PyObject * +valpy_new (PyTypeObject *subtype, PyObject *args, PyObject *keywords) +{ + struct value *value = NULL; /* Initialize to appease gcc warning. */ + value_object *value_obj; + + if (PyTuple_Size (args) != 1) + { + PyErr_SetString (PyExc_TypeError, _("Value object creation takes only " + "1 argument")); + return NULL; + } + + value_obj = (value_object *) subtype->tp_alloc (subtype, 1); + if (value_obj == NULL) + { + PyErr_SetString (PyExc_MemoryError, _("Could not allocate memory to " + "create Value object.")); + return NULL; + } + + value = convert_value_from_python (PyTuple_GetItem (args, 0)); + if (value == NULL) + { + subtype->tp_free (value_obj); + return NULL; + } + + value_obj->value = value; + value_incref (value); + value_obj->address = NULL; + value_obj->type = NULL; + note_value (value_obj); + + return (PyObject *) value_obj; +} + +/* Iterate over all the Value objects, calling preserve_one_value on + each. */ +void +preserve_python_values (struct objfile *objfile, htab_t copied_types) +{ + value_object *iter; + + for (iter = values_in_python; iter; iter = iter->next) + preserve_one_value (iter->value, objfile, copied_types); +} + +/* Given a value of a pointer type, apply the C unary * operator to it. */ +static PyObject * +valpy_dereference (PyObject *self, PyObject *args) +{ + struct value *res_val = NULL; /* Initialize to appease gcc warning. */ + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + res_val = value_ind (((value_object *) self)->value); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return value_to_value_object (res_val); +} + +/* Return "&value". */ +static PyObject * +valpy_get_address (PyObject *self, void *closure) +{ + struct value *res_val = NULL; /* Initialize to appease gcc warning. */ + value_object *val_obj = (value_object *) self; + volatile struct gdb_exception except; + + if (!val_obj->address) + { + TRY_CATCH (except, RETURN_MASK_ALL) + { + res_val = value_addr (val_obj->value); + } + if (except.reason < 0) + { + val_obj->address = Py_None; + Py_INCREF (Py_None); + } + else + val_obj->address = value_to_value_object (res_val); + } + + Py_INCREF (val_obj->address); + + return val_obj->address; +} + +/* Return type of the value. */ +static PyObject * +valpy_get_type (PyObject *self, void *closure) +{ + value_object *obj = (value_object *) self; + if (!obj->type) + { + obj->type = type_to_type_object (value_type (obj->value)); + if (!obj->type) + { + obj->type = Py_None; + Py_INCREF (obj->type); + } + } + Py_INCREF (obj->type); + return obj->type; +} + +/* Implementation of gdb.Value.string ([encoding] [, errors] + [, length]) -> string. Return Unicode string with value contents. + If ENCODING is not given, the string is assumed to be encoded in + the target's charset. If LENGTH is provided, only fetch string to + the length provided. */ + +static PyObject * +valpy_string (PyObject *self, PyObject *args, PyObject *kw) +{ + int length = -1, ret = 0; + gdb_byte *buffer; + struct value *value = ((value_object *) self)->value; + volatile struct gdb_exception except; + PyObject *unicode; + const char *encoding = NULL; + const char *errors = NULL; + const char *user_encoding = NULL; + const char *la_encoding = NULL; + static char *keywords[] = { "encoding", "errors", "length" }; + + if (!PyArg_ParseTupleAndKeywords (args, kw, "|ssi", keywords, + &user_encoding, &errors, &length)) + return NULL; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + LA_GET_STRING (value, &buffer, &length, &la_encoding); + } + GDB_PY_HANDLE_EXCEPTION (except); + + encoding = (user_encoding && *user_encoding) ? user_encoding : la_encoding; + unicode = PyUnicode_Decode (buffer, length, encoding, errors); + xfree (buffer); + + return unicode; +} + +/* Cast a value to a given type. */ +static PyObject * +valpy_cast (PyObject *self, PyObject *args) +{ + PyObject *type_obj; + struct type *type; + struct value *res_val = NULL; /* Initialize to appease gcc warning. */ + volatile struct gdb_exception except; + + if (! PyArg_ParseTuple (args, "O", &type_obj)) + return NULL; + + type = type_object_to_type (type_obj); + if (! type) + { + PyErr_SetString (PyExc_RuntimeError, "argument must be a Type"); + return NULL; + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + res_val = value_cast (type, ((value_object *) self)->value); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return value_to_value_object (res_val); +} + +static Py_ssize_t +valpy_length (PyObject *self) +{ + /* We don't support getting the number of elements in a struct / class. */ + PyErr_SetString (PyExc_NotImplementedError, + "Invalid operation on gdb.Value."); + return -1; +} + +/* Given string name of an element inside structure, return its value + object. */ +static PyObject * +valpy_getitem (PyObject *self, PyObject *key) +{ + value_object *self_value = (value_object *) self; + char *field = NULL; + struct value *res_val = NULL; + volatile struct gdb_exception except; + + if (gdbpy_is_string (key)) + { + field = python_string_to_host_string (key); + if (field == NULL) + return NULL; + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + struct value *tmp = self_value->value; + + if (field) + res_val = value_struct_elt (&tmp, NULL, field, 0, NULL); + else + { + /* Assume we are attempting an array access, and let the + value code throw an exception if the index has an invalid + type. */ + struct value *idx = convert_value_from_python (key); + if (idx != NULL) + res_val = value_subscript (tmp, value_as_long (idx)); + } + } + + xfree (field); + GDB_PY_HANDLE_EXCEPTION (except); + + return res_val ? value_to_value_object (res_val) : NULL; +} + +static int +valpy_setitem (PyObject *self, PyObject *key, PyObject *value) +{ + PyErr_Format (PyExc_NotImplementedError, + _("Setting of struct elements is not currently supported.")); + return -1; +} + +/* Called by the Python interpreter to obtain string representation + of the object. */ +static PyObject * +valpy_str (PyObject *self) +{ + char *s = NULL; + struct ui_file *stb; + struct cleanup *old_chain; + PyObject *result; + struct value_print_options opts; + volatile struct gdb_exception except; + + get_user_print_options (&opts); + opts.deref_ref = 0; + + stb = mem_fileopen (); + old_chain = make_cleanup_ui_file_delete (stb); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + common_val_print (((value_object *) self)->value, stb, 0, + &opts, python_language); + s = ui_file_xstrdup (stb, NULL); + } + GDB_PY_HANDLE_EXCEPTION (except); + + do_cleanups (old_chain); + + result = PyUnicode_Decode (s, strlen (s), host_charset (), NULL); + xfree (s); + + return result; +} + +/* Implements gdb.Value.is_optimized_out. */ +static PyObject * +valpy_get_is_optimized_out (PyObject *self, void *closure) +{ + struct value *value = ((value_object *) self)->value; + + if (value_optimized_out (value)) + Py_RETURN_TRUE; + + Py_RETURN_FALSE; +} + +enum valpy_opcode +{ + VALPY_ADD, + VALPY_SUB, + VALPY_MUL, + VALPY_DIV, + VALPY_REM, + VALPY_POW, + VALPY_LSH, + VALPY_RSH, + VALPY_BITAND, + VALPY_BITOR, + VALPY_BITXOR +}; + +/* If TYPE is a reference, return the target; otherwise return TYPE. */ +#define STRIP_REFERENCE(TYPE) \ + ((TYPE_CODE (TYPE) == TYPE_CODE_REF) ? (TYPE_TARGET_TYPE (TYPE)) : (TYPE)) + +/* Returns a value object which is the result of applying the operation + specified by OPCODE to the given arguments. */ +static PyObject * +valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other) +{ + struct value *res_val = NULL; /* Initialize to appease gcc warning. */ + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + struct value *arg1, *arg2; + + /* If the gdb.Value object is the second operand, then it will be passed + to us as the OTHER argument, and SELF will be an entirely different + kind of object, altogether. Because of this, we can't assume self is + a gdb.Value object and need to convert it from python as well. */ + arg1 = convert_value_from_python (self); + if (arg1 == NULL) + break; + + arg2 = convert_value_from_python (other); + if (arg2 == NULL) + break; + + switch (opcode) + { + case VALPY_ADD: + { + struct type *ltype = value_type (arg1); + struct type *rtype = value_type (arg2); + + CHECK_TYPEDEF (ltype); + ltype = STRIP_REFERENCE (ltype); + CHECK_TYPEDEF (rtype); + rtype = STRIP_REFERENCE (rtype); + + if (TYPE_CODE (ltype) == TYPE_CODE_PTR + && is_integral_type (rtype)) + res_val = value_ptradd (arg1, value_as_long (arg2)); + else if (TYPE_CODE (rtype) == TYPE_CODE_PTR + && is_integral_type (ltype)) + res_val = value_ptradd (arg2, value_as_long (arg1)); + else + res_val = value_binop (arg1, arg2, BINOP_ADD); + } + break; + case VALPY_SUB: + { + struct type *ltype = value_type (arg1); + struct type *rtype = value_type (arg2); + + CHECK_TYPEDEF (ltype); + ltype = STRIP_REFERENCE (ltype); + CHECK_TYPEDEF (rtype); + rtype = STRIP_REFERENCE (rtype); + + if (TYPE_CODE (ltype) == TYPE_CODE_PTR + && TYPE_CODE (rtype) == TYPE_CODE_PTR) + /* A ptrdiff_t for the target would be preferable here. */ + res_val = value_from_longest (builtin_type_pyint, + value_ptrdiff (arg1, arg2)); + else if (TYPE_CODE (ltype) == TYPE_CODE_PTR + && is_integral_type (rtype)) + res_val = value_ptradd (arg1, - value_as_long (arg2)); + else + res_val = value_binop (arg1, arg2, BINOP_SUB); + } + break; + case VALPY_MUL: + res_val = value_binop (arg1, arg2, BINOP_MUL); + break; + case VALPY_DIV: + res_val = value_binop (arg1, arg2, BINOP_DIV); + break; + case VALPY_REM: + res_val = value_binop (arg1, arg2, BINOP_REM); + break; + case VALPY_POW: + res_val = value_binop (arg1, arg2, BINOP_EXP); + break; + case VALPY_LSH: + res_val = value_binop (arg1, arg2, BINOP_LSH); + break; + case VALPY_RSH: + res_val = value_binop (arg1, arg2, BINOP_RSH); + break; + case VALPY_BITAND: + res_val = value_binop (arg1, arg2, BINOP_BITWISE_AND); + break; + case VALPY_BITOR: + res_val = value_binop (arg1, arg2, BINOP_BITWISE_IOR); + break; + case VALPY_BITXOR: + res_val = value_binop (arg1, arg2, BINOP_BITWISE_XOR); + break; + } + } + GDB_PY_HANDLE_EXCEPTION (except); + + return res_val ? value_to_value_object (res_val) : NULL; +} + +static PyObject * +valpy_add (PyObject *self, PyObject *other) +{ + return valpy_binop (VALPY_ADD, self, other); +} + +static PyObject * +valpy_subtract (PyObject *self, PyObject *other) +{ + return valpy_binop (VALPY_SUB, self, other); +} + +static PyObject * +valpy_multiply (PyObject *self, PyObject *other) +{ + return valpy_binop (VALPY_MUL, self, other); +} + +static PyObject * +valpy_divide (PyObject *self, PyObject *other) +{ + return valpy_binop (VALPY_DIV, self, other); +} + +static PyObject * +valpy_remainder (PyObject *self, PyObject *other) +{ + return valpy_binop (VALPY_REM, self, other); +} + +static PyObject * +valpy_power (PyObject *self, PyObject *other, PyObject *unused) +{ + /* We don't support the ternary form of pow. I don't know how to express + that, so let's just throw NotImplementedError to at least do something + about it. */ + if (unused != Py_None) + { + PyErr_SetString (PyExc_NotImplementedError, + "Invalid operation on gdb.Value."); + return NULL; + } + + return valpy_binop (VALPY_POW, self, other); +} + +static PyObject * +valpy_negative (PyObject *self) +{ + struct value *val = NULL; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + val = value_neg (((value_object *) self)->value); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return value_to_value_object (val); +} + +static PyObject * +valpy_positive (PyObject *self) +{ + return value_to_value_object (((value_object *) self)->value); +} + +static PyObject * +valpy_absolute (PyObject *self) +{ + struct value *value = ((value_object *) self)->value; + if (value_less (value, value_zero (value_type (value), not_lval))) + return valpy_negative (self); + else + return valpy_positive (self); +} + +/* Implements boolean evaluation of gdb.Value. */ +static int +valpy_nonzero (PyObject *self) +{ + value_object *self_value = (value_object *) self; + struct type *type; + + type = check_typedef (value_type (self_value->value)); + + if (is_integral_type (type) || TYPE_CODE (type) == TYPE_CODE_PTR) + return !!value_as_long (self_value->value); + else if (TYPE_CODE (type) == TYPE_CODE_FLT) + return value_as_double (self_value->value) != 0; + else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT) + return !decimal_is_zero (value_contents (self_value->value), + TYPE_LENGTH (type), + gdbarch_byte_order (get_type_arch (type))); + else + { + PyErr_SetString (PyExc_TypeError, _("Attempted truth testing on invalid " + "gdb.Value type.")); + return 0; + } +} + +/* Implements ~ for value objects. */ +static PyObject * +valpy_invert (PyObject *self) +{ + struct value *val = NULL; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + val = value_complement (((value_object *) self)->value); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return value_to_value_object (val); +} + +/* Implements left shift for value objects. */ +static PyObject * +valpy_lsh (PyObject *self, PyObject *other) +{ + return valpy_binop (VALPY_LSH, self, other); +} + +/* Implements right shift for value objects. */ +static PyObject * +valpy_rsh (PyObject *self, PyObject *other) +{ + return valpy_binop (VALPY_RSH, self, other); +} + +/* Implements bitwise and for value objects. */ +static PyObject * +valpy_and (PyObject *self, PyObject *other) +{ + return valpy_binop (VALPY_BITAND, self, other); +} + +/* Implements bitwise or for value objects. */ +static PyObject * +valpy_or (PyObject *self, PyObject *other) +{ + return valpy_binop (VALPY_BITOR, self, other); +} + +/* Implements bitwise xor for value objects. */ +static PyObject * +valpy_xor (PyObject *self, PyObject *other) +{ + return valpy_binop (VALPY_BITXOR, self, other); +} + +/* Implements comparison operations for value objects. */ +static PyObject * +valpy_richcompare (PyObject *self, PyObject *other, int op) +{ + int result = 0; + struct value *value_other; + volatile struct gdb_exception except; + + if (other == Py_None) + /* Comparing with None is special. From what I can tell, in Python + None is smaller than anything else. */ + switch (op) { + case Py_LT: + case Py_LE: + case Py_EQ: + Py_RETURN_FALSE; + case Py_NE: + case Py_GT: + case Py_GE: + Py_RETURN_TRUE; + default: + /* Can't happen. */ + PyErr_SetString (PyExc_NotImplementedError, + "Invalid operation on gdb.Value."); + return NULL; + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + value_other = convert_value_from_python (other); + if (value_other == NULL) + { + result = -1; + break; + } + + switch (op) { + case Py_LT: + result = value_less (((value_object *) self)->value, value_other); + break; + case Py_LE: + result = value_less (((value_object *) self)->value, value_other) + || value_equal (((value_object *) self)->value, value_other); + break; + case Py_EQ: + result = value_equal (((value_object *) self)->value, value_other); + break; + case Py_NE: + result = !value_equal (((value_object *) self)->value, value_other); + break; + case Py_GT: + result = value_less (value_other, ((value_object *) self)->value); + break; + case Py_GE: + result = value_less (value_other, ((value_object *) self)->value) + || value_equal (((value_object *) self)->value, value_other); + break; + default: + /* Can't happen. */ + PyErr_SetString (PyExc_NotImplementedError, + "Invalid operation on gdb.Value."); + result = -1; + break; + } + } + GDB_PY_HANDLE_EXCEPTION (except); + + /* In this case, the Python exception has already been set. */ + if (result < 0) + return NULL; + + if (result == 1) + Py_RETURN_TRUE; + + Py_RETURN_FALSE; +} + +/* Helper function to determine if a type is "int-like". */ +static int +is_intlike (struct type *type, int ptr_ok) +{ + CHECK_TYPEDEF (type); + return (TYPE_CODE (type) == TYPE_CODE_INT + || TYPE_CODE (type) == TYPE_CODE_ENUM + || TYPE_CODE (type) == TYPE_CODE_BOOL + || TYPE_CODE (type) == TYPE_CODE_CHAR + || (ptr_ok && TYPE_CODE (type) == TYPE_CODE_PTR)); +} + +/* Implements conversion to int. */ +static PyObject * +valpy_int (PyObject *self) +{ + struct value *value = ((value_object *) self)->value; + struct type *type = value_type (value); + LONGEST l = 0; + volatile struct gdb_exception except; + + CHECK_TYPEDEF (type); + if (!is_intlike (type, 0)) + { + PyErr_SetString (PyExc_RuntimeError, "cannot convert value to int"); + return NULL; + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + l = value_as_long (value); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return PyInt_FromLong (l); +} + +/* Implements conversion to long. */ +static PyObject * +valpy_long (PyObject *self) +{ + struct value *value = ((value_object *) self)->value; + struct type *type = value_type (value); + LONGEST l = 0; + volatile struct gdb_exception except; + + if (!is_intlike (type, 1)) + { + PyErr_SetString (PyExc_RuntimeError, "cannot convert value to long"); + return NULL; + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + l = value_as_long (value); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return PyLong_FromLong (l); +} + +/* Implements conversion to float. */ +static PyObject * +valpy_float (PyObject *self) +{ + struct value *value = ((value_object *) self)->value; + struct type *type = value_type (value); + double d = 0; + volatile struct gdb_exception except; + + CHECK_TYPEDEF (type); + if (TYPE_CODE (type) != TYPE_CODE_FLT) + { + PyErr_SetString (PyExc_RuntimeError, "cannot convert value to float"); + return NULL; + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + d = value_as_double (value); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return PyFloat_FromDouble (d); +} + +/* Returns an object for a value which is released from the all_values chain, + so its lifetime is not bound to the execution of a command. */ +PyObject * +value_to_value_object (struct value *val) +{ + value_object *val_obj; + + val_obj = PyObject_New (value_object, &value_object_type); + if (val_obj != NULL) + { + val_obj->value = val; + value_incref (val); + val_obj->address = NULL; + val_obj->type = NULL; + note_value (val_obj); + } + + return (PyObject *) val_obj; +} + +/* Returns a borrowed reference to the struct value corresponding to + the given value object. */ +struct value * +value_object_to_value (PyObject *self) +{ + value_object *real; + if (! PyObject_TypeCheck (self, &value_object_type)) + return NULL; + real = (value_object *) self; + return real->value; +} + +/* Try to convert a Python value to a gdb value. If the value cannot + be converted, set a Python exception and return NULL. Returns a + reference to a new value on the all_values chain. */ + +struct value * +convert_value_from_python (PyObject *obj) +{ + struct value *value = NULL; /* -Wall */ + PyObject *target_str, *unicode_str; + struct cleanup *old; + volatile struct gdb_exception except; + int cmp; + + gdb_assert (obj != NULL); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + if (PyBool_Check (obj)) + { + cmp = PyObject_IsTrue (obj); + if (cmp >= 0) + value = value_from_longest (builtin_type_pybool, cmp); + } + else if (PyInt_Check (obj)) + { + long l = PyInt_AsLong (obj); + + if (! PyErr_Occurred ()) + value = value_from_longest (builtin_type_pyint, l); + } + else if (PyLong_Check (obj)) + { + LONGEST l = PyLong_AsLongLong (obj); + + if (! PyErr_Occurred ()) + value = value_from_longest (builtin_type_pylong, l); + } + else if (PyFloat_Check (obj)) + { + double d = PyFloat_AsDouble (obj); + + if (! PyErr_Occurred ()) + value = value_from_double (builtin_type_pyfloat, d); + } + else if (gdbpy_is_string (obj)) + { + char *s; + + s = python_string_to_target_string (obj); + if (s != NULL) + { + old = make_cleanup (xfree, s); + value = value_cstring (s, strlen (s), builtin_type_pychar); + do_cleanups (old); + } + } + else if (PyObject_TypeCheck (obj, &value_object_type)) + value = value_copy (((value_object *) obj)->value); + else + PyErr_Format (PyExc_TypeError, _("Could not convert Python object: %s"), + PyString_AsString (PyObject_Str (obj))); + } + if (except.reason < 0) + { + PyErr_Format (except.reason == RETURN_QUIT + ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, + "%s", except.message); + return NULL; + } + + return value; +} + +/* Returns value object in the ARGth position in GDB's history. */ +PyObject * +gdbpy_history (PyObject *self, PyObject *args) +{ + int i; + struct value *res_val = NULL; /* Initialize to appease gcc warning. */ + volatile struct gdb_exception except; + + if (!PyArg_ParseTuple (args, "i", &i)) + return NULL; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + res_val = access_value_history (i); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return value_to_value_object (res_val); +} + +void +gdbpy_initialize_values (void) +{ + if (PyType_Ready (&value_object_type) < 0) + return; + + Py_INCREF (&value_object_type); + PyModule_AddObject (gdb_module, "Value", (PyObject *) &value_object_type); + + values_in_python = NULL; +} + + + +static PyGetSetDef value_object_getset[] = { + { "address", valpy_get_address, NULL, "The address of the value.", + NULL }, + { "is_optimized_out", valpy_get_is_optimized_out, NULL, + "Boolean telling whether the value is optimized out (i.e., not available).", + NULL }, + { "type", valpy_get_type, NULL, "Type of the value.", NULL }, + {NULL} /* Sentinel */ +}; + +static PyMethodDef value_object_methods[] = { + { "cast", valpy_cast, METH_VARARGS, "Cast the value to the supplied type." }, + { "dereference", valpy_dereference, METH_NOARGS, "Dereferences the value." }, + { "string", (PyCFunction) valpy_string, METH_VARARGS | METH_KEYWORDS, + "string ([encoding] [, errors] [, length]) -> string\n\ +Return Unicode string representation of the value." }, + {NULL} /* Sentinel */ +}; + +static PyNumberMethods value_object_as_number = { + valpy_add, + valpy_subtract, + valpy_multiply, + valpy_divide, + valpy_remainder, + NULL, /* nb_divmod */ + valpy_power, /* nb_power */ + valpy_negative, /* nb_negative */ + valpy_positive, /* nb_positive */ + valpy_absolute, /* nb_absolute */ + valpy_nonzero, /* nb_nonzero */ + valpy_invert, /* nb_invert */ + valpy_lsh, /* nb_lshift */ + valpy_rsh, /* nb_rshift */ + valpy_and, /* nb_and */ + valpy_xor, /* nb_xor */ + valpy_or, /* nb_or */ + NULL, /* nb_coerce */ + valpy_int, /* nb_int */ + valpy_long, /* nb_long */ + valpy_float, /* nb_float */ + NULL, /* nb_oct */ + NULL /* nb_hex */ +}; + +static PyMappingMethods value_object_as_mapping = { + valpy_length, + valpy_getitem, + valpy_setitem +}; + +PyTypeObject value_object_type = { + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Value", /*tp_name*/ + sizeof (value_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + valpy_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + &value_object_as_number, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + &value_object_as_mapping, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + valpy_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ + "GDB value object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + valpy_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + value_object_methods, /* tp_methods */ + 0, /* tp_members */ + value_object_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + valpy_new /* tp_new */ +}; + +#else + +void +preserve_python_values (struct objfile *objfile, htab_t copied_types) +{ + /* Nothing. */ +} + +#endif /* HAVE_PYTHON */ diff --git a/gdb/python/python-cmd.c b/gdb/python/python-cmd.c deleted file mode 100644 index 528aca6ffda..00000000000 --- a/gdb/python/python-cmd.c +++ /dev/null @@ -1,585 +0,0 @@ -/* gdb commands implemented in Python - - Copyright (C) 2008, 2009 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 . */ - - -#include "defs.h" -#include "arch-utils.h" -#include "value.h" -#include "exceptions.h" -#include "python-internal.h" -#include "charset.h" -#include "gdbcmd.h" -#include "cli/cli-decode.h" -#include "completer.h" -#include "language.h" - -/* Struct representing built-in completion types. */ -struct cmdpy_completer -{ - /* Python symbol name. */ - char *name; - /* Completion function. */ - char **(*completer) (struct cmd_list_element *, char *, char *); -}; - -static struct cmdpy_completer completers[] = -{ - { "COMPLETE_NONE", noop_completer }, - { "COMPLETE_FILENAME", filename_completer }, - { "COMPLETE_LOCATION", location_completer }, - { "COMPLETE_COMMAND", command_completer }, - { "COMPLETE_SYMBOL", make_symbol_completion_list_fn }, -}; - -#define N_COMPLETERS (sizeof (completers) / sizeof (completers[0])) - -/* 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. */ - struct cmd_list_element *command; - - /* A prefix command requires storage for a list of its sub-commands. - A pointer to this is passed to add_prefix_command, and to add_cmd - for sub-commands of that prefix. If this Command is not a prefix - command, then this field is unused. */ - struct cmd_list_element *sub_list; -}; - -typedef struct cmdpy_object cmdpy_object; - -static PyTypeObject cmdpy_object_type; - - -/* Constants used by this module. */ -static PyObject *invoke_cst; -static PyObject *complete_cst; - - - -/* Python function which wraps dont_repeat. */ -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) -{ - cmdpy_object *cmd; - struct cleanup *cleanup; - - cleanup = ensure_python_env (get_current_arch (), current_language); - - /* Release our hold on the command object. */ - cmd = (cmdpy_object *) context; - cmd->command = NULL; - Py_DECREF (cmd); - - /* We allocated the name, doc string, and perhaps the prefix - name. */ - xfree (self->name); - xfree (self->doc); - xfree (self->prefixname); - - do_cleanups (cleanup); -} - -/* 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 *argobj, *ttyobj, *result; - struct cleanup *cleanup; - - cleanup = ensure_python_env (get_current_arch (), current_language); - - if (! obj) - error (_("Invalid invocation of Python command object.")); - if (! PyObject_HasAttr ((PyObject *) obj, invoke_cst)) - { - if (obj->command->prefixname) - { - /* A prefix command does not need an invoke method. */ - do_cleanups (cleanup); - return; - } - error (_("Python command object missing 'invoke' method.")); - } - - if (! args) - args = ""; - argobj = PyUnicode_Decode (args, strlen (args), host_charset (), NULL); - if (! argobj) - error (_("Could not convert arguments to Python string.")); - - ttyobj = from_tty ? Py_True : Py_False; - Py_INCREF (ttyobj); - result = PyObject_CallMethodObjArgs ((PyObject *) obj, invoke_cst, argobj, - ttyobj, NULL); - Py_DECREF (argobj); - Py_DECREF (ttyobj); - if (! result) - { - PyObject *ptype, *pvalue, *ptraceback; - char *s, *str; - - PyErr_Fetch (&ptype, &pvalue, &ptraceback); - - if (pvalue && PyString_Check (pvalue)) - { - /* Make a temporary copy of the string data. */ - char *s = PyString_AsString (pvalue); - char *copy = alloca (strlen (s) + 1); - strcpy (copy, s); - - PyErr_Restore (ptype, pvalue, ptraceback); - gdbpy_print_stack (); - error (_("Error occurred in Python command: %s"), copy); - } - else - { - PyErr_Restore (ptype, pvalue, ptraceback); - gdbpy_print_stack (); - error (_("Error occurred in Python command.")); - } - } - Py_DECREF (result); - do_cleanups (cleanup); -} - -/* Called by gdb for command completion. */ -static char ** -cmdpy_completer (struct cmd_list_element *command, char *text, char *word) -{ - cmdpy_object *obj = (cmdpy_object *) get_cmd_context (command); - PyObject *textobj, *wordobj, *resultobj = NULL; - char **result = NULL; - struct cleanup *cleanup; - - cleanup = ensure_python_env (get_current_arch (), current_language); - - if (! obj) - error (_("Invalid invocation of Python command object.")); - if (! PyObject_HasAttr ((PyObject *) obj, complete_cst)) - { - /* If there is no complete method, don't error -- instead, just - say that there are no completions. */ - goto done; - } - - textobj = PyUnicode_Decode (text, strlen (text), host_charset (), NULL); - if (! textobj) - error (_("Could not convert argument to Python string.")); - wordobj = PyUnicode_Decode (word, strlen (word), host_charset (), NULL); - if (! wordobj) - error (_("Could not convert argument to Python string.")); - - resultobj = PyObject_CallMethodObjArgs ((PyObject *) obj, complete_cst, - textobj, wordobj, NULL); - Py_DECREF (textobj); - Py_DECREF (wordobj); - if (! resultobj) - { - /* Just swallow errors here. */ - PyErr_Clear (); - goto done; - } - make_cleanup_py_decref (resultobj); - - result = NULL; - if (PySequence_Check (resultobj)) - { - Py_ssize_t i, len = PySequence_Size (resultobj); - Py_ssize_t out; - if (len < 0) - goto done; - - result = (char **) xmalloc ((len + 1) * sizeof (char *)); - for (i = out = 0; i < len; ++i) - { - int l; - PyObject *elt = PySequence_GetItem (resultobj, i); - if (elt == NULL || ! gdbpy_is_string (elt)) - { - /* Skip problem elements. */ - PyErr_Clear (); - continue; - } - result[out] = python_string_to_host_string (elt); - ++out; - } - result[out] = NULL; - } - else if (PyInt_Check (resultobj)) - { - /* User code may also return one of the completion constants, - thus requesting that sort of completion. */ - long value = PyInt_AsLong (resultobj); - if (value >= 0 && value < (long) N_COMPLETERS) - result = completers[value].completer (command, text, word); - } - - done: - - do_cleanups (cleanup); - - return result; -} - -/* Helper for cmdpy_init which locates the command list to use and - pulls out the command name. - - TEXT is the command name list. The final word in the list is the - name of the new command. All earlier words must be existing prefix - commands. - - *BASE_LIST is set to the final prefix command's list of - *sub-commands. - - This function returns the xmalloc()d name of the new command. On - error sets the Python error and returns NULL. */ -static char * -parse_command_name (char *text, struct cmd_list_element ***base_list) -{ - struct cmd_list_element *elt; - int len = strlen (text); - int i, lastchar; - char *prefix_text; - char *result; - - /* Skip trailing whitespace. */ - for (i = len - 1; i >= 0 && (text[i] == ' ' || text[i] == '\t'); --i) - ; - if (i < 0) - { - PyErr_SetString (PyExc_RuntimeError, _("no command name found")); - return NULL; - } - lastchar = i; - - /* Find first character of the final word. */ - for (; i > 0 && (isalnum (text[i - 1]) - || text[i - 1] == '-' - || text[i - 1] == '_'); - --i) - ; - result = xmalloc (lastchar - i + 2); - memcpy (result, &text[i], lastchar - i + 1); - result[lastchar - i + 1] = '\0'; - - /* Skip whitespace again. */ - for (--i; i >= 0 && (text[i] == ' ' || text[i] == '\t'); --i) - ; - if (i < 0) - { - *base_list = &cmdlist; - return result; - } - - prefix_text = xmalloc (i + 2); - memcpy (prefix_text, text, i + 1); - prefix_text[i + 1] = '\0'; - - text = prefix_text; - elt = lookup_cmd_1 (&text, cmdlist, NULL, 1); - if (!elt || elt == (struct cmd_list_element *) -1) - { - PyErr_Format (PyExc_RuntimeError, _("could not find command prefix %s"), - prefix_text); - xfree (prefix_text); - xfree (result); - return NULL; - } - - if (elt->prefixlist) - { - xfree (prefix_text); - *base_list = elt->prefixlist; - return result; - } - - PyErr_Format (PyExc_RuntimeError, _("'%s' is not a prefix command"), - prefix_text); - xfree (prefix_text); - xfree (result); - return NULL; -} - -/* Object initializer; sets up gdb-side structures for command. - - Use: __init__(NAME, COMMAND_CLASS [, COMPLETER_CLASS][, PREFIX]]). - - NAME is the name of the command. It may consist of multiple words, - in which case the final word is the name of the new command, and - earlier words must be prefix commands. - - COMMAND_CLASS is the kind of command. It should be one of the COMMAND_* - constants defined in the gdb module. - - COMPLETER_CLASS is the kind of completer. If not given, the - "complete" method will be used. Otherwise, it should be one of the - COMPLETE_* constants defined in the gdb module. - - If PREFIX is True, then this command is a prefix command. - - The documentation for the command is taken from the doc string for - the python class. - -*/ -static int -cmdpy_init (PyObject *self, PyObject *args, PyObject *kw) -{ - cmdpy_object *obj = (cmdpy_object *) self; - char *name; - int cmdtype; - int completetype = -1; - char *docstring = NULL; - volatile struct gdb_exception except; - struct cmd_list_element **cmd_list; - char *cmd_name, *pfx_name; - static char *keywords[] = { "name", "command_class", "completer_class", - "prefix", NULL }; - PyObject *is_prefix = NULL; - int cmp; - - 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_ParseTupleAndKeywords (args, kw, "si|iO", keywords, &name, &cmdtype, - &completetype, &is_prefix)) - 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; - } - - if (completetype < -1 || completetype >= (int) N_COMPLETERS) - { - PyErr_Format (PyExc_RuntimeError, _("invalid completion type argument")); - return -1; - } - - cmd_name = parse_command_name (name, &cmd_list); - if (! cmd_name) - return -1; - - pfx_name = NULL; - if (is_prefix != NULL) - { - cmp = PyObject_IsTrue (is_prefix); - if (cmp == 1) - { - int i, out; - - /* Make a normalized form of the command name. */ - pfx_name = xmalloc (strlen (name) + 2); - - i = 0; - out = 0; - while (name[i]) - { - /* Skip whitespace. */ - while (name[i] == ' ' || name[i] == '\t') - ++i; - /* Copy non-whitespace characters. */ - while (name[i] && name[i] != ' ' && name[i] != '\t') - pfx_name[out++] = name[i++]; - /* Add a single space after each word -- including the final - word. */ - pfx_name[out++] = ' '; - } - pfx_name[out] = '\0'; - } - else if (cmp < 0) - return -1; - } - if (PyObject_HasAttr (self, gdbpy_doc_cst)) - { - PyObject *ds_obj = PyObject_GetAttr (self, gdbpy_doc_cst); - if (ds_obj && gdbpy_is_string (ds_obj)) - docstring = python_string_to_host_string (ds_obj); - } - if (! docstring) - docstring = xstrdup (_("This command is not documented.")); - - Py_INCREF (self); - - TRY_CATCH (except, RETURN_MASK_ALL) - { - struct cmd_list_element *cmd; - - if (pfx_name) - { - int allow_unknown; - - /* If we have our own "invoke" method, then allow unknown - sub-commands. */ - allow_unknown = PyObject_HasAttr (self, invoke_cst); - cmd = add_prefix_cmd (cmd_name, (enum command_class) cmdtype, - NULL, docstring, &obj->sub_list, - pfx_name, allow_unknown, cmd_list); - } - else - cmd = add_cmd (cmd_name, (enum command_class) cmdtype, NULL, - docstring, cmd_list); - - /* There appears to be no API to set this. */ - cmd->func = cmdpy_function; - cmd->destroyer = cmdpy_destroyer; - - obj->command = cmd; - set_cmd_context (cmd, self); - set_cmd_completer (cmd, ((completetype == -1) ? cmdpy_completer - : completers[completetype].completer)); - } - if (except.reason < 0) - { - xfree (cmd_name); - xfree (docstring); - xfree (pfx_name); - Py_DECREF (self); - PyErr_Format (except.reason == RETURN_QUIT - ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, - "%s", except.message); - return -1; - } - return 0; -} - - - -/* Initialize the 'commands' code. */ -void -gdbpy_initialize_commands (void) -{ - int i; - - if (PyType_Ready (&cmdpy_object_type) < 0) - return; - - /* Note: alias and user are 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_RUNNING", class_run) < 0 - || PyModule_AddIntConstant (gdb_module, "COMMAND_DATA", 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_STATUS", class_info) < 0 - || PyModule_AddIntConstant (gdb_module, "COMMAND_BREAKPOINTS", - class_breakpoint) < 0 - || PyModule_AddIntConstant (gdb_module, "COMMAND_TRACEPOINTS", - class_trace) < 0 - || PyModule_AddIntConstant (gdb_module, "COMMAND_OBSCURE", - class_obscure) < 0 - || PyModule_AddIntConstant (gdb_module, "COMMAND_MAINTENANCE", - class_maintenance) < 0) - return; - - for (i = 0; i < N_COMPLETERS; ++i) - { - if (PyModule_AddIntConstant (gdb_module, completers[i].name, i) < 0) - return; - } - - Py_INCREF (&cmdpy_object_type); - PyModule_AddObject (gdb_module, "Command", - (PyObject *) &cmdpy_object_type); - - invoke_cst = PyString_FromString ("invoke"); - complete_cst = PyString_FromString ("complete"); -} - - - -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 */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - cmdpy_init, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew /* tp_new */ -}; diff --git a/gdb/python/python-frame.c b/gdb/python/python-frame.c deleted file mode 100644 index 279415c6eeb..00000000000 --- a/gdb/python/python-frame.c +++ /dev/null @@ -1,539 +0,0 @@ -/* Python interface to stack frames - - Copyright (C) 2008, 2009 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 . */ - -#include "defs.h" -#include "charset.h" -#include "block.h" -#include "frame.h" -#include "exceptions.h" -#include "symtab.h" -#include "stack.h" -#include "value.h" -#include "python-internal.h" - -typedef struct { - PyObject_HEAD - struct frame_id frame_id; - struct gdbarch *gdbarch; - - /* Marks that the FRAME_ID member actually holds the ID of the frame next - to this, and not this frames' ID itself. This is a hack to permit Python - frame objects which represent invalid frames (i.e., the last frame_info - in a corrupt stack). The problem arises from the fact that this code - relies on FRAME_ID to uniquely identify a frame, which is not always true - for the last "frame" in a corrupt stack (it can have a null ID, or the same - ID as the previous frame). Whenever get_prev_frame returns NULL, we - record the frame_id of the next frame and set FRAME_ID_IS_NEXT to 1. */ - int frame_id_is_next; -} frame_object; - -/* Require a valid frame. This must be called inside a TRY_CATCH, or - another context in which a gdb exception is allowed. */ -#define FRAPY_REQUIRE_VALID(frame_obj, frame) \ - do { \ - frame = frame_object_to_frame_info (frame_obj); \ - if (frame == NULL) \ - error ("Frame is invalid."); \ - } while (0) - -static PyTypeObject frame_object_type; - -/* Returns the frame_info object corresponding to the given Python Frame - object. If the frame doesn't exist anymore (the frame id doesn't - correspond to any frame in the inferior), returns NULL. */ - -static struct frame_info * -frame_object_to_frame_info (frame_object *frame_obj) -{ - struct frame_info *frame; - - frame = frame_find_by_id (frame_obj->frame_id); - if (frame == NULL) - return NULL; - - if (frame_obj->frame_id_is_next) - frame = get_prev_frame (frame); - - return frame; -} - -/* Called by the Python interpreter to obtain string representation - of the object. */ - -static PyObject * -frapy_str (PyObject *self) -{ - char *s; - PyObject *result; - struct ui_file *strfile; - - strfile = mem_fileopen (); - fprint_frame_id (strfile, ((frame_object *) self)->frame_id); - s = ui_file_xstrdup (strfile, NULL); - result = PyString_FromString (s); - xfree (s); - - return result; -} - -/* Implementation of gdb.Frame.is_valid (self) -> Boolean. - Returns True if the frame corresponding to the frame_id of this - object still exists in the inferior. */ - -static PyObject * -frapy_is_valid (PyObject *self, PyObject *args) -{ - struct frame_info *frame; - - frame = frame_object_to_frame_info ((frame_object *) self); - if (frame == NULL) - Py_RETURN_FALSE; - - Py_RETURN_TRUE; -} - -/* Implementation of gdb.Frame.name (self) -> String. - Returns the name of the function corresponding to this frame. */ - -static PyObject * -frapy_name (PyObject *self, PyObject *args) -{ - struct frame_info *frame; - char *name; - enum language lang; - PyObject *result; - volatile struct gdb_exception except; - - TRY_CATCH (except, RETURN_MASK_ALL) - { - FRAPY_REQUIRE_VALID ((frame_object *) self, frame); - - find_frame_funname (frame, &name, &lang); - } - GDB_PY_HANDLE_EXCEPTION (except); - - if (name) - result = PyUnicode_Decode (name, strlen (name), host_charset (), NULL); - else - { - result = Py_None; - Py_INCREF (Py_None); - } - - return result; -} - -/* Implementation of gdb.Frame.type (self) -> Integer. - Returns the frame type, namely one of the gdb.*_FRAME constants. */ - -static PyObject * -frapy_type (PyObject *self, PyObject *args) -{ - struct frame_info *frame; - enum frame_type type = NORMAL_FRAME;/* Initialize to appease gcc warning. */ - volatile struct gdb_exception except; - - TRY_CATCH (except, RETURN_MASK_ALL) - { - FRAPY_REQUIRE_VALID ((frame_object *) self, frame); - - type = get_frame_type (frame); - } - GDB_PY_HANDLE_EXCEPTION (except); - - return PyInt_FromLong (type); -} - -/* Implementation of gdb.Frame.unwind_stop_reason (self) -> Integer. - Returns one of the gdb.FRAME_UNWIND_* constants. */ - -static PyObject * -frapy_unwind_stop_reason (PyObject *self, PyObject *args) -{ - struct frame_info *frame = NULL; /* Initialize to appease gcc warning. */ - volatile struct gdb_exception except; - enum unwind_stop_reason stop_reason; - - TRY_CATCH (except, RETURN_MASK_ALL) - { - FRAPY_REQUIRE_VALID ((frame_object *) self, frame); - } - GDB_PY_HANDLE_EXCEPTION (except); - - stop_reason = get_frame_unwind_stop_reason (frame); - - return PyInt_FromLong (stop_reason); -} - -/* Implementation of gdb.Frame.pc (self) -> Long. - Returns the frame's resume address. */ - -static PyObject * -frapy_pc (PyObject *self, PyObject *args) -{ - CORE_ADDR pc = 0; /* Initialize to appease gcc warning. */ - struct frame_info *frame; - volatile struct gdb_exception except; - - TRY_CATCH (except, RETURN_MASK_ALL) - { - FRAPY_REQUIRE_VALID ((frame_object *) self, frame); - - pc = get_frame_pc (frame); - } - GDB_PY_HANDLE_EXCEPTION (except); - - return PyLong_FromUnsignedLongLong (pc); -} - -/* Convert a frame_info struct to a Python Frame object. - Sets a Python exception and returns NULL on error. */ - -static frame_object * -frame_info_to_frame_object (struct frame_info *frame) -{ - frame_object *frame_obj; - - frame_obj = PyObject_New (frame_object, &frame_object_type); - if (frame_obj == NULL) - { - PyErr_SetString (PyExc_MemoryError, "Could not allocate frame object."); - return NULL; - } - - /* Try to get the previous frame, to determine if this is the last frame - in a corrupt stack. If so, we need to store the frame_id of the next - frame and not of this one (which is possibly invalid). */ - if (get_prev_frame (frame) == NULL - && get_frame_unwind_stop_reason (frame) != UNWIND_NO_REASON - && get_next_frame (frame) != NULL) - { - frame_obj->frame_id = get_frame_id (get_next_frame (frame)); - frame_obj->frame_id_is_next = 1; - } - else - { - frame_obj->frame_id = get_frame_id (frame); - frame_obj->frame_id_is_next = 0; - } - - frame_obj->gdbarch = get_frame_arch (frame); - - return frame_obj; -} - -/* Implementation of gdb.Frame.older (self) -> gdb.Frame. - Returns the frame immediately older (outer) to this frame, or None if - there isn't one. */ - -static PyObject * -frapy_older (PyObject *self, PyObject *args) -{ - struct frame_info *frame, *prev; - volatile struct gdb_exception except; - PyObject *prev_obj = NULL; /* Initialize to appease gcc warning. */ - - TRY_CATCH (except, RETURN_MASK_ALL) - { - FRAPY_REQUIRE_VALID ((frame_object *) self, frame); - - prev = get_prev_frame (frame); - if (prev) - prev_obj = (PyObject *) frame_info_to_frame_object (prev); - else - { - Py_INCREF (Py_None); - prev_obj = Py_None; - } - } - GDB_PY_HANDLE_EXCEPTION (except); - - return prev_obj; -} - -/* Implementation of gdb.Frame.newer (self) -> gdb.Frame. - Returns the frame immediately newer (inner) to this frame, or None if - there isn't one. */ - -static PyObject * -frapy_newer (PyObject *self, PyObject *args) -{ - struct frame_info *frame, *next; - volatile struct gdb_exception except; - PyObject *next_obj = NULL; /* Initialize to appease gcc warning. */ - - TRY_CATCH (except, RETURN_MASK_ALL) - { - FRAPY_REQUIRE_VALID ((frame_object *) self, frame); - - next = get_next_frame (frame); - if (next) - next_obj = (PyObject *) frame_info_to_frame_object (next); - else - { - Py_INCREF (Py_None); - next_obj = Py_None; - } - } - GDB_PY_HANDLE_EXCEPTION (except); - - return next_obj; -} - -/* Implementation of gdb.Frame.read_var_value (self, variable) -> gdb.Value. - Returns the value of the given variable in this frame. The argument must be - a string. Returns None if GDB can't find the specified variable. */ - -static PyObject * -frapy_read_var (PyObject *self, PyObject *args) -{ - struct frame_info *frame; - PyObject *sym_obj; - struct symbol *var = NULL; /* gcc-4.3.2 false warning. */ - struct value *val = NULL; - volatile struct gdb_exception except; - - if (!PyArg_ParseTuple (args, "O", &sym_obj)) - return NULL; - - if (gdbpy_is_string (sym_obj)) - { - char *var_name; - struct block *block = NULL; - struct cleanup *cleanup; - volatile struct gdb_exception except; - - var_name = python_string_to_target_string (sym_obj); - if (!var_name) - return NULL; - cleanup = make_cleanup (xfree, var_name); - - TRY_CATCH (except, RETURN_MASK_ALL) - { - FRAPY_REQUIRE_VALID ((frame_object *) self, frame); - - block = block_for_pc (get_frame_address_in_block (frame)); - var = lookup_symbol (var_name, block, VAR_DOMAIN, NULL); - } - GDB_PY_HANDLE_EXCEPTION (except); - - if (!var) - { - PyErr_Format (PyExc_ValueError, - _("variable '%s' not found"), var_name); - do_cleanups (cleanup); - - return NULL; - } - - do_cleanups (cleanup); - } - else - { - PyErr_SetString (PyExc_TypeError, - _("argument must be a symbol or string")); - return NULL; - } - - TRY_CATCH (except, RETURN_MASK_ALL) - { - FRAPY_REQUIRE_VALID ((frame_object *) self, frame); - - val = read_var_value (var, frame); - } - GDB_PY_HANDLE_EXCEPTION (except); - - if (val) - return value_to_value_object (val); - - Py_RETURN_NONE; -} - -/* Implementation of gdb.selected_frame () -> gdb.Frame. - Returns the selected frame object. */ - -PyObject * -gdbpy_selected_frame (PyObject *self, PyObject *args) -{ - struct frame_info *frame; - frame_object *frame_obj = NULL; /* Initialize to appease gcc warning. */ - volatile struct gdb_exception except; - - TRY_CATCH (except, RETURN_MASK_ALL) - { - frame = get_selected_frame ("No frame is currently selected."); - frame_obj = frame_info_to_frame_object (frame); - } - GDB_PY_HANDLE_EXCEPTION (except); - - return (PyObject *) frame_obj; -} - -/* Implementation of gdb.stop_reason_string (Integer) -> String. - Return a string explaining the unwind stop reason. */ - -PyObject * -gdbpy_frame_stop_reason_string (PyObject *self, PyObject *args) -{ - int reason; - const char *str; - - if (!PyArg_ParseTuple (args, "i", &reason)) - return NULL; - - if (reason < 0 || reason > UNWIND_NO_SAVED_PC) - { - PyErr_SetString (PyExc_ValueError, "Invalid frame stop reason."); - return NULL; - } - - str = frame_stop_reason_string (reason); - return PyUnicode_Decode (str, strlen (str), host_charset (), NULL); -} - -/* Implements the equality comparison for Frame objects. - All other comparison operators will throw a TypeError Python exception, - as they aren't valid for frames. */ - -static PyObject * -frapy_richcompare (PyObject *self, PyObject *other, int op) -{ - int result; - - if (!PyObject_TypeCheck (other, &frame_object_type) - || (op != Py_EQ && op != Py_NE)) - { - Py_INCREF (Py_NotImplemented); - return Py_NotImplemented; - } - - if (frame_id_eq (((frame_object *) self)->frame_id, - ((frame_object *) other)->frame_id)) - result = Py_EQ; - else - result = Py_NE; - - if (op == result) - Py_RETURN_TRUE; - Py_RETURN_FALSE; -} - -/* Sets up the Frame API in the gdb module. */ - -void -gdbpy_initialize_frames (void) -{ - if (PyType_Ready (&frame_object_type) < 0) - return; - - /* Note: These would probably be best exposed as class attributes of Frame, - but I don't know how to do it except by messing with the type's dictionary. - That seems too messy. */ - PyModule_AddIntConstant (gdb_module, "NORMAL_FRAME", NORMAL_FRAME); - PyModule_AddIntConstant (gdb_module, "DUMMY_FRAME", DUMMY_FRAME); - PyModule_AddIntConstant (gdb_module, "SIGTRAMP_FRAME", SIGTRAMP_FRAME); - PyModule_AddIntConstant (gdb_module, "SENTINEL_FRAME", SENTINEL_FRAME); - PyModule_AddIntConstant (gdb_module, - "FRAME_UNWIND_NO_REASON", UNWIND_NO_REASON); - PyModule_AddIntConstant (gdb_module, - "FRAME_UNWIND_NULL_ID", UNWIND_NULL_ID); - PyModule_AddIntConstant (gdb_module, - "FRAME_UNWIND_FIRST_ERROR", UNWIND_FIRST_ERROR); - PyModule_AddIntConstant (gdb_module, - "FRAME_UNWIND_INNER_ID", UNWIND_INNER_ID); - PyModule_AddIntConstant (gdb_module, - "FRAME_UNWIND_SAME_ID", UNWIND_SAME_ID); - PyModule_AddIntConstant (gdb_module, - "FRAME_UNWIND_NO_SAVED_PC", UNWIND_NO_SAVED_PC); - - Py_INCREF (&frame_object_type); - PyModule_AddObject (gdb_module, "Frame", (PyObject *) &frame_object_type); -} - - - -static PyMethodDef frame_object_methods[] = { - { "is_valid", frapy_is_valid, METH_NOARGS, - "is_valid () -> Boolean.\n\ -Return true if this frame is valid, false if not." }, - { "name", frapy_name, METH_NOARGS, - "name () -> String.\n\ -Return the function name of the frame, or None if it can't be determined." }, - { "type", frapy_type, METH_NOARGS, - "type () -> Integer.\n\ -Return the type of the frame." }, - { "unwind_stop_reason", frapy_unwind_stop_reason, METH_NOARGS, - "unwind_stop_reason () -> Integer.\n\ -Return the reason why it's not possible to find frames older than this." }, - { "pc", frapy_pc, METH_NOARGS, - "pc () -> Long.\n\ -Return the frame's resume address." }, - { "older", frapy_older, METH_NOARGS, - "older () -> gdb.Frame.\n\ -Return the frame that called this frame." }, - { "newer", frapy_newer, METH_NOARGS, - "newer () -> gdb.Frame.\n\ -Return the frame called by this frame." }, - { "read_var", frapy_read_var, METH_VARARGS, - "read_var (variable) -> gdb.Value.\n\ -Return the value of the variable in this frame." }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject frame_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /* ob_size */ - "gdb.Frame", /* tp_name */ - sizeof (frame_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 */ - frapy_str, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - "GDB frame object", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - frapy_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - frame_object_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew /* tp_new */ -}; diff --git a/gdb/python/python-function.c b/gdb/python/python-function.c deleted file mode 100644 index 8a5abaff9d0..00000000000 --- a/gdb/python/python-function.c +++ /dev/null @@ -1,180 +0,0 @@ -/* Convenience functions implemented in Python. - - Copyright (C) 2008, 2009 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 . */ - - -#include "defs.h" -#include "value.h" -#include "exceptions.h" -#include "python-internal.h" -#include "charset.h" -#include "gdbcmd.h" -#include "cli/cli-decode.h" -#include "completer.h" -#include "expression.h" -#include "language.h" - -static PyTypeObject fnpy_object_type; - - - -static PyObject * -convert_values_to_python (int argc, struct value **argv) -{ - int i; - PyObject *result = PyTuple_New (argc); - for (i = 0; i < argc; ++i) - { - PyObject *elt = value_to_value_object (argv[i]); - if (! elt) - { - Py_DECREF (result); - error (_("Could not convert value to Python object.")); - } - PyTuple_SetItem (result, i, elt); - } - return result; -} - -/* Call a Python function object's invoke method. */ - -static struct value * -fnpy_call (struct gdbarch *gdbarch, const struct language_defn *language, - void *cookie, int argc, struct value **argv) -{ - int i; - struct value *value = NULL; - PyObject *result, *callable, *args; - struct cleanup *cleanup; - - cleanup = ensure_python_env (gdbarch, language); - - args = convert_values_to_python (argc, argv); - - callable = PyObject_GetAttrString ((PyObject *) cookie, "invoke"); - if (! callable) - { - Py_DECREF (args); - error (_("No method named 'invoke' in object.")); - } - - result = PyObject_Call (callable, args, NULL); - Py_DECREF (callable); - Py_DECREF (args); - - if (!result) - { - gdbpy_print_stack (); - error (_("Error while executing Python code.")); - } - - value = convert_value_from_python (result); - if (value == NULL) - { - Py_DECREF (result); - gdbpy_print_stack (); - error (_("Error while executing Python code.")); - } - - Py_DECREF (result); - do_cleanups (cleanup); - - return value; -} - -/* Initializer for a Function object. It takes one argument, the name - of the function. */ - -static int -fnpy_init (PyObject *self, PyObject *args, PyObject *kwds) -{ - char *name, *docstring = NULL; - if (! PyArg_ParseTuple (args, "s", &name)) - return -1; - Py_INCREF (self); - - if (PyObject_HasAttrString (self, "__doc__")) - { - PyObject *ds_obj = PyObject_GetAttrString (self, "__doc__"); - if (ds_obj && gdbpy_is_string (ds_obj)) - /* Nothing ever frees this. */ - docstring = python_string_to_host_string (ds_obj); - } - if (! docstring) - docstring = _("This function is not documented."); - - add_internal_function (name, docstring, fnpy_call, self); - return 0; -} - -/* Initialize internal function support. */ - -void -gdbpy_initialize_functions (void) -{ - if (PyType_Ready (&fnpy_object_type) < 0) - return; - - Py_INCREF (&fnpy_object_type); - PyModule_AddObject (gdb_module, "Function", (PyObject *) &fnpy_object_type); -} - - - -static PyTypeObject fnpy_object_type = -{ - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ - "gdb.Function", /*tp_name*/ - sizeof (PyObject), /*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 function object", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - fnpy_init, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew /* tp_new */ -}; diff --git a/gdb/python/python-objfile.c b/gdb/python/python-objfile.c deleted file mode 100644 index a483d3371a1..00000000000 --- a/gdb/python/python-objfile.c +++ /dev/null @@ -1,230 +0,0 @@ -/* Python interface to objfiles. - - Copyright (C) 2008, 2009 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 . */ - -#include "defs.h" -#include "python-internal.h" -#include "charset.h" -#include "objfiles.h" -#include "language.h" - -typedef struct -{ - PyObject_HEAD - - /* The corresponding objfile. */ - struct objfile *objfile; - - /* The pretty-printer list of functions. */ - PyObject *printers; -} objfile_object; - -static PyTypeObject objfile_object_type; - -static const struct objfile_data *objfpy_objfile_data_key; - - - -/* An Objfile method which returns the objfile's file name, or None. */ -static PyObject * -objfpy_get_filename (PyObject *self, void *closure) -{ - objfile_object *obj = (objfile_object *) self; - if (obj->objfile && obj->objfile->name) - return PyString_Decode (obj->objfile->name, strlen (obj->objfile->name), - host_charset (), NULL); - Py_RETURN_NONE; -} - -static void -objfpy_dealloc (PyObject *o) -{ - objfile_object *self = (objfile_object *) o; - Py_XDECREF (self->printers); - self->ob_type->tp_free ((PyObject *) self); -} - -static PyObject * -objfpy_new (PyTypeObject *type, PyObject *args, PyObject *keywords) -{ - objfile_object *self = (objfile_object *) type->tp_alloc (type, 0); - if (self) - { - self->objfile = NULL; - - self->printers = PyList_New (0); - if (!self->printers) - { - Py_DECREF (self); - return NULL; - } - } - return (PyObject *) self; -} - -PyObject * -objfpy_get_printers (PyObject *o, void *ignore) -{ - objfile_object *self = (objfile_object *) o; - Py_INCREF (self->printers); - return self->printers; -} - -static int -objfpy_set_printers (PyObject *o, PyObject *value, void *ignore) -{ - PyObject *tmp; - objfile_object *self = (objfile_object *) o; - if (! value) - { - PyErr_SetString (PyExc_TypeError, - "cannot delete the pretty_printers attribute"); - return -1; - } - - if (! PyList_Check (value)) - { - PyErr_SetString (PyExc_TypeError, - "the pretty_printers attribute must be a list"); - return -1; - } - - /* Take care in case the LHS and RHS are related somehow. */ - tmp = self->printers; - Py_INCREF (value); - self->printers = value; - Py_XDECREF (tmp); - - return 0; -} - - - -/* Clear the OBJFILE pointer in an Objfile object and remove the - reference. */ -static void -clean_up_objfile (struct objfile *objfile, void *datum) -{ - struct cleanup *cleanup; - objfile_object *object = datum; - - cleanup = ensure_python_env (get_objfile_arch (objfile), current_language); - object->objfile = NULL; - Py_DECREF ((PyObject *) object); - do_cleanups (cleanup); -} - -/* Return a borrowed reference to the Python object of type Objfile - representing OBJFILE. If the object has already been created, - return it. Otherwise, create it. Return NULL and set the Python - error on failure. */ -PyObject * -objfile_to_objfile_object (struct objfile *objfile) -{ - objfile_object *object; - - object = objfile_data (objfile, objfpy_objfile_data_key); - if (!object) - { - object = PyObject_New (objfile_object, &objfile_object_type); - if (object) - { - PyObject *dict; - - object->objfile = objfile; - - object->printers = PyList_New (0); - if (!object->printers) - { - Py_DECREF (object); - return NULL; - } - - set_objfile_data (objfile, objfpy_objfile_data_key, object); - } - } - - return (PyObject *) object; -} - -void -gdbpy_initialize_objfile (void) -{ - objfpy_objfile_data_key - = register_objfile_data_with_cleanup (clean_up_objfile); - - if (PyType_Ready (&objfile_object_type) < 0) - return; - - Py_INCREF (&objfile_object_type); - PyModule_AddObject (gdb_module, "Objfile", (PyObject *) &objfile_object_type); -} - - - -static PyGetSetDef objfile_getset[] = -{ - { "filename", objfpy_get_filename, NULL, - "The objfile's filename, or None.", NULL }, - { "pretty_printers", objfpy_get_printers, objfpy_set_printers, - "Pretty printers.", NULL }, - { NULL } -}; - -static PyTypeObject objfile_object_type = -{ - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ - "gdb.Objfile", /*tp_name*/ - sizeof (objfile_object), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - objfpy_dealloc, /*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, /*tp_flags*/ - "GDB objfile object", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - objfile_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - objfpy_new, /* tp_new */ -}; diff --git a/gdb/python/python-prettyprint.c b/gdb/python/python-prettyprint.c deleted file mode 100644 index 5d696c86d3d..00000000000 --- a/gdb/python/python-prettyprint.c +++ /dev/null @@ -1,612 +0,0 @@ -/* Python pretty-printing - - Copyright (C) 2008, 2009 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 . */ - -#include "defs.h" -#include "exceptions.h" -#include "objfiles.h" -#include "symtab.h" -#include "language.h" -#include "valprint.h" - -#include "python.h" - -#ifdef HAVE_PYTHON -#include "python-internal.h" - - -/* Helper function for find_pretty_printer which iterates over a list, - calls each function and inspects output. This will return a - printer object if one recognizes VALUE. If no printer is found, it - will return None. On error, it will set the Python error and - return NULL. */ -static PyObject * -search_pp_list (PyObject *list, PyObject *value) -{ - Py_ssize_t pp_list_size, list_index; - PyObject *function, *printer = NULL; - - pp_list_size = PyList_Size (list); - for (list_index = 0; list_index < pp_list_size; list_index++) - { - function = PyList_GetItem (list, list_index); - if (! function) - return NULL; - - printer = PyObject_CallFunctionObjArgs (function, value, NULL); - if (! printer) - return NULL; - else if (printer != Py_None) - return printer; - - Py_DECREF (printer); - } - - Py_RETURN_NONE; -} - -/* Find the pretty-printing constructor function for VALUE. If no - pretty-printer exists, return None. If one exists, return a new - reference. On error, set the Python error and return NULL. */ -static PyObject * -find_pretty_printer (PyObject *value) -{ - PyObject *pp_list = NULL; - PyObject *function = NULL; - struct objfile *obj; - volatile struct gdb_exception except; - - /* Look at the pretty-printer dictionary for each objfile. */ - ALL_OBJFILES (obj) - { - PyObject *objf = objfile_to_objfile_object (obj); - if (!objf) - { - /* Ignore the error and continue. */ - PyErr_Clear (); - continue; - } - - pp_list = objfpy_get_printers (objf, NULL); - function = search_pp_list (pp_list, value); - - /* If there is an error in any objfile list, abort the search and - exit. */ - if (! function) - { - Py_XDECREF (pp_list); - return NULL; - } - - if (function != Py_None) - goto done; - - Py_DECREF (function); - Py_XDECREF (pp_list); - } - - pp_list = NULL; - /* Fetch the global pretty printer dictionary. */ - if (! PyObject_HasAttrString (gdb_module, "pretty_printers")) - { - function = Py_None; - Py_INCREF (function); - goto done; - } - pp_list = PyObject_GetAttrString (gdb_module, "pretty_printers"); - if (! pp_list) - goto done; - if (! PyList_Check (pp_list)) - goto done; - - function = search_pp_list (pp_list, value); - - done: - Py_XDECREF (pp_list); - - return function; -} -/* Pretty-print a single value, via the printer object PRINTER. - If the function returns a string, a PyObject containing the string - is returned. Otherwise, if the function returns a value, - *OUT_VALUE is set to the value, and NULL is returned. On error, - *OUT_VALUE is set to NULL, and NULL is returned. */ -static PyObject * -pretty_print_one_value (PyObject *printer, struct value **out_value) -{ - volatile struct gdb_exception except; - PyObject *result = NULL; - - *out_value = NULL; - TRY_CATCH (except, RETURN_MASK_ALL) - { - result = PyObject_CallMethodObjArgs (printer, gdbpy_to_string_cst, NULL); - if (result) - { - if (! gdbpy_is_string (result)) - { - *out_value = convert_value_from_python (result); - if (PyErr_Occurred ()) - *out_value = NULL; - Py_DECREF (result); - result = NULL; - } - } - } - - return result; -} - -/* Return the display hint for the object printer, PRINTER. Return - NULL if there is no display_hint method, or if the method did not - return a string. On error, print stack trace and return NULL. On - success, return an xmalloc()d string. */ -char * -gdbpy_get_display_hint (PyObject *printer) -{ - PyObject *hint; - char *result = NULL; - - if (! PyObject_HasAttr (printer, gdbpy_display_hint_cst)) - return NULL; - - hint = PyObject_CallMethodObjArgs (printer, gdbpy_display_hint_cst, NULL); - if (gdbpy_is_string (hint)) - result = python_string_to_host_string (hint); - if (hint) - Py_DECREF (hint); - else - gdbpy_print_stack (); - - return result; -} - -/* Helper for apply_val_pretty_printer which calls to_string and - formats the result. */ -static void -print_string_repr (PyObject *printer, const char *hint, - struct ui_file *stream, int recurse, - const struct value_print_options *options, - const struct language_defn *language, - struct gdbarch *gdbarch) -{ - struct value *replacement = NULL; - PyObject *py_str = NULL; - - py_str = pretty_print_one_value (printer, &replacement); - if (py_str) - { - PyObject *string = python_string_to_target_python_string (py_str); - if (string) - { - gdb_byte *output = PyString_AsString (string); - int len = PyString_Size (string); - - if (hint && !strcmp (hint, "string")) - LA_PRINT_STRING (stream, builtin_type (gdbarch)->builtin_char, - output, len, 0, options); - else - fputs_filtered (output, stream); - Py_DECREF (string); - } - else - gdbpy_print_stack (); - Py_DECREF (py_str); - } - else if (replacement) - common_val_print (replacement, stream, recurse, options, language); - else - gdbpy_print_stack (); -} - -static void -py_restore_tstate (void *p) -{ - PyFrameObject *frame = p; - PyThreadState *tstate = PyThreadState_GET (); - tstate->frame = frame; -} - -/* Create a dummy PyFrameObject, needed to work around - a Python-2.4 bug with generators. */ -static PyObject * -push_dummy_python_frame () -{ - PyObject *empty_string, *null_tuple, *globals; - PyCodeObject *code; - PyFrameObject *frame; - PyThreadState *tstate; - - empty_string = PyString_FromString (""); - if (!empty_string) - return NULL; - - null_tuple = PyTuple_New (0); - if (!null_tuple) - { - Py_DECREF (empty_string); - return NULL; - } - - code = PyCode_New (0, /* argcount */ - 0, /* nlocals */ - 0, /* stacksize */ - 0, /* flags */ - empty_string, /* code */ - null_tuple, /* consts */ - null_tuple, /* names */ - null_tuple, /* varnames */ -#if PYTHON_API_VERSION >= 1010 - null_tuple, /* freevars */ - null_tuple, /* cellvars */ -#endif - empty_string, /* filename */ - empty_string, /* name */ - 1, /* firstlineno */ - empty_string /* lnotab */ - ); - - Py_DECREF (empty_string); - Py_DECREF (null_tuple); - - if (!code) - return NULL; - - globals = PyDict_New (); - if (!globals) - { - Py_DECREF (code); - return NULL; - } - - tstate = PyThreadState_GET (); - - frame = PyFrame_New (tstate, code, globals, NULL); - - Py_DECREF (globals); - Py_DECREF (code); - - if (!frame) - return NULL; - - tstate->frame = frame; - make_cleanup (py_restore_tstate, frame->f_back); - return (PyObject *) frame; -} - -/* Helper for apply_val_pretty_printer that formats children of the - printer, if any exist. */ -static void -print_children (PyObject *printer, const char *hint, - struct ui_file *stream, int recurse, - const struct value_print_options *options, - const struct language_defn *language) -{ - int is_map, is_array, done_flag, pretty; - unsigned int i; - PyObject *children, *iter, *frame; - struct cleanup *cleanups; - - if (! PyObject_HasAttr (printer, gdbpy_children_cst)) - return; - - /* If we are printing a map or an array, we want some special - formatting. */ - is_map = hint && ! strcmp (hint, "map"); - is_array = hint && ! strcmp (hint, "array"); - - children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst, - NULL); - if (! children) - { - gdbpy_print_stack (); - return; - } - - cleanups = make_cleanup_py_decref (children); - - iter = PyObject_GetIter (children); - if (!iter) - { - gdbpy_print_stack (); - goto done; - } - make_cleanup_py_decref (iter); - - /* Use the prettyprint_arrays option if we are printing an array, - and the pretty option otherwise. */ - pretty = is_array ? options->prettyprint_arrays : options->pretty; - - /* Manufacture a dummy Python frame to work around Python 2.4 bug, - where it insists on having a non-NULL tstate->frame when - a generator is called. */ - frame = push_dummy_python_frame (); - if (!frame) - { - gdbpy_print_stack (); - goto done; - } - make_cleanup_py_decref (frame); - - done_flag = 0; - for (i = 0; i < options->print_max; ++i) - { - PyObject *py_v, *item = PyIter_Next (iter); - char *name; - struct cleanup *inner_cleanup; - - if (! item) - { - if (PyErr_Occurred ()) - gdbpy_print_stack (); - /* Set a flag so we can know whether we printed all the - available elements. */ - else - done_flag = 1; - break; - } - - if (! PyArg_ParseTuple (item, "sO", &name, &py_v)) - { - gdbpy_print_stack (); - Py_DECREF (item); - continue; - } - inner_cleanup = make_cleanup_py_decref (item); - - /* Print initial "{". For other elements, there are three - cases: - 1. Maps. Print a "," after each value element. - 2. Arrays. Always print a ",". - 3. Other. Always print a ",". */ - if (i == 0) - fputs_filtered (" = {", stream); - else if (! is_map || i % 2 == 0) - fputs_filtered (pretty ? "," : ", ", stream); - - /* In summary mode, we just want to print "= {...}" if there is - a value. */ - if (options->summary) - { - /* This increment tricks the post-loop logic to print what - we want. */ - ++i; - /* Likewise. */ - pretty = 0; - break; - } - - if (! is_map || i % 2 == 0) - { - if (pretty) - { - fputs_filtered ("\n", stream); - print_spaces_filtered (2 + 2 * recurse, stream); - } - else - wrap_here (n_spaces (2 + 2 *recurse)); - } - - if (is_map && i % 2 == 0) - fputs_filtered ("[", stream); - else if (is_array) - { - /* We print the index, not whatever the child method - returned as the name. */ - if (options->print_array_indexes) - fprintf_filtered (stream, "[%d] = ", i); - } - else if (! is_map) - { - fputs_filtered (name, stream); - fputs_filtered (" = ", stream); - } - - if (gdbpy_is_string (py_v)) - { - char *text = python_string_to_host_string (py_v); - if (! text) - gdbpy_print_stack (); - else - { - fputs_filtered (text, stream); - xfree (text); - } - } - else - { - struct value *value = convert_value_from_python (py_v); - - if (value == NULL) - { - gdbpy_print_stack (); - error (_("Error while executing Python code.")); - } - else - common_val_print (value, stream, recurse + 1, options, language); - } - - if (is_map && i % 2 == 0) - fputs_filtered ("] = ", stream); - - do_cleanups (inner_cleanup); - } - - if (i) - { - if (!done_flag) - { - if (pretty) - { - fputs_filtered ("\n", stream); - print_spaces_filtered (2 + 2 * recurse, stream); - } - fputs_filtered ("...", stream); - } - if (pretty) - { - fputs_filtered ("\n", stream); - print_spaces_filtered (2 * recurse, stream); - } - fputs_filtered ("}", stream); - } - - done: - do_cleanups (cleanups); -} - -int -apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr, - int embedded_offset, CORE_ADDR address, - struct ui_file *stream, int recurse, - const struct value_print_options *options, - const struct language_defn *language) -{ - struct gdbarch *gdbarch = get_type_arch (type); - PyObject *printer = NULL; - PyObject *val_obj = NULL; - struct value *value; - char *hint = NULL; - struct cleanup *cleanups; - int result = 0; - - cleanups = ensure_python_env (gdbarch, language); - - /* Instantiate the printer. */ - if (valaddr) - valaddr += embedded_offset; - value = value_from_contents_and_address (type, valaddr, address); - - val_obj = value_to_value_object (value); - if (! val_obj) - goto done; - - /* Find the constructor. */ - printer = find_pretty_printer (val_obj); - Py_DECREF (val_obj); - make_cleanup_py_decref (printer); - if (! printer || printer == Py_None) - goto done; - - /* If we are printing a map, we want some special formatting. */ - hint = gdbpy_get_display_hint (printer); - make_cleanup (free_current_contents, &hint); - - /* Print the section */ - print_string_repr (printer, hint, stream, recurse, options, language, - gdbarch); - print_children (printer, hint, stream, recurse, options, language); - result = 1; - - - done: - if (PyErr_Occurred ()) - gdbpy_print_stack (); - do_cleanups (cleanups); - return result; -} - - -/* Apply a pretty-printer for the varobj code. PRINTER_OBJ is the - print object. It must have a 'to_string' method (but this is - checked by varobj, not here) which takes no arguments and - returns a string. The printer will return a value and in the case - of a Python string being returned, this function will return a - PyObject containing the string. For any other type, *REPLACEMENT is - set to the replacement value and this function returns NULL. On - error, *REPLACEMENT is set to NULL and this function also returns - NULL. */ -PyObject * -apply_varobj_pretty_printer (PyObject *printer_obj, - struct value **replacement) -{ - int size = 0; - PyObject *py_str = NULL; - - *replacement = NULL; - py_str = pretty_print_one_value (printer_obj, replacement); - - if (*replacement == NULL && py_str == NULL) - gdbpy_print_stack (); - - return py_str; -} - -/* Find a pretty-printer object for the varobj module. Returns a new - reference to the object if successful; returns NULL if not. VALUE - is the value for which a printer tests to determine if it - can pretty-print the value. */ -PyObject * -gdbpy_get_varobj_pretty_printer (struct value *value) -{ - PyObject *val_obj; - PyObject *pretty_printer = NULL; - volatile struct gdb_exception except; - - TRY_CATCH (except, RETURN_MASK_ALL) - { - value = value_copy (value); - } - GDB_PY_HANDLE_EXCEPTION (except); - - val_obj = value_to_value_object (value); - if (! val_obj) - return NULL; - - pretty_printer = find_pretty_printer (val_obj); - Py_DECREF (val_obj); - return pretty_printer; -} - -/* A Python function which wraps find_pretty_printer and instantiates - the resulting class. This accepts a Value argument and returns a - pretty printer instance, or None. This function is useful as an - argument to the MI command -var-set-visualizer. */ -PyObject * -gdbpy_default_visualizer (PyObject *self, PyObject *args) -{ - PyObject *val_obj; - PyObject *cons, *printer = NULL; - struct value *value; - - if (! PyArg_ParseTuple (args, "O", &val_obj)) - return NULL; - value = value_object_to_value (val_obj); - if (! value) - { - PyErr_SetString (PyExc_TypeError, "argument must be a gdb.Value"); - return NULL; - } - - cons = find_pretty_printer (val_obj); - return cons; -} - -#else /* HAVE_PYTHON */ - -int -apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr, - int embedded_offset, CORE_ADDR address, - struct ui_file *stream, int recurse, - const struct value_print_options *options, - const struct language_defn *language) -{ - return 0; -} - -#endif /* HAVE_PYTHON */ diff --git a/gdb/python/python-type.c b/gdb/python/python-type.c deleted file mode 100644 index f23248c607b..00000000000 --- a/gdb/python/python-type.c +++ /dev/null @@ -1,799 +0,0 @@ -/* Python interface to types. - - Copyright (C) 2008, 2009 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 . */ - -#include "defs.h" -#include "value.h" -#include "exceptions.h" -#include "python-internal.h" -#include "charset.h" -#include "gdbtypes.h" -#include "cp-support.h" -#include "demangle.h" -#include "objfiles.h" -#include "language.h" - -typedef struct pyty_type_object -{ - PyObject_HEAD - struct type *type; - - /* If a Type object is associated with an objfile, it is kept on a - doubly-linked list, rooted in the objfile. This lets us copy the - underlying struct type when the objfile is deleted. */ - struct pyty_type_object *prev; - struct pyty_type_object *next; -} type_object; - -static PyTypeObject type_object_type; - -/* A Field object. */ -typedef struct pyty_field_object -{ - PyObject_HEAD - - /* Dictionary holding our attributes. */ - PyObject *dict; -} field_object; - -static PyTypeObject field_object_type; - -/* This is used to initialize various gdb.TYPE_ constants. */ -struct pyty_code -{ - /* The code. */ - enum type_code code; - /* The name. */ - const char *name; -}; - -#define ENTRY(X) { X, #X } - -static struct pyty_code pyty_codes[] = -{ - ENTRY (TYPE_CODE_PTR), - ENTRY (TYPE_CODE_ARRAY), - ENTRY (TYPE_CODE_STRUCT), - ENTRY (TYPE_CODE_UNION), - ENTRY (TYPE_CODE_ENUM), - ENTRY (TYPE_CODE_FLAGS), - ENTRY (TYPE_CODE_FUNC), - ENTRY (TYPE_CODE_INT), - ENTRY (TYPE_CODE_FLT), - ENTRY (TYPE_CODE_VOID), - ENTRY (TYPE_CODE_SET), - ENTRY (TYPE_CODE_RANGE), - ENTRY (TYPE_CODE_STRING), - ENTRY (TYPE_CODE_BITSTRING), - ENTRY (TYPE_CODE_ERROR), - ENTRY (TYPE_CODE_METHOD), - ENTRY (TYPE_CODE_METHODPTR), - ENTRY (TYPE_CODE_MEMBERPTR), - ENTRY (TYPE_CODE_REF), - ENTRY (TYPE_CODE_CHAR), - ENTRY (TYPE_CODE_BOOL), - ENTRY (TYPE_CODE_COMPLEX), - ENTRY (TYPE_CODE_TYPEDEF), - ENTRY (TYPE_CODE_NAMESPACE), - ENTRY (TYPE_CODE_DECFLOAT), - ENTRY (TYPE_CODE_INTERNAL_FUNCTION), - { TYPE_CODE_UNDEF, NULL } -}; - - - -static void -field_dealloc (PyObject *obj) -{ - field_object *f = (field_object *) obj; - Py_XDECREF (f->dict); - f->ob_type->tp_free (obj); -} - -static PyObject * -field_new (void) -{ - field_object *result = PyObject_New (field_object, &field_object_type); - if (result) - { - result->dict = PyDict_New (); - if (!result->dict) - { - Py_DECREF (result); - result = NULL; - } - } - return (PyObject *) result; -} - - - -/* Return the code for this type. */ -static PyObject * -typy_get_code (PyObject *self, void *closure) -{ - struct type *type = ((type_object *) self)->type; - return PyInt_FromLong (TYPE_CODE (type)); -} - -/* Helper function for typy_fields which converts a single field to a - dictionary. Returns NULL on error. */ -static PyObject * -convert_field (struct type *type, int field) -{ - PyObject *result = field_new (); - PyObject *arg; - - if (!result) - return NULL; - - if (!field_is_static (&TYPE_FIELD (type, field))) - { - arg = PyLong_FromLong (TYPE_FIELD_BITPOS (type, field)); - if (!arg) - goto fail; - - if (PyObject_SetAttrString (result, "bitpos", arg) < 0) - goto failarg; - } - - if (TYPE_FIELD_NAME (type, field)) - arg = PyString_FromString (TYPE_FIELD_NAME (type, field)); - else - { - arg = Py_None; - Py_INCREF (arg); - } - if (!arg) - goto fail; - if (PyObject_SetAttrString (result, "name", arg) < 0) - goto failarg; - - arg = TYPE_FIELD_ARTIFICIAL (type, field) ? Py_True : Py_False; - Py_INCREF (arg); - if (PyObject_SetAttrString (result, "artificial", arg) < 0) - goto failarg; - - arg = PyLong_FromLong (TYPE_FIELD_BITSIZE (type, field)); - if (!arg) - goto fail; - if (PyObject_SetAttrString (result, "bitsize", arg) < 0) - goto failarg; - - /* A field can have a NULL type in some situations. */ - if (TYPE_FIELD_TYPE (type, field) == NULL) - { - arg = Py_None; - Py_INCREF (arg); - } - else - arg = type_to_type_object (TYPE_FIELD_TYPE (type, field)); - if (!arg) - goto fail; - if (PyObject_SetAttrString (result, "type", arg) < 0) - goto failarg; - - return result; - - failarg: - Py_DECREF (arg); - fail: - Py_DECREF (result); - return NULL; -} - -/* Return a sequence of all fields. Each field is a dictionary with - some pre-defined keys. */ -static PyObject * -typy_fields (PyObject *self, PyObject *args) -{ - PyObject *result; - int i; - struct type *type = ((type_object *) self)->type; - - /* We would like to make a tuple here, make fields immutable, and - then memoize the result (and perhaps make Field.type() lazy). - However, that can lead to cycles. */ - result = PyList_New (0); - - for (i = 0; i < TYPE_NFIELDS (type); ++i) - { - PyObject *dict = convert_field (type, i); - if (!dict) - { - Py_DECREF (result); - return NULL; - } - if (PyList_Append (result, dict)) - { - Py_DECREF (dict); - Py_DECREF (result); - return NULL; - } - } - - return result; -} - -/* Return the type's tag, or None. */ -static PyObject * -typy_get_tag (PyObject *self, void *closure) -{ - struct type *type = ((type_object *) self)->type; - if (!TYPE_TAG_NAME (type)) - Py_RETURN_NONE; - return PyString_FromString (TYPE_TAG_NAME (type)); -} - -/* Return the type, stripped of typedefs. */ -static PyObject * -typy_strip_typedefs (PyObject *self, PyObject *args) -{ - struct type *type = ((type_object *) self)->type; - - return type_to_type_object (check_typedef (type)); -} - -/* Return a Type object which represents a pointer to SELF. */ -static PyObject * -typy_pointer (PyObject *self, PyObject *args) -{ - struct type *type = ((type_object *) self)->type; - volatile struct gdb_exception except; - - TRY_CATCH (except, RETURN_MASK_ALL) - { - type = lookup_pointer_type (type); - } - GDB_PY_HANDLE_EXCEPTION (except); - - return type_to_type_object (type); -} - -/* Return a Type object which represents a reference to SELF. */ -static PyObject * -typy_reference (PyObject *self, PyObject *args) -{ - struct type *type = ((type_object *) self)->type; - volatile struct gdb_exception except; - - TRY_CATCH (except, RETURN_MASK_ALL) - { - type = lookup_reference_type (type); - } - GDB_PY_HANDLE_EXCEPTION (except); - - return type_to_type_object (type); -} - -/* Return a Type object which represents the target type of SELF. */ -static PyObject * -typy_target (PyObject *self, PyObject *args) -{ - struct type *type = ((type_object *) self)->type; - - if (!TYPE_TARGET_TYPE (type)) - { - PyErr_SetString (PyExc_RuntimeError, "type does not have a target"); - return NULL; - } - - return type_to_type_object (TYPE_TARGET_TYPE (type)); -} - -/* Return a const-qualified type variant. */ -static PyObject * -typy_const (PyObject *self, PyObject *args) -{ - struct type *type = ((type_object *) self)->type; - volatile struct gdb_exception except; - - TRY_CATCH (except, RETURN_MASK_ALL) - { - type = make_cv_type (1, 0, type, NULL); - } - GDB_PY_HANDLE_EXCEPTION (except); - - return type_to_type_object (type); -} - -/* Return a volatile-qualified type variant. */ -static PyObject * -typy_volatile (PyObject *self, PyObject *args) -{ - struct type *type = ((type_object *) self)->type; - volatile struct gdb_exception except; - - TRY_CATCH (except, RETURN_MASK_ALL) - { - type = make_cv_type (0, 1, type, NULL); - } - GDB_PY_HANDLE_EXCEPTION (except); - - return type_to_type_object (type); -} - -/* Return an unqualified type variant. */ -static PyObject * -typy_unqualified (PyObject *self, PyObject *args) -{ - struct type *type = ((type_object *) self)->type; - volatile struct gdb_exception except; - - TRY_CATCH (except, RETURN_MASK_ALL) - { - type = make_cv_type (0, 0, type, NULL); - } - GDB_PY_HANDLE_EXCEPTION (except); - - return type_to_type_object (type); -} - -/* Return the size of the type represented by SELF, in bytes. */ -static PyObject * -typy_get_sizeof (PyObject *self, void *closure) -{ - struct type *type = ((type_object *) self)->type; - volatile struct gdb_exception except; - - TRY_CATCH (except, RETURN_MASK_ALL) - { - check_typedef (type); - } - /* Ignore exceptions. */ - - return PyLong_FromLong (TYPE_LENGTH (type)); -} - -static struct type * -typy_lookup_typename (char *type_name) -{ - struct type *type = NULL; - volatile struct gdb_exception except; - TRY_CATCH (except, RETURN_MASK_ALL) - { - if (!strncmp (type_name, "struct ", 7)) - type = lookup_struct (type_name + 7, NULL); - else if (!strncmp (type_name, "union ", 6)) - type = lookup_union (type_name + 6, NULL); - else if (!strncmp (type_name, "enum ", 5)) - type = lookup_enum (type_name + 5, NULL); - else - type = lookup_typename (python_language, python_gdbarch, - type_name, NULL, 0); - } - if (except.reason < 0) - { - PyErr_Format (except.reason == RETURN_QUIT - ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, - "%s", except.message); - return NULL; - } - - return type; -} - -static struct type * -typy_lookup_type (struct demangle_component *demangled) -{ - struct type *type; - char *type_name; - enum demangle_component_type demangled_type; - - /* Save the type: typy_lookup_type() may (indirectly) overwrite - memory pointed by demangled. */ - demangled_type = demangled->type; - - if (demangled_type == DEMANGLE_COMPONENT_POINTER - || demangled_type == DEMANGLE_COMPONENT_REFERENCE - || demangled_type == DEMANGLE_COMPONENT_CONST - || demangled_type == DEMANGLE_COMPONENT_VOLATILE) - { - type = typy_lookup_type (demangled->u.s_binary.left); - if (! type) - return NULL; - - switch (demangled_type) - { - case DEMANGLE_COMPONENT_REFERENCE: - return lookup_reference_type (type); - case DEMANGLE_COMPONENT_POINTER: - return lookup_pointer_type (type); - case DEMANGLE_COMPONENT_CONST: - return make_cv_type (1, 0, type, NULL); - case DEMANGLE_COMPONENT_VOLATILE: - return make_cv_type (0, 1, type, NULL); - } - } - - type_name = cp_comp_to_string (demangled, 10); - type = typy_lookup_typename (type_name); - xfree (type_name); - - return type; -} - -static PyObject * -typy_template_argument (PyObject *self, PyObject *args) -{ - int i, argno, n_pointers; - struct type *type = ((type_object *) self)->type; - struct demangle_component *demangled; - const char *err; - struct type *argtype; - - if (! PyArg_ParseTuple (args, "i", &argno)) - return NULL; - - type = check_typedef (type); - if (TYPE_CODE (type) == TYPE_CODE_REF) - type = check_typedef (TYPE_TARGET_TYPE (type)); - - if (TYPE_NAME (type) == NULL) - { - PyErr_SetString (PyExc_RuntimeError, "null type name"); - return NULL; - } - - /* Note -- this is not thread-safe. */ - demangled = cp_demangled_name_to_comp (TYPE_NAME (type), &err); - if (! demangled) - { - PyErr_SetString (PyExc_RuntimeError, err); - return NULL; - } - - /* Strip off component names. */ - while (demangled->type == DEMANGLE_COMPONENT_QUAL_NAME - || demangled->type == DEMANGLE_COMPONENT_LOCAL_NAME) - demangled = demangled->u.s_binary.right; - - if (demangled->type != DEMANGLE_COMPONENT_TEMPLATE) - { - PyErr_SetString (PyExc_RuntimeError, "type is not a template"); - return NULL; - } - - /* Skip from the template to the arguments. */ - demangled = demangled->u.s_binary.right; - - for (i = 0; demangled && i < argno; ++i) - demangled = demangled->u.s_binary.right; - - if (! demangled) - { - PyErr_Format (PyExc_RuntimeError, "no argument %d in template", - argno); - return NULL; - } - - argtype = typy_lookup_type (demangled->u.s_binary.left); - if (! argtype) - return NULL; - - return type_to_type_object (argtype); -} - -static PyObject * -typy_str (PyObject *self) -{ - volatile struct gdb_exception except; - char *thetype = NULL; - long length = 0; - PyObject *result; - - TRY_CATCH (except, RETURN_MASK_ALL) - { - struct cleanup *old_chain; - struct ui_file *stb; - - stb = mem_fileopen (); - old_chain = make_cleanup_ui_file_delete (stb); - - type_print (type_object_to_type (self), "", stb, -1); - - thetype = ui_file_xstrdup (stb, &length); - do_cleanups (old_chain); - } - if (except.reason < 0) - { - xfree (thetype); - GDB_PY_HANDLE_EXCEPTION (except); - } - - result = PyUnicode_Decode (thetype, length, host_charset (), NULL); - xfree (thetype); - - return result; -} - - - -static const struct objfile_data *typy_objfile_data_key; - -static void -clean_up_objfile_types (struct objfile *objfile, void *datum) -{ - type_object *obj = datum; - htab_t copied_types; - struct cleanup *cleanup; - - /* This prevents another thread from freeing the objects we're - operating on. */ - cleanup = ensure_python_env (get_objfile_arch (objfile), current_language); - - copied_types = create_copied_types_hash (objfile); - - while (obj) - { - type_object *next = obj->next; - - htab_empty (copied_types); - - obj->type = copy_type_recursive (objfile, obj->type, copied_types); - - obj->next = NULL; - obj->prev = NULL; - - obj = next; - } - - htab_delete (copied_types); - - do_cleanups (cleanup); -} - -static void -set_type (type_object *obj, struct type *type) -{ - obj->type = type; - obj->prev = NULL; - if (type && TYPE_OBJFILE (type)) - { - struct objfile *objfile = TYPE_OBJFILE (type); - - obj->next = objfile_data (objfile, typy_objfile_data_key); - if (obj->next) - obj->next->prev = obj; - set_objfile_data (objfile, typy_objfile_data_key, obj); - } - else - obj->next = NULL; -} - -static void -typy_dealloc (PyObject *obj) -{ - type_object *type = (type_object *) obj; - - if (type->prev) - type->prev->next = type->next; - else if (type->type && TYPE_OBJFILE (type->type)) - { - /* Must reset head of list. */ - struct objfile *objfile = TYPE_OBJFILE (type->type); - if (objfile) - set_objfile_data (objfile, typy_objfile_data_key, type->next); - } - if (type->next) - type->next->prev = type->prev; - - type->ob_type->tp_free (type); -} - -/* Create a new Type referring to TYPE. */ -PyObject * -type_to_type_object (struct type *type) -{ - type_object *type_obj; - - type_obj = PyObject_New (type_object, &type_object_type); - if (type_obj) - set_type (type_obj, type); - - return (PyObject *) type_obj; -} - -struct type * -type_object_to_type (PyObject *obj) -{ - if (! PyObject_TypeCheck (obj, &type_object_type)) - return NULL; - return ((type_object *) obj)->type; -} - - - -/* Implementation of gdb.lookup_type. */ -PyObject * -gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw) -{ - static char *keywords[] = { "name", NULL }; - char *type_name = NULL; - struct type *type = NULL; - - if (! PyArg_ParseTupleAndKeywords (args, kw, "s", keywords, &type_name)) - return NULL; - - type = typy_lookup_typename (type_name); - if (! type) - return NULL; - - return (PyObject *) type_to_type_object (type); -} - -void -gdbpy_initialize_types (void) -{ - int i; - - typy_objfile_data_key - = register_objfile_data_with_cleanup (clean_up_objfile_types); - - if (PyType_Ready (&type_object_type) < 0) - return; - if (PyType_Ready (&field_object_type) < 0) - return; - - for (i = 0; pyty_codes[i].name; ++i) - { - if (PyModule_AddIntConstant (gdb_module, - /* Cast needed for Python 2.4. */ - (char *) pyty_codes[i].name, - pyty_codes[i].code) < 0) - return; - } - - Py_INCREF (&type_object_type); - PyModule_AddObject (gdb_module, "Type", (PyObject *) &type_object_type); - - Py_INCREF (&field_object_type); - PyModule_AddObject (gdb_module, "Field", (PyObject *) &field_object_type); -} - - - -static PyGetSetDef type_object_getset[] = -{ - { "code", typy_get_code, NULL, - "The code for this type.", NULL }, - { "sizeof", typy_get_sizeof, NULL, - "The size of this type, in bytes.", NULL }, - { "tag", typy_get_tag, NULL, - "The tag name for this type, or None.", NULL }, - { NULL } -}; - -static PyMethodDef type_object_methods[] = -{ - { "const", typy_const, METH_NOARGS, - "const () -> Type\n\ -Return a const variant of this type." }, - { "fields", typy_fields, METH_NOARGS, - "field () -> list\n\ -Return a sequence holding all the fields of this type.\n\ -Each field is a dictionary." }, - { "pointer", typy_pointer, METH_NOARGS, - "pointer () -> Type\n\ -Return a type of pointer to this type." }, - { "reference", typy_reference, METH_NOARGS, - "reference () -> Type\n\ -Return a type of reference to this type." }, - { "strip_typedefs", typy_strip_typedefs, METH_NOARGS, - "strip_typedefs () -> Type\n\ -Return a type formed by stripping this type of all typedefs."}, - { "target", typy_target, METH_NOARGS, - "target () -> Type\n\ -Return the target type of this type." }, - { "template_argument", typy_template_argument, METH_VARARGS, - "template_argument (arg) -> Type\n\ -Return the type of a template argument." }, - { "unqualified", typy_unqualified, METH_NOARGS, - "unqualified () -> Type\n\ -Return a variant of this type without const or volatile attributes." }, - { "volatile", typy_volatile, METH_NOARGS, - "volatile () -> Type\n\ -Return a volatile variant of this type" }, - { NULL } -}; - -static PyTypeObject type_object_type = -{ - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ - "gdb.Type", /*tp_name*/ - sizeof (type_object), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - typy_dealloc, /*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*/ - typy_str, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ - "GDB type object", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - type_object_methods, /* tp_methods */ - 0, /* tp_members */ - type_object_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ -}; - -static PyTypeObject field_object_type = -{ - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ - "gdb.Field", /*tp_name*/ - sizeof (field_object), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - field_dealloc, /*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_HAVE_ITER, /*tp_flags*/ - "GDB field object", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof (field_object, dict), /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ -}; diff --git a/gdb/python/python-utils.c b/gdb/python/python-utils.c deleted file mode 100644 index 49c0437c138..00000000000 --- a/gdb/python/python-utils.c +++ /dev/null @@ -1,221 +0,0 @@ -/* General utility routines for GDB/Python. - - Copyright (C) 2008, 2009 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 . */ - -#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; - Py_INCREF (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 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. */ -static char * -unicode_to_encoded_string (PyObject *unicode_str, const char *charset) -{ - char *result; - PyObject *string; - - /* Translate string to named charset. */ - string = PyUnicode_AsEncodedString (unicode_str, charset, NULL); - if (string == NULL) - return NULL; - - result = xstrdup (PyString_AsString (string)); - - Py_DECREF (string); - - return result; -} - -/* Returns a PyObject with the contents of the given unicode string - object converted to a named charset. If an error occurs during - the conversion, NULL will be returned and a python exception will - be set. */ -static PyObject * -unicode_to_encoded_python_string (PyObject *unicode_str, const char *charset) -{ - PyObject *string; - - /* Translate string to named charset. */ - string = PyUnicode_AsEncodedString (unicode_str, charset, NULL); - if (string == NULL) - return NULL; - - return string; -} - -/* 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) -{ - return unicode_to_encoded_string (unicode_str, target_charset ()); -} - -/* Returns a PyObject 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. */ -PyObject * -unicode_to_target_python_string (PyObject *unicode_str) -{ - return unicode_to_encoded_python_string (unicode_str, target_charset ()); -} - -/* 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; - char *result; - - str = python_string_to_unicode (obj); - if (str == NULL) - return NULL; - - result = unicode_to_target_string (str); - Py_DECREF (str); - return result; -} - -/* 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. */ -PyObject * -python_string_to_target_python_string (PyObject *obj) -{ - PyObject *str; - PyObject *result; - - str = python_string_to_unicode (obj); - if (str == NULL) - return NULL; - - result = unicode_to_target_python_string (str); - Py_DECREF (str); - return result; -} - -/* Converts a python string (8-bit or unicode) to a target string in - the host's charset. Returns NULL on error, with a python exception set. - - The caller is responsible for xfree'ing the string. */ -char * -python_string_to_host_string (PyObject *obj) -{ - PyObject *str; - char *result; - - str = python_string_to_unicode (obj); - if (str == NULL) - return NULL; - - result = unicode_to_encoded_string (str, host_charset ()); - Py_DECREF (str); - return result; -} - -/* Converts a target string of LENGTH bytes in the target's charset to a - Python Unicode string. If LENGTH is -1, convert until a null byte is found. - - Returns NULL on error, with a python exception set. */ -PyObject * -target_string_to_unicode (const gdb_byte *str, int length) -{ - if (length == -1) - length = strlen (str); - - return PyUnicode_Decode (str, length, target_charset (), NULL); -} - -/* Return true if OBJ is a Python string or unicode object, false - otherwise. */ - -int -gdbpy_is_string (PyObject *obj) -{ - return PyString_Check (obj) || PyUnicode_Check (obj); -} diff --git a/gdb/python/python-value.c b/gdb/python/python-value.c deleted file mode 100644 index 3d88aa31f8b..00000000000 --- a/gdb/python/python-value.c +++ /dev/null @@ -1,1068 +0,0 @@ -/* Python interface to values. - - Copyright (C) 2008, 2009 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 . */ - -#include "defs.h" -#include "gdb_assert.h" -#include "charset.h" -#include "value.h" -#include "exceptions.h" -#include "language.h" -#include "dfp.h" -#include "valprint.h" - -#ifdef HAVE_PYTHON - -#include "python-internal.h" - -/* Even though Python scalar types directly map to host types, we use - target types here to remain consistent with the the values system in - GDB (which uses target arithmetic). */ - -/* Python's integer type corresponds to C's long type. */ -#define builtin_type_pyint builtin_type (python_gdbarch)->builtin_long - -/* Python's float type corresponds to C's double type. */ -#define builtin_type_pyfloat builtin_type (python_gdbarch)->builtin_double - -/* Python's long type corresponds to C's long long type. */ -#define builtin_type_pylong builtin_type (python_gdbarch)->builtin_long_long - -#define builtin_type_pybool \ - language_bool_type (python_language, python_gdbarch) - -#define builtin_type_pychar \ - language_string_char_type (python_language, python_gdbarch) - -typedef struct value_object { - PyObject_HEAD - struct value_object *next; - struct value_object *prev; - struct value *value; - PyObject *address; - PyObject *type; -} value_object; - -/* List of all values which are currently exposed to Python. It is - maintained so that when an objfile is discarded, preserve_values - can copy the values' types if needed. */ -/* This variable is unnecessarily initialized to NULL in order to - work around a linker bug on MacOS. */ -static value_object *values_in_python = NULL; - -/* Called by the Python interpreter when deallocating a value object. */ -static void -valpy_dealloc (PyObject *obj) -{ - value_object *self = (value_object *) obj; - - /* Remove SELF from the global list. */ - if (self->prev) - self->prev->next = self->next; - else - { - gdb_assert (values_in_python == self); - values_in_python = self->next; - } - if (self->next) - self->next->prev = self->prev; - - value_free (self->value); - - if (self->address) - /* Use braces to appease gcc warning. *sigh* */ - { - Py_DECREF (self->address); - } - - if (self->type) - { - Py_DECREF (self->type); - } - - self->ob_type->tp_free (self); -} - -/* Helper to push a Value object on the global list. */ -static void -note_value (value_object *value_obj) -{ - value_obj->next = values_in_python; - if (value_obj->next) - value_obj->next->prev = value_obj; - value_obj->prev = NULL; - values_in_python = value_obj; -} - -/* Called when a new gdb.Value object needs to be allocated. */ -static PyObject * -valpy_new (PyTypeObject *subtype, PyObject *args, PyObject *keywords) -{ - struct value *value = NULL; /* Initialize to appease gcc warning. */ - value_object *value_obj; - - if (PyTuple_Size (args) != 1) - { - PyErr_SetString (PyExc_TypeError, _("Value object creation takes only " - "1 argument")); - return NULL; - } - - value_obj = (value_object *) subtype->tp_alloc (subtype, 1); - if (value_obj == NULL) - { - PyErr_SetString (PyExc_MemoryError, _("Could not allocate memory to " - "create Value object.")); - return NULL; - } - - value = convert_value_from_python (PyTuple_GetItem (args, 0)); - if (value == NULL) - { - subtype->tp_free (value_obj); - return NULL; - } - - value_obj->value = value; - value_incref (value); - value_obj->address = NULL; - value_obj->type = NULL; - note_value (value_obj); - - return (PyObject *) value_obj; -} - -/* Iterate over all the Value objects, calling preserve_one_value on - each. */ -void -preserve_python_values (struct objfile *objfile, htab_t copied_types) -{ - value_object *iter; - - for (iter = values_in_python; iter; iter = iter->next) - preserve_one_value (iter->value, objfile, copied_types); -} - -/* Given a value of a pointer type, apply the C unary * operator to it. */ -static PyObject * -valpy_dereference (PyObject *self, PyObject *args) -{ - struct value *res_val = NULL; /* Initialize to appease gcc warning. */ - volatile struct gdb_exception except; - - TRY_CATCH (except, RETURN_MASK_ALL) - { - res_val = value_ind (((value_object *) self)->value); - } - GDB_PY_HANDLE_EXCEPTION (except); - - return value_to_value_object (res_val); -} - -/* Return "&value". */ -static PyObject * -valpy_get_address (PyObject *self, void *closure) -{ - struct value *res_val = NULL; /* Initialize to appease gcc warning. */ - value_object *val_obj = (value_object *) self; - volatile struct gdb_exception except; - - if (!val_obj->address) - { - TRY_CATCH (except, RETURN_MASK_ALL) - { - res_val = value_addr (val_obj->value); - } - if (except.reason < 0) - { - val_obj->address = Py_None; - Py_INCREF (Py_None); - } - else - val_obj->address = value_to_value_object (res_val); - } - - Py_INCREF (val_obj->address); - - return val_obj->address; -} - -/* Return type of the value. */ -static PyObject * -valpy_get_type (PyObject *self, void *closure) -{ - value_object *obj = (value_object *) self; - if (!obj->type) - { - obj->type = type_to_type_object (value_type (obj->value)); - if (!obj->type) - { - obj->type = Py_None; - Py_INCREF (obj->type); - } - } - Py_INCREF (obj->type); - return obj->type; -} - -/* Implementation of gdb.Value.string ([encoding] [, errors] - [, length]) -> string. Return Unicode string with value contents. - If ENCODING is not given, the string is assumed to be encoded in - the target's charset. If LENGTH is provided, only fetch string to - the length provided. */ - -static PyObject * -valpy_string (PyObject *self, PyObject *args, PyObject *kw) -{ - int length = -1, ret = 0; - gdb_byte *buffer; - struct value *value = ((value_object *) self)->value; - volatile struct gdb_exception except; - PyObject *unicode; - const char *encoding = NULL; - const char *errors = NULL; - const char *user_encoding = NULL; - const char *la_encoding = NULL; - static char *keywords[] = { "encoding", "errors", "length" }; - - if (!PyArg_ParseTupleAndKeywords (args, kw, "|ssi", keywords, - &user_encoding, &errors, &length)) - return NULL; - - TRY_CATCH (except, RETURN_MASK_ALL) - { - LA_GET_STRING (value, &buffer, &length, &la_encoding); - } - GDB_PY_HANDLE_EXCEPTION (except); - - encoding = (user_encoding && *user_encoding) ? user_encoding : la_encoding; - unicode = PyUnicode_Decode (buffer, length, encoding, errors); - xfree (buffer); - - return unicode; -} - -/* Cast a value to a given type. */ -static PyObject * -valpy_cast (PyObject *self, PyObject *args) -{ - PyObject *type_obj; - struct type *type; - struct value *res_val = NULL; /* Initialize to appease gcc warning. */ - volatile struct gdb_exception except; - - if (! PyArg_ParseTuple (args, "O", &type_obj)) - return NULL; - - type = type_object_to_type (type_obj); - if (! type) - { - PyErr_SetString (PyExc_RuntimeError, "argument must be a Type"); - return NULL; - } - - TRY_CATCH (except, RETURN_MASK_ALL) - { - res_val = value_cast (type, ((value_object *) self)->value); - } - GDB_PY_HANDLE_EXCEPTION (except); - - return value_to_value_object (res_val); -} - -static Py_ssize_t -valpy_length (PyObject *self) -{ - /* We don't support getting the number of elements in a struct / class. */ - PyErr_SetString (PyExc_NotImplementedError, - "Invalid operation on gdb.Value."); - return -1; -} - -/* Given string name of an element inside structure, return its value - object. */ -static PyObject * -valpy_getitem (PyObject *self, PyObject *key) -{ - value_object *self_value = (value_object *) self; - char *field = NULL; - struct value *res_val = NULL; - volatile struct gdb_exception except; - - if (gdbpy_is_string (key)) - { - field = python_string_to_host_string (key); - if (field == NULL) - return NULL; - } - - TRY_CATCH (except, RETURN_MASK_ALL) - { - struct value *tmp = self_value->value; - - if (field) - res_val = value_struct_elt (&tmp, NULL, field, 0, NULL); - else - { - /* Assume we are attempting an array access, and let the - value code throw an exception if the index has an invalid - type. */ - struct value *idx = convert_value_from_python (key); - if (idx != NULL) - res_val = value_subscript (tmp, value_as_long (idx)); - } - } - - xfree (field); - GDB_PY_HANDLE_EXCEPTION (except); - - return res_val ? value_to_value_object (res_val) : NULL; -} - -static int -valpy_setitem (PyObject *self, PyObject *key, PyObject *value) -{ - PyErr_Format (PyExc_NotImplementedError, - _("Setting of struct elements is not currently supported.")); - return -1; -} - -/* Called by the Python interpreter to obtain string representation - of the object. */ -static PyObject * -valpy_str (PyObject *self) -{ - char *s = NULL; - struct ui_file *stb; - struct cleanup *old_chain; - PyObject *result; - struct value_print_options opts; - volatile struct gdb_exception except; - - get_user_print_options (&opts); - opts.deref_ref = 0; - - stb = mem_fileopen (); - old_chain = make_cleanup_ui_file_delete (stb); - - TRY_CATCH (except, RETURN_MASK_ALL) - { - common_val_print (((value_object *) self)->value, stb, 0, - &opts, python_language); - s = ui_file_xstrdup (stb, NULL); - } - GDB_PY_HANDLE_EXCEPTION (except); - - do_cleanups (old_chain); - - result = PyUnicode_Decode (s, strlen (s), host_charset (), NULL); - xfree (s); - - return result; -} - -/* Implements gdb.Value.is_optimized_out. */ -static PyObject * -valpy_get_is_optimized_out (PyObject *self, void *closure) -{ - struct value *value = ((value_object *) self)->value; - - if (value_optimized_out (value)) - Py_RETURN_TRUE; - - Py_RETURN_FALSE; -} - -enum valpy_opcode -{ - VALPY_ADD, - VALPY_SUB, - VALPY_MUL, - VALPY_DIV, - VALPY_REM, - VALPY_POW, - VALPY_LSH, - VALPY_RSH, - VALPY_BITAND, - VALPY_BITOR, - VALPY_BITXOR -}; - -/* If TYPE is a reference, return the target; otherwise return TYPE. */ -#define STRIP_REFERENCE(TYPE) \ - ((TYPE_CODE (TYPE) == TYPE_CODE_REF) ? (TYPE_TARGET_TYPE (TYPE)) : (TYPE)) - -/* Returns a value object which is the result of applying the operation - specified by OPCODE to the given arguments. */ -static PyObject * -valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other) -{ - struct value *res_val = NULL; /* Initialize to appease gcc warning. */ - volatile struct gdb_exception except; - - TRY_CATCH (except, RETURN_MASK_ALL) - { - struct value *arg1, *arg2; - - /* If the gdb.Value object is the second operand, then it will be passed - to us as the OTHER argument, and SELF will be an entirely different - kind of object, altogether. Because of this, we can't assume self is - a gdb.Value object and need to convert it from python as well. */ - arg1 = convert_value_from_python (self); - if (arg1 == NULL) - break; - - arg2 = convert_value_from_python (other); - if (arg2 == NULL) - break; - - switch (opcode) - { - case VALPY_ADD: - { - struct type *ltype = value_type (arg1); - struct type *rtype = value_type (arg2); - - CHECK_TYPEDEF (ltype); - ltype = STRIP_REFERENCE (ltype); - CHECK_TYPEDEF (rtype); - rtype = STRIP_REFERENCE (rtype); - - if (TYPE_CODE (ltype) == TYPE_CODE_PTR - && is_integral_type (rtype)) - res_val = value_ptradd (arg1, value_as_long (arg2)); - else if (TYPE_CODE (rtype) == TYPE_CODE_PTR - && is_integral_type (ltype)) - res_val = value_ptradd (arg2, value_as_long (arg1)); - else - res_val = value_binop (arg1, arg2, BINOP_ADD); - } - break; - case VALPY_SUB: - { - struct type *ltype = value_type (arg1); - struct type *rtype = value_type (arg2); - - CHECK_TYPEDEF (ltype); - ltype = STRIP_REFERENCE (ltype); - CHECK_TYPEDEF (rtype); - rtype = STRIP_REFERENCE (rtype); - - if (TYPE_CODE (ltype) == TYPE_CODE_PTR - && TYPE_CODE (rtype) == TYPE_CODE_PTR) - /* A ptrdiff_t for the target would be preferable here. */ - res_val = value_from_longest (builtin_type_pyint, - value_ptrdiff (arg1, arg2)); - else if (TYPE_CODE (ltype) == TYPE_CODE_PTR - && is_integral_type (rtype)) - res_val = value_ptradd (arg1, - value_as_long (arg2)); - else - res_val = value_binop (arg1, arg2, BINOP_SUB); - } - break; - case VALPY_MUL: - res_val = value_binop (arg1, arg2, BINOP_MUL); - break; - case VALPY_DIV: - res_val = value_binop (arg1, arg2, BINOP_DIV); - break; - case VALPY_REM: - res_val = value_binop (arg1, arg2, BINOP_REM); - break; - case VALPY_POW: - res_val = value_binop (arg1, arg2, BINOP_EXP); - break; - case VALPY_LSH: - res_val = value_binop (arg1, arg2, BINOP_LSH); - break; - case VALPY_RSH: - res_val = value_binop (arg1, arg2, BINOP_RSH); - break; - case VALPY_BITAND: - res_val = value_binop (arg1, arg2, BINOP_BITWISE_AND); - break; - case VALPY_BITOR: - res_val = value_binop (arg1, arg2, BINOP_BITWISE_IOR); - break; - case VALPY_BITXOR: - res_val = value_binop (arg1, arg2, BINOP_BITWISE_XOR); - break; - } - } - GDB_PY_HANDLE_EXCEPTION (except); - - return res_val ? value_to_value_object (res_val) : NULL; -} - -static PyObject * -valpy_add (PyObject *self, PyObject *other) -{ - return valpy_binop (VALPY_ADD, self, other); -} - -static PyObject * -valpy_subtract (PyObject *self, PyObject *other) -{ - return valpy_binop (VALPY_SUB, self, other); -} - -static PyObject * -valpy_multiply (PyObject *self, PyObject *other) -{ - return valpy_binop (VALPY_MUL, self, other); -} - -static PyObject * -valpy_divide (PyObject *self, PyObject *other) -{ - return valpy_binop (VALPY_DIV, self, other); -} - -static PyObject * -valpy_remainder (PyObject *self, PyObject *other) -{ - return valpy_binop (VALPY_REM, self, other); -} - -static PyObject * -valpy_power (PyObject *self, PyObject *other, PyObject *unused) -{ - /* We don't support the ternary form of pow. I don't know how to express - that, so let's just throw NotImplementedError to at least do something - about it. */ - if (unused != Py_None) - { - PyErr_SetString (PyExc_NotImplementedError, - "Invalid operation on gdb.Value."); - return NULL; - } - - return valpy_binop (VALPY_POW, self, other); -} - -static PyObject * -valpy_negative (PyObject *self) -{ - struct value *val = NULL; - volatile struct gdb_exception except; - - TRY_CATCH (except, RETURN_MASK_ALL) - { - val = value_neg (((value_object *) self)->value); - } - GDB_PY_HANDLE_EXCEPTION (except); - - return value_to_value_object (val); -} - -static PyObject * -valpy_positive (PyObject *self) -{ - return value_to_value_object (((value_object *) self)->value); -} - -static PyObject * -valpy_absolute (PyObject *self) -{ - struct value *value = ((value_object *) self)->value; - if (value_less (value, value_zero (value_type (value), not_lval))) - return valpy_negative (self); - else - return valpy_positive (self); -} - -/* Implements boolean evaluation of gdb.Value. */ -static int -valpy_nonzero (PyObject *self) -{ - value_object *self_value = (value_object *) self; - struct type *type; - - type = check_typedef (value_type (self_value->value)); - - if (is_integral_type (type) || TYPE_CODE (type) == TYPE_CODE_PTR) - return !!value_as_long (self_value->value); - else if (TYPE_CODE (type) == TYPE_CODE_FLT) - return value_as_double (self_value->value) != 0; - else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT) - return !decimal_is_zero (value_contents (self_value->value), - TYPE_LENGTH (type), - gdbarch_byte_order (get_type_arch (type))); - else - { - PyErr_SetString (PyExc_TypeError, _("Attempted truth testing on invalid " - "gdb.Value type.")); - return 0; - } -} - -/* Implements ~ for value objects. */ -static PyObject * -valpy_invert (PyObject *self) -{ - struct value *val = NULL; - volatile struct gdb_exception except; - - TRY_CATCH (except, RETURN_MASK_ALL) - { - val = value_complement (((value_object *) self)->value); - } - GDB_PY_HANDLE_EXCEPTION (except); - - return value_to_value_object (val); -} - -/* Implements left shift for value objects. */ -static PyObject * -valpy_lsh (PyObject *self, PyObject *other) -{ - return valpy_binop (VALPY_LSH, self, other); -} - -/* Implements right shift for value objects. */ -static PyObject * -valpy_rsh (PyObject *self, PyObject *other) -{ - return valpy_binop (VALPY_RSH, self, other); -} - -/* Implements bitwise and for value objects. */ -static PyObject * -valpy_and (PyObject *self, PyObject *other) -{ - return valpy_binop (VALPY_BITAND, self, other); -} - -/* Implements bitwise or for value objects. */ -static PyObject * -valpy_or (PyObject *self, PyObject *other) -{ - return valpy_binop (VALPY_BITOR, self, other); -} - -/* Implements bitwise xor for value objects. */ -static PyObject * -valpy_xor (PyObject *self, PyObject *other) -{ - return valpy_binop (VALPY_BITXOR, self, other); -} - -/* Implements comparison operations for value objects. */ -static PyObject * -valpy_richcompare (PyObject *self, PyObject *other, int op) -{ - int result = 0; - struct value *value_other; - volatile struct gdb_exception except; - - if (other == Py_None) - /* Comparing with None is special. From what I can tell, in Python - None is smaller than anything else. */ - switch (op) { - case Py_LT: - case Py_LE: - case Py_EQ: - Py_RETURN_FALSE; - case Py_NE: - case Py_GT: - case Py_GE: - Py_RETURN_TRUE; - default: - /* Can't happen. */ - PyErr_SetString (PyExc_NotImplementedError, - "Invalid operation on gdb.Value."); - return NULL; - } - - TRY_CATCH (except, RETURN_MASK_ALL) - { - value_other = convert_value_from_python (other); - if (value_other == NULL) - { - result = -1; - break; - } - - switch (op) { - case Py_LT: - result = value_less (((value_object *) self)->value, value_other); - break; - case Py_LE: - result = value_less (((value_object *) self)->value, value_other) - || value_equal (((value_object *) self)->value, value_other); - break; - case Py_EQ: - result = value_equal (((value_object *) self)->value, value_other); - break; - case Py_NE: - result = !value_equal (((value_object *) self)->value, value_other); - break; - case Py_GT: - result = value_less (value_other, ((value_object *) self)->value); - break; - case Py_GE: - result = value_less (value_other, ((value_object *) self)->value) - || value_equal (((value_object *) self)->value, value_other); - break; - default: - /* Can't happen. */ - PyErr_SetString (PyExc_NotImplementedError, - "Invalid operation on gdb.Value."); - result = -1; - break; - } - } - GDB_PY_HANDLE_EXCEPTION (except); - - /* In this case, the Python exception has already been set. */ - if (result < 0) - return NULL; - - if (result == 1) - Py_RETURN_TRUE; - - Py_RETURN_FALSE; -} - -/* Helper function to determine if a type is "int-like". */ -static int -is_intlike (struct type *type, int ptr_ok) -{ - CHECK_TYPEDEF (type); - return (TYPE_CODE (type) == TYPE_CODE_INT - || TYPE_CODE (type) == TYPE_CODE_ENUM - || TYPE_CODE (type) == TYPE_CODE_BOOL - || TYPE_CODE (type) == TYPE_CODE_CHAR - || (ptr_ok && TYPE_CODE (type) == TYPE_CODE_PTR)); -} - -/* Implements conversion to int. */ -static PyObject * -valpy_int (PyObject *self) -{ - struct value *value = ((value_object *) self)->value; - struct type *type = value_type (value); - LONGEST l = 0; - volatile struct gdb_exception except; - - CHECK_TYPEDEF (type); - if (!is_intlike (type, 0)) - { - PyErr_SetString (PyExc_RuntimeError, "cannot convert value to int"); - return NULL; - } - - TRY_CATCH (except, RETURN_MASK_ALL) - { - l = value_as_long (value); - } - GDB_PY_HANDLE_EXCEPTION (except); - - return PyInt_FromLong (l); -} - -/* Implements conversion to long. */ -static PyObject * -valpy_long (PyObject *self) -{ - struct value *value = ((value_object *) self)->value; - struct type *type = value_type (value); - LONGEST l = 0; - volatile struct gdb_exception except; - - if (!is_intlike (type, 1)) - { - PyErr_SetString (PyExc_RuntimeError, "cannot convert value to long"); - return NULL; - } - - TRY_CATCH (except, RETURN_MASK_ALL) - { - l = value_as_long (value); - } - GDB_PY_HANDLE_EXCEPTION (except); - - return PyLong_FromLong (l); -} - -/* Implements conversion to float. */ -static PyObject * -valpy_float (PyObject *self) -{ - struct value *value = ((value_object *) self)->value; - struct type *type = value_type (value); - double d = 0; - volatile struct gdb_exception except; - - CHECK_TYPEDEF (type); - if (TYPE_CODE (type) != TYPE_CODE_FLT) - { - PyErr_SetString (PyExc_RuntimeError, "cannot convert value to float"); - return NULL; - } - - TRY_CATCH (except, RETURN_MASK_ALL) - { - d = value_as_double (value); - } - GDB_PY_HANDLE_EXCEPTION (except); - - return PyFloat_FromDouble (d); -} - -/* Returns an object for a value which is released from the all_values chain, - so its lifetime is not bound to the execution of a command. */ -PyObject * -value_to_value_object (struct value *val) -{ - value_object *val_obj; - - val_obj = PyObject_New (value_object, &value_object_type); - if (val_obj != NULL) - { - val_obj->value = val; - value_incref (val); - val_obj->address = NULL; - val_obj->type = NULL; - note_value (val_obj); - } - - return (PyObject *) val_obj; -} - -/* Returns a borrowed reference to the struct value corresponding to - the given value object. */ -struct value * -value_object_to_value (PyObject *self) -{ - value_object *real; - if (! PyObject_TypeCheck (self, &value_object_type)) - return NULL; - real = (value_object *) self; - return real->value; -} - -/* Try to convert a Python value to a gdb value. If the value cannot - be converted, set a Python exception and return NULL. Returns a - reference to a new value on the all_values chain. */ - -struct value * -convert_value_from_python (PyObject *obj) -{ - struct value *value = NULL; /* -Wall */ - PyObject *target_str, *unicode_str; - struct cleanup *old; - volatile struct gdb_exception except; - int cmp; - - gdb_assert (obj != NULL); - - TRY_CATCH (except, RETURN_MASK_ALL) - { - if (PyBool_Check (obj)) - { - cmp = PyObject_IsTrue (obj); - if (cmp >= 0) - value = value_from_longest (builtin_type_pybool, cmp); - } - else if (PyInt_Check (obj)) - { - long l = PyInt_AsLong (obj); - - if (! PyErr_Occurred ()) - value = value_from_longest (builtin_type_pyint, l); - } - else if (PyLong_Check (obj)) - { - LONGEST l = PyLong_AsLongLong (obj); - - if (! PyErr_Occurred ()) - value = value_from_longest (builtin_type_pylong, l); - } - else if (PyFloat_Check (obj)) - { - double d = PyFloat_AsDouble (obj); - - if (! PyErr_Occurred ()) - value = value_from_double (builtin_type_pyfloat, d); - } - else if (gdbpy_is_string (obj)) - { - char *s; - - s = python_string_to_target_string (obj); - if (s != NULL) - { - old = make_cleanup (xfree, s); - value = value_cstring (s, strlen (s), builtin_type_pychar); - do_cleanups (old); - } - } - else if (PyObject_TypeCheck (obj, &value_object_type)) - value = value_copy (((value_object *) obj)->value); - else - PyErr_Format (PyExc_TypeError, _("Could not convert Python object: %s"), - PyString_AsString (PyObject_Str (obj))); - } - if (except.reason < 0) - { - PyErr_Format (except.reason == RETURN_QUIT - ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, - "%s", except.message); - return NULL; - } - - return value; -} - -/* Returns value object in the ARGth position in GDB's history. */ -PyObject * -gdbpy_history (PyObject *self, PyObject *args) -{ - int i; - struct value *res_val = NULL; /* Initialize to appease gcc warning. */ - volatile struct gdb_exception except; - - if (!PyArg_ParseTuple (args, "i", &i)) - return NULL; - - TRY_CATCH (except, RETURN_MASK_ALL) - { - res_val = access_value_history (i); - } - GDB_PY_HANDLE_EXCEPTION (except); - - return value_to_value_object (res_val); -} - -void -gdbpy_initialize_values (void) -{ - if (PyType_Ready (&value_object_type) < 0) - return; - - Py_INCREF (&value_object_type); - PyModule_AddObject (gdb_module, "Value", (PyObject *) &value_object_type); - - values_in_python = NULL; -} - - - -static PyGetSetDef value_object_getset[] = { - { "address", valpy_get_address, NULL, "The address of the value.", - NULL }, - { "is_optimized_out", valpy_get_is_optimized_out, NULL, - "Boolean telling whether the value is optimized out (i.e., not available).", - NULL }, - { "type", valpy_get_type, NULL, "Type of the value.", NULL }, - {NULL} /* Sentinel */ -}; - -static PyMethodDef value_object_methods[] = { - { "cast", valpy_cast, METH_VARARGS, "Cast the value to the supplied type." }, - { "dereference", valpy_dereference, METH_NOARGS, "Dereferences the value." }, - { "string", (PyCFunction) valpy_string, METH_VARARGS | METH_KEYWORDS, - "string ([encoding] [, errors] [, length]) -> string\n\ -Return Unicode string representation of the value." }, - {NULL} /* Sentinel */ -}; - -static PyNumberMethods value_object_as_number = { - valpy_add, - valpy_subtract, - valpy_multiply, - valpy_divide, - valpy_remainder, - NULL, /* nb_divmod */ - valpy_power, /* nb_power */ - valpy_negative, /* nb_negative */ - valpy_positive, /* nb_positive */ - valpy_absolute, /* nb_absolute */ - valpy_nonzero, /* nb_nonzero */ - valpy_invert, /* nb_invert */ - valpy_lsh, /* nb_lshift */ - valpy_rsh, /* nb_rshift */ - valpy_and, /* nb_and */ - valpy_xor, /* nb_xor */ - valpy_or, /* nb_or */ - NULL, /* nb_coerce */ - valpy_int, /* nb_int */ - valpy_long, /* nb_long */ - valpy_float, /* nb_float */ - NULL, /* nb_oct */ - NULL /* nb_hex */ -}; - -static PyMappingMethods value_object_as_mapping = { - valpy_length, - valpy_getitem, - valpy_setitem -}; - -PyTypeObject value_object_type = { - PyObject_HEAD_INIT (NULL) - 0, /*ob_size*/ - "gdb.Value", /*tp_name*/ - sizeof (value_object), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - valpy_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - &value_object_as_number, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - &value_object_as_mapping, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - valpy_str, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ - "GDB value object", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - valpy_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - value_object_methods, /* tp_methods */ - 0, /* tp_members */ - value_object_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - valpy_new /* tp_new */ -}; - -#else - -void -preserve_python_values (struct objfile *objfile, htab_t copied_types) -{ - /* Nothing. */ -} - -#endif /* HAVE_PYTHON */ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index f6ffeb9d2f8..1b265196c86 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,25 @@ +2009-09-08 Thiago Jung Bauermann + + * gdb.python/Makefile.in (EXECUTABLES): Adjust to new executable + names, add missing ones. + * gdb.python/py-cmd.exp: Rename from python-cmd.exp. + * gdb.python/py-frame.c: Rename from python-frame.c. + * gdb.python/py-frame.exp: Rename from python-frame.exp. Adjust + testfile name. + * gdb.python/py-function.exp: Rename from python-function.exp. + * gdb.python/py-mi.exp: Rename from python-mi.exp. Adjust + testfile name. + * gdb.python/py-prettyprint.c: Rename from python-prettyprint.c. + * gdb.python/py-prettyprint.exp: Rename from python-prettyprint.exp. + Adjust testfile name. + * gdb.python/py-prettyprint.py: Rename from python-prettyprint.py. + * gdb.python/py-template.cc: Rename from python-template.cc. + * gdb.python/py-template.exp: Rename from python-template.exp. + Adjust testfile name. + * gdb.python/py-value.c: Rename from python-value.c. + * gdb.python/py-value.exp: Rename from python-value.exp. Adjust + testfile name. + 2009-09-08 Jan Kratochvil * gdb.base/breakpoint-shadow.exp (Second breakpoint placed): Initialize diff --git a/gdb/testsuite/gdb.python/Makefile.in b/gdb/testsuite/gdb.python/Makefile.in index 79be9e76eae..ca5cdc72dbf 100644 --- a/gdb/testsuite/gdb.python/Makefile.in +++ b/gdb/testsuite/gdb.python/Makefile.in @@ -1,7 +1,7 @@ VPATH = @srcdir@ srcdir = @srcdir@ -EXECUTABLES = python-value +EXECUTABLES = py-value py-prettyprint py-template all info install-info dvi install uninstall installcheck check: @echo "Nothing to be done for $@..." diff --git a/gdb/testsuite/gdb.python/py-cmd.exp b/gdb/testsuite/gdb.python/py-cmd.exp new file mode 100644 index 00000000000..f6ef938f48a --- /dev/null +++ b/gdb/testsuite/gdb.python/py-cmd.exp @@ -0,0 +1,133 @@ +# Copyright (C) 2009 Free Software Foundation, Inc. + +# 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 . + +# This file is part of the GDB testsuite. It tests the mechanism +# for defining new GDB commands in Python. + +if $tracelevel then { + strace $tracelevel +} + +# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}... +# Run a test named NAME, consisting of multiple lines of input. +# After each input line INPUT, search for result line RESULT. +# Succeed if all results are seen; fail otherwise. +proc gdb_py_test_multiple {name args} { + global gdb_prompt + foreach {input result} $args { + if {[gdb_test_multiple $input "$name - $input" { + -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" { + pass "$name - $input" + } + }]} { + return 1 + } + } + return 0 +} + +# Start with a fresh gdb. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +gdb_test_multiple "python print 'hello, world!'" "verify python support" { + -re "not supported.*$gdb_prompt $" { + unsupported "python support is disabled" + return -1 + } + -re "$gdb_prompt $" {} +} + +# Test a simple command. + +gdb_py_test_multiple "input simple command" \ + "python" "" \ + "class test_cmd (gdb.Command):" "" \ + " def __init__ (self):" "" \ + " super (test_cmd, self).__init__ (\"test_cmd\", gdb.COMMAND_OBSCURE)" "" \ + " def invoke (self, arg, from_tty):" "" \ + " print \"test_cmd output, arg = %s\" % arg" "" \ + "test_cmd ()" "" \ + "end" "" + +gdb_test "test_cmd ugh" "test_cmd output, arg = ugh" "call simple command" + +# Test a prefix command, and a subcommand within it. + +gdb_py_test_multiple "input prefix command" \ + "python" "" \ + "class prefix_cmd (gdb.Command):" "" \ + " def __init__ (self):" "" \ + " super (prefix_cmd, self).__init__ (\"prefix_cmd\", gdb.COMMAND_OBSCURE, gdb.COMPLETE_NONE, True)" "" \ + " def invoke (self, arg, from_tty):" "" \ + " print \"prefix_cmd output, arg = %s\" % arg" "" \ + "prefix_cmd ()" "" \ + "end" "" + +gdb_test "prefix_cmd ugh" "prefix_cmd output, arg = ugh" "call prefix command" + +gdb_py_test_multiple "input subcommand" \ + "python" "" \ + "class subcmd (gdb.Command):" "" \ + " def __init__ (self):" "" \ + " super (subcmd, self).__init__ (\"prefix_cmd subcmd\", gdb.COMMAND_OBSCURE)" "" \ + " def invoke (self, arg, from_tty):" "" \ + " print \"subcmd output, arg = %s\" % arg" "" \ + "subcmd ()" "" \ + "end" "" + +gdb_test "prefix_cmd subcmd ugh" "subcmd output, arg = ugh" "call subcmd" + +# Test prefix command using keyword arguments. + +gdb_py_test_multiple "input prefix command, keyword arguments" \ + "python" "" \ + "class prefix_cmd2 (gdb.Command):" "" \ + " def __init__ (self):" "" \ + " super (prefix_cmd2, self).__init__ (\"prefix_cmd2\", gdb.COMMAND_OBSCURE, prefix = True, completer_class = gdb.COMPLETE_FILENAME)" "" \ + " def invoke (self, arg, from_tty):" "" \ + " print \"prefix_cmd2 output, arg = %s\" % arg" "" \ + "prefix_cmd2 ()" "" \ + "end" "" + +gdb_test "prefix_cmd2 argh" "prefix_cmd2 output, arg = argh" "call prefix command, keyword arguments" + +gdb_py_test_multiple "input subcommand under prefix_cmd2" \ + "python" "" \ + "class subcmd (gdb.Command):" "" \ + " def __init__ (self):" "" \ + " super (subcmd, self).__init__ (\"prefix_cmd2 subcmd\", gdb.COMMAND_OBSCURE)" "" \ + " def invoke (self, arg, from_tty):" "" \ + " print \"subcmd output, arg = %s\" % arg" "" \ + "subcmd ()" "" \ + "end" "" + +gdb_test "prefix_cmd2 subcmd ugh" "subcmd output, arg = ugh" "call subcmd under prefix_cmd2" + +# Test a subcommand in an existing GDB prefix. + +gdb_py_test_multiple "input new subcommand" \ + "python" "" \ + "class newsubcmd (gdb.Command):" "" \ + " def __init__ (self):" "" \ + " super (newsubcmd, self).__init__ (\"info newsubcmd\", gdb.COMMAND_OBSCURE)" "" \ + " def invoke (self, arg, from_tty):" "" \ + " print \"newsubcmd output, arg = %s\" % arg" "" \ + "newsubcmd ()" "" \ + "end" "" + +gdb_test "info newsubcmd ugh" "newsubcmd output, arg = ugh" "call newsubcmd" diff --git a/gdb/testsuite/gdb.python/py-frame.c b/gdb/testsuite/gdb.python/py-frame.c new file mode 100644 index 00000000000..22eb9f2fdf8 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-frame.c @@ -0,0 +1,14 @@ +int f2 (int a) +{ + return ++a; +} + +int f1 (int a, int b) +{ + return f2(a) + b; +} + +int main (int argc, char *argv[]) +{ + return f1 (1, 2); +} diff --git a/gdb/testsuite/gdb.python/py-frame.exp b/gdb/testsuite/gdb.python/py-frame.exp new file mode 100644 index 00000000000..a67eaa35a86 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-frame.exp @@ -0,0 +1,88 @@ +# Copyright (C) 2009 Free Software Foundation, Inc. + +# 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 . + +# This file is part of the GDB testsuite. It tests the mechanism +# exposing values to Python. + +if $tracelevel then { + strace $tracelevel +} + +set testfile "py-frame" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile ${srcfile}" + return -1 +} + +# Run a command in GDB, and report a failure if a Python exception is thrown. +# If report_pass is true, report a pass if no exception is thrown. +proc gdb_py_test_silent_cmd {cmd name report_pass} { + global gdb_prompt + + gdb_test_multiple $cmd $name { + -re "Traceback.*$gdb_prompt $" { fail $name } + -re "$gdb_prompt $" { if $report_pass { pass $name } } + } +} + +# Start with a fresh gdb. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +gdb_test_multiple "python print 'hello, world!'" "verify python support" { + -re "not supported.*$gdb_prompt $" { + unsupported "python support is disabled" + return -1 + } + -re "$gdb_prompt $" {} +} + +# The following tests require execution. + +if ![runto_main] then { + fail "Can't run to main" + return 0 +} + +gdb_breakpoint "f2" +gdb_continue_to_breakpoint "breakpoint at f2" +gdb_test "up" "" "" + +gdb_py_test_silent_cmd "python f1 = gdb.selected_frame ()" "get second frame" 0 +gdb_py_test_silent_cmd "python f0 = f1.newer ()" "get first frame" 0 + +gdb_test "python print 'result =', f0 == f1" " = False" "test equality comparison (false)" +gdb_test "python print 'result =', f0 == f0" " = True" "test equality comparison (true)" +gdb_test "python print 'result =', f0 != f1" " = True" "test inequality comparison (true)" +gdb_test "python print 'result =', f0 != f0" " = False" "test inequality comparison (false)" +gdb_test "python print 'result =', f0.is_valid ()" " = True" "test Frame.is_valid" +gdb_test "python print 'result =', f0.name ()" " = f2" "test Frame.name" +gdb_test "python print 'result =', f0.type () == gdb.NORMAL_FRAME" " = True" "test Frame.type" +gdb_test "python print 'result =', f0.unwind_stop_reason () == gdb.FRAME_UNWIND_NO_REASON" " = True" "test Frame.type" +gdb_test "python print 'result =', gdb.frame_stop_reason_string (gdb.FRAME_UNWIND_INNER_ID)" " = previous frame inner to this frame \\(corrupt stack\\?\\)" "test gdb.frame_stop_reason_string" +gdb_test "python print 'result =', f0.pc ()" " = \[0-9\]+" "test Frame.pc" +gdb_test "python print 'result =', f0.older () == f1" " = True" "test Frame.older" +gdb_test "python print 'result =', f1.newer () == f0" " = True" "test Frame.newer" +gdb_test "python print 'result =', f0.read_var ('variable_which_surely_doesnt_exist')" \ + "ValueError: variable 'variable_which_surely_doesnt_exist' not found.*Error while executing Python code." \ + "test Frame.read_var - error" +gdb_test "python print 'result =', f0.read_var ('a')" " = 1" "test Frame.read_var - success" + +gdb_test "python print 'result =', gdb.selected_frame () == f1" " = True" "test gdb.selected_frame" diff --git a/gdb/testsuite/gdb.python/py-function.exp b/gdb/testsuite/gdb.python/py-function.exp new file mode 100644 index 00000000000..7feca2b6aad --- /dev/null +++ b/gdb/testsuite/gdb.python/py-function.exp @@ -0,0 +1,79 @@ +# Copyright (C) 2009 Free Software Foundation, Inc. + +# 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 . + +# This file is part of the GDB testsuite. It tests the mechanism +# exposing convenience functions to Python. + +if $tracelevel then { + strace $tracelevel +} + +# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}... +# Run a test named NAME, consisting of multiple lines of input. +# After each input line INPUT, search for result line RESULT. +# Succeed if all results are seen; fail otherwise. +proc gdb_py_test_multiple {name args} { + global gdb_prompt + foreach {input result} $args { + if {[gdb_test_multiple $input "$name - $input" { + -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" { + pass "$name - $input" + } + }]} { + return 1 + } + } + return 0 +} + +# Start with a fresh gdb. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +gdb_test_multiple "python print 'hello, world!'" "verify python support" { + -re "not supported.*$gdb_prompt $" { + unsupported "python support is disabled" + return -1 + } + -re "$gdb_prompt $" {} +} + +gdb_py_test_multiple "input convenience function" \ + "python" "" \ + "class test_func (gdb.Function):" "" \ + " def __init__ (self):" "" \ + " super (test_func, self).__init__ (\"test_func\")" "" \ + " def invoke (self, arg):" "" \ + " return \"test_func output, arg = %s\" % arg.string ()" "" \ + "test_func ()" "" \ + "end" "" + +gdb_test "print \$test_func (\"ugh\")" "= \"test_func output, arg = ugh\"" "call function" + +# Test returning a gdb.Value from the function. This segfaulted GDB at one point. + +gdb_py_test_multiple "input value-returning convenience function" \ + "python" "" \ + "class Double (gdb.Function):" "" \ + " def __init__ (self):" "" \ + " super (Double, self).__init__ (\"double\")" "" \ + " def invoke (self, n):" "" \ + " return n*2" "" \ + "Double ()" "" \ + "end" "" + +gdb_test "print \$double (1)" "= 2" "call value-returning function" diff --git a/gdb/testsuite/gdb.python/py-mi.exp b/gdb/testsuite/gdb.python/py-mi.exp new file mode 100644 index 00000000000..d3f44b28c59 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-mi.exp @@ -0,0 +1,99 @@ +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. + +# 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 . + +# This file is part of the GDB testsuite. It tests Python-based +# pretty-printing for MI. + +load_lib mi-support.exp +set MIFLAGS "-i=mi2" + +gdb_exit +if [mi_gdb_start] { + continue +} + +set testfile "py-prettyprint" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-DMI}] != "" } { + untested mi2-var-child.exp + return -1 +} + +mi_delete_breakpoints +mi_gdb_reinitialize_dir $srcdir/$subdir +mi_gdb_load ${binfile} + +if {[lsearch -exact [mi_get_features] python] < 0} { + unsupported "python support is disabled" + return -1 +} + +mi_runto main + +mi_gdb_test "python execfile ('${srcdir}/${subdir}/${testfile}.py')" "" + +mi_continue_to_line [gdb_get_line_number {MI breakpoint here} ${testfile}.c] \ + "step to breakpoint" + +mi_create_floating_varobj container c "create container varobj" + +mi_list_varobj_children container { +} "examine container children=0" + +mi_next "next over update 1" + +mi_varobj_update_dynamic container { + { {container.\[0\]} {\[0\]} 0 int } +} "varobj update 1" + +mi_next "next over update 2" + +mi_varobj_update_dynamic container { + { {container.\[0\]} {\[0\]} 0 int } + { {container.\[1\]} {\[1\]} 0 int } +} "varobj update 2" + +mi_gdb_test "-var-set-visualizer container None" \ + "\\^done" \ + "clear visualizer" + +mi_gdb_test "-var-update container" \ + "\\^done,changelist=\\\[\\\]" \ + "varobj update after clearing" + +mi_gdb_test "-var-set-visualizer container gdb.default_visualizer" \ + "\\^done" \ + "choose default visualizer" + +mi_varobj_update_dynamic container { + { {container.\[0\]} {\[0\]} 0 int } + { {container.\[1\]} {\[1\]} 0 int } +} "varobj update after choosing default" + +mi_gdb_test "-var-set-visualizer container ContainerPrinter" \ + "\\^done" \ + "choose visualizer using expression" + +mi_varobj_update_dynamic container { + { {container.\[0\]} {\[0\]} 0 int } + { {container.\[1\]} {\[1\]} 0 int } +} "varobj update after choosing via expression" + +mi_continue_to_line \ + [gdb_get_line_number {Another MI breakpoint} ${testfile}.c] \ + "step to second breakpoint" + +mi_varobj_update_with_type_change container int 0 "update after type change" diff --git a/gdb/testsuite/gdb.python/py-prettyprint.c b/gdb/testsuite/gdb.python/py-prettyprint.c new file mode 100644 index 00000000000..3cafc482007 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-prettyprint.c @@ -0,0 +1,200 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2008, 2009 Free Software Foundation, Inc. + + 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 . */ + +struct s +{ + int a; + int *b; +}; + +struct ss +{ + struct s a; + struct s b; +}; + +struct ns { + const char *null_str; + int length; +}; + +#ifdef __cplusplus +struct S : public s { + int zs; +}; + +struct SS { + int zss; + S s; +}; + +struct SSS +{ + SSS (int x, const S& r); + int a; + const S &b; +}; +SSS::SSS (int x, const S& r) : a(x), b(r) { } + +class VirtualTest +{ + private: + int value; + + public: + VirtualTest () + { + value = 1; + } +}; + +class Vbase1 : public virtual VirtualTest { }; +class Vbase2 : public virtual VirtualTest { }; +class Vbase3 : public virtual VirtualTest { }; + +class Derived : public Vbase1, public Vbase2, public Vbase3 +{ + private: + int value; + + public: + Derived () + { + value = 2; + } +}; + +#endif + +typedef struct string_repr +{ + struct whybother + { + const char *contents; + } whybother; +} string; + +/* This lets us avoid malloc. */ +int array[100]; + +struct container +{ + string name; + int len; + int *elements; +}; + +typedef struct container zzz_type; + +string +make_string (const char *s) +{ + string result; + result.whybother.contents = s; + return result; +} + +zzz_type +make_container (const char *s) +{ + zzz_type result; + + result.name = make_string (s); + result.len = 0; + result.elements = 0; + + return result; +} + +void +add_item (zzz_type *c, int val) +{ + if (c->len == 0) + c->elements = array; + c->elements[c->len] = val; + ++c->len; +} + +void init_s(struct s *s, int a) +{ + s->a = a; + s->b = &s->a; +} + +void init_ss(struct ss *s, int a, int b) +{ + init_s(&s->a, a); + init_s(&s->b, b); +} + +void do_nothing(void) +{ + int c; + + c = 23; /* Another MI breakpoint */ +} + +int +main () +{ + struct ss ss; + struct ss ssa[2]; + string x = make_string ("this is x"); + zzz_type c = make_container ("container"); + const struct string_repr cstring = { { "const string" } }; + + init_ss(&ss, 1, 2); + init_ss(ssa+0, 3, 4); + init_ss(ssa+1, 5, 6); + + struct ns ns; + ns.null_str = "embedded\0null\0string"; + ns.length = 20; + +#ifdef __cplusplus + S cps; + + cps.zs = 7; + init_s(&cps, 8); + + SS cpss; + cpss.zss = 9; + init_s(&cpss.s, 10); + + SS cpssa[2]; + cpssa[0].zss = 11; + init_s(&cpssa[0].s, 12); + cpssa[1].zss = 13; + init_s(&cpssa[1].s, 14); + + SSS sss(15, cps); + + SSS& ref (sss); + + Derived derived; + +#endif + + add_item (&c, 23); /* MI breakpoint here */ + add_item (&c, 72); + +#ifdef MI + do_nothing (); +#endif + + return 0; /* break to inspect struct and union */ +} diff --git a/gdb/testsuite/gdb.python/py-prettyprint.exp b/gdb/testsuite/gdb.python/py-prettyprint.exp new file mode 100644 index 00000000000..d2db5bc2064 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-prettyprint.exp @@ -0,0 +1,93 @@ +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. + +# 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 . + +# This file is part of the GDB testsuite. It tests Python-based +# pretty-printing for the CLI. + +if $tracelevel then { + strace $tracelevel +} + +set testfile "py-prettyprint" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +# Start with a fresh gdb. +gdb_exit +gdb_start +gdb_test_multiple "python print 'hello, world!'" "verify python support" { + -re "not supported.*$gdb_prompt $" { + unsupported "python support is disabled" + return -1 + } + -re "$gdb_prompt $" {} +} + +proc run_lang_tests {lang} { + global srcdir subdir srcfile binfile testfile hex + if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "debug $lang"] != "" } { + untested "Couldn't compile ${srcfile} in $lang mode" + return -1 + } + + set nl "\[\r\n\]+" + + # Start with a fresh gdb. + gdb_exit + gdb_start + gdb_reinitialize_dir $srcdir/$subdir + gdb_load ${binfile} + + + if ![runto_main ] then { + perror "couldn't run to breakpoint" + return + } + + gdb_test "set print pretty on" "" + + gdb_test "b [gdb_get_line_number {break to inspect} ${testfile}.c ]" \ + ".*Breakpoint.*" + gdb_test "continue" ".*Breakpoint.*" + + gdb_test "python execfile ('${srcdir}/${subdir}/${testfile}.py')" "" + + gdb_test "print ss" " = a=< a=<1> b=<$hex>> b=< a=<2> b=<$hex>>" + gdb_test "print ssa\[1\]" " = a=< a=<5> b=<$hex>> b=< a=<6> b=<$hex>>" + gdb_test "print ssa" " = {a=< a=<3> b=<$hex>> b=< a=<4> b=<$hex>>, a=< a=<5> b=<$hex>> b=< a=<6> b=<$hex>>}" + + if {$lang == "c++"} { + gdb_test "print cps" "= a=<8> b=<$hex>" + gdb_test "print cpss" " = {$nl *zss = 9, *$nl *s = a=<10> b=<$hex>$nl}" + gdb_test "print cpssa\[0\]" " = {$nl *zss = 11, *$nl *s = a=<12> b=<$hex>$nl}" + gdb_test "print cpssa\[1\]" " = {$nl *zss = 13, *$nl *s = a=<14> b=<$hex>$nl}" + gdb_test "print cpssa" " = {{$nl *zss = 11, *$nl *s = a=<12> b=<$hex>$nl *}, {$nl *zss = 13, *$nl *s = a=<14> b=<$hex>$nl *}}" + gdb_test "print sss" "= a=<15> b=< a=<8> b=<$hex>>" + gdb_test "print ref" "= a=<15> b=< a=<8> b=<$hex>>" + gdb_test "print derived" \ + " = \{.* = pp class name: Vbase1.* = \{.* = pp value variable is: 1,.*members of Vbase2:.*_vptr.Vbase2 = $hex.* = \{.*members of Vbase3.*members of Derived:.*value = 2.*" + gdb_test "print ns " "\"embedded\\\\000null\\\\000string\"" + } + + gdb_test "print x" " = $hex \"this is x\"" + gdb_test "print cstring" " = $hex \"const string\"" + + gdb_test "print c" " = container $hex \"container\" with 2 elements = {$nl *.0. = 23,$nl *.1. = 72$nl}" + + gdb_test "continue" "Program exited normally\." +} + +run_lang_tests "c" +run_lang_tests "c++" diff --git a/gdb/testsuite/gdb.python/py-prettyprint.py b/gdb/testsuite/gdb.python/py-prettyprint.py new file mode 100644 index 00000000000..bf009a1e6c1 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-prettyprint.py @@ -0,0 +1,166 @@ +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. + +# 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 . + +# This file is part of the GDB testsuite. It tests python pretty +# printers. + +import re + +# Test returning a Value from a printer. +class string_print: + def __init__(self, val): + self.val = val + + def to_string(self): + return self.val['whybother']['contents'] + +# Test a class-based printer. +class ContainerPrinter: + class _iterator: + def __init__ (self, pointer, len): + self.start = pointer + self.pointer = pointer + self.end = pointer + len + + def __iter__(self): + return self + + def next(self): + if self.pointer == self.end: + raise StopIteration + result = self.pointer + self.pointer = self.pointer + 1 + return ('[%d]' % int (result - self.start), result.dereference()) + + def __init__(self, val): + self.val = val + + def to_string(self): + return 'container %s with %d elements' % (self.val['name'], self.val['len']) + + def children(self): + return self._iterator(self.val['elements'], self.val['len']) + +class pp_s: + def __init__(self, val): + self.val = val + + def to_string(self): + a = self.val["a"] + b = self.val["b"] + if a.address != b: + raise Exception("&a(%s) != b(%s)" % (str(a.address), str(b))) + return " a=<" + str(self.val["a"]) + "> b=<" + str(self.val["b"]) + ">" + +class pp_ss: + def __init__(self, val): + self.val = val + + def to_string(self): + return "a=<" + str(self.val["a"]) + "> b=<" + str(self.val["b"]) + ">" + +class pp_sss: + def __init__(self, val): + self.val = val + + def to_string(self): + return "a=<" + str(self.val['a']) + "> b=<" + str(self.val["b"]) + ">" + +class pp_multiple_virtual: + def __init__ (self, val): + self.val = val + + def to_string (self): + return "pp value variable is: " + str (self.val['value']) + +class pp_vbase1: + def __init__ (self, val): + self.val = val + + def to_string (self): + return "pp class name: " + self.val.type.tag + +class pp_ns: + "Print a std::basic_string of some kind" + + def __init__(self, val): + self.val = val + + def to_string(self): + len = self.val['length'] + return self.val['null_str'].string (gdb.parameter ('target-charset'), length = len) + + def display_hint (self): + return 'string' + +def lookup_function (val): + "Look-up and return a pretty-printer that can print val." + + # Get the type. + type = val.type; + + # If it points to a reference, get the reference. + if type.code == gdb.TYPE_CODE_REF: + type = type.target () + + # Get the unqualified type, stripped of typedefs. + type = type.unqualified ().strip_typedefs () + + # Get the type name. + typename = type.tag + + if typename == None: + return None + + # Iterate over local dictionary of types to determine + # if a printer is registered for that type. Return an + # instantiation of the printer if found. + for function in pretty_printers_dict: + if function.match (typename): + return pretty_printers_dict[function] (val) + + # Cannot find a pretty printer. Return None. + + return None + + +def register_pretty_printers (): + pretty_printers_dict[re.compile ('^struct s$')] = pp_s + pretty_printers_dict[re.compile ('^s$')] = pp_s + pretty_printers_dict[re.compile ('^S$')] = pp_s + + pretty_printers_dict[re.compile ('^struct ss$')] = pp_ss + pretty_printers_dict[re.compile ('^ss$')] = pp_ss + pretty_printers_dict[re.compile ('^const S &$')] = pp_s + pretty_printers_dict[re.compile ('^SSS$')] = pp_sss + + pretty_printers_dict[re.compile ('^VirtualTest$')] = pp_multiple_virtual + pretty_printers_dict[re.compile ('^Vbase1$')] = pp_vbase1 + + # Note that we purposely omit the typedef names here. + # Printer lookup is based on canonical name. + # However, we do need both tagged and untagged variants, to handle + # both the C and C++ cases. + pretty_printers_dict[re.compile ('^struct string_repr$')] = string_print + pretty_printers_dict[re.compile ('^struct container$')] = ContainerPrinter + pretty_printers_dict[re.compile ('^string_repr$')] = string_print + pretty_printers_dict[re.compile ('^container$')] = ContainerPrinter + + pretty_printers_dict[re.compile ('^struct ns$')] = pp_ns + pretty_printers_dict[re.compile ('^ns$')] = pp_ns +pretty_printers_dict = {} + +register_pretty_printers () +gdb.pretty_printers.append (lookup_function) diff --git a/gdb/testsuite/gdb.python/py-template.cc b/gdb/testsuite/gdb.python/py-template.cc new file mode 100644 index 00000000000..bd6a212e70d --- /dev/null +++ b/gdb/testsuite/gdb.python/py-template.cc @@ -0,0 +1,30 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2008 Free Software Foundation, Inc. + + 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 . */ + +template +struct Foo { +}; + +#ifndef TYPE +#define TYPE int +#endif + +int main() +{ + Foo foo; + return 0; // break here +} diff --git a/gdb/testsuite/gdb.python/py-template.exp b/gdb/testsuite/gdb.python/py-template.exp new file mode 100644 index 00000000000..cea6ae04c7b --- /dev/null +++ b/gdb/testsuite/gdb.python/py-template.exp @@ -0,0 +1,75 @@ +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. + +# 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 . + +# This file is part of the GDB testsuite. It tests the mechanism +# exposing values to Python. + +if $tracelevel then { + strace $tracelevel +} + +set testfile "py-template" +set srcfile ${testfile}.cc +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable \ + {debug c++}] != "" } { + untested "Couldn't compile ${srcfile}" + return -1 +} + +# Start with a fresh gdb. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +gdb_test_multiple "python print 23" "verify python support" { + -re "not supported.*$gdb_prompt $" { + unsupported "python support is disabled" + return -1 + } + -re "$gdb_prompt $" {} +} + +proc test_template_arg {type} { + global testfile srcdir subdir srcfile binfile + if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ + executable \ + [list debug c++ additional_flags="-DTYPE=$type"]] != "" } { + untested $type + return -1 + } + gdb_load ${binfile} + if ![runto_main ] then { + perror "couldn't run to breakpoint" + return + } + # There is no executable code in main(), so we are where we want to be + gdb_test "print foo" "" + gdb_test "python foo = gdb.history(0)" "" + + # Replace '*' with '\*' in regex. + regsub -all {\*} $type {\*} t + gdb_test "python print foo.type.template_argument(0)" $t $type +} + +test_template_arg "const int" +test_template_arg "volatile int" +test_template_arg "const int &" +test_template_arg "volatile int &" +test_template_arg "volatile int * const" +test_template_arg "volatile int * const *" +test_template_arg "const int * volatile" +test_template_arg "const int * volatile * const * volatile *" diff --git a/gdb/testsuite/gdb.python/py-value.c b/gdb/testsuite/gdb.python/py-value.c new file mode 100644 index 00000000000..f3d62845369 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-value.c @@ -0,0 +1,55 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2008, 2009 Free Software Foundation, Inc. + + 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 . */ + +struct s +{ + int a; + int b; +}; + +union u +{ + int a; + float b; +}; + +enum e + { + ONE = 1, + TWO = 2 + }; + +typedef struct s *PTR; + +enum e evalue = TWO; + +int +main (int argc, char *argv[]) +{ + char *cp = argv[0]; /* Prevent gcc from optimizing argv[] out. */ + struct s s; + union u u; + PTR x = &s; + char st[17] = "divide et impera"; + char nullst[17] = "divide\0et\0impera"; + + s.a = 3; + s.b = 5; + u.a = 7; + + return 0; /* break to inspect struct and union */ +} diff --git a/gdb/testsuite/gdb.python/py-value.exp b/gdb/testsuite/gdb.python/py-value.exp new file mode 100644 index 00000000000..9b4190de19a --- /dev/null +++ b/gdb/testsuite/gdb.python/py-value.exp @@ -0,0 +1,324 @@ +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. + +# 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 . + +# This file is part of the GDB testsuite. It tests the mechanism +# exposing values to Python. + +if $tracelevel then { + strace $tracelevel +} + +set testfile "py-value" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile ${srcfile}" + return -1 +} + +# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}... +# Run a test named NAME, consisting of multiple lines of input. +# After each input line INPUT, search for result line RESULT. +# Succeed if all results are seen; fail otherwise. +proc gdb_py_test_multiple {name args} { + global gdb_prompt + foreach {input result} $args { + if {[gdb_test_multiple $input "$name - $input" { + -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" { + pass "$name - $input" + } + }]} { + return 1 + } + } + return 0 +} + +# Run a command in GDB, and report a failure if a Python exception is thrown. +# If report_pass is true, report a pass if no exception is thrown. +proc gdb_py_test_silent_cmd {cmd name report_pass} { + global gdb_prompt + + gdb_test_multiple $cmd $name { + -re "Traceback.*$gdb_prompt $" { fail $name } + -re "$gdb_prompt $" { if $report_pass { pass $name } } + } +} + +proc test_value_creation {} { + global gdb_prompt + + gdb_py_test_silent_cmd "python i = gdb.Value (True)" "create boolean value" 1 + gdb_py_test_silent_cmd "python i = gdb.Value (5)" "create integer value" 1 + gdb_py_test_silent_cmd "python i = gdb.Value (5L)" "create long value" 1 + gdb_py_test_silent_cmd "python f = gdb.Value (1.25)" "create double value" 1 + gdb_py_test_silent_cmd "python a = gdb.Value ('string test')" "create 8-bit string value" 1 + gdb_test "python print a" "\"string test\"" "print 8-bit string" + gdb_test "python print a.__class__" "" "verify type of 8-bit string" + gdb_py_test_silent_cmd "python a = gdb.Value (u'unicode test')" "create unicode value" 1 + gdb_test "python print a" "\"unicode test\"" "print Unicode string" + gdb_test "python print a.__class__" "" "verify type of unicode string" + + # Test address attribute is None in a non-addressable value + gdb_test "python print 'result =', i.address" "= None" "Test address attribute in non-addressable value" +} + +proc test_value_numeric_ops {} { + global gdb_prompt + + gdb_py_test_silent_cmd "python i = gdb.Value (5)" "create first integer value" 0 + gdb_py_test_silent_cmd "python j = gdb.Value (2)" "create second integer value" 0 + gdb_py_test_silent_cmd "python f = gdb.Value (1.25)" "create first double value" 0 + gdb_py_test_silent_cmd "python g = gdb.Value (2.5)" "create second double value" 0 + gdb_test "python print 'result = ' + str(i+j)" " = 7" "add two integer values" + gdb_test "python print (i+j).__class__" "" "verify type of integer add result" + + gdb_test "python print 'result = ' + str(f+g)" " = 3.75" "add two double values" + gdb_test "python print 'result = ' + str(i-j)" " = 3" "subtract two integer values" + gdb_test "python print 'result = ' + str(f-g)" " = -1.25" "subtract two double values" + gdb_test "python print 'result = ' + str(i*j)" " = 10" "multiply two integer values" + gdb_test "python print 'result = ' + str(f*g)" " = 3.125" "multiply two double values" + gdb_test "python print 'result = ' + str(i/j)" " = 2" "divide two integer values" + gdb_test "python print 'result = ' + str(f/g)" " = 0.5" "divide two double values" + gdb_test "python print 'result = ' + str(i%j)" " = 1" "take remainder of two integer values" + # Remainder of float is implemented in Python but not in GDB's value system. + + gdb_test "python print 'result = ' + str(i**j)" " = 25" "integer value raised to the power of another integer value" + gdb_test "python print 'result = ' + str(g**j)" " = 6.25" "double value raised to the power of integer value" + + gdb_test "python print 'result = ' + str(-i)" " = -5" "negated integer value" + gdb_test "python print 'result = ' + str(+i)" " = 5" "positive integer value" + gdb_test "python print 'result = ' + str(-f)" " = -1.25" "negated double value" + gdb_test "python print 'result = ' + str(+f)" " = 1.25" "positive double value" + gdb_test "python print 'result = ' + str(abs(j-i))" " = 3" "absolute of integer value" + gdb_test "python print 'result = ' + str(abs(f-g))" " = 1.25" "absolute of double value" + + # Test gdb.Value mixed with Python types. + + gdb_test "python print 'result = ' + str(i-1)" " = 4" "subtract integer value from python integer" + gdb_test "python print (i-1).__class__" "" "verify type of mixed integer subtraction result" + gdb_test "python print 'result = ' + str(f+1.5)" " = 2.75" "add double value with python float" + + gdb_test "python print 'result = ' + str(1-i)" " = -4" "subtract python integer from integer value" + gdb_test "python print 'result = ' + str(1.5+f)" " = 2.75" "add python float with double value" + + # Conversion test. + gdb_test "print evalue" " = TWO" + gdb_test "python evalue = gdb.history (0)" "" + gdb_test "python print int (evalue)" "2" + + # Test pointer arithmethic + + # First, obtain the pointers + gdb_test "print (void *) 2" "" "" + gdb_test "python a = gdb.history (0)" "" "" + gdb_test "print (void *) 5" "" "" + gdb_test "python b = gdb.history (0)" "" "" + + gdb_test "python print 'result = ' + str(a+5)" " = 0x7" "add pointer value with python integer" + gdb_test "python print 'result = ' + str(b-2)" " = 0x3" "subtract python integer from pointer value" + gdb_test "python print 'result = ' + str(b-a)" " = 3" "subtract two pointer values" + + # Test some invalid operations. + + gdb_test_multiple "python print 'result = ' + str(i+'foo')" "catch error in python type conversion" { + -re "Argument to arithmetic operation not a number or boolean.*$gdb_prompt $" {pass "catch error in python type conversion"} + -re "result = .*$gdb_prompt $" {fail "catch error in python type conversion"} + -re "$gdb_prompt $" {fail "catch error in python type conversion"} + } + + gdb_test_multiple "python print 'result = ' + str(i+gdb.Value('foo'))" "catch throw of GDB error" { + -re "Traceback.*$gdb_prompt $" {pass "catch throw of GDB error"} + -re "result = .*$gdb_prompt $" {fail "catch throw of GDB error"} + -re "$gdb_prompt $" {fail "catch throw of GDB error"} + } +} + +proc test_value_boolean {} { + # First, define a useful function to test booleans. + gdb_py_test_multiple "define function to test booleans" \ + "python" "" \ + "def test_bool (val):" "" \ + " if val:" "" \ + " print 'yay'" "" \ + " else:" "" \ + " print 'nay'" "" \ + "end" "" + + gdb_test "py test_bool (gdb.Value (True))" "yay" "check evaluation of true boolean value in expression" + + gdb_test "py test_bool (gdb.Value (False))" "nay" "check evaluation of false boolean value in expression" + + gdb_test "py test_bool (gdb.Value (5))" "yay" "check evaluation of true integer value in expression" + + gdb_test "py test_bool (gdb.Value (0))" "nay" "check evaluation of false integer value in expression" + + gdb_test "py test_bool (gdb.Value (5.2))" "yay" "check evaluation of true integer value in expression" + + gdb_test "py test_bool (gdb.Value (0.0))" "nay" "check evaluation of false integer value in expression" +} + +proc test_value_compare {} { + gdb_test "py print gdb.Value (1) < gdb.Value (1)" "False" "less than, equal" + gdb_test "py print gdb.Value (1) < gdb.Value (2)" "True" "less than, less" + gdb_test "py print gdb.Value (2) < gdb.Value (1)" "False" "less than, greater" + gdb_test "py print gdb.Value (2) < None" "False" "less than, None" + + gdb_test "py print gdb.Value (1) <= gdb.Value (1)" "True" "less or equal, equal" + gdb_test "py print gdb.Value (1) <= gdb.Value (2)" "True" "less or equal, less" + gdb_test "py print gdb.Value (2) <= gdb.Value (1)" "False" "less or equal, greater" + gdb_test "py print gdb.Value (2) <= None" "False" "less or equal, None" + + gdb_test "py print gdb.Value (1) == gdb.Value (1)" "True" "equality of gdb.Values" + gdb_test "py print gdb.Value (1) == gdb.Value (2)" "False" "inequality of gdb.Values" + gdb_test "py print gdb.Value (1) == 1.0" "True" "equality of gdb.Value with Python value" + gdb_test "py print gdb.Value (1) == 2" "False" "inequality of gdb.Value with Python value" + gdb_test "py print gdb.Value (1) == None" "False" "inequality of gdb.Value with None" + + gdb_test "py print gdb.Value (1) != gdb.Value (1)" "False" "inequality, false" + gdb_test "py print gdb.Value (1) != gdb.Value (2)" "True" "inequality, true" + gdb_test "py print gdb.Value (1) != None" "True" "inequality, None" + + gdb_test "py print gdb.Value (1) > gdb.Value (1)" "False" "greater than, equal" + gdb_test "py print gdb.Value (1) > gdb.Value (2)" "False" "greater than, less" + gdb_test "py print gdb.Value (2) > gdb.Value (1)" "True" "greater than, greater" + gdb_test "py print gdb.Value (2) > None" "True" "greater than, None" + + gdb_test "py print gdb.Value (1) >= gdb.Value (1)" "True" "greater or equal, equal" + gdb_test "py print gdb.Value (1) >= gdb.Value (2)" "False" "greater or equal, less" + gdb_test "py print gdb.Value (2) >= gdb.Value (1)" "True" "greater or equal, greater" + gdb_test "py print gdb.Value (2) >= None" "True" "greater or equal, None" +} + +proc test_value_in_inferior {} { + global gdb_prompt + global testfile + + gdb_breakpoint [gdb_get_line_number "break to inspect struct and union"] + + gdb_continue_to_breakpoint "break to inspect struct and union" + + # Just get inferior variable s in the value history, available to python. + gdb_test "print s" " = {a = 3, b = 5}" "" + + gdb_py_test_silent_cmd "python s = gdb.history (0)" "get value from history" 1 + + gdb_test "python print 'result = ' + str(s\['a'\])" " = 3" "access element inside struct using 8-bit string name" + gdb_test "python print 'result = ' + str(s\[u'a'\])" " = 3" "access element inside struct using unicode name" + + # Test dereferencing the argv pointer + + # Just get inferior variable argv the value history, available to python. + gdb_test "print argv" " = \\(char \\*\\*\\) 0x.*" "" + + gdb_py_test_silent_cmd "python argv = gdb.history (0)" "" 0 + gdb_py_test_silent_cmd "python arg0 = argv.dereference ()" "dereference value" 1 + + # Check that the dereferenced value is sane + gdb_test "python print arg0" "0x.*$testfile\"" "verify dereferenced value" + + # Smoke-test is_optimized_out attribute + gdb_test "python print 'result =', arg0.is_optimized_out" "= False" "Test is_optimized_out attribute" + + # Test address attribute + gdb_test "python print 'result =', arg0.address" "= 0x\[\[:xdigit:\]\]+" "Test address attribute" + + # Test string fetches, both partial and whole. + gdb_test "print st" "\"divide et impera\"" + gdb_py_test_silent_cmd "python st = gdb.history (0)" "get value from history" 1 + gdb_test "python print st.string ()" "divide et impera" "Test string with no length" + gdb_test "python print st.string (length = -1)" "divide et impera" "Test string (length = -1) is all of the string" + gdb_test "python print st.string (length = 6)" "divide" + gdb_test "python print \"---\"+st.string (length = 0)+\"---\"" "------" "Test string (length = 0) is empty" + gdb_test "python print len(st.string (length = 0))" "0" "Test length is 0" + + + # Fetch a string that has embedded nulls. + gdb_test "print nullst" "\"divide\\\\000et\\\\000impera\".*" + gdb_py_test_silent_cmd "python nullst = gdb.history (0)" "get value from history" 1 + gdb_test "python print nullst.string ()" "divide" "Test string to first null" + # Python cannot print strings that contain the null (\0) character. + # For the purposes of this test, use repr() + gdb_py_test_silent_cmd "python nullst = nullst.string (length = 9)" "get string beyond null" 1 + gdb_test "python print repr(nullst)" "u'divide\\\\x00et'" +} + +# A few objfile tests. +proc test_objfiles {} { + gdb_test "python\nok=False\nfor file in gdb.objfiles():\n if 'py-value' in file.filename:\n ok=True\nprint ok\nend" "True" + + gdb_test "python print gdb.objfiles()\[0\].pretty_printers" "\\\[\\\]" + + gdb_test "python gdb.objfiles()\[0\].pretty_printers = 0" \ + "pretty_printers attribute must be a list.*Error while executing Python code." +} + +proc test_value_after_death {} { + # Construct a type while the inferior is still running. + gdb_py_test_silent_cmd "python ptrtype = gdb.lookup_type('PTR')" \ + "create PTR type" 1 + + # Kill the inferior and remove the symbols. + gdb_test "kill" "" "kill the inferior" \ + "Kill the program being debugged. .y or n. $" \ + "y" + gdb_test "file" "" "Discard the symbols" \ + "Discard symbol table from.*y or n. $" \ + "y" + + # Now create a value using that type. Relies on arg0, created by + # test_value_in_inferior. + gdb_py_test_silent_cmd "python castval = arg0.cast(ptrtype.pointer())" \ + "cast arg0 to PTR" 1 + + # Make sure the type is deleted. + gdb_py_test_silent_cmd "python ptrtype = None" \ + "delete PTR type" 1 + + # Now see if the value's type is still valid. + gdb_test "python print castval.type" "PTR ." \ + "print value's type" +} + +# Start with a fresh gdb. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +gdb_test_multiple "python print 'hello, world!'" "verify python support" { + -re "not supported.*$gdb_prompt $" { + unsupported "python support is disabled" + return -1 + } + -re "$gdb_prompt $" {} +} + +test_value_creation +test_value_numeric_ops +test_value_boolean +test_value_compare +test_objfiles + +# The following tests require execution. + +if ![runto_main] then { + fail "Can't run to main" + return 0 +} + +test_value_in_inferior +test_value_after_death diff --git a/gdb/testsuite/gdb.python/python-cmd.exp b/gdb/testsuite/gdb.python/python-cmd.exp deleted file mode 100644 index f6ef938f48a..00000000000 --- a/gdb/testsuite/gdb.python/python-cmd.exp +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright (C) 2009 Free Software Foundation, Inc. - -# 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 . - -# This file is part of the GDB testsuite. It tests the mechanism -# for defining new GDB commands in Python. - -if $tracelevel then { - strace $tracelevel -} - -# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}... -# Run a test named NAME, consisting of multiple lines of input. -# After each input line INPUT, search for result line RESULT. -# Succeed if all results are seen; fail otherwise. -proc gdb_py_test_multiple {name args} { - global gdb_prompt - foreach {input result} $args { - if {[gdb_test_multiple $input "$name - $input" { - -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" { - pass "$name - $input" - } - }]} { - return 1 - } - } - return 0 -} - -# Start with a fresh gdb. - -gdb_exit -gdb_start -gdb_reinitialize_dir $srcdir/$subdir - -gdb_test_multiple "python print 'hello, world!'" "verify python support" { - -re "not supported.*$gdb_prompt $" { - unsupported "python support is disabled" - return -1 - } - -re "$gdb_prompt $" {} -} - -# Test a simple command. - -gdb_py_test_multiple "input simple command" \ - "python" "" \ - "class test_cmd (gdb.Command):" "" \ - " def __init__ (self):" "" \ - " super (test_cmd, self).__init__ (\"test_cmd\", gdb.COMMAND_OBSCURE)" "" \ - " def invoke (self, arg, from_tty):" "" \ - " print \"test_cmd output, arg = %s\" % arg" "" \ - "test_cmd ()" "" \ - "end" "" - -gdb_test "test_cmd ugh" "test_cmd output, arg = ugh" "call simple command" - -# Test a prefix command, and a subcommand within it. - -gdb_py_test_multiple "input prefix command" \ - "python" "" \ - "class prefix_cmd (gdb.Command):" "" \ - " def __init__ (self):" "" \ - " super (prefix_cmd, self).__init__ (\"prefix_cmd\", gdb.COMMAND_OBSCURE, gdb.COMPLETE_NONE, True)" "" \ - " def invoke (self, arg, from_tty):" "" \ - " print \"prefix_cmd output, arg = %s\" % arg" "" \ - "prefix_cmd ()" "" \ - "end" "" - -gdb_test "prefix_cmd ugh" "prefix_cmd output, arg = ugh" "call prefix command" - -gdb_py_test_multiple "input subcommand" \ - "python" "" \ - "class subcmd (gdb.Command):" "" \ - " def __init__ (self):" "" \ - " super (subcmd, self).__init__ (\"prefix_cmd subcmd\", gdb.COMMAND_OBSCURE)" "" \ - " def invoke (self, arg, from_tty):" "" \ - " print \"subcmd output, arg = %s\" % arg" "" \ - "subcmd ()" "" \ - "end" "" - -gdb_test "prefix_cmd subcmd ugh" "subcmd output, arg = ugh" "call subcmd" - -# Test prefix command using keyword arguments. - -gdb_py_test_multiple "input prefix command, keyword arguments" \ - "python" "" \ - "class prefix_cmd2 (gdb.Command):" "" \ - " def __init__ (self):" "" \ - " super (prefix_cmd2, self).__init__ (\"prefix_cmd2\", gdb.COMMAND_OBSCURE, prefix = True, completer_class = gdb.COMPLETE_FILENAME)" "" \ - " def invoke (self, arg, from_tty):" "" \ - " print \"prefix_cmd2 output, arg = %s\" % arg" "" \ - "prefix_cmd2 ()" "" \ - "end" "" - -gdb_test "prefix_cmd2 argh" "prefix_cmd2 output, arg = argh" "call prefix command, keyword arguments" - -gdb_py_test_multiple "input subcommand under prefix_cmd2" \ - "python" "" \ - "class subcmd (gdb.Command):" "" \ - " def __init__ (self):" "" \ - " super (subcmd, self).__init__ (\"prefix_cmd2 subcmd\", gdb.COMMAND_OBSCURE)" "" \ - " def invoke (self, arg, from_tty):" "" \ - " print \"subcmd output, arg = %s\" % arg" "" \ - "subcmd ()" "" \ - "end" "" - -gdb_test "prefix_cmd2 subcmd ugh" "subcmd output, arg = ugh" "call subcmd under prefix_cmd2" - -# Test a subcommand in an existing GDB prefix. - -gdb_py_test_multiple "input new subcommand" \ - "python" "" \ - "class newsubcmd (gdb.Command):" "" \ - " def __init__ (self):" "" \ - " super (newsubcmd, self).__init__ (\"info newsubcmd\", gdb.COMMAND_OBSCURE)" "" \ - " def invoke (self, arg, from_tty):" "" \ - " print \"newsubcmd output, arg = %s\" % arg" "" \ - "newsubcmd ()" "" \ - "end" "" - -gdb_test "info newsubcmd ugh" "newsubcmd output, arg = ugh" "call newsubcmd" diff --git a/gdb/testsuite/gdb.python/python-frame.c b/gdb/testsuite/gdb.python/python-frame.c deleted file mode 100644 index 22eb9f2fdf8..00000000000 --- a/gdb/testsuite/gdb.python/python-frame.c +++ /dev/null @@ -1,14 +0,0 @@ -int f2 (int a) -{ - return ++a; -} - -int f1 (int a, int b) -{ - return f2(a) + b; -} - -int main (int argc, char *argv[]) -{ - return f1 (1, 2); -} diff --git a/gdb/testsuite/gdb.python/python-frame.exp b/gdb/testsuite/gdb.python/python-frame.exp deleted file mode 100644 index 82b526ec765..00000000000 --- a/gdb/testsuite/gdb.python/python-frame.exp +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright (C) 2009 Free Software Foundation, Inc. - -# 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 . - -# This file is part of the GDB testsuite. It tests the mechanism -# exposing values to Python. - -if $tracelevel then { - strace $tracelevel -} - -set testfile "python-frame" -set srcfile ${testfile}.c -set binfile ${objdir}/${subdir}/${testfile} -if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { - untested "Couldn't compile ${srcfile}" - return -1 -} - -# Run a command in GDB, and report a failure if a Python exception is thrown. -# If report_pass is true, report a pass if no exception is thrown. -proc gdb_py_test_silent_cmd {cmd name report_pass} { - global gdb_prompt - - gdb_test_multiple $cmd $name { - -re "Traceback.*$gdb_prompt $" { fail $name } - -re "$gdb_prompt $" { if $report_pass { pass $name } } - } -} - -# Start with a fresh gdb. - -gdb_exit -gdb_start -gdb_reinitialize_dir $srcdir/$subdir -gdb_load ${binfile} - -gdb_test_multiple "python print 'hello, world!'" "verify python support" { - -re "not supported.*$gdb_prompt $" { - unsupported "python support is disabled" - return -1 - } - -re "$gdb_prompt $" {} -} - -# The following tests require execution. - -if ![runto_main] then { - fail "Can't run to main" - return 0 -} - -gdb_breakpoint "f2" -gdb_continue_to_breakpoint "breakpoint at f2" -gdb_test "up" "" "" - -gdb_py_test_silent_cmd "python f1 = gdb.selected_frame ()" "get second frame" 0 -gdb_py_test_silent_cmd "python f0 = f1.newer ()" "get first frame" 0 - -gdb_test "python print 'result =', f0 == f1" " = False" "test equality comparison (false)" -gdb_test "python print 'result =', f0 == f0" " = True" "test equality comparison (true)" -gdb_test "python print 'result =', f0 != f1" " = True" "test inequality comparison (true)" -gdb_test "python print 'result =', f0 != f0" " = False" "test inequality comparison (false)" -gdb_test "python print 'result =', f0.is_valid ()" " = True" "test Frame.is_valid" -gdb_test "python print 'result =', f0.name ()" " = f2" "test Frame.name" -gdb_test "python print 'result =', f0.type () == gdb.NORMAL_FRAME" " = True" "test Frame.type" -gdb_test "python print 'result =', f0.unwind_stop_reason () == gdb.FRAME_UNWIND_NO_REASON" " = True" "test Frame.type" -gdb_test "python print 'result =', gdb.frame_stop_reason_string (gdb.FRAME_UNWIND_INNER_ID)" " = previous frame inner to this frame \\(corrupt stack\\?\\)" "test gdb.frame_stop_reason_string" -gdb_test "python print 'result =', f0.pc ()" " = \[0-9\]+" "test Frame.pc" -gdb_test "python print 'result =', f0.older () == f1" " = True" "test Frame.older" -gdb_test "python print 'result =', f1.newer () == f0" " = True" "test Frame.newer" -gdb_test "python print 'result =', f0.read_var ('variable_which_surely_doesnt_exist')" \ - "ValueError: variable 'variable_which_surely_doesnt_exist' not found.*Error while executing Python code." \ - "test Frame.read_var - error" -gdb_test "python print 'result =', f0.read_var ('a')" " = 1" "test Frame.read_var - success" - -gdb_test "python print 'result =', gdb.selected_frame () == f1" " = True" "test gdb.selected_frame" diff --git a/gdb/testsuite/gdb.python/python-function.exp b/gdb/testsuite/gdb.python/python-function.exp deleted file mode 100644 index 7feca2b6aad..00000000000 --- a/gdb/testsuite/gdb.python/python-function.exp +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright (C) 2009 Free Software Foundation, Inc. - -# 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 . - -# This file is part of the GDB testsuite. It tests the mechanism -# exposing convenience functions to Python. - -if $tracelevel then { - strace $tracelevel -} - -# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}... -# Run a test named NAME, consisting of multiple lines of input. -# After each input line INPUT, search for result line RESULT. -# Succeed if all results are seen; fail otherwise. -proc gdb_py_test_multiple {name args} { - global gdb_prompt - foreach {input result} $args { - if {[gdb_test_multiple $input "$name - $input" { - -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" { - pass "$name - $input" - } - }]} { - return 1 - } - } - return 0 -} - -# Start with a fresh gdb. - -gdb_exit -gdb_start -gdb_reinitialize_dir $srcdir/$subdir - -gdb_test_multiple "python print 'hello, world!'" "verify python support" { - -re "not supported.*$gdb_prompt $" { - unsupported "python support is disabled" - return -1 - } - -re "$gdb_prompt $" {} -} - -gdb_py_test_multiple "input convenience function" \ - "python" "" \ - "class test_func (gdb.Function):" "" \ - " def __init__ (self):" "" \ - " super (test_func, self).__init__ (\"test_func\")" "" \ - " def invoke (self, arg):" "" \ - " return \"test_func output, arg = %s\" % arg.string ()" "" \ - "test_func ()" "" \ - "end" "" - -gdb_test "print \$test_func (\"ugh\")" "= \"test_func output, arg = ugh\"" "call function" - -# Test returning a gdb.Value from the function. This segfaulted GDB at one point. - -gdb_py_test_multiple "input value-returning convenience function" \ - "python" "" \ - "class Double (gdb.Function):" "" \ - " def __init__ (self):" "" \ - " super (Double, self).__init__ (\"double\")" "" \ - " def invoke (self, n):" "" \ - " return n*2" "" \ - "Double ()" "" \ - "end" "" - -gdb_test "print \$double (1)" "= 2" "call value-returning function" diff --git a/gdb/testsuite/gdb.python/python-mi.exp b/gdb/testsuite/gdb.python/python-mi.exp deleted file mode 100644 index 32588105d9a..00000000000 --- a/gdb/testsuite/gdb.python/python-mi.exp +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright (C) 2008, 2009 Free Software Foundation, Inc. - -# 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 . - -# This file is part of the GDB testsuite. It tests Python-based -# pretty-printing for MI. - -load_lib mi-support.exp -set MIFLAGS "-i=mi2" - -gdb_exit -if [mi_gdb_start] { - continue -} - -set testfile "python-prettyprint" -set srcfile ${testfile}.c -set binfile ${objdir}/${subdir}/${testfile} -if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-DMI}] != "" } { - untested mi2-var-child.exp - return -1 -} - -mi_delete_breakpoints -mi_gdb_reinitialize_dir $srcdir/$subdir -mi_gdb_load ${binfile} - -if {[lsearch -exact [mi_get_features] python] < 0} { - unsupported "python support is disabled" - return -1 -} - -mi_runto main - -mi_gdb_test "python execfile ('${srcdir}/${subdir}/${testfile}.py')" "" - -mi_continue_to_line [gdb_get_line_number {MI breakpoint here} ${testfile}.c] \ - "step to breakpoint" - -mi_create_floating_varobj container c "create container varobj" - -mi_list_varobj_children container { -} "examine container children=0" - -mi_next "next over update 1" - -mi_varobj_update_dynamic container { - { {container.\[0\]} {\[0\]} 0 int } -} "varobj update 1" - -mi_next "next over update 2" - -mi_varobj_update_dynamic container { - { {container.\[0\]} {\[0\]} 0 int } - { {container.\[1\]} {\[1\]} 0 int } -} "varobj update 2" - -mi_gdb_test "-var-set-visualizer container None" \ - "\\^done" \ - "clear visualizer" - -mi_gdb_test "-var-update container" \ - "\\^done,changelist=\\\[\\\]" \ - "varobj update after clearing" - -mi_gdb_test "-var-set-visualizer container gdb.default_visualizer" \ - "\\^done" \ - "choose default visualizer" - -mi_varobj_update_dynamic container { - { {container.\[0\]} {\[0\]} 0 int } - { {container.\[1\]} {\[1\]} 0 int } -} "varobj update after choosing default" - -mi_gdb_test "-var-set-visualizer container ContainerPrinter" \ - "\\^done" \ - "choose visualizer using expression" - -mi_varobj_update_dynamic container { - { {container.\[0\]} {\[0\]} 0 int } - { {container.\[1\]} {\[1\]} 0 int } -} "varobj update after choosing via expression" - -mi_continue_to_line \ - [gdb_get_line_number {Another MI breakpoint} ${testfile}.c] \ - "step to second breakpoint" - -mi_varobj_update_with_type_change container int 0 "update after type change" diff --git a/gdb/testsuite/gdb.python/python-prettyprint.c b/gdb/testsuite/gdb.python/python-prettyprint.c deleted file mode 100644 index 3cafc482007..00000000000 --- a/gdb/testsuite/gdb.python/python-prettyprint.c +++ /dev/null @@ -1,200 +0,0 @@ -/* This testcase is part of GDB, the GNU debugger. - - Copyright 2008, 2009 Free Software Foundation, Inc. - - 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 . */ - -struct s -{ - int a; - int *b; -}; - -struct ss -{ - struct s a; - struct s b; -}; - -struct ns { - const char *null_str; - int length; -}; - -#ifdef __cplusplus -struct S : public s { - int zs; -}; - -struct SS { - int zss; - S s; -}; - -struct SSS -{ - SSS (int x, const S& r); - int a; - const S &b; -}; -SSS::SSS (int x, const S& r) : a(x), b(r) { } - -class VirtualTest -{ - private: - int value; - - public: - VirtualTest () - { - value = 1; - } -}; - -class Vbase1 : public virtual VirtualTest { }; -class Vbase2 : public virtual VirtualTest { }; -class Vbase3 : public virtual VirtualTest { }; - -class Derived : public Vbase1, public Vbase2, public Vbase3 -{ - private: - int value; - - public: - Derived () - { - value = 2; - } -}; - -#endif - -typedef struct string_repr -{ - struct whybother - { - const char *contents; - } whybother; -} string; - -/* This lets us avoid malloc. */ -int array[100]; - -struct container -{ - string name; - int len; - int *elements; -}; - -typedef struct container zzz_type; - -string -make_string (const char *s) -{ - string result; - result.whybother.contents = s; - return result; -} - -zzz_type -make_container (const char *s) -{ - zzz_type result; - - result.name = make_string (s); - result.len = 0; - result.elements = 0; - - return result; -} - -void -add_item (zzz_type *c, int val) -{ - if (c->len == 0) - c->elements = array; - c->elements[c->len] = val; - ++c->len; -} - -void init_s(struct s *s, int a) -{ - s->a = a; - s->b = &s->a; -} - -void init_ss(struct ss *s, int a, int b) -{ - init_s(&s->a, a); - init_s(&s->b, b); -} - -void do_nothing(void) -{ - int c; - - c = 23; /* Another MI breakpoint */ -} - -int -main () -{ - struct ss ss; - struct ss ssa[2]; - string x = make_string ("this is x"); - zzz_type c = make_container ("container"); - const struct string_repr cstring = { { "const string" } }; - - init_ss(&ss, 1, 2); - init_ss(ssa+0, 3, 4); - init_ss(ssa+1, 5, 6); - - struct ns ns; - ns.null_str = "embedded\0null\0string"; - ns.length = 20; - -#ifdef __cplusplus - S cps; - - cps.zs = 7; - init_s(&cps, 8); - - SS cpss; - cpss.zss = 9; - init_s(&cpss.s, 10); - - SS cpssa[2]; - cpssa[0].zss = 11; - init_s(&cpssa[0].s, 12); - cpssa[1].zss = 13; - init_s(&cpssa[1].s, 14); - - SSS sss(15, cps); - - SSS& ref (sss); - - Derived derived; - -#endif - - add_item (&c, 23); /* MI breakpoint here */ - add_item (&c, 72); - -#ifdef MI - do_nothing (); -#endif - - return 0; /* break to inspect struct and union */ -} diff --git a/gdb/testsuite/gdb.python/python-prettyprint.exp b/gdb/testsuite/gdb.python/python-prettyprint.exp deleted file mode 100644 index 01d4a06c89f..00000000000 --- a/gdb/testsuite/gdb.python/python-prettyprint.exp +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright (C) 2008, 2009 Free Software Foundation, Inc. - -# 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 . - -# This file is part of the GDB testsuite. It tests Python-based -# pretty-printing for the CLI. - -if $tracelevel then { - strace $tracelevel -} - -set testfile "python-prettyprint" -set srcfile ${testfile}.c -set binfile ${objdir}/${subdir}/${testfile} - -# Start with a fresh gdb. -gdb_exit -gdb_start -gdb_test_multiple "python print 'hello, world!'" "verify python support" { - -re "not supported.*$gdb_prompt $" { - unsupported "python support is disabled" - return -1 - } - -re "$gdb_prompt $" {} -} - -proc run_lang_tests {lang} { - global srcdir subdir srcfile binfile testfile hex - if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "debug $lang"] != "" } { - untested "Couldn't compile ${srcfile} in $lang mode" - return -1 - } - - set nl "\[\r\n\]+" - - # Start with a fresh gdb. - gdb_exit - gdb_start - gdb_reinitialize_dir $srcdir/$subdir - gdb_load ${binfile} - - - if ![runto_main ] then { - perror "couldn't run to breakpoint" - return - } - - gdb_test "set print pretty on" "" - - gdb_test "b [gdb_get_line_number {break to inspect} ${testfile}.c ]" \ - ".*Breakpoint.*" - gdb_test "continue" ".*Breakpoint.*" - - gdb_test "python execfile ('${srcdir}/${subdir}/${testfile}.py')" "" - - gdb_test "print ss" " = a=< a=<1> b=<$hex>> b=< a=<2> b=<$hex>>" - gdb_test "print ssa\[1\]" " = a=< a=<5> b=<$hex>> b=< a=<6> b=<$hex>>" - gdb_test "print ssa" " = {a=< a=<3> b=<$hex>> b=< a=<4> b=<$hex>>, a=< a=<5> b=<$hex>> b=< a=<6> b=<$hex>>}" - - if {$lang == "c++"} { - gdb_test "print cps" "= a=<8> b=<$hex>" - gdb_test "print cpss" " = {$nl *zss = 9, *$nl *s = a=<10> b=<$hex>$nl}" - gdb_test "print cpssa\[0\]" " = {$nl *zss = 11, *$nl *s = a=<12> b=<$hex>$nl}" - gdb_test "print cpssa\[1\]" " = {$nl *zss = 13, *$nl *s = a=<14> b=<$hex>$nl}" - gdb_test "print cpssa" " = {{$nl *zss = 11, *$nl *s = a=<12> b=<$hex>$nl *}, {$nl *zss = 13, *$nl *s = a=<14> b=<$hex>$nl *}}" - gdb_test "print sss" "= a=<15> b=< a=<8> b=<$hex>>" - gdb_test "print ref" "= a=<15> b=< a=<8> b=<$hex>>" - gdb_test "print derived" \ - " = \{.* = pp class name: Vbase1.* = \{.* = pp value variable is: 1,.*members of Vbase2:.*_vptr.Vbase2 = $hex.* = \{.*members of Vbase3.*members of Derived:.*value = 2.*" - gdb_test "print ns " "\"embedded\\\\000null\\\\000string\"" - } - - gdb_test "print x" " = $hex \"this is x\"" - gdb_test "print cstring" " = $hex \"const string\"" - - gdb_test "print c" " = container $hex \"container\" with 2 elements = {$nl *.0. = 23,$nl *.1. = 72$nl}" - - gdb_test "continue" "Program exited normally\." -} - -run_lang_tests "c" -run_lang_tests "c++" diff --git a/gdb/testsuite/gdb.python/python-prettyprint.py b/gdb/testsuite/gdb.python/python-prettyprint.py deleted file mode 100644 index bf009a1e6c1..00000000000 --- a/gdb/testsuite/gdb.python/python-prettyprint.py +++ /dev/null @@ -1,166 +0,0 @@ -# Copyright (C) 2008, 2009 Free Software Foundation, Inc. - -# 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 . - -# This file is part of the GDB testsuite. It tests python pretty -# printers. - -import re - -# Test returning a Value from a printer. -class string_print: - def __init__(self, val): - self.val = val - - def to_string(self): - return self.val['whybother']['contents'] - -# Test a class-based printer. -class ContainerPrinter: - class _iterator: - def __init__ (self, pointer, len): - self.start = pointer - self.pointer = pointer - self.end = pointer + len - - def __iter__(self): - return self - - def next(self): - if self.pointer == self.end: - raise StopIteration - result = self.pointer - self.pointer = self.pointer + 1 - return ('[%d]' % int (result - self.start), result.dereference()) - - def __init__(self, val): - self.val = val - - def to_string(self): - return 'container %s with %d elements' % (self.val['name'], self.val['len']) - - def children(self): - return self._iterator(self.val['elements'], self.val['len']) - -class pp_s: - def __init__(self, val): - self.val = val - - def to_string(self): - a = self.val["a"] - b = self.val["b"] - if a.address != b: - raise Exception("&a(%s) != b(%s)" % (str(a.address), str(b))) - return " a=<" + str(self.val["a"]) + "> b=<" + str(self.val["b"]) + ">" - -class pp_ss: - def __init__(self, val): - self.val = val - - def to_string(self): - return "a=<" + str(self.val["a"]) + "> b=<" + str(self.val["b"]) + ">" - -class pp_sss: - def __init__(self, val): - self.val = val - - def to_string(self): - return "a=<" + str(self.val['a']) + "> b=<" + str(self.val["b"]) + ">" - -class pp_multiple_virtual: - def __init__ (self, val): - self.val = val - - def to_string (self): - return "pp value variable is: " + str (self.val['value']) - -class pp_vbase1: - def __init__ (self, val): - self.val = val - - def to_string (self): - return "pp class name: " + self.val.type.tag - -class pp_ns: - "Print a std::basic_string of some kind" - - def __init__(self, val): - self.val = val - - def to_string(self): - len = self.val['length'] - return self.val['null_str'].string (gdb.parameter ('target-charset'), length = len) - - def display_hint (self): - return 'string' - -def lookup_function (val): - "Look-up and return a pretty-printer that can print val." - - # Get the type. - type = val.type; - - # If it points to a reference, get the reference. - if type.code == gdb.TYPE_CODE_REF: - type = type.target () - - # Get the unqualified type, stripped of typedefs. - type = type.unqualified ().strip_typedefs () - - # Get the type name. - typename = type.tag - - if typename == None: - return None - - # Iterate over local dictionary of types to determine - # if a printer is registered for that type. Return an - # instantiation of the printer if found. - for function in pretty_printers_dict: - if function.match (typename): - return pretty_printers_dict[function] (val) - - # Cannot find a pretty printer. Return None. - - return None - - -def register_pretty_printers (): - pretty_printers_dict[re.compile ('^struct s$')] = pp_s - pretty_printers_dict[re.compile ('^s$')] = pp_s - pretty_printers_dict[re.compile ('^S$')] = pp_s - - pretty_printers_dict[re.compile ('^struct ss$')] = pp_ss - pretty_printers_dict[re.compile ('^ss$')] = pp_ss - pretty_printers_dict[re.compile ('^const S &$')] = pp_s - pretty_printers_dict[re.compile ('^SSS$')] = pp_sss - - pretty_printers_dict[re.compile ('^VirtualTest$')] = pp_multiple_virtual - pretty_printers_dict[re.compile ('^Vbase1$')] = pp_vbase1 - - # Note that we purposely omit the typedef names here. - # Printer lookup is based on canonical name. - # However, we do need both tagged and untagged variants, to handle - # both the C and C++ cases. - pretty_printers_dict[re.compile ('^struct string_repr$')] = string_print - pretty_printers_dict[re.compile ('^struct container$')] = ContainerPrinter - pretty_printers_dict[re.compile ('^string_repr$')] = string_print - pretty_printers_dict[re.compile ('^container$')] = ContainerPrinter - - pretty_printers_dict[re.compile ('^struct ns$')] = pp_ns - pretty_printers_dict[re.compile ('^ns$')] = pp_ns -pretty_printers_dict = {} - -register_pretty_printers () -gdb.pretty_printers.append (lookup_function) diff --git a/gdb/testsuite/gdb.python/python-template.cc b/gdb/testsuite/gdb.python/python-template.cc deleted file mode 100644 index bd6a212e70d..00000000000 --- a/gdb/testsuite/gdb.python/python-template.cc +++ /dev/null @@ -1,30 +0,0 @@ -/* This testcase is part of GDB, the GNU debugger. - - Copyright 2008 Free Software Foundation, Inc. - - 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 . */ - -template -struct Foo { -}; - -#ifndef TYPE -#define TYPE int -#endif - -int main() -{ - Foo foo; - return 0; // break here -} diff --git a/gdb/testsuite/gdb.python/python-template.exp b/gdb/testsuite/gdb.python/python-template.exp deleted file mode 100644 index 1ace5d6e2fa..00000000000 --- a/gdb/testsuite/gdb.python/python-template.exp +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright (C) 2008, 2009 Free Software Foundation, Inc. - -# 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 . - -# This file is part of the GDB testsuite. It tests the mechanism -# exposing values to Python. - -if $tracelevel then { - strace $tracelevel -} - -set testfile "python-template" -set srcfile ${testfile}.cc -set binfile ${objdir}/${subdir}/${testfile} -if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable \ - {debug c++}] != "" } { - untested "Couldn't compile ${srcfile}" - return -1 -} - -# Start with a fresh gdb. - -gdb_exit -gdb_start -gdb_reinitialize_dir $srcdir/$subdir - -gdb_test_multiple "python print 23" "verify python support" { - -re "not supported.*$gdb_prompt $" { - unsupported "python support is disabled" - return -1 - } - -re "$gdb_prompt $" {} -} - -proc test_template_arg {type} { - global testfile srcdir subdir srcfile binfile - if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ - executable \ - [list debug c++ additional_flags="-DTYPE=$type"]] != "" } { - untested $type - return -1 - } - gdb_load ${binfile} - if ![runto_main ] then { - perror "couldn't run to breakpoint" - return - } - # There is no executable code in main(), so we are where we want to be - gdb_test "print foo" "" - gdb_test "python foo = gdb.history(0)" "" - - # Replace '*' with '\*' in regex. - regsub -all {\*} $type {\*} t - gdb_test "python print foo.type.template_argument(0)" $t $type -} - -test_template_arg "const int" -test_template_arg "volatile int" -test_template_arg "const int &" -test_template_arg "volatile int &" -test_template_arg "volatile int * const" -test_template_arg "volatile int * const *" -test_template_arg "const int * volatile" -test_template_arg "const int * volatile * const * volatile *" diff --git a/gdb/testsuite/gdb.python/python-value.c b/gdb/testsuite/gdb.python/python-value.c deleted file mode 100644 index f3d62845369..00000000000 --- a/gdb/testsuite/gdb.python/python-value.c +++ /dev/null @@ -1,55 +0,0 @@ -/* This testcase is part of GDB, the GNU debugger. - - Copyright 2008, 2009 Free Software Foundation, Inc. - - 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 . */ - -struct s -{ - int a; - int b; -}; - -union u -{ - int a; - float b; -}; - -enum e - { - ONE = 1, - TWO = 2 - }; - -typedef struct s *PTR; - -enum e evalue = TWO; - -int -main (int argc, char *argv[]) -{ - char *cp = argv[0]; /* Prevent gcc from optimizing argv[] out. */ - struct s s; - union u u; - PTR x = &s; - char st[17] = "divide et impera"; - char nullst[17] = "divide\0et\0impera"; - - s.a = 3; - s.b = 5; - u.a = 7; - - return 0; /* break to inspect struct and union */ -} diff --git a/gdb/testsuite/gdb.python/python-value.exp b/gdb/testsuite/gdb.python/python-value.exp deleted file mode 100644 index 19cabeb6c7e..00000000000 --- a/gdb/testsuite/gdb.python/python-value.exp +++ /dev/null @@ -1,324 +0,0 @@ -# Copyright (C) 2008, 2009 Free Software Foundation, Inc. - -# 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 . - -# This file is part of the GDB testsuite. It tests the mechanism -# exposing values to Python. - -if $tracelevel then { - strace $tracelevel -} - -set testfile "python-value" -set srcfile ${testfile}.c -set binfile ${objdir}/${subdir}/${testfile} -if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { - untested "Couldn't compile ${srcfile}" - return -1 -} - -# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}... -# Run a test named NAME, consisting of multiple lines of input. -# After each input line INPUT, search for result line RESULT. -# Succeed if all results are seen; fail otherwise. -proc gdb_py_test_multiple {name args} { - global gdb_prompt - foreach {input result} $args { - if {[gdb_test_multiple $input "$name - $input" { - -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" { - pass "$name - $input" - } - }]} { - return 1 - } - } - return 0 -} - -# Run a command in GDB, and report a failure if a Python exception is thrown. -# If report_pass is true, report a pass if no exception is thrown. -proc gdb_py_test_silent_cmd {cmd name report_pass} { - global gdb_prompt - - gdb_test_multiple $cmd $name { - -re "Traceback.*$gdb_prompt $" { fail $name } - -re "$gdb_prompt $" { if $report_pass { pass $name } } - } -} - -proc test_value_creation {} { - global gdb_prompt - - gdb_py_test_silent_cmd "python i = gdb.Value (True)" "create boolean value" 1 - gdb_py_test_silent_cmd "python i = gdb.Value (5)" "create integer value" 1 - gdb_py_test_silent_cmd "python i = gdb.Value (5L)" "create long value" 1 - gdb_py_test_silent_cmd "python f = gdb.Value (1.25)" "create double value" 1 - gdb_py_test_silent_cmd "python a = gdb.Value ('string test')" "create 8-bit string value" 1 - gdb_test "python print a" "\"string test\"" "print 8-bit string" - gdb_test "python print a.__class__" "" "verify type of 8-bit string" - gdb_py_test_silent_cmd "python a = gdb.Value (u'unicode test')" "create unicode value" 1 - gdb_test "python print a" "\"unicode test\"" "print Unicode string" - gdb_test "python print a.__class__" "" "verify type of unicode string" - - # Test address attribute is None in a non-addressable value - gdb_test "python print 'result =', i.address" "= None" "Test address attribute in non-addressable value" -} - -proc test_value_numeric_ops {} { - global gdb_prompt - - gdb_py_test_silent_cmd "python i = gdb.Value (5)" "create first integer value" 0 - gdb_py_test_silent_cmd "python j = gdb.Value (2)" "create second integer value" 0 - gdb_py_test_silent_cmd "python f = gdb.Value (1.25)" "create first double value" 0 - gdb_py_test_silent_cmd "python g = gdb.Value (2.5)" "create second double value" 0 - gdb_test "python print 'result = ' + str(i+j)" " = 7" "add two integer values" - gdb_test "python print (i+j).__class__" "" "verify type of integer add result" - - gdb_test "python print 'result = ' + str(f+g)" " = 3.75" "add two double values" - gdb_test "python print 'result = ' + str(i-j)" " = 3" "subtract two integer values" - gdb_test "python print 'result = ' + str(f-g)" " = -1.25" "subtract two double values" - gdb_test "python print 'result = ' + str(i*j)" " = 10" "multiply two integer values" - gdb_test "python print 'result = ' + str(f*g)" " = 3.125" "multiply two double values" - gdb_test "python print 'result = ' + str(i/j)" " = 2" "divide two integer values" - gdb_test "python print 'result = ' + str(f/g)" " = 0.5" "divide two double values" - gdb_test "python print 'result = ' + str(i%j)" " = 1" "take remainder of two integer values" - # Remainder of float is implemented in Python but not in GDB's value system. - - gdb_test "python print 'result = ' + str(i**j)" " = 25" "integer value raised to the power of another integer value" - gdb_test "python print 'result = ' + str(g**j)" " = 6.25" "double value raised to the power of integer value" - - gdb_test "python print 'result = ' + str(-i)" " = -5" "negated integer value" - gdb_test "python print 'result = ' + str(+i)" " = 5" "positive integer value" - gdb_test "python print 'result = ' + str(-f)" " = -1.25" "negated double value" - gdb_test "python print 'result = ' + str(+f)" " = 1.25" "positive double value" - gdb_test "python print 'result = ' + str(abs(j-i))" " = 3" "absolute of integer value" - gdb_test "python print 'result = ' + str(abs(f-g))" " = 1.25" "absolute of double value" - - # Test gdb.Value mixed with Python types. - - gdb_test "python print 'result = ' + str(i-1)" " = 4" "subtract integer value from python integer" - gdb_test "python print (i-1).__class__" "" "verify type of mixed integer subtraction result" - gdb_test "python print 'result = ' + str(f+1.5)" " = 2.75" "add double value with python float" - - gdb_test "python print 'result = ' + str(1-i)" " = -4" "subtract python integer from integer value" - gdb_test "python print 'result = ' + str(1.5+f)" " = 2.75" "add python float with double value" - - # Conversion test. - gdb_test "print evalue" " = TWO" - gdb_test "python evalue = gdb.history (0)" "" - gdb_test "python print int (evalue)" "2" - - # Test pointer arithmethic - - # First, obtain the pointers - gdb_test "print (void *) 2" "" "" - gdb_test "python a = gdb.history (0)" "" "" - gdb_test "print (void *) 5" "" "" - gdb_test "python b = gdb.history (0)" "" "" - - gdb_test "python print 'result = ' + str(a+5)" " = 0x7" "add pointer value with python integer" - gdb_test "python print 'result = ' + str(b-2)" " = 0x3" "subtract python integer from pointer value" - gdb_test "python print 'result = ' + str(b-a)" " = 3" "subtract two pointer values" - - # Test some invalid operations. - - gdb_test_multiple "python print 'result = ' + str(i+'foo')" "catch error in python type conversion" { - -re "Argument to arithmetic operation not a number or boolean.*$gdb_prompt $" {pass "catch error in python type conversion"} - -re "result = .*$gdb_prompt $" {fail "catch error in python type conversion"} - -re "$gdb_prompt $" {fail "catch error in python type conversion"} - } - - gdb_test_multiple "python print 'result = ' + str(i+gdb.Value('foo'))" "catch throw of GDB error" { - -re "Traceback.*$gdb_prompt $" {pass "catch throw of GDB error"} - -re "result = .*$gdb_prompt $" {fail "catch throw of GDB error"} - -re "$gdb_prompt $" {fail "catch throw of GDB error"} - } -} - -proc test_value_boolean {} { - # First, define a useful function to test booleans. - gdb_py_test_multiple "define function to test booleans" \ - "python" "" \ - "def test_bool (val):" "" \ - " if val:" "" \ - " print 'yay'" "" \ - " else:" "" \ - " print 'nay'" "" \ - "end" "" - - gdb_test "py test_bool (gdb.Value (True))" "yay" "check evaluation of true boolean value in expression" - - gdb_test "py test_bool (gdb.Value (False))" "nay" "check evaluation of false boolean value in expression" - - gdb_test "py test_bool (gdb.Value (5))" "yay" "check evaluation of true integer value in expression" - - gdb_test "py test_bool (gdb.Value (0))" "nay" "check evaluation of false integer value in expression" - - gdb_test "py test_bool (gdb.Value (5.2))" "yay" "check evaluation of true integer value in expression" - - gdb_test "py test_bool (gdb.Value (0.0))" "nay" "check evaluation of false integer value in expression" -} - -proc test_value_compare {} { - gdb_test "py print gdb.Value (1) < gdb.Value (1)" "False" "less than, equal" - gdb_test "py print gdb.Value (1) < gdb.Value (2)" "True" "less than, less" - gdb_test "py print gdb.Value (2) < gdb.Value (1)" "False" "less than, greater" - gdb_test "py print gdb.Value (2) < None" "False" "less than, None" - - gdb_test "py print gdb.Value (1) <= gdb.Value (1)" "True" "less or equal, equal" - gdb_test "py print gdb.Value (1) <= gdb.Value (2)" "True" "less or equal, less" - gdb_test "py print gdb.Value (2) <= gdb.Value (1)" "False" "less or equal, greater" - gdb_test "py print gdb.Value (2) <= None" "False" "less or equal, None" - - gdb_test "py print gdb.Value (1) == gdb.Value (1)" "True" "equality of gdb.Values" - gdb_test "py print gdb.Value (1) == gdb.Value (2)" "False" "inequality of gdb.Values" - gdb_test "py print gdb.Value (1) == 1.0" "True" "equality of gdb.Value with Python value" - gdb_test "py print gdb.Value (1) == 2" "False" "inequality of gdb.Value with Python value" - gdb_test "py print gdb.Value (1) == None" "False" "inequality of gdb.Value with None" - - gdb_test "py print gdb.Value (1) != gdb.Value (1)" "False" "inequality, false" - gdb_test "py print gdb.Value (1) != gdb.Value (2)" "True" "inequality, true" - gdb_test "py print gdb.Value (1) != None" "True" "inequality, None" - - gdb_test "py print gdb.Value (1) > gdb.Value (1)" "False" "greater than, equal" - gdb_test "py print gdb.Value (1) > gdb.Value (2)" "False" "greater than, less" - gdb_test "py print gdb.Value (2) > gdb.Value (1)" "True" "greater than, greater" - gdb_test "py print gdb.Value (2) > None" "True" "greater than, None" - - gdb_test "py print gdb.Value (1) >= gdb.Value (1)" "True" "greater or equal, equal" - gdb_test "py print gdb.Value (1) >= gdb.Value (2)" "False" "greater or equal, less" - gdb_test "py print gdb.Value (2) >= gdb.Value (1)" "True" "greater or equal, greater" - gdb_test "py print gdb.Value (2) >= None" "True" "greater or equal, None" -} - -proc test_value_in_inferior {} { - global gdb_prompt - global testfile - - gdb_breakpoint [gdb_get_line_number "break to inspect struct and union"] - - gdb_continue_to_breakpoint "break to inspect struct and union" - - # Just get inferior variable s in the value history, available to python. - gdb_test "print s" " = {a = 3, b = 5}" "" - - gdb_py_test_silent_cmd "python s = gdb.history (0)" "get value from history" 1 - - gdb_test "python print 'result = ' + str(s\['a'\])" " = 3" "access element inside struct using 8-bit string name" - gdb_test "python print 'result = ' + str(s\[u'a'\])" " = 3" "access element inside struct using unicode name" - - # Test dereferencing the argv pointer - - # Just get inferior variable argv the value history, available to python. - gdb_test "print argv" " = \\(char \\*\\*\\) 0x.*" "" - - gdb_py_test_silent_cmd "python argv = gdb.history (0)" "" 0 - gdb_py_test_silent_cmd "python arg0 = argv.dereference ()" "dereference value" 1 - - # Check that the dereferenced value is sane - gdb_test "python print arg0" "0x.*$testfile\"" "verify dereferenced value" - - # Smoke-test is_optimized_out attribute - gdb_test "python print 'result =', arg0.is_optimized_out" "= False" "Test is_optimized_out attribute" - - # Test address attribute - gdb_test "python print 'result =', arg0.address" "= 0x\[\[:xdigit:\]\]+" "Test address attribute" - - # Test string fetches, both partial and whole. - gdb_test "print st" "\"divide et impera\"" - gdb_py_test_silent_cmd "python st = gdb.history (0)" "get value from history" 1 - gdb_test "python print st.string ()" "divide et impera" "Test string with no length" - gdb_test "python print st.string (length = -1)" "divide et impera" "Test string (length = -1) is all of the string" - gdb_test "python print st.string (length = 6)" "divide" - gdb_test "python print \"---\"+st.string (length = 0)+\"---\"" "------" "Test string (length = 0) is empty" - gdb_test "python print len(st.string (length = 0))" "0" "Test length is 0" - - - # Fetch a string that has embedded nulls. - gdb_test "print nullst" "\"divide\\\\000et\\\\000impera\".*" - gdb_py_test_silent_cmd "python nullst = gdb.history (0)" "get value from history" 1 - gdb_test "python print nullst.string ()" "divide" "Test string to first null" - # Python cannot print strings that contain the null (\0) character. - # For the purposes of this test, use repr() - gdb_py_test_silent_cmd "python nullst = nullst.string (length = 9)" "get string beyond null" 1 - gdb_test "python print repr(nullst)" "u'divide\\\\x00et'" -} - -# A few objfile tests. -proc test_objfiles {} { - gdb_test "python\nok=False\nfor file in gdb.objfiles():\n if 'python-value' in file.filename:\n ok=True\nprint ok\nend" "True" - - gdb_test "python print gdb.objfiles()\[0\].pretty_printers" "\\\[\\\]" - - gdb_test "python gdb.objfiles()\[0\].pretty_printers = 0" \ - "pretty_printers attribute must be a list.*Error while executing Python code." -} - -proc test_value_after_death {} { - # Construct a type while the inferior is still running. - gdb_py_test_silent_cmd "python ptrtype = gdb.lookup_type('PTR')" \ - "create PTR type" 1 - - # Kill the inferior and remove the symbols. - gdb_test "kill" "" "kill the inferior" \ - "Kill the program being debugged. .y or n. $" \ - "y" - gdb_test "file" "" "Discard the symbols" \ - "Discard symbol table from.*y or n. $" \ - "y" - - # Now create a value using that type. Relies on arg0, created by - # test_value_in_inferior. - gdb_py_test_silent_cmd "python castval = arg0.cast(ptrtype.pointer())" \ - "cast arg0 to PTR" 1 - - # Make sure the type is deleted. - gdb_py_test_silent_cmd "python ptrtype = None" \ - "delete PTR type" 1 - - # Now see if the value's type is still valid. - gdb_test "python print castval.type" "PTR ." \ - "print value's type" -} - -# Start with a fresh gdb. - -gdb_exit -gdb_start -gdb_reinitialize_dir $srcdir/$subdir -gdb_load ${binfile} - -gdb_test_multiple "python print 'hello, world!'" "verify python support" { - -re "not supported.*$gdb_prompt $" { - unsupported "python support is disabled" - return -1 - } - -re "$gdb_prompt $" {} -} - -test_value_creation -test_value_numeric_ops -test_value_boolean -test_value_compare -test_objfiles - -# The following tests require execution. - -if ![runto_main] then { - fail "Can't run to main" - return 0 -} - -test_value_in_inferior -test_value_after_death