13 Commits

Author SHA1 Message Date
59912fb2d2 gdb: add Python events for program space addition and removal
Initially I just wanted a Python event for when GDB removes a program
space, I'm writing a Python extension that caches information for each
program space, and need to know when I should discard entries for a
particular program space.

But, it seemed easy enough to also add an event for when GDB adds a
new program space, so I went ahead and added both new events.

Of course, we don't currently have an observable for program space
addition or removal, so I first needed to add these.  After that it's
pretty simple to add two new Python events and have these trigger.

The two new event registries are:

  events.new_progspace
  events.free_progspace

These emit NewProgspaceEvent and FreeProgspaceEvent objects
respectively, each of these new event types has a 'progspace'
attribute that contains the relevant gdb.Progspace object.

There's a couple of things to be mindful of.

First, it is not possible to catch the NewProgspaceEvent for the very
first program space, the one that is created when GDB first starts, as
this program space is created before any Python scripts are sourced.

In order to allow this event to be caught we would need to defer
creating the first program space, and as a consequence the first
inferior, until some later time.  But, existing scripts could easily
depend on there being an initial inferior, so I really don't think we
should change that -- and so, we end up with the consequence that we
can't catch the event for the first program space.

The second, I think minor, issue, is that GDB doesn't clean up its
program spaces upon exit -- or at least, they are not cleaned up
before Python is shut down.  As a result, any program spaces in use at
the time GDB exits don't generate a FreeProgspaceEvent.  I'm not
particularly worried about this for my use case, I'm using the event
to ensure that a cache doesn't hold stale entries within a single GDB
session.  It's also easy enough to add a Python at-exit callback which
can do any final cleanup if needed.

Finally, when testing, I did hit a slightly weird issue with some of
the remote boards (e.g. remote-stdio-gdbserver).  As a consequence of
this issue I see some output like this in the gdb.log:

  (gdb) PASS: gdb.python/py-progspace-events.exp: inferior 1
  step
  FreeProgspaceEvent: <gdb.Progspace object at 0x7fb7e1d19c10>
  warning: cannot close "target:/lib64/libm.so.6": Cannot execute this command while the target is running.
  Use the "interrupt" command to stop the target
  and then try again.
  warning: cannot close "target:/lib64/libc.so.6": Cannot execute this command while the target is running.
  Use the "interrupt" command to stop the target
  and then try again.
  warning: cannot close "target:/lib64/ld-linux-x86-64.so.2": Cannot execute this command while the target is running.
  Use the "interrupt" command to stop the target
  and then try again.
  do_parent_stuff () at py-progspace-events.c:41
  41        ++global_var;
  (gdb) PASS: gdb.python/py-progspace-events.exp: step

The 'FreeProgspaceEvent ...' line is expected, that's my test Python
extension logging the event.  What isn't expected are all the blocks
like:

  warning: cannot close "target:/lib64/libm.so.6": Cannot execute this command while the target is running.
  Use the "interrupt" command to stop the target
  and then try again.

It turns out that this has nothing to do with my changes, this is just
a consequence of reading files over the remote protocol.  The test
forks a child process which GDB stays attached too.  When the child
exits, GDB cleans up by calling prune_inferiors, which in turn can
result in GDB trying to close some files that are open because of the
inferior being deleted.

If the prune_inferiors call occurs when the remote target is
running (and in non-async mode) then GDB will try to send a fileio
packet while the remote target is waiting for a stop reply, and the
remote target will throw an error, see remote_target::putpkt_binary in
remote.c for details.

I'm going to look at fixing this, but, as I said, this is nothing to
do with this change, I just mention it because I ended up needing to
account for these warning messages in one of my tests, and it all
looks a bit weird.

Approved-By: Tom Tromey <tom@tromey.com>
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
2023-10-02 17:06:40 +01:00
42f297ad36 gdb/python: make the executable_changed event available from Python
This commit makes the executable_changed observable available through
the Python API as an event.  There's nothing particularly interesting
going on here, it just follows the same pattern as many of the other
Python events we support.

The new event registry is called events.executable_changed, and this
emits an ExecutableChangedEvent object which has two attributes, a
gdb.Progspace called 'progspace', this is the program space in which
the executable changed, and a Boolean called 'reload', which is True
if the same executable changed on disk and has been reloaded, or is
False when a new executable has been loaded.

One interesting thing did come up during testing though, you'll notice
the test contains a setup_kfail call.  During testing I observed that
the executable_changed event would trigger twice when GDB restarted an
inferior.  However, the ExecutableChangedEvent object is identical for
both calls, so the wrong information is never sent out, we just see
one too many events.

