2009-05-28 00:47:20 +00:00
|
|
|
|
/* Python interface to types.
|
|
|
|
|
|
|
2026-01-05 08:13:29 -07:00
|
|
|
|
Copyright (C) 2008-2026 Free Software Foundation, Inc.
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
|
|
|
|
|
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 "value.h"
|
|
|
|
|
|
#include "python-internal.h"
|
|
|
|
|
|
#include "charset.h"
|
|
|
|
|
|
#include "gdbtypes.h"
|
|
|
|
|
|
#include "cp-support.h"
|
|
|
|
|
|
#include "demangle.h"
|
|
|
|
|
|
#include "objfiles.h"
|
2009-06-17 18:46:26 +00:00
|
|
|
|
#include "language.h"
|
* NEWS: Update.
* c-typeprint.c (c_type_print_base): Handle print_method and
print_typedefs flags.
* gdbcmd.h (setprinttypelist, showprinttypelist): Declare.
* python/py-type.c (typy_str): Use LA_PRINT_TYPE and raw
options.
* typeprint.c (type_print_raw_options, default_ptype_flags):
Update for new field.s
(whatis_exp): Parse flags. Use LA_PRINT_TYPE.
(setprinttypelist, showprinttypelist, print_methods,
print_typedefs): New globals.
(set_print_type, show_print_type, set_print_type_methods,
show_print_type_methods, set_print_type_typedefs,
show_print_type_typedefs): New functions.
(_initialize_typeprint): Update documentation. Add "print
type methods" and "print type typedefs" parameters.
* typeprint.h (struct type_print_options) <print_methods,
print_typedefs>: New fields.
doc
* gdb.texinfo (Symbols): Document "set print type methods",
"set print type typedefs", and flags to ptype and whatis.
2012-11-12 17:26:21 +00:00
|
|
|
|
#include "typeprint.h"
|
2021-06-25 08:01:15 -06:00
|
|
|
|
#include "ada-lang.h"
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
2026-01-05 12:14:28 +01:00
|
|
|
|
struct type_object : public PyObject
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
|
|
|
|
|
struct type *type;
|
Remove redundant typedefs
I was inspired by this patch of Simon's:
https://sourceware.org/pipermail/gdb-patches/2020-November/173522.html
... to remove other typedefs that are no longer necessary now that gdb
uses C++.
I didn't remove absolutely every one -- I didn't touch the tdep files.
However, I removed many of them. In some cases, I removed an existing
different struct tag.
2020-12-04 Tom Tromey <tromey@adacore.com>
* linespec.c (struct linespec_token): Rename; remove typedef.
* guile/scm-block.c (struct block_smob): Remove typedef.
(struct block_syms_progress_smob): Likewise.
* guile/scm-symbol.c (struct symbol_smob): Remove typedef.
* guile/scm-symtab.c (symtab_smob): Remove typedef.
(struct sal_smob): Remove typedef.
* guile/scm-param.c (struct param_smob): Remove typedef.
* guile/scm-progspace.c (struct pspace_smob): Rename.
* guile/scm-objfile.c (struct objfile_smob): Rename.
* guile/scm-iterator.c (struct iterator_smob): Rename.
* guile/scm-frame.c (struct frame_smob): Rename.
* guile/scm-arch.c (struct arch_smob): Rename.
* guile/scm-type.c (struct field_smob): Remove typedef.
(struct type_smob): Rename.
* guile/scm-cmd.c (struct command_smob): Remove typedef.
* guile/scm-ports.c (struct ioscm_memory_port): Remove typedef.
* guile/scm-value.c (struct value_smob): Remove typedef.
* guile/scm-lazy-string.c (lazy_string_smob): Remove typedef.
* guile/guile-internal.h (struct scheme_variable)
(struct scheme_function, struct scheme_integer_constant)
(struct gdb_smob, struct chained_gdb_smob)
(struct eqable_gdb_smob, arch_smob, frame_smob, iterator_smob)
(objfile_smob, pspace_smob, type_smob): Remove typedef.
* guile/scm-pretty-print.c (pretty_printer_smob): Remove typedef.
(struct pretty_printer_worker_smob): Remove typedef.
* guile/scm-exception.c (struct exception_smob): Remove typedef.
* python/py-block.c (struct block_object): Remove typedef.
(block_syms_iterator_object): Update.
(set_block): Update.
(block_syms_iterator_object): Remove typedef.
* python/py-inferior.c (struct membuf_object): Remove typedef.
* python/py-symtab.c (struct symtab_object): Remove typedef.
(set_symtab): Update.
(sal_object): Remove typedef.
(set_sal): Update.
* python/py-frame.c (frame_object): Remove typedef.
* python/py-record-btrace.c (struct btpy_list_object): Remove
typedef.
* python/py-arch.c (struct arch_object): Remove typedef.
* python/py-linetable.c (struct linetable_entry_object)
(linetable_object, struct ltpy_iterator_object): Remove typedef.
* python/py-events.h (eventregistry_object): Remove typedef.
(struct events_object): Remove typedef.
* python/python-internal.h (gdbpy_breakpoint_object): Remove
typedef.
(thread_object): Remove typedef.
* python/py-progspace.c (pspace_object): Remove typedef.
* python/py-value.c (struct value_object): Remove typedef.
* python/py-record.h (recpy_record_object): Remove typedef.
(struct recpy_element_object): Remove typedef.
* python/py-lazy-string.c (lazy_string_object): Remove typedef.
* python/py-objfile.c (objfile_object): Remove typedef.
* python/py-cmd.c (struct cmdpy_object): Remove typedef.
* python/py-type.c (type_object): Remove typedef.
(typy_iterator_object): Update.
(set_type): Update.
(field_object): Remove typedef.
(typy_iterator_object): Remove typedef.
* python/py-registers.c (register_descriptor_iterator_object):
Remove typedef.
(struct register_descriptor_object)
(struct reggroup_iterator_object, struct reggroup_object): Remove
typedef.
* python/py-record.c (recpy_gap_object): Remove typedef.
* python/py-symbol.c (symbol_object): Remove typedef.
(set_symbol): Update.
* python/py-event.h (event_object): Remove typedef.
* python/py-param.c (parmpy_object): Remove typedef.
* python/py-instruction.c (struct py_insn_obj): Remove typedef.
* python/py-unwind.c (struct pending_frame_object): Remove typedef.
(unwind_info_object, struct cached_frame_info): Likewise.
2020-12-04 13:09:43 -07:00
|
|
|
|
};
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
gdb/python: add type traits check for all PyObject sub-classes
All of our custom Python types are created as structs, like this:
struct some_new_type : public PyObject
{
... various fields ...
};
Then instances of this struct are created by calling PyObject_New,
either directly within GDB's C++ code, or within Python when a user's
Python script creates an instance of that class.
The problem is that Python is written in C, and PyObject_New doesn't
call any constructors for `some_new_type`, nor for any of the fields
within `some_new_type`.
If `some_new_type` is Plain Old Data (POD), then this is fine. Or, to
be more C++ specific, if `some_new_type` is trivially default
constructable, then we're fine.
But if a field within `some_new_type` has a non-trivial constructor,
then we're in trouble as that constructor will never be run.
An example of a problematic field type is frame_info_ptr. The
constructor for this type registers the new object with a central
management object, recording the `this` pointer, using this type within
`some_new_type` will not work as expected; frame invalidation will not
show up within the frame_info_ptr as you might expect.
And so, this type trait exists. Whenever a struct is created to define
a new Python type we should add a line like:
static_assert (gdb::is_python_allocatable_v<some_new_type>);
This will fail if any field of `some_new_type` are unsuitable for this
use.
We don't actually check is_trivially_default_constructible here. Some
types, e.g. ui_file_style::color, have non-trivial (or no default)
constructors, but are still safe to use within `some_new_type` because
their constructors just initialise data fields; there's nothing
"special" that the constructor does that cannot be achieved by
assigning the fields after creation with PyObject_New.
What actually matters is that the type is trivially destructible
(Python won't call C++ destructors, so destructors with side effects,
like deregistering from a list, would be skipped) and trivially
copyable (Python may copy objects with memcpy). Types like
frame_info_ptr, whose constructors and destructors have side effects
such as registering with a central management object, will be caught
because they are neither trivially destructible nor trivially copyable.
Simple POD types like ui_file_style are trivially destructible and
copyable, so pass this trait.
This commit adds the new type trait, and makes use of it in all cases
but one, pending_frame_object in python/py-unwind.c, has a field of
type frame_info_ptr, which is currently broken. This will be fixed,
and the static_assert added, in the next commit.
Approved-By: Tom Tromey <tom@tromey.com>
2026-05-14 09:39:57 +01:00
|
|
|
|
static_assert (gdb::is_python_allocatable_v<type_object>);
|
|
|
|
|
|
|
2025-10-21 10:00:20 -06:00
|
|
|
|
extern PyTypeObject type_object_type;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
|
|
|
|
|
/* A Field object. */
|
gdb: new setters and getters for __dict__, and attributes
GDB is currently using the Python unlimited API. Migrating the codebase
to the Python limited API would have for benefit to make a GDB build
artifacts compatible with older and newer versions of Python that they
were built with.
This patch prepares the ground for migrating the existing C extension
types from static types to heap-allocated ones, by removing the
dependency on tp_dictoffset, which is unavailable when using the limited
API.
One of the most common incompatibilities in the current static type
declarations is the tp_dictoffset slot, which specifies the dictionary
offset within the instance structure. Historically, the unlimited
API has provided two approaches to supply a dictionary for __dict__:
* A managed dictionary.
Setting Py_TPFLAGS_MANAGED_DICT in tp_flags indicates that the
instances of the type have a __dict__ attribute, and that the
dictionary is managed by Python.
According to the Python documentation, this is the recommended approach.
However, this flag was introduced in 3.12, together with
PyObject_VisitManagedDict() and PyObject_ClearManagedDict(), neither
of which is part of the limited API (at least for now). As a result,
this recommended approach is not viable in the context of the limited
API.
* An instance dictionary, for which the offset in the instance is
provided via tp_dictoffset.
According to the Python documentation, this "tp slot" is on the
deprecation path, and Py_TPFLAGS_MANAGED_DICT should be used instead.
Given the age of the GDB codebase and the requirement to support older
Python versions (>= 3.4), no need to argue that today, the implementation
of __dict__ relies on tp_dictoffset. However, in the context of the
limited API, PyType_Slot does not provide a Py_tp_dictoffset member, so
another approach is needed to provide __dict__ to instances of C extension
types.
Given the constraints of the limited API, the proposed solution consists
in providing a dictionary through a common base class, gdbpy__dict__wrapper.
This helper class owns a dictionary member corresponding to __dict__, and
any C extension type requiring a __dict__ must inherit from it. Since
extension object must also be convertible to PyObject, this wrapper class
publicly inherits from PyObject as well.
Access to the dictionary is provided via a custom getter defined in a
PyGetSetDef, similarily to what was previously done with gdb_py_generic_dict().
Because __dict__ participates in attribute look-up, and since this dictionary
is neither managed by Python nor exposed via tp_dictoffset, custom
implementations of tp_getattro and tp_setattro are required to correctly
redirect attribute look-ups to the dictionary. These custom implementations
— equivalent to PyObject_GenericGetAttr() and PyObject_GenericSetAttr() —
must be installed via tp_getattro / tp_setattro for static types, or
Py_tp_getattro / Py_tp_setattro for heap-allocated types.
- gdbpy__dict__wrapper: a base class for C extension objects that own a
__dict__.
- gdb_py_generic_dict_getter: a __dict__ getter for extension types
derived from gdbpy__dict__wrapper.
- gdb_py_generic_getattro: equivalent of PyObject_GenericGetAttr, but
fixes the look-up of __dict__.
- gdb_py_generic_setattro: equivalent of PyObject_GenericSetAttr, but
fixes the look-up of __dict__.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23830
Approved-By: Tom Tromey <tom@tromey.com>
2025-07-17 18:36:41 +01:00
|
|
|
|
struct field_object : public gdbpy_dict_wrapper
|
|
|
|
|
|
{};
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
2025-10-21 10:00:20 -06:00
|
|
|
|
extern PyTypeObject field_object_type;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
2011-09-28 20:04:52 +00:00
|
|
|
|
/* A type iterator object. */
|
2026-01-27 12:33:42 +00:00
|
|
|
|
struct typy_iterator_object : public PyObject
|
|
|
|
|
|
{
|
2011-09-28 20:04:52 +00:00
|
|
|
|
/* The current field index. */
|
|
|
|
|
|
int field;
|
|
|
|
|
|
/* What to return. */
|
|
|
|
|
|
enum gdbpy_iter_kind kind;
|
|
|
|
|
|
/* Pointer back to the original source type object. */
|
Remove redundant typedefs
I was inspired by this patch of Simon's:
https://sourceware.org/pipermail/gdb-patches/2020-November/173522.html
... to remove other typedefs that are no longer necessary now that gdb
uses C++.
I didn't remove absolutely every one -- I didn't touch the tdep files.
However, I removed many of them. In some cases, I removed an existing
different struct tag.
2020-12-04 Tom Tromey <tromey@adacore.com>
* linespec.c (struct linespec_token): Rename; remove typedef.
* guile/scm-block.c (struct block_smob): Remove typedef.
(struct block_syms_progress_smob): Likewise.
* guile/scm-symbol.c (struct symbol_smob): Remove typedef.
* guile/scm-symtab.c (symtab_smob): Remove typedef.
(struct sal_smob): Remove typedef.
* guile/scm-param.c (struct param_smob): Remove typedef.
* guile/scm-progspace.c (struct pspace_smob): Rename.
* guile/scm-objfile.c (struct objfile_smob): Rename.
* guile/scm-iterator.c (struct iterator_smob): Rename.
* guile/scm-frame.c (struct frame_smob): Rename.
* guile/scm-arch.c (struct arch_smob): Rename.
* guile/scm-type.c (struct field_smob): Remove typedef.
(struct type_smob): Rename.
* guile/scm-cmd.c (struct command_smob): Remove typedef.
* guile/scm-ports.c (struct ioscm_memory_port): Remove typedef.
* guile/scm-value.c (struct value_smob): Remove typedef.
* guile/scm-lazy-string.c (lazy_string_smob): Remove typedef.
* guile/guile-internal.h (struct scheme_variable)
(struct scheme_function, struct scheme_integer_constant)
(struct gdb_smob, struct chained_gdb_smob)
(struct eqable_gdb_smob, arch_smob, frame_smob, iterator_smob)
(objfile_smob, pspace_smob, type_smob): Remove typedef.
* guile/scm-pretty-print.c (pretty_printer_smob): Remove typedef.
(struct pretty_printer_worker_smob): Remove typedef.
* guile/scm-exception.c (struct exception_smob): Remove typedef.
* python/py-block.c (struct block_object): Remove typedef.
(block_syms_iterator_object): Update.
(set_block): Update.
(block_syms_iterator_object): Remove typedef.
* python/py-inferior.c (struct membuf_object): Remove typedef.
* python/py-symtab.c (struct symtab_object): Remove typedef.
(set_symtab): Update.
(sal_object): Remove typedef.
(set_sal): Update.
* python/py-frame.c (frame_object): Remove typedef.
* python/py-record-btrace.c (struct btpy_list_object): Remove
typedef.
* python/py-arch.c (struct arch_object): Remove typedef.
* python/py-linetable.c (struct linetable_entry_object)
(linetable_object, struct ltpy_iterator_object): Remove typedef.
* python/py-events.h (eventregistry_object): Remove typedef.
(struct events_object): Remove typedef.
* python/python-internal.h (gdbpy_breakpoint_object): Remove
typedef.
(thread_object): Remove typedef.
* python/py-progspace.c (pspace_object): Remove typedef.
* python/py-value.c (struct value_object): Remove typedef.
* python/py-record.h (recpy_record_object): Remove typedef.
(struct recpy_element_object): Remove typedef.
* python/py-lazy-string.c (lazy_string_object): Remove typedef.
* python/py-objfile.c (objfile_object): Remove typedef.
* python/py-cmd.c (struct cmdpy_object): Remove typedef.
* python/py-type.c (type_object): Remove typedef.
(typy_iterator_object): Update.
(set_type): Update.
(field_object): Remove typedef.
(typy_iterator_object): Remove typedef.
* python/py-registers.c (register_descriptor_iterator_object):
Remove typedef.
(struct register_descriptor_object)
(struct reggroup_iterator_object, struct reggroup_object): Remove
typedef.
* python/py-record.c (recpy_gap_object): Remove typedef.
* python/py-symbol.c (symbol_object): Remove typedef.
(set_symbol): Update.
* python/py-event.h (event_object): Remove typedef.
* python/py-param.c (parmpy_object): Remove typedef.
* python/py-instruction.c (struct py_insn_obj): Remove typedef.
* python/py-unwind.c (struct pending_frame_object): Remove typedef.
(unwind_info_object, struct cached_frame_info): Likewise.
2020-12-04 13:09:43 -07:00
|
|
|
|
type_object *source;
|
|
|
|
|
|
};
|
2011-09-28 20:04:52 +00:00
|
|
|
|
|
gdb/python: add type traits check for all PyObject sub-classes
All of our custom Python types are created as structs, like this:
struct some_new_type : public PyObject
{
... various fields ...
};
Then instances of this struct are created by calling PyObject_New,
either directly within GDB's C++ code, or within Python when a user's
Python script creates an instance of that class.
The problem is that Python is written in C, and PyObject_New doesn't
call any constructors for `some_new_type`, nor for any of the fields
within `some_new_type`.
If `some_new_type` is Plain Old Data (POD), then this is fine. Or, to
be more C++ specific, if `some_new_type` is trivially default
constructable, then we're fine.
But if a field within `some_new_type` has a non-trivial constructor,
then we're in trouble as that constructor will never be run.
An example of a problematic field type is frame_info_ptr. The
constructor for this type registers the new object with a central
management object, recording the `this` pointer, using this type within
`some_new_type` will not work as expected; frame invalidation will not
show up within the frame_info_ptr as you might expect.
And so, this type trait exists. Whenever a struct is created to define
a new Python type we should add a line like:
static_assert (gdb::is_python_allocatable_v<some_new_type>);
This will fail if any field of `some_new_type` are unsuitable for this
use.
We don't actually check is_trivially_default_constructible here. Some
types, e.g. ui_file_style::color, have non-trivial (or no default)
constructors, but are still safe to use within `some_new_type` because
their constructors just initialise data fields; there's nothing
"special" that the constructor does that cannot be achieved by
assigning the fields after creation with PyObject_New.
What actually matters is that the type is trivially destructible
(Python won't call C++ destructors, so destructors with side effects,
like deregistering from a list, would be skipped) and trivially
copyable (Python may copy objects with memcpy). Types like
frame_info_ptr, whose constructors and destructors have side effects
such as registering with a central management object, will be caught
because they are neither trivially destructible nor trivially copyable.
Simple POD types like ui_file_style are trivially destructible and
copyable, so pass this trait.
This commit adds the new type trait, and makes use of it in all cases
but one, pending_frame_object in python/py-unwind.c, has a field of
type frame_info_ptr, which is currently broken. This will be fixed,
and the static_assert added, in the next commit.
Approved-By: Tom Tromey <tom@tromey.com>
2026-05-14 09:39:57 +01:00
|
|
|
|
static_assert (gdb::is_python_allocatable_v<typy_iterator_object>);
|
|
|
|
|
|
|
2025-10-21 10:00:20 -06:00
|
|
|
|
extern PyTypeObject type_iterator_object_type;
|
2011-09-28 20:04:52 +00:00
|
|
|
|
|
2009-05-28 00:47:20 +00:00
|
|
|
|
/* This is used to initialize various gdb.TYPE_ constants. */
|
|
|
|
|
|
struct pyty_code
|
|
|
|
|
|
{
|
|
|
|
|
|
/* The code. */
|
2022-10-12 08:40:34 -06:00
|
|
|
|
int code;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
/* The name. */
|
|
|
|
|
|
const char *name;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2011-10-04 16:20:03 +00:00
|
|
|
|
/* Forward declarations. */
|
|
|
|
|
|
static PyObject *typy_make_iter (PyObject *self, enum gdbpy_iter_kind kind);
|
|
|
|
|
|
|
2009-05-28 00:47:20 +00:00
|
|
|
|
static struct pyty_code pyty_codes[] =
|
|
|
|
|
|
{
|
2022-10-12 08:40:34 -06:00
|
|
|
|
/* This is kept for backward compatibility. */
|
|
|
|
|
|
{ -1, "TYPE_CODE_BITSTRING" },
|
|
|
|
|
|
|
|
|
|
|
|
#define OP(X) { X, #X },
|
|
|
|
|
|
#include "type-codes.def"
|
|
|
|
|
|
#undef OP
|
2009-05-28 00:47:20 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
field_dealloc (PyObject *obj)
|
|
|
|
|
|
{
|
|
|
|
|
|
field_object *f = (field_object *) obj;
|
2010-05-17 21:23:25 +00:00
|
|
|
|
|
2009-05-28 00:47:20 +00:00
|
|
|
|
Py_XDECREF (f->dict);
|
2012-12-12 16:47:30 +00:00
|
|
|
|
Py_TYPE (obj)->tp_free (obj);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
field_new (void)
|
|
|
|
|
|
{
|
2017-01-11 16:28:43 -07:00
|
|
|
|
gdbpy_ref<field_object> result (PyObject_New (field_object,
|
|
|
|
|
|
&field_object_type));
|
2010-05-17 21:23:25 +00:00
|
|
|
|
|
2026-02-27 10:30:36 +00:00
|
|
|
|
if (result != nullptr && !result->allocate_dict ())
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
2017-01-11 16:28:43 -07:00
|
|
|
|
return (PyObject *) result.release ();
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-12-12 15:18:27 -08:00
|
|
|
|
/* Return true if OBJ is of type gdb.Field, false otherwise. */
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
gdbpy_is_field (PyObject *obj)
|
|
|
|
|
|
{
|
|
|
|
|
|
return PyObject_TypeCheck (obj, &field_object_type);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2009-05-28 00:47:20 +00:00
|
|
|
|
/* Return the code for this type. */
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_get_code (PyObject *self, void *closure)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct type *type = ((type_object *) self)->type;
|
2010-05-17 21:23:25 +00:00
|
|
|
|
|
2020-09-15 11:08:56 -06:00
|
|
|
|
return gdb_py_object_from_longest (type->code ()).release ();
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Helper function for typy_fields which converts a single field to a
|
2011-09-28 20:04:52 +00:00
|
|
|
|
gdb.Field object. Returns NULL on error. */
|
|
|
|
|
|
|
2018-12-27 12:08:09 -07:00
|
|
|
|
static gdbpy_ref<>
|
2009-05-28 00:47:20 +00:00
|
|
|
|
convert_field (struct type *type, int field)
|
|
|
|
|
|
{
|
Turn gdbpy_ref into a template
This turns gdbpy_ref into a template class, so that it can be used to
wrap subclasses of PyObject. The default argument remains PyObject;
and this necessitated renaming uses of "gdbpy_ref" to "gdbpy_ref<>".
gdb/ChangeLog
2017-02-10 Tom Tromey <tom@tromey.com>
* python/py-ref.h (gdbpy_ref_policy): Now a template.
(gdbpy_ref): Now a template; allow subclasses of PyObject to be
used.
* python/py-arch.c, python/py-bpevent.c, python/py-breakpoint.c,
python/py-cmd.c, python/py-continueevent.c, python/py-event.c,
python/py-exitedevent.c, python/py-finishbreakpoint.c,
python/py-framefilter.c, python/py-function.c,
python/py-inferior.c, python/py-infevents.c,
python/py-linetable.c, python/py-newobjfileevent.c,
python/py-param.c, python/py-prettyprint.c, python/py-ref.h,
python/py-signalevent.c, python/py-stopevent.c,
python/py-symbol.c, python/py-threadevent.c, python/py-type.c,
python/py-unwind.c, python/py-utils.c, python/py-value.c,
python/py-varobj.c, python/py-xmethods.c, python/python.c,
varobj.c: Change gdbpy_ref to gdbpy_ref<>.
2017-02-09 13:16:36 -07:00
|
|
|
|
gdbpy_ref<> result (field_new ());
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
2016-11-06 20:59:51 -07:00
|
|
|
|
if (result == NULL)
|
2009-05-28 00:47:20 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
|
|
2026-02-20 13:05:24 -07:00
|
|
|
|
gdbpy_ref<> arg = type_to_type_object (type);
|
2013-12-12 15:18:27 -08:00
|
|
|
|
if (arg == NULL)
|
2016-11-06 20:59:51 -07:00
|
|
|
|
return NULL;
|
|
|
|
|
|
if (PyObject_SetAttrString (result.get (), "parent_type", arg.get ()) < 0)
|
|
|
|
|
|
return NULL;
|
2013-12-12 15:18:27 -08:00
|
|
|
|
|
2023-04-22 12:41:43 -06:00
|
|
|
|
if (!type->field (field).is_static ())
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2012-04-18 06:46:47 +00:00
|
|
|
|
const char *attrstring;
|
|
|
|
|
|
|
2020-05-14 13:46:38 -04:00
|
|
|
|
if (type->code () == TYPE_CODE_ENUM)
|
2012-04-18 06:46:47 +00:00
|
|
|
|
{
|
2021-09-26 16:38:02 -04:00
|
|
|
|
arg = gdb_py_object_from_longest (type->field (field).loc_enumval ());
|
2012-04-18 06:46:47 +00:00
|
|
|
|
attrstring = "enumval";
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-05-20 10:45:07 -06:00
|
|
|
|
if (type->field (field).loc_is_dwarf_block ())
|
2026-05-15 21:38:12 +02:00
|
|
|
|
arg = py_none ();
|
2020-04-24 13:40:31 -06:00
|
|
|
|
else
|
2021-09-26 16:36:15 -04:00
|
|
|
|
arg = gdb_py_object_from_longest (type->field (field).loc_bitpos ());
|
2012-04-18 06:46:47 +00:00
|
|
|
|
attrstring = "bitpos";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-11-06 20:59:51 -07:00
|
|
|
|
if (arg == NULL)
|
|
|
|
|
|
return NULL;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
Remove Python 2.4 and 2.5 support
This removes all the remainings spots I could find that work around
issues in Python 2.4 and 2.5.
I don't have a good way to test that Python 2.6 still works.
Tested by the buildbot.
gdb/ChangeLog
2019-02-27 Tom Tromey <tromey@adacore.com>
* config.in, configure: Rebuild.
* configure.ac (HAVE_LIBPYTHON2_4, HAVE_LIBPYTHON2_5): Never
define.
* python/py-value.c: Remove Python 2.4 workaround.
* python/py-utils.c (gdb_pymodule_addobject): Remove Python 2.4
workaround.
* python/py-type.c (convert_field, gdbpy_initialize_types): Remove
Python 2.4 workaround.
* python/python-internal.h: Remove Python 2.4 comment.
(Py_ssize_t): Don't define.
(PyVarObject_HEAD_INIT, Py_TYPE): Don't define.
(gdb_Py_DECREF): Remove Python 2.4 workaround.
(gdb_PyObject_GetAttrString, PyObject_GetAttrString): Remove.
(gdb_PyObject_HasAttrString, PyObject_HasAttrString): Remove.
* python/python.c (do_start_initialization): Remove Python 2.4
workaround.
* python/py-prettyprint.c (class dummy_python_frame): Remove.
(print_children): Remove Python 2.4 workaround.
* python/py-inferior.c (buffer_procs): Remove Python 2.4
workaround.
(CHARBUFFERPROC_NAME): Remove.
* python/py-breakpoint.c (gdbpy_initialize_breakpoints): Remove
Python 2.4 workaround.
gdb/testsuite/ChangeLog
2019-02-27 Tom Tromey <tromey@adacore.com>
* lib/gdb.exp (skip_python_tests_prompt): Don't check for Python
2.4.
* gdb.python/py-finish-breakpoint.exp: Remove Python 2.4
workaround.
gdb/ChangeLog
2019-02-27 Tom Tromey <tromey@adacore.com>
* config.in, configure: Rebuild.
* configure.ac (HAVE_LIBPYTHON2_4, HAVE_LIBPYTHON2_5): Never
define.
* python/py-value.c: Remove Python 2.4 workaround.
* python/py-utils.c (gdb_pymodule_addobject): Remove Python 2.4
workaround.
* python/py-type.c (convert_field, gdbpy_initialize_types): Remove
Python 2.4 workaround.
* python/python-internal.h: Remove Python 2.4 comment.
(Py_ssize_t): Don't define.
(PyVarObject_HEAD_INIT, Py_TYPE): Don't define.
(gdb_Py_DECREF): Remove Python 2.4 workaround.
(gdb_PyObject_GetAttrString, PyObject_GetAttrString): Remove.
(gdb_PyObject_HasAttrString, PyObject_HasAttrString): Remove.
* python/python.c (do_start_initialization): Remove Python 2.4
workaround.
* python/py-prettyprint.c (class dummy_python_frame): Remove.
(print_children): Remove Python 2.4 workaround.
* python/py-inferior.c (buffer_procs): Remove Python 2.4
workaround.
(CHARBUFFERPROC_NAME): Remove.
* python/py-breakpoint.c (gdbpy_initialize_breakpoints): Remove
Python 2.4 workaround.
2019-02-26 11:58:47 -07:00
|
|
|
|
if (PyObject_SetAttrString (result.get (), attrstring, arg.get ()) < 0)
|
2016-11-06 20:59:51 -07:00
|
|
|
|
return NULL;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-11-06 20:59:51 -07:00
|
|
|
|
arg.reset (NULL);
|
2021-08-30 11:49:49 -04:00
|
|
|
|
if (type->field (field).name ())
|
2013-12-27 12:20:59 -08:00
|
|
|
|
{
|
2021-08-30 11:49:49 -04:00
|
|
|
|
const char *field_name = type->field (field).name ();
|
2014-01-15 16:28:08 +04:00
|
|
|
|
|
2013-12-27 12:20:59 -08:00
|
|
|
|
if (field_name[0] != '\0')
|
|
|
|
|
|
{
|
2022-03-21 10:07:41 -04:00
|
|
|
|
arg.reset (PyUnicode_FromString (type->field (field).name ()));
|
2013-12-27 12:20:59 -08:00
|
|
|
|
if (arg == NULL)
|
2016-11-06 20:59:51 -07:00
|
|
|
|
return NULL;
|
2013-12-27 12:20:59 -08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (arg == NULL)
|
2026-05-15 21:38:12 +02:00
|
|
|
|
arg = py_none ();
|
2018-12-27 12:08:09 -07:00
|
|
|
|
|
2016-11-06 20:59:51 -07:00
|
|
|
|
if (PyObject_SetAttrString (result.get (), "name", arg.get ()) < 0)
|
|
|
|
|
|
return NULL;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
2023-08-31 11:46:24 -04:00
|
|
|
|
arg.reset (PyBool_FromLong (type->field (field).is_artificial ()));
|
2016-11-06 20:59:51 -07:00
|
|
|
|
if (PyObject_SetAttrString (result.get (), "artificial", arg.get ()) < 0)
|
|
|
|
|
|
return NULL;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
2020-05-14 13:46:38 -04:00
|
|
|
|
if (type->code () == TYPE_CODE_STRUCT)
|
2022-06-07 09:15:24 -06:00
|
|
|
|
arg.reset (PyBool_FromLong (field < TYPE_N_BASECLASSES (type)));
|
2009-12-03 21:19:49 +00:00
|
|
|
|
else
|
2026-05-15 21:38:12 +02:00
|
|
|
|
arg = py_false ();
|
2016-11-06 20:59:51 -07:00
|
|
|
|
if (PyObject_SetAttrString (result.get (), "is_base_class", arg.get ()) < 0)
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
2023-08-31 11:46:27 -04:00
|
|
|
|
arg = gdb_py_object_from_longest (type->field (field).bitsize ());
|
2016-11-06 20:59:51 -07:00
|
|
|
|
if (arg == NULL)
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
if (PyObject_SetAttrString (result.get (), "bitsize", arg.get ()) < 0)
|
|
|
|
|
|
return NULL;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
|
|
|
|
|
/* A field can have a NULL type in some situations. */
|
2020-06-08 15:26:20 -04:00
|
|
|
|
if (type->field (field).type () == NULL)
|
2026-05-15 21:38:12 +02:00
|
|
|
|
arg = py_none ();
|
2009-05-28 00:47:20 +00:00
|
|
|
|
else
|
2026-02-20 13:05:24 -07:00
|
|
|
|
arg = type_to_type_object (type->field (field).type ());
|
2016-11-06 20:59:51 -07:00
|
|
|
|
if (arg == NULL)
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
if (PyObject_SetAttrString (result.get (), "type", arg.get ()) < 0)
|
|
|
|
|
|
return NULL;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
2018-12-27 12:08:09 -07:00
|
|
|
|
return result;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-09-28 20:04:52 +00:00
|
|
|
|
/* 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. */
|
|
|
|
|
|
|
2018-12-27 12:08:09 -07:00
|
|
|
|
static gdbpy_ref<>
|
2011-09-28 20:04:52 +00:00
|
|
|
|
field_name (struct type *type, int field)
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2018-12-27 12:08:09 -07:00
|
|
|
|
gdbpy_ref<> result;
|
2011-09-28 20:04:52 +00:00
|
|
|
|
|
2021-08-30 11:49:49 -04:00
|
|
|
|
if (type->field (field).name ())
|
2022-03-21 10:07:41 -04:00
|
|
|
|
result.reset (PyUnicode_FromString (type->field (field).name ()));
|
2011-09-28 20:04:52 +00:00
|
|
|
|
else
|
2026-05-15 21:38:12 +02:00
|
|
|
|
result = py_none ();
|
2018-12-27 12:08:09 -07:00
|
|
|
|
|
2011-09-28 20:04:52 +00:00
|
|
|
|
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. */
|
|
|
|
|
|
|
2018-12-27 12:08:09 -07:00
|
|
|
|
static gdbpy_ref<>
|
2011-09-28 20:04:52 +00:00
|
|
|
|
make_fielditem (struct type *type, int i, enum gdbpy_iter_kind kind)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (kind)
|
|
|
|
|
|
{
|
|
|
|
|
|
case iter_items:
|
2016-11-06 20:59:51 -07:00
|
|
|
|
{
|
Turn gdbpy_ref into a template
This turns gdbpy_ref into a template class, so that it can be used to
wrap subclasses of PyObject. The default argument remains PyObject;
and this necessitated renaming uses of "gdbpy_ref" to "gdbpy_ref<>".
gdb/ChangeLog
2017-02-10 Tom Tromey <tom@tromey.com>
* python/py-ref.h (gdbpy_ref_policy): Now a template.
(gdbpy_ref): Now a template; allow subclasses of PyObject to be
used.
* python/py-arch.c, python/py-bpevent.c, python/py-breakpoint.c,
python/py-cmd.c, python/py-continueevent.c, python/py-event.c,
python/py-exitedevent.c, python/py-finishbreakpoint.c,
python/py-framefilter.c, python/py-function.c,
python/py-inferior.c, python/py-infevents.c,
python/py-linetable.c, python/py-newobjfileevent.c,
python/py-param.c, python/py-prettyprint.c, python/py-ref.h,
python/py-signalevent.c, python/py-stopevent.c,
python/py-symbol.c, python/py-threadevent.c, python/py-type.c,
python/py-unwind.c, python/py-utils.c, python/py-value.c,
python/py-varobj.c, python/py-xmethods.c, python/python.c,
varobj.c: Change gdbpy_ref to gdbpy_ref<>.
2017-02-09 13:16:36 -07:00
|
|
|
|
gdbpy_ref<> key (field_name (type, i));
|
2016-11-06 20:59:51 -07:00
|
|
|
|
if (key == NULL)
|
|
|
|
|
|
return NULL;
|
2018-12-27 12:08:09 -07:00
|
|
|
|
gdbpy_ref<> value = convert_field (type, i);
|
2016-11-06 20:59:51 -07:00
|
|
|
|
if (value == NULL)
|
|
|
|
|
|
return NULL;
|
Turn gdbpy_ref into a template
This turns gdbpy_ref into a template class, so that it can be used to
wrap subclasses of PyObject. The default argument remains PyObject;
and this necessitated renaming uses of "gdbpy_ref" to "gdbpy_ref<>".
gdb/ChangeLog
2017-02-10 Tom Tromey <tom@tromey.com>
* python/py-ref.h (gdbpy_ref_policy): Now a template.
(gdbpy_ref): Now a template; allow subclasses of PyObject to be
used.
* python/py-arch.c, python/py-bpevent.c, python/py-breakpoint.c,
python/py-cmd.c, python/py-continueevent.c, python/py-event.c,
python/py-exitedevent.c, python/py-finishbreakpoint.c,
python/py-framefilter.c, python/py-function.c,
python/py-inferior.c, python/py-infevents.c,
python/py-linetable.c, python/py-newobjfileevent.c,
python/py-param.c, python/py-prettyprint.c, python/py-ref.h,
python/py-signalevent.c, python/py-stopevent.c,
python/py-symbol.c, python/py-threadevent.c, python/py-type.c,
python/py-unwind.c, python/py-utils.c, python/py-value.c,
python/py-varobj.c, python/py-xmethods.c, python/python.c,
varobj.c: Change gdbpy_ref to gdbpy_ref<>.
2017-02-09 13:16:36 -07:00
|
|
|
|
gdbpy_ref<> item (PyTuple_New (2));
|
2016-11-06 20:59:51 -07:00
|
|
|
|
if (item == NULL)
|
|
|
|
|
|
return NULL;
|
2026-01-28 14:34:20 +00:00
|
|
|
|
if (PyTuple_SetItem (item.get (), 0, key.release ()) < 0
|
|
|
|
|
|
|| PyTuple_SetItem (item.get (), 1, value.release ()) < 0)
|
|
|
|
|
|
return nullptr;
|
2018-12-27 12:08:09 -07:00
|
|
|
|
return item;
|
2016-11-06 20:59:51 -07:00
|
|
|
|
}
|
2011-09-28 20:04:52 +00:00
|
|
|
|
case iter_keys:
|
2016-11-06 20:59:51 -07:00
|
|
|
|
return field_name (type, i);
|
2011-09-28 20:04:52 +00:00
|
|
|
|
case iter_values:
|
2016-11-06 20:59:51 -07:00
|
|
|
|
return convert_field (type, i);
|
2011-09-28 20:04:52 +00:00
|
|
|
|
}
|
2016-11-06 20:59:51 -07:00
|
|
|
|
gdb_assert_not_reached ("invalid gdbpy_iter_kind");
|
2011-09-28 20:04:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
|
{
|
2011-11-10 19:15:10 +00:00
|
|
|
|
PyObject *py_type = self;
|
|
|
|
|
|
struct type *type = ((type_object *) py_type)->type;
|
|
|
|
|
|
struct type *checked_type = type;
|
|
|
|
|
|
|
2019-04-03 16:02:42 -06:00
|
|
|
|
try
|
2011-11-10 19:15:10 +00:00
|
|
|
|
{
|
2015-07-06 16:05:06 -04:00
|
|
|
|
checked_type = check_typedef (checked_type);
|
2011-11-10 19:15:10 +00:00
|
|
|
|
}
|
2019-04-03 15:59:07 -06:00
|
|
|
|
catch (const gdb_exception &except)
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
}
|
2011-11-10 19:15:10 +00:00
|
|
|
|
|
2018-12-27 11:53:20 -07:00
|
|
|
|
gdbpy_ref<> type_holder;
|
2011-11-10 19:15:10 +00:00
|
|
|
|
if (checked_type != type)
|
|
|
|
|
|
{
|
2026-02-20 13:05:24 -07:00
|
|
|
|
type_holder = type_to_type_object (checked_type);
|
2018-12-27 11:53:20 -07:00
|
|
|
|
if (type_holder == nullptr)
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
py_type = type_holder.get ();
|
2011-11-10 19:15:10 +00:00
|
|
|
|
}
|
2018-12-27 11:53:20 -07:00
|
|
|
|
gdbpy_ref<> iter (typy_make_iter (py_type, kind));
|
|
|
|
|
|
if (iter == nullptr)
|
|
|
|
|
|
return nullptr;
|
2011-11-10 19:15:10 +00:00
|
|
|
|
|
2018-12-27 11:53:20 -07:00
|
|
|
|
return PySequence_List (iter.get ());
|
2011-09-28 20:04:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Return a sequence of all fields. Each field is a gdb.Field object. */
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
2011-11-15 21:17:04 +00:00
|
|
|
|
typy_values (PyObject *self, PyObject *args)
|
2011-09-28 20:04:52 +00:00
|
|
|
|
{
|
|
|
|
|
|
return typy_fields_items (self, iter_values);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-11-15 21:17:04 +00:00
|
|
|
|
/* Return a sequence of all fields. Each field is a gdb.Field object.
|
2013-11-29 12:00:47 -08:00
|
|
|
|
This method is similar to typy_values, except where the supplied
|
2011-11-15 21:17:04 +00:00
|
|
|
|
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;
|
2013-11-29 12:00:47 -08:00
|
|
|
|
|
2020-05-14 13:46:38 -04:00
|
|
|
|
if (type->code () != TYPE_CODE_ARRAY)
|
2011-11-15 21:17:04 +00:00
|
|
|
|
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. */
|
2018-12-27 12:08:09 -07:00
|
|
|
|
gdbpy_ref<> r = convert_field (type, 0);
|
2011-11-15 21:17:04 +00:00
|
|
|
|
if (r == NULL)
|
|
|
|
|
|
return NULL;
|
2013-11-29 12:00:47 -08:00
|
|
|
|
|
2016-11-06 20:59:51 -07:00
|
|
|
|
return Py_BuildValue ("[O]", r.get ());
|
2011-11-15 21:17:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-09-28 20:04:52 +00:00
|
|
|
|
/* 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);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-11-29 12:00:47 -08:00
|
|
|
|
/* Return a sequence of all (name, fields) pairs. Each field is a
|
2011-09-28 20:04:52 +00:00
|
|
|
|
gdb.Field object. */
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_items (PyObject *self, PyObject *args)
|
|
|
|
|
|
{
|
|
|
|
|
|
return typy_fields_items (self, iter_items);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-12-23 07:18:51 +04:00
|
|
|
|
/* Return the type's name, or None. */
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_get_name (PyObject *self, void *closure)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct type *type = ((type_object *) self)->type;
|
|
|
|
|
|
|
2020-05-16 12:16:06 -04:00
|
|
|
|
if (type->name () == NULL)
|
2026-05-15 21:38:12 +02:00
|
|
|
|
return py_none ().release ();
|
2021-06-25 08:01:15 -06:00
|
|
|
|
/* Ada type names are encoded, but it is better for users to see the
|
|
|
|
|
|
decoded form. */
|
|
|
|
|
|
if (ADA_TYPE_P (type))
|
|
|
|
|
|
{
|
|
|
|
|
|
std::string name = ada_decode (type->name (), false);
|
|
|
|
|
|
if (!name.empty ())
|
2022-03-21 10:07:41 -04:00
|
|
|
|
return PyUnicode_FromString (name.c_str ());
|
2021-06-25 08:01:15 -06:00
|
|
|
|
}
|
2022-03-21 10:07:41 -04:00
|
|
|
|
return PyUnicode_FromString (type->name ());
|
2013-12-23 07:18:51 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
2009-05-28 00:47:20 +00:00
|
|
|
|
/* Return the type's tag, or None. */
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_get_tag (PyObject *self, void *closure)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct type *type = ((type_object *) self)->type;
|
Remove TYPE_TAG_NAME
TYPE_TAG_NAME has been an occasional source of confusion and bugs. It
seems to me that it is only useful for C and C++ -- but even there,
not so much, because at least with DWARF there doesn't seem to be any
way to wind up with a type where the name and the tag name are both
non-NULL and different.
So, this patch removes TYPE_TAG_NAME entirely. This should save a
little memory, but more importantly, it simplifies this part of gdb.
A few minor test suite adjustments were needed. In some situations
the new code does not yield identical output to the old code.
gdb/ChangeLog
2018-06-01 Tom Tromey <tom@tromey.com>
* valops.c (enum_constant_from_type, value_namespace_elt)
(value_maybe_namespace_elt): Update.
* valarith.c (find_size_for_pointer_math): Update.
* target-descriptions.c (make_gdb_type): Update.
* symmisc.c (print_symbol): Update.
* stabsread.c (define_symbol, read_type)
(complain_about_struct_wipeout, add_undefined_type)
(cleanup_undefined_types_1): Update.
* rust-lang.c (rust_tuple_type_p, rust_slice_type_p)
(rust_range_type_p, val_print_struct, rust_print_struct_def)
(rust_internal_print_type, rust_composite_type)
(rust_evaluate_funcall, rust_evaluate_subexp)
(rust_inclusive_range_type_p): Update.
* python/py-type.c (typy_get_tag): Update.
* p-typeprint.c (pascal_type_print_base): Update.
* mdebugread.c (parse_symbol, parse_type): Update.
* m2-typeprint.c (m2_long_set, m2_record_fields, m2_enum):
Update.
* guile/scm-type.c (gdbscm_type_tag): Update.
* go-lang.c (sixg_string_p): Update.
* gnu-v3-abi.c (build_gdb_vtable_type, build_std_type_info_type):
Update.
* gdbtypes.h (struct main_type) <tag_name>: Remove.
(TYPE_TAG_NAME): Remove.
* gdbtypes.c (type_name_no_tag): Simplify.
(check_typedef, check_types_equal, recursive_dump_type)
(copy_type_recursive, arch_composite_type): Update.
* f-typeprint.c (f_type_print_base): Update. Print "Type" prefix
in summary mode when needed.
* eval.c (evaluate_funcall): Update.
* dwarf2read.c (fixup_go_packaging, read_structure_type)
(process_structure_scope, read_enumeration_type)
(read_namespace_type, read_module_type, determine_prefix): Update.
* cp-support.c (inspect_type): Update.
* coffread.c (process_coff_symbol, decode_base_type): Update.
* c-varobj.c (c_is_path_expr_parent): Update.
* c-typeprint.c (c_type_print_base_struct_union): Update.
(c_type_print_base_1): Update. Print struct/class/union/enum in
summary when using C language.
* ax-gdb.c (gen_struct_ref, gen_namespace_elt)
(gen_maybe_namespace_elt): Update.
* ada-lang.c (ada_type_name): Simplify.
(empty_record, ada_template_to_fixed_record_type_1)
(template_to_static_fixed_type)
(to_record_with_fixed_variant_part, ada_check_typedef): Update.
gdb/testsuite/ChangeLog
2018-06-01 Tom Tromey <tom@tromey.com>
* gdb.xml/tdesc-regs.exp (load_description): Update expected
results.
* gdb.dwarf2/method-ptr.exp: Set language to C++.
* gdb.dwarf2/member-ptr-forwardref.exp: Set language to C++.
* gdb.cp/typeid.exp (do_typeid_tests): Update type_re.
* gdb.base/maint.exp (maint_pass_if): Update.
2018-04-17 13:51:24 -06:00
|
|
|
|
const char *tagname = nullptr;
|
2010-05-17 21:23:25 +00:00
|
|
|
|
|
2020-05-14 13:46:38 -04:00
|
|
|
|
if (type->code () == TYPE_CODE_STRUCT
|
|
|
|
|
|
|| type->code () == TYPE_CODE_UNION
|
|
|
|
|
|
|| type->code () == TYPE_CODE_ENUM)
|
2020-05-16 12:16:06 -04:00
|
|
|
|
tagname = type->name ();
|
Remove TYPE_TAG_NAME
TYPE_TAG_NAME has been an occasional source of confusion and bugs. It
seems to me that it is only useful for C and C++ -- but even there,
not so much, because at least with DWARF there doesn't seem to be any
way to wind up with a type where the name and the tag name are both
non-NULL and different.
So, this patch removes TYPE_TAG_NAME entirely. This should save a
little memory, but more importantly, it simplifies this part of gdb.
A few minor test suite adjustments were needed. In some situations
the new code does not yield identical output to the old code.
gdb/ChangeLog
2018-06-01 Tom Tromey <tom@tromey.com>
* valops.c (enum_constant_from_type, value_namespace_elt)
(value_maybe_namespace_elt): Update.
* valarith.c (find_size_for_pointer_math): Update.
* target-descriptions.c (make_gdb_type): Update.
* symmisc.c (print_symbol): Update.
* stabsread.c (define_symbol, read_type)
(complain_about_struct_wipeout, add_undefined_type)
(cleanup_undefined_types_1): Update.
* rust-lang.c (rust_tuple_type_p, rust_slice_type_p)
(rust_range_type_p, val_print_struct, rust_print_struct_def)
(rust_internal_print_type, rust_composite_type)
(rust_evaluate_funcall, rust_evaluate_subexp)
(rust_inclusive_range_type_p): Update.
* python/py-type.c (typy_get_tag): Update.
* p-typeprint.c (pascal_type_print_base): Update.
* mdebugread.c (parse_symbol, parse_type): Update.
* m2-typeprint.c (m2_long_set, m2_record_fields, m2_enum):
Update.
* guile/scm-type.c (gdbscm_type_tag): Update.
* go-lang.c (sixg_string_p): Update.
* gnu-v3-abi.c (build_gdb_vtable_type, build_std_type_info_type):
Update.
* gdbtypes.h (struct main_type) <tag_name>: Remove.
(TYPE_TAG_NAME): Remove.
* gdbtypes.c (type_name_no_tag): Simplify.
(check_typedef, check_types_equal, recursive_dump_type)
(copy_type_recursive, arch_composite_type): Update.
* f-typeprint.c (f_type_print_base): Update. Print "Type" prefix
in summary mode when needed.
* eval.c (evaluate_funcall): Update.
* dwarf2read.c (fixup_go_packaging, read_structure_type)
(process_structure_scope, read_enumeration_type)
(read_namespace_type, read_module_type, determine_prefix): Update.
* cp-support.c (inspect_type): Update.
* coffread.c (process_coff_symbol, decode_base_type): Update.
* c-varobj.c (c_is_path_expr_parent): Update.
* c-typeprint.c (c_type_print_base_struct_union): Update.
(c_type_print_base_1): Update. Print struct/class/union/enum in
summary when using C language.
* ax-gdb.c (gen_struct_ref, gen_namespace_elt)
(gen_maybe_namespace_elt): Update.
* ada-lang.c (ada_type_name): Simplify.
(empty_record, ada_template_to_fixed_record_type_1)
(template_to_static_fixed_type)
(to_record_with_fixed_variant_part, ada_check_typedef): Update.
gdb/testsuite/ChangeLog
2018-06-01 Tom Tromey <tom@tromey.com>
* gdb.xml/tdesc-regs.exp (load_description): Update expected
results.
* gdb.dwarf2/method-ptr.exp: Set language to C++.
* gdb.dwarf2/member-ptr-forwardref.exp: Set language to C++.
* gdb.cp/typeid.exp (do_typeid_tests): Update type_re.
* gdb.base/maint.exp (maint_pass_if): Update.
2018-04-17 13:51:24 -06:00
|
|
|
|
|
|
|
|
|
|
if (tagname == nullptr)
|
2026-05-15 21:38:12 +02:00
|
|
|
|
return py_none ().release ();
|
2022-03-21 10:07:41 -04:00
|
|
|
|
return PyUnicode_FromString (tagname);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-05-23 16:37:29 -05:00
|
|
|
|
/* Return the type's objfile, or None. */
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_get_objfile (PyObject *self, void *closure)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct type *type = ((type_object *) self)->type;
|
2021-01-28 10:09:02 -05:00
|
|
|
|
struct objfile *objfile = type->objfile_owner ();
|
2019-05-23 16:37:29 -05:00
|
|
|
|
|
|
|
|
|
|
if (objfile == nullptr)
|
2026-05-15 21:38:12 +02:00
|
|
|
|
return py_none ().release ();
|
2019-05-23 16:37:29 -05:00
|
|
|
|
return objfile_to_objfile_object (objfile).release ();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-02-25 10:54:04 +00:00
|
|
|
|
/* Return true if this is a scalar type, otherwise, returns false. */
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_is_scalar (PyObject *self, void *closure)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct type *type = ((type_object *) self)->type;
|
|
|
|
|
|
|
|
|
|
|
|
if (is_scalar_type (type))
|
2026-05-15 21:38:12 +02:00
|
|
|
|
return py_true ().release ();
|
2022-02-25 10:54:04 +00:00
|
|
|
|
else
|
2026-05-15 21:38:12 +02:00
|
|
|
|
return py_false ().release ();
|
2022-02-25 10:54:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-11-30 14:35:44 +00:00
|
|
|
|
/* Return true if this type is signed. Raises a ValueError if this type
|
|
|
|
|
|
is not a scalar type. */
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_is_signed (PyObject *self, void *closure)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct type *type = ((type_object *) self)->type;
|
|
|
|
|
|
|
|
|
|
|
|
if (!is_scalar_type (type))
|
|
|
|
|
|
{
|
|
|
|
|
|
PyErr_SetString (PyExc_ValueError,
|
|
|
|
|
|
_("Type must be a scalar type"));
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (type->is_unsigned ())
|
2026-05-15 21:38:12 +02:00
|
|
|
|
return py_false ().release ();
|
2021-11-30 14:35:44 +00:00
|
|
|
|
else
|
2026-05-15 21:38:12 +02:00
|
|
|
|
return py_true ().release ();
|
2021-11-30 14:35:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-07-24 07:29:46 -06:00
|
|
|
|
/* Return true if this type is array-like. */
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_is_array_like (PyObject *self, void *closure)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct type *type = ((type_object *) self)->type;
|
2023-09-05 12:29:23 -06:00
|
|
|
|
bool result = false;
|
2023-07-24 07:29:46 -06:00
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
type = check_typedef (type);
|
2023-09-05 12:29:23 -06:00
|
|
|
|
result = type->is_array_like ();
|
2023-07-24 07:29:46 -06:00
|
|
|
|
}
|
|
|
|
|
|
catch (const gdb_exception &except)
|
|
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
2023-07-24 07:29:46 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-09-05 12:29:23 -06:00
|
|
|
|
if (result)
|
2026-05-15 21:38:12 +02:00
|
|
|
|
return py_true ().release ();
|
2023-07-24 07:29:46 -06:00
|
|
|
|
else
|
2026-05-15 21:38:12 +02:00
|
|
|
|
return py_false ().release ();
|
2023-07-24 07:29:46 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Return true if this type is string-like. */
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_is_string_like (PyObject *self, void *closure)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct type *type = ((type_object *) self)->type;
|
|
|
|
|
|
bool result = false;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
type = check_typedef (type);
|
2023-09-05 12:29:23 -06:00
|
|
|
|
result = type->is_string_like ();
|
2023-07-24 07:29:46 -06:00
|
|
|
|
}
|
|
|
|
|
|
catch (const gdb_exception &except)
|
|
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
2023-07-24 07:29:46 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (result)
|
2026-05-15 21:38:12 +02:00
|
|
|
|
return py_true ().release ();
|
2023-07-24 07:29:46 -06:00
|
|
|
|
else
|
2026-05-15 21:38:12 +02:00
|
|
|
|
return py_false ().release ();
|
2023-07-24 07:29:46 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
2009-05-28 00:47:20 +00:00
|
|
|
|
/* Return the type, stripped of typedefs. */
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_strip_typedefs (PyObject *self, PyObject *args)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct type *type = ((type_object *) self)->type;
|
2011-11-28 15:49:43 +00:00
|
|
|
|
|
2019-04-03 16:02:42 -06:00
|
|
|
|
try
|
2011-11-28 15:49:43 +00:00
|
|
|
|
{
|
|
|
|
|
|
type = check_typedef (type);
|
|
|
|
|
|
}
|
2019-04-03 15:59:07 -06:00
|
|
|
|
catch (const gdb_exception &except)
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
}
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
2026-02-20 13:05:24 -07:00
|
|
|
|
return type_to_type_object (type).release ();
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-11-15 21:17:04 +00:00
|
|
|
|
/* 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)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
|
|
{
|
2019-04-03 16:02:42 -06:00
|
|
|
|
try
|
2011-11-15 21:17:04 +00:00
|
|
|
|
{
|
2015-07-06 16:05:06 -04:00
|
|
|
|
type = check_typedef (type);
|
2011-11-15 21:17:04 +00:00
|
|
|
|
}
|
2019-04-03 15:59:07 -06:00
|
|
|
|
catch (const gdb_exception &except)
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
}
|
2011-11-15 21:17:04 +00:00
|
|
|
|
|
2021-09-11 13:58:04 -06:00
|
|
|
|
if (!type->is_pointer_or_reference ())
|
2011-11-15 21:17:04 +00:00
|
|
|
|
break;
|
2022-07-30 22:43:54 -04:00
|
|
|
|
type = type->target_type ();
|
2011-11-15 21:17:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* If this is not a struct, union, or enum type, raise TypeError
|
|
|
|
|
|
exception. */
|
2020-05-14 13:46:38 -04:00
|
|
|
|
if (type->code () != TYPE_CODE_STRUCT
|
|
|
|
|
|
&& type->code () != TYPE_CODE_UNION
|
|
|
|
|
|
&& type->code () != TYPE_CODE_ENUM
|
2020-12-18 16:17:46 +01:00
|
|
|
|
&& type->code () != TYPE_CODE_METHOD
|
2020-05-14 13:46:38 -04:00
|
|
|
|
&& type->code () != TYPE_CODE_FUNC)
|
2011-11-15 21:17:04 +00:00
|
|
|
|
{
|
|
|
|
|
|
PyErr_SetString (PyExc_TypeError,
|
2015-10-21 15:57:22 -04:00
|
|
|
|
"Type is not a structure, union, enum, or function type.");
|
2011-11-15 21:17:04 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
2013-11-29 12:00:47 -08:00
|
|
|
|
|
2011-11-15 21:17:04 +00:00
|
|
|
|
return type;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-08-10 20:26:00 +00:00
|
|
|
|
/* Helper for typy_array and typy_vector. */
|
2010-08-23 20:21:28 +00:00
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
2012-08-10 20:26:00 +00:00
|
|
|
|
typy_array_1 (PyObject *self, PyObject *args, int is_vector)
|
2010-08-23 20:21:28 +00:00
|
|
|
|
{
|
2011-01-26 20:53:45 +00:00
|
|
|
|
long n1, n2;
|
2010-08-23 20:21:28 +00:00
|
|
|
|
PyObject *n2_obj = NULL;
|
|
|
|
|
|
struct type *array = NULL;
|
|
|
|
|
|
struct type *type = ((type_object *) self)->type;
|
|
|
|
|
|
|
2011-01-26 20:53:45 +00:00
|
|
|
|
if (! PyArg_ParseTuple (args, "l|O", &n1, &n2_obj))
|
2010-08-23 20:21:28 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
|
|
if (n2_obj)
|
|
|
|
|
|
{
|
2022-03-21 10:07:41 -04:00
|
|
|
|
if (!PyLong_Check (n2_obj))
|
2010-08-23 20:21:28 +00:00
|
|
|
|
{
|
|
|
|
|
|
PyErr_SetString (PyExc_RuntimeError,
|
|
|
|
|
|
_("Array bound must be an integer"));
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
2011-01-26 20:53:45 +00:00
|
|
|
|
|
|
|
|
|
|
if (! gdb_py_int_as_long (n2_obj, &n2))
|
2010-08-23 20:21:28 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
n2 = n1;
|
|
|
|
|
|
n1 = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-01-07 07:34:29 +04:00
|
|
|
|
if (n2 < n1 - 1) /* Note: An empty array has n2 == n1 - 1. */
|
2010-08-23 20:21:28 +00:00
|
|
|
|
{
|
|
|
|
|
|
PyErr_SetString (PyExc_ValueError,
|
|
|
|
|
|
_("Array length must not be negative"));
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-04-03 16:02:42 -06:00
|
|
|
|
try
|
2010-08-23 20:21:28 +00:00
|
|
|
|
{
|
|
|
|
|
|
array = lookup_array_range_type (type, n1, n2);
|
2012-08-10 20:26:00 +00:00
|
|
|
|
if (is_vector)
|
|
|
|
|
|
make_vector_type (array);
|
2010-08-23 20:21:28 +00:00
|
|
|
|
}
|
2019-04-03 15:59:07 -06:00
|
|
|
|
catch (const gdb_exception &except)
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
}
|
2010-08-23 20:21:28 +00:00
|
|
|
|
|
2026-02-20 13:05:24 -07:00
|
|
|
|
return type_to_type_object (array).release ();
|
2010-08-23 20:21:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-08-10 20:26:00 +00:00
|
|
|
|
/* Return an array type. */
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_array (PyObject *self, PyObject *args)
|
|
|
|
|
|
{
|
|
|
|
|
|
return typy_array_1 (self, args, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Return a vector type. */
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_vector (PyObject *self, PyObject *args)
|
|
|
|
|
|
{
|
|
|
|
|
|
return typy_array_1 (self, args, 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2009-05-28 00:47:20 +00:00
|
|
|
|
/* 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;
|
|
|
|
|
|
|
2019-04-03 16:02:42 -06:00
|
|
|
|
try
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
|
|
|
|
|
type = lookup_pointer_type (type);
|
|
|
|
|
|
}
|
2019-04-03 15:59:07 -06:00
|
|
|
|
catch (const gdb_exception &except)
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
}
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
2026-02-20 13:05:24 -07:00
|
|
|
|
return type_to_type_object (type).release ();
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2009-12-08 14:06:04 +00:00
|
|
|
|
/* 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;
|
2009-12-09 07:49:31 +00:00
|
|
|
|
/* Initialize these to appease GCC warnings. */
|
|
|
|
|
|
LONGEST low = 0, high = 0;
|
2009-12-08 14:06:04 +00:00
|
|
|
|
|
2020-05-14 13:46:38 -04:00
|
|
|
|
if (type->code () != TYPE_CODE_ARRAY
|
|
|
|
|
|
&& type->code () != TYPE_CODE_STRING
|
|
|
|
|
|
&& type->code () != TYPE_CODE_RANGE)
|
2009-12-08 14:06:04 +00:00
|
|
|
|
{
|
|
|
|
|
|
PyErr_SetString (PyExc_RuntimeError,
|
2010-04-14 13:18:55 +00:00
|
|
|
|
_("This type does not have a range."));
|
2009-12-08 14:06:04 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-05-14 13:46:38 -04:00
|
|
|
|
switch (type->code ())
|
2009-12-08 14:06:04 +00:00
|
|
|
|
{
|
|
|
|
|
|
case TYPE_CODE_ARRAY:
|
|
|
|
|
|
case TYPE_CODE_STRING:
|
|
|
|
|
|
case TYPE_CODE_RANGE:
|
2023-04-19 09:40:20 -06:00
|
|
|
|
if (type->bounds ()->low.is_constant ())
|
gdb: fix getting range of flexible array member in Python
As reported in bug 27757, we get an internal error when doing:
$ cat test.c
struct foo {
int len;
int items[];
};
struct foo *p;
int main() {
return 0;
}
$ gcc test.c -g -O0 -o test
$ ./gdb -q -nx --data-directory=data-directory ./test -ex 'python gdb.parse_and_eval("p").type.target()["items"].type.range()'
Reading symbols from ./test...
/home/simark/src/binutils-gdb/gdb/gdbtypes.h:435: internal-error: LONGEST dynamic_prop::const_val() const: Assertion `m_kind == PROP_CONST' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n)
This is because the Python code (typy_range) blindly reads the high
bound of the type of `items` as a constant value. Since it is a
flexible array member, it has no high bound, the property is undefined.
Since commit 8c2e4e0689 ("gdb: add accessors to struct dynamic_prop"),
the getters check that you are not getting a property value of the wrong
kind, so this causes a failed assertion.
Fix it by checking if the property is indeed a constant value before
accessing it as such. Otherwise, use 0. This restores the previous GDB
behavior: because the structure was zero-initialized, this is what was
returned before. But now this behavior is explicit and not accidental.
Add a test, gdb.python/flexible-array-member.exp, that is derived from
gdb.base/flexible-array-member.exp. It tests the same things, but
through the Python API. It also specifically tests getting the range
from the various kinds of flexible array member types (AFAIK it wasn't
possible to do the equivalent through the CLI).
gdb/ChangeLog:
PR gdb/27757
* python/py-type.c (typy_range): Check that bounds are constant
before accessing them as such.
* guile/scm-type.c (gdbscm_type_range): Likewise.
gdb/testsuite/ChangeLog:
PR gdb/27757
* gdb.python/flexible-array-member.c: New test.
* gdb.python/flexible-array-member.exp: New test.
* gdb.guile/scm-type.exp (test_range): Add test for flexible
array member.
* gdb.guile/scm-type.c (struct flex_member): New.
(main): Use it.
Change-Id: Ibef92ee5fd871ecb7c791db2a788f203dff2b841
2021-04-22 15:01:28 -04:00
|
|
|
|
low = type->bounds ()->low.const_val ();
|
|
|
|
|
|
else
|
|
|
|
|
|
low = 0;
|
|
|
|
|
|
|
2023-04-19 09:40:20 -06:00
|
|
|
|
if (type->bounds ()->high.is_constant ())
|
gdb: fix getting range of flexible array member in Python
As reported in bug 27757, we get an internal error when doing:
$ cat test.c
struct foo {
int len;
int items[];
};
struct foo *p;
int main() {
return 0;
}
$ gcc test.c -g -O0 -o test
$ ./gdb -q -nx --data-directory=data-directory ./test -ex 'python gdb.parse_and_eval("p").type.target()["items"].type.range()'
Reading symbols from ./test...
/home/simark/src/binutils-gdb/gdb/gdbtypes.h:435: internal-error: LONGEST dynamic_prop::const_val() const: Assertion `m_kind == PROP_CONST' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n)
This is because the Python code (typy_range) blindly reads the high
bound of the type of `items` as a constant value. Since it is a
flexible array member, it has no high bound, the property is undefined.
Since commit 8c2e4e0689 ("gdb: add accessors to struct dynamic_prop"),
the getters check that you are not getting a property value of the wrong
kind, so this causes a failed assertion.
Fix it by checking if the property is indeed a constant value before
accessing it as such. Otherwise, use 0. This restores the previous GDB
behavior: because the structure was zero-initialized, this is what was
returned before. But now this behavior is explicit and not accidental.
Add a test, gdb.python/flexible-array-member.exp, that is derived from
gdb.base/flexible-array-member.exp. It tests the same things, but
through the Python API. It also specifically tests getting the range
from the various kinds of flexible array member types (AFAIK it wasn't
possible to do the equivalent through the CLI).
gdb/ChangeLog:
PR gdb/27757
* python/py-type.c (typy_range): Check that bounds are constant
before accessing them as such.
* guile/scm-type.c (gdbscm_type_range): Likewise.
gdb/testsuite/ChangeLog:
PR gdb/27757
* gdb.python/flexible-array-member.c: New test.
* gdb.python/flexible-array-member.exp: New test.
* gdb.guile/scm-type.exp (test_range): Add test for flexible
array member.
* gdb.guile/scm-type.c (struct flex_member): New.
(main): Use it.
Change-Id: Ibef92ee5fd871ecb7c791db2a788f203dff2b841
2021-04-22 15:01:28 -04:00
|
|
|
|
high = type->bounds ()->high.const_val ();
|
|
|
|
|
|
else
|
|
|
|
|
|
high = 0;
|
2009-12-08 14:06:04 +00:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-15 11:08:56 -06:00
|
|
|
|
gdbpy_ref<> low_bound = gdb_py_object_from_longest (low);
|
2016-11-06 20:59:51 -07:00
|
|
|
|
if (low_bound == NULL)
|
|
|
|
|
|
return NULL;
|
2009-12-08 14:06:04 +00:00
|
|
|
|
|
2020-09-15 11:08:56 -06:00
|
|
|
|
gdbpy_ref<> high_bound = gdb_py_object_from_longest (high);
|
2016-11-06 20:59:51 -07:00
|
|
|
|
if (high_bound == NULL)
|
|
|
|
|
|
return NULL;
|
2009-12-08 14:06:04 +00:00
|
|
|
|
|
Turn gdbpy_ref into a template
This turns gdbpy_ref into a template class, so that it can be used to
wrap subclasses of PyObject. The default argument remains PyObject;
and this necessitated renaming uses of "gdbpy_ref" to "gdbpy_ref<>".
gdb/ChangeLog
2017-02-10 Tom Tromey <tom@tromey.com>
* python/py-ref.h (gdbpy_ref_policy): Now a template.
(gdbpy_ref): Now a template; allow subclasses of PyObject to be
used.
* python/py-arch.c, python/py-bpevent.c, python/py-breakpoint.c,
python/py-cmd.c, python/py-continueevent.c, python/py-event.c,
python/py-exitedevent.c, python/py-finishbreakpoint.c,
python/py-framefilter.c, python/py-function.c,
python/py-inferior.c, python/py-infevents.c,
python/py-linetable.c, python/py-newobjfileevent.c,
python/py-param.c, python/py-prettyprint.c, python/py-ref.h,
python/py-signalevent.c, python/py-stopevent.c,
python/py-symbol.c, python/py-threadevent.c, python/py-type.c,
python/py-unwind.c, python/py-utils.c, python/py-value.c,
python/py-varobj.c, python/py-xmethods.c, python/python.c,
varobj.c: Change gdbpy_ref to gdbpy_ref<>.
2017-02-09 13:16:36 -07:00
|
|
|
|
gdbpy_ref<> result (PyTuple_New (2));
|
2016-11-06 20:59:51 -07:00
|
|
|
|
if (result == NULL)
|
|
|
|
|
|
return NULL;
|
2013-11-29 12:00:47 -08:00
|
|
|
|
|
2016-11-06 20:59:51 -07:00
|
|
|
|
if (PyTuple_SetItem (result.get (), 0, low_bound.release ()) != 0
|
|
|
|
|
|
|| PyTuple_SetItem (result.get (), 1, high_bound.release ()) != 0)
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
return result.release ();
|
2009-12-08 14:06:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2009-05-28 00:47:20 +00:00
|
|
|
|
/* 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;
|
|
|
|
|
|
|
2019-04-03 16:02:42 -06:00
|
|
|
|
try
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2017-03-20 13:47:39 -07:00
|
|
|
|
type = lookup_lvalue_reference_type (type);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
2019-04-03 15:59:07 -06:00
|
|
|
|
catch (const gdb_exception &except)
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
}
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
2026-02-20 13:05:24 -07:00
|
|
|
|
return type_to_type_object (type).release ();
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
2022-07-30 22:43:54 -04:00
|
|
|
|
if (!type->target_type ())
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2013-11-29 12:00:47 -08:00
|
|
|
|
PyErr_SetString (PyExc_RuntimeError,
|
2010-04-14 13:18:55 +00:00
|
|
|
|
_("Type does not have a target."));
|
2009-05-28 00:47:20 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-20 13:05:24 -07:00
|
|
|
|
return type_to_type_object (type->target_type ()).release ();
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Return a const-qualified type variant. */
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_const (PyObject *self, PyObject *args)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct type *type = ((type_object *) self)->type;
|
|
|
|
|
|
|
2019-04-03 16:02:42 -06:00
|
|
|
|
try
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2025-12-17 10:55:00 -05:00
|
|
|
|
type = make_cv_type (1, TYPE_VOLATILE (type), type);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
2019-04-03 15:59:07 -06:00
|
|
|
|
catch (const gdb_exception &except)
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
}
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
2026-02-20 13:05:24 -07:00
|
|
|
|
return type_to_type_object (type).release ();
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Return a volatile-qualified type variant. */
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_volatile (PyObject *self, PyObject *args)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct type *type = ((type_object *) self)->type;
|
|
|
|
|
|
|
2019-04-03 16:02:42 -06:00
|
|
|
|
try
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2025-12-17 10:55:00 -05:00
|
|
|
|
type = make_cv_type (TYPE_CONST (type), 1, type);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
2019-04-03 15:59:07 -06:00
|
|
|
|
catch (const gdb_exception &except)
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
}
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
2026-02-20 13:05:24 -07:00
|
|
|
|
return type_to_type_object (type).release ();
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Return an unqualified type variant. */
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_unqualified (PyObject *self, PyObject *args)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct type *type = ((type_object *) self)->type;
|
|
|
|
|
|
|
2019-04-03 16:02:42 -06:00
|
|
|
|
try
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2025-12-17 10:55:00 -05:00
|
|
|
|
type = make_cv_type (0, 0, type);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
2019-04-03 15:59:07 -06:00
|
|
|
|
catch (const gdb_exception &except)
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
}
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
2026-02-20 13:05:24 -07:00
|
|
|
|
return type_to_type_object (type).release ();
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
2020-04-24 13:40:31 -06:00
|
|
|
|
bool size_varies = false;
|
2019-04-03 16:02:42 -06:00
|
|
|
|
try
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
|
|
|
|
|
check_typedef (type);
|
2020-04-24 13:40:31 -06:00
|
|
|
|
|
|
|
|
|
|
size_varies = TYPE_HAS_DYNAMIC_LENGTH (type);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
2019-04-03 15:59:07 -06:00
|
|
|
|
catch (const gdb_exception &except)
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2009-05-28 00:47:20 +00:00
|
|
|
|
/* Ignore exceptions. */
|
|
|
|
|
|
|
2020-04-24 13:40:31 -06:00
|
|
|
|
if (size_varies)
|
2026-05-15 21:38:12 +02:00
|
|
|
|
return py_none ().release ();
|
2022-09-21 11:05:21 -04:00
|
|
|
|
return gdb_py_object_from_longest (type->length ()).release ();
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-20 15:43:56 -06:00
|
|
|
|
/* Return the alignment of the type represented by SELF, in bytes. */
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_get_alignof (PyObject *self, void *closure)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct type *type = ((type_object *) self)->type;
|
|
|
|
|
|
|
|
|
|
|
|
ULONGEST align = 0;
|
2019-04-03 16:02:42 -06:00
|
|
|
|
try
|
2018-04-20 15:43:56 -06:00
|
|
|
|
{
|
|
|
|
|
|
align = type_align (type);
|
|
|
|
|
|
}
|
2019-04-03 15:59:07 -06:00
|
|
|
|
catch (const gdb_exception &except)
|
2018-04-20 15:43:56 -06:00
|
|
|
|
{
|
|
|
|
|
|
align = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Ignore exceptions. */
|
|
|
|
|
|
|
2018-10-24 16:33:23 -06:00
|
|
|
|
return gdb_py_object_from_ulongest (align).release ();
|
2018-04-20 15:43:56 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-04-24 13:40:31 -06:00
|
|
|
|
/* Return whether or not the type is dynamic. */
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_get_dynamic (PyObject *self, void *closure)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct type *type = ((type_object *) self)->type;
|
|
|
|
|
|
|
|
|
|
|
|
bool result = false;
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
result = is_dynamic_type (type);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (const gdb_exception &except)
|
|
|
|
|
|
{
|
|
|
|
|
|
/* Ignore exceptions. */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (result)
|
2026-05-15 21:38:12 +02:00
|
|
|
|
return py_true ().release ();
|
|
|
|
|
|
return py_false ().release ();
|
2020-04-24 13:40:31 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
2009-05-28 00:47:20 +00:00
|
|
|
|
static struct type *
|
2011-10-20 12:31:30 +00:00
|
|
|
|
typy_lookup_typename (const char *type_name, const struct block *block)
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
|
|
|
|
|
struct type *type = NULL;
|
2010-05-17 21:23:25 +00:00
|
|
|
|
|
2019-04-03 16:02:42 -06:00
|
|
|
|
try
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2015-03-06 09:42:06 +00:00
|
|
|
|
if (startswith (type_name, "struct "))
|
2025-04-03 22:13:00 -06:00
|
|
|
|
type = lookup_struct (type_name + 7, block);
|
2015-03-06 09:42:06 +00:00
|
|
|
|
else if (startswith (type_name, "union "))
|
2025-04-03 22:13:00 -06:00
|
|
|
|
type = lookup_union (type_name + 6, block);
|
2015-03-06 09:42:06 +00:00
|
|
|
|
else if (startswith (type_name, "enum "))
|
2025-04-03 22:13:00 -06:00
|
|
|
|
type = lookup_enum (type_name + 5, block);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
else
|
Change how Python architecture and language are handled
Currently, gdb's Python layer captures the current architecture and
language when "entering" Python code. This has some undesirable
effects, and so this series changes how this is handled.
First, there is code like this:
gdbpy_enter enter_py (python_gdbarch, python_language);
This is incorrect, because both of these are NULL when not otherwise
assigned. This can cause crashes in some cases -- I've added one to
the test suite. (Note that this crasher is just an example, other
ones along the same lines are possible.)
Second, when the language is captured in this way, it means that
Python code cannot affect the current language for its own purposes.
It's reasonable to want to write code like this:
gdb.execute('set language mumble')
... stuff using the current language
gdb.execute('set language previous-value')
However, this won't actually work, because the language is captured on
entry. I've added a test to show this as well.
This patch changes gdb to try to avoid capturing the current values.
The Python concept of the current gdbarch is only set in those few
cases where a non-default value is computed or needed; and the
language is not captured at all -- instead, in the cases where it's
required, the current language is temporarily changed.
2022-01-04 08:02:24 -07:00
|
|
|
|
type = lookup_typename (current_language,
|
2010-02-26 09:08:10 +00:00
|
|
|
|
type_name, block, 0);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
2019-04-03 15:59:07 -06:00
|
|
|
|
catch (const gdb_exception &except)
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
}
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static struct type *
|
2010-02-26 09:08:10 +00:00
|
|
|
|
typy_lookup_type (struct demangle_component *demangled,
|
2011-10-20 12:31:30 +00:00
|
|
|
|
const struct block *block)
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2011-11-04 11:57:04 +00:00
|
|
|
|
struct type *type, *rtype = NULL;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
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
|
2017-03-20 13:47:46 -07:00
|
|
|
|
|| demangled_type == DEMANGLE_COMPONENT_RVALUE_REFERENCE
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|| demangled_type == DEMANGLE_COMPONENT_CONST
|
|
|
|
|
|
|| demangled_type == DEMANGLE_COMPONENT_VOLATILE)
|
|
|
|
|
|
{
|
2010-02-26 09:08:10 +00:00
|
|
|
|
type = typy_lookup_type (demangled->u.s_binary.left, block);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
if (! type)
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
2019-04-03 16:02:42 -06:00
|
|
|
|
try
|
2011-10-27 09:14:27 +00:00
|
|
|
|
{
|
2011-11-04 11:57:04 +00:00
|
|
|
|
/* 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. */
|
2011-10-27 09:14:27 +00:00
|
|
|
|
switch (demangled_type)
|
|
|
|
|
|
{
|
|
|
|
|
|
case DEMANGLE_COMPONENT_REFERENCE:
|
2017-03-20 13:47:39 -07:00
|
|
|
|
rtype = lookup_lvalue_reference_type (type);
|
2011-11-04 11:57:04 +00:00
|
|
|
|
break;
|
2017-03-20 13:47:46 -07:00
|
|
|
|
case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
|
|
|
|
|
|
rtype = lookup_rvalue_reference_type (type);
|
|
|
|
|
|
break;
|
2011-10-27 09:14:27 +00:00
|
|
|
|
case DEMANGLE_COMPONENT_POINTER:
|
2011-11-04 11:57:04 +00:00
|
|
|
|
rtype = lookup_pointer_type (type);
|
|
|
|
|
|
break;
|
2011-10-27 09:14:27 +00:00
|
|
|
|
case DEMANGLE_COMPONENT_CONST:
|
2025-12-17 10:55:00 -05:00
|
|
|
|
rtype = make_cv_type (1, TYPE_VOLATILE (type), type);
|
2011-11-04 11:57:04 +00:00
|
|
|
|
break;
|
2011-10-27 09:14:27 +00:00
|
|
|
|
case DEMANGLE_COMPONENT_VOLATILE:
|
2025-12-17 10:55:00 -05:00
|
|
|
|
rtype = make_cv_type (TYPE_CONST (type), 1, type);
|
2011-11-04 11:57:04 +00:00
|
|
|
|
break;
|
2011-10-27 09:14:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2019-04-03 15:59:07 -06:00
|
|
|
|
catch (const gdb_exception &except)
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
}
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
2013-11-29 12:00:47 -08:00
|
|
|
|
|
2011-11-04 11:57:04 +00:00
|
|
|
|
/* If we have a type from the switch statement above, just return
|
|
|
|
|
|
that. */
|
|
|
|
|
|
if (rtype)
|
|
|
|
|
|
return rtype;
|
2013-11-29 12:00:47 -08:00
|
|
|
|
|
2011-11-04 11:57:04 +00:00
|
|
|
|
/* We don't have a type, so lookup the type. */
|
2017-08-09 15:04:32 +01:00
|
|
|
|
gdb::unique_xmalloc_ptr<char> type_name = cp_comp_to_string (demangled, 10);
|
|
|
|
|
|
return typy_lookup_typename (type_name.get (), block);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2010-07-28 20:50:17 +00:00
|
|
|
|
/* 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_*. */
|
|
|
|
|
|
|
2009-05-28 00:47:20 +00:00
|
|
|
|
static PyObject *
|
2011-10-20 12:31:30 +00:00
|
|
|
|
typy_legacy_template_argument (struct type *type, const struct block *block,
|
2010-07-28 20:50:17 +00:00
|
|
|
|
int argno)
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2010-07-28 20:50:17 +00:00
|
|
|
|
int i;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
struct demangle_component *demangled;
|
2016-11-28 21:39:47 -07:00
|
|
|
|
std::unique_ptr<demangle_parse_info> info;
|
2018-05-23 21:05:52 -06:00
|
|
|
|
std::string err;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
struct type *argtype;
|
|
|
|
|
|
|
2020-05-16 12:16:06 -04:00
|
|
|
|
if (type->name () == NULL)
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2010-02-26 09:08:10 +00:00
|
|
|
|
PyErr_SetString (PyExc_RuntimeError, _("Null type name."));
|
2009-05-28 00:47:20 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-04-03 16:02:42 -06:00
|
|
|
|
try
|
2011-11-28 15:49:43 +00:00
|
|
|
|
{
|
|
|
|
|
|
/* Note -- this is not thread-safe. */
|
2020-05-16 12:16:06 -04:00
|
|
|
|
info = cp_demangled_name_to_comp (type->name (), &err);
|
2011-11-28 15:49:43 +00:00
|
|
|
|
}
|
2019-04-03 15:59:07 -06:00
|
|
|
|
catch (const gdb_exception &except)
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
}
|
2011-11-28 15:49:43 +00:00
|
|
|
|
|
2011-08-18 16:17:39 +00:00
|
|
|
|
if (! info)
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2018-05-23 21:05:52 -06:00
|
|
|
|
PyErr_SetString (PyExc_RuntimeError, err.c_str ());
|
2009-05-28 00:47:20 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
2011-08-18 16:17:39 +00:00
|
|
|
|
demangled = info->tree;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
|
{
|
2010-02-26 09:08:10 +00:00
|
|
|
|
PyErr_SetString (PyExc_RuntimeError, _("Type is not a template."));
|
2009-05-28 00:47:20 +00:00
|
|
|
|
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)
|
|
|
|
|
|
{
|
2010-02-26 09:08:10 +00:00
|
|
|
|
PyErr_Format (PyExc_RuntimeError, _("No argument %d in template."),
|
2009-05-28 00:47:20 +00:00
|
|
|
|
argno);
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-02-26 09:08:10 +00:00
|
|
|
|
argtype = typy_lookup_type (demangled->u.s_binary.left, block);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
if (! argtype)
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
2026-02-20 13:05:24 -07:00
|
|
|
|
return type_to_type_object (argtype).release ();
|
2010-07-28 20:50:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_template_argument (PyObject *self, PyObject *args)
|
|
|
|
|
|
{
|
|
|
|
|
|
int argno;
|
|
|
|
|
|
struct type *type = ((type_object *) self)->type;
|
2011-10-20 12:31:30 +00:00
|
|
|
|
const struct block *block = NULL;
|
2010-07-28 20:50:17 +00:00
|
|
|
|
PyObject *block_obj = NULL;
|
|
|
|
|
|
struct symbol *sym;
|
|
|
|
|
|
|
|
|
|
|
|
if (! PyArg_ParseTuple (args, "i|O", &argno, &block_obj))
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
2018-09-15 00:29:20 -06:00
|
|
|
|
if (argno < 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
PyErr_SetString (PyExc_RuntimeError,
|
|
|
|
|
|
_("Template argument number must be non-negative"));
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-07-28 20:50:17 +00:00
|
|
|
|
if (block_obj)
|
|
|
|
|
|
{
|
|
|
|
|
|
block = block_object_to_block (block_obj);
|
|
|
|
|
|
if (! block)
|
|
|
|
|
|
{
|
|
|
|
|
|
PyErr_SetString (PyExc_RuntimeError,
|
|
|
|
|
|
_("Second argument must be block."));
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-04-03 16:02:42 -06:00
|
|
|
|
try
|
2010-08-23 20:23:55 +00:00
|
|
|
|
{
|
|
|
|
|
|
type = check_typedef (type);
|
Convert lvalue reference type check to general reference type check
In almost all contexts (except for overload resolution rules and expression
semantics), lvalue and rvalue references are equivalent. That means that in all
but these cases we can replace a TYPE_CODE_REF check to a TYPE_IS_REFERENCE
check and, for switch statements, add a case label for a rvalue reference type
next to a case label for an lvalue reference type. This patch does exactly
that.
gdb/ChangeLog
PR gdb/14441
* aarch64-tdep.c (aarch64_type_align)
(aarch64_extract_return_value, aarch64_store_return_value): Change
lvalue reference type checks to general reference type checks.
* amd64-tdep.c (amd64_classify): Likewise.
* amd64-windows-tdep.c (amd64_windows_passed_by_integer_register):
Likewise.
* arm-tdep.c (arm_type_align, arm_extract_return_value)
(arm_store_return_value): Likewise.
* ax-gdb.c (gen_fetch, gen_cast): Likewise.
* c-typeprint.c (c_print_type): Likewise.
* c-varobj.c (adjust_value_for_child_access, c_value_of_variable)
(cplus_number_of_children, cplus_describe_child): Likewise.
* compile/compile-c-symbols.c (generate_vla_size): Likewise.
* completer.c (expression_completer): Likewise.
* cp-support.c (make_symbol_overload_list_adl_namespace):
Likewise.
* darwin-nat-info.c (info_mach_region_command): Likewise.
* dwarf2loc.c (entry_data_value_coerce_ref)
(value_of_dwarf_reg_entry): Likewise.
* eval.c (ptrmath_type_p, evaluate_subexp_standard)
(evaluate_subexp_for_address, evaluate_subexp_for_sizeof):
Likewise.
* findvar.c (extract_typed_address, store_typed_address):
Likewise.
* gdbtypes.c (rank_one_type): Likewise.
* hppa-tdep.c (hppa64_integral_or_pointer_p): Likewise.
* infcall.c (value_arg_coerce): Likewise.
* language.c (pointer_type): Likewise.
* m32c-tdep.c (m32c_reg_arg_type, m32c_m16c_address_to_pointer):
Likewise.
* m88k-tdep.c (m88k_integral_or_pointer_p): Likewise.
* mn10300-tdep.c (mn10300_type_align): Likewise.
* msp430-tdep.c (msp430_push_dummy_call): Likewise.
* ppc-sysv-tdep.c (do_ppc_sysv_return_value)
(ppc64_sysv_abi_push_param, ppc64_sysv_abi_return_value):
Likewise.
* printcmd.c (print_formatted, x_command): Likewise.
* python/py-type.c (typy_get_composite, typy_template_argument):
Likewise.
* python/py-value.c (valpy_referenced_value)
(valpy_get_dynamic_type, value_has_field): Likewise.
* s390-linux-tdep.c (s390_function_arg_integer): Likewise.
* sparc-tdep.c (sparc_integral_or_pointer_p): Likewise.
* sparc64-tdep.c (sparc64_integral_or_pointer_p): Likewise.
* spu-tdep.c (spu_scalar_value_p): Likewise.
* symtab.c (lookup_symbol_aux): Likewise.
* typeprint.c (whatis_exp, print_type_scalar): Likewise.
* valarith.c (binop_types_user_defined_p, unop_user_defined_p):
Likewise.
* valops.c (value_cast_pointers, value_cast)
(value_reinterpret_cast, value_dynamic_cast, value_addr, typecmp)
(value_struct_elt, value_struct_elt_bitpos)
(value_find_oload_method_list, find_overload_match)
(value_rtti_indirect_type): Likewise.
* valprint.c (val_print_scalar_type_p, generic_val_print):
Likewise.
* value.c (value_actual_type, value_as_address, unpack_long)
(pack_long, pack_unsigned_long, coerce_ref_if_computed)
(coerce_ref): Likewise.
* varobj.c (varobj_get_value_type): Likewise.
2017-03-20 13:47:54 -07:00
|
|
|
|
if (TYPE_IS_REFERENCE (type))
|
2022-07-30 22:43:54 -04:00
|
|
|
|
type = check_typedef (type->target_type ());
|
2010-08-23 20:23:55 +00:00
|
|
|
|
}
|
2019-04-03 15:59:07 -06:00
|
|
|
|
catch (const gdb_exception &except)
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
}
|
2010-07-28 20:50:17 +00:00
|
|
|
|
|
|
|
|
|
|
/* 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);
|
2025-08-14 16:14:06 -04:00
|
|
|
|
if (sym->loc_class () == LOC_TYPEDEF)
|
2026-02-20 13:05:24 -07:00
|
|
|
|
return type_to_type_object (sym->type ()).release ();
|
2025-08-14 16:14:06 -04:00
|
|
|
|
else if (sym->loc_class () == LOC_OPTIMIZED_OUT)
|
2010-07-28 20:50:17 +00:00
|
|
|
|
{
|
|
|
|
|
|
PyErr_Format (PyExc_RuntimeError,
|
|
|
|
|
|
_("Template argument is optimized out"));
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-20 13:02:00 -07:00
|
|
|
|
gdbpy_ref<> result;
|
2019-04-03 16:02:42 -06:00
|
|
|
|
try
|
2010-07-28 20:50:17 +00:00
|
|
|
|
{
|
Fix value chain use-after-free
Hannes filed a bug showing a crash, where a pretty-printer written in
Python could cause a use-after-free. He sent a patch, but I thought a
different approach was needed.
In a much earlier patch (see bug #12533), we changed the Python code
to release new values from the value chain when constructing a
gdb.Value. The rationale for this is that if you write a command that
does a lot of computations in a loop, all the values will be kept live
by the value chain, resulting in gdb using a large amount of memory.
However, suppose a value is passed to Python from some code in gdb
that needs to use the value after the call into Python. In this
scenario, value_to_value_object will still release the value -- and
because gdb code doesn't generally keep strong references to values (a
consequence of the ancient decision to use the value chain to avoid
memory management), this will result in a use-after-free.
This scenario can happen, as it turns out, when a value is passed to
Python for pretty-printing. Now, normally this route boxes the value
via value_to_value_object_no_release, avoiding the problematic release
from the value chain. However, if you then call Value.cast, the
underlying value API might return the same value, when is then
released from the chain.
This patch fixes the problem by changing how value boxing is done.
value_to_value_object no longer removes a value from the chain.
Instead, every spot in gdb that might construct new values uses a
scoped_value_mark to ensure that the requirements of bug #12533 are
met. And, because incoming values aren't ever released from the chain
(the Value.cast one comes earlier on the chain than the
scoped_value_mark), the bug can no longer occur. (Note that many
spots in the Python layer already take this approach, so not many
places needed to be touched.)
In the future I think we should replace the use of raw "value *" with
value_ref_ptr pretty much everywhere. This will ensure lifetime
safety throughout gdb.
The test case in this patch comes from Hannes' original patch. I only
made a trivial ("require") change to it. However, while this fails
for him, I can't make it fail on this machine; nevertheless, he tried
my patch and reported the bug as being fixed.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30044
2023-02-08 13:59:36 -07:00
|
|
|
|
scoped_value_mark free_values;
|
|
|
|
|
|
struct value *val = value_of_variable (sym, block);
|
|
|
|
|
|
result = value_to_value_object (val);
|
2010-07-28 20:50:17 +00:00
|
|
|
|
}
|
2019-04-03 15:59:07 -06:00
|
|
|
|
catch (const gdb_exception &except)
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
}
|
2010-07-28 20:50:17 +00:00
|
|
|
|
|
2026-02-20 13:02:00 -07:00
|
|
|
|
return result.release ();
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-05-18 00:33:57 -03:00
|
|
|
|
/* __repr__ implementation for gdb.Type. */
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_repr (PyObject *self)
|
|
|
|
|
|
{
|
|
|
|
|
|
const auto type = type_object_to_type (self);
|
|
|
|
|
|
if (type == nullptr)
|
2024-01-04 10:07:48 +00:00
|
|
|
|
return gdb_py_invalid_object_repr (self);
|
2023-05-18 00:33:57 -03:00
|
|
|
|
|
|
|
|
|
|
const char *code = pyty_codes[type->code ()].name;
|
|
|
|
|
|
string_file type_name;
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
current_language->print_type (type, "", &type_name, -1, 0,
|
|
|
|
|
|
&type_print_raw_options);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (const gdb_exception &except)
|
|
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
2023-05-18 00:33:57 -03:00
|
|
|
|
}
|
|
|
|
|
|
auto py_typename = PyUnicode_Decode (type_name.c_str (), type_name.size (),
|
|
|
|
|
|
host_charset (), NULL);
|
|
|
|
|
|
|
gdb: add new helpers for retrieving a type's fully qualified name
Py_TYPE (self)->tp_name is the traditional idiomatic way to get a Python
type's fully qualified name. However, in the context of the Python
limited API, PyTypeObject is opaque, so the 'tp_name' attribute is no
longer accessible. Additionally, retrieving the type of a Python object
requires Py_TYPE, which is only available as part of the stable API
starting with Python 3.14.
This patch increases minimal Python limited API version from 3.11 to 3.14.
It also introduces two new helpers to retrieve a type's fully qualified
name: gdb_py_tp_name() and gdbpy_py_obj_tp_name(), which extract the fully
qualified name from a PyTypeObject and a PyObject, respectively. Ifdefery
allows these wrappers to select the appropriate API depending on the Python
version and whether the Python limited API is enabled. For any Python
version less than 3.13, gdb_py_tp_name() fallbacks using __qualname__
instead. However, the result may differ slightly in some cases, e.g. the
module name may be missing.
Finally, this patch adapts the existing code to use these wrappers, and
adjusts some test expectations to use the fully qualified name (or
__qualname__ for versions <= 3.13) where it was not previously used.
Note that the corner case where the module name would be missing does not
appear in the testsuite.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23830
Approved-By: Tom Tromey <tom@tromey.com>
2026-01-28 13:09:51 +00:00
|
|
|
|
return PyUnicode_FromFormat ("<%s code=%s name=%U>",
|
2026-05-26 11:46:29 +01:00
|
|
|
|
gdbpy_py_obj_tp_name (self).c_str (),
|
2023-05-18 00:33:57 -03:00
|
|
|
|
code, py_typename);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2009-05-28 00:47:20 +00:00
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_str (PyObject *self)
|
|
|
|
|
|
{
|
Eliminate make_cleanup_ui_file_delete / make ui_file a class hierarchy
This patch starts from the desire to eliminate
make_cleanup_ui_file_delete, but then goes beyond. It makes ui_file &
friends a real C++ class hierarchy, and switches temporary
ui_file-like objects to stack-based allocation.
- mem_fileopen -> string_file
mem_fileopen is replaced with a new string_file class that is treated
as a value class created on the stack. This alone eliminates most
make_cleanup_ui_file_delete calls, and, simplifies code a whole lot
(diffstat shows around 1k loc dropped.)
string_file's internal buffer is a std::string, thus the "string" in
the name. This simplifies the implementation much, compared to
mem_fileopen, which managed growing its internal buffer manually.
- ui_file_as_string, ui_file_strdup, ui_file_obsavestring all gone
The new string_file class has a string() method that provides direct
writable access to the internal std::string buffer. This replaced
ui_file_as_string, which forced a copy of the same data the stream had
inside. With direct access via a writable reference, we can instead
move the string out of the string_stream, avoiding deep string
copying.
Related, ui_file_xstrdup calls are replaced with xstrdup'ping the
stream's string, and ui_file_obsavestring is replaced by
obstack_copy0.
With all those out of the way, getting rid of the weird ui_file_put
mechanism was possible.
- New ui_file::printf, ui_file::puts, etc. methods
These simplify / clarify client code. I considered splitting
client-code changes, like these, e.g.:
- stb = mem_fileopen ();
- fprintf_unfiltered (stb, "%s%s%s",
- _("The valid values are:\n"),
- regdesc,
- _("The default is \"std\"."));
+ string_file stb;
+ stb.printf ("%s%s%s",
+ _("The valid values are:\n"),
+ regdesc,
+ _("The default is \"std\"."));
In two steps, with the first step leaving fprintf_unfiltered (etc.)
calls in place, and only afterwards do a pass to change all those to
call stb.printf etc.. I didn't do that split, because (when I tried),
it turned out to be pointless make-work: the first pass would have to
touch the fprintf_unfiltered line anyway, to replace "stb" with
"&stb".
- gdb_fopen replaced with stack-based objects
This avoids the need for cleanups or unique_ptr's. I.e., this:
struct ui_file *file = gdb_fopen (filename, "w");
if (filename == NULL)
perror_with_name (filename);
cleanups = make_cleanup_ui_file_delete (file);
// use file.
do_cleanups (cleanups);
is replaced with this:
stdio_file file;
if (!file.open (filename, "w"))
perror_with_name (filename);
// use file.
- odd contorsions in null_file_write / null_file_fputs around when to
call to_fputs / to_write eliminated.
- Global null_stream object
A few places that were allocating a ui_file in order to print to
"nowhere" are adjusted to instead refer to a new 'null_stream' global
stream.
- TUI's tui_sfileopen eliminated. TUI's ui_file much simplified
The TUI's ui_file was serving a dual purpose. It supported being used
as string buffer, and supported being backed by a stdio FILE. The
string buffer part is gone, replaced by using of string_file. The
'FILE *' support is now much simplified, by making the TUI's ui_file
inherit from stdio_file.
gdb/ChangeLog:
2017-02-02 Pedro Alves <palves@redhat.com>
* ada-lang.c (type_as_string): Use string_file.
* ada-valprint.c (ada_print_floating): Use string_file.
* ada-varobj.c (ada_varobj_scalar_image)
(ada_varobj_get_value_image): Use string_file.
* aix-thread.c (aix_thread_extra_thread_info): Use string_file.
* arm-tdep.c (_initialize_arm_tdep): Use string_printf.
* breakpoint.c (update_inserted_breakpoint_locations)
(insert_breakpoint_locations, reattach_breakpoints)
(print_breakpoint_location, print_one_detail_ranged_breakpoint)
(print_it_watchpoint): Use string_file.
(save_breakpoints): Use stdio_file.
* c-exp.y (oper): Use string_file.
* cli/cli-logging.c (set_logging_redirect): Use ui_file_up and
tee_file.
(pop_output_files): Use delete.
(handle_redirections): Use stdio_file and tee_file.
* cli/cli-setshow.c (do_show_command): Use string_file.
* compile/compile-c-support.c (c_compute_program): Use
string_file.
* compile/compile-c-symbols.c (generate_vla_size): Take a
'string_file &' instead of a 'ui_file *'.
(generate_c_for_for_one_variable): Take a 'string_file &' instead
of a 'ui_file *'. Use string_file.
(generate_c_for_variable_locations): Take a 'string_file &'
instead of a 'ui_file *'.
* compile/compile-internal.h (generate_c_for_for_one_variable):
Take a 'string_file &' instead of a 'ui_file *'.
* compile/compile-loc2c.c (push, pushf, unary, binary)
(print_label, pushf_register_address, pushf_register)
(do_compile_dwarf_expr_to_c): Take a 'string_file &' instead of a
'ui_file *'. Adjust.
* compile/compile.c (compile_to_object): Use string_file.
* compile/compile.h (compile_dwarf_expr_to_c)
(compile_dwarf_bounds_to_c): Take a 'string_file &' instead of a
'ui_file *'.
* cp-support.c (inspect_type): Use string_file and obstack_copy0.
(replace_typedefs_qualified_name): Use string_file and
obstack_copy0.
* disasm.c (gdb_pretty_print_insn): Use string_file.
(gdb_disassembly): Adjust reference the null_stream global.
(do_ui_file_delete): Delete.
(gdb_insn_length): Use null_stream.
* dummy-frame.c (maintenance_print_dummy_frames): Use stdio_file.
* dwarf2loc.c (dwarf2_compile_property_to_c)
(locexpr_generate_c_location, loclist_generate_c_location): Take a
'string_file &' instead of a 'ui_file *'.
* dwarf2loc.h (dwarf2_compile_property_to_c): Likewise.
* dwarf2read.c (do_ui_file_peek_last): Delete.
(dwarf2_compute_name): Use string_file.
* event-top.c (gdb_setup_readline): Use stdio_file.
* gdbarch.sh (verify_gdbarch): Use string_file.
* gdbtypes.c (safe_parse_type): Use null_stream.
* guile/scm-breakpoint.c (gdbscm_breakpoint_commands): Use
string_file.
* guile/scm-disasm.c (gdbscm_print_insn_from_port): Take a
'string_file *' instead of a 'ui_file *'.
(gdbscm_arch_disassemble): Use string_file.
* guile/scm-frame.c (frscm_print_frame_smob): Use string_file.
* guile/scm-ports.c (class ioscm_file_port): Now a class that
inherits from ui_file.
(ioscm_file_port_delete, ioscm_file_port_rewind)
(ioscm_file_port_put): Delete.
(ioscm_file_port_write): Rename to ...
(ioscm_file_port::write): ... this. Remove file_port_magic
checks.
(ioscm_file_port_new): Delete.
(ioscm_with_output_to_port_worker): Use ioscm_file_port and
ui_file_up.
* guile/scm-type.c (tyscm_type_name): Use string_file.
* guile/scm-value.c (vlscm_print_value_smob, gdbscm_value_print):
Use string_file.
* infcmd.c (print_return_value_1): Use string_file.
* infrun.c (print_target_wait_results): Use string_file.
* language.c (add_language): Use string_file.
* location.c (explicit_to_string_internal): Use string_file.
* main.c (captured_main_1): Use null_file.
* maint.c (maintenance_print_architecture): Use stdio_file.
* mi/mi-cmd-stack.c (list_arg_or_local): Use string_file.
* mi/mi-common.h (struct mi_interp) <out, err, log, targ,
event_channel>: Change type to mi_console_file pointer.
* mi/mi-console.c (mi_console_file_fputs, mi_console_file_flush)
(mi_console_file_delete): Delete.
(struct mi_console_file): Delete.
(mi_console_file_magic): Delete.
(mi_console_file_new): Delete.
(mi_console_file::mi_console_file): New.
(mi_console_file_delete): Delete.
(mi_console_file_fputs): Delete.
(mi_console_file::write): New.
(mi_console_raw_packet): Delete.
(mi_console_file::flush): New.
(mi_console_file_flush): Delete.
(mi_console_set_raw): Rename to ...
(mi_console_file::set_raw): ... this.
* mi/mi-console.h (class mi_console_file): New class.
(mi_console_file_new, mi_console_set_raw): Delete.
* mi/mi-interp.c (mi_interpreter_init): Use mi_console_file.
(mi_set_logging): Use delete and tee_file. Adjust.
* mi/mi-main.c (output_register): Use string_file.
(mi_cmd_data_evaluate_expression): Use string_file.
(mi_cmd_data_read_memory): Use string_file.
(mi_cmd_execute, print_variable_or_computed): Use string_file.
* mi/mi-out.c (mi_ui_out::main_stream): New.
(mi_ui_out::rewind): Use main_stream and
string_file.
(mi_ui_out::put): Use main_stream and string_file.
(mi_ui_out::mi_ui_out): Remove 'stream' parameter.
Allocate a 'string_file' instead.
(mi_out_new): Don't allocate a mem_fileopen stream here.
* mi/mi-out.h (mi_ui_out::mi_ui_out): Remove 'stream' parameter.
(mi_ui_out::main_stream): Declare method.
* printcmd.c (eval_command): Use string_file.
* psymtab.c (maintenance_print_psymbols): Use stdio_file.
* python/py-arch.c (archpy_disassemble): Use string_file.
* python/py-breakpoint.c (bppy_get_commands): Use string_file.
* python/py-frame.c (frapy_str): Use string_file.
* python/py-framefilter.c (py_print_type, py_print_single_arg):
Use string_file.
* python/py-type.c (typy_str): Use string_file.
* python/py-unwind.c (unwind_infopy_str): Use string_file.
* python/py-value.c (valpy_str): Use string_file.
* record-btrace.c (btrace_insn_history): Use string_file.
* regcache.c (regcache_print): Use stdio_file.
* reggroups.c (maintenance_print_reggroups): Use stdio_file.
* remote.c (escape_buffer): Use string_file.
* rust-lang.c (rust_get_disr_info): Use string_file.
* serial.c (serial_open_ops_1): Use stdio_file.
(do_serial_close): Use delete.
* stack.c (print_frame_arg): Use string_file.
(print_frame_args): Remove local mem_fileopen stream, not used.
(print_frame): Use string_file.
* symmisc.c (maintenance_print_symbols): Use stdio_file.
* symtab.h (struct symbol_computed_ops) <generate_c_location>:
Take a 'string_file *' instead of a 'ui_file *'.
* top.c (new_ui): Use stdio_file and stderr_file.
(free_ui): Use delete.
(execute_command_to_string): Use string_file.
(quit_confirm): Use string_file.
* tracepoint.c (collection_list::append_exp): Use string_file.
* tui/tui-disasm.c (tui_disassemble): Use string_file.
* tui/tui-file.c: Don't include "ui-file.h".
(enum streamtype, struct tui_stream): Delete.
(tui_file_new, tui_file_delete, tui_fileopen, tui_sfileopen)
(tui_file_isatty, tui_file_rewind, tui_file_put): Delete.
(tui_file::tui_file): New method.
(tui_file_fputs): Delete.
(tui_file_get_strbuf): Delete.
(tui_file::puts): New method.
(tui_file_adjust_strbuf): Delete.
(tui_file_flush): Delete.
(tui_file::flush): New method.
* tui/tui-file.h: Tweak intro comment.
Include ui-file.h.
(tui_fileopen, tui_sfileopen, tui_file_get_strbuf)
(tui_file_adjust_strbuf): Delete declarations.
(class tui_file): New class.
* tui/tui-io.c (tui_initialize_io): Use tui_file.
* tui/tui-regs.c (tui_restore_gdbout): Use delete.
(tui_register_format): Use string_stream.
* tui/tui-stack.c (tui_make_status_line): Use string_file.
(tui_get_function_from_frame): Use string_file.
* typeprint.c (type_to_string): Use string_file.
* ui-file.c (struct ui_file, ui_file_magic, ui_file_new): Delete.
(null_stream): New global.
(ui_file_delete): Delete.
(ui_file::ui_file): New.
(null_file_isatty): Delete.
(ui_file::~ui_file): New.
(null_file_rewind): Delete.
(ui_file::printf): New.
(null_file_put): Delete.
(null_file_flush): Delete.
(ui_file::putstr): New.
(null_file_write): Delete.
(ui_file::putstrn): New.
(null_file_read): Delete.
(ui_file::putc): New.
(null_file_fputs): Delete.
(null_file_write_async_safe): Delete.
(ui_file::vprintf): New.
(null_file_delete): Delete.
(null_file::write): New.
(null_file_fseek): Delete.
(null_file::puts): New.
(ui_file_data): Delete.
(null_file::write_async_safe): New.
(gdb_flush, ui_file_isatty): Adjust.
(ui_file_put, ui_file_rewind): Delete.
(ui_file_write): Adjust.
(ui_file_write_for_put): Delete.
(ui_file_write_async_safe, ui_file_read): Adjust.
(ui_file_fseek): Delete.
(fputs_unfiltered): Adjust.
(set_ui_file_flush, set_ui_file_isatty, set_ui_file_rewind)
(set_ui_file_put, set_ui_file_write, set_ui_file_write_async_safe)
(set_ui_file_read, set_ui_file_fputs, set_ui_file_fseek)
(set_ui_file_data): Delete.
(string_file::~string_file, string_file::write)
(struct accumulated_ui_file, do_ui_file_xstrdup, ui_file_xstrdup)
(do_ui_file_as_string, ui_file_as_string): Delete.
(do_ui_file_obsavestring, ui_file_obsavestring): Delete.
(struct mem_file): Delete.
(mem_file_new): Delete.
(stdio_file::stdio_file): New.
(mem_file_delete): Delete.
(stdio_file::stdio_file): New.
(mem_fileopen): Delete.
(stdio_file::~stdio_file): New.
(mem_file_rewind): Delete.
(stdio_file::set_stream): New.
(mem_file_put): Delete.
(stdio_file::open): New.
(mem_file_write): Delete.
(stdio_file_magic, struct stdio_file): Delete.
(stdio_file_new, stdio_file_delete, stdio_file_flush): Delete.
(stdio_file::flush): New.
(stdio_file_read): Rename to ...
(stdio_file::read): ... this. Adjust.
(stdio_file_write): Rename to ...
(stdio_file::write): ... this. Adjust.
(stdio_file_write_async_safe): Rename to ...
(stdio_file::write_async_safe) ... this. Adjust.
(stdio_file_fputs): Rename to ...
(stdio_file::puts) ... this. Adjust.
(stdio_file_isatty): Delete.
(stdio_file_fseek): Delete.
(stdio_file::isatty): New.
(stderr_file_write): Rename to ...
(stderr_file::write) ... this. Adjust.
(stderr_file_fputs): Rename to ...
(stderr_file::puts) ... this. Adjust.
(stderr_fileopen, stdio_fileopen, gdb_fopen): Delete.
(stderr_file::stderr_file): New.
(tee_file_magic): Delete.
(struct tee_file): Delete.
(tee_file::tee_file): New.
(tee_file_new): Delete.
(tee_file::~tee_file): New.
(tee_file_delete): Delete.
(tee_file_flush): Rename to ...
(tee_file::flush): ... this. Adjust.
(tee_file_write): Rename to ...
(tee_file::write): ... this. Adjust.
(tee_file::write_async_safe): New.
(tee_file_fputs): Rename to ...
(tee_file::puts): ... this. Adjust.
(tee_file_isatty): Rename to ...
(tee_file::isatty): ... this. Adjust.
* ui-file.h (struct obstack, struct ui_file): Don't
forward-declare.
(ui_file_new, ui_file_flush_ftype, set_ui_file_flush)
(ui_file_write_ftype)
(set_ui_file_write, ui_file_fputs_ftype, set_ui_file_fputs)
(ui_file_write_async_safe_ftype, set_ui_file_write_async_safe)
(ui_file_read_ftype, set_ui_file_read, ui_file_isatty_ftype)
(set_ui_file_isatty, ui_file_rewind_ftype, set_ui_file_rewind)
(ui_file_put_method_ftype, ui_file_put_ftype, set_ui_file_put)
(ui_file_delete_ftype, set_ui_file_data, ui_file_fseek_ftype)
(set_ui_file_fseek): Delete.
(ui_file_data, ui_file_delete, ui_file_rewind)
(struct ui_file): New.
(ui_file_up): New.
(class null_file): New.
(null_stream): Declare.
(ui_file_write_for_put, ui_file_put): Delete.
(ui_file_xstrdup, ui_file_as_string, ui_file_obsavestring):
Delete.
(ui_file_fseek, mem_fileopen, stdio_fileopen, stderr_fileopen)
(gdb_fopen, tee_file_new): Delete.
(struct string_file): New.
(struct stdio_file): New.
(stdio_file_up): New.
(struct stderr_file): New.
(class tee_file): New.
* ui-out.c (ui_out::field_stream): Take a 'string_file &' instead
of a 'ui_file *'. Adjust.
* ui-out.h (class ui_out) <field_stream>: Likewise.
* utils.c (do_ui_file_delete, make_cleanup_ui_file_delete)
(null_stream): Delete.
(error_stream): Take a 'string_file &' instead of a 'ui_file *'.
Adjust.
* utils.h (struct ui_file): Delete forward declaration..
(make_cleanup_ui_file_delete, null_stream): Delete declarations.
(error_stream): Take a 'string_file &' instead of a
'ui_file *'.
* varobj.c (varobj_value_get_print_value): Use string_file.
* xtensa-tdep.c (xtensa_verify_config): Use string_file.
* gdbarch.c: Regenerate.
2017-02-02 11:11:47 +00:00
|
|
|
|
string_file thetype;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
2019-04-03 16:02:42 -06:00
|
|
|
|
try
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2022-01-22 16:31:06 -07:00
|
|
|
|
current_language->print_type (type_object_to_type (self), "",
|
|
|
|
|
|
&thetype, -1, 0,
|
|
|
|
|
|
&type_print_raw_options);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
2019-04-03 15:59:07 -06:00
|
|
|
|
catch (const gdb_exception &except)
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
Eliminate make_cleanup_ui_file_delete / make ui_file a class hierarchy
This patch starts from the desire to eliminate
make_cleanup_ui_file_delete, but then goes beyond. It makes ui_file &
friends a real C++ class hierarchy, and switches temporary
ui_file-like objects to stack-based allocation.
- mem_fileopen -> string_file
mem_fileopen is replaced with a new string_file class that is treated
as a value class created on the stack. This alone eliminates most
make_cleanup_ui_file_delete calls, and, simplifies code a whole lot
(diffstat shows around 1k loc dropped.)
string_file's internal buffer is a std::string, thus the "string" in
the name. This simplifies the implementation much, compared to
mem_fileopen, which managed growing its internal buffer manually.
- ui_file_as_string, ui_file_strdup, ui_file_obsavestring all gone
The new string_file class has a string() method that provides direct
writable access to the internal std::string buffer. This replaced
ui_file_as_string, which forced a copy of the same data the stream had
inside. With direct access via a writable reference, we can instead
move the string out of the string_stream, avoiding deep string
copying.
Related, ui_file_xstrdup calls are replaced with xstrdup'ping the
stream's string, and ui_file_obsavestring is replaced by
obstack_copy0.
With all those out of the way, getting rid of the weird ui_file_put
mechanism was possible.
- New ui_file::printf, ui_file::puts, etc. methods
These simplify / clarify client code. I considered splitting
client-code changes, like these, e.g.:
- stb = mem_fileopen ();
- fprintf_unfiltered (stb, "%s%s%s",
- _("The valid values are:\n"),
- regdesc,
- _("The default is \"std\"."));
+ string_file stb;
+ stb.printf ("%s%s%s",
+ _("The valid values are:\n"),
+ regdesc,
+ _("The default is \"std\"."));
In two steps, with the first step leaving fprintf_unfiltered (etc.)
calls in place, and only afterwards do a pass to change all those to
call stb.printf etc.. I didn't do that split, because (when I tried),
it turned out to be pointless make-work: the first pass would have to
touch the fprintf_unfiltered line anyway, to replace "stb" with
"&stb".
- gdb_fopen replaced with stack-based objects
This avoids the need for cleanups or unique_ptr's. I.e., this:
struct ui_file *file = gdb_fopen (filename, "w");
if (filename == NULL)
perror_with_name (filename);
cleanups = make_cleanup_ui_file_delete (file);
// use file.
do_cleanups (cleanups);
is replaced with this:
stdio_file file;
if (!file.open (filename, "w"))
perror_with_name (filename);
// use file.
- odd contorsions in null_file_write / null_file_fputs around when to
call to_fputs / to_write eliminated.
- Global null_stream object
A few places that were allocating a ui_file in order to print to
"nowhere" are adjusted to instead refer to a new 'null_stream' global
stream.
- TUI's tui_sfileopen eliminated. TUI's ui_file much simplified
The TUI's ui_file was serving a dual purpose. It supported being used
as string buffer, and supported being backed by a stdio FILE. The
string buffer part is gone, replaced by using of string_file. The
'FILE *' support is now much simplified, by making the TUI's ui_file
inherit from stdio_file.
gdb/ChangeLog:
2017-02-02 Pedro Alves <palves@redhat.com>
* ada-lang.c (type_as_string): Use string_file.
* ada-valprint.c (ada_print_floating): Use string_file.
* ada-varobj.c (ada_varobj_scalar_image)
(ada_varobj_get_value_image): Use string_file.
* aix-thread.c (aix_thread_extra_thread_info): Use string_file.
* arm-tdep.c (_initialize_arm_tdep): Use string_printf.
* breakpoint.c (update_inserted_breakpoint_locations)
(insert_breakpoint_locations, reattach_breakpoints)
(print_breakpoint_location, print_one_detail_ranged_breakpoint)
(print_it_watchpoint): Use string_file.
(save_breakpoints): Use stdio_file.
* c-exp.y (oper): Use string_file.
* cli/cli-logging.c (set_logging_redirect): Use ui_file_up and
tee_file.
(pop_output_files): Use delete.
(handle_redirections): Use stdio_file and tee_file.
* cli/cli-setshow.c (do_show_command): Use string_file.
* compile/compile-c-support.c (c_compute_program): Use
string_file.
* compile/compile-c-symbols.c (generate_vla_size): Take a
'string_file &' instead of a 'ui_file *'.
(generate_c_for_for_one_variable): Take a 'string_file &' instead
of a 'ui_file *'. Use string_file.
(generate_c_for_variable_locations): Take a 'string_file &'
instead of a 'ui_file *'.
* compile/compile-internal.h (generate_c_for_for_one_variable):
Take a 'string_file &' instead of a 'ui_file *'.
* compile/compile-loc2c.c (push, pushf, unary, binary)
(print_label, pushf_register_address, pushf_register)
(do_compile_dwarf_expr_to_c): Take a 'string_file &' instead of a
'ui_file *'. Adjust.
* compile/compile.c (compile_to_object): Use string_file.
* compile/compile.h (compile_dwarf_expr_to_c)
(compile_dwarf_bounds_to_c): Take a 'string_file &' instead of a
'ui_file *'.
* cp-support.c (inspect_type): Use string_file and obstack_copy0.
(replace_typedefs_qualified_name): Use string_file and
obstack_copy0.
* disasm.c (gdb_pretty_print_insn): Use string_file.
(gdb_disassembly): Adjust reference the null_stream global.
(do_ui_file_delete): Delete.
(gdb_insn_length): Use null_stream.
* dummy-frame.c (maintenance_print_dummy_frames): Use stdio_file.
* dwarf2loc.c (dwarf2_compile_property_to_c)
(locexpr_generate_c_location, loclist_generate_c_location): Take a
'string_file &' instead of a 'ui_file *'.
* dwarf2loc.h (dwarf2_compile_property_to_c): Likewise.
* dwarf2read.c (do_ui_file_peek_last): Delete.
(dwarf2_compute_name): Use string_file.
* event-top.c (gdb_setup_readline): Use stdio_file.
* gdbarch.sh (verify_gdbarch): Use string_file.
* gdbtypes.c (safe_parse_type): Use null_stream.
* guile/scm-breakpoint.c (gdbscm_breakpoint_commands): Use
string_file.
* guile/scm-disasm.c (gdbscm_print_insn_from_port): Take a
'string_file *' instead of a 'ui_file *'.
(gdbscm_arch_disassemble): Use string_file.
* guile/scm-frame.c (frscm_print_frame_smob): Use string_file.
* guile/scm-ports.c (class ioscm_file_port): Now a class that
inherits from ui_file.
(ioscm_file_port_delete, ioscm_file_port_rewind)
(ioscm_file_port_put): Delete.
(ioscm_file_port_write): Rename to ...
(ioscm_file_port::write): ... this. Remove file_port_magic
checks.
(ioscm_file_port_new): Delete.
(ioscm_with_output_to_port_worker): Use ioscm_file_port and
ui_file_up.
* guile/scm-type.c (tyscm_type_name): Use string_file.
* guile/scm-value.c (vlscm_print_value_smob, gdbscm_value_print):
Use string_file.
* infcmd.c (print_return_value_1): Use string_file.
* infrun.c (print_target_wait_results): Use string_file.
* language.c (add_language): Use string_file.
* location.c (explicit_to_string_internal): Use string_file.
* main.c (captured_main_1): Use null_file.
* maint.c (maintenance_print_architecture): Use stdio_file.
* mi/mi-cmd-stack.c (list_arg_or_local): Use string_file.
* mi/mi-common.h (struct mi_interp) <out, err, log, targ,
event_channel>: Change type to mi_console_file pointer.
* mi/mi-console.c (mi_console_file_fputs, mi_console_file_flush)
(mi_console_file_delete): Delete.
(struct mi_console_file): Delete.
(mi_console_file_magic): Delete.
(mi_console_file_new): Delete.
(mi_console_file::mi_console_file): New.
(mi_console_file_delete): Delete.
(mi_console_file_fputs): Delete.
(mi_console_file::write): New.
(mi_console_raw_packet): Delete.
(mi_console_file::flush): New.
(mi_console_file_flush): Delete.
(mi_console_set_raw): Rename to ...
(mi_console_file::set_raw): ... this.
* mi/mi-console.h (class mi_console_file): New class.
(mi_console_file_new, mi_console_set_raw): Delete.
* mi/mi-interp.c (mi_interpreter_init): Use mi_console_file.
(mi_set_logging): Use delete and tee_file. Adjust.
* mi/mi-main.c (output_register): Use string_file.
(mi_cmd_data_evaluate_expression): Use string_file.
(mi_cmd_data_read_memory): Use string_file.
(mi_cmd_execute, print_variable_or_computed): Use string_file.
* mi/mi-out.c (mi_ui_out::main_stream): New.
(mi_ui_out::rewind): Use main_stream and
string_file.
(mi_ui_out::put): Use main_stream and string_file.
(mi_ui_out::mi_ui_out): Remove 'stream' parameter.
Allocate a 'string_file' instead.
(mi_out_new): Don't allocate a mem_fileopen stream here.
* mi/mi-out.h (mi_ui_out::mi_ui_out): Remove 'stream' parameter.
(mi_ui_out::main_stream): Declare method.
* printcmd.c (eval_command): Use string_file.
* psymtab.c (maintenance_print_psymbols): Use stdio_file.
* python/py-arch.c (archpy_disassemble): Use string_file.
* python/py-breakpoint.c (bppy_get_commands): Use string_file.
* python/py-frame.c (frapy_str): Use string_file.
* python/py-framefilter.c (py_print_type, py_print_single_arg):
Use string_file.
* python/py-type.c (typy_str): Use string_file.
* python/py-unwind.c (unwind_infopy_str): Use string_file.
* python/py-value.c (valpy_str): Use string_file.
* record-btrace.c (btrace_insn_history): Use string_file.
* regcache.c (regcache_print): Use stdio_file.
* reggroups.c (maintenance_print_reggroups): Use stdio_file.
* remote.c (escape_buffer): Use string_file.
* rust-lang.c (rust_get_disr_info): Use string_file.
* serial.c (serial_open_ops_1): Use stdio_file.
(do_serial_close): Use delete.
* stack.c (print_frame_arg): Use string_file.
(print_frame_args): Remove local mem_fileopen stream, not used.
(print_frame): Use string_file.
* symmisc.c (maintenance_print_symbols): Use stdio_file.
* symtab.h (struct symbol_computed_ops) <generate_c_location>:
Take a 'string_file *' instead of a 'ui_file *'.
* top.c (new_ui): Use stdio_file and stderr_file.
(free_ui): Use delete.
(execute_command_to_string): Use string_file.
(quit_confirm): Use string_file.
* tracepoint.c (collection_list::append_exp): Use string_file.
* tui/tui-disasm.c (tui_disassemble): Use string_file.
* tui/tui-file.c: Don't include "ui-file.h".
(enum streamtype, struct tui_stream): Delete.
(tui_file_new, tui_file_delete, tui_fileopen, tui_sfileopen)
(tui_file_isatty, tui_file_rewind, tui_file_put): Delete.
(tui_file::tui_file): New method.
(tui_file_fputs): Delete.
(tui_file_get_strbuf): Delete.
(tui_file::puts): New method.
(tui_file_adjust_strbuf): Delete.
(tui_file_flush): Delete.
(tui_file::flush): New method.
* tui/tui-file.h: Tweak intro comment.
Include ui-file.h.
(tui_fileopen, tui_sfileopen, tui_file_get_strbuf)
(tui_file_adjust_strbuf): Delete declarations.
(class tui_file): New class.
* tui/tui-io.c (tui_initialize_io): Use tui_file.
* tui/tui-regs.c (tui_restore_gdbout): Use delete.
(tui_register_format): Use string_stream.
* tui/tui-stack.c (tui_make_status_line): Use string_file.
(tui_get_function_from_frame): Use string_file.
* typeprint.c (type_to_string): Use string_file.
* ui-file.c (struct ui_file, ui_file_magic, ui_file_new): Delete.
(null_stream): New global.
(ui_file_delete): Delete.
(ui_file::ui_file): New.
(null_file_isatty): Delete.
(ui_file::~ui_file): New.
(null_file_rewind): Delete.
(ui_file::printf): New.
(null_file_put): Delete.
(null_file_flush): Delete.
(ui_file::putstr): New.
(null_file_write): Delete.
(ui_file::putstrn): New.
(null_file_read): Delete.
(ui_file::putc): New.
(null_file_fputs): Delete.
(null_file_write_async_safe): Delete.
(ui_file::vprintf): New.
(null_file_delete): Delete.
(null_file::write): New.
(null_file_fseek): Delete.
(null_file::puts): New.
(ui_file_data): Delete.
(null_file::write_async_safe): New.
(gdb_flush, ui_file_isatty): Adjust.
(ui_file_put, ui_file_rewind): Delete.
(ui_file_write): Adjust.
(ui_file_write_for_put): Delete.
(ui_file_write_async_safe, ui_file_read): Adjust.
(ui_file_fseek): Delete.
(fputs_unfiltered): Adjust.
(set_ui_file_flush, set_ui_file_isatty, set_ui_file_rewind)
(set_ui_file_put, set_ui_file_write, set_ui_file_write_async_safe)
(set_ui_file_read, set_ui_file_fputs, set_ui_file_fseek)
(set_ui_file_data): Delete.
(string_file::~string_file, string_file::write)
(struct accumulated_ui_file, do_ui_file_xstrdup, ui_file_xstrdup)
(do_ui_file_as_string, ui_file_as_string): Delete.
(do_ui_file_obsavestring, ui_file_obsavestring): Delete.
(struct mem_file): Delete.
(mem_file_new): Delete.
(stdio_file::stdio_file): New.
(mem_file_delete): Delete.
(stdio_file::stdio_file): New.
(mem_fileopen): Delete.
(stdio_file::~stdio_file): New.
(mem_file_rewind): Delete.
(stdio_file::set_stream): New.
(mem_file_put): Delete.
(stdio_file::open): New.
(mem_file_write): Delete.
(stdio_file_magic, struct stdio_file): Delete.
(stdio_file_new, stdio_file_delete, stdio_file_flush): Delete.
(stdio_file::flush): New.
(stdio_file_read): Rename to ...
(stdio_file::read): ... this. Adjust.
(stdio_file_write): Rename to ...
(stdio_file::write): ... this. Adjust.
(stdio_file_write_async_safe): Rename to ...
(stdio_file::write_async_safe) ... this. Adjust.
(stdio_file_fputs): Rename to ...
(stdio_file::puts) ... this. Adjust.
(stdio_file_isatty): Delete.
(stdio_file_fseek): Delete.
(stdio_file::isatty): New.
(stderr_file_write): Rename to ...
(stderr_file::write) ... this. Adjust.
(stderr_file_fputs): Rename to ...
(stderr_file::puts) ... this. Adjust.
(stderr_fileopen, stdio_fileopen, gdb_fopen): Delete.
(stderr_file::stderr_file): New.
(tee_file_magic): Delete.
(struct tee_file): Delete.
(tee_file::tee_file): New.
(tee_file_new): Delete.
(tee_file::~tee_file): New.
(tee_file_delete): Delete.
(tee_file_flush): Rename to ...
(tee_file::flush): ... this. Adjust.
(tee_file_write): Rename to ...
(tee_file::write): ... this. Adjust.
(tee_file::write_async_safe): New.
(tee_file_fputs): Rename to ...
(tee_file::puts): ... this. Adjust.
(tee_file_isatty): Rename to ...
(tee_file::isatty): ... this. Adjust.
* ui-file.h (struct obstack, struct ui_file): Don't
forward-declare.
(ui_file_new, ui_file_flush_ftype, set_ui_file_flush)
(ui_file_write_ftype)
(set_ui_file_write, ui_file_fputs_ftype, set_ui_file_fputs)
(ui_file_write_async_safe_ftype, set_ui_file_write_async_safe)
(ui_file_read_ftype, set_ui_file_read, ui_file_isatty_ftype)
(set_ui_file_isatty, ui_file_rewind_ftype, set_ui_file_rewind)
(ui_file_put_method_ftype, ui_file_put_ftype, set_ui_file_put)
(ui_file_delete_ftype, set_ui_file_data, ui_file_fseek_ftype)
(set_ui_file_fseek): Delete.
(ui_file_data, ui_file_delete, ui_file_rewind)
(struct ui_file): New.
(ui_file_up): New.
(class null_file): New.
(null_stream): Declare.
(ui_file_write_for_put, ui_file_put): Delete.
(ui_file_xstrdup, ui_file_as_string, ui_file_obsavestring):
Delete.
(ui_file_fseek, mem_fileopen, stdio_fileopen, stderr_fileopen)
(gdb_fopen, tee_file_new): Delete.
(struct string_file): New.
(struct stdio_file): New.
(stdio_file_up): New.
(struct stderr_file): New.
(class tee_file): New.
* ui-out.c (ui_out::field_stream): Take a 'string_file &' instead
of a 'ui_file *'. Adjust.
* ui-out.h (class ui_out) <field_stream>: Likewise.
* utils.c (do_ui_file_delete, make_cleanup_ui_file_delete)
(null_stream): Delete.
(error_stream): Take a 'string_file &' instead of a 'ui_file *'.
Adjust.
* utils.h (struct ui_file): Delete forward declaration..
(make_cleanup_ui_file_delete, null_stream): Delete declarations.
(error_stream): Take a 'string_file &' instead of a
'ui_file *'.
* varobj.c (varobj_value_get_print_value): Use string_file.
* xtensa-tdep.c (xtensa_verify_config): Use string_file.
* gdbarch.c: Regenerate.
2017-02-02 11:11:47 +00:00
|
|
|
|
return PyUnicode_Decode (thetype.c_str (), thetype.size (),
|
|
|
|
|
|
host_charset (), NULL);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2010-08-23 20:26:10 +00:00
|
|
|
|
/* Implement the richcompare method. */
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_richcompare (PyObject *self, PyObject *other, int op)
|
|
|
|
|
|
{
|
2018-05-29 00:29:23 -06:00
|
|
|
|
bool result = false;
|
2010-08-23 20:26:10 +00:00
|
|
|
|
struct type *type1 = type_object_to_type (self);
|
|
|
|
|
|
struct type *type2 = type_object_to_type (other);
|
|
|
|
|
|
|
|
|
|
|
|
/* We can only compare ourselves to another Type object, and only
|
|
|
|
|
|
for equality or inequality. */
|
|
|
|
|
|
if (type2 == NULL || (op != Py_EQ && op != Py_NE))
|
2026-05-15 21:38:12 +02:00
|
|
|
|
return py_notimplemented ().release ();
|
2010-08-23 20:26:10 +00:00
|
|
|
|
|
|
|
|
|
|
if (type1 == type2)
|
2018-05-29 00:29:23 -06:00
|
|
|
|
result = true;
|
2010-08-23 20:26:10 +00:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2019-04-03 16:02:42 -06:00
|
|
|
|
try
|
2010-08-23 20:26:10 +00:00
|
|
|
|
{
|
2013-11-21 20:28:35 -08:00
|
|
|
|
result = types_deeply_equal (type1, type2);
|
2010-08-23 20:26:10 +00:00
|
|
|
|
}
|
2019-04-03 15:59:07 -06:00
|
|
|
|
catch (const gdb_exception &except)
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
{
|
|
|
|
|
|
/* If there is a GDB exception, a comparison is not capable
|
|
|
|
|
|
(or trusted), so exit. */
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 15:14:14 +00:00
|
|
|
|
}
|
2010-08-23 20:26:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-11-21 20:28:35 -08:00
|
|
|
|
if (op == (result ? Py_EQ : Py_NE))
|
2026-05-15 21:38:12 +02:00
|
|
|
|
return py_true ().release ();
|
|
|
|
|
|
return py_false ().release ();
|
2010-08-23 20:26:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
2025-03-19 21:12:53 +00:00
|
|
|
|
/* Forward declaration, see below. */
|
|
|
|
|
|
static void set_type (type_object *obj, struct type *type);
|
|
|
|
|
|
|
2025-03-19 21:12:53 +00:00
|
|
|
|
/* Invalidator that saves types when an objfile is being destroyed. */
|
|
|
|
|
|
struct typy_invalidator
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2020-10-18 11:38:10 -06:00
|
|
|
|
void operator() (type_object *obj)
|
|
|
|
|
|
{
|
2025-03-19 21:12:53 +00:00
|
|
|
|
if (obj->type->is_objfile_owned ())
|
2020-10-18 11:38:10 -06:00
|
|
|
|
{
|
2025-03-19 21:12:53 +00:00
|
|
|
|
copied_types_hash_t copied_types;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
2025-03-19 21:12:53 +00:00
|
|
|
|
/* Set a copied (now arch-owned) type. As a side-effect this
|
|
|
|
|
|
adds OBJ to per-arch list. We do not need to remove it from
|
|
|
|
|
|
per-objfile list since the objfile is going to go completely
|
|
|
|
|
|
anyway. */
|
|
|
|
|
|
set_type (obj, copy_type_recursive (obj->type, copied_types));
|
2020-10-18 11:38:10 -06:00
|
|
|
|
}
|
2025-03-19 21:12:53 +00:00
|
|
|
|
else
|
2025-03-19 21:12:53 +00:00
|
|
|
|
{
|
|
|
|
|
|
obj->type = nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-03-19 21:12:53 +00:00
|
|
|
|
static const gdbpy_registry<gdbpy_memoizing_registry_storage<type_object,
|
|
|
|
|
|
type, &type_object::type, typy_invalidator>> typy_registry;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
set_type (type_object *obj, struct type *type)
|
|
|
|
|
|
{
|
2025-03-19 21:12:53 +00:00
|
|
|
|
gdb_assert (type != nullptr);
|
|
|
|
|
|
|
2009-05-28 00:47:20 +00:00
|
|
|
|
obj->type = type;
|
2025-03-19 21:12:53 +00:00
|
|
|
|
|
|
|
|
|
|
if (type->objfile_owner () != nullptr)
|
2025-03-19 21:12:53 +00:00
|
|
|
|
typy_registry.add (type->objfile_owner (), obj);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
else
|
2025-03-19 21:12:53 +00:00
|
|
|
|
typy_registry.add (type->arch_owner (), obj);
|
2025-03-19 21:12:53 +00:00
|
|
|
|
}
|
2025-03-19 21:12:53 +00:00
|
|
|
|
|
2009-05-28 00:47:20 +00:00
|
|
|
|
static void
|
|
|
|
|
|
typy_dealloc (PyObject *obj)
|
|
|
|
|
|
{
|
2025-03-19 21:12:53 +00:00
|
|
|
|
type_object *type_obj = (type_object *) obj;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
2025-03-19 21:12:53 +00:00
|
|
|
|
if (type_obj->type != nullptr)
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2025-03-19 21:12:53 +00:00
|
|
|
|
if (type_obj->type->is_objfile_owned ())
|
|
|
|
|
|
typy_registry.remove (type_obj->type->objfile_owner (), type_obj);
|
2025-03-19 21:12:53 +00:00
|
|
|
|
else
|
2025-03-19 21:12:53 +00:00
|
|
|
|
typy_registry.remove (type_obj->type->arch_owner (), type_obj);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-19 21:12:53 +00:00
|
|
|
|
Py_TYPE (obj)->tp_free (obj);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-09-28 20:04:52 +00:00
|
|
|
|
/* Return number of fields ("length" of the field dictionary). */
|
|
|
|
|
|
|
|
|
|
|
|
static Py_ssize_t
|
|
|
|
|
|
typy_length (PyObject *self)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct type *type = ((type_object *) self)->type;
|
|
|
|
|
|
|
2011-11-15 21:17:04 +00:00
|
|
|
|
type = typy_get_composite (type);
|
|
|
|
|
|
if (type == NULL)
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
2020-05-22 16:55:15 -04:00
|
|
|
|
return type->num_fields ();
|
2011-09-28 20:04:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-11-15 21:17:04 +00:00
|
|
|
|
/* Implements boolean evaluation of gdb.Type. Handle this like other
|
2013-11-29 12:00:47 -08:00
|
|
|
|
Python objects that don't have a meaningful truth value -- all
|
2011-11-15 21:17:04 +00:00
|
|
|
|
values are true. */
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
|
typy_nonzero (PyObject *self)
|
|
|
|
|
|
{
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-04-28 17:41:09 -07:00
|
|
|
|
/* Return optimized out value of this type. */
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
typy_optimized_out (PyObject *self, PyObject *args)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct type *type = ((type_object *) self)->type;
|
|
|
|
|
|
|
Fix value chain use-after-free
Hannes filed a bug showing a crash, where a pretty-printer written in
Python could cause a use-after-free. He sent a patch, but I thought a
different approach was needed.
In a much earlier patch (see bug #12533), we changed the Python code
to release new values from the value chain when constructing a
gdb.Value. The rationale for this is that if you write a command that
does a lot of computations in a loop, all the values will be kept live
by the value chain, resulting in gdb using a large amount of memory.
However, suppose a value is passed to Python from some code in gdb
that needs to use the value after the call into Python. In this
scenario, value_to_value_object will still release the value -- and
because gdb code doesn't generally keep strong references to values (a
consequence of the ancient decision to use the value chain to avoid
memory management), this will result in a use-after-free.
This scenario can happen, as it turns out, when a value is passed to
Python for pretty-printing. Now, normally this route boxes the value
via value_to_value_object_no_release, avoiding the problematic release
from the value chain. However, if you then call Value.cast, the
underlying value API might return the same value, when is then
released from the chain.
This patch fixes the problem by changing how value boxing is done.
value_to_value_object no longer removes a value from the chain.
Instead, every spot in gdb that might construct new values uses a
scoped_value_mark to ensure that the requirements of bug #12533 are
met. And, because incoming values aren't ever released from the chain
(the Value.cast one comes earlier on the chain than the
scoped_value_mark), the bug can no longer occur. (Note that many
spots in the Python layer already take this approach, so not many
places needed to be touched.)
In the future I think we should replace the use of raw "value *" with
value_ref_ptr pretty much everywhere. This will ensure lifetime
safety throughout gdb.
The test case in this patch comes from Hannes' original patch. I only
made a trivial ("require") change to it. However, while this fails
for him, I can't make it fail on this machine; nevertheless, he tried
my patch and reported the bug as being fixed.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30044
2023-02-08 13:59:36 -07:00
|
|
|
|
scoped_value_mark free_values;
|
2026-02-20 13:02:00 -07:00
|
|
|
|
return value_to_value_object (value::allocate_optimized_out (type)).release ();
|
2015-04-28 17:41:09 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-09-28 20:04:52 +00:00
|
|
|
|
/* 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;
|
|
|
|
|
|
int i;
|
2011-10-27 09:14:27 +00:00
|
|
|
|
|
Use unique_xmalloc_ptr in Python code
This changes some utility functions in the Python code to return
unique_xmalloc_ptr, and then fixes up the callers.
I chose unique_xmalloc_ptr rather than std::string because at a few
call points the xmalloc'd string is released and ownership transferred
elsewhere.
This patch found a few existing memory leaks. For example,
py-unwind.c called gdbpy_obj_to_string but never freed the result.
Built and regression tested on the buildbot.
2016-11-09 Tom Tromey <tom@tromey.com>
* varobj.h (varobj_get_display_hint): Change return type.
* varobj.c (varobj_get_display_hint): Return unique_xmalloc_ptr.
(varobj_value_get_print_value): Update.
* python/python.c (gdbpy_before_prompt_hook, gdbpy_print_stack)
(gdbpy_apply_type_printers): Update.
* python/python-internal.h (unicode_to_target_string)
(python_string_to_target_string, python_string_to_host_string)
(gdbpy_obj_to_string, gdbpy_exception_to_string)
(gdbpy_get_display_hint): Change return types.
* python/py-varobj.c (py_varobj_iter_next): Update.
* python/py-value.c (valpy_getitem, convert_value_from_python):
Update.
* python/py-utils.c (unicode_to_encoded_string)
(unicode_to_target_string, python_string_to_target_string)
(python_string_to_host_string, gdbpy_obj_to_string)
(gdbpy_exception_to_string): Return unique_xmalloc_ptr.
* python/py-unwind.c (pyuw_parse_register_id): Update.
* python/py-type.c (typy_getitem): Update.
* python/py-prettyprint.c (gdbpy_get_display_hint)
(print_stack_unless_memory_error, print_children)
(gdbpy_apply_val_pretty_printer): Update.
* python/py-param.c (set_parameter_value): Update.
(get_doc_string, call_doc_function): Return unique_xmalloc_ptr.
(get_set_value, get_show_value, compute_enum_values, parmpy_init):
Update.
* python/py-infthread.c (thpy_set_name): Update.
* python/py-function.c (fnpy_call, fnpy_init): Update.
* python/py-framefilter.c (extract_sym): Change "name" to
unique_xmalloc_ptr.
(enumerate_args, enumerate_locals): Update.
(py_print_frame): Use unique_xmalloc_ptr.
* python/py-frame.c (frapy_read_var): Update. Remove cleanup.
* python/py-cmd.c (cmdpy_function, cmdpy_completer, cmdpy_init):
Update.
* python/py-breakpoint.c (bppy_set_condition): Use
unique_xmalloc_ptr.
(bppy_init): Likewise. Remove cleanup.
(local_setattro): Update.
* mi/mi-cmd-var.c (print_varobj, mi_cmd_var_list_children)
(varobj_update_one): Update.
2016-10-15 09:20:02 -06:00
|
|
|
|
gdb::unique_xmalloc_ptr<char> field = python_string_to_host_string (key);
|
2011-09-28 20:04:52 +00:00
|
|
|
|
if (field == NULL)
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
2013-11-29 12:00:47 -08:00
|
|
|
|
/* We want just fields of this type, not of base types, so instead of
|
2011-09-28 20:04:52 +00:00
|
|
|
|
using lookup_struct_elt_type, portions of that function are
|
|
|
|
|
|
copied here. */
|
|
|
|
|
|
|
2011-11-15 21:17:04 +00:00
|
|
|
|
type = typy_get_composite (type);
|
|
|
|
|
|
if (type == NULL)
|
|
|
|
|
|
return NULL;
|
2013-11-29 12:00:47 -08:00
|
|
|
|
|
2020-05-22 16:55:15 -04:00
|
|
|
|
for (i = 0; i < type->num_fields (); i++)
|
2011-09-28 20:04:52 +00:00
|
|
|
|
{
|
2021-08-30 11:49:49 -04:00
|
|
|
|
const char *t_field_name = type->field (i).name ();
|
2011-09-28 20:04:52 +00:00
|
|
|
|
|
Use unique_xmalloc_ptr in Python code
This changes some utility functions in the Python code to return
unique_xmalloc_ptr, and then fixes up the callers.
I chose unique_xmalloc_ptr rather than std::string because at a few
call points the xmalloc'd string is released and ownership transferred
elsewhere.
This patch found a few existing memory leaks. For example,
py-unwind.c called gdbpy_obj_to_string but never freed the result.
Built and regression tested on the buildbot.
2016-11-09 Tom Tromey <tom@tromey.com>
* varobj.h (varobj_get_display_hint): Change return type.
* varobj.c (varobj_get_display_hint): Return unique_xmalloc_ptr.
(varobj_value_get_print_value): Update.
* python/python.c (gdbpy_before_prompt_hook, gdbpy_print_stack)
(gdbpy_apply_type_printers): Update.
* python/python-internal.h (unicode_to_target_string)
(python_string_to_target_string, python_string_to_host_string)
(gdbpy_obj_to_string, gdbpy_exception_to_string)
(gdbpy_get_display_hint): Change return types.
* python/py-varobj.c (py_varobj_iter_next): Update.
* python/py-value.c (valpy_getitem, convert_value_from_python):
Update.
* python/py-utils.c (unicode_to_encoded_string)
(unicode_to_target_string, python_string_to_target_string)
(python_string_to_host_string, gdbpy_obj_to_string)
(gdbpy_exception_to_string): Return unique_xmalloc_ptr.
* python/py-unwind.c (pyuw_parse_register_id): Update.
* python/py-type.c (typy_getitem): Update.
* python/py-prettyprint.c (gdbpy_get_display_hint)
(print_stack_unless_memory_error, print_children)
(gdbpy_apply_val_pretty_printer): Update.
* python/py-param.c (set_parameter_value): Update.
(get_doc_string, call_doc_function): Return unique_xmalloc_ptr.
(get_set_value, get_show_value, compute_enum_values, parmpy_init):
Update.
* python/py-infthread.c (thpy_set_name): Update.
* python/py-function.c (fnpy_call, fnpy_init): Update.
* python/py-framefilter.c (extract_sym): Change "name" to
unique_xmalloc_ptr.
(enumerate_args, enumerate_locals): Update.
(py_print_frame): Use unique_xmalloc_ptr.
* python/py-frame.c (frapy_read_var): Update. Remove cleanup.
* python/py-cmd.c (cmdpy_function, cmdpy_completer, cmdpy_init):
Update.
* python/py-breakpoint.c (bppy_set_condition): Use
unique_xmalloc_ptr.
(bppy_init): Likewise. Remove cleanup.
(local_setattro): Update.
* mi/mi-cmd-var.c (print_varobj, mi_cmd_var_list_children)
(varobj_update_one): Update.
2016-10-15 09:20:02 -06:00
|
|
|
|
if (t_field_name && (strcmp_iw (t_field_name, field.get ()) == 0))
|
2018-12-27 12:08:09 -07:00
|
|
|
|
return convert_field (type, i).release ();
|
2011-09-28 20:04:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
PyErr_SetObject (PyExc_KeyError, key);
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-11-29 12:00:47 -08:00
|
|
|
|
/* Implement the "get" method on the type object. This is the
|
2011-09-28 20:04:52 +00:00
|
|
|
|
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;
|
2013-11-29 12:00:47 -08:00
|
|
|
|
|
2011-09-28 20:04:52 +00:00
|
|
|
|
if (!PyArg_UnpackTuple (args, "get", 1, 2, &key, &defval))
|
|
|
|
|
|
return NULL;
|
2013-11-29 12:00:47 -08:00
|
|
|
|
|
2011-09-28 20:04:52 +00:00
|
|
|
|
result = typy_getitem (self, key);
|
|
|
|
|
|
if (result != NULL)
|
|
|
|
|
|
return result;
|
2013-11-29 12:00:47 -08:00
|
|
|
|
|
2011-09-28 20:04:52 +00:00
|
|
|
|
/* 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;
|
2013-11-29 12:00:47 -08:00
|
|
|
|
|
2011-09-28 20:04:52 +00:00
|
|
|
|
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;
|
2025-08-01 11:11:41 -06:00
|
|
|
|
const char *field_name;
|
2011-10-27 09:14:27 +00:00
|
|
|
|
|
2025-08-01 11:11:41 -06:00
|
|
|
|
if (!PyArg_ParseTuple (args, "s", &field_name))
|
2011-09-28 20:04:52 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
|
|
2013-11-29 12:00:47 -08:00
|
|
|
|
/* We want just fields of this type, not of base types, so instead of
|
2011-09-28 20:04:52 +00:00
|
|
|
|
using lookup_struct_elt_type, portions of that function are
|
|
|
|
|
|
copied here. */
|
|
|
|
|
|
|
2011-11-15 21:17:04 +00:00
|
|
|
|
type = typy_get_composite (type);
|
|
|
|
|
|
if (type == NULL)
|
|
|
|
|
|
return NULL;
|
2011-09-28 20:04:52 +00:00
|
|
|
|
|
2025-08-01 11:11:41 -06:00
|
|
|
|
for (const auto &field : type->fields ())
|
2011-09-28 20:04:52 +00:00
|
|
|
|
{
|
2025-08-01 11:11:41 -06:00
|
|
|
|
const char *t_field_name = field.name ();
|
2011-09-28 20:04:52 +00:00
|
|
|
|
|
2025-08-01 11:11:41 -06:00
|
|
|
|
if (t_field_name && (strcmp_iw (t_field_name, field_name) == 0))
|
2026-05-15 21:38:12 +02:00
|
|
|
|
return py_true ().release ();
|
2011-09-28 20:04:52 +00:00
|
|
|
|
}
|
2026-05-15 21:38:12 +02:00
|
|
|
|
return py_false ().release ();
|
2011-09-28 20:04:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
2011-11-15 21:17:04 +00:00
|
|
|
|
/* Check that "self" is a structure or union type. */
|
|
|
|
|
|
if (typy_get_composite (((type_object *) self)->type) == NULL)
|
|
|
|
|
|
return NULL;
|
2013-11-29 12:00:47 -08:00
|
|
|
|
|
2011-09-28 20:04:52 +00:00
|
|
|
|
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;
|
2013-11-29 12:00:47 -08:00
|
|
|
|
|
2020-05-22 16:55:15 -04:00
|
|
|
|
if (iter_obj->field < type->num_fields ())
|
2011-09-28 20:04:52 +00:00
|
|
|
|
{
|
2018-12-27 12:08:09 -07:00
|
|
|
|
gdbpy_ref<> result = make_fielditem (type, iter_obj->field,
|
|
|
|
|
|
iter_obj->kind);
|
2011-09-28 20:04:52 +00:00
|
|
|
|
if (result != NULL)
|
|
|
|
|
|
iter_obj->field++;
|
2018-12-27 12:08:09 -07:00
|
|
|
|
return result.release ();
|
2011-09-28 20:04:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
typy_iterator_dealloc (PyObject *obj)
|
|
|
|
|
|
{
|
|
|
|
|
|
typy_iterator_object *iter_obj = (typy_iterator_object *) obj;
|
|
|
|
|
|
|
|
|
|
|
|
Py_DECREF (iter_obj->source);
|
Fix a bunch of python leaks due to missing calls to tp_free in *_dealloc functions.
valgrind reports leaks in many python tests, such as:
==17162== VALGRIND_GDB_ERROR_BEGIN
==17162== 8,208 (5,472 direct, 2,736 indirect) bytes in 57 blocks are definitely lost in loss record 7,551 of 7,679
==17162== at 0x4835753: malloc (vg_replace_malloc.c:307)
==17162== by 0x6EAFD1: _PyObject_New (object.c:279)
==17162== by 0x4720E6: blpy_iter(_object*) (py-block.c:92)
==17162== by 0x698772: PyObject_GetIter (abstract.c:2577)
==17162== by 0x2343BE: _PyEval_EvalFrameDefault (ceval.c:3159)
==17162== by 0x22E9E2: function_code_fastcall (call.c:283)
==17162== by 0x2340A8: _PyObject_Vectorcall (abstract.h:127)
==17162== by 0x2340A8: call_function (ceval.c:4987)
==17162== by 0x2340A8: _PyEval_EvalFrameDefault (ceval.c:3486)
==17162== by 0x22E9E2: function_code_fastcall (call.c:283)
==17162== by 0x82172B: _PyObject_Vectorcall (abstract.h:127)
==17162== by 0x82172B: method_vectorcall (classobject.c:67)
==17162== by 0x6AF474: _PyObject_Vectorcall (abstract.h:127)
==17162== by 0x6AF474: _PyObject_CallNoArg (abstract.h:153)
==17162== by 0x6AF474: _PyObject_CallFunctionVa (call.c:914)
==17162== by 0x6B0673: callmethod (call.c:1010)
==17162== by 0x6B0673: _PyObject_CallMethod_SizeT (call.c:1103)
==17162== by 0x477DFE: gdb_PyObject_CallMethod<> (python-internal.h:182)
==17162== by 0x477DFE: get_py_iter_from_func(_object*, char const*) (py-framefilter.c:272)
==17162== by 0x4791B4: py_print_args (py-framefilter.c:706)
==17162== by 0x4791B4: py_print_frame(_object*, enum_flags<frame_filter_flag>, ext_lang_frame_args, ui_out*, int, htab*) (py-framefilter.c:960)
==17162== by 0x47A130: gdbpy_apply_frame_filter(extension_language_defn const*, frame_info*, enum_flags<frame_filter_flag>, ext_lang_frame_args, ui_out*, int, int) (py-framefilter.c:1236)
==17162== by 0x369C39: apply_ext_lang_frame_filter(frame_info*, enum_flags<frame_filter_flag>, ext_lang_frame_args, ui_out*, int, int) (extension.c:563)
==17162== by 0x4EC9C9: backtrace_command_1 (stack.c:2031)
==17162== by 0x4EC9C9: backtrace_command(char const*, int) (stack.c:2183)
...
Most of the leaks in python tests are due to the fact that many
PyObject xxxxx_dealloc functions are missing the line to free self
or obj such as:
Py_TYPE (self)->tp_free (self);
or
Py_TYPE (obj)->tp_free (obj);
With this patch, the number of python tests leaking decreases from 52 to 12.
gdb/ChangeLog
2019-11-18 Philippe Waroquiers <philippe.waroquiers@skynet.be>
* python/py-block.c (blpy_dealloc): Call tp_free.
(blpy_block_syms_dealloc): Likewise.
* python/py-finishbreakpoint.c (bpfinishpy_dealloc): Likewise.
* python/py-inferior.c (infpy_dealloc): Likewise.
* python/py-lazy-string.c (stpy_dealloc): Likewise.
* python/py-linetable.c (ltpy_iterator_dealloc): Likewise.
* python/py-symbol.c (sympy_dealloc): Likewise.
* python/py-symtab.c (stpy_dealloc): Likewise.
* python/py-type.c (typy_iterator_dealloc): Likewise.
2019-11-17 22:48:48 +01:00
|
|
|
|
Py_TYPE (obj)->tp_free (obj);
|
2011-09-28 20:04:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2009-05-28 00:47:20 +00:00
|
|
|
|
/* Create a new Type referring to TYPE. */
|
2026-02-20 13:05:24 -07:00
|
|
|
|
gdbpy_ref<>
|
2009-05-28 00:47:20 +00:00
|
|
|
|
type_to_type_object (struct type *type)
|
|
|
|
|
|
{
|
2019-08-19 13:41:34 -06:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
/* Try not to let stub types leak out to Python. */
|
2020-09-14 11:07:59 -04:00
|
|
|
|
if (type->is_stub ())
|
2019-08-19 13:41:34 -06:00
|
|
|
|
type = check_typedef (type);
|
|
|
|
|
|
}
|
2024-08-22 09:49:53 +02:00
|
|
|
|
catch (const gdb_exception_error &)
|
2019-08-19 13:41:34 -06:00
|
|
|
|
{
|
|
|
|
|
|
/* Just ignore failures in check_typedef. */
|
|
|
|
|
|
}
|
2024-08-22 09:49:53 +02:00
|
|
|
|
catch (const gdb_exception &except)
|
|
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, except);
|
2024-08-22 09:49:53 +02:00
|
|
|
|
}
|
2025-03-19 21:12:53 +00:00
|
|
|
|
|
|
|
|
|
|
/* Look if there's already a gdb.Type object for given TYPE
|
|
|
|
|
|
and if so, return it. */
|
2026-02-20 13:34:45 -07:00
|
|
|
|
gdbpy_ref<> result;
|
2025-03-19 21:12:53 +00:00
|
|
|
|
if (type->is_objfile_owned ())
|
2026-02-20 13:34:45 -07:00
|
|
|
|
result = typy_registry.lookup (type->objfile_owner (), type);
|
2025-03-19 21:12:53 +00:00
|
|
|
|
else
|
2026-02-20 13:34:45 -07:00
|
|
|
|
result = typy_registry.lookup (type->arch_owner (), type);
|
2025-03-19 21:12:53 +00:00
|
|
|
|
|
2026-02-20 13:34:45 -07:00
|
|
|
|
if (result == nullptr)
|
2026-02-20 13:05:24 -07:00
|
|
|
|
{
|
2026-02-20 13:34:45 -07:00
|
|
|
|
type_object *type_obj = PyObject_New (type_object, &type_object_type);
|
|
|
|
|
|
if (type_obj != nullptr)
|
2026-02-20 13:05:24 -07:00
|
|
|
|
set_type (type_obj, type);
|
2026-02-20 13:34:45 -07:00
|
|
|
|
result = gdbpy_ref<> (type_obj);
|
2026-02-20 13:05:24 -07:00
|
|
|
|
}
|
2026-02-20 13:34:45 -07:00
|
|
|
|
return result;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
{
|
-Wwrite-strings: Add a PyArg_ParseTupleAndKeywords "const char *" overload
-Wwrite-strings flags code like:
static char *keywords[] = {"command", "from_tty", "to_string", NULL };
as needing "(char *)" casts, because string literals are "const char []".
We can get rid of the casts by changing the array type like this:
- static char *keywords[] = {"command", "from_tty", "to_string", NULL };
+ static const char *keywords[] = {"command", "from_tty", "to_string", NULL };
However, passing the such array to PyArg_ParseTupleAndKeywords no longer
works OOTB, because PyArg_ParseTupleAndKeywords expects a "char **":
PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw,
const char *format,
char *keywords[], ...);
and "const char **" is not implicitly convertible to "char **". C++
is more tolerant that C here WRT aliasing, and a const_cast<char **>
is fine. However, to avoid having all callers do the cast themselves,
this commit defines a gdb_PyArg_ParseTupleAndKeywords function here
with a corresponding 'keywords' parameter type that does the cast in a
single place.
gdb/ChangeLog:
2017-04-05 Pedro Alves <palves@redhat.com>
* python/python-internal.h (gdb_PyArg_ParseTupleAndKeywords): New
static inline function.
* python/py-arch.c (archpy_disassemble): Constify 'keywords'
array and use gdb_PyArg_ParseTupleAndKeywords.
* python/py-cmd.c (cmdpy_init): Likewise.
* python/py-finishbreakpoint.c (bpfinishpy_init): Likewise.
* python/py-inferior.c (infpy_read_memory, infpy_write_memory)
(infpy_search_memory): Likewise.
* python/py-objfile.c (objfpy_add_separate_debug_file)
(gdbpy_lookup_objfile): Likewise.
* python/py-symbol.c (gdbpy_lookup_symbol)
(gdbpy_lookup_global_symbol): Likewise.
* python/py-type.c (gdbpy_lookup_type): Likewise.
* python/py-value.c (valpy_lazy_string, valpy_string): Likewise.
* python/python.c (execute_gdb_command, gdbpy_write, gdbpy_flush):
Likewise.
2017-04-05 19:21:36 +01:00
|
|
|
|
static const char *keywords[] = { "name", "block", NULL };
|
2011-06-24 19:47:37 +00:00
|
|
|
|
const char *type_name = NULL;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
struct type *type = NULL;
|
2010-02-26 09:08:10 +00:00
|
|
|
|
PyObject *block_obj = NULL;
|
2011-10-20 12:31:30 +00:00
|
|
|
|
const struct block *block = NULL;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
-Wwrite-strings: Add a PyArg_ParseTupleAndKeywords "const char *" overload
-Wwrite-strings flags code like:
static char *keywords[] = {"command", "from_tty", "to_string", NULL };
as needing "(char *)" casts, because string literals are "const char []".
We can get rid of the casts by changing the array type like this:
- static char *keywords[] = {"command", "from_tty", "to_string", NULL };
+ static const char *keywords[] = {"command", "from_tty", "to_string", NULL };
However, passing the such array to PyArg_ParseTupleAndKeywords no longer
works OOTB, because PyArg_ParseTupleAndKeywords expects a "char **":
PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw,
const char *format,
char *keywords[], ...);
and "const char **" is not implicitly convertible to "char **". C++
is more tolerant that C here WRT aliasing, and a const_cast<char **>
is fine. However, to avoid having all callers do the cast themselves,
this commit defines a gdb_PyArg_ParseTupleAndKeywords function here
with a corresponding 'keywords' parameter type that does the cast in a
single place.
gdb/ChangeLog:
2017-04-05 Pedro Alves <palves@redhat.com>
* python/python-internal.h (gdb_PyArg_ParseTupleAndKeywords): New
static inline function.
* python/py-arch.c (archpy_disassemble): Constify 'keywords'
array and use gdb_PyArg_ParseTupleAndKeywords.
* python/py-cmd.c (cmdpy_init): Likewise.
* python/py-finishbreakpoint.c (bpfinishpy_init): Likewise.
* python/py-inferior.c (infpy_read_memory, infpy_write_memory)
(infpy_search_memory): Likewise.
* python/py-objfile.c (objfpy_add_separate_debug_file)
(gdbpy_lookup_objfile): Likewise.
* python/py-symbol.c (gdbpy_lookup_symbol)
(gdbpy_lookup_global_symbol): Likewise.
* python/py-type.c (gdbpy_lookup_type): Likewise.
* python/py-value.c (valpy_lazy_string, valpy_string): Likewise.
* python/python.c (execute_gdb_command, gdbpy_write, gdbpy_flush):
Likewise.
2017-04-05 19:21:36 +01:00
|
|
|
|
if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "s|O", keywords,
|
|
|
|
|
|
&type_name, &block_obj))
|
2009-05-28 00:47:20 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
|
|
2010-02-26 09:08:10 +00:00
|
|
|
|
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);
|
2009-05-28 00:47:20 +00:00
|
|
|
|
if (! type)
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
2026-02-20 13:05:24 -07:00
|
|
|
|
return type_to_type_object (type).release ();
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-21 10:00:20 -06:00
|
|
|
|
static int
|
|
|
|
|
|
gdbpy_initialize_types ()
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2024-09-11 10:35:20 -06:00
|
|
|
|
if (gdbpy_type_ready (&type_object_type) < 0)
|
* python/py-arch.c (gdbpy_initialize_arch): Return 'int'.
Check errors.
* python/py-auto-load.c (gdbpy_initialize_auto_load): Return 'int'.
* python/py-block.c (gdbpy_initialize_blocks): Return 'int'.
Check errors.
* python/py-breakpoint.c (gdbpy_initialize_breakpoints): Return 'int'.
Check errors.
* python/py-cmd.c (gdbpy_initialize_commands): Return 'int'.
Check errors.
* python/py-event.c (gdbpy_initialize_event): Return 'int'.
Check errors.
* python/py-event.h (GDBPY_NEW_EVENT_TYPE): Change generated
init function to return 'int'.
* python/py-evtregistry.c (gdbpy_initialize_eventregistry):
Return 'int'. Check errors.
* python/py-evts.c (gdbpy_initialize_py_events): Return 'int'.
Check errors.
* python/py-finishbreakpoint.c (gdbpy_initialize_finishbreakpoints):
Return 'int'. Check errors.
* python/py-frame.c (gdbpy_initialize_frames): Return 'int'.
Check errors.
* python/py-function.c (gdbpy_initialize_functions): Return 'int'.
Check errors.
* python/py-gdb-readline.c (gdbpy_initialize_gdb_readline):
Check errors.
* python/py-inferior.c (gdbpy_initialize_inferior): Return 'int'.
Check errors.
* python/py-infthread.c (gdbpy_initialize_thread): Return 'int'.
Check errors.
* python/py-lazy-string.c (gdbpy_initialize_lazy_string): Return 'int'.
Check errors.
* python/py-objfile.c (gdbpy_initialize_objfile): Return 'int'.
Check errors.
* python/py-param.c (gdbpy_initialize_parameters): Return 'int'.
Check errors.
* python/py-progspace.c (gdbpy_initialize_pspace): Return 'int'.
Check errors.
* python/py-symbol.c (gdbpy_initialize_symbols): Return 'int'.
Check errors.
* python/py-symtab.c (gdbpy_initialize_symtabs): Return 'int'.
Check errors.
* python/py-type.c (gdbpy_initialize_types): Return 'int'.
Check errors.
* python/py-value.c (gdbpy_initialize_values): Return 'int'.
Check errors.
* python/python-internal.h (gdbpy_initialize_auto_load,
gdbpy_initialize_values, gdbpy_initialize_frames,
gdbpy_initialize_symtabs, gdbpy_initialize_commands,
gdbpy_initialize_symbols, gdbpy_initialize_symtabs,
gdbpy_initialize_blocks, gdbpy_initialize_types,
gdbpy_initialize_functions, gdbpy_initialize_pspace,
gdbpy_initialize_objfile, gdbpy_initialize_breakpoints,
gdbpy_initialize_finishbreakpoints,
gdbpy_initialize_lazy_string, gdbpy_initialize_parameters,
gdbpy_initialize_thread, gdbpy_initialize_inferior,
gdbpy_initialize_eventregistry, gdbpy_initialize_event,
gdbpy_initialize_py_events, gdbpy_initialize_stop_event,
gdbpy_initialize_signal_event,
gdbpy_initialize_breakpoint_event,
gdbpy_initialize_continue_event,
gdbpy_initialize_exited_event, gdbpy_initialize_thread_event,
gdbpy_initialize_new_objfile_event, gdbpy_initialize_arch):
Update. Use CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION.
* python/python.c (gdb_python_initialized): New global.
(gdbpy_initialize_events): Return 'int'. Check errors.
(_initialize_python): Check errors. Set
gdb_python_initialized.
2013-05-20 20:28:52 +00:00
|
|
|
|
return -1;
|
2024-09-11 10:35:20 -06:00
|
|
|
|
if (gdbpy_type_ready (&field_object_type) < 0)
|
* python/py-arch.c (gdbpy_initialize_arch): Return 'int'.
Check errors.
* python/py-auto-load.c (gdbpy_initialize_auto_load): Return 'int'.
* python/py-block.c (gdbpy_initialize_blocks): Return 'int'.
Check errors.
* python/py-breakpoint.c (gdbpy_initialize_breakpoints): Return 'int'.
Check errors.
* python/py-cmd.c (gdbpy_initialize_commands): Return 'int'.
Check errors.
* python/py-event.c (gdbpy_initialize_event): Return 'int'.
Check errors.
* python/py-event.h (GDBPY_NEW_EVENT_TYPE): Change generated
init function to return 'int'.
* python/py-evtregistry.c (gdbpy_initialize_eventregistry):
Return 'int'. Check errors.
* python/py-evts.c (gdbpy_initialize_py_events): Return 'int'.
Check errors.
* python/py-finishbreakpoint.c (gdbpy_initialize_finishbreakpoints):
Return 'int'. Check errors.
* python/py-frame.c (gdbpy_initialize_frames): Return 'int'.
Check errors.
* python/py-function.c (gdbpy_initialize_functions): Return 'int'.
Check errors.
* python/py-gdb-readline.c (gdbpy_initialize_gdb_readline):
Check errors.
* python/py-inferior.c (gdbpy_initialize_inferior): Return 'int'.
Check errors.
* python/py-infthread.c (gdbpy_initialize_thread): Return 'int'.
Check errors.
* python/py-lazy-string.c (gdbpy_initialize_lazy_string): Return 'int'.
Check errors.
* python/py-objfile.c (gdbpy_initialize_objfile): Return 'int'.
Check errors.
* python/py-param.c (gdbpy_initialize_parameters): Return 'int'.
Check errors.
* python/py-progspace.c (gdbpy_initialize_pspace): Return 'int'.
Check errors.
* python/py-symbol.c (gdbpy_initialize_symbols): Return 'int'.
Check errors.
* python/py-symtab.c (gdbpy_initialize_symtabs): Return 'int'.
Check errors.
* python/py-type.c (gdbpy_initialize_types): Return 'int'.
Check errors.
* python/py-value.c (gdbpy_initialize_values): Return 'int'.
Check errors.
* python/python-internal.h (gdbpy_initialize_auto_load,
gdbpy_initialize_values, gdbpy_initialize_frames,
gdbpy_initialize_symtabs, gdbpy_initialize_commands,
gdbpy_initialize_symbols, gdbpy_initialize_symtabs,
gdbpy_initialize_blocks, gdbpy_initialize_types,
gdbpy_initialize_functions, gdbpy_initialize_pspace,
gdbpy_initialize_objfile, gdbpy_initialize_breakpoints,
gdbpy_initialize_finishbreakpoints,
gdbpy_initialize_lazy_string, gdbpy_initialize_parameters,
gdbpy_initialize_thread, gdbpy_initialize_inferior,
gdbpy_initialize_eventregistry, gdbpy_initialize_event,
gdbpy_initialize_py_events, gdbpy_initialize_stop_event,
gdbpy_initialize_signal_event,
gdbpy_initialize_breakpoint_event,
gdbpy_initialize_continue_event,
gdbpy_initialize_exited_event, gdbpy_initialize_thread_event,
gdbpy_initialize_new_objfile_event, gdbpy_initialize_arch):
Update. Use CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION.
* python/python.c (gdb_python_initialized): New global.
(gdbpy_initialize_events): Return 'int'. Check errors.
(_initialize_python): Check errors. Set
gdb_python_initialized.
2013-05-20 20:28:52 +00:00
|
|
|
|
return -1;
|
2024-09-11 10:35:20 -06:00
|
|
|
|
if (gdbpy_type_ready (&type_iterator_object_type) < 0)
|
* python/py-arch.c (gdbpy_initialize_arch): Return 'int'.
Check errors.
* python/py-auto-load.c (gdbpy_initialize_auto_load): Return 'int'.
* python/py-block.c (gdbpy_initialize_blocks): Return 'int'.
Check errors.
* python/py-breakpoint.c (gdbpy_initialize_breakpoints): Return 'int'.
Check errors.
* python/py-cmd.c (gdbpy_initialize_commands): Return 'int'.
Check errors.
* python/py-event.c (gdbpy_initialize_event): Return 'int'.
Check errors.
* python/py-event.h (GDBPY_NEW_EVENT_TYPE): Change generated
init function to return 'int'.
* python/py-evtregistry.c (gdbpy_initialize_eventregistry):
Return 'int'. Check errors.
* python/py-evts.c (gdbpy_initialize_py_events): Return 'int'.
Check errors.
* python/py-finishbreakpoint.c (gdbpy_initialize_finishbreakpoints):
Return 'int'. Check errors.
* python/py-frame.c (gdbpy_initialize_frames): Return 'int'.
Check errors.
* python/py-function.c (gdbpy_initialize_functions): Return 'int'.
Check errors.
* python/py-gdb-readline.c (gdbpy_initialize_gdb_readline):
Check errors.
* python/py-inferior.c (gdbpy_initialize_inferior): Return 'int'.
Check errors.
* python/py-infthread.c (gdbpy_initialize_thread): Return 'int'.
Check errors.
* python/py-lazy-string.c (gdbpy_initialize_lazy_string): Return 'int'.
Check errors.
* python/py-objfile.c (gdbpy_initialize_objfile): Return 'int'.
Check errors.
* python/py-param.c (gdbpy_initialize_parameters): Return 'int'.
Check errors.
* python/py-progspace.c (gdbpy_initialize_pspace): Return 'int'.
Check errors.
* python/py-symbol.c (gdbpy_initialize_symbols): Return 'int'.
Check errors.
* python/py-symtab.c (gdbpy_initialize_symtabs): Return 'int'.
Check errors.
* python/py-type.c (gdbpy_initialize_types): Return 'int'.
Check errors.
* python/py-value.c (gdbpy_initialize_values): Return 'int'.
Check errors.
* python/python-internal.h (gdbpy_initialize_auto_load,
gdbpy_initialize_values, gdbpy_initialize_frames,
gdbpy_initialize_symtabs, gdbpy_initialize_commands,
gdbpy_initialize_symbols, gdbpy_initialize_symtabs,
gdbpy_initialize_blocks, gdbpy_initialize_types,
gdbpy_initialize_functions, gdbpy_initialize_pspace,
gdbpy_initialize_objfile, gdbpy_initialize_breakpoints,
gdbpy_initialize_finishbreakpoints,
gdbpy_initialize_lazy_string, gdbpy_initialize_parameters,
gdbpy_initialize_thread, gdbpy_initialize_inferior,
gdbpy_initialize_eventregistry, gdbpy_initialize_event,
gdbpy_initialize_py_events, gdbpy_initialize_stop_event,
gdbpy_initialize_signal_event,
gdbpy_initialize_breakpoint_event,
gdbpy_initialize_continue_event,
gdbpy_initialize_exited_event, gdbpy_initialize_thread_event,
gdbpy_initialize_new_objfile_event, gdbpy_initialize_arch):
Update. Use CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION.
* python/python.c (gdb_python_initialized): New global.
(gdbpy_initialize_events): Return 'int'. Check errors.
(_initialize_python): Check errors. Set
gdb_python_initialized.
2013-05-20 20:28:52 +00:00
|
|
|
|
return -1;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
2021-11-30 14:18:09 +00:00
|
|
|
|
for (const auto &item : pyty_codes)
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2021-11-30 14:18:09 +00:00
|
|
|
|
if (PyModule_AddIntConstant (gdb_module, item.name, item.code) < 0)
|
* python/py-arch.c (gdbpy_initialize_arch): Return 'int'.
Check errors.
* python/py-auto-load.c (gdbpy_initialize_auto_load): Return 'int'.
* python/py-block.c (gdbpy_initialize_blocks): Return 'int'.
Check errors.
* python/py-breakpoint.c (gdbpy_initialize_breakpoints): Return 'int'.
Check errors.
* python/py-cmd.c (gdbpy_initialize_commands): Return 'int'.
Check errors.
* python/py-event.c (gdbpy_initialize_event): Return 'int'.
Check errors.
* python/py-event.h (GDBPY_NEW_EVENT_TYPE): Change generated
init function to return 'int'.
* python/py-evtregistry.c (gdbpy_initialize_eventregistry):
Return 'int'. Check errors.
* python/py-evts.c (gdbpy_initialize_py_events): Return 'int'.
Check errors.
* python/py-finishbreakpoint.c (gdbpy_initialize_finishbreakpoints):
Return 'int'. Check errors.
* python/py-frame.c (gdbpy_initialize_frames): Return 'int'.
Check errors.
* python/py-function.c (gdbpy_initialize_functions): Return 'int'.
Check errors.
* python/py-gdb-readline.c (gdbpy_initialize_gdb_readline):
Check errors.
* python/py-inferior.c (gdbpy_initialize_inferior): Return 'int'.
Check errors.
* python/py-infthread.c (gdbpy_initialize_thread): Return 'int'.
Check errors.
* python/py-lazy-string.c (gdbpy_initialize_lazy_string): Return 'int'.
Check errors.
* python/py-objfile.c (gdbpy_initialize_objfile): Return 'int'.
Check errors.
* python/py-param.c (gdbpy_initialize_parameters): Return 'int'.
Check errors.
* python/py-progspace.c (gdbpy_initialize_pspace): Return 'int'.
Check errors.
* python/py-symbol.c (gdbpy_initialize_symbols): Return 'int'.
Check errors.
* python/py-symtab.c (gdbpy_initialize_symtabs): Return 'int'.
Check errors.
* python/py-type.c (gdbpy_initialize_types): Return 'int'.
Check errors.
* python/py-value.c (gdbpy_initialize_values): Return 'int'.
Check errors.
* python/python-internal.h (gdbpy_initialize_auto_load,
gdbpy_initialize_values, gdbpy_initialize_frames,
gdbpy_initialize_symtabs, gdbpy_initialize_commands,
gdbpy_initialize_symbols, gdbpy_initialize_symtabs,
gdbpy_initialize_blocks, gdbpy_initialize_types,
gdbpy_initialize_functions, gdbpy_initialize_pspace,
gdbpy_initialize_objfile, gdbpy_initialize_breakpoints,
gdbpy_initialize_finishbreakpoints,
gdbpy_initialize_lazy_string, gdbpy_initialize_parameters,
gdbpy_initialize_thread, gdbpy_initialize_inferior,
gdbpy_initialize_eventregistry, gdbpy_initialize_event,
gdbpy_initialize_py_events, gdbpy_initialize_stop_event,
gdbpy_initialize_signal_event,
gdbpy_initialize_breakpoint_event,
gdbpy_initialize_continue_event,
gdbpy_initialize_exited_event, gdbpy_initialize_thread_event,
gdbpy_initialize_new_objfile_event, gdbpy_initialize_arch):
Update. Use CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION.
* python/python.c (gdb_python_initialized): New global.
(gdbpy_initialize_events): Return 'int'. Check errors.
(_initialize_python): Check errors. Set
gdb_python_initialized.
2013-05-20 20:28:52 +00:00
|
|
|
|
return -1;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-11 10:35:20 -06:00
|
|
|
|
return 0;
|
2009-05-28 00:47:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
gdb/python: add mechanism to manage Python initialization functions
Currently, when we add a new python sub-system to GDB,
e.g. py-inferior.c, we end up having to create a new function like
gdbpy_initialize_inferior, which then has to be called from the
function do_start_initialization in python.c.
In some cases (py-micmd.c and py-tui.c), we have two functions
gdbpy_initialize_*, and gdbpy_finalize_*, with the second being called
from finalize_python which is also in python.c.
This commit proposes a mechanism to manage these initialization and
finalization calls, this means that adding a new Python subsystem will
no longer require changes to python.c or python-internal.h, instead,
the initialization and finalization functions will be registered
directly from the sub-system file, e.g. py-inferior.c, or py-micmd.c.
The initialization and finalization functions are managed through a
new class gdbpy_initialize_file in python-internal.h. This class
contains a single global vector of all the initialization and
finalization functions.
In each Python sub-system we create a new gdbpy_initialize_file
object, the object constructor takes care of registering the two
callback functions.
Now from python.c we can call static functions on the
gdbpy_initialize_file class which take care of walking the callback
list and invoking each callback in turn.
To slightly simplify the Python sub-system files I added a new macro
GDBPY_INITIALIZE_FILE, which hides the need to create an object. We
can now just do this:
GDBPY_INITIALIZE_FILE (gdbpy_initialize_registers);
One possible problem with this change is that there is now no
guaranteed ordering of how the various sub-systems are initialized (or
finalized). To try and avoid dependencies creeping in I have added a
use of the environment variable GDB_REVERSE_INIT_FUNCTIONS, this is
the same environment variable used in the generated init.c file.
Just like with init.c, when this environment variable is set we
reverse the list of Python initialization (and finalization)
functions. As there is already a test that starts GDB with the
environment variable set then this should offer some level of
protection against dependencies creeping in - though for full
protection I guess we'd need to run all gdb.python/*.exp tests with
the variable set.
I have tested this patch with the environment variable set, and saw no
regressions, so I think we are fine right now.
One other change of note was for gdbpy_initialize_gdb_readline, this
function previously returned void. In order to make this function
have the correct signature I've updated its return type to int, and we
now return 0 to indicate success.
All of the other initialize (and finalize) functions have been made
static within their respective sub-system files.
There should be no user visible changes after this commit.
2022-09-16 16:08:17 +01:00
|
|
|
|
GDBPY_INITIALIZE_FILE (gdbpy_initialize_types);
|
|
|
|
|
|
|
2009-05-28 00:47:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
-Wwrite-strings: Wrap PyGetSetDef for construction with string literals
Unfortunately, PyGetSetDef's 'name' and 'doc' members are 'char *'
instead of 'const char *', meaning that in order to list-initialize
PyGetSetDef arrays using string literals requires writing explicit
'char *' casts. For example:
static PyGetSetDef value_object_getset[] = {
- { "address", valpy_get_address, NULL, "The address of the value.",
+ { (char *) "address", valpy_get_address, NULL,
+ (char *) "The address of the value.",
NULL },
- { "is_optimized_out", valpy_get_is_optimized_out, NULL,
- "Boolean telling whether the value is optimized "
+ { (char *) "is_optimized_out", valpy_get_is_optimized_out, NULL,
+ (char *) "Boolean telling whether the value is optimized "
"out (i.e., not available).",
NULL },
- { "type", valpy_get_type, NULL, "Type of the value.", NULL },
- { "dynamic_type", valpy_get_dynamic_type, NULL,
- "Dynamic type of the value.", NULL },
- { "is_lazy", valpy_get_is_lazy, NULL,
- "Boolean telling whether the value is lazy (not fetched yet\n\
+ { (char *) "type", valpy_get_type, NULL,
+ (char *) "Type of the value.", NULL },
+ { (char *) "dynamic_type", valpy_get_dynamic_type, NULL,
+ (char *) "Dynamic type of the value.", NULL },
+ { (char *) "is_lazy", valpy_get_is_lazy, NULL,
+ (char *) "Boolean telling whether the value is lazy (not fetched yet\n\
from the inferior). A lazy value is fetched when needed, or when\n\
the \"fetch_lazy()\" method is called.", NULL },
{NULL} /* Sentinel */
We have ~20 such arrays, and I first wrote a patch that fixed all of
them like that... It's not pretty...
One way to make these a bit less ugly would be add a new macro that
hides the casts, like:
#define GDBPY_GSDEF(NAME, GET, SET, DOC, CLOSURE) \
{ (char *) NAME, GET, SET, (char *) DOC, CLOSURE }
and then use it like:
static PyGetSetDef value_object_getset[] = {
GDBPY_GSDEF ("address", valpy_get_address, NULL,
"The address of the value.", NULL),
GDBPY_GSDEF ("is_optimized_out", valpy_get_is_optimized_out, NULL,
"Boolean telling whether the value is optimized ", NULL),
{NULL} /* Sentinel */
};
But since we have C++11, which gives us constexpr and list
initialization, I thought of a way that requires no changes where the
arrays are initialized:
We add a new type that extends PyGetSetDef (called gdb_PyGetSetDef),
and add constexpr constructors that accept const 'name' and 'doc', and
then list/aggregate initialization simply "calls" these matching
constructors instead.
I put "calls" in quotes, because given "constexpr", it's all done at
compile time, and there's no overhead either in binary size or at run
time. In fact, we get identical binaries, before/after this change.
Unlike the fixes that fix some old Python API to match the API of more
recent Python, this switches to using explicit "gdb_PyGetSetDef"
everywhere, just to be clear that we are using our own version of it.
gdb/ChangeLog:
2017-04-05 Pedro Alves <palves@redhat.com>
* python/python-internal.h (gdb_PyGetSetDef): New type.
* python/py-block.c (block_object_getset)
(breakpoint_object_getset): Now a gdb_PyGetSetDef array.
* python/py-event.c (event_object_getset)
(finish_breakpoint_object_getset): Likewise.
* python/py-inferior.c (inferior_object_getset): Likewise.
* python/py-infthread.c (thread_object_getset): Likewise.
* python/py-lazy-string.c (lazy_string_object_getset): Likewise.
* python/py-linetable.c (linetable_entry_object_getset): Likewise.
* python/py-objfile.c (objfile_getset): Likewise.
* python/py-progspace.c (pspace_getset): Likewise.
* python/py-record-btrace.c (btpy_insn_getset, btpy_call_getset):
Likewise.
* python/py-record.c (recpy_record_getset): Likewise.
* python/py-symbol.c (symbol_object_getset): Likewise.
* python/py-symtab.c (symtab_object_getset, sal_object_getset):
Likewise.
* python/py-type.c (type_object_getset, field_object_getset):
Likewise.
* python/py-value.c (value_object_getset): Likewise.
2017-04-05 19:21:36 +01:00
|
|
|
|
static gdb_PyGetSetDef type_object_getset[] =
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2018-04-20 15:43:56 -06:00
|
|
|
|
{ "alignof", typy_get_alignof, NULL,
|
|
|
|
|
|
"The alignment of this type, in bytes.", NULL },
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{ "code", typy_get_code, NULL,
|
|
|
|
|
|
"The code for this type.", NULL },
|
2020-04-24 13:40:31 -06:00
|
|
|
|
{ "dynamic", typy_get_dynamic, NULL,
|
|
|
|
|
|
"Whether this type is dynamic.", NULL },
|
2013-12-23 07:18:51 +04:00
|
|
|
|
{ "name", typy_get_name, NULL,
|
|
|
|
|
|
"The name for this type, or None.", NULL },
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{ "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 },
|
2019-05-23 16:37:29 -05:00
|
|
|
|
{ "objfile", typy_get_objfile, NULL,
|
|
|
|
|
|
"The objfile this type was defined in, or None.", NULL },
|
2022-02-25 10:54:04 +00:00
|
|
|
|
{ "is_scalar", typy_is_scalar, nullptr,
|
|
|
|
|
|
"Is this a scalar type?", nullptr },
|
2021-11-30 14:35:44 +00:00
|
|
|
|
{ "is_signed", typy_is_signed, nullptr,
|
2023-07-21 10:33:07 -06:00
|
|
|
|
"Is this a signed type?", nullptr },
|
2023-07-24 07:29:46 -06:00
|
|
|
|
{ "is_array_like", typy_is_array_like, nullptr,
|
|
|
|
|
|
"Is this an array-like type?", nullptr },
|
|
|
|
|
|
{ "is_string_like", typy_is_string_like, nullptr,
|
|
|
|
|
|
"Is this a string-like type?", nullptr },
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{ NULL }
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static PyMethodDef type_object_methods[] =
|
|
|
|
|
|
{
|
2010-08-23 20:21:28 +00:00
|
|
|
|
{ "array", typy_array, METH_VARARGS,
|
2011-12-02 00:27:48 +00:00
|
|
|
|
"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." },
|
2012-08-10 20:26:00 +00:00
|
|
|
|
{ "vector", typy_vector, METH_VARARGS,
|
|
|
|
|
|
"vector ([LOW_BOUND,] HIGH_BOUND) -> Type\n\
|
|
|
|
|
|
Return a type which represents a vector 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.\n\
|
|
|
|
|
|
Vectors differ from arrays in that if the current language has C-style\n\
|
|
|
|
|
|
arrays, vectors don't decay to a pointer to the first element.\n\
|
|
|
|
|
|
They are first class values." },
|
2011-09-28 20:04:52 +00:00
|
|
|
|
{ "__contains__", typy_has_key, METH_VARARGS,
|
|
|
|
|
|
"T.__contains__(k) -> True if T has a field named k, else False" },
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{ "const", typy_const, METH_NOARGS,
|
|
|
|
|
|
"const () -> Type\n\
|
|
|
|
|
|
Return a const variant of this type." },
|
2015-04-28 17:41:09 -07:00
|
|
|
|
{ "optimized_out", typy_optimized_out, METH_NOARGS,
|
|
|
|
|
|
"optimized_out() -> Value\n\
|
|
|
|
|
|
Return optimized out value of this type." },
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{ "fields", typy_fields, METH_NOARGS,
|
2011-09-28 20:04:52 +00:00
|
|
|
|
"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." },
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{ "pointer", typy_pointer, METH_NOARGS,
|
|
|
|
|
|
"pointer () -> Type\n\
|
|
|
|
|
|
Return a type of pointer to this type." },
|
2009-12-08 14:06:04 +00:00
|
|
|
|
{ "range", typy_range, METH_NOARGS,
|
|
|
|
|
|
"range () -> tuple\n\
|
|
|
|
|
|
Return a tuple containing the lower and upper range for this type."},
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{ "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,
|
2010-02-26 09:08:10 +00:00
|
|
|
|
"template_argument (arg, [block]) -> Type\n\
|
2009-05-28 00:47:20 +00:00
|
|
|
|
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." },
|
2011-11-15 21:17:04 +00:00
|
|
|
|
{ "values", typy_values, METH_NOARGS,
|
2011-09-28 20:04:52 +00:00
|
|
|
|
"values () -> list\n\
|
|
|
|
|
|
Return a list holding all the fields of this type.\n\
|
|
|
|
|
|
Each field is a gdb.Field object." },
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{ "volatile", typy_volatile, METH_NOARGS,
|
|
|
|
|
|
"volatile () -> Type\n\
|
|
|
|
|
|
Return a volatile variant of this type" },
|
|
|
|
|
|
{ NULL }
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2011-11-15 21:17:04 +00:00
|
|
|
|
static PyNumberMethods type_object_as_number = {
|
|
|
|
|
|
NULL, /* nb_add */
|
|
|
|
|
|
NULL, /* nb_subtract */
|
|
|
|
|
|
NULL, /* nb_multiply */
|
|
|
|
|
|
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 */
|
2012-12-12 16:47:30 +00:00
|
|
|
|
NULL, /* nb_int */
|
|
|
|
|
|
NULL, /* reserved */
|
2011-11-15 21:17:04 +00:00
|
|
|
|
NULL, /* nb_float */
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2011-09-28 20:04:52 +00:00
|
|
|
|
static PyMappingMethods typy_mapping = {
|
|
|
|
|
|
typy_length,
|
|
|
|
|
|
typy_getitem,
|
|
|
|
|
|
NULL /* no "set" method */
|
|
|
|
|
|
};
|
|
|
|
|
|
|
Fix redefinition errors in C++ mode
In C, we can forward declare static structure instances. That doesn't
work in C++ though. C++ treats these as definitions. So then the
compiler complains about symbol redefinition, like:
src/gdb/elfread.c:1569:29: error: redefinition of ‘const sym_fns elf_sym_fns_lazy_psyms’
src/gdb/elfread.c:53:29: error: ‘const sym_fns elf_sym_fns_lazy_psyms’ previously declared here
The intent of static here is naturally to avoid making these objects
visible outside the compilation unit. The equivalent in C++ would be
to instead define the objects in the anonymous namespace. But given
that it's desirable to leave the codebase compiling as both C and C++
for a while, this just makes the objects extern.
(base_breakpoint_ops is already declared in breakpoint.h, so we can
just remove the forward declare from breakpoint.c)
gdb/ChangeLog:
2015-02-11 Tom Tromey <tromey@redhat.com>
Pedro Alves <palves@redhat.com>
* breakpoint.c (base_breakpoint_ops): Delete.
* dwarf2loc.c (dwarf_expr_ctx_funcs): Make extern.
* elfread.c (elf_sym_fns_gdb_index, elf_sym_fns_lazy_psyms): Make extern.
* guile/guile.c (guile_extension_script_ops, guile_extension_ops): Make extern.
* ppcnbsd-tdep.c (ppcnbsd2_sigtramp): Make extern.
* python/py-arch.c (arch_object_type): Make extern.
* python/py-block.c (block_syms_iterator_object_type): Make extern.
* python/py-bpevent.c (breakpoint_event_object_type): Make extern.
* python/py-cmd.c (cmdpy_object_type): Make extern.
* python/py-continueevent.c (continue_event_object_type)
* python/py-event.h (GDBPY_NEW_EVENT_TYPE): Remove 'qual'
parameter. Update all callers.
* python/py-evtregistry.c (eventregistry_object_type): Make extern.
* python/py-exitedevent.c (exited_event_object_type): Make extern.
* python/py-finishbreakpoint.c (finish_breakpoint_object_type): Make extern.
* python/py-function.c (fnpy_object_type): Make extern.
* python/py-inferior.c (inferior_object_type, membuf_object_type): Make extern.
* python/py-infevents.c (call_pre_event_object_type)
(inferior_call_post_event_object_type).
(memory_changed_event_object_type): Make extern.
* python/py-infthread.c (thread_object_type): Make extern.
* python/py-lazy-string.c (lazy_string_object_type): Make extern.
* python/py-linetable.c (linetable_entry_object_type)
(linetable_object_type, ltpy_iterator_object_type): Make extern.
* python/py-newobjfileevent.c (new_objfile_event_object_type)
(clear_objfiles_event_object_type): Make extern.
* python/py-objfile.c (objfile_object_type): Make extern.
* python/py-param.c (parmpy_object_type): Make extern.
* python/py-progspace.c (pspace_object_type): Make extern.
* python/py-signalevent.c (signal_event_object_type): Make extern.
* python/py-symtab.c (symtab_object_type, sal_object_type): Make extern.
* python/py-type.c (type_object_type, field_object_type)
(type_iterator_object_type): Make extern.
* python/python.c (python_extension_script_ops)
(python_extension_ops): Make extern.
* stap-probe.c (stap_probe_ops): Make extern.
2015-02-11 11:20:21 +00:00
|
|
|
|
PyTypeObject type_object_type =
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2012-12-12 16:47:30 +00:00
|
|
|
|
PyVarObject_HEAD_INIT (NULL, 0)
|
2009-05-28 00:47:20 +00:00
|
|
|
|
"gdb.Type", /*tp_name*/
|
|
|
|
|
|
sizeof (type_object), /*tp_basicsize*/
|
|
|
|
|
|
0, /*tp_itemsize*/
|
2025-03-19 21:12:53 +00:00
|
|
|
|
typy_dealloc, /*tp_dealloc*/
|
2009-05-28 00:47:20 +00:00
|
|
|
|
0, /*tp_print*/
|
|
|
|
|
|
0, /*tp_getattr*/
|
|
|
|
|
|
0, /*tp_setattr*/
|
|
|
|
|
|
0, /*tp_compare*/
|
2023-05-18 00:33:57 -03:00
|
|
|
|
typy_repr, /*tp_repr*/
|
2011-11-15 21:17:04 +00:00
|
|
|
|
&type_object_as_number, /*tp_as_number*/
|
2009-05-28 00:47:20 +00:00
|
|
|
|
0, /*tp_as_sequence*/
|
2011-09-28 20:04:52 +00:00
|
|
|
|
&typy_mapping, /*tp_as_mapping*/
|
2009-05-28 00:47:20 +00:00
|
|
|
|
0, /*tp_hash */
|
|
|
|
|
|
0, /*tp_call*/
|
|
|
|
|
|
typy_str, /*tp_str*/
|
|
|
|
|
|
0, /*tp_getattro*/
|
|
|
|
|
|
0, /*tp_setattro*/
|
|
|
|
|
|
0, /*tp_as_buffer*/
|
gdb/python: remove all uses of Py_TPFLAGS_HAVE_ITER
Python 2 has a bit flag Py_TPFLAGS_HAVE_ITER which can be passed as
part of the tp_flags field when defining a new object type. This flag
is not defined in Python 3 and so we define it to 0 in
python-internal.h (when IS_PY3K is defined).
The meaning of this flag is that the object has the fields tp_iter and
tp_iternext. Note the use of "has" here, the flag says nothing about
the values in those fields, just that the type object has the fields.
In early versions of Python 2 these fields were no part of the
PyTypeObject struct, they were added in version 2.2 (see
https://docs.python.org/release/2.3/api/type-structs.html). And so,
there could be a some code compiled out there which has a PyTypeObject
structure within it that doesn't even have the tp_iter and tp_iternext
fields, attempting to access these fields would be undefined
behaviour.
And so Python added the Py_TPFLAGS_HAVE_ITER flag. If the flag is
present then Python is free to access the tp_iter and tp_iternext
fields.
If we consider GDB then we always assume that the tp_iter and
tp_iternext fields are part of PyTypeObject. If someone was crazy
enough to try and compile GDB against Python 2.1 then we'd get lots of
build errors saying that we were passing too many fields when
initializing PyTypeObject structures. And so, I claim, we can be sure
that GDB will always be compiled with a version of Python that has the
tp_iter and tp_iternext fields in PyTypeObject.
Next we can look at the Py_TPFLAGS_DEFAULT flag. In Python 2, each
time additional fields are added to PyTypeObject a new Py_TPFLAGS_*
flag would be defined to indicate whether those flags are present or
not. And, those new flags would be added to Py_TPFLAGS_DEFAULT. And
so, in the latest version of Python 2 the Py_TPFLAGS_DEFAULT flag
includes Py_TPFLAGS_HAVE_ITER (see
https://docs.python.org/2.7/c-api/typeobj.html).
In GDB we pass Py_TPFLAGS_DEFAULT as part of the tp_flags for all
objects we define.
And so, in this commit, I propose to remove all uses of
Py_TPFLAGS_HAVE_ITER from GDB, it's simply not needed.
There should be no user visible changes after this commit.
2021-09-01 14:24:15 +01:00
|
|
|
|
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
2009-05-28 00:47:20 +00:00
|
|
|
|
"GDB type object", /* tp_doc */
|
|
|
|
|
|
0, /* tp_traverse */
|
|
|
|
|
|
0, /* tp_clear */
|
2010-08-23 20:26:10 +00:00
|
|
|
|
typy_richcompare, /* tp_richcompare */
|
2009-05-28 00:47:20 +00:00
|
|
|
|
0, /* tp_weaklistoffset */
|
2011-09-28 20:04:52 +00:00
|
|
|
|
typy_iter, /* tp_iter */
|
2009-05-28 00:47:20 +00:00
|
|
|
|
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 */
|
|
|
|
|
|
};
|
|
|
|
|
|
|
-Wwrite-strings: Wrap PyGetSetDef for construction with string literals
Unfortunately, PyGetSetDef's 'name' and 'doc' members are 'char *'
instead of 'const char *', meaning that in order to list-initialize
PyGetSetDef arrays using string literals requires writing explicit
'char *' casts. For example:
static PyGetSetDef value_object_getset[] = {
- { "address", valpy_get_address, NULL, "The address of the value.",
+ { (char *) "address", valpy_get_address, NULL,
+ (char *) "The address of the value.",
NULL },
- { "is_optimized_out", valpy_get_is_optimized_out, NULL,
- "Boolean telling whether the value is optimized "
+ { (char *) "is_optimized_out", valpy_get_is_optimized_out, NULL,
+ (char *) "Boolean telling whether the value is optimized "
"out (i.e., not available).",
NULL },
- { "type", valpy_get_type, NULL, "Type of the value.", NULL },
- { "dynamic_type", valpy_get_dynamic_type, NULL,
- "Dynamic type of the value.", NULL },
- { "is_lazy", valpy_get_is_lazy, NULL,
- "Boolean telling whether the value is lazy (not fetched yet\n\
+ { (char *) "type", valpy_get_type, NULL,
+ (char *) "Type of the value.", NULL },
+ { (char *) "dynamic_type", valpy_get_dynamic_type, NULL,
+ (char *) "Dynamic type of the value.", NULL },
+ { (char *) "is_lazy", valpy_get_is_lazy, NULL,
+ (char *) "Boolean telling whether the value is lazy (not fetched yet\n\
from the inferior). A lazy value is fetched when needed, or when\n\
the \"fetch_lazy()\" method is called.", NULL },
{NULL} /* Sentinel */
We have ~20 such arrays, and I first wrote a patch that fixed all of
them like that... It's not pretty...
One way to make these a bit less ugly would be add a new macro that
hides the casts, like:
#define GDBPY_GSDEF(NAME, GET, SET, DOC, CLOSURE) \
{ (char *) NAME, GET, SET, (char *) DOC, CLOSURE }
and then use it like:
static PyGetSetDef value_object_getset[] = {
GDBPY_GSDEF ("address", valpy_get_address, NULL,
"The address of the value.", NULL),
GDBPY_GSDEF ("is_optimized_out", valpy_get_is_optimized_out, NULL,
"Boolean telling whether the value is optimized ", NULL),
{NULL} /* Sentinel */
};
But since we have C++11, which gives us constexpr and list
initialization, I thought of a way that requires no changes where the
arrays are initialized:
We add a new type that extends PyGetSetDef (called gdb_PyGetSetDef),
and add constexpr constructors that accept const 'name' and 'doc', and
then list/aggregate initialization simply "calls" these matching
constructors instead.
I put "calls" in quotes, because given "constexpr", it's all done at
compile time, and there's no overhead either in binary size or at run
time. In fact, we get identical binaries, before/after this change.
Unlike the fixes that fix some old Python API to match the API of more
recent Python, this switches to using explicit "gdb_PyGetSetDef"
everywhere, just to be clear that we are using our own version of it.
gdb/ChangeLog:
2017-04-05 Pedro Alves <palves@redhat.com>
* python/python-internal.h (gdb_PyGetSetDef): New type.
* python/py-block.c (block_object_getset)
(breakpoint_object_getset): Now a gdb_PyGetSetDef array.
* python/py-event.c (event_object_getset)
(finish_breakpoint_object_getset): Likewise.
* python/py-inferior.c (inferior_object_getset): Likewise.
* python/py-infthread.c (thread_object_getset): Likewise.
* python/py-lazy-string.c (lazy_string_object_getset): Likewise.
* python/py-linetable.c (linetable_entry_object_getset): Likewise.
* python/py-objfile.c (objfile_getset): Likewise.
* python/py-progspace.c (pspace_getset): Likewise.
* python/py-record-btrace.c (btpy_insn_getset, btpy_call_getset):
Likewise.
* python/py-record.c (recpy_record_getset): Likewise.
* python/py-symbol.c (symbol_object_getset): Likewise.
* python/py-symtab.c (symtab_object_getset, sal_object_getset):
Likewise.
* python/py-type.c (type_object_getset, field_object_getset):
Likewise.
* python/py-value.c (value_object_getset): Likewise.
2017-04-05 19:21:36 +01:00
|
|
|
|
static gdb_PyGetSetDef field_object_getset[] =
|
2012-02-17 19:24:27 +00:00
|
|
|
|
{
|
2026-02-27 14:13:26 +00:00
|
|
|
|
gdbpy_dict_wrapper_cfg_dict_getter ("field"),
|
|
|
|
|
|
{ nullptr }
|
2012-02-17 19:24:27 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
Fix redefinition errors in C++ mode
In C, we can forward declare static structure instances. That doesn't
work in C++ though. C++ treats these as definitions. So then the
compiler complains about symbol redefinition, like:
src/gdb/elfread.c:1569:29: error: redefinition of ‘const sym_fns elf_sym_fns_lazy_psyms’
src/gdb/elfread.c:53:29: error: ‘const sym_fns elf_sym_fns_lazy_psyms’ previously declared here
The intent of static here is naturally to avoid making these objects
visible outside the compilation unit. The equivalent in C++ would be
to instead define the objects in the anonymous namespace. But given
that it's desirable to leave the codebase compiling as both C and C++
for a while, this just makes the objects extern.
(base_breakpoint_ops is already declared in breakpoint.h, so we can
just remove the forward declare from breakpoint.c)
gdb/ChangeLog:
2015-02-11 Tom Tromey <tromey@redhat.com>
Pedro Alves <palves@redhat.com>
* breakpoint.c (base_breakpoint_ops): Delete.
* dwarf2loc.c (dwarf_expr_ctx_funcs): Make extern.
* elfread.c (elf_sym_fns_gdb_index, elf_sym_fns_lazy_psyms): Make extern.
* guile/guile.c (guile_extension_script_ops, guile_extension_ops): Make extern.
* ppcnbsd-tdep.c (ppcnbsd2_sigtramp): Make extern.
* python/py-arch.c (arch_object_type): Make extern.
* python/py-block.c (block_syms_iterator_object_type): Make extern.
* python/py-bpevent.c (breakpoint_event_object_type): Make extern.
* python/py-cmd.c (cmdpy_object_type): Make extern.
* python/py-continueevent.c (continue_event_object_type)
* python/py-event.h (GDBPY_NEW_EVENT_TYPE): Remove 'qual'
parameter. Update all callers.
* python/py-evtregistry.c (eventregistry_object_type): Make extern.
* python/py-exitedevent.c (exited_event_object_type): Make extern.
* python/py-finishbreakpoint.c (finish_breakpoint_object_type): Make extern.
* python/py-function.c (fnpy_object_type): Make extern.
* python/py-inferior.c (inferior_object_type, membuf_object_type): Make extern.
* python/py-infevents.c (call_pre_event_object_type)
(inferior_call_post_event_object_type).
(memory_changed_event_object_type): Make extern.
* python/py-infthread.c (thread_object_type): Make extern.
* python/py-lazy-string.c (lazy_string_object_type): Make extern.
* python/py-linetable.c (linetable_entry_object_type)
(linetable_object_type, ltpy_iterator_object_type): Make extern.
* python/py-newobjfileevent.c (new_objfile_event_object_type)
(clear_objfiles_event_object_type): Make extern.
* python/py-objfile.c (objfile_object_type): Make extern.
* python/py-param.c (parmpy_object_type): Make extern.
* python/py-progspace.c (pspace_object_type): Make extern.
* python/py-signalevent.c (signal_event_object_type): Make extern.
* python/py-symtab.c (symtab_object_type, sal_object_type): Make extern.
* python/py-type.c (type_object_type, field_object_type)
(type_iterator_object_type): Make extern.
* python/python.c (python_extension_script_ops)
(python_extension_ops): Make extern.
* stap-probe.c (stap_probe_ops): Make extern.
2015-02-11 11:20:21 +00:00
|
|
|
|
PyTypeObject field_object_type =
|
2009-05-28 00:47:20 +00:00
|
|
|
|
{
|
2012-12-12 16:47:30 +00:00
|
|
|
|
PyVarObject_HEAD_INIT (NULL, 0)
|
2009-05-28 00:47:20 +00:00
|
|
|
|
"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*/
|
2026-02-27 14:13:26 +00:00
|
|
|
|
gdbpy_dict_wrapper_getsetattro,
|
2009-05-28 00:47:20 +00:00
|
|
|
|
0, /*tp_as_buffer*/
|
gdb/python: remove all uses of Py_TPFLAGS_HAVE_ITER
Python 2 has a bit flag Py_TPFLAGS_HAVE_ITER which can be passed as
part of the tp_flags field when defining a new object type. This flag
is not defined in Python 3 and so we define it to 0 in
python-internal.h (when IS_PY3K is defined).
The meaning of this flag is that the object has the fields tp_iter and
tp_iternext. Note the use of "has" here, the flag says nothing about
the values in those fields, just that the type object has the fields.
In early versions of Python 2 these fields were no part of the
PyTypeObject struct, they were added in version 2.2 (see
https://docs.python.org/release/2.3/api/type-structs.html). And so,
there could be a some code compiled out there which has a PyTypeObject
structure within it that doesn't even have the tp_iter and tp_iternext
fields, attempting to access these fields would be undefined
behaviour.
And so Python added the Py_TPFLAGS_HAVE_ITER flag. If the flag is
present then Python is free to access the tp_iter and tp_iternext
fields.
If we consider GDB then we always assume that the tp_iter and
tp_iternext fields are part of PyTypeObject. If someone was crazy
enough to try and compile GDB against Python 2.1 then we'd get lots of
build errors saying that we were passing too many fields when
initializing PyTypeObject structures. And so, I claim, we can be sure
that GDB will always be compiled with a version of Python that has the
tp_iter and tp_iternext fields in PyTypeObject.
Next we can look at the Py_TPFLAGS_DEFAULT flag. In Python 2, each
time additional fields are added to PyTypeObject a new Py_TPFLAGS_*
flag would be defined to indicate whether those flags are present or
not. And, those new flags would be added to Py_TPFLAGS_DEFAULT. And
so, in the latest version of Python 2 the Py_TPFLAGS_DEFAULT flag
includes Py_TPFLAGS_HAVE_ITER (see
https://docs.python.org/2.7/c-api/typeobj.html).
In GDB we pass Py_TPFLAGS_DEFAULT as part of the tp_flags for all
objects we define.
And so, in this commit, I propose to remove all uses of
Py_TPFLAGS_HAVE_ITER from GDB, it's simply not needed.
There should be no user visible changes after this commit.
2021-09-01 14:24:15 +01:00
|
|
|
|
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
2009-05-28 00:47:20 +00:00
|
|
|
|
"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 */
|
2012-02-17 19:24:27 +00:00
|
|
|
|
field_object_getset, /* tp_getset */
|
2009-05-28 00:47:20 +00:00
|
|
|
|
0, /* tp_base */
|
|
|
|
|
|
0, /* tp_dict */
|
|
|
|
|
|
0, /* tp_descr_get */
|
|
|
|
|
|
0, /* tp_descr_set */
|
gdb: new setters and getters for __dict__, and attributes
GDB is currently using the Python unlimited API. Migrating the codebase
to the Python limited API would have for benefit to make a GDB build
artifacts compatible with older and newer versions of Python that they
were built with.
This patch prepares the ground for migrating the existing C extension
types from static types to heap-allocated ones, by removing the
dependency on tp_dictoffset, which is unavailable when using the limited
API.
One of the most common incompatibilities in the current static type
declarations is the tp_dictoffset slot, which specifies the dictionary
offset within the instance structure. Historically, the unlimited
API has provided two approaches to supply a dictionary for __dict__:
* A managed dictionary.
Setting Py_TPFLAGS_MANAGED_DICT in tp_flags indicates that the
instances of the type have a __dict__ attribute, and that the
dictionary is managed by Python.
According to the Python documentation, this is the recommended approach.
However, this flag was introduced in 3.12, together with
PyObject_VisitManagedDict() and PyObject_ClearManagedDict(), neither
of which is part of the limited API (at least for now). As a result,
this recommended approach is not viable in the context of the limited
API.
* An instance dictionary, for which the offset in the instance is
provided via tp_dictoffset.
According to the Python documentation, this "tp slot" is on the
deprecation path, and Py_TPFLAGS_MANAGED_DICT should be used instead.
Given the age of the GDB codebase and the requirement to support older
Python versions (>= 3.4), no need to argue that today, the implementation
of __dict__ relies on tp_dictoffset. However, in the context of the
limited API, PyType_Slot does not provide a Py_tp_dictoffset member, so
another approach is needed to provide __dict__ to instances of C extension
types.
Given the constraints of the limited API, the proposed solution consists
in providing a dictionary through a common base class, gdbpy__dict__wrapper.
This helper class owns a dictionary member corresponding to __dict__, and
any C extension type requiring a __dict__ must inherit from it. Since
extension object must also be convertible to PyObject, this wrapper class
publicly inherits from PyObject as well.
Access to the dictionary is provided via a custom getter defined in a
PyGetSetDef, similarily to what was previously done with gdb_py_generic_dict().
Because __dict__ participates in attribute look-up, and since this dictionary
is neither managed by Python nor exposed via tp_dictoffset, custom
implementations of tp_getattro and tp_setattro are required to correctly
redirect attribute look-ups to the dictionary. These custom implementations
— equivalent to PyObject_GenericGetAttr() and PyObject_GenericSetAttr() —
must be installed via tp_getattro / tp_setattro for static types, or
Py_tp_getattro / Py_tp_setattro for heap-allocated types.
- gdbpy__dict__wrapper: a base class for C extension objects that own a
__dict__.
- gdb_py_generic_dict_getter: a __dict__ getter for extension types
derived from gdbpy__dict__wrapper.
- gdb_py_generic_getattro: equivalent of PyObject_GenericGetAttr, but
fixes the look-up of __dict__.
- gdb_py_generic_setattro: equivalent of PyObject_GenericSetAttr, but
fixes the look-up of __dict__.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23830
Approved-By: Tom Tromey <tom@tromey.com>
2025-07-17 18:36:41 +01:00
|
|
|
|
0, /* tp_dictoffset */
|
2009-05-28 00:47:20 +00:00
|
|
|
|
0, /* tp_init */
|
|
|
|
|
|
0, /* tp_alloc */
|
|
|
|
|
|
0, /* tp_new */
|
|
|
|
|
|
};
|
2011-09-28 20:04:52 +00:00
|
|
|
|
|
Fix redefinition errors in C++ mode
In C, we can forward declare static structure instances. That doesn't
work in C++ though. C++ treats these as definitions. So then the
compiler complains about symbol redefinition, like:
src/gdb/elfread.c:1569:29: error: redefinition of ‘const sym_fns elf_sym_fns_lazy_psyms’
src/gdb/elfread.c:53:29: error: ‘const sym_fns elf_sym_fns_lazy_psyms’ previously declared here
The intent of static here is naturally to avoid making these objects
visible outside the compilation unit. The equivalent in C++ would be
to instead define the objects in the anonymous namespace. But given
that it's desirable to leave the codebase compiling as both C and C++
for a while, this just makes the objects extern.
(base_breakpoint_ops is already declared in breakpoint.h, so we can
just remove the forward declare from breakpoint.c)
gdb/ChangeLog:
2015-02-11 Tom Tromey <tromey@redhat.com>
Pedro Alves <palves@redhat.com>
* breakpoint.c (base_breakpoint_ops): Delete.
* dwarf2loc.c (dwarf_expr_ctx_funcs): Make extern.
* elfread.c (elf_sym_fns_gdb_index, elf_sym_fns_lazy_psyms): Make extern.
* guile/guile.c (guile_extension_script_ops, guile_extension_ops): Make extern.
* ppcnbsd-tdep.c (ppcnbsd2_sigtramp): Make extern.
* python/py-arch.c (arch_object_type): Make extern.
* python/py-block.c (block_syms_iterator_object_type): Make extern.
* python/py-bpevent.c (breakpoint_event_object_type): Make extern.
* python/py-cmd.c (cmdpy_object_type): Make extern.
* python/py-continueevent.c (continue_event_object_type)
* python/py-event.h (GDBPY_NEW_EVENT_TYPE): Remove 'qual'
parameter. Update all callers.
* python/py-evtregistry.c (eventregistry_object_type): Make extern.
* python/py-exitedevent.c (exited_event_object_type): Make extern.
* python/py-finishbreakpoint.c (finish_breakpoint_object_type): Make extern.
* python/py-function.c (fnpy_object_type): Make extern.
* python/py-inferior.c (inferior_object_type, membuf_object_type): Make extern.
* python/py-infevents.c (call_pre_event_object_type)
(inferior_call_post_event_object_type).
(memory_changed_event_object_type): Make extern.
* python/py-infthread.c (thread_object_type): Make extern.
* python/py-lazy-string.c (lazy_string_object_type): Make extern.
* python/py-linetable.c (linetable_entry_object_type)
(linetable_object_type, ltpy_iterator_object_type): Make extern.
* python/py-newobjfileevent.c (new_objfile_event_object_type)
(clear_objfiles_event_object_type): Make extern.
* python/py-objfile.c (objfile_object_type): Make extern.
* python/py-param.c (parmpy_object_type): Make extern.
* python/py-progspace.c (pspace_object_type): Make extern.
* python/py-signalevent.c (signal_event_object_type): Make extern.
* python/py-symtab.c (symtab_object_type, sal_object_type): Make extern.
* python/py-type.c (type_object_type, field_object_type)
(type_iterator_object_type): Make extern.
* python/python.c (python_extension_script_ops)
(python_extension_ops): Make extern.
* stap-probe.c (stap_probe_ops): Make extern.
2015-02-11 11:20:21 +00:00
|
|
|
|
PyTypeObject type_iterator_object_type = {
|
2012-12-12 16:47:30 +00:00
|
|
|
|
PyVarObject_HEAD_INIT (NULL, 0)
|
2011-09-28 20:04:52 +00:00
|
|
|
|
"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*/
|
gdb/python: remove all uses of Py_TPFLAGS_HAVE_ITER
Python 2 has a bit flag Py_TPFLAGS_HAVE_ITER which can be passed as
part of the tp_flags field when defining a new object type. This flag
is not defined in Python 3 and so we define it to 0 in
python-internal.h (when IS_PY3K is defined).
The meaning of this flag is that the object has the fields tp_iter and
tp_iternext. Note the use of "has" here, the flag says nothing about
the values in those fields, just that the type object has the fields.
In early versions of Python 2 these fields were no part of the
PyTypeObject struct, they were added in version 2.2 (see
https://docs.python.org/release/2.3/api/type-structs.html). And so,
there could be a some code compiled out there which has a PyTypeObject
structure within it that doesn't even have the tp_iter and tp_iternext
fields, attempting to access these fields would be undefined
behaviour.
And so Python added the Py_TPFLAGS_HAVE_ITER flag. If the flag is
present then Python is free to access the tp_iter and tp_iternext
fields.
If we consider GDB then we always assume that the tp_iter and
tp_iternext fields are part of PyTypeObject. If someone was crazy
enough to try and compile GDB against Python 2.1 then we'd get lots of
build errors saying that we were passing too many fields when
initializing PyTypeObject structures. And so, I claim, we can be sure
that GDB will always be compiled with a version of Python that has the
tp_iter and tp_iternext fields in PyTypeObject.
Next we can look at the Py_TPFLAGS_DEFAULT flag. In Python 2, each
time additional fields are added to PyTypeObject a new Py_TPFLAGS_*
flag would be defined to indicate whether those flags are present or
not. And, those new flags would be added to Py_TPFLAGS_DEFAULT. And
so, in the latest version of Python 2 the Py_TPFLAGS_DEFAULT flag
includes Py_TPFLAGS_HAVE_ITER (see
https://docs.python.org/2.7/c-api/typeobj.html).
In GDB we pass Py_TPFLAGS_DEFAULT as part of the tp_flags for all
objects we define.
And so, in this commit, I propose to remove all uses of
Py_TPFLAGS_HAVE_ITER from GDB, it's simply not needed.
There should be no user visible changes after this commit.
2021-09-01 14:24:15 +01:00
|
|
|
|
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
2011-09-28 20:04:52 +00:00
|
|
|
|
"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 */
|
|
|
|
|
|
};
|