Commit graph

1831 commits

Author SHA1 Message Date
Tom Tromey
bbc133a308 Hold the GIL while clearing gdbpy_reggroup_object_map
Tom de Vries pointed out that a certain Python test left a core file.
Looking into this, I think the problem is that the GIL is not held
when gdbpy_reggroup_object_map is destroyed.

This patch changes the code to explicitly clear the global while
holding the GIL.  This fixed the crash for me.

This also adds a comment to gdbpy_initialize_file to explicitly
mention that the GIL is held while the finalizers are run.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34013
Reviewed-By: Tom de Vries <tdevries@suse.de>
2026-03-25 11:12:14 -06:00
Jan Vrany
1a10ac9995 gdb/python: add property ranges to gdb.Block object
This commit adds a new property - ranges - to gdb.Block object. It holds
a tuple of ranges for that block. Each range is a tuple of (start, end)
address. For contiguous blocks it contains only one range.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Approved-By: Tom Tromey <tom@tromey.com>
2026-03-25 15:06:23 +00:00
Andrew Burgess
285072c3d5 gdb/python: allow Architecture.disassemble to give styled output
Extend the Architecture.disassemble API to allow the user to request
styled disassembler output via a new styling argument.  A user can now
write:

  insn = arch.disassemble(address, styling = True)

The instruction strings returned within INSN will contain ANSI escape
sequences so long as 'set style enabled on' is in effect.  This means
that the user's personal settings (disabling styling) will override a
GDB extension that requests styled disassembler output.  I think this
makes sense.

The default for the styling argument is False, this maintains the
current unstyled output as default.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Approved-By: Tom Tromey <tom@tromey.com>
2026-03-23 10:15:11 +00:00
Andrew Burgess
e9feb8a010 gdb: change new_objfile observer to take an objfile reference
I was looking at the new_objfile observer and noticed a comment in
reread_symbols (symfile.c) that seemed out of date, it talked about
calling the new objfile observer with a NULL objfile argument.

A little digging indicates that the comment is indeed out of date, and
that we never call the new_objfile observer with a NULL argument any
more.

So in this commit I have:

  1. Updated the out of date comment in reread_symbols.

  2. Changed the argument type for the new_objfile observer from
     'objfile *' to 'objfile &'.  Passing a NULL pointer is no longer
     an option.

  3. Updated the existing new_objfile observers to take 'objfile &'
     and updated their implementations as needed.

There should be no user visible changes after this commit.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
2026-03-19 14:36:25 +00:00
Simon Marchi
b73d92e2c5 gdb, gdbserver, gdbsupport: replace many uses of strcmp with streq
Replace all occurrences of:

  strcmp (...) == 0
  strcmp (...) != 0
  !strcmp (...)
  0 == strcmp (...)
  strcmp (...) directly used as a boolean predicate

with the equivalent expression using streq.

This is for consistency (we already use streq as some places in the
testsuite) but also for clarity.  I think that streq is clearer on the
intent than strcmp.  It's also a bit shorter.

Change-Id: Ibbf5261b1872c240bc0c982c147f6a5477275a91
Approved-By: Andrew Burgess <aburgess@redhat.com>
2026-03-16 13:24:00 -04:00
Matthieu Longo
1c9bcee307 gdb/python: add accessor helpers for __dict__ in Python extension objects
Python extension objects that support __dict__ must inherit from
gdbpy_dict_wrapper, a wrapper class that stores the PyObject
corresponding to the __dict__ attribute. Because this dictionary
is not managed directly by Python, each extension objects must
provide appropriate accessors so that attributes stored in __dict__
are looked up correctly.

Currently, management of this dictionary is not centralized, and
each Python extension object implements its own logic to create,
access, and destroy it.

A previous patch centralized the creation logic; this patch focuses
on centralizing the access to the dictionary. It introduces two new
macros:
- gdbpy_dict_wrapper_cfg_dict_getter, which defines a getter for
  __dict__.
- gdbpy_dict_wrapper_getsetattro, which sets tp_getattro and
  tp_setattro in PyTypeObject to gdb_py_generic_getattro and
  gdb_py_generic_setattro, respectively. These helpers already
  centralizes attribute access for Python extension objects having
  a __dict__.
  Note: this macro will eventually be removed once Python extension
  types are migrated to heap-allocated types.

