* Python pretty-printing [3/6]
@ 2009-04-02 20:55 Tom Tromey
2009-04-03 15:16 ` Eli Zaretskii
` (3 more replies)
0 siblings, 4 replies; 16+ messages in thread
From: Tom Tromey @ 2009-04-02 20:55 UTC (permalink / raw)
To: gdb-patches
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 <tromey@redhat.com>
Paul Pluzhnikov <ppluzhnikov@google.com>
* 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 <bauerman@br.ibm.com>
Tom Tromey <tromey@redhat.com>
* gdb.texinfo (Types From Inferior): New node.
(Python API): Update.
2009-04-01 Thiago Jung Bauermann <bauerman@br.ibm.com>
Tom Tromey <tromey@redhat.com>
Pedro Alves <pedro@codesourcery.com>
Paul Pluzhnikov <ppluzhnikov@google.com>
* 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 <http://www.gnu.org/licenses/>. */
+
+#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 }
+};
+
+\f
+
+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;
+}
+
+\f
+
+/* 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;
+}
+
+\f
+
+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;
+}
+
+\f
+
+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);
+}
+
+\f
+
+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;
}
+\f
+
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
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: Python pretty-printing [3/6] 2009-04-02 20:55 Python pretty-printing [3/6] Tom Tromey @ 2009-04-03 15:16 ` Eli Zaretskii 2009-04-07 19:52 ` Tom Tromey 2009-04-03 16:30 ` Daniel Jacobowitz ` (2 subsequent siblings) 3 siblings, 1 reply; 16+ messages in thread From: Eli Zaretskii @ 2009-04-03 15:16 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches > From: Tom Tromey <tromey@redhat.com> > Date: Thu, 02 Apr 2009 14:55:41 -0600 > > 2009-04-01 Thiago Jung Bauermann <bauerman@br.ibm.com> > Tom Tromey <tromey@redhat.com> > > * gdb.texinfo (Types From Inferior): New node. > (Python API): Update. Thanks. Comments: > +@node Types From Inferior > +@subsubsection Types From Inferior Some @cindex entry here would be good. > The base types of C++ classes are also Please use "C@t{++}", it looks better in print. > +@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. What are "static fields"? Should that be explained here? > +@item type > +The type of the field. This is usually an instance of @code{Type}, > +but it can be @code{None} in some situations. Should we tell what are those situations where you get "None", or at least give an example or two? > +@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. Should we talk about more than just C? (I assume that at least one more language has some of these tag names.) > +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. Again, this sounds specific to C and C++; isn't there something useful we can tell for other languages, like Ada or Pascal or Java? > +@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. Is this C++-specific? If so, what will happen in other languages? > +@item TYPE_CODE_METHOD > +A C++ method type. Would it make sense to call it TYPE_CODE_CPP_METHOD, to make more clear that it's C++-specific (is it?)? Likewise for other C++-specific constants described below. ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Python pretty-printing [3/6] 2009-04-03 15:16 ` Eli Zaretskii @ 2009-04-07 19:52 ` Tom Tromey 2009-04-07 21:45 ` Eli Zaretskii 0 siblings, 1 reply; 16+ messages in thread From: Tom Tromey @ 2009-04-07 19:52 UTC (permalink / raw) To: Eli Zaretskii; +Cc: gdb-patches >>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes: Tom> +@item bitpos Tom> +This attribute is not available for @code{static} fields. For Tom> +non-@code{static} fields, the value is the bit position of the field. Eli> What are "static fields"? Should that be explained here? A static field is a C++ (and Java, and probably others) concept. I don't think we should explain it, we can just refer to C++. Tom> +@item type Tom> +The type of the field. This is usually an instance of @code{Type}, Tom> +but it can be @code{None} in some situations. Eli> Should we tell what are those situations where you get "None", or at Eli> least give an example or two? I would like to but I don't know when this can happen. Basically it is when FIELD_TYPE is NULL, but I don't know the conditions under which this can happen. Tom> +@defmethod Type tag Tom> +Return the tag name for this type. The tag name is the name after Tom> +@code{struct}, @code{union}, or @code{enum} in C; not all languages Tom> +have this concept. Eli> Should we talk about more than just C? (I assume that at least one Eli> more language has some of these tag names.) C++ does, though I think in C++ the tag is also the name. I don't know about others. Tom> +For a pointer type, the target type is the type of the pointed-to Tom> +object. For an array type, the target type is the type of the Tom> +elements of the array. For a function type, the target type is the Tom> +type of the return value. For a complex type, the target type is the Tom> +type of the elements. For a typedef, the target type is the aliased Tom> +type. Eli> Again, this sounds specific to C and C++; isn't there something useful Eli> we can tell for other languages, like Ada or Pascal or Java? I can update the places that I know to be C-specific. Much of this does not apply to Java. I don't know Ada or Pascal, so someone else would have to supply that information. Tom> +@defmethod Type template_argument n Tom> +If this @code{gdb.Type} is a template type, this will return a new Tom> +@code{gdb.Type} which represents the type of the @var{n}th template Tom> +argument. Eli> Is this C++-specific? If so, what will happen in other languages? I assume it is specific to C++, but I can't say for certain. I will update the text to indicate that an exception is thrown for non-template types. Tom> +@item TYPE_CODE_METHOD Tom> +A C++ method type. Eli> Would it make sense to call it TYPE_CODE_CPP_METHOD, to make more Eli> clear that it's C++-specific (is it?)? Likewise for other Eli> C++-specific constants described below. I believe Java will use this as well as C++. I assume that some other languages provide methods, but I don't know. Tom ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Python pretty-printing [3/6] 2009-04-07 19:52 ` Tom Tromey @ 2009-04-07 21:45 ` Eli Zaretskii 0 siblings, 0 replies; 16+ messages in thread From: Eli Zaretskii @ 2009-04-07 21:45 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches > Cc: gdb-patches@sourceware.org > From: Tom Tromey <tromey@redhat.com> > Date: Tue, 07 Apr 2009 13:52:08 -0600 > > >>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes: > > Tom> +@item bitpos > Tom> +This attribute is not available for @code{static} fields. For > Tom> +non-@code{static} fields, the value is the bit position of the field. > > Eli> What are "static fields"? Should that be explained here? > > A static field is a C++ (and Java, and probably others) concept. I > don't think we should explain it, we can just refer to C++. Here and elsewhere, I guess the best we can do now is for you to mention the language(s) you know about, and someone else will have to complete the information when it is available. Thanks. ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Python pretty-printing [3/6] 2009-04-02 20:55 Python pretty-printing [3/6] Tom Tromey 2009-04-03 15:16 ` Eli Zaretskii @ 2009-04-03 16:30 ` Daniel Jacobowitz 2009-04-06 23:26 ` Tom Tromey 2009-04-03 20:34 ` Thiago Jung Bauermann 2009-04-08 18:39 ` Tom Tromey 3 siblings, 1 reply; 16+ messages in thread From: Daniel Jacobowitz @ 2009-04-03 16:30 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches On Thu, Apr 02, 2009 at 02:55:41PM -0600, Tom Tromey wrote: > * Values From Inferior:: > +* Types From Inferior:: Python representation of types. This isn't entirely a new problem, as you can see from context above, but is there anything we can call this besides "From Inferior"? Types don't come from an inferior, they come from a program or an object file. > +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 So the constructor does a lookup. This will be a little weird if we want to create types from scratch someday (could be very useful). And what happens if name is not given? Anyway, I wonder if there shouldn't be an explicit lookup routine instead. > +@findex TYPE_CODE_FLAGS > +@findex gdb.TYPE_CODE_FLAGS > +@item TYPE_CODE_FLAGS > +A bit flags type. > +@c FIXME: what is this? It's used for the x86 status register, for instance. Try info reg eflags. It's more friendly than just a number (although I do get user complaints about it; could be friendlier). > +@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 DWARF does not represent TYPE_CODE_TEMPLATE, as far as I know. This was used by the HP symbol reader. It looks like nothing in GDB currently creates these and they could be garbage collected (with optional reimplementation later). > +@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? No, see above. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Python pretty-printing [3/6] 2009-04-03 16:30 ` Daniel Jacobowitz @ 2009-04-06 23:26 ` Tom Tromey 2009-04-07 0:34 ` Thiago Jung Bauermann 2009-04-07 1:16 ` Daniel Jacobowitz 0 siblings, 2 replies; 16+ messages in thread From: Tom Tromey @ 2009-04-06 23:26 UTC (permalink / raw) To: gdb-patches >>>>> "Daniel" == Daniel Jacobowitz <drow@false.org> writes: >> +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 Daniel> So the constructor does a lookup. This will be a little weird if we Daniel> want to create types from scratch someday (could be very useful). At that point we can always make the constructor change its behavior depending on the runtime type of the argument. t = Type(gdb.STRUCT) # make a new struct, STRUCT is an int t = Type("whatever") # look up "whatever" Daniel> And what happens if name is not given? This is some relic or misconception in the code... the name need not be optional. Daniel> Anyway, I wonder if there shouldn't be an explicit lookup Daniel> routine instead. I like it ok the way it is. But, if you really want it changed, I will do that; now is not a super time to do this, but it will only be harder in the future. Thiago, what do you think? Tom ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Python pretty-printing [3/6] 2009-04-06 23:26 ` Tom Tromey @ 2009-04-07 0:34 ` Thiago Jung Bauermann 2009-04-07 1:16 ` Daniel Jacobowitz 1 sibling, 0 replies; 16+ messages in thread From: Thiago Jung Bauermann @ 2009-04-07 0:34 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches El lun, 06-04-2009 a las 17:26 -0600, Tom Tromey escribió: > >>>>> "Daniel" == Daniel Jacobowitz <drow@false.org> writes: > Daniel> Anyway, I wonder if there shouldn't be an explicit lookup > Daniel> routine instead. > > I like it ok the way it is. But, if you really want it changed, I > will do that; now is not a super time to do this, but it will only be > harder in the future. Thiago, what do you think? I prefer to have a separate lookup routine. A gdb.lookup_type function would be more consistent with the little API direction we already have than a Type.lookup static method (I remember we discussed module functions vs static methods in the past, I don't remember the outcome though). Well, you asked what I thought. :-) I don't want to inflict any pain on you, though. I don't feel strongly about these choices. I wouldn't mind if you preferred to keep it like this. Or if you preferred to implement Type.lookup. -- []'s Thiago Jung Bauermann IBM Linux Technology Center ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Python pretty-printing [3/6] 2009-04-06 23:26 ` Tom Tromey 2009-04-07 0:34 ` Thiago Jung Bauermann @ 2009-04-07 1:16 ` Daniel Jacobowitz 2009-04-07 2:03 ` Thiago Jung Bauermann 1 sibling, 1 reply; 16+ messages in thread From: Daniel Jacobowitz @ 2009-04-07 1:16 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches On Mon, Apr 06, 2009 at 05:26:06PM -0600, Tom Tromey wrote: > Daniel> So the constructor does a lookup. This will be a little weird if we > Daniel> want to create types from scratch someday (could be very useful). > > At that point we can always make the constructor change its behavior > depending on the runtime type of the argument. > > t = Type(gdb.STRUCT) # make a new struct, STRUCT is an int > t = Type("whatever") # look up "whatever" OK, that makes sense. > Daniel> And what happens if name is not given? > > This is some relic or misconception in the code... the name need not > be optional. Let's fix the docs then. > Daniel> Anyway, I wonder if there shouldn't be an explicit lookup > Daniel> routine instead. > > I like it ok the way it is. But, if you really want it changed, I > will do that; now is not a super time to do this, but it will only be > harder in the future. Thiago, what do you think? Especially if we have to make other incompatible changes now anyway, I'd rather have a lookup routine for this than a constructor. But I don't want to just make work for you. At some point I know we'll want explicit lookup routines; there's scope to consider. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Python pretty-printing [3/6] 2009-04-07 1:16 ` Daniel Jacobowitz @ 2009-04-07 2:03 ` Thiago Jung Bauermann 2009-04-07 2:27 ` Daniel Jacobowitz 0 siblings, 1 reply; 16+ messages in thread From: Thiago Jung Bauermann @ 2009-04-07 2:03 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: Tom Tromey, gdb-patches El lun, 06-04-2009 a las 21:16 -0400, Daniel Jacobowitz escribió: > On Mon, Apr 06, 2009 at 05:26:06PM -0600, Tom Tromey wrote: > At some point I know we'll want explicit lookup routines; there's > scope to consider. For scope specification and definition, I have created a gdb.Block class in the python branch. I'm not sure if you had a look at it. Is there any other way that scope could be defined? -- []'s Thiago Jung Bauermann IBM Linux Technology Center ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Python pretty-printing [3/6] 2009-04-07 2:03 ` Thiago Jung Bauermann @ 2009-04-07 2:27 ` Daniel Jacobowitz 0 siblings, 0 replies; 16+ messages in thread From: Daniel Jacobowitz @ 2009-04-07 2:27 UTC (permalink / raw) To: Thiago Jung Bauermann; +Cc: Tom Tromey, gdb-patches On Mon, Apr 06, 2009 at 11:03:42PM -0300, Thiago Jung Bauermann wrote: > El lun, 06-04-2009 a las 21:16 -0400, Daniel Jacobowitz escribió: > > On Mon, Apr 06, 2009 at 05:26:06PM -0600, Tom Tromey wrote: > > At some point I know we'll want explicit lookup routines; there's > > scope to consider. > > For scope specification and definition, I have created a gdb.Block class > in the python branch. I'm not sure if you had a look at it. Is there any > other way that scope could be defined? Types are usually not block scoped, at least, I can't think of any language where that's allowed, but it's adequate since they can be function scoped. They can also be source file scoped, or you could look up a type by name in an objfile or globally. Linkage of types is not as well defined as for symbols. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Python pretty-printing [3/6] 2009-04-02 20:55 Python pretty-printing [3/6] Tom Tromey 2009-04-03 15:16 ` Eli Zaretskii 2009-04-03 16:30 ` Daniel Jacobowitz @ 2009-04-03 20:34 ` Thiago Jung Bauermann 2009-04-06 23:32 ` Tom Tromey 2009-04-08 18:26 ` Tom Tromey 2009-04-08 18:39 ` Tom Tromey 3 siblings, 2 replies; 16+ messages in thread From: Thiago Jung Bauermann @ 2009-04-03 20:34 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches El jue, 02-04-2009 a las 14:55 -0600, Tom Tromey escribió: > +static void > +field_dealloc (PyObject *obj) > +{ > + field_object *f = (field_object *) obj; > + Py_XDECREF (f->dict); > +} You need to call f->ob_type->tp_free here. > +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; > + } Perhaps this is nitpicking, but: any reason why you don't use GDB_PY_HANDLE_EXCEPTION here? This code seems to do the same thing. > +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 } > +}; I think most of these methods could be attributes instead. The ones which should stay as methods are those who have side-effects (like causing a symtab to be loaded, or somesuch). Even the methods which create new types only do so if the requested type doesn't exist yet, IIUC. Are there side-effects in, say, Type.pointer or Type.reference? Also, another no-no for an attribute would be if its getter would throw an exception. WDYT? > @@ -855,6 +891,8 @@ gdbpy_initialize_values (void) > values_in_python = NULL; > } > > +\f > + :-) > 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." }, What about making Value.type an attribute? -- []'s Thiago Jung Bauermann IBM Linux Technology Center ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Python pretty-printing [3/6] 2009-04-03 20:34 ` Thiago Jung Bauermann @ 2009-04-06 23:32 ` Tom Tromey 2009-04-08 18:26 ` Tom Tromey 1 sibling, 0 replies; 16+ messages in thread From: Tom Tromey @ 2009-04-06 23:32 UTC (permalink / raw) To: Thiago Jung Bauermann; +Cc: gdb-patches >>>>> "Thiago" == Thiago Jung Bauermann <bauerman@br.ibm.com> writes: Thiago> I think most of these methods could be attributes instead. Ok. Thiago> The ones which should stay as methods are those who have Thiago> side-effects (like causing a symtab to be loaded, or Thiago> somesuch). Even the methods which create new types only do so Thiago> if the requested type doesn't exist yet, IIUC. Are there Thiago> side-effects in, say, Type.pointer or Type.reference? Only allocation, as far as I can tell. That seems safe enough. Thiago> Also, another no-no for an attribute would be if its getter Thiago> would throw an exception. Thiago> WDYT? I'll do it. This strengthens the argument for changing the Type constructor now, if we want to. We might as well make all the changes at once :) What do you think of a static method named "Type.lookup"? Daniel? Thiago> What about making Value.type an attribute? I remember thinking that we couldn't memoize a value's Type. But now I'm thinking that I remember this from before type reference counting; and on the branch it seems like it ought to be safe. Type is still a bit weird. We don't have a way to compare Type objects, which makes them hard to use in dictionaries and whatnot. One idea would be to compare the underlying struct type, with the proviso that, in the current gdb, this won't always work correctly for types with no associated objfile. This would be an improvement, at least, and we could lift this restriction later. Tom ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Python pretty-printing [3/6] 2009-04-03 20:34 ` Thiago Jung Bauermann 2009-04-06 23:32 ` Tom Tromey @ 2009-04-08 18:26 ` Tom Tromey 1 sibling, 0 replies; 16+ messages in thread From: Tom Tromey @ 2009-04-08 18:26 UTC (permalink / raw) To: Thiago Jung Bauermann; +Cc: gdb-patches >>>>> "Thiago" == Thiago Jung Bauermann <bauerman@br.ibm.com> writes: Tom> + if (except.reason < 0) Tom> + { Tom> + PyErr_Format (except.reason == RETURN_QUIT Tom> + ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, Tom> + "%s", except.message); Tom> + return NULL; Tom> + } Thiago> Perhaps this is nitpicking, but: any reason why you don't use Thiago> GDB_PY_HANDLE_EXCEPTION here? This code seems to do the same thing. GDB_PY_HANDLE_EXCEPTION does "return PyErr_Format...", which means the return uses the wrong type. (I didn't see this at first either, I found out by trying :-) [ methods ] Thiago> I think most of these methods could be attributes instead. The ones Thiago> which should stay as methods are those who have side-effects (like Thiago> causing a symtab to be loaded, or somesuch). Even the methods which Thiago> create new types only do so if the requested type doesn't exist yet, Thiago> IIUC. Are there side-effects in, say, Type.pointer or Type.reference? I changed a few to be attributes: code, sizeof, and tag. The rest I left as methods. It seemed reasonable to me that requests for type variants (or pointer-to or reference-to or whatever) should be methods. They may cause a new type to be created. Tom ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Python pretty-printing [3/6] 2009-04-02 20:55 Python pretty-printing [3/6] Tom Tromey ` (2 preceding siblings ...) 2009-04-03 20:34 ` Thiago Jung Bauermann @ 2009-04-08 18:39 ` Tom Tromey 2009-04-08 19:23 ` Eli Zaretskii 3 siblings, 1 reply; 16+ messages in thread From: Tom Tromey @ 2009-04-08 18:39 UTC (permalink / raw) To: gdb-patches Here is the updated version of this patch. Tom 2009-04-01 Tom Tromey <tromey@redhat.com> Thiago Jung Bauermann <bauerman@br.ibm.com> Phil Muldoon <pmuldoon@redhat.com> Paul Pluzhnikov <ppluzhnikov@google.com> * python/python.c (_initialize_python): Call gdbpy_initialize_types. (GdbMethods): Add "lookup_type". * python/python-value.c (value_object) <type>: New field. (valpy_dealloc): Decref type. (valpy_new): Initialize type. (valpy_get_type): New function. (value_to_value_object): Initialize type. (valpy_cast): New function. (value_object_getset): Add "type". (value_object_methods): Add "cast". * python/python-internal.h (type_to_type_object): Declare. (type_object_to_type): Likewise. (gdbpy_initialize_types): Likewise. (gdbpy_lookup_type): Declare. * 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 <bauerman@br.ibm.com> Tom Tromey <tromey@redhat.com> * gdb.texinfo (Types In Python): New node. (Values From Inferior): "type" is now an attribute. (Python API): Update. 2009-04-08 Tom Tromey <tromey@redhat.com> Paul Pluzhnikov <ppluzhnikov@google.com> Thiago Jung Bauermann <bauerman@br.ibm.com> * gdb.python/python-template.exp: New file. * gdb.python/python-template.cc: New file. * gdb.python/python.exp (gdb_py_test_multiple): Add two objfile tests. * gdb.python/python-value.exp (py_objfile_tests): New proc. Call it. gdb/ChangeLog | 25 + gdb/Makefile.in | 6 + gdb/doc/ChangeLog | 7 + gdb/doc/gdb.texinfo | 286 +++++++++- gdb/python/python-internal.h | 4 + gdb/python/python-type.c | 799 ++++++++++++++++++++++++++ gdb/python/python-value.c | 58 ++ gdb/python/python.c | 6 + gdb/testsuite/ChangeLog | 15 +- gdb/testsuite/gdb.python/python-template.cc | 30 + gdb/testsuite/gdb.python/python-template.exp | 75 +++ gdb/testsuite/gdb.python/python-value.c | 6 +- gdb/testsuite/gdb.python/python-value.exp | 28 + 13 files changed, 1338 insertions(+), 7 deletions(-) create mode 100644 gdb/python/python-type.c create mode 100644 gdb/testsuite/gdb.python/python-template.cc create mode 100644 gdb/testsuite/gdb.python/python-template.exp 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 ca3c99b..45ee8cf 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -18225,6 +18225,7 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown. * Exception Handling:: * Auto-loading:: Automatically loading Python code. * Values From Inferior:: +* Types In Python:: Python representation of types. * Commands In Python:: Implementing new commands in Python. * Functions In Python:: Writing new convenience functions. * Objfiles In Python:: Object files. @@ -18409,17 +18410,22 @@ Again, @code{bar} will also be a @code{gdb.Value} object. The following attributes are provided: @table @code -@defmethod Value address +@defivar Value address If this object is addressable, this read-only attribute holds a @code{gdb.Value} object representing the address. Otherwise, this attribute holds @code{None}. -@end defmethod +@end defivar @cindex optimized out value in Python -@defmethod Value is_optimized_out +@defivar Value is_optimized_out This read-only boolean attribute is true if the compiler optimized out this value, thus it is not available for fetching from the inferior. -@end defmethod +@end defivar + +@defivar Value type +The type of this @code{gdb.Value}. The value of this attribute is a +@code{gdb.Type} object. +@end defivar @end table The following methods are provided: @@ -18474,6 +18480,278 @@ argument to Python's @code{string.decode} method. @end defmethod @end table +@node Types In Python +@subsubsection Types In Python +@cindex types in Python +@cindex Python, working with types + +@tindex gdb.Type +@value{GDBN} represents types from the inferior using the class +@code{gdb.Type}. + +The following type-related functions are available in the @code{gdb} +module: + +@findex gdb.lookup_type +@defun lookup_type name [block] +This function looks up a type by name. @var{name} is the name of the +type to look up. It must be a string. + +Ordinarily, this function will return an instance of @code{gdb.Type}. +If the named type cannot be found, it will throw an exception. +@end defun + +An instance of @code{Type} has the following attributes: + +@table @code +@defivar Type code +The type code for this type. The type code will be one of the +@code{TYPE_CODE_} constants defined below. +@end defivar + +@defivar Type sizeof +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 defivar + +@defivar Type tag +The tag name for this type. The tag name is the name after +@code{struct}, @code{union}, or @code{enum} in C and C@t{++}; not all +languages have this concept. If this type has no tag name, then +@code{None} is returned. +@end defivar +@end table + +The following methods are provided: + +@table @code +@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@t{++} 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 (as in +C@t{++} or Java). 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 strip_typedefs +Return a new @code{gdb.Type} that represents the real type, +after removing all layers of typedefs. +@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 (meaning C-like arrays), the target type is +the type of the elements of the array. For a function or method 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. + +If the type does not have a target, this method will throw an +exception. +@end defmethod + +@defmethod Type template_argument n +If this @code{gdb.Type} is an instantiation of a template, 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. Ordinarily, only C@t{++} code will have template types. + +@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, used for things such as status registers. + +@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 method type, as found in C++ or Java. + +@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_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..408d329 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -64,16 +64,20 @@ extern PyObject *gdb_module; extern PyTypeObject value_object_type; PyObject *gdbpy_history (PyObject *self, PyObject *args); +PyObject *gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw); 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..577ebd2 --- /dev/null +++ b/gdb/python/python-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 <http://www.gnu.org/licenses/>. */ + +#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_NAMESPACE), + ENTRY (TYPE_CODE_DECFLOAT), + ENTRY (TYPE_CODE_INTERNAL_FUNCTION), + { TYPE_CODE_UNDEF, NULL } +}; + +\f + +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; +} + +\f + +/* 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 (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; +} + +\f + +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 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; +} + +\f + +/* 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); +} + +\f + +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-value.c b/gdb/python/python-value.c index 5faa281..76f5cde 100644 --- a/gdb/python/python-value.c +++ b/gdb/python/python-value.c @@ -59,6 +59,7 @@ typedef struct { PyObject_HEAD struct value *value; PyObject *address; + PyObject *type; } value_object; /* Called by the Python interpreter when deallocating a value object. */ @@ -77,6 +78,11 @@ valpy_dealloc (PyObject *obj) Py_DECREF (self->address); } + if (self->type) + { + Py_DECREF (self->type); + } + self->ob_type->tp_free (self); } @@ -111,6 +117,7 @@ valpy_new (PyTypeObject *subtype, PyObject *args, PyObject *keywords) value_obj->value = value; value_obj->address = NULL; + value_obj->type = NULL; release_value (value); value_prepend_to_list (&values_in_python, value); @@ -161,6 +168,24 @@ valpy_get_address (PyObject *self, void *closure) 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]) -> 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 +220,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) { @@ -744,6 +797,7 @@ value_to_value_object (struct value *val) { val_obj->value = val; val_obj->address = NULL; + val_obj->type = NULL; release_value (val); value_prepend_to_list (&values_in_python, val); } @@ -855,16 +909,20 @@ gdbpy_initialize_values (void) values_in_python = NULL; } +\f + 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]) -> string\n\ diff --git a/gdb/python/python.c b/gdb/python/python.c index fcf351f..1330cd1 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -551,6 +551,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"); @@ -610,6 +611,11 @@ static PyMethodDef GdbMethods[] = { "objfiles", gdbpy_objfiles, METH_NOARGS, "Return a sequence of all loaded objfiles." }, + { "lookup_type", (PyCFunction) gdbpy_lookup_type, + METH_VARARGS | METH_KEYWORDS, + "lookup_type (name [, block]) -> type\n\ +Return a Type corresponding to the given name." }, + { "write", gdbpy_write, METH_VARARGS, "Write a string using gdb's filtered stream." }, { "flush", gdbpy_flush, METH_NOARGS, diff --git a/gdb/testsuite/gdb.python/python-template.cc b/gdb/testsuite/gdb.python/python-template.cc new file mode 100644 index 0000000..bd6a212 --- /dev/null +++ b/gdb/testsuite/gdb.python/python-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 <http://www.gnu.org/licenses/>. */ + +template <typename T> +struct Foo { +}; + +#ifndef TYPE +#define TYPE int +#endif + +int main() +{ + Foo<TYPE> foo; + return 0; // break here +} diff --git a/gdb/testsuite/gdb.python/python-template.exp b/gdb/testsuite/gdb.python/python-template.exp new file mode 100644 index 0000000..1ace5d6 --- /dev/null +++ b/gdb/testsuite/gdb.python/python-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 <http://www.gnu.org/licenses/>. + +# 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 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 93e9d89..20333f6 100644 --- a/gdb/testsuite/gdb.python/python-value.exp +++ b/gdb/testsuite/gdb.python/python-value.exp @@ -246,6 +246,33 @@ proc test_objfiles {} { "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 @@ -275,3 +302,4 @@ if ![runto_main] then { } test_value_in_inferior +test_value_after_death -- 1.6.0.6 ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Python pretty-printing [3/6] 2009-04-08 18:39 ` Tom Tromey @ 2009-04-08 19:23 ` Eli Zaretskii 2009-04-09 1:16 ` Tom Tromey 0 siblings, 1 reply; 16+ messages in thread From: Eli Zaretskii @ 2009-04-08 19:23 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches > From: Tom Tromey <tromey@redhat.com> > Date: Wed, 08 Apr 2009 12:38:11 -0600 > > 2009-04-01 Thiago Jung Bauermann <bauerman@br.ibm.com> > Tom Tromey <tromey@redhat.com> > > * gdb.texinfo (Types In Python): New node. > (Values From Inferior): "type" is now an attribute. > (Python API): Update. This part is OK, but there are 2 places where you use "C++" instead of "C@t{++}". ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Python pretty-printing [3/6] 2009-04-08 19:23 ` Eli Zaretskii @ 2009-04-09 1:16 ` Tom Tromey 0 siblings, 0 replies; 16+ messages in thread From: Tom Tromey @ 2009-04-09 1:16 UTC (permalink / raw) To: Eli Zaretskii; +Cc: gdb-patches >>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes: Eli> This part is OK, but there are 2 places where you use "C++" instead of Eli> "C@t{++}". Oops, I thought I got them all. I fixed this on my local branch. Tom ^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2009-04-09 1:16 UTC | newest] Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2009-04-02 20:55 Python pretty-printing [3/6] Tom Tromey 2009-04-03 15:16 ` Eli Zaretskii 2009-04-07 19:52 ` Tom Tromey 2009-04-07 21:45 ` Eli Zaretskii 2009-04-03 16:30 ` Daniel Jacobowitz 2009-04-06 23:26 ` Tom Tromey 2009-04-07 0:34 ` Thiago Jung Bauermann 2009-04-07 1:16 ` Daniel Jacobowitz 2009-04-07 2:03 ` Thiago Jung Bauermann 2009-04-07 2:27 ` Daniel Jacobowitz 2009-04-03 20:34 ` Thiago Jung Bauermann 2009-04-06 23:32 ` Tom Tromey 2009-04-08 18:26 ` Tom Tromey 2009-04-08 18:39 ` Tom Tromey 2009-04-08 19:23 ` Eli Zaretskii 2009-04-09 1:16 ` Tom Tromey
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox