public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Add gdb.free_objfile event registry
@ 2022-06-20 17:36 Tom Tromey
  2022-06-20 18:21 ` Eli Zaretskii
  2022-06-20 18:36 ` Lancelot SIX
  0 siblings, 2 replies; 4+ messages in thread
From: Tom Tromey @ 2022-06-20 17:36 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

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.
---
 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(+)
 create mode 100644 gdb/testsuite/gdb.python/py-event-load.c
 create mode 100644 gdb/testsuite/gdb.python/py-event-load.exp
 create mode 100644 gdb/testsuite/gdb.python/py-event-load.py

diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 9e2e97b1e74..7d2c6e323a1 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -3470,6 +3470,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
 
+@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);
 
+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 (PyTypeObject *py_type,
 					       PyObject *thread);
 
 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);
 
 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)
     }
 }
 
+/* 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-newobjfileevent.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;
 }
 
+/* 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
+    = create_event_object (&free_objfile_event_object_type);
+  if (objfile_event == nullptr)
+    return nullptr;
+
+  gdbpy_ref<> py_objfile = objfile_to_objfile_object (objfile);
+  if (py_objfile == 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 = create_free_objfile_event_object (objfile);
+  if (event == nullptr)
+    return -1;
+  return evpy_emit_event (event.get (), gdb_py_events.free_objfile);
+}
+
 \f
 /* Subroutine of emit_clear_objfiles_event to simplify it.  */
 
diff --git a/gdb/testsuite/gdb.python/py-event-load.c b/gdb/testsuite/gdb.python/py-event-load.c
new file mode 100644
index 00000000000..515b4b0be08
--- /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 2010-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  <http://www.gnu.org/licenses/>.  */
+
+#include <unistd.h>
+
+#ifdef __WIN32__
+#include <windows.h>
+#define dlopen(name, mode) LoadLibrary (TEXT (name))
+#define dlclose(handle) FreeLibrary (handle)
+#else
+#include <dlfcn.h>
+#endif
+
+/* This is updated by the .exp file.  */
+char *libname = "catch-load-so.so";
+
+int
+main ()
+{
+  void *h;
+
+  h = dlopen (libname, RTLD_LAZY);
+
+  dlclose (h);
+
+  h = 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 <http://www.gnu.org/licenses/>.
+#
+
+# 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}] != ""} {
+    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}] != ""} {
+    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 = \"$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 <http://www.gnu.org/licenses/>.
+
+# Test Python free_objfile event.
+
+import gdb
+
+
+freed_objfile = None
+
+
+def free_objfile_handler(event):
+    assert isinstance(event, gdb.FreeObjFileEvent)
+    global freed_objfile
+    freed_objfile = event.objfile.username
+
+
+gdb.events.free_objfile.connect(free_objfile_handler)
-- 
2.34.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] Add gdb.free_objfile event registry
  2022-06-20 17:36 [PATCH] Add gdb.free_objfile event registry Tom Tromey
@ 2022-06-20 18:21 ` Eli Zaretskii
  2022-06-20 18:36 ` Lancelot SIX
  1 sibling, 0 replies; 4+ messages in thread
From: Eli Zaretskii @ 2022-06-20 18:21 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

> Date: Mon, 20 Jun 2022 11:36:22 -0600
> From: Tom Tromey via Gdb-patches <gdb-patches@sourceware.org>
> Cc: Tom Tromey <tromey@adacore.com>
> 
> 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.
> ---
>  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(+)
>  create mode 100644 gdb/testsuite/gdb.python/py-event-load.c
>  create mode 100644 gdb/testsuite/gdb.python/py-event-load.exp
>  create mode 100644 gdb/testsuite/gdb.python/py-event-load.py