Approved-By: Tom Tromey <tom@tromey.com>
2026-03-14 13:21:06 +00:00
Tom Tromey
969c57240e Return bool from valid_task_id
This changes valid_task_id to return bool and updates some callers.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
2026-03-11 08:26:46 -06:00
Tom Tromey
79518ad271 Return bool from iterate_over_objfiles_in_search_order callbacks
I noticed that many callbacks passed to
iterate_over_objfiles_in_search_order were still returning 0/1 rather
than false/true.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
2026-03-10 07:18:55 -06:00
Matthieu Longo
28d828f4df gdb/python: add gdbpy_dict_wrapper:allocate_dict helper
Python extension objects that support __dict__ must inherit from
gdbpy_dict_wrapper, a wrapper class that stores the PyObject
corresponding to the __dict__ attribute.

Currently, management of this dictionary is not centralized, and
each Python extension object implements its own logic to create,
access, and destroy it.

This patch focuses on the allocation of the dictionary, introduces
a new method, gdbpy_dict_wrapper::allocate_dict(), and
adapts the existing code to use this method.

Approved-By: Tom Tromey <tom@tromey.com>
2026-03-10 12:43:12 +00:00
Matthieu Longo
f295945e26 gdb/python: flatten functions calling PyObject_New and use gdbpy_ref
This patch aims at systematically using gdbpy_ref<> at all call sites
of PyObject_New(). This prepares for future patches that expect
gdbby_ref<> parameters and affect return handling.
As part of this change, flattening the affected functions so that the
return logic becomes clearer and more flexible to adjust.

Approved-By: Tom Tromey <tom@tromey.com>
2026-03-10 12:43:12 +00:00
Matthieu Longo
f0cfbf6ced gdb/python: allow ref_ptr<T, Policy>::new_reference to accept subclasses of T
When ref_ptr<T,Policy>::new_reference() is specialized for 'PyObject'
(i.e. gdbpy_ref<>), it currently requires the argument type to be exactly
'PyObject *'. As a result, pointers to subclasses of 'PyObject' must be
explicitly cast before being passed, making call sites unnecessarily
verbose.

This patch makes ref_ptr<T,Policy>::new_reference() a template method
that accepts both T and subclasses of T, performing the cast to 'T *'
internally when needed. This removes redundant casts at call sites
without changing behavior.

Approved-By: Tom Tromey <tom@tromey.com>
2026-03-10 12:43:12 +00:00
Matthieu Longo
995cf2f8fe gdb: introduce rgb_color type to simplify existing code
This patch replaces the raw uint8[3] buffer used to represent RGB values
with a more convenient wrapper, rgb_color, around std::array<uint8_t, 3>.
It also changes the return type of ui_file_style::color::get_rgb to
rgb_color instead of filling a caller-provided buffer, and updates all
callers accordingly.

This expected benefit of this change consists in:
- removing the manual size handling.
- proving accessors without using hard-coded indexes.
- making the API safer.
- simplifying call sites.

This refactoring does not introduce any functional change.

Approved-By: Tom Tromey <tom@tromey.com>
2026-03-10 11:22:28 +00:00
Matthieu Longo
83d7283c4b gdb/python: accept gdbpy_ref in init helpers and return bool
Passing 'gdbpy_ref<> &' instead of raw 'PyObject *' to init helpers
makes ownership of PyObject clearer at call sites, and removes
unnecessary '.get()' calls.
Changing the return type from 'int' to 'bool' improves readability
and better expresses the success/failure semantics.

Approved-By: Tom Tromey <tom@tromey.com>
2026-03-09 13:09:18 +00:00
Andrew Burgess
e4fe38115f gdb/python: fix gdb.FinishBreakpoint returning to a tail call frame
I noticed that gdb.FinishBreakpoint doesn't work if the parent
function is a tail call function.  In bpfinishpy_init we use
get_frame_pc to find the address at which the finish breakpoint should
be placed within the previous frame.

However, if the previous frame is a tail call frame, then get_frame_pc
will return an address outside of the tail call function, an address
which will not be reached on the return path.

Unlike other recent tail call fixes I've made, we cannot switch to
using something like get_frame_address_in_block here as in the tail
call case this will return an address within the function, but not an
address that will be executed when we return.

