Subject: bug#79144: [PATCH] New debugger-trap function to break to GDB

From: Jeremy Bryant <[email-masked]>
Date: Sun, 03 Aug 2025 22:41:18 +0100

Paul Eggert <[email-masked]> writes:

> On 2025-08-02 13:10, Jeremy Bryant wrote:
>> Would the following clarification be clearer from your perspective?
>>         doc: /* Trap execution flow and hand over control to GDB.
>> To use, set up a breakpoint in GDB with
>> break Fdebugger_trap
>> This is done in the Emacs source distribution in src/.gdbinit.
>> The function itself is a do-nothing primitive.  It is reserved for
>> debugging purposes, and not called by Emacs otherwise.  */)
>
> Yes, thanks. Some minor wording tweaks, which make it easier for me to
> understand:
>
> Trap execution flow and hand over control to GDB. The Emacs source
> file src/.gdbinit uses this via the GDB command "break Fdebugger
> trap".
>
> This function has no effect.  It is reserved for debugging, and is not
> called by Emacs otherwise.

OK, revised patch attached for consideration.

The change is in the docstring, incorporating your suggestion, Paul, as
well as the addition proposed by Jim, at the end.

What do people think of this change now?

Extract of patch for the docstring:-

DEFUN ("debugger-trap", Fdebugger_trap, Sdebugger_trap, 0, 0, "",
       doc: /* Trap execution flow and hand over control to GDB.
The Emacs source file src/.gdbinit uses this via the GDB command
"break Fdebugger_trap".

This function has no effect.  It is reserved for debugging, and is not
called by Emacs otherwise.

For Lisp debugging see debug, as well as edebug, in the manual:
"(elisp) Debugging".  */)
  (void)
{
  return Qnil;
}

>From 0a8dc27576090e863c92a0abc5461b0241714313 Mon Sep 17 00:00:00 2001
From: Jeremy Bryant <[email-masked]>
Date: Wed, 23 Jul 2025 23:35:01 +0100
Subject: [PATCH] New debugger-trap function to break to GDB

* src/eval.c: new primitive debugger-trap
* src/.gdbinit: set breakpoint to Fdebugger_trap
* etc/DEBUG: document it.
Remove suggestion to use Fredraw_display.

This do-nothing primitive gives control to GDB, and for debugging
convenience a breakpoint is set by default in .gdbinit.
---
 etc/DEBUG    | 11 ++++++-----
 src/.gdbinit |  5 +++++
 src/eval.c   | 16 ++++++++++++++++
 3 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/etc/DEBUG b/etc/DEBUG
index 25049ad42b4..44f19900c64 100644
--- a/etc/DEBUG
+++ b/etc/DEBUG
@@ -211,16 +211,17 @@ the debugger, but before running it, is the most efficient way of
 making sure control will be returned to the debugger when you need
 that.
 
+There is a default function to give control to the debugger.  It is
+called debugger-trap.  This is a do-nothing primitive, as a convenient
+point to return control to the debugger.  You can invoke interactively
+with "M-x debugger-trap RET".  The src/.gdbinit file in the Emacs source
+distribution sets a breakpoint on this function.
+
 'Fsignal' is a very useful place to put a breakpoint in.  All Lisp
 errors go through there.  If you are only interested in errors that
 would fire the Lisp debugger, breaking at 'maybe_call_debugger' is
 useful.
 
-Another technique for getting control to the debugger is to put a
-breakpoint in some rarely used function.  One such convenient function
-is Fredraw_display, which you can invoke at will interactively with
-"M-x redraw-display RET".
-
 It is also useful to have a guaranteed way to return to the debugger
 at any arbitrary time.  When using X, this is easy: type C-z at the
 window where you are interacting with GDB, and it will stop Emacs just
diff --git a/src/.gdbinit b/src/.gdbinit
index d3bfad59486..0eab7ac9afa 100644
--- a/src/.gdbinit
+++ b/src/.gdbinit
@@ -1314,6 +1314,11 @@ if defined_WINDOWSNT
   end
 end
 
+# Break at default trap function to give control to GDB.
+# Call from Emacs with M-x debugger-trap
+break Fdebugger_trap
+
+
 # Put the Python code at the end of .gdbinit so that if GDB does not
 # support Python, GDB will do all the above initializations before
 # reporting an error.
diff --git a/src/eval.c b/src/eval.c
index 5e2b5bff796..ab2d53815de 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -3089,6 +3089,21 @@ FUNCTIONP (Lisp_Object object)
     return false;
 }
 
+DEFUN ("debugger-trap", Fdebugger_trap, Sdebugger_trap, 0, 0, "",
+       doc: /* Trap execution flow and hand over control to GDB.
+The Emacs source file src/.gdbinit uses this via the GDB command
+"break Fdebugger_trap".
+
+This function has no effect.  It is reserved for debugging, and is not
+called by Emacs otherwise.
+
+For Lisp debugging see debug, as well as edebug, in the manual:
+"(elisp) Debugging".  */)
+  (void)
+{
+  return Qnil;
+}
+
 Lisp_Object
 funcall_general (Lisp_Object fun, ptrdiff_t numargs, Lisp_Object *args)
 {
@@ -4615,4 +4630,5 @@ syms_of_eval (void)
   defsubr (&Sspecial_variable_p);
   DEFSYM (Qfunctionp, "functionp");
   defsubr (&Sfunctionp);
+  defsubr (&Sdebugger_trap);
 }
-- 
2.47.2