Thanks, the documentation part is OK.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] Add gdb.free_objfile event registry
  2022-06-20 17:36 [PATCH] Add gdb.free_objfile event registry Tom Tromey
  2022-06-20 18:21 ` Eli Zaretskii
@ 2022-06-20 18:36 ` Lancelot SIX
  2022-07-18 17:25   ` Tom Tromey
  1 sibling, 1 reply; 4+ messages in thread
From: Lancelot SIX @ 2022-06-20 18:36 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

Hi,

I have minor remarks / questions down below.

> diff --git a/gdb/testsuite/gdb.python/py-event-load.c b/gdb/testsuite/gdb.python/py-event-load.c
> new file mode 100644
> index 00000000000..515b4b0be08
> --- /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 2010-2022 Free Software Foundation, Inc.

Is the 2010 intentional?  It looks that this file is copied from
gdb.base/catch-load.c which is marked 2012-2022.

> +
> +   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 <unistd.h>
> +
> +#ifdef __WIN32__
> +#include <windows.h>
> +#define dlopen(name, mode) LoadLibrary (TEXT (name))
> +#define dlclose(handle) FreeLibrary (handle)
> +#else
> +#include <dlfcn.h>
> +#endif
> +
> +/* This is updated by the .exp file.  */
> +char *libname = "catch-load-so.so";

To be "consistent" with other files which uses this pattern, shouldn't
the default libname reflect the test name? Something like
py-event-load-so.so I guess.  Later in the test you use
"py-events-shlib.so" as actual libname.

> +
> +int
> +main ()
> +{
> +  void *h;
> +
> +  h = dlopen (libname, RTLD_LAZY);
> +
> +  dlclose (h);
> +
> +  h = 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 <http://www.gnu.org/licenses/>.
> +#
> +
> +# 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}] != ""} {
> +    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}] != ""} {
> +    untested "failed to compile shared library"
> +    return -1
> +}
> +
> +clean_restart $testfile
> +
> +if {![runto_main]} {
> +    return
> +}
> +
> +if { [skip_python_tests] } { return }

I guess that this skip check can be moved above (together with the
skip_shlib_tests), so on target which skip python tests we do not bother
compiling the test program.  WDYT?

Best,
Lancelot.

> +
> +gdb_test_no_output "set var libname = \"$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 <http://www.gnu.org/licenses/>.
> +
> +# Test Python free_objfile event.
> +
> +import gdb
> +
> +
> +freed_objfile = None
> +
> +
> +def free_objfile_handler(event):
> +    assert isinstance(event, gdb.FreeObjFileEvent)
> +    global freed_objfile
> +    freed_objfile = event.objfile.username
> +
> +
> +gdb.events.free_objfile.connect(free_objfile_handler)
> -- 
> 2.34.1
> 

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] Add gdb.free_objfile event registry
  2022-06-20 18:36 ` Lancelot SIX
@ 2022-07-18 17:25   ` Tom Tromey
  0 siblings, 0 replies; 4+ messages in thread
From: Tom Tromey @ 2022-07-18 17:25 UTC (permalink / raw)
  To: Lancelot SIX; +Cc: Tom Tromey, gdb-patches

>> +   Copyright 2010-2022 Free Software Foundation, Inc.

Lancelot> Is the 2010 intentional?  It looks that this file is copied from
Lancelot> gdb.base/catch-load.c which is marked 2012-2022.

I changed it to just 2022.

>> +/* This is updated by the .exp file.  */
>> +char *libname = "catch-load-so.so";

Lancelot> To be "consistent" with other files which uses this pattern, shouldn't
Lancelot> the default libname reflect the test name? Something like
Lancelot> py-event-load-so.so I guess.  Later in the test you use
Lancelot> "py-events-shlib.so" as actual libname.

I updated this.

>> +clean_restart $testfile
>> +
>> +if {![runto_main]} {
>> +    return
>> +}
>> +
>> +if { [skip_python_tests] } { return }

Lancelot> I guess that this skip check can be moved above (together with the
Lancelot> skip_shlib_tests), so on target which skip python tests we do not bother
Lancelot> compiling the test program.  WDYT?

Unfortunately, skip_python_tests requires that gdb already be running.

I'm going to check in the updated patch now.

Tom

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-07-18 17:25 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-20 17:36 [PATCH] Add gdb.free_objfile event registry Tom Tromey
2022-06-20 18:21 ` Eli Zaretskii
2022-06-20 18:36 ` Lancelot SIX
2022-07-18 17:25   ` Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).