* 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-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-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 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-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-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-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-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