From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2126) id 901BB385840F; Mon, 18 Jul 2022 17:26:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 901BB385840F Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Tom Tromey To: gdb-cvs@sourceware.org Subject: [binutils-gdb] Add gdb.free_objfile event registry X-Act-Checkin: binutils-gdb X-Git-Author: Tom Tromey X-Git-Refname: refs/heads/master X-Git-Oldrev: 23948f56021f46bb2bdee7afad074aafe8329230 X-Git-Newrev: 0b4fe76f956293778f109764911a0b14dc944f5d Message-Id: <20220718172621.901BB385840F@sourceware.org> Date: Mon, 18 Jul 2022 17:26:21 +0000 (GMT) X-BeenThere: gdb-cvs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 18 Jul 2022 17:26:21 -0000 https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D0b4fe76f9562= 93778f109764911a0b14dc944f5d commit 0b4fe76f956293778f109764911a0b14dc944f5d Author: Tom Tromey Date: Mon Jun 20 11:30:04 2022 -0600 Add gdb.free_objfile event registry =20 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. =20 This patch adds a gdb.free_objfile event registry and arranges for an event to be emitted in this case. Diff: --- gdb/doc/python.texi | 11 +++++ gdb/python/py-all-events.def | 1 + gdb/python/py-event-types.def | 5 +++ gdb/python/py-event.h | 1 + gdb/python/py-inferior.c | 15 +++++++ gdb/python/py-newobjfileevent.c | 36 ++++++++++++++++ gdb/testsuite/gdb.python/py-event-load.c | 42 +++++++++++++++++++ gdb/testsuite/gdb.python/py-event-load.exp | 67 ++++++++++++++++++++++++++= ++++ gdb/testsuite/gdb.python/py-event-load.py | 30 +++++++++++++ 9 files changed, 208 insertions(+) diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index 5dd907fac42..eeb847aeaa8 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -3494,6 +3494,17 @@ A reference to the object file (@code{gdb.Objfile}) = which has been loaded. @xref{Objfiles In Python}, for details of the @code{gdb.Objfile} object. @end defvar =20 +@item events.free_objfile +Emits @code{gdb.FreeObjFileEvent} which indicates that an object file +is about to be removed from @value{GDBN}. One reason this can happen +is when the inferior calls @code{dlclose}. +@code{gdb.FreeObjFileEvent} has one attribute: + +@defvar NewObjFileEvent.objfile +A reference to the object file (@code{gdb.Objfile}) which will be unloaded. +@xref{Objfiles In Python}, for details of the @code{gdb.Objfile} object. +@end defvar + @item events.clear_objfiles Emits @code{gdb.ClearObjFilesEvent} which indicates that the list of object files for a program space has been reset. diff --git a/gdb/python/py-all-events.def b/gdb/python/py-all-events.def index 7db8efa1390..e8ae9066875 100644 --- a/gdb/python/py-all-events.def +++ b/gdb/python/py-all-events.def @@ -27,6 +27,7 @@ GDB_PY_DEFINE_EVENT(stop) GDB_PY_DEFINE_EVENT(cont) GDB_PY_DEFINE_EVENT(exited) GDB_PY_DEFINE_EVENT(new_objfile) +GDB_PY_DEFINE_EVENT(free_objfile) GDB_PY_DEFINE_EVENT(clear_objfiles) GDB_PY_DEFINE_EVENT(new_inferior) GDB_PY_DEFINE_EVENT(inferior_deleted) diff --git a/gdb/python/py-event-types.def b/gdb/python/py-event-types.def index 596e68a852a..e613e6949d3 100644 --- a/gdb/python/py-event-types.def +++ b/gdb/python/py-event-types.def @@ -86,6 +86,11 @@ GDB_PY_DEFINE_EVENT_TYPE (new_objfile, "GDB new object file event object", event_object_type); =20 +GDB_PY_DEFINE_EVENT_TYPE (free_objfile, + "FreeObjFileEvent", + "GDB free object file event object", + event_object_type); + GDB_PY_DEFINE_EVENT_TYPE (clear_objfiles, "ClearObjFilesEvent", "GDB clear object files event object", diff --git a/gdb/python/py-event.h b/gdb/python/py-event.h index 831dd10fc85..220af1f7b12 100644 --- a/gdb/python/py-event.h +++ b/gdb/python/py-event.h @@ -74,6 +74,7 @@ extern gdbpy_ref<> create_thread_event_object (PyTypeObje= ct *py_type, PyObject *thread); =20 extern int emit_new_objfile_event (struct objfile *objfile); +extern int emit_free_objfile_event (struct objfile *objfile); extern int emit_clear_objfiles_event (void); =20 extern void evpy_dealloc (PyObject *self); diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c index ebcd5b0a70f..61ed342d1c1 100644 --- a/gdb/python/py-inferior.c +++ b/gdb/python/py-inferior.c @@ -197,6 +197,20 @@ python_new_objfile (struct objfile *objfile) } } =20 +/* Emit a Python event when an objfile is about to be removed. */ + +static void +python_free_objfile (struct objfile *objfile) +{ + if (!gdb_python_initialized) + return; + + gdbpy_enter enter_py (objfile->arch ()); + + if (emit_free_objfile_event (objfile) < 0) + gdbpy_print_stack (); +} + /* Return a reference to the Python object of type Inferior representing INFERIOR. If the object has already been created, return it and increment the reference count, otherwise, create it. @@ -853,6 +867,7 @@ gdbpy_initialize_inferior (void) gdb::observers::new_objfile.attach (python_new_objfile, "py-inferior", { &auto_load_new_objfile_observer_token }); + gdb::observers::free_objfile.attach (python_free_objfile, "py-inferior"); gdb::observers::inferior_added.attach (python_new_inferior, "py-inferior= "); gdb::observers::inferior_removed.attach (python_inferior_deleted, "py-inferior"); diff --git a/gdb/python/py-newobjfileevent.c b/gdb/python/py-newobjfileeven= t.c index dcbd0faf3a8..929d0eaac73 100644 --- a/gdb/python/py-newobjfileevent.c +++ b/gdb/python/py-newobjfileevent.c @@ -53,6 +53,42 @@ emit_new_objfile_event (struct objfile *objfile) return -1; } =20 +/* Create an event object representing a to-be-freed objfile. Return + nullptr, with the Python exception set, on error. */ + +static gdbpy_ref<> +create_free_objfile_event_object (struct objfile *objfile) +{ + gdbpy_ref<> objfile_event + =3D create_event_object (&free_objfile_event_object_type); + if (objfile_event =3D=3D nullptr) + return nullptr; + + gdbpy_ref<> py_objfile =3D objfile_to_objfile_object (objfile); + if (py_objfile =3D=3D nullptr + || evpy_add_attribute (objfile_event.get (), "objfile", + py_objfile.get ()) < 0) + return nullptr; + + return objfile_event; +} + +/* Callback function which notifies observers when a free objfile + event occurs. This function will create a new Python event object. + Return -1 if emit fails. */ + +int +emit_free_objfile_event (struct objfile *objfile) +{ + if (evregpy_no_listeners_p (gdb_py_events.free_objfile)) + return 0; + + gdbpy_ref<> event =3D create_free_objfile_event_object (objfile); + if (event =3D=3D nullptr) + return -1; + return evpy_emit_event (event.get (), gdb_py_events.free_objfile); +} + =0C /* Subroutine of emit_clear_objfiles_event to simplify it. */ =20 diff --git a/gdb/testsuite/gdb.python/py-event-load.c b/gdb/testsuite/gdb.p= ython/py-event-load.c new file mode 100644 index 00000000000..de89c5eff5a --- /dev/null +++ b/gdb/testsuite/gdb.python/py-event-load.c @@ -0,0 +1,42 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2022 Free Software Foundation, Inc. + + 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 . = */ + +#include + +#ifdef __WIN32__ +#include +#define dlopen(name, mode) LoadLibrary (TEXT (name)) +#define dlclose(handle) FreeLibrary (handle) +#else +#include +#endif + +/* This is updated by the .exp file. */ +char *libname =3D "py-events-shlib.so"; + +int +main () +{ + void *h; + + h =3D dlopen (libname, RTLD_LAZY); + + dlclose (h); + + h =3D NULL; /* final breakpoint here */ + return 0; +} diff --git a/gdb/testsuite/gdb.python/py-event-load.exp b/gdb/testsuite/gdb= .python/py-event-load.exp new file mode 100644 index 00000000000..f7aeb5f33fb --- /dev/null +++ b/gdb/testsuite/gdb.python/py-event-load.exp @@ -0,0 +1,67 @@ +# Copyright 2022 Free Software Foundation, Inc. +# +# 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 . +# + +# Test the Python free_objfile event. + +load_lib gdb-python.exp + +if {[skip_shlib_tests]} { + untested "skipping shared library tests" + return -1 +} + +if {[get_compiler_info]} { + warning "Could not get compiler info" + untested "no compiler info" + return -1 +} + +standard_testfile .c +if {[gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ + executable {debug shlib_load}] !=3D ""} { + untested "failed to compile" + return -1 +} + +set testfile2 py-events-shlib +set srcfile2 ${testfile2}.c +set binfile2 [standard_output_file ${testfile2}.so] +set binfile2_dlopen [shlib_target_file ${testfile2}.so] +if {[gdb_compile_shlib "${srcdir}/${subdir}/${srcfile2}" \ + ${binfile2} {debug}] !=3D ""} { + untested "failed to compile shared library" + return -1 +} + +clean_restart $testfile + +if {![runto_main]} { + return +} + +if { [skip_python_tests] } { return } + +gdb_test_no_output "set var libname =3D \"$binfile2_dlopen\"" + +set pyfile [gdb_remote_download host ${srcdir}/${subdir}/py-event-load.py] +gdb_test_no_output "source ${pyfile}" "load python file" + +gdb_breakpoint [gdb_get_line_number "final breakpoint here"] + +gdb_continue_to_breakpoint "run to final breakpoint" + +gdb_test "python print(freed_objfile)" [string_to_regexp $binfile2_dlopen]= \ + "print name of unloaded objfile" diff --git a/gdb/testsuite/gdb.python/py-event-load.py b/gdb/testsuite/gdb.= python/py-event-load.py new file mode 100644 index 00000000000..9cf56115205 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-event-load.py @@ -0,0 +1,30 @@ +# Copyright (C) 2022 Free Software Foundation, Inc. + +# 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 . + +# Test Python free_objfile event. + +import gdb + + +freed_objfile =3D None + + +def free_objfile_handler(event): + assert isinstance(event, gdb.FreeObjFileEvent) + global freed_objfile + freed_objfile =3D event.objfile.username + + +gdb.events.free_objfile.connect(free_objfile_handler)