What we need to do in the tail call case is create the finish
breakpoint in the frame that called the tail call function.  Or if
that frame is itself a tail call, then we should walk back up the call
stack until we find a non-tail call function.

This can be achieved by adding a call to skip_tailcall_frames into
bpfinishpy_init after our existing call to get_prev_frame.

I've extended the existing test case to cover this additional
situation.

Approved-By: Tom Tromey <tom@tromey.com>
2026-03-05 17:45:29 +00:00
Andrew Burgess
99d7dc93ce gdb/python: don't allow FinishBreakpoints for inline frames
Creating a Python gdb.FinishBreakpoint for an inline frame doesn't
work.

If we look at the 'finish' command, in the finish_command
function (infcmd.c) then we see that GDB handles inline frames very
different to non-inline frames.

For non-inline frames GDB creates a temporary breakpoint and then
resumes the inferior until the breakpoint is hit.

But for inline frames, GDB steps forward until we have left the inline
frame.

When it comes to gdb.FinishBreakpoint we only have the "create a
temporary breakpoint" mechanism; that is, after all, what the
FinishBreakpoint is, it's a temporary breakpoint placed at the
return address in the caller.

Currently, when a FinishBreakpoint is created within an inline frame,
GDB ends up creating the breakpoint at the current $pc.  As a result
the breakpoint will not be hit before the current function
exits (unless there's a loop going on, but that's not the point).

We could imagine what a solution to this problem would look like, GDB
would need to figure out the set of addresses for all possible exit
points from the inline function, and place a breakpoint at each of
these locations.  I don't propose doing that in this commit.

Instead, I plan to update the docs to note that creating a
FinishBreakpoint within an inline frame is not allowed, and I will
catch this case within bpfinishpy_init (python/py-finishbreakpoint.c)
and throw an error.

Though the error is new, all I'm doing is raising an error for a case
that never worked.

There's a new test to cover this case.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=18339

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Approved-By: Tom Tromey <tom@tromey.com>
2026-03-05 17:45:28 +00:00
Andrew Burgess
d0c1dcb58e gdb/python: fix FinishBreakpoint.return_value for tail call functions
The FinishBreakpoint.return_value attribute will not be populated
correctly for tail call functions.

In bpfinishpy_init (python/py-finishbreakpoint.c) we use the function
get_frame_pc_if_available to return an address, and then use this
address to lookup a function symbol.

The problem is that, for tail call functions, the address returned by
get_frame_pc_if_available can be outside the bounds of the function,
as a result GDB might find no function symbol at all, or might find
the wrong function symbol, if the tail call function is immediately
adjacent to the next function.

Fix this by using get_frame_address_in_block_if_available instead.
For tail call functions this will return an address within the bounds
of the function, which means that GDB should find the correct function
symbol, and from this the correct return type.

I've extended the existing FinishBreakpoint with tail call test case
to include printing the return value, this test fails without this
patch, but now works.

Approved-By: Tom Tromey <tom@tromey.com>
2026-03-05 17:45:27 +00:00
Andrew Burgess
030f56e0e8 gdb/python: introduce gdb.Symtab.source_lines method
This commit adds a new method gdb.Symtab.source_lines.  This method
can be used to read the lines from a symtab's source file.  This is
similar to GDB's internal source_cache::get_source_lines function.

Currently using the Python API, if a user wants to display source
lines then they need to use Symtab.fullname() to get the source file
name, then open this file and parse out the lines themselves.

This isn't too much effort, but the problem is that these lines will
not be styled.  The user could style the source content themselves,
but will this be styled exactly as GDB would style it?

The new Symtab.source_lines() method returns source lines with styling
included (as ANSI terminal escape sequences), assuming of course, that
styling is currently enabled.

Of course, in some cases, a user of the Python API might want source
code without styling.  That's supported too, the new method has an
'unstyled' argument.  If this is True then the output is forced to be
unstyled.  The argument is named 'unstyled' rather than 'styled'
because the API call cannot force styling on.  If 'set style enabled
off' is in effect then making the API call will never return styled
source lines.

The new API call allows for a range of lines to be requested if
desired.

