old-cross-binutils/gdb/python/py-type.c
Tom Tromey f8eba3c616 the "ambiguous linespec" series
gdb
2011-12-06  Joel Brobecker  <brobecker@acacore.com>

        * language.h (struct language_defn): Add new component
        la_symbol_name_compare.
        * symfile.h (struct quick_symbol_functions): Update the profile
        of parameter "name_matcher" for the expand_symtabs_matching
        method.  Update the documentation accordingly.
        * ada-lang.h (ada_name_for_lookup): Add declaration.
        * ada-lang.c (ada_name_for_lookup): New function, extracted out
        from ada_iterate_over_symbols.
        (ada_iterate_over_symbols): Do not encode symbol name anymore.
        (ada_expand_partial_symbol_name): Adjust profile.
        (ada_language_defn): Add value for la_symbol_name_compare field.
        * linespec.c: #include "ada-lang.h".
        (iterate_name_matcher): Add language parameter. Replace call
        to strcmp_iw by call to language->la_symbol_name_compare.
        (decode_variable): Encode COPY if current language is Ada.
        * dwarf2read.c (dw2_expand_symtabs_matching): Adjust profile
        of name_matcher parameter.  Adjust call to name_matcher.
        * psymtab.c (expand_symtabs_matching_via_partial): Likewise.
        (expand_partial_symbol_names): Update profile of parameter "fun".
        * psymtab.h (expand_partial_symbol_names): Update profile of
        parameter "fun".
        * symtab.c (demangle_for_lookup): Update function documentation.
        (search_symbols_name_matches): Add language parameter.
        (expand_partial_symbol_name): Likewise.
        * c-lang.c (c_language_defn, cplus_language_defn)
        (asm_language_defn, minimal_language_defn): Add value for
        la_symbol_name_compare field.
        * d-lang.c (d_language_defn): Likewise.
        * f-lang.c (f_language_defn): Ditto.
        * jv-lang.c (java_language_defn): Ditto.
        * m2-lang.c (m2_language_defn): Ditto.
        * objc-lang.c (objc_language_defn): Ditto.
        * opencl-lang.c (opencl_language_defn): Ditto.
        * p-lang.c (pascal_language_defn): Ditto.
        * language.c (unknown_language_defn, auto_language_defn)
        (local_language_defn): Ditto.

2011-12-06  Tom Tromey  <tromey@redhat.com>

	* linespec.c (iterate_over_all_matching_symtabs): Use
	LA_ITERATE_OVER_SYMBOLS.
	(lookup_prefix_sym, add_matching_symbols_to_info): Likewise.
	(find_function_symbols, decode_variable): Remove Ada special
	case.
	* language.h (struct language_defn) <la_iterate_over_symbols>: New
	field.
	(LA_ITERATE_OVER_SYMBOLS): New macro.
	* language.c (unknown_language_defn, auto_language_defn)
	(local_language_defn): Update.
	* c-lang.c (c_language_defn, cplus_language_defn)
	(asm_language_defn, minimal_language_defn): Update.
	* d-lang.c (d_language_defn): Update.
	* f-lang.c (f_language_defn): Update.
	* jv-lang.c (java_language_defn): Update.
	* m2-lang.c (m2_language_defn): Update.
	* objc-lang.c (objc_language_defn): Update.
	* opencl-lang.c (opencl_language_defn): Update.
	* p-lang.c (pascal_language_defn): Update.
	* ada-lang.c (ada_iterate_over_symbols): New function.
	(ada_language_defn): Update.