I tracked this down to how the reload_symbols function (symfile.c)
takes care to also reload the executable, however, I've split fixing
this into a separate commit, so see the next commit for details.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Approved-By: Tom Tromey <tom@tromey.com>
2023-09-28 15:33:13 +01:00
28ab59607e gdb/Python: Added ThreadExitedEvent
v6:
Fix comments.
Fix copyright
Remove unnecessary test suite stuff. save_var had to stay, as it mutates
some test suite state that otherwise fails.

v5:
Did what Tom Tromey requested in v4; which can be found here: https://pi.simark.ca/gdb-patches/87pmjm0xar.fsf@tromey.com/

v4:
Doc formatting fixed.

v3:
Eli:
Updated docs & NEWS to reflect new changes. Added
a reference from the .ptid attribute of the ThreadExitedEvent
to the ptid attribute of InferiorThread. To do this,
I've added an anchor to that attribute.

Tom:
Tom requested that I should probably just emit the thread object;
I ran into two issues for this, which I could not resolve in this patch;

1 - The Thread Object (the python type) checks it's own validity
by doing a comparison of it's `thread_info* thread` to nullptr. This
means that any access of it's attributes may (probably, since we are
in "async" land) throw Python exceptions because the thread has been
removed from the thread object. Therefore I've decided in v3 of this
patch to just emit most of the same fields that gdb.InferiorThread has, namely
global_num, name, num and ptid (the 3-attribute tuple provided by
gdb.InferiorThread.ptid).

2 - A python user can hold a global reference to an exiting thread. Thus
in order to have a ThreadExit event that can provide attribute access
reliably (both as a global reference, but also inside the thread exit
handler, as we can never guarantee that it's executed _before_ the
thread_info pointer is removed from the gdbpy thread object),
the `thread_info *` thread pointer must not be null. However, this
comes at the cost of gdb.InferiorThread believing it is "valid" - which means,
that if a user holds takes a global reference to that
exiting event thread object, they can some time later do `t.switch()` at which
point GDB will 'explode' so to speak.

v2:
Fixed white space issues and NULL/nullptr stuff,
as requested by Tom Tromey.

v1:
Currently no event is emitted for a thread exit.

This adds this functionality by emitting a new gdb.ThreadExitedEvent.

It currently provides four attributes:
- global_num: The GDB assigned global thread number
- num: the per-inferior thread number
- name: name of the thread or none if not set
- ptid: the PTID of the thread, a 3-attribute tuple, identical to
InferiorThread.ptid attribute

Added info to docs & the NEWS file as well.

Added test to test suite.

Fixed formatting.

Feedback wanted and appreciated.
2023-06-19 16:17:21 +02:00
213516ef31 Update copyright year range in header of all files managed by GDB
This commit is the result of running the gdb/copyright.py script,
which automated the update of the copyright year range for all
source files managed by the GDB project to be updated to include
year 2023.
2023-01-01 17:01:16 +04:00
0b4fe76f95 Add gdb.free_objfile event registry
Currently, Python code can use event registries to detect when gdb
loads a new objfile, and when gdb clears the objfile list.  However,
there's no way to detect the removal of an objfile, say when the
inferior calls dlclose.

This patch adds a gdb.free_objfile event registry and arranges for an
event to be emitted in this case.
2022-07-18 11:25:34 -06:00
4a94e36819 Automatic Copyright Year update after running gdb/copyright.py
This commit brings all the changes made by running gdb/copyright.py
as per GDB's Start of New Year Procedure.

For the avoidance of doubt, all changes in this commits were
performed by the script.
2022-01-01 19:13:23 +04:00
0e3b7c25ee gdb/python: introduce gdb.TargetConnection object type
This commit adds a new object type gdb.TargetConnection.  This new
type represents a connection within GDB (a connection as displayed by
'info connections').

There's three ways to find a gdb.TargetConnection, there's a new
'gdb.connections()' function, which returns a list of all currently
active connections.

Or you can read the new 'connection' property on the gdb.Inferior
object type, this contains the connection for that inferior (or None
if the inferior has no connection, for example, it is exited).

Finally, there's a new gdb.events.connection_removed event registry,
this emits a new gdb.ConnectionEvent whenever a connection is removed
from GDB (this can happen when all inferiors using a connection exit,
though this is not always the case, depending on the connection type).
The gdb.ConnectionEvent has a 'connection' property, which is the
gdb.TargetConnection being removed from GDB.

The gdb.TargetConnection has an 'is_valid()' method.  A connection
object becomes invalid when the underlying connection is removed from
GDB (as discussed above, this might be when all inferiors using a
connection exit, or it might be when the user explicitly replaces a
connection in GDB by issuing another 'target' command).