As part of this commit I've updated the host_string_to_python_string
utility function to take a std::string_view.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Approved-By: Tom Tromey <tom@tromey.com>
2026-03-05 10:17:08 +00:00
Andrew Burgess
ee89a3c9ef gdb/python: new selected_context event
This commit introduces a new Python event, selected_context.  This
event is attached to the user_selected_context_changed observer, which
triggers when the user changes the currently selected inferior,
thread, or frame.

Adding this event allows a Python extension to update in response to
user driven changes without having to poll the state from a
before_prompt hook, which is what I currently do to achieve the same
results.

I did consider splitting the user_selected_context_changed observer
into 3 separate Python events, inferior_changed, thread_changed, and
frame_changed, but I couldn't see any significant advantage to doing
this, so in the end I went with just a single event, and the event
object contains the inferior, thread, and frame.

Additionally, the user isn't informed about which aspect of the
context changed.  That is, every event carries the inferior, thread,
and frame, so an event triggered when switching frames will looks
identical to an event triggered when switching inferiors.  If the user
wants to know what changed then they will have to track the current
state themselves, and then compare the event state to the stored
current state.  In many cases though I suspect that just being told
something changed, and then updating everything will be sufficient,
which is why I've not bothered trying to inform the user what changed.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=24482

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Approved-By: Tom Tromey <tom@tromey.com>
2026-03-05 09:42:18 +00:00
Tom Tromey
c2af35131a Use ref_ptr upcasts in Python code
In some spots the Python code will do an explicit upcast of gdbpy_ref,
like:

    return gdbpy_ref<> ((PyObject *) color_obj.release ());

Now that ref_ptr allows upcasts, and because gdb's Python objects
derive from PyObject, these reshufflings can be expressed more simply.

Approved-By: Andrew Burgess <aburgess@redhat.com>
2026-03-04 10:09:33 -07:00
Tom Tromey
0d9faae86e Don't use template for gdbpy_ref_policy
Now that gdb's Python types derive from PyObject, there's no need to
use a template for gdbpy_ref_policy.  This simplifies the code a tiny
bit.

Approved-By: Andrew Burgess <aburgess@redhat.com>
2026-03-04 10:07:33 -07:00
Matthieu Longo
071381ae0d gdb: switch bytes object helpers to Python limited API equivalents
* PyBytes_AS_STRING -> PyBytes_AsString
* PyBytes_GET_SIZE -> PyBytes_Size

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23830
Approved-By: Tom Tromey <tom@tromey.com>
2026-03-04 15:38:28 +00:00
Matthieu Longo
7a45ab6fb3 gdb: switch tuple object helpers to Python limited API equivalents
* PyTuple_GET_ITEM -> PyTuple_GetItem
* PyTuple_SET_ITEM -> PyTuple_SetItem
* PyTuple_GET_SIZE -> PyTuple_Size

Unlike PyTuple_SET_ITEM(), PyTuple_SetItem() returns an integer: 0 on
success and -1 on error (e.g. IndexError). The existing code must therefore
be updated to handle this new behaviour.

Since processing now stops when PyTuple_SetItem() returns an error, some
resources (such as newly allocated tuples) must be properly deallocated in
error paths. To address this, this patch replaces the use of raw 'PyObject *'
pointers with gdbpy_ref<>, a reference-counted wrapper around 'PyObject *',
which automatically decrements the reference count on early exit.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23830
Approved-By: Tom Tromey <tom@tromey.com>
2026-03-04 15:38:11 +00:00
Tom Tromey
720a5d5688 Use the "O!" format more in the Python code
I noticed a few spots in the Python code that were decoding method
arguments and then immediately type-checking an argument.  This can be
done more concisely using the "O!" format.

Reviewed-By: Tom de Vries <tdevries@suse.de>
2026-02-27 12:01:56 -07:00
Matthieu Longo
e302db7135 gdb: switch sequence protocol helpers to Python limited API equivalents
* PySequence_ITEM -> PySequence_GetItem

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23830
Approved-By: Tom Tromey <tom@tromey.com>
2026-02-27 11:38:57 +00:00
Simon Marchi
2a2b24ecc1 gdb/python: remove some unreachable Py_RETURN_NONE
They are unreachable because there is a return statement in all possible code
paths before.

