From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 24579 invoked by alias); 2 Apr 2009 20:55:59 -0000 Received: (qmail 24188 invoked by uid 22791); 2 Apr 2009 20:55:54 -0000 X-SWARE-Spam-Status: No, hits=-0.4 required=5.0 tests=AWL,BAYES_50,J_CHICKENPOX_37,J_CHICKENPOX_54,SPF_HELO_PASS,SPF_PASS X-Spam-Check-By: sourceware.org Received: from mx2.redhat.com (HELO mx2.redhat.com) (66.187.237.31) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 02 Apr 2009 20:55:46 +0000 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n32KtjqY027471 for ; Thu, 2 Apr 2009 16:55:45 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx2.corp.redhat.com (8.13.1/8.13.1) with ESMTP id n32KtjUa009496; Thu, 2 Apr 2009 16:55:45 -0400 Received: from opsy.redhat.com (vpn-12-111.rdu.redhat.com [10.11.12.111]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id n32KthEJ000682; Thu, 2 Apr 2009 16:55:43 -0400 Received: by opsy.redhat.com (Postfix, from userid 500) id ED47D3784C0; Thu, 2 Apr 2009 14:55:41 -0600 (MDT) To: gdb-patches@sourceware.org Subject: Python pretty-printing [3/6] From: Tom Tromey Reply-To: Tom Tromey Date: Thu, 02 Apr 2009 20:55:00 -0000 Message-ID: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2009-04/txt/msg00047.txt.bz2 This patch adds a Python wrapper for struct type, plus various auxiliary methods, like Value.type. This patch differs from the Archer python branch in two ways. First, I removed the references to gdb.Block. I was not ready to import this yet, and no code seems to use this part of Type. Second, I removed references to the type reference counting patch. This means that in some situations, this code can leak memory; in particular, this can happen if a Type remains live after an objfile is closed. Jan will be submitted the type reference counting patch separately, at which point we can add the fixes to python-type.c. This patch is necessary because most pretty-printers rely on types. Tom 2009-04-01 Tom Tromey Paul Pluzhnikov * python/python.c (_initialize_python): Call gdbpy_initialize_types. * python/python-value.c (valpy_type): New function. (valpy_cast): New function. (value_object_methods): Added "cast", "type". * python/python-internal.h (type_to_type_object): Declare. (type_object_to_type): Likewise. (gdbpy_initialize_types): Likewise. * Makefile.in (SUBDIR_PYTHON_OBS): Add python-type.o. (SUBDIR_PYTHON_SRCS): Add python-type.c. (python-type.o): New target. * python/python-type.c: New file. 2009-04-01 Thiago Jung Bauermann Tom Tromey * gdb.texinfo (Types From Inferior): New node. (Python API): Update. 2009-04-01 Thiago Jung Bauermann Tom Tromey Pedro Alves Paul Pluzhnikov * gdb.python/python-value.exp (test_value_after_death): New proc. * gdb.python/python-value.c (PTR): New typedef. (main): New variable 'x'. gdb/ChangeLog | 18 + gdb/Makefile.in | 6 + gdb/doc/ChangeLog | 6 + gdb/doc/gdb.texinfo | 272 ++++++++++ gdb/python/python-internal.h | 3 + gdb/python/python-type.c | 792 +++++++++++++++++++++++++++++ gdb/python/python-value.c | 40 ++ gdb/python/python.c | 1 + gdb/testsuite/ChangeLog | 9 + gdb/testsuite/gdb.python/python-value.c | 6 +- gdb/testsuite/gdb.python/python-value.exp | 28 + 11 files changed, 1179 insertions(+), 2 deletions(-) create mode 100644 gdb/python/python-type.c diff --git a/gdb/Makefile.in b/gdb/Makefile.in index dbd2126..265ec94 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -268,6 +268,7 @@ SUBDIR_PYTHON_OBS = \ python-cmd.o \ python-function.o \ python-objfile.o \ + python-type.o \ python-utils.o \ python-value.o SUBDIR_PYTHON_SRCS = \ @@ -275,6 +276,7 @@ SUBDIR_PYTHON_SRCS = \ python/python-cmd.c \ python/python-function.c \ python/python-objfile.c \ + python/python-type.c \ python/python-utils.c \ python/python-value.c SUBDIR_PYTHON_DEPS = @@ -1857,6 +1859,10 @@ python-objfile.o: $(srcdir)/python/python-objfile.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-objfile.c $(POSTCOMPILE) +python-type.o: $(srcdir)/python/python-type.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-type.c + $(POSTCOMPILE) + python-utils.o: $(srcdir)/python/python-utils.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-utils.c $(POSTCOMPILE) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index bcfc9bf..5196842 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -18193,6 +18193,7 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown. * Exception Handling:: * Auto-loading:: Automatically loading Python code. * Values From Inferior:: +* Types From Inferior:: Python representation of types. * Commands In Python:: Implementing new commands in Python. * Functions In Python:: Writing new convenience functions. * Objfiles In Python:: Object files. @@ -18447,6 +18448,277 @@ argument to Python's @code{string.decode} method. @end defmethod @end table +@node Types From Inferior +@subsubsection Types From Inferior + +@cindex gdb.Type +@value{GDBN} represents types from the inferior using the class +@code{gdb.Type}. + +The following methods are provided: + +@table @code +@defmethod Type Type [name] +Construct a new instance of @code{gdb.Type}. + +If @var{name} is given, it specifies the name of a type to look up in +the inferior. @var{name} is searched for globally. +@end defmethod + +@defmethod Type code +Return the type code for this type. The type code will be one of the +@code{TYPE_CODE_} constants defined below. +@end defmethod + +@defmethod Type fields +For structure and union types, this method returns the fields. Range +types have two fields, the minimum and maximum values. Enum types +have one field per enum constant. Function and method types have one +field per parameter. The base types of C++ classes are also +represented as fields. If the type has no fields, or does not fit +into one of these categories, an empty sequence will be returned. + +Each field is an object, with some pre-defined attributes: +@table @code +@item bitpos +This attribute is not available for @code{static} fields. For +non-@code{static} fields, the value is the bit position of the field. + +@item name +The name of the field, or @code{None} for anonymous fields. + +@item artificial +This is @code{True} if the field is artificial, usually meaning that +it was provided by the compiler and not the user. This attribute is +always provided, and is @code{False} if the field is not artificial. + +@item bitsize +If the field is packed, or is a bitfield, then this will have a +non-zero value, which is the size of the field in bits. Otherwise, +this will be zero; in this case the field's size is given by its type. + +@item type +The type of the field. This is usually an instance of @code{Type}, +but it can be @code{None} in some situations. +@end table +@end defmethod + +@defmethod Type const +Return a new @code{gdb.Type} object which represents a +@code{const}-qualified variant of this type. +@end defmethod + +@defmethod Type volatile +Return a new @code{gdb.Type} object which represents a +@code{volatile}-qualified variant of this type. +@end defmethod + +@defmethod Type unqualified +Return a new @code{gdb.Type} object which represents an unqualified +variant of this type. That is, the result is neither @code{const} nor +@code{volatile}. +@end defmethod + +@defmethod Type reference +Return a new @code{gdb.Type} object which represents a reference to this +type. +@end defmethod + +@defmethod Type sizeof +Return the size of this type, in target @code{char} units. Usually, a +target's @code{char} type will be an 8-bit byte. However, on some +unusual platforms, this type may have a different size. +@end defmethod + +@defmethod Type strip_typedefs +Return a new @code{gdb.Type} that represents the real type, +after removing all layers of typedefs. +@end defmethod + +@defmethod Type tag +Return the tag name for this type. The tag name is the name after +@code{struct}, @code{union}, or @code{enum} in C; not all languages +have this concept. If this type has no tag name, then @code{None} is +returned. +@end defmethod + +@defmethod Type target +Return a new @code{gdb.Type} object which represents the target type +of this type. + +For a pointer type, the target type is the type of the pointed-to +object. For an array type, the target type is the type of the +elements of the array. For a function type, the target type is the +type of the return value. For a complex type, the target type is the +type of the elements. For a typedef, the target type is the aliased +type. +@end defmethod + +@defmethod Type template_argument n +If this @code{gdb.Type} is a template type, this will return a new +@code{gdb.Type} which represents the type of the @var{n}th template +argument. + +If this @code{gdb.Type} is not a template type, this will throw an +exception. + +@var{name} is searched for globally. +@end defmethod +@end table + + +Each type has a code, which indicates what category this type falls +into. The available type categories are represented by constants +defined in the @code{gdb} module: + +@table @code +@findex TYPE_CODE_PTR +@findex gdb.TYPE_CODE_PTR +@item TYPE_CODE_PTR +The type is a pointer. + +@findex TYPE_CODE_ARRAY +@findex gdb.TYPE_CODE_ARRAY +@item TYPE_CODE_ARRAY +The type is an array. + +@findex TYPE_CODE_STRUCT +@findex gdb.TYPE_CODE_STRUCT +@item TYPE_CODE_STRUCT +The type is a structure. + +@findex TYPE_CODE_UNION +@findex gdb.TYPE_CODE_UNION +@item TYPE_CODE_UNION +The type is a union. + +@findex TYPE_CODE_ENUM +@findex gdb.TYPE_CODE_ENUM +@item TYPE_CODE_ENUM +The type is an enum. + +@findex TYPE_CODE_FLAGS +@findex gdb.TYPE_CODE_FLAGS +@item TYPE_CODE_FLAGS +A bit flags type. +@c FIXME: what is this? + +@findex TYPE_CODE_FUNC +@findex gdb.TYPE_CODE_FUNC +@item TYPE_CODE_FUNC +The type is a function. + +@findex TYPE_CODE_INT +@findex gdb.TYPE_CODE_INT +@item TYPE_CODE_INT +The type is an integer type. + +@findex TYPE_CODE_FLT +@findex gdb.TYPE_CODE_FLT +@item TYPE_CODE_FLT +A floating point type. + +@findex TYPE_CODE_VOID +@findex gdb.TYPE_CODE_VOID +@item TYPE_CODE_VOID +The special type @code{void}. + +@findex TYPE_CODE_SET +@findex gdb.TYPE_CODE_SET +@item TYPE_CODE_SET +A Pascal set type. + +@findex TYPE_CODE_RANGE +@findex gdb.TYPE_CODE_RANGE +@item TYPE_CODE_RANGE +A range type, that is, an integer type with bounds. + +@findex TYPE_CODE_STRING +@findex gdb.TYPE_CODE_STRING +@item TYPE_CODE_STRING +A string type. Note that this is only used for certain languages with +language-defined string types; C strings are not represented this way. + +@findex TYPE_CODE_BITSTRING +@findex gdb.TYPE_CODE_BITSTRING +@item TYPE_CODE_BITSTRING +A string of bits. + +@findex TYPE_CODE_ERROR +@findex gdb.TYPE_CODE_ERROR +@item TYPE_CODE_ERROR +An unknown or erroneous type. + +@findex TYPE_CODE_METHOD +@findex gdb.TYPE_CODE_METHOD +@item TYPE_CODE_METHOD +A C++ method type. + +@findex TYPE_CODE_METHODPTR +@findex gdb.TYPE_CODE_METHODPTR +@item TYPE_CODE_METHODPTR +A pointer-to-member-function. + +@findex TYPE_CODE_MEMBERPTR +@findex gdb.TYPE_CODE_MEMBERPTR +@item TYPE_CODE_MEMBERPTR +A pointer-to-member. + +@findex TYPE_CODE_REF +@findex gdb.TYPE_CODE_REF +@item TYPE_CODE_REF +A reference type. + +@findex TYPE_CODE_CHAR +@findex gdb.TYPE_CODE_CHAR +@item TYPE_CODE_CHAR +A character type. + +@findex TYPE_CODE_BOOL +@findex gdb.TYPE_CODE_BOOL +@item TYPE_CODE_BOOL +A boolean type. + +@findex TYPE_CODE_COMPLEX +@findex gdb.TYPE_CODE_COMPLEX +@item TYPE_CODE_COMPLEX +A complex float type. + +@findex TYPE_CODE_TYPEDEF +@findex gdb.TYPE_CODE_TYPEDEF +@item TYPE_CODE_TYPEDEF +A typedef to some other type. + +@findex TYPE_CODE_TEMPLATE +@findex gdb.TYPE_CODE_TEMPLATE +@item TYPE_CODE_TEMPLATE +A C++ template type. Note that this is not used for a template +instantiation; those appear as ordinary struct types. +@c FIXME I hope that is true + +@findex TYPE_CODE_TEMPLATE_ARG +@findex gdb.TYPE_CODE_TEMPLATE_ARG +@item TYPE_CODE_TEMPLATE_ARG +A C++ template argument. +@c FIXME: is this ever used? + +@findex TYPE_CODE_NAMESPACE +@findex gdb.TYPE_CODE_NAMESPACE +@item TYPE_CODE_NAMESPACE +A C++ namespace. + +@findex TYPE_CODE_DECFLOAT +@findex gdb.TYPE_CODE_DECFLOAT +@item TYPE_CODE_DECFLOAT +A decimal floating point type. + +@findex TYPE_CODE_INTERNAL_FUNCTION +@findex gdb.TYPE_CODE_INTERNAL_FUNCTION +@item TYPE_CODE_INTERNAL_FUNCTION +A function internal to @value{GDBN}. This is the type used to represent +convenience functions. +@end table + @node Commands In Python @subsubsection Commands In Python diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index 9764f4f..aca61d9 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -66,14 +66,17 @@ extern PyTypeObject value_object_type; PyObject *gdbpy_history (PyObject *self, PyObject *args); PyObject *value_to_value_object (struct value *v); +PyObject *type_to_type_object (struct type *); PyObject *objfile_to_objfile_object (struct objfile *); PyObject *objfpy_get_printers (PyObject *, void *); struct value *convert_value_from_python (PyObject *obj); +struct type *type_object_to_type (PyObject *obj); void gdbpy_initialize_values (void); void gdbpy_initialize_commands (void); +void gdbpy_initialize_types (void); void gdbpy_initialize_functions (void); void gdbpy_initialize_objfile (void); diff --git a/gdb/python/python-type.c b/gdb/python/python-type.c new file mode 100644 index 0000000..e8a9f29 --- /dev/null +++ b/gdb/python/python-type.c @@ -0,0 +1,792 @@ +/* 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" + +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_TEMPLATE), + ENTRY (TYPE_CODE_TEMPLATE_ARG), + 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); +} + +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_code (PyObject *self, PyObject *args) +{ + 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_tag (PyObject *self, PyObject *args) +{ + 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_sizeof (PyObject *self, PyObject *args) +{ + struct type *type = ((type_object *) self)->type; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + CHECK_TYPEDEF (type); + } + GDB_PY_HANDLE_EXCEPTION (except); + + 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 (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; + PyObject *result; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + struct cleanup *old_chain; + struct ui_file *stb; + long length; + + 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, strlen (thetype), 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; + PyGILState_STATE state; + + /* This prevents another thread from freeing the objects we're + operating on. */ + state = PyGILState_Ensure (); + cleanup = make_cleanup_py_restore_gil (&state); + + 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 PyObject * +typy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs) +{ + char *type_name = NULL; + struct type *type = NULL; + type_object *result; + + /* FIXME: it is strange to allow a Type with no name, but we need + this for type_to_type_object. */ + if (! PyArg_ParseTuple (args, "|s", &type_name)) + return NULL; + + if (type_name) + { + type = typy_lookup_typename (type_name); + if (! type) + return NULL; + } + + result = (type_object *) subtype->tp_alloc (subtype, 1); + if (! result) + return NULL; + + set_type (result, type); + + return (PyObject *) result; +} + +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; +} + + + +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 PyMethodDef type_object_methods[] = +{ + { "code", typy_code, METH_NOARGS, "Return the code for this type" }, + { "const", typy_const, METH_NOARGS, "Return a const variant of this type" }, + { "fields", typy_fields, METH_NOARGS, + "Return a sequence holding all the fields of this type.\n\ +Each field is a dictionary." }, + { "pointer", typy_pointer, METH_NOARGS, "Return pointer to this type" }, + { "reference", typy_reference, METH_NOARGS, "Return reference to this type" }, + { "sizeof", typy_sizeof, METH_NOARGS, + "Return the size of this type, in bytes" }, + { "tag", typy_tag, METH_NOARGS, + "Return the tag name for this type, or None." }, + { "strip_typedefs", typy_strip_typedefs, METH_NOARGS, + "Return a type stripped of typedefs"}, + { "target", typy_target, METH_NOARGS, + "Return the target type of this type" }, + { "template_argument", typy_template_argument, METH_VARARGS, + "Return a single template argument type" }, + { "unqualified", typy_unqualified, METH_NOARGS, + "Return a variant of this type without const or volatile attributes" }, + { "volatile", typy_volatile, METH_NOARGS, + "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 */ + 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 */ + typy_new, /* 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-value.c b/gdb/python/python-value.c index 5faa281..f34c41b 100644 --- a/gdb/python/python-value.c +++ b/gdb/python/python-value.c @@ -161,6 +161,14 @@ valpy_get_address (PyObject *self, void *closure) return val_obj->address; } +/* Return type of the value. */ +static PyObject * +valpy_type (PyObject *self, PyObject *args) +{ + struct value *value = ((value_object *) self)->value; + return type_to_type_object (value_type (value)); +} + /* Implementation of gdb.Value.string ([encoding] [, errors]) -> string Return Unicode string with value contents. If ENCODING is not given, the string is assumed to be encoded in the target's charset. */ @@ -195,6 +203,34 @@ valpy_string (PyObject *self, PyObject *args, PyObject *kw) 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) { @@ -855,6 +891,8 @@ gdbpy_initialize_values (void) values_in_python = NULL; } + + static PyGetSetDef value_object_getset[] = { { "address", valpy_get_address, NULL, "The address of the value.", NULL }, @@ -865,7 +903,9 @@ static PyGetSetDef value_object_getset[] = { }; 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." }, + { "type", valpy_type, METH_NOARGS, "Return type of the value." }, { "string", (PyCFunction) valpy_string, METH_VARARGS | METH_KEYWORDS, "string ([encoding] [, errors]) -> string\n\ Return Unicode string representation of the value." }, diff --git a/gdb/python/python.c b/gdb/python/python.c index 5044b8a..81d762f 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -557,6 +557,7 @@ Enables or disables auto-loading of Python code when an object is opened."), gdbpy_initialize_values (); gdbpy_initialize_commands (); gdbpy_initialize_functions (); + gdbpy_initialize_types (); gdbpy_initialize_objfile (); PyRun_SimpleString ("import gdb"); diff --git a/gdb/testsuite/gdb.python/python-value.c b/gdb/testsuite/gdb.python/python-value.c index 17e5c62..092c520 100644 --- a/gdb/testsuite/gdb.python/python-value.c +++ b/gdb/testsuite/gdb.python/python-value.c @@ -33,19 +33,21 @@ enum e 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; s.a = 3; s.b = 5; u.a = 7; - argv[0][0] = 'a'; /* Just to avoid getting argv optimized out. */ - 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 index b3b5746..a7a3ee0 100644 --- a/gdb/testsuite/gdb.python/python-value.exp +++ b/gdb/testsuite/gdb.python/python-value.exp @@ -236,6 +236,33 @@ proc test_value_in_inferior {} { gdb_test "python print 'result =', arg0.address" "= 0x\[\[:xdigit:\]\]+" "Test address attribute" } +proc test_value_after_death {} { + # Construct a type while the inferior is still running. + gdb_py_test_silent_cmd "python ptrtype = gdb.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. @@ -265,3 +292,4 @@ if ![runto_main] then { } test_value_in_inferior +test_value_after_death -- 1.6.0.6