2011-12-06  Tom Tromey  <tromey@redhat.com>
	    Joel Brobecker  <brobecker@acacore.com>

	PR breakpoints/13105, PR objc/8341, PR objc/8343, PR objc/8366,
	PR objc/8535, PR breakpoints/11657, PR breakpoints/11970,
	PR breakpoints/12023, PR breakpoints/12334, PR breakpoints/12856,
	PR shlibs/8929, PR shlibs/7393:
	* python/py-type.c (compare_maybe_null_strings): Rename from
	compare_strings.
	(check_types_equal): Update.
	* utils.c (compare_strings): New function.
	* tui/tui-winsource.c (tui_update_breakpoint_info): Update for
	location changes.
	* tracepoint.c (scope_info): Update.
	(trace_find_line_command): Use DECODE_LINE_FUNFIRSTLINE.
	* symtab.h (iterate_over_minimal_symbols)
	(iterate_over_some_symtabs, iterate_over_symtabs)
	(find_pcs_for_symtab_line, iterate_over_symbols)
	(demangle_for_lookup): Declare.
	(expand_line_sal): Remove.
	* symtab.c (iterate_over_some_symtabs, iterate_over_symtabs)
	(lookup_symtab_callback): New functions.
	(lookup_symtab): Rewrite.
	(demangle_for_lookup): New function, extract from
	lookup_symbol_in_language.
	(lookup_symbol_in_language): Use it.
	(iterate_over_symbols): New function.
	(find_line_symtab): Update.
	(find_pcs_for_symtab_line): New functions.
	(find_line_common): Add 'start' argument.
	(decode_line_spec): Update.  Change argument to 'flags', change
	interpretation.
	(append_expanded_sal): Remove.
	(append_exact_match_to_sals): Remove.
	(expand_line_sal): Remove.
	* symfile.h (struct quick_symbol_functions) <lookup_symtab>:
	Remove.
	<map_symtabs_matching_filename>: New field.
	* stack.c (func_command): Only look in the current program space.
	Use DECODE_LINE_FUNFIRSTLINE.
	* source.c (line_info): Set pspace on sal.  Check program space in
	the loop.  Use DECODE_LINE_LIST_MODE.
	(select_source_symtab): Use DECODE_LINE_FUNFIRSTLINE.
	* solib-target.c: Remove DEF_VEC_I(CORE_ADDR).
	* python/python.c (gdbpy_decode_line): Update.
	* psymtab.c (partial_map_expand_apply): New function.
	(partial_map_symtabs_matching_filename): Rename from
	lookup_partial_symbol.  Update arguments.
	(lookup_symtab_via_partial_symtab): Remove.
	(psym_functions): Update.
	* objc-lang.h (parse_selector, parse_method): Don't declare.
	(find_imps): Update.
	* objc-lang.c (parse_selector, parse_method): Now static.
	(find_methods): Change arguments.  Fill in a vector of symbol
	names.
	(uniquify_strings): New function.
	(find_imps): Change arguments.
	* minsyms.c (iterate_over_minimal_symbols): New function.
	* linespec.h (enum decode_line_flags): New.
	(struct linespec_sals): New.
	(struct linespec_result) <canonical>: Remove.
	<pre_expanded, addr_string, sals>: New fields.
	(destroy_linespec_result, make_cleanup_destroy_linespec_result)
	(decode_line_full): Declare.
	(decode_line_1): Update.
	* linespec.c (struct address_entry, struct linespec_state, struct
	collect_info): New types.
	(add_sal_to_sals_basic, add_sal_to_sals, hash_address_entry)
	(eq_address_entry, maybe_add_address): New functions.
	(total_number_of_methods): Remove.
	(iterate_name_matcher, iterate_over_all_matching_symtabs): New
	functions.
	(find_methods): Change arguments.  Don't canonicalize input.
	Simplify logic.
	(add_matching_methods, add_constructors)
	(build_canonical_line_spec): Remove.
	(filter_results, convert_results_to_lsals): New functions.
	(decode_line_2): Change arguments.  Rewrite for new data
	structures.
	(decode_line_internal): Rename from decode_line_1.  Change
	arguments.  Add cleanups.  Update for new data structures.
	(linespec_state_constructor, linespec_state_destructor)
	(decode_line_full, decode_line_1): New functions.
	(decode_indirect): Change arguments.  Update.
	(locate_first_half): Use skip_spaces.
	(decode_objc): Change arguments.  Update for new data structures.
	Simplify logic.
	(decode_compound): Change arguments.  Add cleanups.  Remove
	fallback code, replace with error.
	(struct decode_compound_collector): New type.
	(collect_one_symbol): New function.
	(lookup_prefix_sym): Change arguments.  Update.
	(compare_symbol_name, add_all_symbol_names_from_pspace)
	(find_superclass_methods ): New functions.
	(find_method): Rewrite.
	(struct symtab_collector): New type.
	(add_symtabs_to_list, collect_symtabs_from_filename): New
	functions.
	(symtabs_from_filename): Change API.  Rename from
	symtab_from_filename.
	(collect_function_symbols): New function.
	(find_function_symbols): Change API.  Rename from
	find_function_symbol.  Rewrite.
	(decode_all_digits): Change arguments.  Rewrite.
	(decode_dollar): Change arguments.  Use decode_variable.
	(decode_label): Change arguments.  Rewrite.
	(collect_symbols): New function.
	(minsym_found): Change arguments.  Rewrite.
	(check_minsym, search_minsyms_for_name)
	(add_matching_symbols_to_info): New function.
	(decode_variable): Change arguments.  Iterate over all symbols.
	(symbol_found): Remove.
	(symbol_to_sal): New function.
	(init_linespec_result, destroy_linespec_result)
	(cleanup_linespec_result, make_cleanup_destroy_linespec_result):
	New functions.
	(decode_digits_list_mode, decode_digits_ordinary): New functions.
	* dwarf2read.c (dw2_map_expand_apply): New function.
	(dw2_map_symtabs_matching_filename): Rename from
	dw2_lookup_symtab.  Change arguments.
	(dwarf2_gdb_index_functions): Update.
	* dwarf2loc.c: Remove DEF_VEC_I(CORE_ADDR).
	* defs.h (compare_strings): Declare.
	* cli/cli-cmds.c (compare_strings): Move to utils.c.
	(edit_command, list_command): Use DECODE_LINE_LIST_MODE.  Call
	filter_sals.
	(compare_symtabs, filter_sals): New functions.
	* breakpoint.h (struct bp_location) <line_number, source_file>:
	New fields.
	(struct breakpoint) <line_number, source_file>: Remove.
	<filter>: New field.
	* breakpoint.c (print_breakpoint_location, init_raw_breakpoint)
	(momentary_breakpoint_from_master, add_location_to_breakpoint):
	Update for changes to locations.
	(init_breakpoint_sal): Add 'filter' argument.  Set 'filter' on
	breakpoint.
	(create_breakpoint_sal): Add 'filter' argument.
	(remove_sal, expand_line_sal_maybe): Remove.
	(create_breakpoints_sal): Remove 'sals' argument.  Handle
	pre-expanded sals and the filter.
	(parse_breakpoint_sals): Use decode_line_full.
	(check_fast_tracepoint_sals): Use get_sal_arch.
	(create_breakpoint): Create a linespec_sals.  Update.
	(break_range_command): Use decode_line_full.  Update.
	(until_break_command): Update.
	(clear_command): Update match conditions for linespec.c changes.
	Use DECODE_LINE_LIST_MODE.
	(say_where): Update for changes to locations.
	(bp_location_dtor): Free 'source_file'.
	(base_breakpoint_dtor): Free 'filter'.  Don't free 'source_file'.
	(update_static_tracepoint): Update for changes to locations.
	(update_breakpoint_locations): Disable ranged breakpoint if too
	many locations match.  Update.
	(addr_string_to_sals): Use decode_line_full.  Resolve all sal
	PCs.
	(breakpoint_re_set_default): Don't call expand_line_sal_maybe.
	(decode_line_spec_1): Update.  Change argument name to 'flags',
	change interpretation.
	* block.h (block_containing_function): Declare.
	* block.c (block_containing_function): New function.
	* skip.c (skip_function_command): Update.
	(skip_re_set): Update.
	* infcmd.c (jump_command): Use DECODE_LINE_FUNFIRSTLINE.
	* mi/mi-main.c (mi_cmd_trace_find): Use DECODE_LINE_FUNFIRSTLINE.
	* NEWS: Add entry.

2011-12-06  Tom Tromey  <tromey@redhat.com>

	* elfread.c (elf_gnu_ifunc_resolver_return_stop): Allow
	breakpoint's pspace to be NULL.
	* breakpoint.h (struct breakpoint) <pspace>: Update comment.
	* breakpoint.c (init_raw_breakpoint): Conditionally set
	breakpoint's pspace.
	(init_breakpoint_sal): Don't set breakpoint's pspace.
	(prepare_re_set_context): Conditionally switch program space.
	(addr_string_to_sals): Check executing_startup on location's
	program space.

2011-12-06  Tom Tromey  <tromey@redhat.com>

	* breakpoint.h (enum enable_state) <bp_startup_disabled>: Remove.
	* breakpoint.c (should_be_inserted): Explicitly check if program
	space is executing startup.
	(describe_other_breakpoints): Update.
	(disable_breakpoints_before_startup): Change executing_startup
	earlier.  Remove loop.
	(enable_breakpoints_after_startup): Likewise.
	(init_breakpoint_sal): Don't use bp_startup_disabled.
	(create_breakpoint): Don't use bp_startup_disabled.
	(update_global_location_list): Use should_be_inserted.
	(bkpt_re_set): Update.
gdb/testsuite
2011-12-06  Joel Brobecker  <brobecker@acacore.com>

        * gdb.ada/fullname_bp.exp: Add tests for other valid linespecs
        involving a fully qualified function name.

2011-12-06  Tom Tromey  <tromey@redhat.com>

	* gdb.ada/homonym.exp: Add three breakpoint tests.

2011-12-06  Tom Tromey  <tromey@redhat.com>

	* gdb.base/solib-weak.exp (do_test): Remove kfail.
	* gdb.trace/tracecmd.exp: Disable pending breakpoints earlier.
	* gdb.objc/objcdecode.exp: Update for output changes.
	* gdb.linespec/linespec.exp: New file.
	* gdb.linespec/lspec.cc: New file.
	* gdb.linespec/lspec.h: New file.
	* gdb.linespec/body.h: New file.
	* gdb.linespec/base/two/thefile.cc: New file.
	* gdb.linespec/base/one/thefile.cc: New file.
	* gdb.linespec/Makefile.in: New file.
	* gdb.cp/templates.exp (test_template_breakpoints): Update for
	output changes.
	* gdb.cp/re-set-overloaded.exp: Remove kfail.
	* gdb.cp/ovldbreak.exp: Update for output changes.  "all" test now
	makes one breakpoint.
	* gdb.cp/method2.exp (test_break): Update for output changes.
	* gdb.cp/mb-templates.exp: Update for output changes.
	* gdb.cp/mb-inline.exp: Update for output changes.
	* gdb.cp/mb-ctor.exp: Update for output changes.
	* gdb.cp/ovsrch.exp: Use fully-qualified names.
	* gdb.base/solib-symbol.exp: Run to main later.  Breakpoint now
	has multiple matches.
	* gdb.base/sepdebug.exp: Disable pending breakpoints.  Update for
	error message change.
	* gdb.base/list.exp (test_list_filename_and_number): Update for
	error message change.
	* gdb.base/break.exp: Disable pending breakpoints.  Update for
	output changes.
	* configure.ac: Add gdb.linespec.
	* configure: Rebuild.
	* Makefile.in (ALL_SUBDIRS): Add gdb.linespec.
gdb/doc
2011-12-06  Tom Tromey  <tromey@redhat.com>

	* gdb.texinfo (Set Breaks): Update for new behavior.
2011-12-06 18:54:43 +00:00

1757 lines
44 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Python interface to types.
Copyright (C) 2008, 2009, 2010, 2011 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"
#include "language.h"
#include "vec.h"
#include "bcache.h"
#include "dwarf2loc.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;
/* A type iterator object. */
typedef struct {
PyObject_HEAD
/* The current field index. */
int field;
/* What to return. */
enum gdbpy_iter_kind kind;
/* Pointer back to the original source type object. */
struct pyty_type_object *source;
} typy_iterator_object;
static PyTypeObject type_iterator_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;
};
/* Forward declarations. */
static PyObject *typy_make_iter (PyObject *self, enum gdbpy_iter_kind kind);
#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
gdb.Field object. 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;
if (TYPE_CODE (type) == TYPE_CODE_CLASS)
arg = field < TYPE_N_BASECLASSES (type) ? Py_True : Py_False;
else
arg = Py_False;
Py_INCREF (arg);
if (PyObject_SetAttrString (result, "is_base_class", 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;
}
/* Helper function to return the name of a field, as a gdb.Field object.
If the field doesn't have a name, None is returned. */
static PyObject *
field_name (struct type *type, int field)
{
PyObject *result;
if (TYPE_FIELD_NAME (type, field))
result = PyString_FromString (TYPE_FIELD_NAME (type, field));
else
{
result = Py_None;
Py_INCREF (result);
}
return result;
}
/* Helper function for Type standard mapping methods. Returns a
Python object for field i of the type. "kind" specifies what to
return: the name of the field, a gdb.Field object corresponding to
the field, or a tuple consisting of field name and gdb.Field
object. */
static PyObject *
make_fielditem (struct type *type, int i, enum gdbpy_iter_kind kind)
{
PyObject *item = NULL, *key = NULL, *value = NULL;
switch (kind)
{
case iter_items:
key = field_name (type, i);
if (key == NULL)
goto fail;
value = convert_field (type, i);
if (value == NULL)
goto fail;
item = PyTuple_New (2);
if (item == NULL)
goto fail;
PyTuple_SET_ITEM (item, 0, key);
PyTuple_SET_ITEM (item, 1, value);
break;
case iter_keys:
item = field_name (type, i);
break;
case iter_values:
item = convert_field (type, i);
break;
}
return item;
fail:
Py_XDECREF (key);
Py_XDECREF (value);
Py_XDECREF (item);
return NULL;
}
/* Return a sequence of all field names, fields, or (name, field) pairs.
Each field is a gdb.Field object. */
static PyObject *
typy_fields_items (PyObject *self, enum gdbpy_iter_kind kind)
{
PyObject *py_type = self;
PyObject *result = NULL, *iter = NULL;
volatile struct gdb_exception except;
struct type *type = ((type_object *) py_type)->type;
struct type *checked_type = type;
TRY_CATCH (except, RETURN_MASK_ALL)
{
CHECK_TYPEDEF (checked_type);
}
GDB_PY_HANDLE_EXCEPTION (except);
if (checked_type != type)
py_type = type_to_type_object (checked_type);
iter = typy_make_iter (py_type, kind);
if (checked_type != type)
{
/* Need to wrap this in braces because Py_DECREF isn't wrapped
in a do{}while(0). */
Py_DECREF (py_type);
}
if (iter != NULL)
{
result = PySequence_List (iter);
Py_DECREF (iter);
}
return result;
}
/* Return a sequence of all fields. Each field is a gdb.Field object. */
static PyObject *
typy_values (PyObject *self, PyObject *args)
{
return typy_fields_items (self, iter_values);
}
/* Return a sequence of all fields. Each field is a gdb.Field object.
This method is similar to typy_values, except where the supplied
gdb.Type is an array, in which case it returns a list of one entry
which is a gdb.Field object for a range (the array bounds). */
static PyObject *
typy_fields (PyObject *self, PyObject *args)
{
struct type *type = ((type_object *) self)->type;
PyObject *r, *rl;
if (TYPE_CODE (type) != TYPE_CODE_ARRAY)
return typy_fields_items (self, iter_values);
/* Array type. Handle this as a special case because the common
machinery wants struct or union or enum types. Build a list of
one entry which is the range for the array. */
r = convert_field (type, 0);
if (r == NULL)
return NULL;
rl = Py_BuildValue ("[O]", r);
if (rl == NULL)
{
Py_DECREF (r);
}
return rl;
}
/* Return a sequence of all field names. Each field is a gdb.Field object. */
static PyObject *
typy_field_names (PyObject *self, PyObject *args)
{
return typy_fields_items (self, iter_keys);
}
/* Return a sequence of all (name, fields) pairs. Each field is a
gdb.Field object. */
static PyObject *
typy_items (PyObject *self, PyObject *args)
{
return typy_fields_items (self, iter_items);
}
/* 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;
volatile struct gdb_exception except;
TRY_CATCH (except, RETURN_MASK_ALL)
{
type = check_typedef (type);
}
GDB_PY_HANDLE_EXCEPTION (except);
return type_to_type_object (check_typedef (type));
}
/* Strip typedefs and pointers/reference from a type. Then check that
it is a struct, union, or enum type. If not, raise TypeError. */
static struct type *
typy_get_composite (struct type *type)
{
volatile struct gdb_exception except;
for (;;)
{
TRY_CATCH (except, RETURN_MASK_ALL)
{
CHECK_TYPEDEF (type);
}
/* Don't use GDB_PY_HANDLE_EXCEPTION here because that returns
a (NULL) pointer of the wrong type. */
if (except.reason < 0)
{
gdbpy_convert_exception (except);
return NULL;
}
if (TYPE_CODE (type) != TYPE_CODE_PTR
&& TYPE_CODE (type) != TYPE_CODE_REF)
break;
type = TYPE_TARGET_TYPE (type);
}
/* If this is not a struct, union, or enum type, raise TypeError
exception. */
if (TYPE_CODE (type) != TYPE_CODE_STRUCT
&& TYPE_CODE (type) != TYPE_CODE_UNION
&& TYPE_CODE (type) != TYPE_CODE_ENUM)
{
PyErr_SetString (PyExc_TypeError,
"Type is not a structure, union, or enum type.");
return NULL;
}
return type;
}
/* Return an array type. */
static PyObject *
typy_array (PyObject *self, PyObject *args)
{
long n1, n2;
PyObject *n2_obj = NULL;
struct type *array = NULL;
struct type *type = ((type_object *) self)->type;
volatile struct gdb_exception except;
if (! PyArg_ParseTuple (args, "l|O", &n1, &n2_obj))
return NULL;
if (n2_obj)
{
if (!PyInt_Check (n2_obj))
{
PyErr_SetString (PyExc_RuntimeError,
_("Array bound must be an integer"));
return NULL;
}
if (! gdb_py_int_as_long (n2_obj, &n2))
return NULL;
}
else
{
n2 = n1;
n1 = 0;
}
if (n2 < n1)
{
PyErr_SetString (PyExc_ValueError,
_("Array length must not be negative"));
return NULL;
}
TRY_CATCH (except, RETURN_MASK_ALL)
{
array = lookup_array_range_type (type, n1, n2);
}
GDB_PY_HANDLE_EXCEPTION (except);
return type_to_type_object (array);
}
/* 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 the range of a type represented by SELF. The return type is
a tuple. The first element of the tuple contains the low bound,
while the second element of the tuple contains the high bound. */
static PyObject *
typy_range (PyObject *self, PyObject *args)
{
struct type *type = ((type_object *) self)->type;
PyObject *result;
PyObject *low_bound = NULL, *high_bound = NULL;
/* Initialize these to appease GCC warnings. */
LONGEST low = 0, high = 0;
if (TYPE_CODE (type) != TYPE_CODE_ARRAY
&& TYPE_CODE (type) != TYPE_CODE_STRING
&& TYPE_CODE (type) != TYPE_CODE_RANGE)
{
PyErr_SetString (PyExc_RuntimeError,
_("This type does not have a range."));
return NULL;
}
switch (TYPE_CODE (type))
{
case TYPE_CODE_ARRAY:
case TYPE_CODE_STRING:
low = TYPE_LOW_BOUND (TYPE_INDEX_TYPE (type));
high = TYPE_HIGH_BOUND (TYPE_INDEX_TYPE (type));
break;
case TYPE_CODE_RANGE:
low = TYPE_LOW_BOUND (type);
high = TYPE_HIGH_BOUND (type);
break;
}
low_bound = PyLong_FromLong (low);
if (!low_bound)
goto failarg;
high_bound = PyLong_FromLong (high);
if (!high_bound)
goto failarg;
result = PyTuple_New (2);
if (!result)
goto failarg;
if (PyTuple_SetItem (result, 0, low_bound) != 0)
{
Py_DECREF (result);
goto failarg;
}
if (PyTuple_SetItem (result, 1, high_bound) != 0)
{
Py_DECREF (high_bound);
Py_DECREF (result);
return NULL;
}
return result;
failarg:
Py_XDECREF (high_bound);
Py_XDECREF (low_bound);
return NULL;
}
/* 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 (const char *type_name, const struct block *block)
{
struct type *type = NULL;
volatile struct gdb_exception except;
TRY_CATCH (except, RETURN_MASK_ALL)
{
if (!strncmp (type_name, "struct ", 7))
type = lookup_struct (type_name + 7, NULL);
else if (!strncmp (type_name, "union ", 6))
type = lookup_union (type_name + 6, NULL);
else if (!strncmp (type_name, "enum ", 5))
type = lookup_enum (type_name + 5, NULL);
else
type = lookup_typename (python_language, python_gdbarch,
type_name, block, 0);
}
if (except.reason < 0)
{
gdbpy_convert_exception (except);
return NULL;
}
return type;
}
static struct type *
typy_lookup_type (struct demangle_component *demangled,
const struct block *block)
{
struct type *type, *rtype = NULL;
char *type_name = NULL;
enum demangle_component_type demangled_type;
volatile struct gdb_exception except;
/* 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, block);
if (! type)
return NULL;
TRY_CATCH (except, RETURN_MASK_ALL)
{
/* If the demangled_type matches with one of the types
below, run the corresponding function and save the type
to return later. We cannot just return here as we are in
an exception handler. */
switch (demangled_type)
{
case DEMANGLE_COMPONENT_REFERENCE:
rtype = lookup_reference_type (type);
break;
case DEMANGLE_COMPONENT_POINTER:
rtype = lookup_pointer_type (type);
break;
case DEMANGLE_COMPONENT_CONST:
rtype = make_cv_type (1, 0, type, NULL);
break;
case DEMANGLE_COMPONENT_VOLATILE:
rtype = make_cv_type (0, 1, type, NULL);
break;
}
}
if (except.reason < 0)
{
gdbpy_convert_exception (except);
return NULL;
}
}
/* If we have a type from the switch statement above, just return
that. */
if (rtype)
return rtype;
/* We don't have a type, so lookup the type. */
type_name = cp_comp_to_string (demangled, 10);
type = typy_lookup_typename (type_name, block);
xfree (type_name);
return type;
}
/* This is a helper function for typy_template_argument that is used
when the type does not have template symbols attached. It works by
parsing the type name. This happens with compilers, like older
versions of GCC, that do not emit DW_TAG_template_*. */
static PyObject *
typy_legacy_template_argument (struct type *type, const struct block *block,
int argno)
{
int i;
struct demangle_component *demangled;
struct demangle_parse_info *info = NULL;
const char *err;
struct type *argtype;
struct cleanup *cleanup;
volatile struct gdb_exception except;
if (TYPE_NAME (type) == NULL)
{
PyErr_SetString (PyExc_RuntimeError, _("Null type name."));
return NULL;
}
TRY_CATCH (except, RETURN_MASK_ALL)
{
/* Note -- this is not thread-safe. */
info = cp_demangled_name_to_comp (TYPE_NAME (type), &err);
}
GDB_PY_HANDLE_EXCEPTION (except);
if (! info)
{
PyErr_SetString (PyExc_RuntimeError, err);
return NULL;
}
demangled = info->tree;
cleanup = make_cleanup_cp_demangled_name_parse_free (info);
/* 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)
{
do_cleanups (cleanup);
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)
{
do_cleanups (cleanup);
PyErr_Format (PyExc_RuntimeError, _("No argument %d in template."),
argno);
return NULL;
}
argtype = typy_lookup_type (demangled->u.s_binary.left, block);
do_cleanups (cleanup);
if (! argtype)
return NULL;
return type_to_type_object (argtype);
}
static PyObject *
typy_template_argument (PyObject *self, PyObject *args)
{
int argno;
struct type *type = ((type_object *) self)->type;
const struct block *block = NULL;
PyObject *block_obj = NULL;
struct symbol *sym;
struct value *val = NULL;
volatile struct gdb_exception except;
if (! PyArg_ParseTuple (args, "i|O", &argno, &block_obj))
return NULL;
if (block_obj)
{
block = block_object_to_block (block_obj);
if (! block)
{
PyErr_SetString (PyExc_RuntimeError,
_("Second argument must be block."));
return NULL;
}
}
TRY_CATCH (except, RETURN_MASK_ALL)
{
type = check_typedef (type);
if (TYPE_CODE (type) == TYPE_CODE_REF)
type = check_typedef (TYPE_TARGET_TYPE (type));
}
GDB_PY_HANDLE_EXCEPTION (except);
/* We might not have DW_TAG_template_*, so try to parse the type's
name. This is inefficient if we do not have a template type --
but that is going to wind up as an error anyhow. */
if (! TYPE_N_TEMPLATE_ARGUMENTS (type))
return typy_legacy_template_argument (type, block, argno);
if (argno >= TYPE_N_TEMPLATE_ARGUMENTS (type))
{
PyErr_Format (PyExc_RuntimeError, _("No argument %d in template."),
argno);
return NULL;
}
sym = TYPE_TEMPLATE_ARGUMENT (type, argno);
if (SYMBOL_CLASS (sym) == LOC_TYPEDEF)
return type_to_type_object (SYMBOL_TYPE (sym));
else if (SYMBOL_CLASS (sym) == LOC_OPTIMIZED_OUT)
{
PyErr_Format (PyExc_RuntimeError,
_("Template argument is optimized out"));
return NULL;
}
TRY_CATCH (except, RETURN_MASK_ALL)
{
val = value_of_variable (sym, block);
}
GDB_PY_HANDLE_EXCEPTION (except);
return value_to_value_object (val);
}
static PyObject *
typy_str (PyObject *self)
{
volatile struct gdb_exception except;
char *thetype = NULL;
long length = 0;
PyObject *result;
TRY_CATCH (except, RETURN_MASK_ALL)
{
struct cleanup *old_chain;
struct ui_file *stb;
stb = mem_fileopen ();
old_chain = make_cleanup_ui_file_delete (stb);
type_print (type_object_to_type (self), "", stb, -1);
thetype = ui_file_xstrdup (stb, &length);
do_cleanups (old_chain);
}
if (except.reason < 0)
{
xfree (thetype);
GDB_PY_HANDLE_EXCEPTION (except);
}
result = PyUnicode_Decode (thetype, length, host_charset (), NULL);
xfree (thetype);
return result;
}
/* An entry in the type-equality bcache. */
typedef struct type_equality_entry
{
struct type *type1, *type2;
} type_equality_entry_d;
DEF_VEC_O (type_equality_entry_d);
/* A helper function to compare two strings. Returns 1 if they are
the same, 0 otherwise. Handles NULLs properly. */
static int
compare_maybe_null_strings (const char *s, const char *t)
{
if (s == NULL && t != NULL)
return 0;
else if (s != NULL && t == NULL)
return 0;
else if (s == NULL && t== NULL)
return 1;
return strcmp (s, t) == 0;
}
/* A helper function for typy_richcompare that checks two types for
"deep" equality. Returns Py_EQ if the types are considered the
same, Py_NE otherwise. */
static int
check_types_equal (struct type *type1, struct type *type2,
VEC (type_equality_entry_d) **worklist)
{
CHECK_TYPEDEF (type1);
CHECK_TYPEDEF (type2);
if (type1 == type2)
return Py_EQ;
if (TYPE_CODE (type1) != TYPE_CODE (type2)
|| TYPE_LENGTH (type1) != TYPE_LENGTH (type2)
|| TYPE_UNSIGNED (type1) != TYPE_UNSIGNED (type2)
|| TYPE_NOSIGN (type1) != TYPE_NOSIGN (type2)
|| TYPE_VARARGS (type1) != TYPE_VARARGS (type2)
|| TYPE_VECTOR (type1) != TYPE_VECTOR (type2)
|| TYPE_NOTTEXT (type1) != TYPE_NOTTEXT (type2)
|| TYPE_INSTANCE_FLAGS (type1) != TYPE_INSTANCE_FLAGS (type2)
|| TYPE_NFIELDS (type1) != TYPE_NFIELDS (type2))
return Py_NE;
if (!compare_maybe_null_strings (TYPE_TAG_NAME (type1),
TYPE_TAG_NAME (type2)))
return Py_NE;
if (!compare_maybe_null_strings (TYPE_NAME (type1), TYPE_NAME (type2)))
return Py_NE;
if (TYPE_CODE (type1) == TYPE_CODE_RANGE)
{
if (memcmp (TYPE_RANGE_DATA (type1), TYPE_RANGE_DATA (type2),
sizeof (*TYPE_RANGE_DATA (type1))) != 0)
return Py_NE;
}
else
{
int i;
for (i = 0; i < TYPE_NFIELDS (type1); ++i)
{
const struct field *field1 = &TYPE_FIELD (type1, i);
const struct field *field2 = &TYPE_FIELD (type2, i);
struct type_equality_entry entry;
if (FIELD_ARTIFICIAL (*field1) != FIELD_ARTIFICIAL (*field2)
|| FIELD_BITSIZE (*field1) != FIELD_BITSIZE (*field2)
|| FIELD_LOC_KIND (*field1) != FIELD_LOC_KIND (*field2))
return Py_NE;
if (!compare_maybe_null_strings (FIELD_NAME (*field1),
FIELD_NAME (*field2)))
return Py_NE;
switch (FIELD_LOC_KIND (*field1))
{
case FIELD_LOC_KIND_BITPOS:
if (FIELD_BITPOS (*field1) != FIELD_BITPOS (*field2))
return Py_NE;
break;
case FIELD_LOC_KIND_PHYSADDR:
if (FIELD_STATIC_PHYSADDR (*field1)
!= FIELD_STATIC_PHYSADDR (*field2))
return Py_NE;
break;
case FIELD_LOC_KIND_PHYSNAME:
if (!compare_maybe_null_strings (FIELD_STATIC_PHYSNAME (*field1),
FIELD_STATIC_PHYSNAME (*field2)))
return Py_NE;
break;
case FIELD_LOC_KIND_DWARF_BLOCK:
{
struct dwarf2_locexpr_baton *block1, *block2;
block1 = FIELD_DWARF_BLOCK (*field1);
block2 = FIELD_DWARF_BLOCK (*field2);
if (block1->per_cu != block2->per_cu
|| block1->size != block2->size
|| memcmp (block1->data, block2->data, block1->size) != 0)
return Py_NE;
}
break;
default:
internal_error (__FILE__, __LINE__, _("Unsupported field kind "
"%d by check_types_equal"),
FIELD_LOC_KIND (*field1));
}
entry.type1 = FIELD_TYPE (*field1);
entry.type2 = FIELD_TYPE (*field2);
VEC_safe_push (type_equality_entry_d, *worklist, &entry);
}
}
if (TYPE_TARGET_TYPE (type1) != NULL)
{
struct type_equality_entry entry;
int added;
if (TYPE_TARGET_TYPE (type2) == NULL)
return Py_NE;
entry.type1 = TYPE_TARGET_TYPE (type1);
entry.type2 = TYPE_TARGET_TYPE (type2);
VEC_safe_push (type_equality_entry_d, *worklist, &entry);
}
else if (TYPE_TARGET_TYPE (type2) != NULL)
return Py_NE;
return Py_EQ;
}
/* Check types on a worklist for equality. Returns Py_NE if any pair
is not equal, Py_EQ if they are all considered equal. */
static int
check_types_worklist (VEC (type_equality_entry_d) **worklist,
struct bcache *cache)
{
while (!VEC_empty (type_equality_entry_d, *worklist))
{
struct type_equality_entry entry;
int added;
entry = *VEC_last (type_equality_entry_d, *worklist);
VEC_pop (type_equality_entry_d, *worklist);
/* If the type pair has already been visited, we know it is
ok. */
bcache_full (&entry, sizeof (entry), cache, &added);
if (!added)
continue;
if (check_types_equal (entry.type1, entry.type2, worklist) == Py_NE)
return Py_NE;
}
return Py_EQ;
}
/* Implement the richcompare method. */
static PyObject *
typy_richcompare (PyObject *self, PyObject *other, int op)
{
int result = Py_NE;
struct type *type1 = type_object_to_type (self);
struct type *type2 = type_object_to_type (other);
volatile struct gdb_exception except;
/* We can only compare ourselves to another Type object, and only
for equality or inequality. */
if (type2 == NULL || (op != Py_EQ && op != Py_NE))
{
Py_INCREF (Py_NotImplemented);
return Py_NotImplemented;
}
if (type1 == type2)
result = Py_EQ;
else
{
struct bcache *cache;
VEC (type_equality_entry_d) *worklist = NULL;
struct type_equality_entry entry;
cache = bcache_xmalloc (NULL, NULL);
entry.type1 = type1;
entry.type2 = type2;
VEC_safe_push (type_equality_entry_d, worklist, &entry);
TRY_CATCH (except, RETURN_MASK_ALL)
{
result = check_types_worklist (&worklist, cache);
}
/* check_types_worklist calls several nested Python helper
functions, some of which can raise a GDB Exception, so we
just check and convert here. If there is a GDB exception, a
comparison is not capable (or trusted), so exit. */
bcache_xfree (cache);
VEC_free (type_equality_entry_d, worklist);
GDB_PY_HANDLE_EXCEPTION (except);
}
if (op == result)
Py_RETURN_TRUE;
Py_RETURN_FALSE;
}
static const struct objfile_data *typy_objfile_data_key;
static void
save_objfile_types (struct objfile *objfile, void *datum)
{
type_object *obj = datum;
htab_t copied_types;
struct cleanup *cleanup;
/* This prevents another thread from freeing the objects we're
operating on. */
cleanup = ensure_python_env (get_objfile_arch (objfile), current_language);
copied_types = create_copied_types_hash (objfile);
while (obj)
{
type_object *next = obj->next;
htab_empty (copied_types);
obj->type = copy_type_recursive (objfile, obj->type, copied_types);
obj->next = NULL;
obj->prev = NULL;
obj = next;
}
htab_delete (copied_types);
do_cleanups (cleanup);
}
static void
set_type (type_object *obj, struct type *type)
{
obj->type = type;
obj->prev = NULL;
if (type && TYPE_OBJFILE (type))
{
struct objfile *objfile = TYPE_OBJFILE (type);
obj->next = objfile_data (objfile, typy_objfile_data_key);
if (obj->next)
obj->next->prev = obj;
set_objfile_data (objfile, typy_objfile_data_key, obj);
}
else
obj->next = NULL;
}
static void
typy_dealloc (PyObject *obj)
{
type_object *type = (type_object *) obj;
if (type->prev)
type->prev->next = type->next;
else if (type->type && TYPE_OBJFILE (type->type))
{
/* Must reset head of list. */
struct objfile *objfile = TYPE_OBJFILE (type->type);
if (objfile)
set_objfile_data (objfile, typy_objfile_data_key, type->next);
}
if (type->next)
type->next->prev = type->prev;
type->ob_type->tp_free (type);
}
/* Return number of fields ("length" of the field dictionary). */
static Py_ssize_t
typy_length (PyObject *self)
{
struct type *type = ((type_object *) self)->type;
type = typy_get_composite (type);
if (type == NULL)
return -1;
return TYPE_NFIELDS (type);
}
/* Implements boolean evaluation of gdb.Type. Handle this like other
Python objects that don't have a meaningful truth value -- all
values are true. */
static int
typy_nonzero (PyObject *self)
{
return 1;
}
/* Return a gdb.Field object for the field named by the argument. */
static PyObject *
typy_getitem (PyObject *self, PyObject *key)
{
struct type *type = ((type_object *) self)->type;
char *field;
int i;
volatile struct gdb_exception except;
field = python_string_to_host_string (key);
if (field == NULL)
return NULL;
/* We want just fields of this type, not of base types, so instead of
using lookup_struct_elt_type, portions of that function are
copied here. */
type = typy_get_composite (type);
if (type == NULL)
return NULL;
for (i = 0; i < TYPE_NFIELDS (type); i++)
{
char *t_field_name = TYPE_FIELD_NAME (type, i);
if (t_field_name && (strcmp_iw (t_field_name, field) == 0))
{
return convert_field (type, i);
}
}
PyErr_SetObject (PyExc_KeyError, key);
return NULL;
}
/* Implement the "get" method on the type object. This is the
same as getitem if the key is present, but returns the supplied
default value or None if the key is not found. */
static PyObject *
typy_get (PyObject *self, PyObject *args)
{
PyObject *key, *defval = Py_None, *result;
if (!PyArg_UnpackTuple (args, "get", 1, 2, &key, &defval))
return NULL;
result = typy_getitem (self, key);
if (result != NULL)
return result;
/* typy_getitem returned error status. If the exception is
KeyError, clear the exception status and return the defval
instead. Otherwise return the exception unchanged. */
if (!PyErr_ExceptionMatches (PyExc_KeyError))
return NULL;
PyErr_Clear ();
Py_INCREF (defval);
return defval;
}
/* Implement the "has_key" method on the type object. */
static PyObject *
typy_has_key (PyObject *self, PyObject *args)
{
struct type *type = ((type_object *) self)->type;
const char *field;
int i;
volatile struct gdb_exception except;
if (!PyArg_ParseTuple (args, "s", &field))
return NULL;
/* We want just fields of this type, not of base types, so instead of
using lookup_struct_elt_type, portions of that function are
copied here. */
type = typy_get_composite (type);
if (type == NULL)
return NULL;
for (i = 0; i < TYPE_NFIELDS (type); i++)
{
char *t_field_name = TYPE_FIELD_NAME (type, i);
if (t_field_name && (strcmp_iw (t_field_name, field) == 0))
Py_RETURN_TRUE;
}
Py_RETURN_FALSE;
}
/* Make an iterator object to iterate over keys, values, or items. */
static PyObject *
typy_make_iter (PyObject *self, enum gdbpy_iter_kind kind)
{
typy_iterator_object *typy_iter_obj;
/* Check that "self" is a structure or union type. */
if (typy_get_composite (((type_object *) self)->type) == NULL)
return NULL;
typy_iter_obj = PyObject_New (typy_iterator_object,
&type_iterator_object_type);
if (typy_iter_obj == NULL)
return NULL;
typy_iter_obj->field = 0;
typy_iter_obj->kind = kind;
Py_INCREF (self);
typy_iter_obj->source = (type_object *) self;
return (PyObject *) typy_iter_obj;
}
/* iteritems() method. */
static PyObject *
typy_iteritems (PyObject *self, PyObject *args)
{
return typy_make_iter (self, iter_items);
}
/* iterkeys() method. */
static PyObject *
typy_iterkeys (PyObject *self, PyObject *args)
{
return typy_make_iter (self, iter_keys);
}
/* Iterating over the class, same as iterkeys except for the function
signature. */
static PyObject *
typy_iter (PyObject *self)
{
return typy_make_iter (self, iter_keys);
}
/* itervalues() method. */
static PyObject *
typy_itervalues (PyObject *self, PyObject *args)
{
return typy_make_iter (self, iter_values);
}
/* Return a reference to the type iterator. */
static PyObject *
typy_iterator_iter (PyObject *self)
{
Py_INCREF (self);
return self;
}
/* Return the next field in the iteration through the list of fields
of the type. */
static PyObject *
typy_iterator_iternext (PyObject *self)
{
typy_iterator_object *iter_obj = (typy_iterator_object *) self;
struct type *type = iter_obj->source->type;
int i;
PyObject *result;
if (iter_obj->field < TYPE_NFIELDS (type))
{
result = make_fielditem (type, iter_obj->field, iter_obj->kind);
if (result != NULL)
iter_obj->field++;
return result;
}
return NULL;
}
static void
typy_iterator_dealloc (PyObject *obj)
{
typy_iterator_object *iter_obj = (typy_iterator_object *) obj;
Py_DECREF (iter_obj->source);
}
/* 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", "block", NULL };
const char *type_name = NULL;
struct type *type = NULL;
PyObject *block_obj = NULL;
const struct block *block = NULL;
if (! PyArg_ParseTupleAndKeywords (args, kw, "s|O", keywords,
&type_name, &block_obj))
return NULL;
if (block_obj)
{
block = block_object_to_block (block_obj);
if (! block)
{
PyErr_SetString (PyExc_RuntimeError,
_("'block' argument must be a Block."));
return NULL;
}
}
type = typy_lookup_typename (type_name, block);
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 (save_objfile_types, NULL);
if (PyType_Ready (&type_object_type) < 0)
return;
if (PyType_Ready (&field_object_type) < 0)
return;
if (PyType_Ready (&type_iterator_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 (&type_iterator_object_type);
PyModule_AddObject (gdb_module, "TypeIterator",
(PyObject *) &type_iterator_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[] =
{
{ "array", typy_array, METH_VARARGS,
"array ([LOW_BOUND,] HIGH_BOUND) -> Type\n\
Return a type which represents an array of objects of this type.\n\
The bounds of the array are [LOW_BOUND, HIGH_BOUND] inclusive.\n\
If LOW_BOUND is omitted, a value of zero is used." },
{ "__contains__", typy_has_key, METH_VARARGS,
"T.__contains__(k) -> True if T has a field named k, else False" },
{ "const", typy_const, METH_NOARGS,
"const () -> Type\n\
Return a const variant of this type." },
{ "fields", typy_fields, METH_NOARGS,
"fields () -> list\n\
Return a list holding all the fields of this type.\n\
Each field is a gdb.Field object." },
{ "get", typy_get, METH_VARARGS,
"T.get(k[,default]) -> returns field named k in T, if it exists;\n\
otherwise returns default, if supplied, or None if not." },
{ "has_key", typy_has_key, METH_VARARGS,
"T.has_key(k) -> True if T has a field named k, else False" },
{ "items", typy_items, METH_NOARGS,
"items () -> list\n\
Return a list of (name, field) pairs of this type.\n\
Each field is a gdb.Field object." },
{ "iteritems", typy_iteritems, METH_NOARGS,
"iteritems () -> an iterator over the (name, field)\n\
pairs of this type. Each field is a gdb.Field object." },
{ "iterkeys", typy_iterkeys, METH_NOARGS,
"iterkeys () -> an iterator over the field names of this type." },
{ "itervalues", typy_itervalues, METH_NOARGS,
"itervalues () -> an iterator over the fields of this type.\n\
Each field is a gdb.Field object." },
{ "keys", typy_field_names, METH_NOARGS,
"keys () -> list\n\
Return a list holding all the fields names of this type." },
{ "pointer", typy_pointer, METH_NOARGS,
"pointer () -> Type\n\
Return a type of pointer to this type." },
{ "range", typy_range, METH_NOARGS,
"range () -> tuple\n\
Return a tuple containing the lower and upper range for 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, [block]) -> 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." },
{ "values", typy_values, METH_NOARGS,
"values () -> list\n\
Return a list holding all the fields of this type.\n\
Each field is a gdb.Field object." },
{ "volatile", typy_volatile, METH_NOARGS,
"volatile () -> Type\n\
Return a volatile variant of this type" },
{ NULL }
};
static PyNumberMethods type_object_as_number = {
NULL, /* nb_add */
NULL, /* nb_subtract */
NULL, /* nb_multiply */
NULL, /* nb_divide */
NULL, /* nb_remainder */
NULL, /* nb_divmod */
NULL, /* nb_power */
NULL, /* nb_negative */
NULL, /* nb_positive */
NULL, /* nb_absolute */
typy_nonzero, /* nb_nonzero */
NULL, /* nb_invert */
NULL, /* nb_lshift */
NULL, /* nb_rshift */
NULL, /* nb_and */
NULL, /* nb_xor */
NULL, /* nb_or */
NULL, /* nb_coerce */
NULL, /* nb_int */
NULL, /* nb_long */
NULL, /* nb_float */
NULL, /* nb_oct */
NULL /* nb_hex */
};
static PyMappingMethods typy_mapping = {
typy_length,
typy_getitem,
NULL /* no "set" method */
};
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*/
&type_object_as_number, /*tp_as_number*/
0, /*tp_as_sequence*/
&typy_mapping, /*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 */
typy_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
typy_iter, /* 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 */
};
static PyTypeObject type_iterator_object_type = {
PyObject_HEAD_INIT (NULL)
0, /*ob_size*/
"gdb.TypeIterator", /*tp_name*/
sizeof (typy_iterator_object), /*tp_basicsize*/
0, /*tp_itemsize*/
typy_iterator_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 type iterator object", /*tp_doc */
0, /*tp_traverse */
0, /*tp_clear */
0, /*tp_richcompare */
0, /*tp_weaklistoffset */
typy_iterator_iter, /*tp_iter */
typy_iterator_iternext, /*tp_iternext */
0 /*tp_methods */
};