The gdb.TargetConnection has the following read-only properties:

  'num': The number for this connection,

  'type': e.g. 'native', 'remote', 'sim', etc

  'description': The longer description as seen in the 'info
                 connections' command output.

  'details': A string or None.  Extra details for the connection, for
             example, a remote connection's details might be
             'hostname:port'.
2021-11-30 12:10:33 +00:00
b1f0f28418 gdb/python: add a new gdb_exiting event
Add a new event, gdb.events.gdb_exiting, which is called once GDB
decides it is going to exit.

This event is not triggered in the case that GDB performs a hard
abort, for example, when handling an internal error and the user
decides to quit the debug session, or if GDB hits an unexpected,
fatal, signal.

This event is triggered if the user just types 'quit' at the command
prompt, or if GDB is run with '-batch' and has processed all of the
required commands.

The new event type is gdb.GdbExitingEvent, and it has a single
attribute exit_code, which is the value that GDB is about to exit
with.

The event is triggered before GDB starts dismantling any of its own
internal state, so, my expectation is that most Python calls should
work just fine at this point.

When considering this functionality I wondered about using the
'atexit' Python module.  However, this is triggered when the Python
environment is shut down, which is done from a final cleanup.  At
this point we don't know for sure what other GDB state has already
been cleaned up.
2021-10-05 10:05:40 +01:00
3666a04883 Update copyright year range in all GDB files
This commits the result of running gdb/copyright.py as per our Start
of New Year procedure...

gdb/ChangeLog

        Update copyright year range in copyright header of all GDB files.
2021-01-01 12:12:21 +04:00
b811d2c292 Update copyright year range in all GDB files.
gdb/ChangeLog:

        Update copyright year range in all GDB files.
2020-01-01 10:20:53 +04:00
42a4f53d2b Update copyright year range in all GDB files.
This commit applies all changes made after running the gdb/copyright.py
script.

Note that one file was flagged by the script, due to an invalid
copyright header
(gdb/unittests/basic_string_view/element_access/char/empty.cc).
As the file was copied from GCC's libstdc++-v3 testsuite, this commit
leaves this file untouched for the time being; a patch to fix the header
was sent to gcc-patches first.

gdb/ChangeLog:

	Update copyright year range in all GDB files.
2019-01-01 10:01:51 +04:00
e2882c8578 Update copyright year range in all GDB files
gdb/ChangeLog:

        Update copyright year range in all GDB files
2018-01-02 07:38:06 +04:00
7d221d749c Make it simpler to add events to Python
The first patch in this series went through several iterations as I'd
forgotten how many places had to be touched to add a new event and a
new event type.

This patch simplifies the process using two new ".def" files.  Now, a
new event type can be added by adding a line to "py-event-types.def",
and a new event registry can be added by adding a line to
"py-all-events.def".

ChangeLog
2017-09-11  Tom Tromey  <tom@tromey.com>

	* python/python.c (do_start_initialization): Use
	py-event-types.def to initialize types.
	Define all object type structures.
	* python/python-internal.h: Don't declare event initialization
	functions.
	* python/py-threadevent.c (thread_event_object_type): Don't
	define.
	* python/py-stopevent.c (stop_event_object_type): Don't define.
	* python/py-signalevent.c (signal_event_object_type): Don't
	declare or define.
	* python/py-newobjfileevent.c (new_objfile_event_object_type)
	(clear_objfiles_event_object_type): Don't declare or define.
	* python/py-infevents.c (inferior_call_pre_event_object_type)
	(inferior_call_post_event_object_type)
	(register_changed_event_object_type)
	(memory_changed_event_object_type): Don't declare or define.
	* python/py-inferior.c (new_thread_event_object_type)
	(new_inferior_event_object_type)
	(inferior_deleted_event_object_type): Don't declare or define.
	* python/py-exitedevent.c (exited_event_object_type): Don't
	declare or define.
	* python/py-evts.c (gdbpy_initialize_py_events): Use
	py-all-events.def.
	* python/py-events.h (thread_event_object_type): Don't declare.
	(events_object): Use py-all-events.def.
	* python/py-event.h (GDBPY_NEW_EVENT_TYPE): Remove.  Use
	py-event-types.def.
	* python/py-event-types.def: New file.
	* python/py-continueevent.c (create_continue_event_object): Don't
	declare or define.
	* python/py-bpevent.c (breakpoint_event_object_type): Don't
	declare or define.
	* python/py-all-events.def: New file.
2017-09-11 14:15:22 -06:00