2010-01-14 08:03:37 +00:00
|
|
|
|
/* Python interface to lazy strings.
|
|
|
|
|
|
|
2025-04-02 13:30:10 -06:00
|
|
|
|
Copyright (C) 2010-2025 Free Software Foundation, Inc.
|
2010-01-14 08:03:37 +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 "python-internal.h"
|
|
|
|
|
|
#include "charset.h"
|
|
|
|
|
|
#include "value.h"
|
|
|
|
|
|
#include "valprint.h"
|
|
|
|
|
|
#include "language.h"
|
|
|
|
|
|
|
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
|
|
|
|
struct lazy_string_object {
|
2010-01-14 08:03:37 +00:00
|
|
|
|
PyObject_HEAD
|
2017-03-15 15:35:13 -07:00
|
|
|
|
|
2010-01-14 08:03:37 +00:00
|
|
|
|
/* Holds the address of the lazy string. */
|
|
|
|
|
|
CORE_ADDR address;
|
|
|
|
|
|
|
|
|
|
|
|
/* Holds the encoding that will be applied to the string
|
|
|
|
|
|
when the string is printed by GDB. If the encoding is set
|
|
|
|
|
|
to None then GDB will select the most appropriate
|
2025-03-06 23:21:54 +01:00
|
|
|
|
encoding when the string is printed. */
|
2010-01-14 08:03:37 +00:00
|
|
|
|
char *encoding;
|
|
|
|
|
|
|
2017-03-15 15:35:13 -07:00
|
|
|
|
/* If TYPE is an array: If the length is known, then this value is the
|
|
|
|
|
|
array's length, otherwise it is -1.
|
|
|
|
|
|
If TYPE is not an array: Then this value represents the string's length.
|
|
|
|
|
|
In either case, if the value is -1 then the string will be fetched and
|
|
|
|
|
|
encoded up to the first null of appropriate width. */
|
2010-01-14 08:03:37 +00:00
|
|
|
|
long length;
|
|
|
|
|
|
|
2017-03-15 15:35:13 -07:00
|
|
|
|
/* This attribute holds the type of the string.
|
|
|
|
|
|
For example if the lazy string was created from a C "char*" then TYPE
|
|
|
|
|
|
represents a C "char*".
|
|
|
|
|
|
To get the type of the character in the string call
|
|
|
|
|
|
stpy_lazy_string_elt_type.
|
|
|
|
|
|
This is recorded as a PyObject so that we take advantage of support for
|
|
|
|
|
|
preserving the type should its owning objfile go away. */
|
|
|
|
|
|
PyObject *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
|
|
|
|
};
|
2010-01-14 08:03:37 +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
|
|
|
|
extern PyTypeObject lazy_string_object_type
|
2013-05-20 20:09:01 +00:00
|
|
|
|
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("lazy_string_object");
|
2010-01-14 08:03:37 +00:00
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
stpy_get_address (PyObject *self, void *closure)
|
|
|
|
|
|
{
|
|
|
|
|
|
lazy_string_object *self_string = (lazy_string_object *) self;
|
2010-05-17 21:23:25 +00:00
|
|
|
|
|
2020-09-15 11:08:56 -06:00
|
|
|
|
return gdb_py_object_from_ulongest (self_string->address).release ();
|
2010-01-14 08:03:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
stpy_get_encoding (PyObject *self, void *closure)
|
|
|
|
|
|
{
|
|
|
|
|
|
lazy_string_object *self_string = (lazy_string_object *) self;
|
|
|
|
|
|
PyObject *result;
|
|
|
|
|
|
|
|
|
|
|
|
/* An encoding can be set to NULL by the user, so check before
|
|
|
|
|
|
attempting a Python FromString call. If NULL return Py_None. */
|
|
|
|
|
|
if (self_string->encoding)
|
2022-03-21 10:07:41 -04:00
|
|
|
|
result = PyUnicode_FromString (self_string->encoding);
|
2010-01-14 08:03:37 +00:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
result = Py_None;
|
|
|
|
|
|
Py_INCREF (result);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
stpy_get_length (PyObject *self, void *closure)
|
|
|
|
|
|
{
|
|
|
|
|
|
lazy_string_object *self_string = (lazy_string_object *) self;
|
2010-05-17 21:23:25 +00:00
|
|
|
|
|
2020-09-15 11:08:56 -06:00
|
|
|
|
return gdb_py_object_from_longest (self_string->length).release ();
|
2010-01-14 08:03:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-03-01 21:06:54 +00:00
|
|
|
|
static PyObject *
|
2010-01-14 08:03:37 +00:00
|
|
|
|
stpy_get_type (PyObject *self, void *closure)
|
|
|
|
|
|
{
|
|
|
|
|
|
lazy_string_object *str_obj = (lazy_string_object *) self;
|
2010-05-17 21:23:25 +00:00
|
|
|
|
|
2017-03-15 15:35:13 -07:00
|
|
|
|
Py_INCREF (str_obj->type);
|
|
|
|
|
|
return str_obj->type;
|
2010-01-14 08:03:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
2017-03-15 15:35:13 -07:00
|
|
|
|
stpy_convert_to_value (PyObject *self, PyObject *args)
|
2010-01-14 08:03:37 +00:00
|
|
|
|
{
|
|
|
|
|
|
lazy_string_object *self_string = (lazy_string_object *) self;
|
|
|
|
|
|
|
2010-04-08 10:28:42 +00:00
|
|
|
|
if (self_string->address == 0)
|
|
|
|
|
|
{
|
2015-05-26 16:13:04 -07:00
|
|
|
|
PyErr_SetString (gdbpy_gdb_memory_error,
|
2010-04-14 13:18:55 +00:00
|
|
|
|
_("Cannot create a value from NULL."));
|
2010-04-08 10:28:42 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
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
|
|
|
|
PyObject *result = nullptr;
|
2019-04-03 16:02:42 -06:00
|
|
|
|
try
|
2011-10-27 09:14:27 +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;
|
|
|
|
|
|
|
2017-03-15 15:35:13 -07:00
|
|
|
|
struct type *type = type_object_to_type (self_string->type);
|
|
|
|
|
|
struct type *realtype;
|
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
|
|
|
|
struct value *val;
|
2017-03-15 15:35:13 -07:00
|
|
|
|
|
|
|
|
|
|
gdb_assert (type != NULL);
|
|
|
|
|
|
realtype = check_typedef (type);
|
2020-05-14 13:46:38 -04:00
|
|
|
|
switch (realtype->code ())
|
2017-03-15 15:35:13 -07:00
|
|
|
|
{
|
|
|
|
|
|
case TYPE_CODE_PTR:
|
|
|
|
|
|
/* If a length is specified we need to convert this to an array
|
|
|
|
|
|
of the specified size. */
|
|
|
|
|
|
if (self_string->length != -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
/* PR 20786: There's no way to specify an array of length zero.
|
|
|
|
|
|
Record a length of [0,-1] which is how Ada does it. Anything
|
|
|
|
|
|
we do is broken, but this is one possible solution. */
|
2022-07-30 22:43:54 -04:00
|
|
|
|
type = lookup_array_range_type (realtype->target_type (),
|
2017-03-15 15:35:13 -07:00
|
|
|
|
0, self_string->length - 1);
|
|
|
|
|
|
val = value_at_lazy (type, self_string->address);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
val = value_from_pointer (type, self_string->address);
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
val = value_at_lazy (type, self_string->address);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
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
|
|
|
|
|
|
|
|
|
|
result = value_to_value_object (val);
|
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
|
|
|
|
}
|
2011-10-27 09:14:27 +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
|
|
|
|
return result;
|
2010-01-14 08:03:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
stpy_dealloc (PyObject *self)
|
|
|
|
|
|
{
|
|
|
|
|
|
lazy_string_object *self_string = (lazy_string_object *) self;
|
2010-05-17 21:23:25 +00:00
|
|
|
|
|
2010-01-14 08:03:37 +00:00
|
|
|
|
xfree (self_string->encoding);
|
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 (self)->tp_free (self);
|
2010-01-14 08:03:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-03-15 15:35:13 -07:00
|
|
|
|
/* Low level routine to create a <gdb.LazyString> object.
|
|
|
|
|
|
|
|
|
|
|
|
Note: If TYPE is an array, LENGTH either must be -1 (meaning to use the
|
|
|
|
|
|
size of the array, which may itself be unknown in which case a length of
|
|
|
|
|
|
-1 is still used) or must be the length of the array. */
|
|
|
|
|
|
|
2010-01-14 08:03:37 +00:00
|
|
|
|
PyObject *
|
|
|
|
|
|
gdbpy_create_lazy_string_object (CORE_ADDR address, long length,
|
2017-03-15 15:35:13 -07:00
|
|
|
|
const char *encoding, struct type *type)
|
2010-01-14 08:03:37 +00:00
|
|
|
|
{
|
|
|
|
|
|
lazy_string_object *str_obj = NULL;
|
2017-03-15 15:35:13 -07:00
|
|
|
|
struct type *realtype;
|
|
|
|
|
|
|
|
|
|
|
|
if (length < -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
PyErr_SetString (PyExc_ValueError, _("Invalid length."));
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
2010-01-14 08:03:37 +00:00
|
|
|
|
|
|
|
|
|
|
if (!type)
|
|
|
|
|
|
{
|
|
|
|
|
|
PyErr_SetString (PyExc_RuntimeError,
|
2010-04-14 13:18:55 +00:00
|
|
|
|
_("A lazy string's type cannot be NULL."));
|
2010-01-14 08:03:37 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-03-15 15:35:13 -07:00
|
|
|
|
realtype = check_typedef (type);
|
2020-05-14 13:46:38 -04:00
|
|
|
|
switch (realtype->code ())
|
2017-03-15 15:35:13 -07:00
|
|
|
|
{
|
|
|
|
|
|
case TYPE_CODE_ARRAY:
|
|
|
|
|
|
{
|
|
|
|
|
|
LONGEST array_length = -1;
|
|
|
|
|
|
LONGEST low_bound, high_bound;
|
|
|
|
|
|
|
|
|
|
|
|
if (get_array_bounds (realtype, &low_bound, &high_bound))
|
|
|
|
|
|
array_length = high_bound - low_bound + 1;
|
|
|
|
|
|
if (length == -1)
|
|
|
|
|
|
length = array_length;
|
|
|
|
|
|
else if (length != array_length)
|
|
|
|
|
|
{
|
|
|
|
|
|
PyErr_SetString (PyExc_ValueError, _("Invalid length."));
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2024-11-19 07:34:26 -07:00
|
|
|
|
|
|
|
|
|
|
case TYPE_CODE_PTR:
|
|
|
|
|
|
if (address == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (length > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
PyErr_SetString (gdbpy_gdb_memory_error,
|
|
|
|
|
|
_("Cannot create a lazy string with address 0x0, " \
|
|
|
|
|
|
"and a non-zero length."));
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
length = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
gdb_assert_not_reached ("invalid type in gdbpy_create_lazy_string_object");
|
2017-03-15 15:35:13 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2010-01-14 08:03:37 +00:00
|
|
|
|
str_obj = PyObject_New (lazy_string_object, &lazy_string_object_type);
|
|
|
|
|
|
if (!str_obj)
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
|
|
str_obj->address = address;
|
|
|
|
|
|
str_obj->length = length;
|
|
|
|
|
|
if (encoding == NULL || !strcmp (encoding, ""))
|
|
|
|
|
|
str_obj->encoding = NULL;
|
|
|
|
|
|
else
|
|
|
|
|
|
str_obj->encoding = xstrdup (encoding);
|
2017-03-15 15:35:13 -07:00
|
|
|
|
str_obj->type = type_to_type_object (type);
|
2010-01-14 08:03:37 +00:00
|
|
|
|
|
|
|
|
|
|
return (PyObject *) str_obj;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
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
|
|
|
|
static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
|
2010-01-14 08:03:37 +00:00
|
|
|
|
gdbpy_initialize_lazy_string (void)
|
|
|
|
|
|
{
|
2024-09-11 10:35:20 -06:00
|
|
|
|
return gdbpy_type_ready (&lazy_string_object_type);
|
2010-01-14 08:03:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Determine whether the printer object pointed to by OBJ is a
|
|
|
|
|
|
Python lazy string. */
|
|
|
|
|
|
int
|
|
|
|
|
|
gdbpy_is_lazy_string (PyObject *result)
|
|
|
|
|
|
{
|
|
|
|
|
|
return PyObject_TypeCheck (result, &lazy_string_object_type);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-03-15 15:35:13 -07:00
|
|
|
|
/* Return the type of a character in lazy string LAZY. */
|
|
|
|
|
|
|
|
|
|
|
|
static struct type *
|
|
|
|
|
|
stpy_lazy_string_elt_type (lazy_string_object *lazy)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct type *type = type_object_to_type (lazy->type);
|
|
|
|
|
|
struct type *realtype;
|
|
|
|
|
|
|
|
|
|
|
|
gdb_assert (type != NULL);
|
|
|
|
|
|
realtype = check_typedef (type);
|
|
|
|
|
|
|
2020-05-14 13:46:38 -04:00
|
|
|
|
switch (realtype->code ())
|
2017-03-15 15:35:13 -07:00
|
|
|
|
{
|
|
|
|
|
|
case TYPE_CODE_PTR:
|
|
|
|
|
|
case TYPE_CODE_ARRAY:
|
2024-05-26 10:41:12 +02:00
|
|
|
|
return check_typedef (realtype->target_type ());
|
2017-03-15 15:35:13 -07:00
|
|
|
|
default:
|
2024-11-18 13:47:22 -07:00
|
|
|
|
gdb_assert_not_reached ("invalid lazy string");
|
2017-03-15 15:35:13 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-10-15 18:54:13 +00:00
|
|
|
|
/* Extract the parameters from the lazy string object STRING.
|
2016-11-12 11:48:48 -07:00
|
|
|
|
ENCODING may be set to NULL, if no encoding is found. */
|
2010-01-14 08:03:37 +00:00
|
|
|
|
|
2010-10-15 18:54:13 +00:00
|
|
|
|
void
|
|
|
|
|
|
gdbpy_extract_lazy_string (PyObject *string, CORE_ADDR *addr,
|
2017-03-15 15:35:13 -07:00
|
|
|
|
struct type **str_elt_type,
|
2016-11-12 11:48:48 -07:00
|
|
|
|
long *length,
|
|
|
|
|
|
gdb::unique_xmalloc_ptr<char> *encoding)
|
2010-10-15 18:54:13 +00:00
|
|
|
|
{
|
|
|
|
|
|
lazy_string_object *lazy;
|
2010-01-14 08:03:37 +00:00
|
|
|
|
|
2010-10-15 18:54:13 +00:00
|
|
|
|
gdb_assert (gdbpy_is_lazy_string (string));
|
2010-01-14 08:03:37 +00:00
|
|
|
|
|
2010-10-15 18:54:13 +00:00
|
|
|
|
lazy = (lazy_string_object *) string;
|
2010-01-14 08:03:37 +00:00
|
|
|
|
|
2010-10-15 18:54:13 +00:00
|
|
|
|
*addr = lazy->address;
|
2017-03-15 15:35:13 -07:00
|
|
|
|
*str_elt_type = stpy_lazy_string_elt_type (lazy);
|
2010-10-15 18:54:13 +00:00
|
|
|
|
*length = lazy->length;
|
2016-11-12 11:48:48 -07:00
|
|
|
|
encoding->reset (lazy->encoding ? xstrdup (lazy->encoding) : NULL);
|
2010-01-14 08:03:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-10-04 11:22:05 -06:00
|
|
|
|
/* __str__ for LazyString. */
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
|
stpy_str (PyObject *self)
|
|
|
|
|
|
{
|
|
|
|
|
|
lazy_string_object *str = (lazy_string_object *) self;
|
|
|
|
|
|
|
|
|
|
|
|
struct value_print_options opts;
|
|
|
|
|
|
get_user_print_options (&opts);
|
|
|
|
|
|
opts.addressprint = false;
|
|
|
|
|
|
|
|
|
|
|
|
string_file stream;
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
struct type *type = stpy_lazy_string_elt_type (str);
|
|
|
|
|
|
val_print_string (type, str->encoding, str->address, str->length,
|
|
|
|
|
|
&stream, &opts);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (const gdb_exception &exc)
|
|
|
|
|
|
{
|
2024-09-24 13:06:32 +02:00
|
|
|
|
return gdbpy_handle_gdb_exception (nullptr, exc);
|
2023-10-04 11:22:05 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return host_string_to_python_string (stream.c_str ()).release ();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
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_lazy_string);
|
|
|
|
|
|
|
2010-01-14 08:03:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static PyMethodDef lazy_string_object_methods[] = {
|
|
|
|
|
|
{ "value", stpy_convert_to_value, METH_NOARGS,
|
|
|
|
|
|
"Create a (lazy) value that contains a pointer to the string." },
|
|
|
|
|
|
{NULL} /* Sentinel */
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
-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 lazy_string_object_getset[] = {
|
2010-01-14 08:03:37 +00:00
|
|
|
|
{ "address", stpy_get_address, NULL, "Address of the string.", NULL },
|
|
|
|
|
|
{ "encoding", stpy_get_encoding, NULL, "Encoding of the string.", NULL },
|
|
|
|
|
|
{ "length", stpy_get_length, NULL, "Length of the string.", NULL },
|
|
|
|
|
|
{ "type", stpy_get_type, NULL, "Type associated with the string.", NULL },
|
|
|
|
|
|
{ NULL } /* Sentinel */
|
|
|
|
|
|
};
|
|
|
|
|
|
|
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 lazy_string_object_type = {
|
2012-12-12 16:47:30 +00:00
|
|
|
|
PyVarObject_HEAD_INIT (NULL, 0)
|
2010-01-14 08:03:37 +00:00
|
|
|
|
"gdb.LazyString", /*tp_name*/
|
|
|
|
|
|
sizeof (lazy_string_object), /*tp_basicsize*/
|
|
|
|
|
|
0, /*tp_itemsize*/
|
|
|
|
|
|
stpy_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*/
|
2023-10-04 11:22:05 -06:00
|
|
|
|
stpy_str, /*tp_str*/
|
2010-01-14 08:03:37 +00:00
|
|
|
|
0, /*tp_getattro*/
|
|
|
|
|
|
0, /*tp_setattro*/
|
|
|
|
|
|
0, /*tp_as_buffer*/
|
|
|
|
|
|
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
|
|
|
|
|
"GDB lazy string object", /* tp_doc */
|
|
|
|
|
|
0, /* tp_traverse */
|
|
|
|
|
|
0, /* tp_clear */
|
|
|
|
|
|
0, /* tp_richcompare */
|
|
|
|
|
|
0, /* tp_weaklistoffset */
|
|
|
|
|
|
0, /* tp_iter */
|
|
|
|
|
|
0, /* tp_iternext */
|
|
|
|
|
|
lazy_string_object_methods, /* tp_methods */
|
|
|
|
|
|
0, /* tp_members */
|
|
|
|
|
|
lazy_string_object_getset /* tp_getset */
|
|
|
|
|
|
};
|