Change-Id: I9db2f41f8017380c0c79f97af9bbf8734038ba9a
Approved-By: Tom Tromey <tom@tromey.com>
2026-02-23 08:21:46 -05:00
Tom Tromey
7fc4f93e28 Return gdbpy_ref<> from gdbpy_registry::lookup
This changes gdbpy_registry::lookup to return a gdbpy_ref<>, using the
type system to convey that a new reference is always returned.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
2026-02-23 05:29:12 -07:00
Tom Tromey
a93acde059 Return gdbpy_ref<> from gdbarch_to_arch_object
This changes gdbarch_to_arch_object to return a gdbpy_ref<>,
using the type system to convey that a new reference is always
returned.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
2026-02-23 05:29:12 -07:00
Tom Tromey
472748485e Return gdbpy_ref<> from symtab_to_linetable_object
This changes symtab_to_linetable_object to return a gdbpy_ref<>,
using the type system to convey that a new reference is always
returned.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
2026-02-23 05:29:12 -07:00
Tom Tromey
3c21c86980 Return gdbpy_ref<> from frame_info_to_frame_object
This changes frame_info_to_frame_object to return a gdbpy_ref<>,
using the type system to convey that a new reference is always
returned.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
2026-02-23 05:29:12 -07:00
Tom Tromey
fb81682fec Return gdbpy_ref<> from type_to_type_object
This changes type_to_type_object to return a gdbpy_ref<>,
using the type system to convey that a new reference is always
returned.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
2026-02-23 05:29:12 -07:00
Tom Tromey
9a17597269 Return gdbpy_ref<> from value_to_value_object
This changes value_to_value_object to return a gdbpy_ref<>,
using the type system to convey that a new reference is always
returned.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
2026-02-23 05:29:11 -07:00
Tom Tromey
702716deaf Return gdbpy_ref<> from block_to_block_object
This changes block_to_block_object to return a gdbpy_ref<>,
using the type system to convey that a new reference is always
returned.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
2026-02-23 05:29:11 -07:00
Tom Tromey
9d71572cba Return gdbpy_ref<> from symtab_to_symtab_object
This changes symtab_to_symtab_object to return a gdbpy_ref<>,
using the type system to convey that a new reference is always
returned.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
2026-02-23 05:29:11 -07:00
Tom Tromey
0ab23e2707 Return gdbpy_ref<> from symbol_to_symbol_object
This changes symbol_to_symbol_object to return a gdbpy_ref<>,
using the type system to convey that a new reference is always
returned.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
2026-02-23 05:29:11 -07:00
Tom Tromey
800d967797 Return gdbpy_ref<> from symtab_and_line_to_sal_object
This changes symtab_and_line_to_sal_object to return a gdbpy_ref<>,
using the type system to convey that a new reference is always
returned.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
2026-02-23 05:29:11 -07:00
Andrew Burgess
7de2cbde43 gdb/gdbserver: move argument setting complexity into gdbsupport/
This commit removes some uses of gdb::argv_vec from GDB.

The gdb::argv_vec class exists in part due to our need to convert from
one container type to another in a few places, and I think by using
templates we can push this conversion down into
gdbsupport/common-inferior.{cc,h} and remove the conversion logic from
higher level code in GDB.  This should make core GDB simpler.

For examples of this simplification, see python/py-inferior.c,
remote.c, and unittests/remote-arg-selftests.c, where this commit has
allowed for the removal of some code that only exists in order to
convert the container type.

Ideally I'd like to see all uses of gdb::argv_vec removed, but I'm
still not sure about the use in nat/fork-inferior.c, I think its use
there might be the best solution, so for now at least, I have no plans
to touch that code.

There should be no user visible changes after this commit.

Approved-By: Tom Tromey <tom@tromey.com>
2026-02-13 16:37:38 +00:00
Simon Marchi
f3965c2404 gdb/registry: add registry:🔑:try_emplace
We have many times the pattern:

    current_source_location *loc
      = current_source_key.get (pspace);
    if (loc == nullptr)
      loc = current_source_key.emplace (pspace);
    return loc;

I thought it would be nice to have it directly part of registry::key.
Add a try_emplace method, which is like emplace, except that it returns
the existing data, if any.  The try_emplace name comes from similar
methods in std::map or gdb::unordered_map
(ankerl::unordered_dense::map).

