Subject: Re: bug#61973: M-x gdb ends up with infinite prompts before starting the process

From: Eli Zaretskii <[email-masked]>
Date: Mon, 06 Mar 2023 20:22:57 +0200

> Date: Sun, 5 Mar 2023 17:26:08 +0200
> Cc: [email-masked]
> From: Dmitry Gutov <[email-masked]>
> 
> On 05/03/2023 17:19, Eli Zaretskii wrote:
> > This confirms my suspicion: we don't recognize the situation
> > where GDB waits for a response, and interpret your "y" response as a
> > GDB command.
> 
> First of all, though, it sends the debuginfod-related prompt to me 12 
> times. I'm guessing that's because there is some scenario running 
> internally that tries to send some other commands to GDB while it's 
> waiting for a particular response (y/n), so it repeats the question 11 
> times instead of reacting to those commands.

Could you please try the patch below?  I don't have access to a system
where GDB can actually download the files from debuginfod servers, so
I could test this only partially.  Please test all the 3 possible
values of the new defcustom gdb-debuginfod-enable-setting.  TIA.

diff --git a/lisp/progmodes/gdb-mi.el b/lisp/progmodes/gdb-mi.el
index 8b157dd..dc18938 100644
--- a/lisp/progmodes/gdb-mi.el
+++ b/lisp/progmodes/gdb-mi.el
@@ -255,6 +255,9 @@ gdb-non-stop
 It is initialized to `gdb-non-stop-setting' at the beginning of
 every GDB session.")
 
+(defvar gdb-debuginfod-enable nil
+  "Whether the current GDB session can query debuginfod servers.")
+
 (defvar-local gdb-buffer-type nil
   "One of the symbols bound in `gdb-buffer-rules'.")
 
@@ -467,6 +470,26 @@ gdb-non-stop-setting
   :group 'gdb-non-stop
   :version "26.1")
 
+(defcustom gdb-debuginfod-enable-setting 'ask
+  "Whether to enable downloading missing debug info from debuginfod servers.
+The debuginfod servers are HTTP servers for distributing source
+files and debug info files of programs.  If GDB was built with
+debuginfod support, it can query these servers when you debug a
+program for which some of these files are not available locally,
+and download the files if the servers have them.
+
+The value nil means never to download from debuginfod servers.
+The value t means always download from debuginfod servers when
+some source or debug info files are missing.
+The value `ask', the default, means ask at the beginning of each
+debugging session whether to download from debuginfod servers
+during that session."
+  :type '(choice (const :tag "Never download from debuginfod servers" nil)
+                 (const :tag "Download from debuginfod servers when necessary" t)
+                 (const :tag "Ask whether to download for each session" ask))
+  :group 'gdb
+  :version "29.1")
+
 ;; TODO Some commands can't be called with --all (give a notice about
 ;; it in setting doc)
 (defcustom gdb-gud-control-all-threads t
@@ -1021,6 +1044,11 @@ gdb
 
   (run-hooks 'gdb-mode-hook))
 
+(defconst gdb--string-regexp (rx "\""
+                                 (* (or (seq "\\" nonl)
+                                        (not (any "\"\\"))))
+                                 "\""))
+
 (defun gdb-init-1 ()
   ;; (Re-)initialize.
   (setq gdb-selected-frame nil
@@ -1044,7 +1072,8 @@ gdb-init-1
         gdb-threads-list '()
         gdb-breakpoints-list '()
         gdb-register-names '()
-        gdb-non-stop gdb-non-stop-setting)
+        gdb-non-stop gdb-non-stop-setting
+        gdb-debuginfod-enable gdb-debuginfod-enable-setting)
   ;;
   (gdbmi-bnf-init)
   ;;
@@ -1053,6 +1082,15 @@ gdb-init-1
   (gdb-force-mode-line-update
    (propertize "initializing..." 'face font-lock-variable-name-face))
 
+  ;; This needs to be done before we ask GDB for anything that might
+  ;; trigger questions about debuginfod queries.
+  (if (eq gdb-debuginfod-enable 'ask)
+      (setq gdb-debuginfod-enable
+            (y-or-n-p "Enable querying debuginfod servers for this session?")))
+  (gdb-input (format "-gdb-set debuginfod enabled %s"
+                     (if gdb-debuginfod-enable "on" "off"))
+             'gdb-debuginfod-message)
+
   (gdb-get-buffer-create 'gdb-inferior-io)
   (gdb-clear-inferior-io)
   (gdb-inferior-io--init-proc (get-process "gdb-inferior"))
@@ -1080,6 +1118,18 @@ gdb-init-1
   (gdb-input "-file-list-exec-source-file" 'gdb-get-source-file)
   (gdb-input "-gdb-show prompt" 'gdb-get-prompt))
 
+(defun gdb-debuginfod-message ()
+  "Show in the echo area GDB error response for a debuginfod command, if any."
+  (goto-char (point-min))
+  (cond
+   ((re-search-forward  "msg=\\(\".+\"\\)$" nil t)
+    ;; Supports debuginfod, but cannot perform command.
+    (message "%s" (buffer-substring (1+ (match-beginning 1))
+                                    (1- (line-end-position)))))
+   ((re-search-forward "No symbol" nil t)
+    (message "This version of GDB doesn't support debuginfod commands."))
+   (t (message nil))))
+
 (defun gdb-non-stop-handler ()
   (goto-char (point-min))
   (if (re-search-forward "No symbol" nil t)
@@ -1148,11 +1198,6 @@ gdb-create-define-alist
 (declare-function tooltip-show "tooltip" (text &optional use-echo-area
                                                text-face default-face))
 
-(defconst gdb--string-regexp (rx "\""
-                                 (* (or (seq "\\" nonl)
-                                        (not (any "\"\\"))))
-                                 "\""))
-
 (defun gdb-tooltip-print (expr)
   (with-current-buffer (gdb-get-buffer 'gdb-partial-output-buffer)
     (goto-char (point-min))