Browse Source
2009-05-27 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. gdb/doc 2009-05-27 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. gdb/testsuite 2009-05-27 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-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. (test_value_after_death): New proc. * gdb.python/python-value.c (PTR): New typedef. (main): New variable 'x'.cgen-1_1-branch
13 changed files with 1339 additions and 6 deletions
@ -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 } |
|||
}; |
|||
|
|||
|
|||
|
|||
static void |
|||
field_dealloc (PyObject *obj) |
|||
{ |
|||
field_object *f = (field_object *) obj; |
|||
Py_XDECREF (f->dict); |
|||
f->ob_type->tp_free (obj); |
|||
} |
|||
|
|||
static PyObject * |
|||
field_new (void) |
|||
{ |
|||
field_object *result = PyObject_New (field_object, &field_object_type); |
|||
if (result) |
|||
{ |
|||
result->dict = PyDict_New (); |
|||
if (!result->dict) |
|||
{ |
|||
Py_DECREF (result); |
|||
result = NULL; |
|||
} |
|||
} |
|||
return (PyObject *) result; |
|||
} |
|||
|
|||
|
|||
|
|||
/* Return the code for this type. */ |
|||
static PyObject * |
|||
typy_get_code (PyObject *self, void *closure) |
|||
{ |
|||
struct type *type = ((type_object *) self)->type; |
|||
return PyInt_FromLong (TYPE_CODE (type)); |
|||
} |
|||
|
|||
/* Helper function for typy_fields which converts a single field to a
|
|||
dictionary. Returns NULL on error. */ |
|||
static PyObject * |
|||
convert_field (struct type *type, int field) |
|||
{ |
|||
PyObject *result = field_new (); |
|||
PyObject *arg; |
|||
|
|||
if (!result) |
|||
return NULL; |
|||
|
|||
if (!field_is_static (&TYPE_FIELD (type, field))) |
|||
{ |
|||
arg = PyLong_FromLong (TYPE_FIELD_BITPOS (type, field)); |
|||
if (!arg) |
|||
goto fail; |
|||
|
|||
if (PyObject_SetAttrString (result, "bitpos", arg) < 0) |
|||
goto failarg; |
|||
} |
|||
|
|||
if (TYPE_FIELD_NAME (type, field)) |
|||
arg = PyString_FromString (TYPE_FIELD_NAME (type, field)); |
|||
else |
|||
{ |
|||
arg = Py_None; |
|||
Py_INCREF (arg); |
|||
} |
|||
if (!arg) |
|||
goto fail; |
|||
if (PyObject_SetAttrString (result, "name", arg) < 0) |
|||
goto failarg; |
|||
|
|||
arg = TYPE_FIELD_ARTIFICIAL (type, field) ? Py_True : Py_False; |
|||
Py_INCREF (arg); |
|||
if (PyObject_SetAttrString (result, "artificial", arg) < 0) |
|||
goto failarg; |
|||
|
|||
arg = PyLong_FromLong (TYPE_FIELD_BITSIZE (type, field)); |
|||
if (!arg) |
|||
goto fail; |
|||
if (PyObject_SetAttrString (result, "bitsize", arg) < 0) |
|||
goto failarg; |
|||
|
|||
/* A field can have a NULL type in some situations. */ |
|||
if (TYPE_FIELD_TYPE (type, field) == NULL) |
|||
{ |
|||
arg = Py_None; |
|||
Py_INCREF (arg); |
|||
} |
|||
else |
|||
arg = type_to_type_object (TYPE_FIELD_TYPE (type, field)); |
|||
if (!arg) |
|||
goto fail; |
|||
if (PyObject_SetAttrString (result, "type", arg) < 0) |
|||
goto failarg; |
|||
|
|||
return result; |
|||
|
|||
failarg: |
|||
Py_DECREF (arg); |
|||
fail: |
|||
Py_DECREF (result); |
|||
return NULL; |
|||
} |
|||
|
|||
/* Return a sequence of all fields. Each field is a dictionary with
|
|||
some pre-defined keys. */ |
|||
static PyObject * |
|||
typy_fields (PyObject *self, PyObject *args) |
|||
{ |
|||
PyObject *result; |
|||
int i; |
|||
struct type *type = ((type_object *) self)->type; |
|||
|
|||
/* We would like to make a tuple here, make fields immutable, and
|
|||
then memoize the result (and perhaps make Field.type() lazy). |
|||
However, that can lead to cycles. */ |
|||
result = PyList_New (0); |
|||
|
|||
for (i = 0; i < TYPE_NFIELDS (type); ++i) |
|||
{ |
|||
PyObject *dict = convert_field (type, i); |
|||
if (!dict) |
|||
{ |
|||
Py_DECREF (result); |
|||
return NULL; |
|||
} |
|||
if (PyList_Append (result, dict)) |
|||
{ |
|||
Py_DECREF (dict); |
|||
Py_DECREF (result); |
|||
return NULL; |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
/* Return the type's tag, or None. */ |
|||
static PyObject * |
|||
typy_get_tag (PyObject *self, void *closure) |
|||
{ |
|||
struct type *type = ((type_object *) self)->type; |
|||
if (!TYPE_TAG_NAME (type)) |
|||
Py_RETURN_NONE; |
|||
return PyString_FromString (TYPE_TAG_NAME (type)); |
|||
} |
|||
|
|||
/* Return the type, stripped of typedefs. */ |
|||
static PyObject * |
|||
typy_strip_typedefs (PyObject *self, PyObject *args) |
|||
{ |
|||
struct type *type = ((type_object *) self)->type; |
|||
|
|||
return type_to_type_object (check_typedef (type)); |
|||
} |
|||
|
|||
/* Return a Type object which represents a pointer to SELF. */ |
|||
static PyObject * |
|||
typy_pointer (PyObject *self, PyObject *args) |
|||
{ |
|||
struct type *type = ((type_object *) self)->type; |
|||
volatile struct gdb_exception except; |
|||
|
|||
TRY_CATCH (except, RETURN_MASK_ALL) |
|||
{ |
|||
type = lookup_pointer_type (type); |
|||
} |
|||
GDB_PY_HANDLE_EXCEPTION (except); |
|||
|
|||
return type_to_type_object (type); |
|||
} |
|||
|
|||
/* Return a Type object which represents a reference to SELF. */ |
|||
static PyObject * |
|||
typy_reference (PyObject *self, PyObject *args) |
|||
{ |
|||
struct type *type = ((type_object *) self)->type; |
|||
volatile struct gdb_exception except; |
|||
|
|||
TRY_CATCH (except, RETURN_MASK_ALL) |
|||
{ |
|||
type = lookup_reference_type (type); |
|||
} |
|||
GDB_PY_HANDLE_EXCEPTION (except); |
|||
|
|||
return type_to_type_object (type); |
|||
} |
|||
|
|||
/* Return a Type object which represents the target type of SELF. */ |
|||
static PyObject * |
|||
typy_target (PyObject *self, PyObject *args) |
|||
{ |
|||
struct type *type = ((type_object *) self)->type; |
|||
|
|||
if (!TYPE_TARGET_TYPE (type)) |
|||
{ |
|||
PyErr_SetString (PyExc_RuntimeError, "type does not have a target"); |
|||
return NULL; |
|||
} |
|||
|
|||
return type_to_type_object (TYPE_TARGET_TYPE (type)); |
|||
} |
|||
|
|||
/* Return a const-qualified type variant. */ |
|||
static PyObject * |
|||
typy_const (PyObject *self, PyObject *args) |
|||
{ |
|||
struct type *type = ((type_object *) self)->type; |
|||
volatile struct gdb_exception except; |
|||
|
|||
TRY_CATCH (except, RETURN_MASK_ALL) |
|||
{ |
|||
type = make_cv_type (1, 0, type, NULL); |
|||
} |
|||
GDB_PY_HANDLE_EXCEPTION (except); |
|||
|
|||
return type_to_type_object (type); |
|||
} |
|||
|
|||
/* Return a volatile-qualified type variant. */ |
|||
static PyObject * |
|||
typy_volatile (PyObject *self, PyObject *args) |
|||
{ |
|||
struct type *type = ((type_object *) self)->type; |
|||
volatile struct gdb_exception except; |
|||
|
|||
TRY_CATCH (except, RETURN_MASK_ALL) |
|||
{ |
|||
type = make_cv_type (0, 1, type, NULL); |
|||
} |
|||
GDB_PY_HANDLE_EXCEPTION (except); |
|||
|
|||
return type_to_type_object (type); |
|||
} |
|||
|
|||
/* Return an unqualified type variant. */ |
|||
static PyObject * |
|||
typy_unqualified (PyObject *self, PyObject *args) |
|||
{ |
|||
struct type *type = ((type_object *) self)->type; |
|||
volatile struct gdb_exception except; |
|||
|
|||
TRY_CATCH (except, RETURN_MASK_ALL) |
|||
{ |
|||
type = make_cv_type (0, 0, type, NULL); |
|||
} |
|||
GDB_PY_HANDLE_EXCEPTION (except); |
|||
|
|||
return type_to_type_object (type); |
|||
} |
|||
|
|||
/* Return the size of the type represented by SELF, in bytes. */ |
|||
static PyObject * |
|||
typy_get_sizeof (PyObject *self, void *closure) |
|||
{ |
|||
struct type *type = ((type_object *) self)->type; |
|||
volatile struct gdb_exception except; |
|||
|
|||
TRY_CATCH (except, RETURN_MASK_ALL) |
|||
{ |
|||
check_typedef (type); |
|||
} |
|||
/* Ignore exceptions. */ |
|||
|
|||
return PyLong_FromLong (TYPE_LENGTH (type)); |
|||
} |
|||
|
|||
static struct type * |
|||
typy_lookup_typename (char *type_name) |
|||
{ |
|||
struct type *type = NULL; |
|||
volatile struct gdb_exception except; |
|||
TRY_CATCH (except, RETURN_MASK_ALL) |
|||
{ |
|||
if (!strncmp (type_name, "struct ", 7)) |
|||
type = lookup_struct (type_name + 7, NULL); |
|||
else if (!strncmp (type_name, "union ", 6)) |
|||
type = lookup_union (type_name + 6, NULL); |
|||
else if (!strncmp (type_name, "enum ", 5)) |
|||
type = lookup_enum (type_name + 5, NULL); |
|||
else |
|||
type = lookup_typename (type_name, NULL, 0); |
|||
} |
|||
if (except.reason < 0) |
|||
{ |
|||
PyErr_Format (except.reason == RETURN_QUIT |
|||
? PyExc_KeyboardInterrupt : PyExc_RuntimeError, |
|||
"%s", except.message); |
|||
return NULL; |
|||
} |
|||
|
|||
return type; |
|||
} |
|||
|
|||
static struct type * |
|||
typy_lookup_type (struct demangle_component *demangled) |
|||
{ |
|||
struct type *type; |
|||
char *type_name; |
|||
enum demangle_component_type demangled_type; |
|||
|
|||
/* Save the type: typy_lookup_type() may (indirectly) overwrite
|
|||
memory pointed by demangled. */ |
|||
demangled_type = demangled->type; |
|||
|
|||
if (demangled_type == DEMANGLE_COMPONENT_POINTER |
|||
|| demangled_type == DEMANGLE_COMPONENT_REFERENCE |
|||
|| demangled_type == DEMANGLE_COMPONENT_CONST |
|||
|| demangled_type == DEMANGLE_COMPONENT_VOLATILE) |
|||
{ |
|||
type = typy_lookup_type (demangled->u.s_binary.left); |
|||
if (! type) |
|||
return NULL; |
|||
|
|||
switch (demangled_type) |
|||
{ |
|||
case DEMANGLE_COMPONENT_REFERENCE: |
|||
return lookup_reference_type (type); |
|||
case DEMANGLE_COMPONENT_POINTER: |
|||
return lookup_pointer_type (type); |
|||
case DEMANGLE_COMPONENT_CONST: |
|||
return make_cv_type (1, 0, type, NULL); |
|||
case DEMANGLE_COMPONENT_VOLATILE: |
|||
return make_cv_type (0, 1, type, NULL); |
|||
} |
|||
} |
|||
|
|||
type_name = cp_comp_to_string (demangled, 10); |
|||
type = typy_lookup_typename (type_name); |
|||
xfree (type_name); |
|||
|
|||
return type; |
|||
} |
|||
|
|||
static PyObject * |
|||
typy_template_argument (PyObject *self, PyObject *args) |
|||
{ |
|||
int i, argno, n_pointers; |
|||
struct type *type = ((type_object *) self)->type; |
|||
struct demangle_component *demangled; |
|||
const char *err; |
|||
struct type *argtype; |
|||
|
|||
if (! PyArg_ParseTuple (args, "i", &argno)) |
|||
return NULL; |
|||
|
|||
type = check_typedef (type); |
|||
if (TYPE_CODE (type) == TYPE_CODE_REF) |
|||
type = check_typedef (TYPE_TARGET_TYPE (type)); |
|||
|
|||
if (TYPE_NAME (type) == NULL) |
|||
{ |
|||
PyErr_SetString (PyExc_RuntimeError, "null type name"); |
|||
return NULL; |
|||
} |
|||
|
|||
/* Note -- this is not thread-safe. */ |
|||
demangled = cp_demangled_name_to_comp (TYPE_NAME (type), &err); |
|||
if (! demangled) |
|||
{ |
|||
PyErr_SetString (PyExc_RuntimeError, err); |
|||
return NULL; |
|||
} |
|||
|
|||
/* Strip off component names. */ |
|||
while (demangled->type == DEMANGLE_COMPONENT_QUAL_NAME |
|||
|| demangled->type == DEMANGLE_COMPONENT_LOCAL_NAME) |
|||
demangled = demangled->u.s_binary.right; |
|||
|
|||
if (demangled->type != DEMANGLE_COMPONENT_TEMPLATE) |
|||
{ |
|||
PyErr_SetString (PyExc_RuntimeError, "type is not a template"); |
|||
return NULL; |
|||
} |
|||
|
|||
/* Skip from the template to the arguments. */ |
|||
demangled = demangled->u.s_binary.right; |
|||
|
|||
for (i = 0; demangled && i < argno; ++i) |
|||
demangled = demangled->u.s_binary.right; |
|||
|
|||
if (! demangled) |
|||
{ |
|||
PyErr_Format (PyExc_RuntimeError, "no argument %d in template", |
|||
argno); |
|||
return NULL; |
|||
} |
|||
|
|||
argtype = typy_lookup_type (demangled->u.s_binary.left); |
|||
if (! argtype) |
|||
return NULL; |
|||
|
|||
return type_to_type_object (argtype); |
|||
} |
|||
|
|||
static PyObject * |
|||
typy_str (PyObject *self) |
|||
{ |
|||
volatile struct gdb_exception except; |
|||
char *thetype = NULL; |
|||
PyObject *result; |
|||
|
|||
TRY_CATCH (except, RETURN_MASK_ALL) |
|||
{ |
|||
struct cleanup *old_chain; |
|||
struct ui_file *stb; |
|||
long length; |
|||
|
|||
stb = mem_fileopen (); |
|||
old_chain = make_cleanup_ui_file_delete (stb); |
|||
|
|||
type_print (type_object_to_type (self), "", stb, -1); |
|||
|
|||
thetype = ui_file_xstrdup (stb, &length); |
|||
do_cleanups (old_chain); |
|||
} |
|||
if (except.reason < 0) |
|||
{ |
|||
xfree (thetype); |
|||
GDB_PY_HANDLE_EXCEPTION (except); |
|||
} |
|||
|
|||
result = PyUnicode_Decode (thetype, strlen (thetype), host_charset (), NULL); |
|||
xfree (thetype); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
|
|||
|
|||
static const struct objfile_data *typy_objfile_data_key; |
|||
|
|||
static void |
|||
clean_up_objfile_types (struct objfile *objfile, void *datum) |
|||
{ |
|||
type_object *obj = datum; |
|||
htab_t copied_types; |
|||
struct cleanup *cleanup; |
|||
PyGILState_STATE state; |
|||
|
|||
/* This prevents another thread from freeing the objects we're
|
|||
operating on. */ |
|||
state = PyGILState_Ensure (); |
|||
cleanup = make_cleanup_py_restore_gil (&state); |
|||
|
|||
copied_types = create_copied_types_hash (objfile); |
|||
|
|||
while (obj) |
|||
{ |
|||
type_object *next = obj->next; |
|||
|
|||
htab_empty (copied_types); |
|||
|
|||
obj->type = copy_type_recursive (objfile, obj->type, copied_types); |
|||
|
|||
obj->next = NULL; |
|||
obj->prev = NULL; |
|||
|
|||
obj = next; |
|||
} |
|||
|
|||
htab_delete (copied_types); |
|||
|
|||
do_cleanups (cleanup); |
|||
} |
|||
|
|||
static void |
|||
set_type (type_object *obj, struct type *type) |
|||
{ |
|||
obj->type = type; |
|||
obj->prev = NULL; |
|||
if (type && TYPE_OBJFILE (type)) |
|||
{ |
|||
struct objfile *objfile = TYPE_OBJFILE (type); |
|||
|
|||
obj->next = objfile_data (objfile, typy_objfile_data_key); |
|||
if (obj->next) |
|||
obj->next->prev = obj; |
|||
set_objfile_data (objfile, typy_objfile_data_key, obj); |
|||
} |
|||
else |
|||
obj->next = NULL; |
|||
} |
|||
|
|||
static void |
|||
typy_dealloc (PyObject *obj) |
|||
{ |
|||
type_object *type = (type_object *) obj; |
|||
|
|||
if (type->prev) |
|||
type->prev->next = type->next; |
|||
else if (type->type && TYPE_OBJFILE (type->type)) |
|||
{ |
|||
/* Must reset head of list. */ |
|||
struct objfile *objfile = TYPE_OBJFILE (type->type); |
|||
if (objfile) |
|||
set_objfile_data (objfile, typy_objfile_data_key, type->next); |
|||
} |
|||
if (type->next) |
|||
type->next->prev = type->prev; |
|||
|
|||
type->ob_type->tp_free (type); |
|||
} |
|||
|
|||
/* Create a new Type referring to TYPE. */ |
|||
PyObject * |
|||
type_to_type_object (struct type *type) |
|||
{ |
|||
type_object *type_obj; |
|||
|
|||
type_obj = PyObject_New (type_object, &type_object_type); |
|||
if (type_obj) |
|||
set_type (type_obj, type); |
|||
|
|||
return (PyObject *) type_obj; |
|||
} |
|||
|
|||
struct type * |
|||
type_object_to_type (PyObject *obj) |
|||
{ |
|||
if (! PyObject_TypeCheck (obj, &type_object_type)) |
|||
return NULL; |
|||
return ((type_object *) obj)->type; |
|||
} |
|||
|
|||
|
|||
|
|||
/* Implementation of gdb.lookup_type. */ |
|||
PyObject * |
|||
gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw) |
|||
{ |
|||
static char *keywords[] = { "name", NULL }; |
|||
char *type_name = NULL; |
|||
struct type *type = NULL; |
|||
|
|||
if (! PyArg_ParseTupleAndKeywords (args, kw, "s", keywords, &type_name)) |
|||
return NULL; |
|||
|
|||
type = typy_lookup_typename (type_name); |
|||
if (! type) |
|||
return NULL; |
|||
|
|||
return (PyObject *) type_to_type_object (type); |
|||
} |
|||
|
|||
void |
|||
gdbpy_initialize_types (void) |
|||
{ |
|||
int i; |
|||
|
|||
typy_objfile_data_key |
|||
= register_objfile_data_with_cleanup (clean_up_objfile_types); |
|||
|
|||
if (PyType_Ready (&type_object_type) < 0) |
|||
return; |
|||
if (PyType_Ready (&field_object_type) < 0) |
|||
return; |
|||
|
|||
for (i = 0; pyty_codes[i].name; ++i) |
|||
{ |
|||
if (PyModule_AddIntConstant (gdb_module, |
|||
/* Cast needed for Python 2.4. */ |
|||
(char *) pyty_codes[i].name, |
|||
pyty_codes[i].code) < 0) |
|||
return; |
|||
} |
|||
|
|||
Py_INCREF (&type_object_type); |
|||
PyModule_AddObject (gdb_module, "Type", (PyObject *) &type_object_type); |
|||
|
|||
Py_INCREF (&field_object_type); |
|||
PyModule_AddObject (gdb_module, "Field", (PyObject *) &field_object_type); |
|||
} |
|||
|
|||
|
|||
|
|||
static PyGetSetDef type_object_getset[] = |
|||
{ |
|||
{ "code", typy_get_code, NULL, |
|||
"The code for this type.", NULL }, |
|||
{ "sizeof", typy_get_sizeof, NULL, |
|||
"The size of this type, in bytes.", NULL }, |
|||
{ "tag", typy_get_tag, NULL, |
|||
"The tag name for this type, or None.", NULL }, |
|||
{ NULL } |
|||
}; |
|||
|
|||
static PyMethodDef type_object_methods[] = |
|||
{ |
|||
{ "const", typy_const, METH_NOARGS, |
|||
"const () -> Type\n\
|
|||
Return a const variant of this type." }, |
|||
{ "fields", typy_fields, METH_NOARGS, |
|||
"field () -> list\n\
|
|||
Return a sequence holding all the fields of this type.\n\ |
|||
Each field is a dictionary." }, |
|||
{ "pointer", typy_pointer, METH_NOARGS, |
|||
"pointer () -> Type\n\
|
|||
Return a type of pointer to this type." }, |
|||
{ "reference", typy_reference, METH_NOARGS, |
|||
"reference () -> Type\n\
|
|||
Return a type of reference to this type." }, |
|||
{ "strip_typedefs", typy_strip_typedefs, METH_NOARGS, |
|||
"strip_typedefs () -> Type\n\
|
|||
Return a type formed by stripping this type of all typedefs."}, |
|||
{ "target", typy_target, METH_NOARGS, |
|||
"target () -> Type\n\
|
|||
Return the target type of this type." }, |
|||
{ "template_argument", typy_template_argument, METH_VARARGS, |
|||
"template_argument (arg) -> Type\n\
|
|||
Return the type of a template argument." }, |
|||
{ "unqualified", typy_unqualified, METH_NOARGS, |
|||
"unqualified () -> Type\n\
|
|||
Return a variant of this type without const or volatile attributes." }, |
|||
{ "volatile", typy_volatile, METH_NOARGS, |
|||
"volatile () -> Type\n\
|
|||
Return a volatile variant of this type" }, |
|||
{ NULL } |
|||
}; |
|||
|
|||
static PyTypeObject type_object_type = |
|||
{ |
|||
PyObject_HEAD_INIT (NULL) |
|||
0, /*ob_size*/ |
|||
"gdb.Type", /*tp_name*/ |
|||
sizeof (type_object), /*tp_basicsize*/ |
|||
0, /*tp_itemsize*/ |
|||
typy_dealloc, /*tp_dealloc*/ |
|||
0, /*tp_print*/ |
|||
0, /*tp_getattr*/ |
|||
0, /*tp_setattr*/ |
|||
0, /*tp_compare*/ |
|||
0, /*tp_repr*/ |
|||
0, /*tp_as_number*/ |
|||
0, /*tp_as_sequence*/ |
|||
0, /*tp_as_mapping*/ |
|||
0, /*tp_hash */ |
|||
0, /*tp_call*/ |
|||
typy_str, /*tp_str*/ |
|||
0, /*tp_getattro*/ |
|||
0, /*tp_setattro*/ |
|||
0, /*tp_as_buffer*/ |
|||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ |
|||
"GDB type object", /* tp_doc */ |
|||
0, /* tp_traverse */ |
|||
0, /* tp_clear */ |
|||
0, /* tp_richcompare */ |
|||
0, /* tp_weaklistoffset */ |
|||
0, /* tp_iter */ |
|||
0, /* tp_iternext */ |
|||
type_object_methods, /* tp_methods */ |
|||
0, /* tp_members */ |
|||
type_object_getset, /* tp_getset */ |
|||
0, /* tp_base */ |
|||
0, /* tp_dict */ |
|||
0, /* tp_descr_get */ |
|||
0, /* tp_descr_set */ |
|||
0, /* tp_dictoffset */ |
|||
0, /* tp_init */ |
|||
0, /* tp_alloc */ |
|||
0, /* tp_new */ |
|||
}; |
|||
|
|||
static PyTypeObject field_object_type = |
|||
{ |
|||
PyObject_HEAD_INIT (NULL) |
|||
0, /*ob_size*/ |
|||
"gdb.Field", /*tp_name*/ |
|||
sizeof (field_object), /*tp_basicsize*/ |
|||
0, /*tp_itemsize*/ |
|||
field_dealloc, /*tp_dealloc*/ |
|||
0, /*tp_print*/ |
|||
0, /*tp_getattr*/ |
|||
0, /*tp_setattr*/ |
|||
0, /*tp_compare*/ |
|||
0, /*tp_repr*/ |
|||
0, /*tp_as_number*/ |
|||
0, /*tp_as_sequence*/ |
|||
0, /*tp_as_mapping*/ |
|||
0, /*tp_hash */ |
|||
0, /*tp_call*/ |
|||
0, /*tp_str*/ |
|||
0, /*tp_getattro*/ |
|||
0, /*tp_setattro*/ |
|||
0, /*tp_as_buffer*/ |
|||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ |
|||
"GDB field object", /* tp_doc */ |
|||
0, /* tp_traverse */ |
|||
0, /* tp_clear */ |
|||
0, /* tp_richcompare */ |
|||
0, /* tp_weaklistoffset */ |
|||
0, /* tp_iter */ |
|||
0, /* tp_iternext */ |
|||
0, /* tp_methods */ |
|||
0, /* tp_members */ |
|||
0, /* tp_getset */ |
|||
0, /* tp_base */ |
|||
0, /* tp_dict */ |
|||
0, /* tp_descr_get */ |
|||
0, /* tp_descr_set */ |
|||
offsetof (field_object, dict), /* tp_dictoffset */ |
|||
0, /* tp_init */ |
|||
0, /* tp_alloc */ |
|||
0, /* tp_new */ |
|||
}; |
|||
@ -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
|
|||
} |
|||
@ -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 *" |
|||
Loading…
Reference in new issue