Replace as many callers as I could find to use it.

Change-Id: I21f922ca065a354f041caaf70484d6cfbcbb76ed
Approved-By: Tom Tromey <tom@tromey.com>
2026-02-09 12:48:36 -05:00
Simon Marchi
ea71a4081d gdb/registry: make registry:🔑:emplace return a reference
Since we use C++ and not C, I think that we should gradually move to
using references for things that can never be nullptr.  One example of
this is the return value of the emplace method.

Change it to return a reference, and (to keep the patch straightforward)
update all callers to take the address.  More patches could follow to
propagate the use of references further.

Change-Id: I725539694cf496f8288918cc29d7aaae9aca2292
Approved-By: Tom Tromey <tom@tromey.com>
2026-02-09 12:48:35 -05:00
Tom Tromey
817003ed46 Rewrite output redirection and logging
This patch changes how gdb output redirection is done.

Currently, output is done via the UI.  gdb_stdout, for example, is a
define the expands to an lvalue referencing a field in the current UI.
When redirecting, this field may temporarily be reset; and when
logging is enabled or disabled, this is also done.

This has lead to bugs where the combination of redirection and logging
results in use-after-free.  Crashes are readily observable; see the
new test cases.

This patch upends this.  Now, gdb_stdout is simply an rvalue, and
refers to the current interpreter.  The interpreter provides ui_files
that do whatever rewriting is needed (mostly for MI); then output is
forward to the current UI via an indirection (see the new
ui::passthrough_file).

The ui provides paging, logging, timestamps, and the final stream that
writes to an actual file descriptor.

Redirection is handled at the ui layer.  Rather than changing the
output pipeline, new ui_files are simply swapped in by rewriting
pointers, hopefully with a scoped_restore.

Redirecting at the ui layer means that interpreter rewriting is still
applied when capturing output.  This fixes one of the reported bugs.

Not changing the pipeline means that the problems with the combination
of redirect and logging simply vanish.  Logging just changes a flag
and doesn't involve object destruction.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=17697
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28620
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28798
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28948
Approved-By: Andrew Burgess <aburgess@redhat.com>
2026-02-09 08:15:44 -07:00
Tom Tromey
0391f70c7d Remove m_applied_style from ui_file
While working on this series, I found a number of odd styling issues
recurred.  For instance, the issue where the pager would lose track
and style subsequent output incorrectly reappeared.

It turned out that different ui_file objects in the output pipeline
would get confused about their current style.  And, looking deeper at
this, I realized that mainly it is the pager that really needs to
track the current style at all.  All the other file implementations
can be purely reactive (except the buffered stream code, as Andrew
pointed out).

This patch moves m_applied_style from ui_file and into pager_file.
This necessitated making ui_file::vprintf virtual, so that the base
class could pass in the "plain" style as the starting point, whereas
the pager could use the applied style.  (I did not investigate whether
this was truly necessary, and I somewhat suspect it might not be.)

This straightforward approach caused some regressions, mostly
involving extra ANSI escapes being emitted.  I fixed most of these by
arranging for ui_out::call_do_message to track styles a little more
thoroughly.

Co-Authored-By: Andrew Burgess <aburgess@redhat.com>
Approved-By: Andrew Burgess <aburgess@redhat.com>
2026-02-09 08:15:29 -07:00
Tom de Vries
49dcedc447 [gdb/python] Fix whitespace in py-ref.h
Fix a whitespace problem pre-commit complains about:
...
check-whitespace........................................................Failed
- hook id: check-whitespace
- exit code: 2

gdb/python/py-ref.h:58: indent with spaces.
+         "The __dict__ for this object.", nullptr },
...
2026-01-29 21:18:52 +01:00
Matthieu Longo
91bf037a39 gdb: make remaining Python extension objects inherit from PyObject
Previous patches made some Python extension objects ipublicly inherit
directly or indirectly from PyObject.
In the interest of consistency, this patch makes all remaining Python
extension objects still not inheriting from PyObject do so.

Approved-By: Tom Tromey <tom@tromey.com>
2026-01-29 16:46:14 +00:00
Matthieu Longo
1fe7c3b749 gdb: cast all Python extension objects passed to gdbpy_ref_policy to PyObject*
When enabling the Python limited API, pointers to Python C extension
objects can no longer be implicitly converted to 'PyObject *' by the
compiler.

gdbpy_ref_policy is a templated class that provides a generic interface
for incrementing and decrementing the reference counter on the given
object. It is used as a specialisation of the policy parameter in
gdb::ref_ptr, together with PyObject as the parameter type. As a result,
gdbpy_ref_policy always expects an argument derived from PyObject.

This patch fixes the resulting compilation issue by adding an explicit
static_cast to 'PyObject *' before passing the value to Py_INCREF and
Py_DECREF. As a side effect, these casts enforce, at compile time, that
the template type passed to gdbpy_ref_policy is a subclass of PyObject.
To provide a clearer diagnostic when an incorrect type is used, a
static_assert is added to gdbpy_ref_policy, avoiding obscure errors
originating from the static_cast. Finally, all C Python extension types
passed to gdbpy_ref_policy are updated to inherit from PyObject.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23830
Approved-By: Tom Tromey <tom@tromey.com>
2026-01-29 16:46:14 +00:00
Matthieu Longo
9a84753aa7 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>
2026-01-29 16:46:14 +00:00
Matthieu Longo
8b0f0d5fbf gdbpy_registry: cast C extension type object to PyObject * before Py_XINCREF
When enabling the Python limited API, pointers to Python C extension
objects can no longer be implicitly converted to 'PyObject *' by the
compiler.

The lookup() method of gbdpy_registry returns a new reference to the
type object of the looked-up entry. It does so by calling Py_XINCREF()
to increment the reference counter of the returned type object. The
template parameter obj_type corresponds to the type of C extension
object type. With the Python limited API enabled, obj_type can no longer
be implicitly converted to 'PyObject *' when passed to Py_XINCREF().

This patch fixes the resulting compilation issue by adding an explicit
static_cast to 'PyObject *' before passing the value to Py_XINCREF().
As a side effect, this cast enforces, at compile time, that the template
type 'Storage::obj_type' passed to gdbpy_registry is a subclass of
PyObject. To provide a clearer diagnostic when an incorrect type is used,
a static_assert is added to gdbpy_registry, avoiding obscure errors
originating from the static_cast. Finally, the relevant C extension types
passed to gdbpy_registry are updated to inherit publicly from PyObject.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23830
Approved-By: Tom Tromey <tom@tromey.com>
2026-01-29 16:46:14 +00:00
Matthieu Longo
c02c23175e Python limited API: migrate PyImport_ExtendInittab
This patch replaces PyImport_ExtendInittab () with its limited C
API equivalent, PyImport_AppendInittab (), a convenience wrapper
around PyImport_ExtendInittab ().

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23830
Approved-By: Tom Tromey <tom@tromey.com>
2026-01-28 09:41:32 +00:00
Matthieu Longo
264a8a2236 Python limited API: migrate Py_CompileStringExFlags and PyRun_SimpleString
This patch replaces Py_CompileStringExFlags () with its limited C API
equivalent, Py_CompileString (). The eval_python_command () helper is
now exposed through the private GDB Python API as a utility function.
PyRun_SimpleString () is replaced with eval_python_command () to avoid
code duplication.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23830
Approved-By: Tom Tromey <tom@tromey.com>
2026-01-28 09:41:25 +00:00
oltolm
7e8aebc9d3 gdb/python: use gdbpy_is_value_object in more places
Make more use of gdbpy_is_value_object in python/py-value.c

Approved-By: Andrew Burgess <aburgess@redhat.com>
2026-01-27 09:40:43 +00:00
Tom Tromey
cdc1fd1bcc Update black to 26.1.0
"pre-commit autoupdate" suggests a new version of black.  This version
seems to want to change how destructuring assignments are formatted.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
2026-01-23 06:45:46 -07:00
Tom Tromey
4f148246ca Use make_unique_xstrdup in more places
This replaces a number of uses of 'ptr.reset (xstrdup ())'
with 'ptr = make_unique_xstrdup ()'.

The main motivation for this is that, IMO, it's better to avoid the
reset method when possible.

Approved-By: Andrew Burgess <aburgess@redhat.com>
2026-01-16 07:44:32 -07:00