* lisp/progmodes/gdb-mi.el (gdbmi-bnf-incomplete-record-result):
[bpt/emacs.git] / lisp / progmodes / gdb-mi.el
CommitLineData
6ff2c8f1 1;;; gdb-mi.el --- User Interface for running GDB -*- lexical-binding: t -*-
691cf4a0 2
ab422c4d 3;; Copyright (C) 2007-2013 Free Software Foundation, Inc.
691cf4a0
NR
4
5;; Author: Nick Roberts <nickrob@gnu.org>
6;; Maintainer: FSF
7;; Keywords: unix, tools
8
9;; This file is part of GNU Emacs.
10
11;; Homepage: http://www.emacswiki.org/emacs/GDB-MI
12
13;; GNU Emacs is free software: you can redistribute it and/or modify
14;; it under the terms of the GNU General Public License as published by
15;; the Free Software Foundation, either version 3 of the License, or
16;; (at your option) any later version.
17
18;; GNU Emacs is distributed in the hope that it will be useful,
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details.
22
23;; You should have received a copy of the GNU General Public License
24;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
25
26;;; Credits:
27
7877f373 28;; This file was written by Nick Roberts following the general design
d0045ba0 29;; used in gdb-ui.el for Emacs 22.1 - 23.1. It was further developed
691cf4a0
NR
30;; by Dmitry Dzhus <dima@sphinx.net.ru> as part of the Google Summer
31;; of Code 2009 Project "Emacs GDB/MI migration".
32
33;;; Commentary:
34
35;; This mode acts as a graphical user interface to GDB. You can interact with
36;; GDB through the GUD buffer in the usual way, but there are also further
37;; buffers which control the execution and describe the state of your program.
38;; It separates the input/output of your program from that of GDB and displays
39;; expressions and their current values in their own buffers. It also uses
40;; features of Emacs 21 such as the fringe/display margin for breakpoints, and
41;; the toolbar (see the GDB Graphical Interface section in the Emacs info
42;; manual).
43
44;; M-x gdb will start the debugger.
45
ee1f1da9
SM
46;; This file uses GDB/MI as the primary interface to GDB. It runs gdb with
47;; GDB/MI (-interp=mi) and access CLI using "-interpreter-exec console
9e7056a5 48;; cli-command". This code replaces gdb-ui.el and uses MI tokens instead
ee1f1da9 49;; of queues. Eventually MI should be asynchronous.
691cf4a0
NR
50
51;; Windows Platforms:
52
53;; If you are using Emacs and GDB on Windows you will need to flush the buffer
54;; explicitly in your program if you want timely display of I/O in Emacs.
55;; Alternatively you can make the output stream unbuffered, for example, by
56;; using a macro:
57
58;; #ifdef UNBUFFERED
59;; setvbuf (stdout, (char *) NULL, _IONBF, 0);
60;; #endif
61
62;; and compiling with -DUNBUFFERED while debugging.
63
64;; If you are using Cygwin GDB and find that the source is not being displayed
65;; in Emacs when you step through it, possible solutions are to:
66
67;; 1) Use Cygwin X Windows and Cygwin Emacs.
68;; (Since 22.1 Emacs builds under Cygwin.)
69;; 2) Use MinGW GDB instead.
70;; 3) Use cygwin-mount.el
71
72;;; Mac OSX:
73
74;; GDB in Emacs on Mac OSX works best with FSF GDB as Apple have made
75;; some changes to the version that they include as part of Mac OSX.
76;; This requires GDB version 7.0 or later (estimated release date Aug 2009)
fe7a3057 77;; as earlier versions do not compile on Mac OSX.
691cf4a0
NR
78
79;;; Known Bugs:
80
81;; 1) Stack buffer doesn't parse MI output if you stop in a routine without
82;; line information, e.g., a routine in libc (just a TODO item).
83
84;; TODO:
85;; 2) Watch windows to work with threads.
86;; 3) Use treebuffer.el instead of the speedbar for watch-expressions?
87;; 4) Mark breakpoint locations on scroll-bar of source buffer?
88
89;;; Code:
90
91(require 'gud)
92(require 'json)
93(require 'bindat)
a464a6c7 94(eval-when-compile (require 'cl-lib))
691cf4a0 95
3db614b0
SM
96(declare-function speedbar-change-initial-expansion-list
97 "speedbar" (new-default))
e02f48d7
JB
98(declare-function speedbar-timer-fn "speedbar" ())
99(declare-function speedbar-line-text "speedbar" (&optional p))
100(declare-function speedbar-change-expand-button-char "speedbar" (char))
101(declare-function speedbar-delete-subblock "speedbar" (indent))
102(declare-function speedbar-center-buffer-smartly "speedbar" ())
103
691cf4a0
NR
104(defvar tool-bar-map)
105(defvar speedbar-initial-expansion-list-name)
106(defvar speedbar-frame)
107
108(defvar gdb-memory-address "main")
109(defvar gdb-memory-last-address nil
110 "Last successfully accessed memory address.")
111(defvar gdb-memory-next-page nil
112 "Address of next memory page for program memory buffer.")
113(defvar gdb-memory-prev-page nil
114 "Address of previous memory page for program memory buffer.")
115
116(defvar gdb-thread-number nil
117 "Main current thread.
118
119Invalidation triggers use this variable to query GDB for
120information on the specified thread by wrapping GDB/MI commands
121in `gdb-current-context-command'.
122
123This variable may be updated implicitly by GDB via `gdb-stopped'
124or explicitly by `gdb-select-thread'.
125
126Only `gdb-setq-thread-number' should be used to change this
127value.")
128
129(defvar gdb-frame-number nil
130 "Selected frame level for main current thread.
131
132Updated according to the following rules:
133
134When a thread is selected or current thread stops, set to \"0\".
135
136When current thread goes running (and possibly exits eventually),
137set to nil.
138
139May be manually changed by user with `gdb-select-frame'.")
140
141(defvar gdb-frame-address nil "Identity of frame for watch expression.")
142
143;; Used to show overlay arrow in source buffer. All set in
144;; gdb-get-main-selected-frame. Disassembly buffer should not use
145;; these but rely on buffer-local thread information instead.
146(defvar gdb-selected-frame nil
147 "Name of selected function for main current thread.")
148(defvar gdb-selected-file nil
149 "Name of selected file for main current thread.")
150(defvar gdb-selected-line nil
151 "Number of selected line for main current thread.")
152
153(defvar gdb-threads-list nil
154 "Associative list of threads provided by \"-thread-info\" MI command.
155
156Keys are thread numbers (in strings) and values are structures as
157returned from -thread-info by `gdb-json-partial-output'. Updated in
158`gdb-thread-list-handler-custom'.")
159
160(defvar gdb-running-threads-count nil
161 "Number of currently running threads.
162
40b1a3a9 163If nil, no information is available.
691cf4a0
NR
164
165Updated in `gdb-thread-list-handler-custom'.")
166
167(defvar gdb-stopped-threads-count nil
168 "Number of currently stopped threads.
169
170See also `gdb-running-threads-count'.")
171
172(defvar gdb-breakpoints-list nil
173 "Associative list of breakpoints provided by \"-break-list\" MI command.
174
175Keys are breakpoint numbers (in string) and values are structures
176as returned from \"-break-list\" by `gdb-json-partial-output'
177\(\"body\" field is used). Updated in
178`gdb-breakpoints-list-handler-custom'.")
179
180(defvar gdb-current-language nil)
181(defvar gdb-var-list nil
182 "List of variables in watch window.
3db614b0
SM
183Each element has the form
184 (VARNUM EXPRESSION NUMCHILD TYPE VALUE STATUS HAS_MORE FP)
691cf4a0
NR
185where STATUS is nil (`unchanged'), `changed' or `out-of-scope', FP the frame
186address for root variables.")
187(defvar gdb-main-file nil "Source file from which program execution begins.")
188
189;; Overlay arrow markers
190(defvar gdb-stack-position nil)
191(defvar gdb-thread-position nil)
192(defvar gdb-disassembly-position nil)
193
194(defvar gdb-location-alist nil
6ff2c8f1
JPG
195 "Alist of breakpoint numbers and full filenames.
196Only used for files that Emacs can't find.")
691cf4a0
NR
197(defvar gdb-active-process nil
198 "GUD tooltips display variable values when t, and macro definitions otherwise.")
199(defvar gdb-error "Non-nil when GDB is reporting an error.")
200(defvar gdb-macro-info nil
201 "Non-nil if GDB knows that the inferior includes preprocessor macro info.")
202(defvar gdb-register-names nil "List of register names.")
203(defvar gdb-changed-registers nil
204 "List of changed register numbers (strings).")
205(defvar gdb-buffer-fringe-width nil)
206(defvar gdb-last-command nil)
207(defvar gdb-prompt-name nil)
208(defvar gdb-token-number 0)
209(defvar gdb-handler-alist '())
210(defvar gdb-handler-number nil)
211(defvar gdb-source-file-list nil
212 "List of source files for the current executable.")
213(defvar gdb-first-done-or-error t)
214(defvar gdb-source-window nil)
215(defvar gdb-inferior-status nil)
216(defvar gdb-continuation nil)
087ef505 217(defvar gdb-supports-non-stop nil)
691cf4a0
NR
218(defvar gdb-filter-output nil
219 "Message to be shown in GUD console.
220
221This variable is updated in `gdb-done-or-error' and returned by
222`gud-gdbmi-marker-filter'.")
223
224(defvar gdb-non-stop nil
225 "Indicates whether current GDB session is using non-stop mode.
226
227It is initialized to `gdb-non-stop-setting' at the beginning of
228every GDB session.")
229
6ff2c8f1 230(defvar-local gdb-buffer-type nil
691cf4a0 231 "One of the symbols bound in `gdb-buffer-rules'.")
691cf4a0
NR
232
233(defvar gdb-output-sink 'nil
234 "The disposition of the output of the current gdb command.
235Possible values are these symbols:
236
237 `user' -- gdb output should be copied to the GUD buffer
238 for the user to see.
239
240 `emacs' -- output should be collected in the partial-output-buffer
241 for subsequent processing by a command. This is the
242 disposition of output generated by commands that
243 gdb mode sends to gdb on its own behalf.")
244
245;; Pending triggers prevent congestion: Emacs won't send two similar
246;; consecutive requests.
247
248(defvar gdb-pending-triggers '()
249 "A list of trigger functions which have not yet been handled.
250
251Elements are either function names or pairs (buffer . function)")
252
253(defmacro gdb-add-pending (item)
254 `(push ,item gdb-pending-triggers))
255(defmacro gdb-pending-p (item)
256 `(member ,item gdb-pending-triggers))
257(defmacro gdb-delete-pending (item)
258 `(setq gdb-pending-triggers
259 (delete ,item gdb-pending-triggers)))
260
261(defmacro gdb-wait-for-pending (&rest body)
262 "Wait until `gdb-pending-triggers' is empty and evaluate FORM.
263
264This function checks `gdb-pending-triggers' value every
265`gdb-wait-for-pending' seconds."
266 (run-with-timer
267 0.5 nil
268 `(lambda ()
269 (if (not gdb-pending-triggers)
270 (progn ,@body)
271 (gdb-wait-for-pending ,@body)))))
272
273;; Publish-subscribe
274
275(defmacro gdb-add-subscriber (publisher subscriber)
276 "Register new PUBLISHER's SUBSCRIBER.
277
278SUBSCRIBER must be a pair, where cdr is a function of one
279argument (see `gdb-emit-signal')."
280 `(add-to-list ',publisher ,subscriber t))
281
282(defmacro gdb-delete-subscriber (publisher subscriber)
283 "Unregister SUBSCRIBER from PUBLISHER."
284 `(setq ,publisher (delete ,subscriber
285 ,publisher)))
286
287(defun gdb-get-subscribers (publisher)
288 publisher)
289
290(defun gdb-emit-signal (publisher &optional signal)
291 "Call cdr for each subscriber of PUBLISHER with SIGNAL as argument."
292 (dolist (subscriber (gdb-get-subscribers publisher))
293 (funcall (cdr subscriber) signal)))
294
295(defvar gdb-buf-publisher '()
6ff2c8f1 296 "Used to invalidate GDB buffers by emitting a signal in `gdb-update'.
691cf4a0
NR
297Must be a list of pairs with cars being buffers and cdr's being
298valid signal handlers.")
299
300(defgroup gdb nil
301 "GDB graphical interface"
302 :group 'tools
303 :link '(info-link "(emacs)GDB Graphical Interface")
304 :version "23.2")
305
306(defgroup gdb-non-stop nil
307 "GDB non-stop debugging settings"
308 :group 'gdb
309 :version "23.2")
310
311(defgroup gdb-buffers nil
312 "GDB buffers"
313 :group 'gdb
314 :version "23.2")
315
316(defcustom gdb-debug-log-max 128
317 "Maximum size of `gdb-debug-log'. If nil, size is unlimited."
318 :group 'gdb
319 :type '(choice (integer :tag "Number of elements")
3db614b0 320 (const :tag "Unlimited" nil))
691cf4a0
NR
321 :version "22.1")
322
323(defcustom gdb-non-stop-setting t
324 "When in non-stop mode, stopped threads can be examined while
325other threads continue to execute.
326
6ff2c8f1 327GDB session needs to be restarted for this setting to take effect."
691cf4a0
NR
328 :type 'boolean
329 :group 'gdb-non-stop
330 :version "23.2")
331
332;; TODO Some commands can't be called with --all (give a notice about
333;; it in setting doc)
334(defcustom gdb-gud-control-all-threads t
6ff2c8f1
JPG
335 "When non-nil, GUD execution commands affect all threads when
336in non-stop mode. Otherwise, only current thread is affected."
691cf4a0
NR
337 :type 'boolean
338 :group 'gdb-non-stop
339 :version "23.2")
340
341(defcustom gdb-switch-reasons t
6ff2c8f1
JPG
342 "List of stop reasons for which Emacs should switch thread.
343When t, switch to stopped thread no matter what the reason was.
344When nil, never switch to stopped thread automatically.
691cf4a0 345
6ff2c8f1 346This setting is used in non-stop mode only. In all-stop mode,
691cf4a0 347Emacs always switches to the thread which caused the stop."
8350f087 348 ;; exited, exited-normally and exited-signaled are not
691cf4a0
NR
349 ;; thread-specific stop reasons and therefore are not included in
350 ;; this list
351 :type '(choice
352 (const :tag "All reasons" t)
353 (set :tag "Selection of reasons..."
354 (const :tag "A breakpoint was reached." "breakpoint-hit")
355 (const :tag "A watchpoint was triggered." "watchpoint-trigger")
3db614b0
SM
356 (const :tag "A read watchpoint was triggered."
357 "read-watchpoint-trigger")
358 (const :tag "An access watchpoint was triggered."
359 "access-watchpoint-trigger")
691cf4a0
NR
360 (const :tag "Function finished execution." "function-finished")
361 (const :tag "Location reached." "location-reached")
3db614b0
SM
362 (const :tag "Watchpoint has gone out of scope"
363 "watchpoint-scope")
364 (const :tag "End of stepping range reached."
365 "end-stepping-range")
366 (const :tag "Signal received (like interruption)."
367 "signal-received"))
691cf4a0
NR
368 (const :tag "None" nil))
369 :group 'gdb-non-stop
370 :version "23.2"
371 :link '(info-link "(gdb)GDB/MI Async Records"))
372
b668fa6e
CY
373(defcustom gdb-stopped-functions nil
374 "List of functions called whenever GDB stops.
691cf4a0
NR
375
376Each function takes one argument, a parsed MI response, which
377contains fields of corresponding MI *stopped async record:
378
379 ((stopped-threads . \"all\")
380 (thread-id . \"1\")
381 (frame (line . \"38\")
382 (fullname . \"/home/sphinx/projects/gsoc/server.c\")
383 (file . \"server.c\")
384 (args ((value . \"0x804b038\")
385 (name . \"arg\")))
386 (func . \"hello\")
387 (addr . \"0x0804869e\"))
388 (reason . \"end-stepping-range\"))
389
390Note that \"reason\" is only present in non-stop debugging mode.
391
392`bindat-get-field' may be used to access the fields of response.
393
394Each function is called after the new current thread was selected
395and GDB buffers were updated in `gdb-stopped'."
396 :type '(repeat function)
397 :group 'gdb
398 :version "23.2"
399 :link '(info-link "(gdb)GDB/MI Async Records"))
400
401(defcustom gdb-switch-when-another-stopped t
6ff2c8f1 402 "When nil, don't switch to stopped thread if some other
691cf4a0
NR
403stopped thread is already selected."
404 :type 'boolean
405 :group 'gdb-non-stop
406 :version "23.2")
407
408(defcustom gdb-stack-buffer-locations t
409 "Show file information or library names in stack buffers."
410 :type 'boolean
411 :group 'gdb-buffers
412 :version "23.2")
413
414(defcustom gdb-stack-buffer-addresses nil
415 "Show frame addresses in stack buffers."
416 :type 'boolean
417 :group 'gdb-buffers
418 :version "23.2")
419
420(defcustom gdb-thread-buffer-verbose-names t
421 "Show long thread names in threads buffer."
422 :type 'boolean
423 :group 'gdb-buffers
424 :version "23.2")
425
426(defcustom gdb-thread-buffer-arguments t
427 "Show function arguments in threads buffer."
428 :type 'boolean
429 :group 'gdb-buffers
430 :version "23.2")
431
432(defcustom gdb-thread-buffer-locations t
433 "Show file information or library names in threads buffer."
434 :type 'boolean
435 :group 'gdb-buffers
436 :version "23.2")
437
438(defcustom gdb-thread-buffer-addresses nil
439 "Show addresses for thread frames in threads buffer."
440 :type 'boolean
441 :group 'gdb-buffers
442 :version "23.2")
443
444(defcustom gdb-show-threads-by-default nil
6ff2c8f1 445 "Show threads list buffer instead of breakpoints list by default."
691cf4a0
NR
446 :type 'boolean
447 :group 'gdb-buffers
448 :version "23.2")
449
450(defvar gdb-debug-log nil
451 "List of commands sent to and replies received from GDB.
452Most recent commands are listed first. This list stores only the last
453`gdb-debug-log-max' values. This variable is used to debug GDB-MI.")
454
455;;;###autoload
e7e85dc0
SM
456(define-minor-mode gdb-enable-debug
457 "Toggle logging of transaction between Emacs and Gdb.
458The log is stored in `gdb-debug-log' as an alist with elements
459whose cons is send, send-item or recv and whose cdr is the string
460being transferred. This list may grow up to a size of
461`gdb-debug-log-max' after which the oldest element (at the end of
462the list) is deleted every time a new one is added (at the front)."
463 :global t
691cf4a0
NR
464 :group 'gdb
465 :version "22.1")
466
467(defcustom gdb-cpp-define-alist-program "gcc -E -dM -"
468 "Shell command for generating a list of defined macros in a source file.
469This list is used to display the #define directive associated
470with an identifier as a tooltip. It works in a debug session with
471GDB, when `gud-tooltip-mode' is t.
472
473Set `gdb-cpp-define-alist-flags' for any include paths or
474predefined macros."
475 :type 'string
476 :group 'gdb
477 :version "22.1")
478
479(defcustom gdb-cpp-define-alist-flags ""
480 "Preprocessor flags for `gdb-cpp-define-alist-program'."
481 :type 'string
482 :group 'gdb
483 :version "22.1")
484
3db614b0
SM
485(defcustom gdb-create-source-file-list t
486 "Non-nil means create a list of files from which the executable was built.
6ff2c8f1
JPG
487Set this to nil if the GUD buffer displays \"initializing...\" in the mode
488line for a long time when starting, possibly because your executable was
489built from a large number of files. This allows quicker initialization
490but means that these files are not automatically enabled for debugging,
491e.g., you won't be able to click in the fringe to set a breakpoint until
492execution has already stopped there."
3db614b0
SM
493 :type 'boolean
494 :group 'gdb
495 :version "23.1")
691cf4a0
NR
496
497(defcustom gdb-show-main nil
498 "Non-nil means display source file containing the main routine at startup.
499Also display the main routine in the disassembly buffer if present."
500 :type 'boolean
501 :group 'gdb
502 :version "22.1")
503
6ff2c8f1
JPG
504(defvar gdbmi-debug-mode nil
505 "When non-nil, print the messages sent/received from GDB/MI in *Messages*.")
506
691cf4a0
NR
507(defun gdb-force-mode-line-update (status)
508 (let ((buffer gud-comint-buffer))
509 (if (and buffer (buffer-name buffer))
510 (with-current-buffer buffer
511 (setq mode-line-process
512 (format ":%s [%s]"
513 (process-status (get-buffer-process buffer)) status))
514 ;; Force mode line redisplay soon.
515 (force-mode-line-update)))))
516
691cf4a0
NR
517;; These two are used for menu and toolbar
518(defun gdb-control-all-threads ()
519 "Switch to non-stop/A mode."
520 (interactive)
521 (setq gdb-gud-control-all-threads t)
522 ;; Actually forcing the tool-bar to update.
523 (force-mode-line-update)
524 (message "Now in non-stop/A mode."))
525
526(defun gdb-control-current-thread ()
527 "Switch to non-stop/T mode."
528 (interactive)
529 (setq gdb-gud-control-all-threads nil)
530 ;; Actually forcing the tool-bar to update.
531 (force-mode-line-update)
532 (message "Now in non-stop/T mode."))
533
534(defun gdb-find-watch-expression ()
535 (let* ((var (nth (- (line-number-at-pos (point)) 2) gdb-var-list))
e02f48d7 536 (varnum (car var)) expr)
691cf4a0
NR
537 (string-match "\\(var[0-9]+\\)\\.\\(.*\\)" varnum)
538 (let ((var1 (assoc (match-string 1 varnum) gdb-var-list)) var2 varnumlet
539 (component-list (split-string (match-string 2 varnum) "\\." t)))
540 (setq expr (nth 1 var1))
541 (setq varnumlet (car var1))
542 (dolist (component component-list)
543 (setq var2 (assoc varnumlet gdb-var-list))
544 (setq expr (concat expr
545 (if (string-match ".*\\[[0-9]+\\]$" (nth 3 var2))
546 (concat "[" component "]")
547 (concat "." component))))
548 (setq varnumlet (concat varnumlet "." component)))
549 expr)))
550
551;; noall is used for commands which don't take --all, but only
552;; --thread.
553(defun gdb-gud-context-command (command &optional noall)
554 "When `gdb-non-stop' is t, add --thread option to COMMAND if
555`gdb-gud-control-all-threads' is nil and --all option otherwise.
556If NOALL is t, always add --thread option no matter what
557`gdb-gud-control-all-threads' value is.
558
559When `gdb-non-stop' is nil, return COMMAND unchanged."
560 (if gdb-non-stop
561 (if (and gdb-gud-control-all-threads
562 (not noall)
087ef505 563 gdb-supports-non-stop)
691cf4a0
NR
564 (concat command " --all ")
565 (gdb-current-context-command command))
566 command))
567
568(defmacro gdb-gud-context-call (cmd1 &optional cmd2 noall noarg)
569 "`gud-call' wrapper which adds --thread/--all options between
6ff2c8f1 570CMD1 and CMD2. NOALL is the same as in `gdb-gud-context-command'.
691cf4a0
NR
571
572NOARG must be t when this macro is used outside `gud-def'"
573 `(gud-call
574 (concat (gdb-gud-context-command ,cmd1 ,noall) " " ,cmd2)
575 ,(when (not noarg) 'arg)))
576
ee1f1da9
SM
577(defun gdb--check-interpreter (proc string)
578 (unless (zerop (length string))
579 (let ((filter (process-get proc 'gud-normal-filter)))
580 (set-process-filter proc filter)
581 (unless (memq (aref string 0) '(?^ ?~ ?@ ?& ?* ?=))
582 ;; Apparently we're not running with -i=mi.
583 (let ((msg "Error: you did not specify -i=mi on GDB's command line!"))
584 (message msg)
585 (setq string (concat (propertize msg 'font-lock-face 'error)
586 "\n" string)))
587 ;; Use the old gud-gbd filter, not because it works, but because it
588 ;; will properly display GDB's answers rather than hanging waiting for
589 ;; answers that aren't coming.
590 (set (make-local-variable 'gud-marker-filter) #'gud-gdb-marker-filter))
591 (funcall filter proc string))))
592
9ee9f470
EZ
593(defvar gdb-control-level 0)
594
691cf4a0
NR
595;;;###autoload
596(defun gdb (command-line)
597 "Run gdb on program FILE in buffer *gud-FILE*.
598The directory containing FILE becomes the initial working directory
599and source-file directory for your debugger.
600
a1c2d21e
CY
601COMMAND-LINE is the shell command for starting the gdb session.
602It should be a string consisting of the name of the gdb
6ff2c8f1 603executable followed by command line options. The command line
a1c2d21e 604options should include \"-i=mi\" to use gdb's MI text interface.
6d823bb2 605Note that the old \"--annotate\" option is no longer supported.
a1c2d21e 606
9fc9a531 607If option `gdb-many-windows' is nil (the default value) then gdb just
691cf4a0
NR
608pops up the GUD buffer unless `gdb-show-main' is t. In this case
609it starts with two windows: one displaying the GUD buffer and the
610other with the source file with the main routine of the inferior.
611
9fc9a531 612If option `gdb-many-windows' is t, regardless of the value of
691cf4a0
NR
613`gdb-show-main', the layout below will appear. Keybindings are
614shown in some of the buffers.
615
616Watch expressions appear in the speedbar/slowbar.
617
618The following commands help control operation :
619
620`gdb-many-windows' - Toggle the number of windows gdb uses.
621`gdb-restore-windows' - To restore the window layout.
622
623See Info node `(emacs)GDB Graphical Interface' for a more
624detailed description of this mode.
625
626
627+----------------------------------------------------------------------+
628| GDB Toolbar |
629+-----------------------------------+----------------------------------+
630| GUD buffer (I/O of GDB) | Locals buffer |
631| | |
632| | |
633| | |
634+-----------------------------------+----------------------------------+
635| Source buffer | I/O buffer (of debugged program) |
636| | (comint-mode) |
637| | |
638| | |
639| | |
640| | |
641| | |
642| | |
643+-----------------------------------+----------------------------------+
644| Stack buffer | Breakpoints buffer |
645| RET gdb-select-frame | SPC gdb-toggle-breakpoint |
646| | RET gdb-goto-breakpoint |
647| | D gdb-delete-breakpoint |
648+-----------------------------------+----------------------------------+"
649 ;;
650 (interactive (list (gud-query-cmdline 'gdb)))
651
652 (when (and gud-comint-buffer
3db614b0
SM
653 (buffer-name gud-comint-buffer)
654 (get-buffer-process gud-comint-buffer)
655 (with-current-buffer gud-comint-buffer (eq gud-minor-mode 'gdba)))
656 (gdb-restore-windows)
657 (error
658 "Multiple debugging requires restarting in text command mode"))
691cf4a0
NR
659 ;;
660 (gud-common-init command-line nil 'gud-gdbmi-marker-filter)
ee1f1da9
SM
661
662 ;; Setup a temporary process filter to warn when GDB was not started
663 ;; with -i=mi.
664 (let ((proc (get-buffer-process gud-comint-buffer)))
665 (process-put proc 'gud-normal-filter (process-filter proc))
666 (set-process-filter proc #'gdb--check-interpreter))
667
691cf4a0 668 (set (make-local-variable 'gud-minor-mode) 'gdbmi)
9ee9f470 669 (set (make-local-variable 'gdb-control-level) 0)
691cf4a0 670 (setq comint-input-sender 'gdb-send)
ac8331a7 671 (when (ring-empty-p comint-input-ring) ; cf shell-mode
927c53e7 672 (let ((hfile (expand-file-name (or (getenv "GDBHISTFILE")
13522cb4
GM
673 (if (eq system-type 'ms-dos)
674 "_gdb_history"
675 ".gdb_history"))))
676 ;; gdb defaults to 256, but we'll default to comint-input-ring-size.
677 (hsize (getenv "HISTSIZE")))
678 (dolist (file (append '("~/.gdbinit")
679 (unless (string-equal (expand-file-name ".")
3db614b0 680 (expand-file-name "~"))
13522cb4
GM
681 '(".gdbinit"))))
682 (if (file-readable-p (setq file (expand-file-name file)))
683 (with-temp-buffer
684 (insert-file-contents file)
685 ;; TODO? check for "set history save\\( *on\\)?" and do
686 ;; not use history otherwise?
687 (while (re-search-forward
688 "^ *set history \\(filename\\|size\\) *\\(.*\\)" nil t)
689 (cond ((string-equal (match-string 1) "filename")
690 (setq hfile (expand-file-name
691 (match-string 2)
692 (file-name-directory file))))
693 ((string-equal (match-string 1) "size")
694 (setq hsize (match-string 2))))))))
1289e5d3 695 (and (stringp hsize)
791cd386 696 (integerp (setq hsize (string-to-number hsize)))
1289e5d3
GM
697 (> hsize 0)
698 (set (make-local-variable 'comint-input-ring-size) hsize))
13522cb4
GM
699 (if (stringp hfile)
700 (set (make-local-variable 'comint-input-ring-file-name) hfile))
701 (comint-read-input-ring t)))
691cf4a0
NR
702 (gud-def gud-tbreak "tbreak %f:%l" "\C-t"
703 "Set temporary breakpoint at current line.")
704 (gud-def gud-jump
705 (progn (gud-call "tbreak %f:%l") (gud-call "jump %f:%l"))
706 "\C-j" "Set execution address to current line.")
707
708 (gud-def gud-up "up %p" "<" "Up N stack frames (numeric arg).")
709 (gud-def gud-down "down %p" ">" "Down N stack frames (numeric arg).")
710 (gud-def gud-print "print %e" "\C-p" "Evaluate C expression at point.")
711 (gud-def gud-pstar "print* %e" nil
712 "Evaluate C dereferenced pointer expression at point.")
713
714 (gud-def gud-step (gdb-gud-context-call "-exec-step" "%p" t)
715 "\C-s"
716 "Step one source line with display.")
717 (gud-def gud-stepi (gdb-gud-context-call "-exec-step-instruction" "%p" t)
718 "\C-i"
719 "Step one instruction with display.")
720 (gud-def gud-next (gdb-gud-context-call "-exec-next" "%p" t)
721 "\C-n"
722 "Step one line (skip functions).")
723 (gud-def gud-nexti (gdb-gud-context-call "-exec-next-instruction" "%p" t)
724 nil
725 "Step one instruction (skip functions).")
726 (gud-def gud-cont (gdb-gud-context-call "-exec-continue")
727 "\C-r"
728 "Continue with display.")
729 (gud-def gud-finish (gdb-gud-context-call "-exec-finish" nil t)
730 "\C-f"
731 "Finish executing current function.")
732 (gud-def gud-run "-exec-run"
733 nil
734 "Run the program.")
735
736 (gud-def gud-break (if (not (string-match "Disassembly" mode-name))
737 (gud-call "break %f:%l" arg)
738 (save-excursion
739 (beginning-of-line)
740 (forward-char 2)
741 (gud-call "break *%a" arg)))
742 "\C-b" "Set breakpoint at current line or address.")
743
744 (gud-def gud-remove (if (not (string-match "Disassembly" mode-name))
745 (gud-call "clear %f:%l" arg)
746 (save-excursion
747 (beginning-of-line)
748 (forward-char 2)
749 (gud-call "clear *%a" arg)))
750 "\C-d" "Remove breakpoint at current line or address.")
751
752 ;; -exec-until doesn't support --all yet
753 (gud-def gud-until (if (not (string-match "Disassembly" mode-name))
754 (gud-call "-exec-until %f:%l" arg)
755 (save-excursion
756 (beginning-of-line)
757 (forward-char 2)
758 (gud-call "-exec-until *%a" arg)))
759 "\C-u" "Continue to current line or address.")
760 ;; TODO Why arg here?
761 (gud-def
762 gud-go (gud-call (if gdb-active-process
763 (gdb-gud-context-command "-exec-continue")
764 "-exec-run") arg)
765 nil "Start or continue execution.")
766
767 ;; For debugging Emacs only.
768 (gud-def gud-pp
769 (gud-call
770 (concat
1ff980ae
AS
771 "pp " (if (eq (buffer-local-value
772 'major-mode (window-buffer)) 'speedbar-mode)
773 (gdb-find-watch-expression) "%e")) arg)
691cf4a0
NR
774 nil "Print the Emacs s-expression.")
775
776 (define-key gud-minor-mode-map [left-margin mouse-1]
777 'gdb-mouse-set-clear-breakpoint)
778 (define-key gud-minor-mode-map [left-fringe mouse-1]
779 'gdb-mouse-set-clear-breakpoint)
3db614b0 780 (define-key gud-minor-mode-map [left-margin C-mouse-1]
691cf4a0
NR
781 'gdb-mouse-toggle-breakpoint-margin)
782 (define-key gud-minor-mode-map [left-fringe C-mouse-1]
783 'gdb-mouse-toggle-breakpoint-fringe)
784
785 (define-key gud-minor-mode-map [left-margin drag-mouse-1]
786 'gdb-mouse-until)
787 (define-key gud-minor-mode-map [left-fringe drag-mouse-1]
788 'gdb-mouse-until)
789 (define-key gud-minor-mode-map [left-margin mouse-3]
790 'gdb-mouse-until)
791 (define-key gud-minor-mode-map [left-fringe mouse-3]
792 'gdb-mouse-until)
793
794 (define-key gud-minor-mode-map [left-margin C-drag-mouse-1]
795 'gdb-mouse-jump)
796 (define-key gud-minor-mode-map [left-fringe C-drag-mouse-1]
797 'gdb-mouse-jump)
798 (define-key gud-minor-mode-map [left-fringe C-mouse-3]
799 'gdb-mouse-jump)
800 (define-key gud-minor-mode-map [left-margin C-mouse-3]
801 'gdb-mouse-jump)
802
2170cb53
CY
803 (set (make-local-variable 'gud-gdb-completion-function)
804 'gud-gdbmi-completions)
ee957461 805
f932a347
WD
806 (add-hook 'completion-at-point-functions #'gud-gdb-completion-at-point
807 nil 'local)
808 (local-set-key "\C-i" 'completion-at-point)
809
f30d612a 810 (local-set-key [remap comint-delchar-or-maybe-eof] 'gdb-delchar-or-quit)
b668fa6e 811
691cf4a0
NR
812 (setq gdb-first-prompt t)
813 (setq gud-running nil)
814
815 (gdb-update)
816
817 (run-hooks 'gdb-mode-hook))
818
819(defun gdb-init-1 ()
e7e85dc0 820 ;; (Re-)initialize.
691cf4a0
NR
821 (setq gdb-selected-frame nil
822 gdb-frame-number nil
823 gdb-thread-number nil
824 gdb-var-list nil
825 gdb-pending-triggers nil
826 gdb-output-sink 'user
827 gdb-location-alist nil
828 gdb-source-file-list nil
829 gdb-last-command nil
830 gdb-token-number 0
831 gdb-handler-alist '()
832 gdb-handler-number nil
833 gdb-prompt-name nil
834 gdb-first-done-or-error t
835 gdb-buffer-fringe-width (car (window-fringes))
836 gdb-debug-log nil
837 gdb-source-window nil
838 gdb-inferior-status nil
839 gdb-continuation nil
840 gdb-buf-publisher '()
841 gdb-threads-list '()
842 gdb-breakpoints-list '()
843 gdb-register-names '()
844 gdb-non-stop gdb-non-stop-setting)
845 ;;
6ff2c8f1
JPG
846 (gdbmi-bnf-init)
847 ;;
691cf4a0
NR
848 (setq gdb-buffer-type 'gdbmi)
849 ;;
850 (gdb-force-mode-line-update
851 (propertize "initializing..." 'face font-lock-variable-name-face))
852
853 (gdb-get-buffer-create 'gdb-inferior-io)
854 (gdb-clear-inferior-io)
f30d612a
CY
855 (gdb-inferior-io--init-proc (get-process "gdb-inferior"))
856
afc6df87
EZ
857 (when (eq system-type 'windows-nt)
858 ;; Don't create a separate console window for the debuggee.
859 (gdb-input "-gdb-set new-console off" 'ignore)
860 ;; Force GDB to behave as if its input and output stream were
861 ;; connected to a TTY device (since on Windows we use pipes for
862 ;; communicating with GDB).
863 (gdb-input "-gdb-set interactive-mode on" 'ignore))
2170cb53 864 (gdb-input "-gdb-set height 0" 'ignore)
691cf4a0
NR
865
866 (when gdb-non-stop
2170cb53 867 (gdb-input "-gdb-set non-stop 1" 'gdb-non-stop-handler))
691cf4a0 868
2170cb53 869 (gdb-input "-enable-pretty-printing" 'ignore)
087ef505 870
e7e85dc0 871 ;; Find source file and compilation directory here.
691cf4a0 872 (if gdb-create-source-file-list
2170cb53
CY
873 ;; Needs GDB 6.2 onwards.
874 (gdb-input "-file-list-exec-source-files" 'gdb-get-source-file-list))
875 ;; Needs GDB 6.0 onwards.
876 (gdb-input "-file-list-exec-source-file" 'gdb-get-source-file)
877 (gdb-input "-gdb-show prompt" 'gdb-get-prompt))
691cf4a0
NR
878
879(defun gdb-non-stop-handler ()
880 (goto-char (point-min))
881 (if (re-search-forward "No symbol" nil t)
882 (progn
3db614b0
SM
883 (message
884 "This version of GDB doesn't support non-stop mode. Turning it off.")
691cf4a0 885 (setq gdb-non-stop nil)
087ef505
KB
886 (setq gdb-supports-non-stop nil))
887 (setq gdb-supports-non-stop t)
2170cb53
CY
888 (gdb-input "-gdb-set target-async 1" 'ignore)
889 (gdb-input "-list-target-features" 'gdb-check-target-async)))
087ef505
KB
890
891(defun gdb-check-target-async ()
892 (goto-char (point-min))
893 (unless (re-search-forward "async" nil t)
894 (message
895 "Target doesn't support non-stop mode. Turning it off.")
896 (setq gdb-non-stop nil)
2170cb53 897 (gdb-input "-gdb-set non-stop 0" 'ignore)))
691cf4a0 898
f30d612a
CY
899(defun gdb-delchar-or-quit (arg)
900 "Delete ARG characters or send a quit command to GDB.
901Send a quit only if point is at the end of the buffer, there is
902no input, and GDB is waiting for input."
903 (interactive "p")
904 (unless (and (eq (current-buffer) gud-comint-buffer)
905 (eq gud-minor-mode 'gdbmi))
906 (error "Not in a GDB-MI buffer"))
907 (let ((proc (get-buffer-process gud-comint-buffer)))
908 (if (and (eobp) proc (process-live-p proc)
909 (not gud-running)
910 (= (point) (marker-position (process-mark proc))))
911 ;; Sending an EOF does not work with GDB-MI; submit an
912 ;; explicit quit command.
913 (progn
914 (insert "quit")
915 (comint-send-input t t))
916 (delete-char arg))))
917
691cf4a0
NR
918(defvar gdb-define-alist nil "Alist of #define directives for GUD tooltips.")
919
920(defun gdb-create-define-alist ()
921 "Create an alist of #define directives for GUD tooltips."
922 (let* ((file (buffer-file-name))
923 (output
924 (with-output-to-string
925 (with-current-buffer standard-output
926 (and file
927 (file-exists-p file)
928 ;; call-process doesn't work with remote file names.
929 (not (file-remote-p default-directory))
930 (call-process shell-file-name file
931 (list t nil) nil "-c"
932 (concat gdb-cpp-define-alist-program " "
933 gdb-cpp-define-alist-flags))))))
3db614b0
SM
934 (define-list (split-string output "\n" t))
935 (name))
691cf4a0
NR
936 (setq gdb-define-alist nil)
937 (dolist (define define-list)
938 (setq name (nth 1 (split-string define "[( ]")))
939 (push (cons name define) gdb-define-alist))))
940
941(declare-function tooltip-show "tooltip" (text &optional use-echo-area))
691cf4a0
NR
942
943(defun gdb-tooltip-print (expr)
3db614b0
SM
944 (with-current-buffer (gdb-get-buffer 'gdb-partial-output-buffer)
945 (goto-char (point-min))
ba025fbd
EZ
946 (cond
947 ((re-search-forward ".*value=\\(\".*\"\\)" nil t)
948 (tooltip-show
949 (concat expr " = " (read (match-string 1)))
950 (or gud-tooltip-echo-area
951 (not (display-graphic-p)))))
952 ((re-search-forward "msg=\\(\".+\"\\)$" nil t)
953 (tooltip-show (read (match-string 1))
954 (or gud-tooltip-echo-area
955 (not (display-graphic-p))))))))
691cf4a0
NR
956
957;; If expr is a macro for a function don't print because of possible dangerous
958;; side-effects. Also printing a function within a tooltip generates an
959;; unexpected starting annotation (phase error).
960(defun gdb-tooltip-print-1 (expr)
961 (with-current-buffer (gdb-get-buffer 'gdb-partial-output-buffer)
962 (goto-char (point-min))
963 (if (search-forward "expands to: " nil t)
964 (unless (looking-at "\\S-+.*(.*).*")
ba025fbd 965 (gdb-input (concat "-data-evaluate-expression \"" expr "\"")
2170cb53 966 `(lambda () (gdb-tooltip-print ,expr)))))))
691cf4a0
NR
967
968(defun gdb-init-buffer ()
969 (set (make-local-variable 'gud-minor-mode) 'gdbmi)
970 (set (make-local-variable 'tool-bar-map) gud-tool-bar-map)
971 (when gud-tooltip-mode
972 (make-local-variable 'gdb-define-alist)
973 (gdb-create-define-alist)
974 (add-hook 'after-save-hook 'gdb-create-define-alist nil t)))
975
e7e85dc0
SM
976(defmacro gdb--if-arrow (arrow-position start-posn end-posn &rest body)
977 (declare (indent 3))
978 (let ((buffer (make-symbol "buffer")))
979 `(if ,arrow-position
980 (let ((,buffer (marker-buffer ,arrow-position)))
981 (if (equal ,buffer (window-buffer (posn-window ,end-posn)))
982 (with-current-buffer ,buffer
983 (when (or (equal ,start-posn ,end-posn)
984 (equal (posn-point ,start-posn)
985 (marker-position ,arrow-position)))
986 ,@body)))))))
691cf4a0
NR
987
988(defun gdb-mouse-until (event)
989 "Continue running until a source line past the current line.
990The destination source line can be selected either by clicking
991with mouse-3 on the fringe/margin or dragging the arrow
992with mouse-1 (default bindings)."
993 (interactive "e")
994 (let ((start (event-start event))
995 (end (event-end event)))
e7e85dc0
SM
996 (gdb--if-arrow gud-overlay-arrow-position start end
997 (let ((line (line-number-at-pos (posn-point end))))
998 (gud-call (concat "until " (number-to-string line)))))
999 (gdb--if-arrow gdb-disassembly-position start end
1000 (save-excursion
1001 (goto-char (point-min))
1002 (forward-line (1- (line-number-at-pos (posn-point end))))
1003 (forward-char 2)
1004 (gud-call (concat "until *%a"))))))
691cf4a0
NR
1005
1006(defun gdb-mouse-jump (event)
1007 "Set execution address/line.
1008The destination source line can be selected either by clicking with C-mouse-3
1009on the fringe/margin or dragging the arrow with C-mouse-1 (default bindings).
1010Unlike `gdb-mouse-until' the destination address can be before the current
1011line, and no execution takes place."
1012 (interactive "e")
1013 (let ((start (event-start event))
1014 (end (event-end event)))
e7e85dc0
SM
1015 (gdb--if-arrow gud-overlay-arrow-position start end
1016 (let ((line (line-number-at-pos (posn-point end))))
1017 (gud-call (concat "tbreak " (number-to-string line)))
1018 (gud-call (concat "jump " (number-to-string line)))))
1019 (gdb--if-arrow gdb-disassembly-position start end
1020 (save-excursion
1021 (goto-char (point-min))
1022 (forward-line (1- (line-number-at-pos (posn-point end))))
1023 (forward-char 2)
1024 (gud-call (concat "tbreak *%a"))
1025 (gud-call (concat "jump *%a"))))))
691cf4a0
NR
1026
1027(defcustom gdb-show-changed-values t
1028 "If non-nil change the face of out of scope variables and changed values.
1029Out of scope variables are suppressed with `shadow' face.
1030Changed values are highlighted with the face `font-lock-warning-face'."
1031 :type 'boolean
1032 :group 'gdb
1033 :version "22.1")
1034
1035(defcustom gdb-max-children 40
1036 "Maximum number of children before expansion requires confirmation."
1037 :type 'integer
1038 :group 'gdb
1039 :version "22.1")
1040
1041(defcustom gdb-delete-out-of-scope t
1042 "If non-nil delete watch expressions automatically when they go out of scope."
1043 :type 'boolean
1044 :group 'gdb
1045 :version "22.2")
1046
e7e85dc0
SM
1047(define-minor-mode gdb-speedbar-auto-raise
1048 "Minor mode to automatically raise the speedbar for watch expressions.
1049With prefix argument ARG, automatically raise speedbar if ARG is
1050positive, otherwise don't automatically raise it."
1051 :global t
691cf4a0
NR
1052 :group 'gdb
1053 :version "22.1")
1054
1055(defcustom gdb-use-colon-colon-notation nil
1056 "If non-nil use FUN::VAR format to display variables in the speedbar."
1057 :type 'boolean
1058 :group 'gdb
1059 :version "22.1")
1060
691cf4a0 1061(define-key gud-minor-mode-map "\C-c\C-w" 'gud-watch)
a77b0ac9 1062(define-key global-map (vconcat gud-key-prefix "\C-w") 'gud-watch)
691cf4a0
NR
1063
1064(declare-function tooltip-identifier-from-point "tooltip" (point))
1065
1066(defun gud-watch (&optional arg event)
1067 "Watch expression at point.
1068With arg, enter name of variable to be watched in the minibuffer."
1069 (interactive (list current-prefix-arg last-input-event))
1070 (let ((minor-mode (buffer-local-value 'gud-minor-mode gud-comint-buffer)))
1071 (if (eq minor-mode 'gdbmi)
1072 (progn
1073 (if event (posn-set-point (event-end event)))
1074 (require 'tooltip)
1075 (save-selected-window
1076 (let ((expr
1077 (if arg
1078 (completing-read "Name of variable: "
1079 'gud-gdb-complete-command)
1080 (if (and transient-mark-mode mark-active)
1081 (buffer-substring (region-beginning) (region-end))
175069ef 1082 (concat (if (derived-mode-p 'gdb-registers-mode) "$")
691cf4a0
NR
1083 (tooltip-identifier-from-point (point)))))))
1084 (set-text-properties 0 (length expr) nil expr)
2170cb53
CY
1085 (gdb-input (concat "-var-create - * " expr "")
1086 `(lambda () (gdb-var-create-handler ,expr))))))
691cf4a0
NR
1087 (message "gud-watch is a no-op in this mode."))))
1088
1089(defun gdb-var-create-handler (expr)
1090 (let* ((result (gdb-json-partial-output)))
1091 (if (not (bindat-get-field result 'msg))
1092 (let ((var
1093 (list (bindat-get-field result 'name)
1094 (if (and (string-equal gdb-current-language "c")
1095 gdb-use-colon-colon-notation gdb-selected-frame)
1096 (setq expr (concat gdb-selected-frame "::" expr))
1097 expr)
1098 (bindat-get-field result 'numchild)
1099 (bindat-get-field result 'type)
1100 (bindat-get-field result 'value)
1101 nil
1102 (bindat-get-field result 'has_more)
3db614b0 1103 gdb-frame-address)))
691cf4a0
NR
1104 (push var gdb-var-list)
1105 (speedbar 1)
1106 (unless (string-equal
1107 speedbar-initial-expansion-list-name "GUD")
1108 (speedbar-change-initial-expansion-list "GUD")))
1109 (message-box "No symbol \"%s\" in current context." expr))))
1110
1111(defun gdb-speedbar-update ()
1112 (when (and (boundp 'speedbar-frame) (frame-live-p speedbar-frame)
1113 (not (gdb-pending-p 'gdb-speedbar-timer)))
1114 ;; Dummy command to update speedbar even when idle.
2170cb53 1115 (gdb-input "-environment-pwd" 'gdb-speedbar-timer-fn)
691cf4a0
NR
1116 ;; Keep gdb-pending-triggers non-nil till end.
1117 (gdb-add-pending 'gdb-speedbar-timer)))
1118
1119(defun gdb-speedbar-timer-fn ()
1120 (if gdb-speedbar-auto-raise
1121 (raise-frame speedbar-frame))
1122 (gdb-delete-pending 'gdb-speedbar-timer)
1123 (speedbar-timer-fn))
1124
1125(defun gdb-var-evaluate-expression-handler (varnum changed)
1126 (goto-char (point-min))
1127 (re-search-forward ".*value=\\(\".*\"\\)" nil t)
1128 (let ((var (assoc varnum gdb-var-list)))
1129 (when var
1130 (if changed (setcar (nthcdr 5 var) 'changed))
1131 (setcar (nthcdr 4 var) (read (match-string 1)))))
1132 (gdb-speedbar-update))
1133
3db614b0 1134 ; Uses "-var-list-children --all-values". Needs GDB 6.1 onwards.
691cf4a0 1135(defun gdb-var-list-children (varnum)
2170cb53
CY
1136 (gdb-input (concat "-var-update " varnum) 'ignore)
1137 (gdb-input (concat "-var-list-children --all-values " varnum)
1138 `(lambda () (gdb-var-list-children-handler ,varnum))))
691cf4a0
NR
1139
1140(defun gdb-var-list-children-handler (varnum)
1141 (let* ((var-list nil)
1142 (output (bindat-get-field (gdb-json-partial-output "child")))
1143 (children (bindat-get-field output 'children)))
3db614b0 1144 (catch 'child-already-watched
691cf4a0
NR
1145 (dolist (var gdb-var-list)
1146 (if (string-equal varnum (car var))
1147 (progn
1148 ;; With dynamic varobjs numchild may have increased.
1149 (setcar (nthcdr 2 var) (bindat-get-field output 'numchild))
1150 (push var var-list)
1151 (dolist (child children)
1152 (let ((varchild (list (bindat-get-field child 'name)
1153 (bindat-get-field child 'exp)
1154 (bindat-get-field child 'numchild)
1155 (bindat-get-field child 'type)
1156 (bindat-get-field child 'value)
1157 nil
1158 (bindat-get-field child 'has_more))))
1159 (if (assoc (car varchild) gdb-var-list)
1160 (throw 'child-already-watched nil))
1161 (push varchild var-list))))
1162 (push var var-list)))
1163 (setq gdb-var-list (nreverse var-list))))
1164 (gdb-speedbar-update))
1165
1166(defun gdb-var-set-format (format)
1167 "Set the output format for a variable displayed in the speedbar."
1168 (let* ((var (nth (- (count-lines (point-min) (point)) 2) gdb-var-list))
1169 (varnum (car var)))
2170cb53 1170 (gdb-input (concat "-var-set-format " varnum " " format) 'ignore)
691cf4a0
NR
1171 (gdb-var-update)))
1172
1173(defun gdb-var-delete-1 (var varnum)
2170cb53 1174 (gdb-input (concat "-var-delete " varnum) 'ignore)
691cf4a0
NR
1175 (setq gdb-var-list (delq var gdb-var-list))
1176 (dolist (varchild gdb-var-list)
1177 (if (string-match (concat (car var) "\\.") (car varchild))
1178 (setq gdb-var-list (delq varchild gdb-var-list)))))
1179
1180(defun gdb-var-delete ()
1181 "Delete watch expression at point from the speedbar."
1182 (interactive)
1183 (let ((text (speedbar-line-text)))
1184 (string-match "\\(\\S-+\\)" text)
3db614b0
SM
1185 (let* ((var (nth (- (count-lines (point-min) (point)) 2) gdb-var-list))
1186 (varnum (car var)))
1187 (if (string-match "\\." (car var))
1188 (message-box "Can only delete a root expression")
1189 (gdb-var-delete-1 var varnum)))))
691cf4a0
NR
1190
1191(defun gdb-var-delete-children (varnum)
1192 "Delete children of variable object at point from the speedbar."
2170cb53 1193 (gdb-input (concat "-var-delete -c " varnum) 'ignore))
691cf4a0 1194
e02f48d7 1195(defun gdb-edit-value (_text _token _indent)
691cf4a0
NR
1196 "Assign a value to a variable displayed in the speedbar."
1197 (let* ((var (nth (- (count-lines (point-min) (point)) 2) gdb-var-list))
e7e85dc0
SM
1198 (varnum (car var))
1199 (value (read-string "New value: ")))
2170cb53
CY
1200 (gdb-input (concat "-var-assign " varnum " " value)
1201 `(lambda () (gdb-edit-value-handler ,value)))))
691cf4a0
NR
1202
1203(defconst gdb-error-regexp "\\^error,msg=\\(\".+\"\\)")
1204
1205(defun gdb-edit-value-handler (value)
1206 (goto-char (point-min))
1207 (if (re-search-forward gdb-error-regexp nil t)
1208 (message-box "Invalid number or expression (%s)" value)))
1209
3db614b0 1210 ; Uses "-var-update --all-values". Needs GDB 6.4 onwards.
691cf4a0
NR
1211(defun gdb-var-update ()
1212 (if (not (gdb-pending-p 'gdb-var-update))
2170cb53 1213 (gdb-input "-var-update --all-values *" 'gdb-var-update-handler))
691cf4a0
NR
1214 (gdb-add-pending 'gdb-var-update))
1215
1216(defun gdb-var-update-handler ()
1217 (let ((changelist (bindat-get-field (gdb-json-partial-output) 'changelist)))
1218 (dolist (var gdb-var-list)
1219 (setcar (nthcdr 5 var) nil))
1220 (let ((temp-var-list gdb-var-list))
1221 (dolist (change changelist)
1222 (let* ((varnum (bindat-get-field change 'name))
1223 (var (assoc varnum gdb-var-list))
1224 (new-num (bindat-get-field change 'new_num_children)))
1225 (when var
1226 (let ((scope (bindat-get-field change 'in_scope))
1227 (has-more (bindat-get-field change 'has_more)))
1228 (cond ((string-equal scope "false")
1229 (if gdb-delete-out-of-scope
1230 (gdb-var-delete-1 var varnum)
1231 (setcar (nthcdr 5 var) 'out-of-scope)))
1232 ((string-equal scope "true")
1233 (setcar (nthcdr 6 var) has-more)
1234 (when (and (or (not has-more)
1235 (string-equal has-more "0"))
1236 (not new-num)
1237 (string-equal (nth 2 var) "0"))
1238 (setcar (nthcdr 4 var)
1239 (bindat-get-field change 'value))
1240 (setcar (nthcdr 5 var) 'changed)))
1241 ((string-equal scope "invalid")
1242 (gdb-var-delete-1 var varnum)))))
1243 (let ((var-list nil) var1
1244 (children (bindat-get-field change 'new_children)))
3db614b0
SM
1245 (when new-num
1246 (setq var1 (pop temp-var-list))
1247 (while var1
1248 (if (string-equal varnum (car var1))
1249 (let ((new (string-to-number new-num))
1250 (previous (string-to-number (nth 2 var1))))
1251 (setcar (nthcdr 2 var1) new-num)
1252 (push var1 var-list)
1253 (cond
1254 ((> new previous)
1255 ;; Add new children to list.
6ff2c8f1 1256 (dotimes (_ previous)
3db614b0
SM
1257 (push (pop temp-var-list) var-list))
1258 (dolist (child children)
1259 (let ((varchild
1260 (list (bindat-get-field child 'name)
1261 (bindat-get-field child 'exp)
1262 (bindat-get-field child 'numchild)
1263 (bindat-get-field child 'type)
1264 (bindat-get-field child 'value)
1265 'changed
1266 (bindat-get-field child 'has_more))))
1267 (push varchild var-list))))
1268 ;; Remove deleted children from list.
1269 ((< new previous)
6ff2c8f1 1270 (dotimes (_ new)
3db614b0 1271 (push (pop temp-var-list) var-list))
6ff2c8f1 1272 (dotimes (_ (- previous new))
3db614b0
SM
1273 (pop temp-var-list)))))
1274 (push var1 var-list))
1275 (setq var1 (pop temp-var-list)))
1276 (setq gdb-var-list (nreverse var-list))))))))
691cf4a0
NR
1277 (setq gdb-pending-triggers
1278 (delq 'gdb-var-update gdb-pending-triggers))
1279 (gdb-speedbar-update))
1280
1281(defun gdb-speedbar-expand-node (text token indent)
1282 "Expand the node the user clicked on.
1283TEXT is the text of the button we clicked on, a + or - item.
1284TOKEN is data related to this node.
1285INDENT is the current indentation depth."
1286 (cond ((string-match "+" text) ;expand this node
1287 (let* ((var (assoc token gdb-var-list))
1288 (expr (nth 1 var)) (children (nth 2 var)))
1289 (if (or (<= (string-to-number children) gdb-max-children)
1290 (y-or-n-p
1291 (format "%s has %s children. Continue? " expr children)))
1292 (gdb-var-list-children token))))
1293 ((string-match "-" text) ;contract this node
1294 (dolist (var gdb-var-list)
1295 (if (string-match (concat token "\\.") (car var))
1296 (setq gdb-var-list (delq var gdb-var-list))))
1297 (gdb-var-delete-children token)
1298 (speedbar-change-expand-button-char ?+)
1299 (speedbar-delete-subblock indent))
1300 (t (error "Ooops... not sure what to do")))
1301 (speedbar-center-buffer-smartly))
1302
1303(defun gdb-get-target-string ()
1304 (with-current-buffer gud-comint-buffer
1305 gud-target-name))
1306\f
1307
1308;;
1309;; gdb buffers.
1310;;
1311;; Each buffer has a TYPE -- a symbol that identifies the function
1312;; of that particular buffer.
1313;;
1314;; The usual gdb interaction buffer is given the type `gdbmi' and
1315;; is constructed specially.
1316;;
1317;; Others are constructed by gdb-get-buffer-create and
1318;; named according to the rules set forth in the gdb-buffer-rules
1319
1320(defvar gdb-buffer-rules '())
1321
1322(defun gdb-rules-name-maker (rules-entry)
1323 (cadr rules-entry))
1324(defun gdb-rules-buffer-mode (rules-entry)
1325 (nth 2 rules-entry))
1326(defun gdb-rules-update-trigger (rules-entry)
1327 (nth 3 rules-entry))
1328
1329(defun gdb-update-buffer-name ()
1330 "Rename current buffer according to name-maker associated with
1331it in `gdb-buffer-rules'."
1332 (let ((f (gdb-rules-name-maker (assoc gdb-buffer-type
1333 gdb-buffer-rules))))
1334 (when f (rename-buffer (funcall f)))))
1335
1336(defun gdb-current-buffer-rules ()
1337 "Get `gdb-buffer-rules' entry for current buffer type."
1338 (assoc gdb-buffer-type gdb-buffer-rules))
1339
1340(defun gdb-current-buffer-thread ()
1341 "Get thread object of current buffer from `gdb-threads-list'.
1342
1343When current buffer is not bound to any thread, return main
1344thread."
1345 (cdr (assoc gdb-thread-number gdb-threads-list)))
1346
1347(defun gdb-current-buffer-frame ()
1348 "Get current stack frame object for thread of current buffer."
1349 (bindat-get-field (gdb-current-buffer-thread) 'frame))
1350
1351(defun gdb-buffer-type (buffer)
1352 "Get value of `gdb-buffer-type' for BUFFER."
1353 (with-current-buffer buffer
1354 gdb-buffer-type))
1355
1356(defun gdb-buffer-shows-main-thread-p ()
1357 "Return t if current GDB buffer shows main selected thread and
1358is not bound to it."
1359 (current-buffer)
1360 (not (local-variable-p 'gdb-thread-number)))
1361
1362(defun gdb-get-buffer (buffer-type &optional thread)
1363 "Get a specific GDB buffer.
1364
1365In that buffer, `gdb-buffer-type' must be equal to BUFFER-TYPE
1366and `gdb-thread-number' (if provided) must be equal to THREAD."
1367 (catch 'found
1368 (dolist (buffer (buffer-list) nil)
1369 (with-current-buffer buffer
1370 (when (and (eq gdb-buffer-type buffer-type)
1371 (or (not thread)
1372 (equal gdb-thread-number thread)))
1373 (throw 'found buffer))))))
1374
1375(defun gdb-get-buffer-create (buffer-type &optional thread)
1376 "Create a new GDB buffer of the type specified by BUFFER-TYPE.
1377The buffer-type should be one of the cars in `gdb-buffer-rules'.
1378
1379If THREAD is non-nil, it is assigned to `gdb-thread-number'
1380buffer-local variable of the new buffer.
1381
1382Buffer mode and name are selected according to buffer type.
1383
1384If buffer has trigger associated with it in `gdb-buffer-rules',
1385this trigger is subscribed to `gdb-buf-publisher' and called with
1386'update argument."
1387 (or (gdb-get-buffer buffer-type thread)
1388 (let ((rules (assoc buffer-type gdb-buffer-rules))
1389 (new (generate-new-buffer "limbo")))
1390 (with-current-buffer new
1391 (let ((mode (gdb-rules-buffer-mode rules))
1392 (trigger (gdb-rules-update-trigger rules)))
1393 (when mode (funcall mode))
1394 (setq gdb-buffer-type buffer-type)
1395 (when thread
1396 (set (make-local-variable 'gdb-thread-number) thread))
1397 (set (make-local-variable 'gud-minor-mode)
1398 (buffer-local-value 'gud-minor-mode gud-comint-buffer))
1399 (set (make-local-variable 'tool-bar-map) gud-tool-bar-map)
1400 (rename-buffer (funcall (gdb-rules-name-maker rules)))
1401 (when trigger
1402 (gdb-add-subscriber gdb-buf-publisher
1403 (cons (current-buffer)
3db614b0
SM
1404 (gdb-bind-function-to-buffer
1405 trigger (current-buffer))))
691cf4a0
NR
1406 (funcall trigger 'start))
1407 (current-buffer))))))
1408
1409(defun gdb-bind-function-to-buffer (expr buffer)
1410 "Return a function which will evaluate EXPR in BUFFER."
1411 `(lambda (&rest args)
1412 (with-current-buffer ,buffer
1413 (apply ',expr args))))
1414
691cf4a0
NR
1415;; Used to display windows with thread-bound buffers
1416(defmacro def-gdb-preempt-display-buffer (name buffer &optional doc
1417 split-horizontal)
1418 `(defun ,name (&optional thread)
1419 ,(when doc doc)
1420 (message thread)
1421 (gdb-preempt-existing-or-display-buffer
1422 (gdb-get-buffer-create ,buffer thread)
1423 ,split-horizontal)))
1424
1425;; This assoc maps buffer type symbols to rules. Each rule is a list of
1426;; at least one and possible more functions. The functions have these
1427;; roles in defining a buffer type:
1428;;
1429;; NAME - Return a name for this buffer type.
1430;;
1431;; The remaining function(s) are optional:
1432;;
1433;; MODE - called in a new buffer with no arguments, should establish
1434;; the proper mode for the buffer.
1435;;
1436
1437(defun gdb-set-buffer-rules (buffer-type &rest rules)
1438 (let ((binding (assoc buffer-type gdb-buffer-rules)))
1439 (if binding
1440 (setcdr binding rules)
1441 (push (cons buffer-type rules)
1442 gdb-buffer-rules))))
1443
1444(defun gdb-parent-mode ()
1445 "Generic mode to derive all other GDB buffer modes from."
1446 (kill-all-local-variables)
1447 (setq buffer-read-only t)
1448 (buffer-disable-undo)
1449 ;; Delete buffer from gdb-buf-publisher when it's killed
1450 ;; (if it has an associated update trigger)
1451 (add-hook
1452 'kill-buffer-hook
1453 (function
1454 (lambda ()
1455 (let ((trigger (gdb-rules-update-trigger
1456 (gdb-current-buffer-rules))))
1457 (when trigger
1458 (gdb-delete-subscriber
1459 gdb-buf-publisher
1460 ;; This should match gdb-add-subscriber done in
1461 ;; gdb-get-buffer-create
1462 (cons (current-buffer)
1463 (gdb-bind-function-to-buffer trigger (current-buffer))))))))
1464 nil t))
1465
1466;; Partial-output buffer : This accumulates output from a command executed on
1467;; behalf of emacs (rather than the user).
1468;;
1469(gdb-set-buffer-rules 'gdb-partial-output-buffer
1470 'gdb-partial-output-name)
1471
1472(defun gdb-partial-output-name ()
1473 (concat " *partial-output-"
1474 (gdb-get-target-string)
1475 "*"))
1476
1477\f
1478(gdb-set-buffer-rules 'gdb-inferior-io
1479 'gdb-inferior-io-name
1480 'gdb-inferior-io-mode)
1481
1482(defun gdb-inferior-io-name ()
1483 (concat "*input/output of "
1484 (gdb-get-target-string)
1485 "*"))
1486
1487(defun gdb-display-io-buffer ()
1488 "Display IO of debugged program in a separate window."
1489 (interactive)
d97af5a0 1490 (gdb-display-buffer (gdb-get-buffer-create 'gdb-inferior-io)))
691cf4a0 1491
f30d612a
CY
1492(defun gdb-inferior-io--init-proc (proc)
1493 ;; Set up inferior I/O. Needs GDB 6.4 onwards.
1494 (set-process-filter proc 'gdb-inferior-filter)
1495 (set-process-sentinel proc 'gdb-inferior-io-sentinel)
ba025fbd
EZ
1496 ;; The process can run on a remote host.
1497 (let ((tty (or (process-get proc 'remote-tty)
1498 (process-tty-name proc))))
1499 (unless (or (null tty)
1500 (string= tty ""))
1501 (gdb-input
1502 (concat "-inferior-tty-set " tty) 'ignore))))
f30d612a 1503
6ff2c8f1 1504(defun gdb-inferior-io-sentinel (proc _str)
f30d612a
CY
1505 (when (eq (process-status proc) 'failed)
1506 ;; When the debugged process exits, Emacs gets an EIO error on
8912063b
CY
1507 ;; read from the pty, and stops listening to it. If the gdb
1508 ;; process is still running, remove the pty, make a new one, and
1509 ;; pass it to gdb.
1510 (let ((gdb-proc (get-buffer-process gud-comint-buffer))
1511 (io-buffer (process-buffer proc)))
1512 (when (and gdb-proc (process-live-p gdb-proc)
1513 (buffer-live-p io-buffer))
1514 ;; `comint-exec' deletes the original process as a side effect.
1515 (comint-exec io-buffer "gdb-inferior" nil nil nil)
1516 (gdb-inferior-io--init-proc (get-buffer-process io-buffer))))))
b668fa6e 1517
8c27235e
CY
1518(defcustom gdb-display-buffer-other-frame-action
1519 '((display-buffer-reuse-window display-buffer-pop-up-frame)
1520 (reusable-frames . visible)
d97af5a0
CY
1521 (inhibit-same-window . t)
1522 (pop-up-frame-parameters (height . 14)
1523 (width . 80)
1524 (unsplittable . t)
1525 (tool-bar-lines . nil)
1526 (menu-bar-lines . nil)
1527 (minibuffer . nil)))
8c27235e
CY
1528 "`display-buffer' action for displaying GDB utility frames."
1529 :group 'gdb
1530 :type display-buffer--action-custom-type
1531 :risky t
1532 :version "24.3")
691cf4a0
NR
1533
1534(defun gdb-frame-io-buffer ()
d97af5a0 1535 "Display IO of debugged program in another frame."
691cf4a0 1536 (interactive)
d97af5a0
CY
1537 (display-buffer (gdb-get-buffer-create 'gdb-inferior-io)
1538 gdb-display-buffer-other-frame-action))
691cf4a0
NR
1539
1540(defvar gdb-inferior-io-mode-map
1541 (let ((map (make-sparse-keymap)))
1542 (define-key map "\C-c\C-c" 'gdb-io-interrupt)
1543 (define-key map "\C-c\C-z" 'gdb-io-stop)
1544 (define-key map "\C-c\C-\\" 'gdb-io-quit)
1545 (define-key map "\C-c\C-d" 'gdb-io-eof)
1546 (define-key map "\C-d" 'gdb-io-eof)
1547 map))
1548
1549;; We want to use comint because it has various nifty and familiar features.
1550(define-derived-mode gdb-inferior-io-mode comint-mode "Inferior I/O"
175069ef 1551 "Major mode for gdb inferior-io."
691cf4a0 1552 :syntax-table nil :abbrev-table nil
175069ef 1553 (make-comint-in-buffer "gdb-inferior" (current-buffer) nil))
691cf4a0
NR
1554
1555(defun gdb-inferior-filter (proc string)
1556 (unless (string-equal string "")
d97af5a0 1557 (gdb-display-buffer (gdb-get-buffer-create 'gdb-inferior-io)))
691cf4a0
NR
1558 (with-current-buffer (gdb-get-buffer-create 'gdb-inferior-io)
1559 (comint-output-filter proc string)))
1560
1561(defun gdb-io-interrupt ()
1562 "Interrupt the program being debugged."
1563 (interactive)
1564 (interrupt-process
1565 (get-buffer-process gud-comint-buffer) comint-ptyp))
1566
1567(defun gdb-io-quit ()
1568 "Send quit signal to the program being debugged."
1569 (interactive)
1570 (quit-process
1571 (get-buffer-process gud-comint-buffer) comint-ptyp))
1572
1573(defun gdb-io-stop ()
1574 "Stop the program being debugged."
1575 (interactive)
1576 (stop-process
1577 (get-buffer-process gud-comint-buffer) comint-ptyp))
1578
1579(defun gdb-io-eof ()
1580 "Send end-of-file to the program being debugged."
1581 (interactive)
1582 (process-send-eof
1583 (get-buffer-process gud-comint-buffer)))
1584
1585(defun gdb-clear-inferior-io ()
1586 (with-current-buffer (gdb-get-buffer-create 'gdb-inferior-io)
1587 (erase-buffer)))
1588\f
1589
1590(defconst breakpoint-xpm-data
1591 "/* XPM */
1592static char *magick[] = {
1593/* columns rows colors chars-per-pixel */
1594\"10 10 2 1\",
1595\" c red\",
1596\"+ c None\",
1597/* pixels */
1598\"+++ +++\",
1599\"++ ++\",
1600\"+ +\",
1601\" \",
1602\" \",
1603\" \",
1604\" \",
1605\"+ +\",
1606\"++ ++\",
1607\"+++ +++\",
1608};"
1609 "XPM data used for breakpoint icon.")
1610
1611(defconst breakpoint-enabled-pbm-data
1612 "P1
161310 10\",
16140 0 0 0 1 1 1 1 0 0 0 0
16150 0 0 1 1 1 1 1 1 0 0 0
16160 0 1 1 1 1 1 1 1 1 0 0
16170 1 1 1 1 1 1 1 1 1 1 0
16180 1 1 1 1 1 1 1 1 1 1 0
16190 1 1 1 1 1 1 1 1 1 1 0
16200 1 1 1 1 1 1 1 1 1 1 0
16210 0 1 1 1 1 1 1 1 1 0 0
16220 0 0 1 1 1 1 1 1 0 0 0
16230 0 0 0 1 1 1 1 0 0 0 0"
1624 "PBM data used for enabled breakpoint icon.")
1625
1626(defconst breakpoint-disabled-pbm-data
1627 "P1
162810 10\",
16290 0 1 0 1 0 1 0 0 0
16300 1 0 1 0 1 0 1 0 0
16311 0 1 0 1 0 1 0 1 0
16320 1 0 1 0 1 0 1 0 1
16331 0 1 0 1 0 1 0 1 0
16340 1 0 1 0 1 0 1 0 1
16351 0 1 0 1 0 1 0 1 0
16360 1 0 1 0 1 0 1 0 1
16370 0 1 0 1 0 1 0 1 0
16380 0 0 1 0 1 0 1 0 0"
1639 "PBM data used for disabled breakpoint icon.")
1640
1641(defvar breakpoint-enabled-icon nil
1642 "Icon for enabled breakpoint in display margin.")
1643
1644(defvar breakpoint-disabled-icon nil
1645 "Icon for disabled breakpoint in display margin.")
1646
1647(declare-function define-fringe-bitmap "fringe.c"
1648 (bitmap bits &optional height width align))
1649
1650(and (display-images-p)
1651 ;; Bitmap for breakpoint in fringe
1652 (define-fringe-bitmap 'breakpoint
1653 "\x3c\x7e\xff\xff\xff\xff\x7e\x3c")
1654 ;; Bitmap for gud-overlay-arrow in fringe
1655 (define-fringe-bitmap 'hollow-right-triangle
1656 "\xe0\x90\x88\x84\x84\x88\x90\xe0"))
1657
1658(defface breakpoint-enabled
1659 '((t
1660 :foreground "red1"
1661 :weight bold))
1662 "Face for enabled breakpoint icon in fringe."
1663 :group 'gdb)
1664
1665(defface breakpoint-disabled
1666 '((((class color) (min-colors 88)) :foreground "grey70")
1667 ;; Ensure that on low-color displays that we end up something visible.
1668 (((class color) (min-colors 8) (background light))
1669 :foreground "black")
1670 (((class color) (min-colors 8) (background dark))
1671 :foreground "white")
1672 (((type tty) (class mono))
1673 :inverse-video t)
1674 (t :background "gray"))
1675 "Face for disabled breakpoint icon in fringe."
1676 :group 'gdb)
1677
1678\f
9ee9f470
EZ
1679(defvar gdb-control-commands-regexp
1680 (concat
1681 "^\\("
1682 "commands\\|if\\|while\\|define\\|document\\|python\\|"
1683 "while-stepping\\|stepping\\|ws\\|actions"
1684 "\\)\\([[:blank:]]+.*\\)?$")
1685 "Regexp matching GDB commands that enter a recursive reading loop.
1686As long as GDB is in the recursive reading loop, it does not expect
1687commands to be prefixed by \"-interpreter-exec console\".")
1688
691cf4a0
NR
1689(defun gdb-send (proc string)
1690 "A comint send filter for gdb."
1691 (with-current-buffer gud-comint-buffer
1692 (let ((inhibit-read-only t))
1693 (remove-text-properties (point-min) (point-max) '(face))))
1694 ;; mimic <RET> key to repeat previous command in GDB
1695 (if (not (string= "" string))
1696 (setq gdb-last-command string)
1697 (if gdb-last-command (setq string gdb-last-command)))
9ee9f470
EZ
1698 (if (or (string-match "^-" string)
1699 (> gdb-control-level 0))
1700 ;; Either MI command or we are feeding GDB's recursive reading loop.
691cf4a0
NR
1701 (progn
1702 (setq gdb-first-done-or-error t)
9ee9f470
EZ
1703 (process-send-string proc (concat string "\n"))
1704 (if (and (string-match "^end$" string)
1705 (> gdb-control-level 0))
1706 (setq gdb-control-level (1- gdb-control-level))))
691cf4a0
NR
1707 ;; CLI command
1708 (if (string-match "\\\\$" string)
1709 (setq gdb-continuation (concat gdb-continuation string "\n"))
1710 (setq gdb-first-done-or-error t)
4fd96557
JB
1711 (let ((to-send (concat "-interpreter-exec console "
1712 (gdb-mi-quote string)
1713 "\n")))
1714 (if gdb-enable-debug
1715 (push (cons 'mi-send to-send) gdb-debug-log))
1716 (process-send-string proc to-send))
9ee9f470
EZ
1717 (if (and (string-match "^end$" string)
1718 (> gdb-control-level 0))
1719 (setq gdb-control-level (1- gdb-control-level)))
1720 (setq gdb-continuation nil)))
1721 (if (string-match gdb-control-commands-regexp string)
1722 (setq gdb-control-level (1+ gdb-control-level))))
691cf4a0 1723
4fd96557
JB
1724(defun gdb-mi-quote (string)
1725 "Return STRING quoted properly as an MI argument.
1726The string is enclosed in double quotes.
1727All embedded quotes, newlines, and backslashes are preceded with a backslash."
1728 (setq string (replace-regexp-in-string "\\([\"\\]\\)" "\\\\\\&" string))
1729 (setq string (replace-regexp-in-string "\n" "\\n" string t t))
1730 (concat "\"" string "\""))
1731
2170cb53
CY
1732(defun gdb-input (command handler-function)
1733 "Send COMMAND to GDB via the MI interface.
1734Run the function HANDLER-FUNCTION, with no arguments, once the command is
1735complete."
1736 (if gdb-enable-debug (push (list 'send-item command handler-function)
1737 gdb-debug-log))
691cf4a0 1738 (setq gdb-token-number (1+ gdb-token-number))
2170cb53
CY
1739 (setq command (concat (number-to-string gdb-token-number) command))
1740 (push (cons gdb-token-number handler-function) gdb-handler-alist)
6ff2c8f1 1741 (if gdbmi-debug-mode (message "gdb-input: %s" command))
691cf4a0 1742 (process-send-string (get-buffer-process gud-comint-buffer)
2170cb53 1743 (concat command "\n")))
691cf4a0
NR
1744
1745;; NOFRAME is used for gud execution control commands
1746(defun gdb-current-context-command (command)
1747 "Add --thread to gdb COMMAND when needed."
1748 (if (and gdb-thread-number
087ef505 1749 gdb-supports-non-stop)
691cf4a0
NR
1750 (concat command " --thread " gdb-thread-number)
1751 command))
1752
1753(defun gdb-current-context-buffer-name (name)
1754 "Add thread information and asterisks to string NAME.
1755
1756If `gdb-thread-number' is nil, just wrap NAME in asterisks."
1757 (concat "*" name
1758 (if (local-variable-p 'gdb-thread-number)
1759 (format " (bound to thread %s)" gdb-thread-number)
1760 "")
1761 "*"))
1762
1763(defun gdb-current-context-mode-name (mode)
6ff2c8f1 1764 "Add thread information to MODE which is to be used as `mode-name'."
691cf4a0
NR
1765 (concat mode
1766 (if gdb-thread-number
1767 (format " [thread %s]" gdb-thread-number)
1768 "")))
1769\f
1770
1771(defcustom gud-gdb-command-name "gdb -i=mi"
1772 "Default command to execute an executable under the GDB debugger."
1773 :type 'string
1774 :group 'gdb)
1775
1776(defun gdb-resync()
1777 (setq gud-running nil)
1778 (setq gdb-output-sink 'user)
1779 (setq gdb-pending-triggers nil))
1780
b668fa6e
CY
1781(defun gdb-update (&optional no-proc)
1782 "Update buffers showing status of debug session.
1783If NO-PROC is non-nil, do not try to contact the GDB process."
691cf4a0
NR
1784 (when gdb-first-prompt
1785 (gdb-force-mode-line-update
1786 (propertize "initializing..." 'face font-lock-variable-name-face))
1787 (gdb-init-1)
1788 (setq gdb-first-prompt nil))
1789
b668fa6e
CY
1790 (unless no-proc
1791 (gdb-get-main-selected-frame))
1792
691cf4a0
NR
1793 ;; We may need to update gdb-threads-list so we can use
1794 (gdb-get-buffer-create 'gdb-threads-buffer)
1795 ;; gdb-break-list is maintained in breakpoints handler
1796 (gdb-get-buffer-create 'gdb-breakpoints-buffer)
1797
b668fa6e
CY
1798 (unless no-proc
1799 (gdb-emit-signal gdb-buf-publisher 'update))
691cf4a0
NR
1800
1801 (gdb-get-changed-registers)
691cf4a0
NR
1802 (when (and (boundp 'speedbar-frame) (frame-live-p speedbar-frame))
1803 (dolist (var gdb-var-list)
1804 (setcar (nthcdr 5 var) nil))
1805 (gdb-var-update)))
1806
1807;; gdb-setq-thread-number and gdb-update-gud-running are decoupled
1808;; because we may need to update current gud-running value without
1809;; changing current thread (see gdb-running)
1810(defun gdb-setq-thread-number (number)
6ff2c8f1
JPG
1811 "Set `gdb-thread-number' to NUMBER.
1812Only this function must be used to change `gdb-thread-number'
691cf4a0
NR
1813value to NUMBER, because `gud-running' and `gdb-frame-number'
1814need to be updated appropriately when current thread changes."
1815 ;; GDB 6.8 and earlier always output thread-id="0" when stopping.
1816 (unless (string-equal number "0") (setq gdb-thread-number number))
1817 (setq gdb-frame-number "0")
1818 (gdb-update-gud-running))
1819
1820(defun gdb-update-gud-running ()
1821 "Set `gud-running' according to the state of current thread.
1822
1823`gdb-frame-number' is set to 0 if current thread is now stopped.
1824
1825Note that when `gdb-gud-control-all-threads' is t, `gud-running'
1826cannot be reliably used to determine whether or not execution
6ff2c8f1 1827control buttons should be shown in menu or toolbar. Use
691cf4a0
NR
1828`gdb-running-threads-count' and `gdb-stopped-threads-count'
1829instead.
1830
1831For all-stop mode, thread information is unavailable while target
1832is running."
1833 (let ((old-value gud-running))
1834 (setq gud-running
1835 (string= (bindat-get-field (gdb-current-buffer-thread) 'state)
1836 "running"))
e7e85dc0 1837 ;; Set frame number to "0" when _current_ threads stops.
691cf4a0
NR
1838 (when (and (gdb-current-buffer-thread)
1839 (not (eq gud-running old-value)))
1840 (setq gdb-frame-number "0"))))
1841
1842(defun gdb-show-run-p ()
1843 "Return t if \"Run/continue\" should be shown on the toolbar."
1844 (or (not gdb-active-process)
1845 (and (or
1846 (not gdb-gud-control-all-threads)
1847 (not gdb-non-stop))
1848 (not gud-running))
1849 (and gdb-gud-control-all-threads
1850 (> gdb-stopped-threads-count 0))))
1851
1852(defun gdb-show-stop-p ()
1853 "Return t if \"Stop\" should be shown on the toolbar."
1854 (or (and (or
1855 (not gdb-gud-control-all-threads)
1856 (not gdb-non-stop))
1857 gud-running)
1858 (and gdb-gud-control-all-threads
1859 (> gdb-running-threads-count 0))))
1860
1861;; GUD displays the selected GDB frame. This might might not be the current
1862;; GDB frame (after up, down etc). If no GDB frame is visible but the last
1863;; visited breakpoint is, use that window.
1864(defun gdb-display-source-buffer (buffer)
1865 (let* ((last-window (if gud-last-last-frame
3db614b0
SM
1866 (get-buffer-window
1867 (gud-find-file (car gud-last-last-frame)))))
691cf4a0
NR
1868 (source-window (or last-window
1869 (if (and gdb-source-window
1870 (window-live-p gdb-source-window))
1871 gdb-source-window))))
1872 (when source-window
1873 (setq gdb-source-window source-window)
1874 (set-window-buffer source-window buffer))
1875 source-window))
1876
6ff2c8f1
JPG
1877
1878(defun gdbmi-start-with (str offset match)
1879 "Return non-nil if string STR starts with MATCH, else returns nil.
1880OFFSET is the position in STR at which the comparison takes place."
1881 (let ((match-length (length match))
1882 (str-length (- (length str) offset)))
1883 (when (>= str-length match-length)
1884 (string-equal match (substring str offset (+ offset match-length))))))
1885
1886(defun gdbmi-same-start (str offset match)
1887 "Return non-nil iff STR and MATCH are equal up to the end of either strings.
1888OFFSET is the position in STR at which the comparison takes place."
1889 (let* ((str-length (- (length str) offset))
1890 (match-length (length match))
1891 (compare-length (min str-length match-length)))
1892 (when (> compare-length 0)
1893 (string-equal (substring str offset (+ offset compare-length))
1894 (substring match 0 compare-length)))))
1895
1896(defun gdbmi-is-number (character)
1897 "Return non-nil iff CHARACTER is a numerical character between 0 and 9."
1898 (and (>= character ?0)
1899 (<= character ?9)))
1900
1901
1902(defvar-local gdbmi-bnf-state 'gdbmi-bnf-output
1903 "Current GDB/MI output parser state.
1904The parser is placed in a different state when an incomplete data steam is
1905received from GDB.
1906This variable will preserve the state required to resume the parsing
1907when more data arrives.")
1908
1909(defvar-local gdbmi-bnf-offset 0
1910 "Offset in `gud-marker-acc' at which the parser is reading.
1911This offset is used to be able to parse the GDB/MI message
1912in-place, without the need of copying the string in a temporary buffer
1913or discarding parsed tokens by substringing the message.")
1914
1915(defun gdbmi-bnf-init ()
1916 "Initialize the GDB/MI message parser."
1917 (setq gdbmi-bnf-state 'gdbmi-bnf-output)
1918 (setq gdbmi-bnf-offset 0)
1919 (setq gud-marker-acc ""))
1920
1921
1922(defun gdbmi-bnf-output ()
1923 "Implementation of the following GDB/MI output grammar rule:
1924
1925 output ==>
1926 ( out-of-band-record )* [ result-record ] gdb-prompt"
1927
1928 (gdbmi-bnf-skip-unrecognized)
1929 (while (gdbmi-bnf-out-of-band-record))
1930 (gdbmi-bnf-result-record)
1931 (gdbmi-bnf-gdb-prompt))
1932
1933
1934(defun gdbmi-bnf-skip-unrecognized ()
1935 "Skip characters until is encounters the beginning of a valid record.
1936Used as a protection mechanism in case something goes wrong when parsing
1937a GDB/MI reply message."
1938 (let ((acc-length (length gud-marker-acc))
1939 (prefix-offset gdbmi-bnf-offset)
1940 (prompt "(gdb) \n"))
1941
1942 (while (and (< prefix-offset acc-length)
1943 (gdbmi-is-number (aref gud-marker-acc prefix-offset)))
1944 (setq prefix-offset (1+ prefix-offset)))
1945
1946 (if (and (< prefix-offset acc-length)
1947 (not (memq (aref gud-marker-acc prefix-offset)
1948 '(?^ ?* ?+ ?= ?~ ?@ ?&)))
1949 (not (gdbmi-same-start gud-marker-acc gdbmi-bnf-offset prompt))
1950 (string-match "\\([^^*+=~@&]+\\)" gud-marker-acc
1951 gdbmi-bnf-offset))
1952 (let ((unrecognized-str (match-string 0 gud-marker-acc)))
1953 (setq gdbmi-bnf-offset (match-end 0))
1954 (if gdbmi-debug-mode
1955 (message "gdbmi-bnf-skip-unrecognized: %s" unrecognized-str))
1956 (gdb-shell unrecognized-str)
1957 t))))
1958
1959
1960(defun gdbmi-bnf-gdb-prompt ()
1961 "Implementation of the following GDB/MI output grammar rule:
1962 gdb-prompt ==>
1963 '(gdb)' nl
1964
1965 nl ==>
1966 CR | CR-LF"
1967
1968 (let ((prompt "(gdb) \n"))
1969 (when (gdbmi-start-with gud-marker-acc gdbmi-bnf-offset prompt)
1970 (if gdbmi-debug-mode (message "gdbmi-bnf-gdb-prompt: %s" prompt))
1971 (gdb-gdb prompt)
1972 (setq gdbmi-bnf-offset (+ gdbmi-bnf-offset (length prompt)))
1973
1974 ;; Returns non-nil to tell gud-gdbmi-marker-filter we've reached
1975 ;; the end of a GDB reply message.
1976 t)))
1977
1978
1979(defun gdbmi-bnf-result-record ()
1980 "Implementation of the following GDB/MI output grammar rule:
1981
1982 result-record ==>
1983 [ token ] '^' result-class ( ',' result )* nl
1984
1985 token ==>
1986 any sequence of digits."
1987
1988 (gdbmi-bnf-result-and-async-record-impl))
1989
1990
1991(defun gdbmi-bnf-out-of-band-record ()
1992 "Implementation of the following GDB/MI output grammar rule:
1993
1994 out-of-band-record ==>
1995 async-record | stream-record"
1996
1997 (or (gdbmi-bnf-async-record)
1998 (gdbmi-bnf-stream-record)))
1999
2000
2001(defun gdbmi-bnf-async-record ()
2002 "Implementation of the following GDB/MI output grammar rules:
2003
2004 async-record ==>
2005 exec-async-output | status-async-output | notify-async-output
2006
2007 exec-async-output ==>
2008 [ token ] '*' async-output
2009
2010 status-async-output ==>
2011 [ token ] '+' async-output
2012
2013 notify-async-output ==>
2014 [ token ] '=' async-output
2015
2016 async-output ==>
2017 async-class ( ',' result )* nl"
2018
2019 (gdbmi-bnf-result-and-async-record-impl))
2020
2021
2022(defun gdbmi-bnf-stream-record ()
2023 "Implement the following GDB/MI output grammar rule:
2024 stream-record ==>
2025 console-stream-output | target-stream-output | log-stream-output
2026
2027 console-stream-output ==>
2028 '~' c-string
2029
2030 target-stream-output ==>
2031 '@' c-string
2032
2033 log-stream-output ==>
2034 '&' c-string"
2035 (when (< gdbmi-bnf-offset (length gud-marker-acc))
2036 (if (and (member (aref gud-marker-acc gdbmi-bnf-offset) '(?~ ?@ ?&))
2037 (string-match "\\([~@&]\\)\\(\".*?\"\\)\n" gud-marker-acc
2038 gdbmi-bnf-offset))
2039 (let ((prefix (match-string 1 gud-marker-acc))
2040 (c-string (match-string 2 gud-marker-acc)))
2041
2042 (setq gdbmi-bnf-offset (match-end 0))
2043 (if gdbmi-debug-mode (message "gdbmi-bnf-stream-record: %s"
2044 (match-string 0 gud-marker-acc)))
2045
2046 (cond ((string-equal prefix "~")
2047 (gdbmi-bnf-console-stream-output c-string))
2048 ((string-equal prefix "@")
2049 (gdbmi-bnf-target-stream-output c-string))
2050 ((string-equal prefix "&")
2051 (gdbmi-bnf-log-stream-output c-string)))
2052 t))))
2053
2054(defun gdbmi-bnf-console-stream-output (c-string)
2055 "Handler for the console-stream-output GDB/MI output grammar rule."
2056 (gdb-console c-string))
2057
2058(defun gdbmi-bnf-target-stream-output (_c-string)
2059 "Handler for the target-stream-output GDB/MI output grammar rule."
2060 ;; Not currently used.
2061 )
2062
2063(defun gdbmi-bnf-log-stream-output (c-string)
2064 "Handler for the log-stream-output GDB/MI output grammar rule."
2065 ;; Suppress "No registers." GDB 6.8 and earlier
2066 ;; duplicates MI error message on internal stream.
2067 ;; Don't print to GUD buffer.
2068 (if (not (string-equal (read c-string) "No registers.\n"))
2069 (gdb-internals c-string)))
2070
2071
2072(defconst gdbmi-bnf-result-state-configs
2073 '(("^" . (("done" . (gdb-done . progressive))
2074 ("error" . (gdb-error . progressive))
2075 ("running" . (gdb-starting . atomic))))
2076 ("*" . (("stopped" . (gdb-stopped . atomic))
2077 ("running" . (gdb-running . atomic))))
2078 ("+" . ())
2079 ("=" . (("thread-created" . (gdb-thread-created . atomic))
2080 ("thread-selected" . (gdb-thread-selected . atomic))
2081 ("thread-existed" . (gdb-ignored-notification . atomic))
2082 ('default . (gdb-ignored-notification . atomic)))))
2083 "Alist of alists, mapping the type and class of message to a handler function.
2084Handler functions are all flagged as either `progressive' or `atomic'.
2085`progressive' handlers are capable of parsing incomplete messages.
2086They can be called several time with new data chunk as they arrive from GDB.
2087`progressive' handlers must have an extra argument that is set to a non-nil
2088value when the message is complete.
2089
2090Implement the following GDB/MI output grammar rule:
2091 result-class ==>
2092 'done' | 'running' | 'connected' | 'error' | 'exit'
2093
2094 async-class ==>
2095 'stopped' | others (where others will be added depending on the needs
2096 --this is still in development).")
2097
2098(defun gdbmi-bnf-result-and-async-record-impl ()
2099 "Common implementation of the result-record and async-record rule.
2100Both rules share the same syntax. Those records may be very large in size.
2101For that reason, the \"result\" part of the record is parsed by
2102`gdbmi-bnf-incomplete-record-result', which will keep
2103receiving characters as they arrive from GDB until the record is complete."
2104 (let ((acc-length (length gud-marker-acc))
2105 (prefix-offset gdbmi-bnf-offset))
2106
2107 (while (and (< prefix-offset acc-length)
2108 (gdbmi-is-number (aref gud-marker-acc prefix-offset)))
2109 (setq prefix-offset (1+ prefix-offset)))
2110
2111 (if (and (< prefix-offset acc-length)
2112 (member (aref gud-marker-acc prefix-offset) '(?* ?+ ?= ?^))
2113 (string-match "\\([0-9]*\\)\\([*+=^]\\)\\(.+?\\)\\([,\n]\\)"
2114 gud-marker-acc gdbmi-bnf-offset))
2115
2116 (let ((token (match-string 1 gud-marker-acc))
2117 (prefix (match-string 2 gud-marker-acc))
2118 (class (match-string 3 gud-marker-acc))
2119 (complete (string-equal (match-string 4 gud-marker-acc) "\n"))
2120 class-alist
2121 class-command)
2122
2123 (setq gdbmi-bnf-offset (match-end 0))
2124 (if gdbmi-debug-mode (message "gdbmi-bnf-result-record: %s"
2125 (match-string 0 gud-marker-acc)))
2126
2127 (setq class-alist
2128 (cdr (assoc prefix gdbmi-bnf-result-state-configs)))
2129 (setq class-command (cdr (assoc class class-alist)))
2130 (if (null class-command)
2131 (setq class-command (cdr (assoc 'default class-alist))))
2132
2133 (if complete
2134 (if class-command
2135 (if (equal (cdr class-command) 'progressive)
2136 (funcall (car class-command) token "" complete)
2137 (funcall (car class-command) token "")))
2138 (setq gdbmi-bnf-state
2139 (lambda ()
2140 (gdbmi-bnf-incomplete-record-result token class-command)))
2141 (funcall gdbmi-bnf-state))
2142 t))))
2143
2144(defun gdbmi-bnf-incomplete-record-result (token class-command)
2145 "State of the parser used to progressively parse a result-record or async-record
2146rule from an incomplete data stream. The parser will stay in this state until
2147the end of the current result or async record is reached."
2148 (when (< gdbmi-bnf-offset (length gud-marker-acc))
2149 ;; Search the data stream for the end of the current record:
2150 (let* ((newline-pos (string-match "\n" gud-marker-acc gdbmi-bnf-offset))
2151 (is-progressive (equal (cdr class-command) 'progressive))
7ce5be54
JPG
2152 (is-complete (not (null newline-pos)))
2153 result-str)
2154
2155 (when gdbmi-debug-mode
2156 (message "gdbmi-bnf-incomplete-record-result: %s"
2157 (substring gud-marker-acc gdbmi-bnf-offset newline-pos)))
6ff2c8f1
JPG
2158
2159 ;; Update the gdbmi-bnf-offset only if the current chunk of data can
2160 ;; be processed by the class-command handler:
2161 (when (or is-complete is-progressive)
7ce5be54 2162 (setq result-str
6ff2c8f1 2163 (substring gud-marker-acc gdbmi-bnf-offset newline-pos))
6ff2c8f1 2164
7ce5be54
JPG
2165 ;; Move gdbmi-bnf-offset past the end of the chunk.
2166 (setq gdbmi-bnf-offset (+ gdbmi-bnf-offset (length result-str)))
2167 (when newline-pos
2168 (setq gdbmi-bnf-offset (1+ gdbmi-bnf-offset))))
6ff2c8f1
JPG
2169
2170 ;; Update the parsing state before invoking the handler in class-command
2171 ;; to make sure it's not left in an invalid state if the handler was
2172 ;; to generate an error.
2173 (if is-complete
2174 (setq gdbmi-bnf-state 'gdbmi-bnf-output))
2175
2176 (if class-command
2177 (if is-progressive
2178 (funcall (car class-command) token result-str is-complete)
2179 (if is-complete
2180 (funcall (car class-command) token result-str))))
2181
2182 (unless is-complete
2183 ;; Incomplete gdb response: abort parsing until we receive more data.
2184 (if gdbmi-debug-mode (message "gdbmi-bnf-incomplete-record-result, aborting: incomplete stream"))
2185 (throw 'gdbmi-incomplete-stream nil))
2186
2187 is-complete)))
2188
2189
2190; The following grammar rules are not yet implemented by this GDBMI-BNF parser.
2191; The handling of those rules is currently done by the handlers registered
2192; in gdbmi-bnf-result-state-configs
2193;
2194; result ==>
2195; variable "=" value
2196;
2197; variable ==>
2198; string
2199;
2200; value ==>
2201; const | tuple | list
2202;
2203; const ==>
2204; c-string
2205;
2206; tuple ==>
2207; "{}" | "{" result ( "," result )* "}"
2208;
2209; list ==>
2210; "[]" | "[" value ( "," value )* "]" | "[" result ( "," result )* "]"
2211
691cf4a0
NR
2212
2213(defun gud-gdbmi-marker-filter (string)
2214 "Filter GDB/MI output."
2215
2216 ;; Record transactions if logging is enabled.
2217 (when gdb-enable-debug
2218 (push (cons 'recv string) gdb-debug-log)
2219 (if (and gdb-debug-log-max
2220 (> (length gdb-debug-log) gdb-debug-log-max))
2221 (setcdr (nthcdr (1- gdb-debug-log-max) gdb-debug-log) nil)))
2222
e7e85dc0 2223 ;; Recall the left over gud-marker-acc from last time.
691cf4a0
NR
2224 (setq gud-marker-acc (concat gud-marker-acc string))
2225
e7e85dc0 2226 ;; Start accumulating output for the GUD buffer.
691cf4a0 2227 (setq gdb-filter-output "")
691cf4a0 2228
6ff2c8f1
JPG
2229 (let ((acc-length (length gud-marker-acc)))
2230 (catch 'gdbmi-incomplete-stream
2231 (while (and (< gdbmi-bnf-offset acc-length)
2232 (funcall gdbmi-bnf-state)))))
2233
2234 (when (/= gdbmi-bnf-offset 0)
2235 (setq gud-marker-acc (substring gud-marker-acc gdbmi-bnf-offset))
2236 (setq gdbmi-bnf-offset 0))
2237
2238 (when (and gdbmi-debug-mode (> (length gud-marker-acc) 0))
2239 (message "gud-gdbmi-marker-filter, unparsed string: %s" gud-marker-acc))
691cf4a0 2240
6ff2c8f1 2241 gdb-filter-output)
691cf4a0 2242
e02f48d7 2243(defun gdb-gdb (_output-field))
691cf4a0
NR
2244
2245(defun gdb-shell (output-field)
e7e85dc0
SM
2246 (setq gdb-filter-output
2247 (concat output-field gdb-filter-output)))
691cf4a0 2248
6ff2c8f1 2249(defun gdb-ignored-notification (_token _output-field))
691cf4a0
NR
2250
2251;; gdb-invalidate-threads is defined to accept 'update-threads signal
6ff2c8f1
JPG
2252(defun gdb-thread-created (_token _output-field))
2253(defun gdb-thread-exited (_token output-field)
2254 "Handle =thread-exited async record.
2255Unset `gdb-thread-number' if current thread exited and update threads list."
3db614b0
SM
2256 (let* ((thread-id (bindat-get-field (gdb-json-string output-field) 'id)))
2257 (if (string= gdb-thread-number thread-id)
2258 (gdb-setq-thread-number nil))
2259 ;; When we continue current thread and it quickly exits,
2260 ;; gdb-pending-triggers left after gdb-running disallow us to
2261 ;; properly call -thread-info without --thread option. Thus we
2262 ;; need to use gdb-wait-for-pending.
2263 (gdb-wait-for-pending
2264 (gdb-emit-signal gdb-buf-publisher 'update-threads))))
691cf4a0 2265
6ff2c8f1 2266(defun gdb-thread-selected (_token output-field)
691cf4a0
NR
2267 "Handler for =thread-selected MI output record.
2268
2269Sets `gdb-thread-number' to new id."
2270 (let* ((result (gdb-json-string output-field))
2271 (thread-id (bindat-get-field result 'id)))
2272 (gdb-setq-thread-number thread-id)
2273 ;; Typing `thread N` in GUD buffer makes GDB emit `^done` followed
2274 ;; by `=thread-selected` notification. `^done` causes `gdb-update`
2275 ;; as usually. Things happen to fast and second call (from
2276 ;; gdb-thread-selected handler) gets cut off by our beloved
2277 ;; gdb-pending-triggers.
2278 ;; Solution is `gdb-wait-for-pending` macro: it guarantees that its
2279 ;; body will get executed when `gdb-pending-triggers` is empty.
2280 (gdb-wait-for-pending
2281 (gdb-update))))
2282
6ff2c8f1 2283(defun gdb-running (_token output-field)
3db614b0
SM
2284 (let* ((thread-id
2285 (bindat-get-field (gdb-json-string output-field) 'thread-id)))
691cf4a0
NR
2286 ;; We reset gdb-frame-number to nil if current thread has gone
2287 ;; running. This can't be done in gdb-thread-list-handler-custom
2288 ;; because we need correct gdb-frame-number by the time
2289 ;; -thread-info command is sent.
2290 (when (or (string-equal thread-id "all")
2291 (string-equal thread-id gdb-thread-number))
2292 (setq gdb-frame-number nil)))
2293 (setq gdb-inferior-status "running")
2294 (gdb-force-mode-line-update
2295 (propertize gdb-inferior-status 'face font-lock-type-face))
2296 (when (not gdb-non-stop)
2297 (setq gud-running t))
2298 (setq gdb-active-process t)
2299 (gdb-emit-signal gdb-buf-publisher 'update-threads))
2300
6ff2c8f1 2301(defun gdb-starting (_output-field _result)
691cf4a0
NR
2302 ;; CLI commands don't emit ^running at the moment so use gdb-running too.
2303 (setq gdb-inferior-status "running")
2304 (gdb-force-mode-line-update
2305 (propertize gdb-inferior-status 'face font-lock-type-face))
2306 (setq gdb-active-process t)
2307 (setq gud-running t)
2308 ;; GDB doesn't seem to respond to -thread-info before first stop or
2309 ;; thread exit (even in non-stop mode), so this is useless.
fe3c5669 2310 ;; Behavior may change in the future.
691cf4a0
NR
2311 (gdb-emit-signal gdb-buf-publisher 'update-threads))
2312
2313;; -break-insert -t didn't give a reason before gdb 6.9
2314
6ff2c8f1 2315(defun gdb-stopped (_token output-field)
691cf4a0
NR
2316 "Given the contents of *stopped MI async record, select new
2317current thread and update GDB buffers."
2318 ;; Reason is available with target-async only
2319 (let* ((result (gdb-json-string output-field))
2320 (reason (bindat-get-field result 'reason))
2321 (thread-id (bindat-get-field result 'thread-id)))
2322
2323 ;; -data-list-register-names needs to be issued for any stopped
2324 ;; thread
2325 (when (not gdb-register-names)
2170cb53
CY
2326 (gdb-input (concat "-data-list-register-names"
2327 (if gdb-supports-non-stop
2328 (concat " --thread " thread-id)))
2329 'gdb-register-names-handler))
691cf4a0 2330
e7e85dc0
SM
2331 ;; Don't set gud-last-frame here as it's currently done in
2332 ;; gdb-frame-handler because synchronous GDB doesn't give these fields
2333 ;; with CLI.
2334 ;;(when file
2335 ;; (setq
2336 ;; ;; Extract the frame position from the marker.
2337 ;; gud-last-frame (cons file
2338 ;; (string-to-number
2339 ;; (match-string 6 gud-marker-acc)))))
691cf4a0
NR
2340
2341 (setq gdb-inferior-status (or reason "unknown"))
2342 (gdb-force-mode-line-update
2343 (propertize gdb-inferior-status 'face font-lock-warning-face))
2344 (if (string-equal reason "exited-normally")
2345 (setq gdb-active-process nil))
2346
2347 ;; Select new current thread.
2348
2349 ;; Don't switch if we have no reasons selected
2350 (when gdb-switch-reasons
2351 ;; Switch from another stopped thread only if we have
2352 ;; gdb-switch-when-another-stopped:
2353 (when (or gdb-switch-when-another-stopped
2354 (not (string= "stopped"
2355 (bindat-get-field (gdb-current-buffer-thread) 'state))))
2356 ;; Switch if current reason has been selected or we have no
2357 ;; reasons
2358 (if (or (eq gdb-switch-reasons t)
2359 (member reason gdb-switch-reasons))
3db614b0
SM
2360 (when (not (string-equal gdb-thread-number thread-id))
2361 (message (concat "Switched to thread " thread-id))
2362 (gdb-setq-thread-number thread-id))
691cf4a0
NR
2363 (message (format "Thread %s stopped" thread-id)))))
2364
3db614b0
SM
2365 ;; Print "(gdb)" to GUD console
2366 (when gdb-first-done-or-error
2367 (setq gdb-filter-output (concat gdb-filter-output gdb-prompt-name)))
691cf4a0 2368
3db614b0
SM
2369 ;; In non-stop, we update information as soon as another thread gets
2370 ;; stopped
2371 (when (or gdb-first-done-or-error
2372 gdb-non-stop)
2373 ;; In all-stop this updates gud-running properly as well.
2374 (gdb-update)
2375 (setq gdb-first-done-or-error nil))
b668fa6e 2376 (run-hook-with-args 'gdb-stopped-functions result)))
691cf4a0
NR
2377
2378;; Remove the trimmings from log stream containing debugging messages
2379;; being produced by GDB's internals, use warning face and send to GUD
2380;; buffer.
2381(defun gdb-internals (output-field)
2382 (setq gdb-filter-output
2383 (gdb-concat-output
2384 gdb-filter-output
ba025fbd
EZ
2385 (if (string= output-field "\"\\n\"")
2386 ""
2387 (let ((error-message
2388 (read output-field)))
2389 (put-text-property
2390 0 (length error-message)
2391 'face font-lock-warning-face
2392 error-message)
2393 error-message)))))
691cf4a0
NR
2394
2395;; Remove the trimmings from the console stream and send to GUD buffer
2396;; (frontend MI commands should not print to this stream)
2397(defun gdb-console (output-field)
3db614b0 2398 (setq gdb-filter-output
2170cb53 2399 (gdb-concat-output gdb-filter-output (read output-field))))
691cf4a0 2400
6ff2c8f1
JPG
2401(defun gdb-done (token-number output-field is-complete)
2402 (gdb-done-or-error token-number 'done output-field is-complete))
2403
2404(defun gdb-error (token-number output-field is-complete)
2405 (gdb-done-or-error token-number 'error output-field is-complete))
2406
2407(defun gdb-done-or-error (token-number type output-field is-complete)
691cf4a0
NR
2408 (if (string-equal token-number "")
2409 ;; Output from command entered by user
2410 (progn
2411 (setq gdb-output-sink 'user)
2412 (setq token-number nil)
2413 ;; MI error - send to minibuffer
2414 (when (eq type 'error)
3db614b0
SM
2415 ;; Skip "msg=" from `output-field'
2416 (message (read (substring output-field 4)))
2417 ;; Don't send to the console twice. (If it is a console error
2418 ;; it is also in the console stream.)
2419 (setq output-field nil)))
691cf4a0
NR
2420 ;; Output from command from frontend.
2421 (setq gdb-output-sink 'emacs))
2422
b668fa6e
CY
2423 ;; The process may already be dead (e.g. C-d at the gdb prompt).
2424 (let* ((proc (get-buffer-process gud-comint-buffer))
2425 (no-proc (or (null proc)
2426 (memq (process-status proc) '(exit signal)))))
691cf4a0 2427
6ff2c8f1 2428 (when (and is-complete gdb-first-done-or-error)
b668fa6e
CY
2429 (unless (or token-number gud-running no-proc)
2430 (setq gdb-filter-output (concat gdb-filter-output gdb-prompt-name)))
2431 (gdb-update no-proc)
2432 (setq gdb-first-done-or-error nil))
2433
2434 (setq gdb-filter-output
2435 (gdb-concat-output gdb-filter-output output-field))
2436
6ff2c8f1
JPG
2437 ;; We are done concatenating to the output sink. Restore it to user sink:
2438 (setq gdb-output-sink 'user)
2439
2440 (when (and token-number is-complete)
b668fa6e
CY
2441 (with-current-buffer
2442 (gdb-get-buffer-create 'gdb-partial-output-buffer)
2443 (funcall
2444 (cdr (assoc (string-to-number token-number) gdb-handler-alist))))
2445 (setq gdb-handler-alist
6ff2c8f1
JPG
2446 (assq-delete-all token-number gdb-handler-alist)))
2447
2448 (when is-complete
2449 (gdb-clear-partial-output))))
691cf4a0
NR
2450
2451(defun gdb-concat-output (so-far new)
2170cb53
CY
2452 (cond
2453 ((eq gdb-output-sink 'user) (concat so-far new))
2454 ((eq gdb-output-sink 'emacs)
2455 (gdb-append-to-partial-output new)
2456 so-far)))
691cf4a0
NR
2457
2458(defun gdb-append-to-partial-output (string)
2459 (with-current-buffer (gdb-get-buffer-create 'gdb-partial-output-buffer)
2460 (goto-char (point-max))
2461 (insert string)))
2462
2463(defun gdb-clear-partial-output ()
2464 (with-current-buffer (gdb-get-buffer-create 'gdb-partial-output-buffer)
2465 (erase-buffer)))
2466
2467(defun gdb-jsonify-buffer (&optional fix-key fix-list)
2468 "Prepare GDB/MI output in current buffer for parsing with `json-read'.
2469
2470Field names are wrapped in double quotes and equal signs are
2471replaced with semicolons.
2472
40b1a3a9 2473If FIX-KEY is non-nil, strip all \"FIX-KEY=\" occurrences from
6ff2c8f1
JPG
2474partial output. This is used to get rid of useless keys in lists
2475in MI messages, e.g.: [key=.., key=..]. -stack-list-frames and
691cf4a0
NR
2476-break-info are examples of MI commands which issue such
2477responses.
2478
2479If FIX-LIST is non-nil, \"FIX-LIST={..}\" is replaced with
2480\"FIX-LIST=[..]\" prior to parsing. This is used to fix broken
2481-break-info output when it contains breakpoint script field
2482incompatible with GDB/MI output syntax."
2483 (save-excursion
2484 (goto-char (point-min))
2485 (when fix-key
2486 (save-excursion
2487 (while (re-search-forward (concat "[\\[,]\\(" fix-key "=\\)") nil t)
2488 (replace-match "" nil nil nil 1))))
2489 (when fix-list
2490 (save-excursion
2491 ;; Find positions of braces which enclose broken list
2492 (while (re-search-forward (concat fix-list "={\"") nil t)
2493 (let ((p1 (goto-char (- (point) 2)))
2494 (p2 (progn (forward-sexp)
2495 (1- (point)))))
2496 ;; Replace braces with brackets
2497 (save-excursion
2498 (goto-char p1)
2499 (delete-char 1)
2500 (insert "[")
2501 (goto-char p2)
2502 (delete-char 1)
2503 (insert "]"))))))
2504 (goto-char (point-min))
2505 (insert "{")
2506 (while (re-search-forward
2507 "\\([[:alnum:]-_]+\\)=\\({\\|\\[\\|\"\"\\|\".*?[^\\]\"\\)" nil t)
2508 (replace-match "\"\\1\":\\2" nil nil))
2509 (goto-char (point-max))
2510 (insert "}")))
2511
2512(defun gdb-json-read-buffer (&optional fix-key fix-list)
2513 "Prepare and parse GDB/MI output in current buffer with `json-read'.
2514
2515FIX-KEY and FIX-LIST work as in `gdb-jsonify-buffer'."
2516 (gdb-jsonify-buffer fix-key fix-list)
2517 (save-excursion
2518 (goto-char (point-min))
2519 (let ((json-array-type 'list))
2520 (json-read))))
2521
2522(defun gdb-json-string (string &optional fix-key fix-list)
2523 "Prepare and parse STRING containing GDB/MI output with `json-read'.
2524
2525FIX-KEY and FIX-LIST work as in `gdb-jsonify-buffer'."
2526 (with-temp-buffer
2527 (insert string)
2528 (gdb-json-read-buffer fix-key fix-list)))
2529
2530(defun gdb-json-partial-output (&optional fix-key fix-list)
2531 "Prepare and parse gdb-partial-output-buffer with `json-read'.
2532
2533FIX-KEY and FIX-KEY work as in `gdb-jsonify-buffer'."
2534 (with-current-buffer (gdb-get-buffer-create 'gdb-partial-output-buffer)
2535 (gdb-json-read-buffer fix-key fix-list)))
2536
2537(defun gdb-line-posns (line)
2538 "Return a pair of LINE beginning and end positions."
2539 (let ((offset (1+ (- line (line-number-at-pos)))))
2540 (cons
2541 (line-beginning-position offset)
2542 (line-end-position offset))))
2543
2544(defmacro gdb-mark-line (line variable)
2545 "Set VARIABLE marker to point at beginning of LINE.
2546
2547If current window has no fringes, inverse colors on LINE.
2548
2549Return position where LINE begins."
2550 `(save-excursion
2551 (let* ((posns (gdb-line-posns ,line))
2552 (start-posn (car posns))
2553 (end-posn (cdr posns)))
2554 (set-marker ,variable (copy-marker start-posn))
2555 (when (not (> (car (window-fringes)) 0))
2556 (put-text-property start-posn end-posn
2557 'font-lock-face '(:inverse-video t)))
2558 start-posn)))
2559
2560(defun gdb-pad-string (string padding)
2561 (format (concat "%" (number-to-string padding) "s") string))
2562
2563;; gdb-table struct is a way to programmatically construct simple
2564;; tables. It help to reliably align columns of data in GDB buffers
2565;; and provides
a464a6c7 2566(cl-defstruct gdb-table
691cf4a0
NR
2567 (column-sizes nil)
2568 (rows nil)
2569 (row-properties nil)
2570 (right-align nil))
2571
2572(defun gdb-mapcar* (function &rest seqs)
2573 "Apply FUNCTION to each element of SEQS, and make a list of the results.
2574If there are several SEQS, FUNCTION is called with that many
c7015153 2575arguments, and mapping stops as soon as the shortest list runs
691cf4a0
NR
2576out."
2577 (let ((shortest (apply #'min (mapcar #'length seqs))))
2578 (mapcar (lambda (i)
2579 (apply function
2580 (mapcar
2581 (lambda (seq)
2582 (nth i seq))
2583 seqs)))
2584 (number-sequence 0 (1- shortest)))))
2585
2586(defun gdb-table-add-row (table row &optional properties)
2587 "Add ROW of string to TABLE and recalculate column sizes.
2588
2589When non-nil, PROPERTIES will be added to the whole row when
2590calling `gdb-table-string'."
2591 (let ((rows (gdb-table-rows table))
2592 (row-properties (gdb-table-row-properties table))
2593 (column-sizes (gdb-table-column-sizes table))
2594 (right-align (gdb-table-right-align table)))
2595 (when (not column-sizes)
2596 (setf (gdb-table-column-sizes table)
2597 (make-list (length row) 0)))
2598 (setf (gdb-table-rows table)
2599 (append rows (list row)))
2600 (setf (gdb-table-row-properties table)
2601 (append row-properties (list properties)))
2602 (setf (gdb-table-column-sizes table)
2603 (gdb-mapcar* (lambda (x s)
3db614b0
SM
2604 (let ((new-x
2605 (max (abs x) (string-width (or s "")))))
2606 (if right-align new-x (- new-x))))
2607 (gdb-table-column-sizes table)
2608 row))
691cf4a0
NR
2609 ;; Avoid trailing whitespace at eol
2610 (if (not (gdb-table-right-align table))
2611 (setcar (last (gdb-table-column-sizes table)) 0))))
2612
2613(defun gdb-table-string (table &optional sep)
2614 "Return TABLE as a string with columns separated with SEP."
e02f48d7 2615 (let ((column-sizes (gdb-table-column-sizes table)))
691cf4a0
NR
2616 (mapconcat
2617 'identity
2618 (gdb-mapcar*
2619 (lambda (row properties)
2620 (apply 'propertize
2621 (mapconcat 'identity
2622 (gdb-mapcar* (lambda (s x) (gdb-pad-string s x))
2623 row column-sizes)
2624 sep)
2625 properties))
2626 (gdb-table-rows table)
2627 (gdb-table-row-properties table))
2628 "\n")))
2629
2630;; bindat-get-field goes deep, gdb-get-many-fields goes wide
2631(defun gdb-get-many-fields (struct &rest fields)
2632 "Return a list of FIELDS values from STRUCT."
2633 (let ((values))
e7e85dc0
SM
2634 (dolist (field fields)
2635 (push (bindat-get-field struct field) values))
2636 (nreverse values)))
691cf4a0
NR
2637
2638(defmacro def-gdb-auto-update-trigger (trigger-name gdb-command
2639 handler-name
2640 &optional signal-list)
2641 "Define a trigger TRIGGER-NAME which sends GDB-COMMAND and sets
6ff2c8f1 2642HANDLER-NAME as its handler. HANDLER-NAME is bound to current
691cf4a0
NR
2643buffer with `gdb-bind-function-to-buffer'.
2644
2645If SIGNAL-LIST is non-nil, GDB-COMMAND is sent only when the
6ff2c8f1 2646defined trigger is called with an argument from SIGNAL-LIST. It's
691cf4a0
NR
2647not recommended to define triggers with empty SIGNAL-LIST.
2648Normally triggers should respond at least to 'update signal.
2649
2650Normally the trigger defined by this command must be called from
6ff2c8f1 2651the buffer where HANDLER-NAME must work. This should be done so
691cf4a0
NR
2652that buffer-local thread number may be used in GDB-COMMAND (by
2653calling `gdb-current-context-command').
2654`gdb-bind-function-to-buffer' is used to achieve this, see
2655`gdb-get-buffer-create'.
2656
2657Triggers defined by this command are meant to be used as a
2658trigger argument when describing buffer types with
2659`gdb-set-buffer-rules'."
2660 `(defun ,trigger-name (&optional signal)
2661 (when
2662 (or (not ,signal-list)
2663 (memq signal ,signal-list))
2664 (when (not (gdb-pending-p
2665 (cons (current-buffer) ',trigger-name)))
2170cb53
CY
2666 (gdb-input ,gdb-command
2667 (gdb-bind-function-to-buffer ',handler-name (current-buffer)))
691cf4a0
NR
2668 (gdb-add-pending (cons (current-buffer) ',trigger-name))))))
2669
2670;; Used by disassembly buffer only, the rest use
2671;; def-gdb-trigger-and-handler
2672(defmacro def-gdb-auto-update-handler (handler-name trigger-name custom-defun
2673 &optional nopreserve)
2674 "Define a handler HANDLER-NAME for TRIGGER-NAME with CUSTOM-DEFUN.
2675
2676Handlers are normally called from the buffers they put output in.
2677
2678Delete ((current-buffer) . TRIGGER-NAME) from
2679`gdb-pending-triggers', erase current buffer and evaluate
6ff2c8f1 2680CUSTOM-DEFUN. Then `gdb-update-buffer-name' is called.
691cf4a0
NR
2681
2682If NOPRESERVE is non-nil, window point is not restored after CUSTOM-DEFUN."
2683 `(defun ,handler-name ()
2684 (gdb-delete-pending (cons (current-buffer) ',trigger-name))
6ff2c8f1
JPG
2685 (let* ((inhibit-read-only t)
2686 ,@(unless nopreserve
2687 '((window (get-buffer-window (current-buffer) 0))
2688 (start (window-start window))
2689 (p (window-point window)))))
691cf4a0
NR
2690 (erase-buffer)
2691 (,custom-defun)
2692 (gdb-update-buffer-name)
6ff2c8f1
JPG
2693 ,@(when (not nopreserve)
2694 '((set-window-start window start)
2695 (set-window-point window p))))))
691cf4a0
NR
2696
2697(defmacro def-gdb-trigger-and-handler (trigger-name gdb-command
3db614b0
SM
2698 handler-name custom-defun
2699 &optional signal-list)
691cf4a0
NR
2700 "Define trigger and handler.
2701
6ff2c8f1
JPG
2702TRIGGER-NAME trigger is defined to send GDB-COMMAND.
2703See `def-gdb-auto-update-trigger'.
691cf4a0 2704
6ff2c8f1
JPG
2705HANDLER-NAME handler uses customization of CUSTOM-DEFUN.
2706See `def-gdb-auto-update-handler'."
691cf4a0
NR
2707 `(progn
2708 (def-gdb-auto-update-trigger ,trigger-name
2709 ,gdb-command
2710 ,handler-name ,signal-list)
2711 (def-gdb-auto-update-handler ,handler-name
2712 ,trigger-name ,custom-defun)))
2713
2714\f
2715
2716;; Breakpoint buffer : This displays the output of `-break-list'.
2717(def-gdb-trigger-and-handler
2718 gdb-invalidate-breakpoints "-break-list"
2719 gdb-breakpoints-list-handler gdb-breakpoints-list-handler-custom
2720 '(start update))
2721
2722(gdb-set-buffer-rules
2723 'gdb-breakpoints-buffer
2724 'gdb-breakpoints-buffer-name
2725 'gdb-breakpoints-mode
2726 'gdb-invalidate-breakpoints)
2727
2728(defun gdb-breakpoints-list-handler-custom ()
2729 (let ((breakpoints-list (bindat-get-field
2730 (gdb-json-partial-output "bkpt" "script")
2731 'BreakpointTable 'body))
2732 (table (make-gdb-table)))
2733 (setq gdb-breakpoints-list nil)
2734 (gdb-table-add-row table '("Num" "Type" "Disp" "Enb" "Addr" "Hits" "What"))
2735 (dolist (breakpoint breakpoints-list)
2736 (add-to-list 'gdb-breakpoints-list
2737 (cons (bindat-get-field breakpoint 'number)
2738 breakpoint))
2739 (let ((at (bindat-get-field breakpoint 'at))
2740 (pending (bindat-get-field breakpoint 'pending))
2741 (func (bindat-get-field breakpoint 'func))
2742 (type (bindat-get-field breakpoint 'type)))
3db614b0
SM
2743 (gdb-table-add-row table
2744 (list
2745 (bindat-get-field breakpoint 'number)
133b8e11
KS
2746 (or type "")
2747 (or (bindat-get-field breakpoint 'disp) "")
3db614b0
SM
2748 (let ((flag (bindat-get-field breakpoint 'enabled)))
2749 (if (string-equal flag "y")
2750 (propertize "y" 'font-lock-face font-lock-warning-face)
2751 (propertize "n" 'font-lock-face font-lock-comment-face)))
2752 (bindat-get-field breakpoint 'addr)
133b8e11
KS
2753 (or (bindat-get-field breakpoint 'times) "")
2754 (if (and type (string-match ".*watchpoint" type))
3db614b0
SM
2755 (bindat-get-field breakpoint 'what)
2756 (or pending at
2757 (concat "in "
2758 (propertize (or func "unknown")
2759 'font-lock-face font-lock-function-name-face)
2760 (gdb-frame-location breakpoint)))))
2761 ;; Add clickable properties only for breakpoints with file:line
2762 ;; information
2763 (append (list 'gdb-breakpoint breakpoint)
2764 (when func '(help-echo "mouse-2, RET: visit breakpoint"
2765 mouse-face highlight))))))
691cf4a0
NR
2766 (insert (gdb-table-string table " "))
2767 (gdb-place-breakpoints)))
2768
2769;; Put breakpoint icons in relevant margins (even those set in the GUD buffer).
2770(defun gdb-place-breakpoints ()
e02f48d7
JB
2771 ;; Remove all breakpoint-icons in source buffers but not assembler buffer.
2772 (dolist (buffer (buffer-list))
2773 (with-current-buffer buffer
2774 (if (and (eq gud-minor-mode 'gdbmi)
2775 (not (string-match "\\` ?\\*.+\\*\\'" (buffer-name))))
2776 (gdb-remove-breakpoint-icons (point-min) (point-max)))))
2777 (dolist (breakpoint gdb-breakpoints-list)
2778 (let* ((breakpoint (cdr breakpoint)) ; gdb-breakpoints-list is
3db614b0 2779 ; an associative list
e02f48d7
JB
2780 (line (bindat-get-field breakpoint 'line)))
2781 (when line
2782 (let ((file (bindat-get-field breakpoint 'fullname))
2783 (flag (bindat-get-field breakpoint 'enabled))
2784 (bptno (bindat-get-field breakpoint 'number)))
a55739d3 2785 (unless (and file (file-exists-p file))
e02f48d7 2786 (setq file (cdr (assoc bptno gdb-location-alist))))
a55739d3
CY
2787 (if (or (null file)
2788 (string-equal file "File not found"))
2789 ;; If the full filename is not recorded in the
2790 ;; breakpoint structure or in `gdb-location-alist', use
2791 ;; -file-list-exec-source-file to extract it.
2792 (when (setq file (bindat-get-field breakpoint 'file))
2793 (gdb-input (concat "list " file ":1") 'ignore)
2794 (gdb-input "-file-list-exec-source-file"
2795 `(lambda () (gdb-get-location
2796 ,bptno ,line ,flag))))
2797 (with-current-buffer (find-file-noselect file 'nowarn)
2798 (gdb-init-buffer)
2799 ;; Only want one breakpoint icon at each location.
2800 (gdb-put-breakpoint-icon (string-equal flag "y") bptno
2801 (string-to-number line)))))))))
691cf4a0
NR
2802
2803(defvar gdb-source-file-regexp "fullname=\"\\(.*?\\)\"")
2804
2805(defun gdb-get-location (bptno line flag)
2806 "Find the directory containing the relevant source file.
2807Put in buffer and place breakpoint icon."
2808 (goto-char (point-min))
2809 (catch 'file-not-found
2810 (if (re-search-forward gdb-source-file-regexp nil t)
2811 (delete (cons bptno "File not found") gdb-location-alist)
3db614b0 2812 (push (cons bptno (match-string 1)) gdb-location-alist)
691cf4a0
NR
2813 (gdb-resync)
2814 (unless (assoc bptno gdb-location-alist)
2815 (push (cons bptno "File not found") gdb-location-alist)
2816 (message-box "Cannot find source file for breakpoint location.
2817Add directory to search path for source files using the GDB command, dir."))
2818 (throw 'file-not-found nil))
2819 (with-current-buffer (find-file-noselect (match-string 1))
2820 (gdb-init-buffer)
2821 ;; only want one breakpoint icon at each location
2822 (gdb-put-breakpoint-icon (eq flag ?y) bptno (string-to-number line)))))
2823
2824(add-hook 'find-file-hook 'gdb-find-file-hook)
2825
2826(defun gdb-find-file-hook ()
2827 "Set up buffer for debugging if file is part of the source code
2828of the current session."
2829 (if (and (buffer-name gud-comint-buffer)
2830 ;; in case gud or gdb-ui is just loaded
2831 gud-comint-buffer
2832 (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer)
2833 'gdbmi))
2834 (if (member buffer-file-name gdb-source-file-list)
2835 (with-current-buffer (find-buffer-visiting buffer-file-name)
2836 (gdb-init-buffer)))))
2837
2838(declare-function gud-remove "gdb-mi" t t) ; gud-def
2839(declare-function gud-break "gdb-mi" t t) ; gud-def
2840(declare-function fringe-bitmaps-at-pos "fringe.c" (&optional pos window))
2841
2842(defun gdb-mouse-set-clear-breakpoint (event)
2843 "Set/clear breakpoint in left fringe/margin at mouse click.
2844If not in a source or disassembly buffer just set point."
2845 (interactive "e")
2846 (mouse-minibuffer-check event)
2847 (let ((posn (event-end event)))
2848 (with-selected-window (posn-window posn)
175069ef 2849 (if (or (buffer-file-name) (derived-mode-p 'gdb-disassembly-mode))
691cf4a0
NR
2850 (if (numberp (posn-point posn))
2851 (save-excursion
2852 (goto-char (posn-point posn))
2853 (if (or (posn-object posn)
2854 (eq (car (fringe-bitmaps-at-pos (posn-point posn)))
2855 'breakpoint))
2856 (gud-remove nil)
2857 (gud-break nil)))))
2858 (posn-set-point posn))))
2859
2860(defun gdb-mouse-toggle-breakpoint-margin (event)
2861 "Enable/disable breakpoint in left margin with mouse click."
2862 (interactive "e")
2863 (mouse-minibuffer-check event)
2864 (let ((posn (event-end event)))
2865 (if (numberp (posn-point posn))
2866 (with-selected-window (posn-window posn)
2867 (save-excursion
2868 (goto-char (posn-point posn))
2869 (if (posn-object posn)
2870 (gud-basic-call
2871 (let ((bptno (get-text-property
2872 0 'gdb-bptno (car (posn-string posn)))))
2873 (concat
2874 (if (get-text-property
2875 0 'gdb-enabled (car (posn-string posn)))
2876 "-break-disable "
2877 "-break-enable ")
2878 bptno)))))))))
2879
2880(defun gdb-mouse-toggle-breakpoint-fringe (event)
2881 "Enable/disable breakpoint in left fringe with mouse click."
2882 (interactive "e")
2883 (mouse-minibuffer-check event)
2884 (let* ((posn (event-end event))
2885 (pos (posn-point posn))
2886 obj)
2887 (when (numberp pos)
2888 (with-selected-window (posn-window posn)
2889 (with-current-buffer (window-buffer (selected-window))
2890 (goto-char pos)
2891 (dolist (overlay (overlays-in pos pos))
2892 (when (overlay-get overlay 'put-break)
2893 (setq obj (overlay-get overlay 'before-string))))
2894 (when (stringp obj)
2895 (gud-basic-call
2896 (concat
2897 (if (get-text-property 0 'gdb-enabled obj)
2898 "-break-disable "
2899 "-break-enable ")
3db614b0 2900 (get-text-property 0 'gdb-bptno obj)))))))))
691cf4a0
NR
2901
2902(defun gdb-breakpoints-buffer-name ()
2903 (concat "*breakpoints of " (gdb-get-target-string) "*"))
2904
d97af5a0
CY
2905(defun gdb-display-breakpoints-buffer (&optional thread)
2906 "Display GDB breakpoints."
2907 (interactive)
2908 (gdb-display-buffer (gdb-get-buffer-create 'gdb-breakpoints-buffer thread)))
691cf4a0 2909
d97af5a0
CY
2910(defun gdb-frame-breakpoints-buffer (&optional thread)
2911 "Display GDB breakpoints in another frame."
2912 (interactive)
2913 (display-buffer (gdb-get-buffer-create 'gdb-breakpoints-buffer thread)
2914 gdb-display-buffer-other-frame-action))
691cf4a0
NR
2915
2916(defvar gdb-breakpoints-mode-map
2917 (let ((map (make-sparse-keymap))
2918 (menu (make-sparse-keymap "Breakpoints")))
2919 (define-key menu [quit] '("Quit" . gdb-delete-frame-or-window))
2920 (define-key menu [goto] '("Goto" . gdb-goto-breakpoint))
2921 (define-key menu [delete] '("Delete" . gdb-delete-breakpoint))
2922 (define-key menu [toggle] '("Toggle" . gdb-toggle-breakpoint))
2923 (suppress-keymap map)
2924 (define-key map [menu-bar breakpoints] (cons "Breakpoints" menu))
2925 (define-key map " " 'gdb-toggle-breakpoint)
2926 (define-key map "D" 'gdb-delete-breakpoint)
2927 ;; Don't bind "q" to kill-this-buffer as we need it for breakpoint icons.
2928 (define-key map "q" 'gdb-delete-frame-or-window)
2929 (define-key map "\r" 'gdb-goto-breakpoint)
4f91a816 2930 (define-key map "\t" (lambda ()
3db614b0
SM
2931 (interactive)
2932 (gdb-set-window-buffer
2933 (gdb-get-buffer-create 'gdb-threads-buffer) t)))
691cf4a0
NR
2934 (define-key map [mouse-2] 'gdb-goto-breakpoint)
2935 (define-key map [follow-link] 'mouse-face)
2936 map))
2937
2938(defun gdb-delete-frame-or-window ()
2939 "Delete frame if there is only one window. Otherwise delete the window."
2940 (interactive)
2941 (if (one-window-p) (delete-frame)
2942 (delete-window)))
2943
2944;;from make-mode-line-mouse-map
2945(defun gdb-make-header-line-mouse-map (mouse function) "\
2946Return a keymap with single entry for mouse key MOUSE on the header line.
2947MOUSE is defined to run function FUNCTION with no args in the buffer
2948corresponding to the mode line clicked."
2949 (let ((map (make-sparse-keymap)))
2950 (define-key map (vector 'header-line mouse) function)
2951 (define-key map (vector 'header-line 'down-mouse-1) 'ignore)
2952 map))
2953
2954(defmacro gdb-propertize-header (name buffer help-echo mouse-face face)
2955 `(propertize ,name
2956 'help-echo ,help-echo
2957 'mouse-face ',mouse-face
2958 'face ',face
2959 'local-map
2960 (gdb-make-header-line-mouse-map
2961 'mouse-1
2962 (lambda (event) (interactive "e")
2963 (save-selected-window
2964 (select-window (posn-window (event-start event)))
2965 (gdb-set-window-buffer
2966 (gdb-get-buffer-create ',buffer) t) )))))
2967
2968\f
2969;; uses "-thread-info". Needs GDB 7.0 onwards.
2970;;; Threads view
2971
2972(defun gdb-threads-buffer-name ()
2973 (concat "*threads of " (gdb-get-target-string) "*"))
2974
d97af5a0
CY
2975(defun gdb-display-threads-buffer (&optional thread)
2976 "Display GDB threads."
2977 (interactive)
2978 (gdb-display-buffer (gdb-get-buffer-create 'gdb-threads-buffer thread)))
691cf4a0 2979
d97af5a0
CY
2980(defun gdb-frame-threads-buffer (&optional thread)
2981 "Display GDB threads in another frame."
2982 (interactive)
2983 (display-buffer (gdb-get-buffer-create 'gdb-threads-buffer thread)
2984 gdb-display-buffer-other-frame-action))
691cf4a0
NR
2985
2986(def-gdb-trigger-and-handler
2987 gdb-invalidate-threads (gdb-current-context-command "-thread-info")
2988 gdb-thread-list-handler gdb-thread-list-handler-custom
2989 '(start update update-threads))
2990
2991(gdb-set-buffer-rules
2992 'gdb-threads-buffer
2993 'gdb-threads-buffer-name
2994 'gdb-threads-mode
2995 'gdb-invalidate-threads)
2996
2997(defvar gdb-threads-font-lock-keywords
2998 '(("in \\([^ ]+\\)" (1 font-lock-function-name-face))
2999 (" \\(stopped\\)" (1 font-lock-warning-face))
3000 (" \\(running\\)" (1 font-lock-string-face))
3001 ("\\(\\(\\sw\\|[_.]\\)+\\)=" (1 font-lock-variable-name-face)))
3002 "Font lock keywords used in `gdb-threads-mode'.")
3003
3004(defvar gdb-threads-mode-map
3005 (let ((map (make-sparse-keymap)))
3006 (define-key map "\r" 'gdb-select-thread)
3007 (define-key map "f" 'gdb-display-stack-for-thread)
3008 (define-key map "F" 'gdb-frame-stack-for-thread)
3009 (define-key map "l" 'gdb-display-locals-for-thread)
3010 (define-key map "L" 'gdb-frame-locals-for-thread)
3011 (define-key map "r" 'gdb-display-registers-for-thread)
3012 (define-key map "R" 'gdb-frame-registers-for-thread)
3013 (define-key map "d" 'gdb-display-disassembly-for-thread)
3014 (define-key map "D" 'gdb-frame-disassembly-for-thread)
3015 (define-key map "i" 'gdb-interrupt-thread)
3016 (define-key map "c" 'gdb-continue-thread)
3017 (define-key map "s" 'gdb-step-thread)
3db614b0
SM
3018 (define-key map "\t"
3019 (lambda ()
3020 (interactive)
3021 (gdb-set-window-buffer
3022 (gdb-get-buffer-create 'gdb-breakpoints-buffer) t)))
691cf4a0
NR
3023 (define-key map [mouse-2] 'gdb-select-thread)
3024 (define-key map [follow-link] 'mouse-face)
3025 map))
3026
3027(defvar gdb-threads-header
3028 (list
3db614b0
SM
3029 (gdb-propertize-header
3030 "Breakpoints" gdb-breakpoints-buffer
3031 "mouse-1: select" mode-line-highlight mode-line-inactive)
691cf4a0
NR
3032 " "
3033 (gdb-propertize-header "Threads" gdb-threads-buffer
3034 nil nil mode-line)))
3035
3036(define-derived-mode gdb-threads-mode gdb-parent-mode "Threads"
175069ef 3037 "Major mode for GDB threads."
691cf4a0
NR
3038 (setq gdb-thread-position (make-marker))
3039 (add-to-list 'overlay-arrow-variable-list 'gdb-thread-position)
3040 (setq header-line-format gdb-threads-header)
3041 (set (make-local-variable 'font-lock-defaults)
3042 '(gdb-threads-font-lock-keywords))
691cf4a0
NR
3043 'gdb-invalidate-threads)
3044
3045(defun gdb-thread-list-handler-custom ()
3046 (let ((threads-list (bindat-get-field (gdb-json-partial-output) 'threads))
3047 (table (make-gdb-table))
3048 (marked-line nil))
3049 (setq gdb-threads-list nil)
3050 (setq gdb-running-threads-count 0)
3051 (setq gdb-stopped-threads-count 0)
3052 (set-marker gdb-thread-position nil)
3053
3054 (dolist (thread (reverse threads-list))
3db614b0
SM
3055 (let ((running (equal (bindat-get-field thread 'state) "running")))
3056 (add-to-list 'gdb-threads-list
3057 (cons (bindat-get-field thread 'id)
3058 thread))
a464a6c7
SM
3059 (cl-incf (if running
3060 gdb-running-threads-count
3061 gdb-stopped-threads-count))
3db614b0 3062
6ff2c8f1
JPG
3063 (gdb-table-add-row
3064 table
3065 (list
3066 (bindat-get-field thread 'id)
3067 (concat
3068 (if gdb-thread-buffer-verbose-names
3069 (concat (bindat-get-field thread 'target-id) " ") "")
3070 (bindat-get-field thread 'state)
3071 ;; Include frame information for stopped threads
3072 (if (not running)
3073 (concat
3074 " in " (bindat-get-field thread 'frame 'func)
3075 (if gdb-thread-buffer-arguments
3076 (concat
3077 " ("
3078 (let ((args (bindat-get-field thread 'frame 'args)))
3079 (mapconcat
3080 (lambda (arg)
3081 (apply #'format "%s=%s"
3082 (gdb-get-many-fields arg 'name 'value)))
3083 args ","))
3084 ")")
3085 "")
3086 (if gdb-thread-buffer-locations
3087 (gdb-frame-location (bindat-get-field thread 'frame)) "")
3088 (if gdb-thread-buffer-addresses
3089 (concat " at " (bindat-get-field thread 'frame 'addr)) ""))
3090 "")))
3091 (list
3092 'gdb-thread thread
3093 'mouse-face 'highlight
3094 'help-echo "mouse-2, RET: select thread")))
691cf4a0
NR
3095 (when (string-equal gdb-thread-number
3096 (bindat-get-field thread 'id))
3097 (setq marked-line (length gdb-threads-list))))
3098 (insert (gdb-table-string table " "))
3099 (when marked-line
3100 (gdb-mark-line marked-line gdb-thread-position)))
3101 ;; We update gud-running here because we need to make sure that
3102 ;; gdb-threads-list is up-to-date
3103 (gdb-update-gud-running)
3104 (gdb-emit-signal gdb-buf-publisher 'update-disassembly))
3105
3106(defmacro def-gdb-thread-buffer-command (name custom-defun &optional doc)
3107 "Define a NAME command which will act upon thread on the current line.
3108
3109CUSTOM-DEFUN may use locally bound `thread' variable, which will
6ff2c8f1
JPG
3110be the value of 'gdb-thread property of the current line.
3111If `gdb-thread' is nil, error is signaled."
691cf4a0
NR
3112 `(defun ,name (&optional event)
3113 ,(when doc doc)
3114 (interactive (list last-input-event))
3115 (if event (posn-set-point (event-end event)))
3116 (save-excursion
3117 (beginning-of-line)
3118 (let ((thread (get-text-property (point) 'gdb-thread)))
3119 (if thread
3120 ,custom-defun
3121 (error "Not recognized as thread line"))))))
3122
3db614b0
SM
3123(defmacro def-gdb-thread-buffer-simple-command (name buffer-command
3124 &optional doc)
691cf4a0
NR
3125 "Define a NAME which will call BUFFER-COMMAND with id of thread
3126on the current line."
3127 `(def-gdb-thread-buffer-command ,name
3128 (,buffer-command (bindat-get-field thread 'id))
3129 ,doc))
3130
3131(def-gdb-thread-buffer-command gdb-select-thread
3132 (let ((new-id (bindat-get-field thread 'id)))
3133 (gdb-setq-thread-number new-id)
2170cb53 3134 (gdb-input (concat "-thread-select " new-id) 'ignore)
691cf4a0
NR
3135 (gdb-update))
3136 "Select the thread at current line of threads buffer.")
3137
3138(def-gdb-thread-buffer-simple-command
3139 gdb-display-stack-for-thread
3140 gdb-preemptively-display-stack-buffer
3141 "Display stack buffer for the thread at current line.")
3142
3143(def-gdb-thread-buffer-simple-command
3144 gdb-display-locals-for-thread
3145 gdb-preemptively-display-locals-buffer
3146 "Display locals buffer for the thread at current line.")
3147
3148(def-gdb-thread-buffer-simple-command
3149 gdb-display-registers-for-thread
3150 gdb-preemptively-display-registers-buffer
3151 "Display registers buffer for the thread at current line.")
3152
3153(def-gdb-thread-buffer-simple-command
3154 gdb-display-disassembly-for-thread
3155 gdb-preemptively-display-disassembly-buffer
3156 "Display disassembly buffer for the thread at current line.")
3157
3158(def-gdb-thread-buffer-simple-command
3159 gdb-frame-stack-for-thread
3160 gdb-frame-stack-buffer
d97af5a0 3161 "Display another frame with stack buffer for thread at current line.")
691cf4a0
NR
3162
3163(def-gdb-thread-buffer-simple-command
3164 gdb-frame-locals-for-thread
3165 gdb-frame-locals-buffer
d97af5a0 3166 "Display another frame with locals buffer for thread at current line.")
691cf4a0
NR
3167
3168(def-gdb-thread-buffer-simple-command
3169 gdb-frame-registers-for-thread
3170 gdb-frame-registers-buffer
d97af5a0 3171 "Display another frame with registers buffer for the thread at current line.")
691cf4a0
NR
3172
3173(def-gdb-thread-buffer-simple-command
3174 gdb-frame-disassembly-for-thread
3175 gdb-frame-disassembly-buffer
d97af5a0 3176 "Display another frame with disassembly buffer for the thread at current line.")
691cf4a0
NR
3177
3178(defmacro def-gdb-thread-buffer-gud-command (name gud-command &optional doc)
3179 "Define a NAME which will execute GUD-COMMAND with
3180`gdb-thread-number' locally bound to id of thread on the current
3181line."
3182 `(def-gdb-thread-buffer-command ,name
3183 (if gdb-non-stop
3184 (let ((gdb-thread-number (bindat-get-field thread 'id))
3185 (gdb-gud-control-all-threads nil))
3186 (call-interactively #',gud-command))
3187 (error "Available in non-stop mode only, customize `gdb-non-stop-setting'"))
3188 ,doc))
3189
3190(def-gdb-thread-buffer-gud-command
3191 gdb-interrupt-thread
3192 gud-stop-subjob
3193 "Interrupt thread at current line.")
3194
3195(def-gdb-thread-buffer-gud-command
3196 gdb-continue-thread
3197 gud-cont
3198 "Continue thread at current line.")
3199
3200(def-gdb-thread-buffer-gud-command
3201 gdb-step-thread
3202 gud-step
3203 "Step thread at current line.")
3204
3205\f
3206;;; Memory view
3207
3208(defcustom gdb-memory-rows 8
3209 "Number of data rows in memory window."
3210 :type 'integer
3211 :group 'gud
3212 :version "23.2")
3213
3214(defcustom gdb-memory-columns 4
3215 "Number of data columns in memory window."
3216 :type 'integer
3217 :group 'gud
3218 :version "23.2")
3219
3220(defcustom gdb-memory-format "x"
3221 "Display format of data items in memory window."
3222 :type '(choice (const :tag "Hexadecimal" "x")
3db614b0
SM
3223 (const :tag "Signed decimal" "d")
3224 (const :tag "Unsigned decimal" "u")
3225 (const :tag "Octal" "o")
3226 (const :tag "Binary" "t"))
691cf4a0
NR
3227 :group 'gud
3228 :version "22.1")
3229
3230(defcustom gdb-memory-unit 4
3231 "Unit size of data items in memory window."
3232 :type '(choice (const :tag "Byte" 1)
3db614b0
SM
3233 (const :tag "Halfword" 2)
3234 (const :tag "Word" 4)
3235 (const :tag "Giant word" 8))
691cf4a0
NR
3236 :group 'gud
3237 :version "23.2")
3238
3239(def-gdb-trigger-and-handler
3240 gdb-invalidate-memory
3241 (format "-data-read-memory %s %s %d %d %d"
3242 gdb-memory-address
3243 gdb-memory-format
3244 gdb-memory-unit
3245 gdb-memory-rows
3246 gdb-memory-columns)
3247 gdb-read-memory-handler
3248 gdb-read-memory-custom
3249 '(start update))
3250
3251(gdb-set-buffer-rules
3252 'gdb-memory-buffer
3253 'gdb-memory-buffer-name
3254 'gdb-memory-mode
3255 'gdb-invalidate-memory)
3256
3257(defun gdb-memory-column-width (size format)
3258 "Return length of string with memory unit of SIZE in FORMAT.
3259
6ff2c8f1 3260SIZE is in bytes, as in `gdb-memory-unit'. FORMAT is a string as
691cf4a0
NR
3261in `gdb-memory-format'."
3262 (let ((format-base (cdr (assoc format
3263 '(("x" . 16)
3264 ("d" . 10) ("u" . 10)
3265 ("o" . 8)
3266 ("t" . 2))))))
3267 (if format-base
3268 (let ((res (ceiling (log (expt 2.0 (* size 8)) format-base))))
3269 (cond ((string-equal format "x")
3270 (+ 2 res)) ; hexadecimal numbers have 0x in front
3271 ((or (string-equal format "d")
3272 (string-equal format "o"))
3273 (1+ res))
3274 (t res)))
3275 (error "Unknown format"))))
3276
3277(defun gdb-read-memory-custom ()
3278 (let* ((res (gdb-json-partial-output))
3279 (err-msg (bindat-get-field res 'msg)))
3280 (if (not err-msg)
3281 (let ((memory (bindat-get-field res 'memory)))
3282 (setq gdb-memory-address (bindat-get-field res 'addr))
3283 (setq gdb-memory-next-page (bindat-get-field res 'next-page))
3284 (setq gdb-memory-prev-page (bindat-get-field res 'prev-page))
3285 (setq gdb-memory-last-address gdb-memory-address)
3db614b0
SM
3286 (dolist (row memory)
3287 (insert (concat (bindat-get-field row 'addr) ":"))
3288 (dolist (column (bindat-get-field row 'data))
3289 (insert (gdb-pad-string column
3290 (+ 2 (gdb-memory-column-width
3291 gdb-memory-unit
3292 gdb-memory-format)))))
3293 (newline)))
691cf4a0
NR
3294 ;; Show last page instead of empty buffer when out of bounds
3295 (progn
3296 (let ((gdb-memory-address gdb-memory-last-address))
3297 (gdb-invalidate-memory 'update)
3298 (error err-msg))))))
3299
3300(defvar gdb-memory-mode-map
3301 (let ((map (make-sparse-keymap)))
3302 (suppress-keymap map t)
3303 (define-key map "q" 'kill-this-buffer)
3304 (define-key map "n" 'gdb-memory-show-next-page)
3305 (define-key map "p" 'gdb-memory-show-previous-page)
3306 (define-key map "a" 'gdb-memory-set-address)
3307 (define-key map "t" 'gdb-memory-format-binary)
3308 (define-key map "o" 'gdb-memory-format-octal)
3309 (define-key map "u" 'gdb-memory-format-unsigned)
3310 (define-key map "d" 'gdb-memory-format-signed)
3311 (define-key map "x" 'gdb-memory-format-hexadecimal)
3312 (define-key map "b" 'gdb-memory-unit-byte)
3313 (define-key map "h" 'gdb-memory-unit-halfword)
3314 (define-key map "w" 'gdb-memory-unit-word)
3315 (define-key map "g" 'gdb-memory-unit-giant)
3316 (define-key map "R" 'gdb-memory-set-rows)
3317 (define-key map "C" 'gdb-memory-set-columns)
3db614b0 3318 map))
691cf4a0
NR
3319
3320(defun gdb-memory-set-address-event (event)
3321 "Handle a click on address field in memory buffer header."
3322 (interactive "e")
3323 (save-selected-window
3324 (select-window (posn-window (event-start event)))
3325 (gdb-memory-set-address)))
3326
3327;; Non-event version for use within keymap
3328(defun gdb-memory-set-address ()
3329 "Set the start memory address."
3330 (interactive)
3331 (let ((arg (read-from-minibuffer "Memory address: ")))
3332 (setq gdb-memory-address arg))
3333 (gdb-invalidate-memory 'update))
3334
3335(defmacro def-gdb-set-positive-number (name variable echo-string &optional doc)
3336 "Define a function NAME which reads new VAR value from minibuffer."
3337 `(defun ,name (event)
3338 ,(when doc doc)
3339 (interactive "e")
3340 (save-selected-window
3341 (select-window (posn-window (event-start event)))
3342 (let* ((arg (read-from-minibuffer ,echo-string))
3343 (count (string-to-number arg)))
3344 (if (<= count 0)
3345 (error "Positive number only")
3346 (customize-set-variable ',variable count)
3347 (gdb-invalidate-memory 'update))))))
3348
3349(def-gdb-set-positive-number
3350 gdb-memory-set-rows
3351 gdb-memory-rows
3352 "Rows: "
3353 "Set the number of data rows in memory window.")
3354
3355(def-gdb-set-positive-number
3356 gdb-memory-set-columns
3357 gdb-memory-columns
3358 "Columns: "
3359 "Set the number of data columns in memory window.")
3360
3361(defmacro def-gdb-memory-format (name format doc)
3362 "Define a function NAME to switch memory buffer to use FORMAT.
3363
3364DOC is an optional documentation string."
3365 `(defun ,name () ,(when doc doc)
3366 (interactive)
3367 (customize-set-variable 'gdb-memory-format ,format)
3368 (gdb-invalidate-memory 'update)))
3369
3370(def-gdb-memory-format
3371 gdb-memory-format-binary "t"
3372 "Set the display format to binary.")
3373
3374(def-gdb-memory-format
3375 gdb-memory-format-octal "o"
3376 "Set the display format to octal.")
3377
3378(def-gdb-memory-format
3379 gdb-memory-format-unsigned "u"
3380 "Set the display format to unsigned decimal.")
3381
3382(def-gdb-memory-format
3383 gdb-memory-format-signed "d"
3384 "Set the display format to decimal.")
3385
3386(def-gdb-memory-format
3387 gdb-memory-format-hexadecimal "x"
3388 "Set the display format to hexadecimal.")
3389
3390(defvar gdb-memory-format-map
3391 (let ((map (make-sparse-keymap)))
3392 (define-key map [header-line down-mouse-3] 'gdb-memory-format-menu-1)
3393 map)
3394 "Keymap to select format in the header line.")
3395
b016851c
SM
3396(defvar gdb-memory-format-menu
3397 (let ((map (make-sparse-keymap "Format")))
3398
3399 (define-key map [binary]
3400 '(menu-item "Binary" gdb-memory-format-binary
3401 :button (:radio . (equal gdb-memory-format "t"))))
3402 (define-key map [octal]
3403 '(menu-item "Octal" gdb-memory-format-octal
3404 :button (:radio . (equal gdb-memory-format "o"))))
3405 (define-key map [unsigned]
3406 '(menu-item "Unsigned Decimal" gdb-memory-format-unsigned
3407 :button (:radio . (equal gdb-memory-format "u"))))
3408 (define-key map [signed]
3409 '(menu-item "Signed Decimal" gdb-memory-format-signed
3410 :button (:radio . (equal gdb-memory-format "d"))))
3411 (define-key map [hexadecimal]
3412 '(menu-item "Hexadecimal" gdb-memory-format-hexadecimal
3413 :button (:radio . (equal gdb-memory-format "x"))))
3414 map)
691cf4a0
NR
3415 "Menu of display formats in the header line.")
3416
691cf4a0
NR
3417(defun gdb-memory-format-menu (event)
3418 (interactive "@e")
3419 (x-popup-menu event gdb-memory-format-menu))
3420
3421(defun gdb-memory-format-menu-1 (event)
3422 (interactive "e")
3423 (save-selected-window
3424 (select-window (posn-window (event-start event)))
3425 (let* ((selection (gdb-memory-format-menu event))
3426 (binding (and selection (lookup-key gdb-memory-format-menu
3427 (vector (car selection))))))
3428 (if binding (call-interactively binding)))))
3429
3430(defmacro def-gdb-memory-unit (name unit-size doc)
3431 "Define a function NAME to switch memory unit size to UNIT-SIZE.
3432
3433DOC is an optional documentation string."
3434 `(defun ,name () ,(when doc doc)
3435 (interactive)
3436 (customize-set-variable 'gdb-memory-unit ,unit-size)
3437 (gdb-invalidate-memory 'update)))
3438
3439(def-gdb-memory-unit gdb-memory-unit-giant 8
3440 "Set the unit size to giant words (eight bytes).")
3441
3442(def-gdb-memory-unit gdb-memory-unit-word 4
3443 "Set the unit size to words (four bytes).")
3444
3445(def-gdb-memory-unit gdb-memory-unit-halfword 2
3446 "Set the unit size to halfwords (two bytes).")
3447
3448(def-gdb-memory-unit gdb-memory-unit-byte 1
3449 "Set the unit size to bytes.")
3450
3451(defmacro def-gdb-memory-show-page (name address-var &optional doc)
3452 "Define a function NAME which show new address in memory buffer.
3453
3454The defined function switches Memory buffer to show address
3455stored in ADDRESS-VAR variable.
3456
3457DOC is an optional documentation string."
3458 `(defun ,name
3459 ,(when doc doc)
3460 (interactive)
3461 (let ((gdb-memory-address ,address-var))
3462 (gdb-invalidate-memory))))
3463
3464(def-gdb-memory-show-page gdb-memory-show-previous-page
3465 gdb-memory-prev-page)
3466
3467(def-gdb-memory-show-page gdb-memory-show-next-page
3468 gdb-memory-next-page)
3469
3470(defvar gdb-memory-unit-map
3471 (let ((map (make-sparse-keymap)))
3472 (define-key map [header-line down-mouse-3] 'gdb-memory-unit-menu-1)
3473 map)
3474 "Keymap to select units in the header line.")
3475
b016851c
SM
3476(defvar gdb-memory-unit-menu
3477 (let ((map (make-sparse-keymap "Unit")))
3478 (define-key map [giantwords]
3479 '(menu-item "Giant words" gdb-memory-unit-giant
3480 :button (:radio . (equal gdb-memory-unit 8))))
3481 (define-key map [words]
3482 '(menu-item "Words" gdb-memory-unit-word
3483 :button (:radio . (equal gdb-memory-unit 4))))
3484 (define-key map [halfwords]
3485 '(menu-item "Halfwords" gdb-memory-unit-halfword
3486 :button (:radio . (equal gdb-memory-unit 2))))
3487 (define-key map [bytes]
3488 '(menu-item "Bytes" gdb-memory-unit-byte
3489 :button (:radio . (equal gdb-memory-unit 1))))
3490 map)
691cf4a0
NR
3491 "Menu of units in the header line.")
3492
691cf4a0
NR
3493(defun gdb-memory-unit-menu (event)
3494 (interactive "@e")
3495 (x-popup-menu event gdb-memory-unit-menu))
3496
3497(defun gdb-memory-unit-menu-1 (event)
3498 (interactive "e")
3499 (save-selected-window
3500 (select-window (posn-window (event-start event)))
3501 (let* ((selection (gdb-memory-unit-menu event))
3502 (binding (and selection (lookup-key gdb-memory-unit-menu
3503 (vector (car selection))))))
3504 (if binding (call-interactively binding)))))
3505
3506(defvar gdb-memory-font-lock-keywords
3507 '(;; <__function.name+n>
3db614b0
SM
3508 ("<\\(\\(\\sw\\|[_.]\\)+\\)\\(\\+[0-9]+\\)?>"
3509 (1 font-lock-function-name-face)))
691cf4a0
NR
3510 "Font lock keywords used in `gdb-memory-mode'.")
3511
3512(defvar gdb-memory-header
3513 '(:eval
3514 (concat
3515 "Start address["
3516 (propertize "-"
3db614b0
SM
3517 'face font-lock-warning-face
3518 'help-echo "mouse-1: decrement address"
3519 'mouse-face 'mode-line-highlight
3520 'local-map (gdb-make-header-line-mouse-map
3521 'mouse-1
3522 #'gdb-memory-show-previous-page))
691cf4a0
NR
3523 "|"
3524 (propertize "+"
3db614b0
SM
3525 'face font-lock-warning-face
3526 'help-echo "mouse-1: increment address"
691cf4a0
NR
3527 'mouse-face 'mode-line-highlight
3528 'local-map (gdb-make-header-line-mouse-map
3529 'mouse-1
3530 #'gdb-memory-show-next-page))
3db614b0
SM
3531 "]: "
3532 (propertize gdb-memory-address
691cf4a0
NR
3533 'face font-lock-warning-face
3534 'help-echo "mouse-1: set start address"
3535 'mouse-face 'mode-line-highlight
3536 'local-map (gdb-make-header-line-mouse-map
3537 'mouse-1
3538 #'gdb-memory-set-address-event))
3db614b0
SM
3539 " Rows: "
3540 (propertize (number-to-string gdb-memory-rows)
691cf4a0
NR
3541 'face font-lock-warning-face
3542 'help-echo "mouse-1: set number of columns"
3543 'mouse-face 'mode-line-highlight
3544 'local-map (gdb-make-header-line-mouse-map
3545 'mouse-1
3546 #'gdb-memory-set-rows))
3db614b0
SM
3547 " Columns: "
3548 (propertize (number-to-string gdb-memory-columns)
691cf4a0
NR
3549 'face font-lock-warning-face
3550 'help-echo "mouse-1: set number of columns"
3551 'mouse-face 'mode-line-highlight
3552 'local-map (gdb-make-header-line-mouse-map
3553 'mouse-1
3554 #'gdb-memory-set-columns))
3db614b0
SM
3555 " Display Format: "
3556 (propertize gdb-memory-format
691cf4a0
NR
3557 'face font-lock-warning-face
3558 'help-echo "mouse-3: select display format"
3559 'mouse-face 'mode-line-highlight
3560 'local-map gdb-memory-format-map)
3db614b0
SM
3561 " Unit Size: "
3562 (propertize (number-to-string gdb-memory-unit)
691cf4a0
NR
3563 'face font-lock-warning-face
3564 'help-echo "mouse-3: select unit size"
3565 'mouse-face 'mode-line-highlight
3566 'local-map gdb-memory-unit-map)))
3567 "Header line used in `gdb-memory-mode'.")
3568
3569(define-derived-mode gdb-memory-mode gdb-parent-mode "Memory"
175069ef 3570 "Major mode for examining memory."
691cf4a0
NR
3571 (setq header-line-format gdb-memory-header)
3572 (set (make-local-variable 'font-lock-defaults)
3573 '(gdb-memory-font-lock-keywords))
691cf4a0
NR
3574 'gdb-invalidate-memory)
3575
3576(defun gdb-memory-buffer-name ()
3577 (concat "*memory of " (gdb-get-target-string) "*"))
3578
d97af5a0
CY
3579(defun gdb-display-memory-buffer (&optional thread)
3580 "Display GDB memory contents."
3581 (interactive)
3582 (gdb-display-buffer (gdb-get-buffer-create 'gdb-memory-buffer thread)))
691cf4a0
NR
3583
3584(defun gdb-frame-memory-buffer ()
d97af5a0 3585 "Display memory contents in another frame."
691cf4a0 3586 (interactive)
d97af5a0
CY
3587 (display-buffer (gdb-get-buffer-create 'gdb-memory-buffer)
3588 gdb-display-buffer-other-frame-action))
691cf4a0
NR
3589
3590\f
3591;;; Disassembly view
3592
3593(defun gdb-disassembly-buffer-name ()
3594 (gdb-current-context-buffer-name
3595 (concat "disassembly of " (gdb-get-target-string))))
3596
d97af5a0
CY
3597(defun gdb-display-disassembly-buffer (&optional thread)
3598 "Display GDB disassembly information."
3599 (interactive)
3600 (gdb-display-buffer (gdb-get-buffer-create 'gdb-disassembly-buffer thread)))
691cf4a0
NR
3601
3602(def-gdb-preempt-display-buffer
3603 gdb-preemptively-display-disassembly-buffer
3604 'gdb-disassembly-buffer)
3605
d97af5a0
CY
3606(defun gdb-frame-disassembly-buffer (&optional thread)
3607 "Display GDB disassembly information in another frame."
3608 (interactive)
3609 (display-buffer (gdb-get-buffer-create 'gdb-disassembly-buffer thread)
3610 gdb-display-buffer-other-frame-action))
691cf4a0
NR
3611
3612(def-gdb-auto-update-trigger gdb-invalidate-disassembly
3613 (let* ((frame (gdb-current-buffer-frame))
3614 (file (bindat-get-field frame 'fullname))
3615 (line (bindat-get-field frame 'line)))
4a07df36
KS
3616 (if file
3617 (format "-data-disassemble -f %s -l %s -n -1 -- 0" file line)
3618 ;; If we're unable to get a file name / line for $PC, simply
3619 ;; follow $PC, disassembling the next 10 (x ~15 (on IA) ==
3620 ;; 150 bytes) instructions.
3621 "-data-disassemble -s $pc -e \"$pc + 150\" -- 0"))
691cf4a0
NR
3622 gdb-disassembly-handler
3623 ;; We update disassembly only after we have actual frame information
3624 ;; about all threads, so no there's `update' signal in this list
3625 '(start update-disassembly))
3626
3627(def-gdb-auto-update-handler
3628 gdb-disassembly-handler
3629 gdb-invalidate-disassembly
3630 gdb-disassembly-handler-custom
3631 t)
3632
3633(gdb-set-buffer-rules
3634 'gdb-disassembly-buffer
3635 'gdb-disassembly-buffer-name
3636 'gdb-disassembly-mode
3637 'gdb-invalidate-disassembly)
3638
3639(defvar gdb-disassembly-font-lock-keywords
3640 '(;; <__function.name+n>
3641 ("<\\(\\(\\sw\\|[_.]\\)+\\)\\(\\+[0-9]+\\)?>"
3642 (1 font-lock-function-name-face))
3643 ;; 0xNNNNNNNN <__function.name+n>: opcode
3644 ("^0x[0-9a-f]+ \\(<\\(\\(\\sw\\|[_.]\\)+\\)\\+[0-9]+>\\)?:[ \t]+\\(\\sw+\\)"
3645 (4 font-lock-keyword-face))
3646 ;; %register(at least i386)
3647 ("%\\sw+" . font-lock-variable-name-face)
3648 ("^\\(Dump of assembler code for function\\) \\(.+\\):"
3649 (1 font-lock-comment-face)
3650 (2 font-lock-function-name-face))
3651 ("^\\(End of assembler dump\\.\\)" . font-lock-comment-face))
3652 "Font lock keywords used in `gdb-disassembly-mode'.")
3653
3654(defvar gdb-disassembly-mode-map
3655 ;; TODO
3656 (let ((map (make-sparse-keymap)))
3657 (suppress-keymap map)
3658 (define-key map "q" 'kill-this-buffer)
3db614b0 3659 map))
691cf4a0
NR
3660
3661(define-derived-mode gdb-disassembly-mode gdb-parent-mode "Disassembly"
175069ef 3662 "Major mode for GDB disassembly information."
691cf4a0
NR
3663 ;; TODO Rename overlay variable for disassembly mode
3664 (add-to-list 'overlay-arrow-variable-list 'gdb-disassembly-position)
3665 (setq fringes-outside-margins t)
3666 (set (make-local-variable 'gdb-disassembly-position) (make-marker))
3667 (set (make-local-variable 'font-lock-defaults)
3668 '(gdb-disassembly-font-lock-keywords))
691cf4a0
NR
3669 'gdb-invalidate-disassembly)
3670
3671(defun gdb-disassembly-handler-custom ()
3672 (let* ((instructions (bindat-get-field (gdb-json-partial-output) 'asm_insns))
3673 (address (bindat-get-field (gdb-current-buffer-frame) 'addr))
691cf4a0
NR
3674 (table (make-gdb-table))
3675 (marked-line nil))
3db614b0 3676 (dolist (instr instructions)
691cf4a0 3677 (gdb-table-add-row table
3db614b0
SM
3678 (list
3679 (bindat-get-field instr 'address)
4a07df36
KS
3680 (let
3681 ((func-name (bindat-get-field instr 'func-name))
3682 (offset (bindat-get-field instr 'offset)))
3683 (if func-name
3684 (format "<%s+%s>:" func-name offset)
3685 ""))
3db614b0 3686 (bindat-get-field instr 'inst)))
691cf4a0
NR
3687 (when (string-equal (bindat-get-field instr 'address)
3688 address)
3689 (progn
3690 (setq marked-line (length (gdb-table-rows table)))
3691 (setq fringe-indicator-alist
3692 (if (string-equal gdb-frame-number "0")
3693 nil
3694 '((overlay-arrow . hollow-right-triangle)))))))
3db614b0
SM
3695 (insert (gdb-table-string table " "))
3696 (gdb-disassembly-place-breakpoints)
3697 ;; Mark current position with overlay arrow and scroll window to
3698 ;; that point
3699 (when marked-line
3700 (let ((window (get-buffer-window (current-buffer) 0)))
3701 (set-window-point window (gdb-mark-line marked-line
3702 gdb-disassembly-position))))
3703 (setq mode-name
3704 (gdb-current-context-mode-name
3705 (concat "Disassembly: "
3706 (bindat-get-field (gdb-current-buffer-frame) 'func))))))
691cf4a0
NR
3707
3708(defun gdb-disassembly-place-breakpoints ()
3709 (gdb-remove-breakpoint-icons (point-min) (point-max))
3710 (dolist (breakpoint gdb-breakpoints-list)
3711 (let* ((breakpoint (cdr breakpoint))
3712 (bptno (bindat-get-field breakpoint 'number))
3713 (flag (bindat-get-field breakpoint 'enabled))
3714 (address (bindat-get-field breakpoint 'addr)))
3715 (save-excursion
3716 (goto-char (point-min))
3717 (if (re-search-forward (concat "^" address) nil t)
3718 (gdb-put-breakpoint-icon (string-equal flag "y") bptno))))))
3719
3720\f
3721(defvar gdb-breakpoints-header
3722 (list
3723 (gdb-propertize-header "Breakpoints" gdb-breakpoints-buffer
3724 nil nil mode-line)
3725 " "
3726 (gdb-propertize-header "Threads" gdb-threads-buffer
3db614b0
SM
3727 "mouse-1: select" mode-line-highlight
3728 mode-line-inactive)))
691cf4a0
NR
3729
3730;;; Breakpoints view
3731(define-derived-mode gdb-breakpoints-mode gdb-parent-mode "Breakpoints"
175069ef 3732 "Major mode for gdb breakpoints."
691cf4a0 3733 (setq header-line-format gdb-breakpoints-header)
691cf4a0
NR
3734 'gdb-invalidate-breakpoints)
3735
3736(defun gdb-toggle-breakpoint ()
3737 "Enable/disable breakpoint at current line of breakpoints buffer."
3738 (interactive)
3739 (save-excursion
3740 (beginning-of-line)
3741 (let ((breakpoint (get-text-property (point) 'gdb-breakpoint)))
3742 (if breakpoint
3743 (gud-basic-call
3db614b0 3744 (concat (if (equal "y" (bindat-get-field breakpoint 'enabled))
691cf4a0
NR
3745 "-break-disable "
3746 "-break-enable ")
3747 (bindat-get-field breakpoint 'number)))
3748 (error "Not recognized as break/watchpoint line")))))
3749
3750(defun gdb-delete-breakpoint ()
3751 "Delete the breakpoint at current line of breakpoints buffer."
3752 (interactive)
3753 (save-excursion
3db614b0
SM
3754 (beginning-of-line)
3755 (let ((breakpoint (get-text-property (point) 'gdb-breakpoint)))
3756 (if breakpoint
3757 (gud-basic-call (concat "-break-delete "
3758 (bindat-get-field breakpoint 'number)))
3759 (error "Not recognized as break/watchpoint line")))))
691cf4a0
NR
3760
3761(defun gdb-goto-breakpoint (&optional event)
6ff2c8f1 3762 "Go to the location of breakpoint at current line of breakpoints buffer."
691cf4a0
NR
3763 (interactive (list last-input-event))
3764 (if event (posn-set-point (event-end event)))
3765 ;; Hack to stop gdb-goto-breakpoint displaying in GUD buffer.
3766 (let ((window (get-buffer-window gud-comint-buffer)))
3767 (if window (save-selected-window (select-window window))))
3768 (save-excursion
3db614b0
SM
3769 (beginning-of-line)
3770 (let ((breakpoint (get-text-property (point) 'gdb-breakpoint)))
3771 (if breakpoint
3772 (let ((bptno (bindat-get-field breakpoint 'number))
3773 (file (bindat-get-field breakpoint 'fullname))
3774 (line (bindat-get-field breakpoint 'line)))
3775 (save-selected-window
3776 (let* ((buffer (find-file-noselect
3777 (if (file-exists-p file) file
3778 (cdr (assoc bptno gdb-location-alist)))))
3779 (window (or (gdb-display-source-buffer buffer)
3780 (display-buffer buffer))))
3781 (setq gdb-source-window window)
3782 (with-current-buffer buffer
3783 (goto-char (point-min))
3784 (forward-line (1- (string-to-number line)))
3785 (set-window-point window (point))))))
3786 (error "Not recognized as break/watchpoint line")))))
691cf4a0
NR
3787
3788\f
91af3942 3789;; Frames buffer. This displays a perpetually correct backtrack trace.
691cf4a0
NR
3790;;
3791(def-gdb-trigger-and-handler
3792 gdb-invalidate-frames (gdb-current-context-command "-stack-list-frames")
3793 gdb-stack-list-frames-handler gdb-stack-list-frames-custom
3794 '(start update))
3795
3796(gdb-set-buffer-rules
3797 'gdb-stack-buffer
3798 'gdb-stack-buffer-name
3799 'gdb-frames-mode
3800 'gdb-invalidate-frames)
3801
3802(defun gdb-frame-location (frame)
3803 "Return \" of file:line\" or \" of library\" for structure FRAME.
3804
3805FRAME must have either \"file\" and \"line\" members or \"from\"
3806member."
3807 (let ((file (bindat-get-field frame 'file))
3808 (line (bindat-get-field frame 'line))
3809 (from (bindat-get-field frame 'from)))
3810 (let ((res (or (and file line (concat file ":" line))
3811 from)))
3812 (if res (concat " of " res) ""))))
3813
3814(defun gdb-stack-list-frames-custom ()
3815 (let ((stack (bindat-get-field (gdb-json-partial-output "frame") 'stack))
3816 (table (make-gdb-table)))
3817 (set-marker gdb-stack-position nil)
3db614b0
SM
3818 (dolist (frame stack)
3819 (gdb-table-add-row table
3820 (list
3821 (bindat-get-field frame 'level)
3822 "in"
3823 (concat
3824 (bindat-get-field frame 'func)
3825 (if gdb-stack-buffer-locations
3826 (gdb-frame-location frame) "")
3827 (if gdb-stack-buffer-addresses
3828 (concat " at " (bindat-get-field frame 'addr)) "")))
3829 `(mouse-face highlight
3830 help-echo "mouse-2, RET: Select frame"
3831 gdb-frame ,frame)))
3832 (insert (gdb-table-string table " ")))
691cf4a0
NR
3833 (when (and gdb-frame-number
3834 (gdb-buffer-shows-main-thread-p))
3835 (gdb-mark-line (1+ (string-to-number gdb-frame-number))
3836 gdb-stack-position))
3837 (setq mode-name
3838 (gdb-current-context-mode-name "Frames")))
3839
3840(defun gdb-stack-buffer-name ()
3841 (gdb-current-context-buffer-name
3842 (concat "stack frames of " (gdb-get-target-string))))
3843
d97af5a0
CY
3844(defun gdb-display-stack-buffer (&optional thread)
3845 "Display GDB backtrace for current stack."
3846 (interactive)
3847 (gdb-display-buffer (gdb-get-buffer-create 'gdb-stack-buffer thread)))
691cf4a0
NR
3848
3849(def-gdb-preempt-display-buffer
3850 gdb-preemptively-display-stack-buffer
3851 'gdb-stack-buffer nil t)
3852
d97af5a0
CY
3853(defun gdb-frame-stack-buffer (&optional thread)
3854 "Display GDB backtrace for current stack in another frame."
3855 (interactive)
3856 (display-buffer (gdb-get-buffer-create 'gdb-stack-buffer thread)
3857 gdb-display-buffer-other-frame-action))
691cf4a0
NR
3858
3859(defvar gdb-frames-mode-map
3860 (let ((map (make-sparse-keymap)))
3861 (suppress-keymap map)
3862 (define-key map "q" 'kill-this-buffer)
3863 (define-key map "\r" 'gdb-select-frame)
3864 (define-key map [mouse-2] 'gdb-select-frame)
3865 (define-key map [follow-link] 'mouse-face)
3866 map))
3867
3868(defvar gdb-frames-font-lock-keywords
3869 '(("in \\([^ ]+\\)" (1 font-lock-function-name-face)))
3870 "Font lock keywords used in `gdb-frames-mode'.")
3871
3872(define-derived-mode gdb-frames-mode gdb-parent-mode "Frames"
175069ef 3873 "Major mode for gdb call stack."
691cf4a0
NR
3874 (setq gdb-stack-position (make-marker))
3875 (add-to-list 'overlay-arrow-variable-list 'gdb-stack-position)
3876 (setq truncate-lines t) ;; Make it easier to see overlay arrow.
3877 (set (make-local-variable 'font-lock-defaults)
3878 '(gdb-frames-font-lock-keywords))
691cf4a0
NR
3879 'gdb-invalidate-frames)
3880
3881(defun gdb-select-frame (&optional event)
3882 "Select the frame and display the relevant source."
3883 (interactive (list last-input-event))
3884 (if event (posn-set-point (event-end event)))
3885 (let ((frame (get-text-property (point) 'gdb-frame)))
3886 (if frame
3887 (if (gdb-buffer-shows-main-thread-p)
3888 (let ((new-level (bindat-get-field frame 'level)))
3889 (setq gdb-frame-number new-level)
2170cb53
CY
3890 (gdb-input (concat "-stack-select-frame " new-level)
3891 'ignore)
691cf4a0
NR
3892 (gdb-update))
3893 (error "Could not select frame for non-current thread"))
3894 (error "Not recognized as frame line"))))
3895
3896\f
3897;; Locals buffer.
3898;; uses "-stack-list-locals --simple-values". Needs GDB 6.1 onwards.
3899(def-gdb-trigger-and-handler
3900 gdb-invalidate-locals
3db614b0
SM
3901 (concat (gdb-current-context-command "-stack-list-locals")
3902 " --simple-values")
691cf4a0
NR
3903 gdb-locals-handler gdb-locals-handler-custom
3904 '(start update))
3905
3906(gdb-set-buffer-rules
3907 'gdb-locals-buffer
3908 'gdb-locals-buffer-name
3909 'gdb-locals-mode
3910 'gdb-invalidate-locals)
3911
3912(defvar gdb-locals-watch-map
3913 (let ((map (make-sparse-keymap)))
3914 (suppress-keymap map)
3915 (define-key map "\r" 'gud-watch)
3916 (define-key map [mouse-2] 'gud-watch)
3917 map)
3db614b0 3918 "Keymap to create watch expression of a complex data type local variable.")
691cf4a0
NR
3919
3920(defvar gdb-edit-locals-map-1
3921 (let ((map (make-sparse-keymap)))
3922 (suppress-keymap map)
3923 (define-key map "\r" 'gdb-edit-locals-value)
3924 (define-key map [mouse-2] 'gdb-edit-locals-value)
3925 map)
3db614b0 3926 "Keymap to edit value of a simple data type local variable.")
691cf4a0
NR
3927
3928(defun gdb-edit-locals-value (&optional event)
3929 "Assign a value to a variable displayed in the locals buffer."
3930 (interactive (list last-input-event))
3931 (save-excursion
3932 (if event (posn-set-point (event-end event)))
3933 (beginning-of-line)
3934 (let* ((var (bindat-get-field
3935 (get-text-property (point) 'gdb-local-variable) 'name))
3936 (value (read-string (format "New value (%s): " var))))
3937 (gud-basic-call
3938 (concat "-gdb-set variable " var " = " value)))))
3939
fe7a3057 3940;; Don't display values of arrays or structures.
691cf4a0
NR
3941;; These can be expanded using gud-watch.
3942(defun gdb-locals-handler-custom ()
3943 (let ((locals-list (bindat-get-field (gdb-json-partial-output) 'locals))
3944 (table (make-gdb-table)))
3945 (dolist (local locals-list)
3946 (let ((name (bindat-get-field local 'name))
3947 (value (bindat-get-field local 'value))
3948 (type (bindat-get-field local 'type)))
3949 (if (or (not value)
3950 (string-match "\\0x" value))
3951 (add-text-properties 0 (length name)
3db614b0
SM
3952 `(mouse-face highlight
3953 help-echo "mouse-2: create watch expression"
3954 local-map ,gdb-locals-watch-map)
3955 name)
691cf4a0
NR
3956 (add-text-properties 0 (length value)
3957 `(mouse-face highlight
3db614b0
SM
3958 help-echo "mouse-2: edit value"
3959 local-map ,gdb-edit-locals-map-1)
691cf4a0
NR
3960 value))
3961 (gdb-table-add-row
3962 table
3963 (list
3964 (propertize type 'font-lock-face font-lock-type-face)
3965 (propertize name 'font-lock-face font-lock-variable-name-face)
3966 value)
3967 `(gdb-local-variable ,local))))
3968 (insert (gdb-table-string table " "))
3969 (setq mode-name
3970 (gdb-current-context-mode-name
3db614b0
SM
3971 (concat "Locals: "
3972 (bindat-get-field (gdb-current-buffer-frame) 'func))))))
691cf4a0
NR
3973
3974(defvar gdb-locals-header
3975 (list
3976 (gdb-propertize-header "Locals" gdb-locals-buffer
3977 nil nil mode-line)
3978 " "
3979 (gdb-propertize-header "Registers" gdb-registers-buffer
3db614b0
SM
3980 "mouse-1: select" mode-line-highlight
3981 mode-line-inactive)))
691cf4a0
NR
3982
3983(defvar gdb-locals-mode-map
3984 (let ((map (make-sparse-keymap)))
3985 (suppress-keymap map)
3986 (define-key map "q" 'kill-this-buffer)
4f91a816 3987 (define-key map "\t" (lambda ()
3db614b0
SM
3988 (interactive)
3989 (gdb-set-window-buffer
3990 (gdb-get-buffer-create
3991 'gdb-registers-buffer
3992 gdb-thread-number) t)))
3993 map))
691cf4a0
NR
3994
3995(define-derived-mode gdb-locals-mode gdb-parent-mode "Locals"
175069ef 3996 "Major mode for gdb locals."
691cf4a0 3997 (setq header-line-format gdb-locals-header)
691cf4a0
NR
3998 'gdb-invalidate-locals)
3999
4000(defun gdb-locals-buffer-name ()
4001 (gdb-current-context-buffer-name
4002 (concat "locals of " (gdb-get-target-string))))
4003
d97af5a0
CY
4004(defun gdb-display-locals-buffer (&optional thread)
4005 "Display the local variables of current GDB stack."
4006 (interactive)
4007 (gdb-display-buffer (gdb-get-buffer-create 'gdb-locals-buffer thread)))
691cf4a0
NR
4008
4009(def-gdb-preempt-display-buffer
3db614b0
SM
4010 gdb-preemptively-display-locals-buffer
4011 'gdb-locals-buffer nil t)
691cf4a0 4012
d97af5a0
CY
4013(defun gdb-frame-locals-buffer (&optional thread)
4014 "Display the local variables of the current GDB stack in another frame."
4015 (interactive)
4016 (display-buffer (gdb-get-buffer-create 'gdb-locals-buffer thread)
4017 gdb-display-buffer-other-frame-action))
691cf4a0
NR
4018
4019\f
4020;; Registers buffer.
4021
4022(def-gdb-trigger-and-handler
4023 gdb-invalidate-registers
4024 (concat (gdb-current-context-command "-data-list-register-values") " x")
4025 gdb-registers-handler
4026 gdb-registers-handler-custom
4027 '(start update))
4028
4029(gdb-set-buffer-rules
4030 'gdb-registers-buffer
4031 'gdb-registers-buffer-name
4032 'gdb-registers-mode
4033 'gdb-invalidate-registers)
4034
4035(defun gdb-registers-handler-custom ()
4036 (when gdb-register-names
3db614b0
SM
4037 (let ((register-values
4038 (bindat-get-field (gdb-json-partial-output) 'register-values))
691cf4a0
NR
4039 (table (make-gdb-table)))
4040 (dolist (register register-values)
4041 (let* ((register-number (bindat-get-field register 'number))
4042 (value (bindat-get-field register 'value))
4043 (register-name (nth (string-to-number register-number)
4044 gdb-register-names)))
4045 (gdb-table-add-row
4046 table
4047 (list
3db614b0
SM
4048 (propertize register-name
4049 'font-lock-face font-lock-variable-name-face)
691cf4a0
NR
4050 (if (member register-number gdb-changed-registers)
4051 (propertize value 'font-lock-face font-lock-warning-face)
4052 value))
4053 `(mouse-face highlight
4054 help-echo "mouse-2: edit value"
4055 gdb-register-name ,register-name))))
4056 (insert (gdb-table-string table " ")))
4057 (setq mode-name
4058 (gdb-current-context-mode-name "Registers"))))
4059
4060(defun gdb-edit-register-value (&optional event)
4061 "Assign a value to a register displayed in the registers buffer."
4062 (interactive (list last-input-event))
4063 (save-excursion
4064 (if event (posn-set-point (event-end event)))
4065 (beginning-of-line)
4066 (let* ((var (bindat-get-field
4067 (get-text-property (point) 'gdb-register-name)))
4068 (value (read-string (format "New value (%s): " var))))
4069 (gud-basic-call
4070 (concat "-gdb-set variable $" var " = " value)))))
4071
4072(defvar gdb-registers-mode-map
4073 (let ((map (make-sparse-keymap)))
4074 (suppress-keymap map)
4075 (define-key map "\r" 'gdb-edit-register-value)
4076 (define-key map [mouse-2] 'gdb-edit-register-value)
4077 (define-key map "q" 'kill-this-buffer)
4f91a816 4078 (define-key map "\t" (lambda ()
3db614b0
SM
4079 (interactive)
4080 (gdb-set-window-buffer
4081 (gdb-get-buffer-create
4082 'gdb-locals-buffer
4083 gdb-thread-number) t)))
691cf4a0
NR
4084 map))
4085
4086(defvar gdb-registers-header
4087 (list
4088 (gdb-propertize-header "Locals" gdb-locals-buffer
3db614b0
SM
4089 "mouse-1: select" mode-line-highlight
4090 mode-line-inactive)
691cf4a0
NR
4091 " "
4092 (gdb-propertize-header "Registers" gdb-registers-buffer
4093 nil nil mode-line)))
4094
4095(define-derived-mode gdb-registers-mode gdb-parent-mode "Registers"
175069ef 4096 "Major mode for gdb registers."
691cf4a0 4097 (setq header-line-format gdb-registers-header)
691cf4a0
NR
4098 'gdb-invalidate-registers)
4099
4100(defun gdb-registers-buffer-name ()
4101 (gdb-current-context-buffer-name
4102 (concat "registers of " (gdb-get-target-string))))
4103
d97af5a0
CY
4104(defun gdb-display-registers-buffer (&optional thread)
4105 "Display GDB register contents."
4106 (interactive)
4107 (gdb-display-buffer (gdb-get-buffer-create 'gdb-registers-buffer thread)))
691cf4a0
NR
4108
4109(def-gdb-preempt-display-buffer
4110 gdb-preemptively-display-registers-buffer
3db614b0 4111 'gdb-registers-buffer nil t)
691cf4a0 4112
d97af5a0
CY
4113(defun gdb-frame-registers-buffer (&optional thread)
4114 "Display GDB register contents in another frame."
4115 (interactive)
4116 (display-buffer (gdb-get-buffer-create 'gdb-registers-buffer thread)
4117 gdb-display-buffer-other-frame-action))
691cf4a0
NR
4118
4119;; Needs GDB 6.4 onwards (used to fail with no stack).
4120(defun gdb-get-changed-registers ()
2170cb53
CY
4121 (when (and (gdb-get-buffer 'gdb-registers-buffer)
4122 (not (gdb-pending-p 'gdb-get-changed-registers)))
4123 (gdb-input "-data-list-changed-registers"
4124 'gdb-changed-registers-handler)
4125 (gdb-add-pending 'gdb-get-changed-registers)))
691cf4a0
NR
4126
4127(defun gdb-changed-registers-handler ()
4128 (gdb-delete-pending 'gdb-get-changed-registers)
4129 (setq gdb-changed-registers nil)
3db614b0
SM
4130 (dolist (register-number
4131 (bindat-get-field (gdb-json-partial-output) 'changed-registers))
691cf4a0
NR
4132 (push register-number gdb-changed-registers)))
4133
4134(defun gdb-register-names-handler ()
4135 ;; Don't use gdb-pending-triggers because this handler is called
4136 ;; only once (in gdb-init-1)
4137 (setq gdb-register-names nil)
3db614b0
SM
4138 (dolist (register-name
4139 (bindat-get-field (gdb-json-partial-output) 'register-names))
691cf4a0
NR
4140 (push register-name gdb-register-names))
4141 (setq gdb-register-names (reverse gdb-register-names)))
4142\f
4143
4144(defun gdb-get-source-file-list ()
4145 "Create list of source files for current GDB session.
6ff2c8f1 4146If buffers already exist for any of these files, `gud-minor-mode'
691cf4a0
NR
4147is set in them."
4148 (goto-char (point-min))
4149 (while (re-search-forward gdb-source-file-regexp nil t)
4150 (push (match-string 1) gdb-source-file-list))
4151 (dolist (buffer (buffer-list))
4152 (with-current-buffer buffer
4153 (when (member buffer-file-name gdb-source-file-list)
51281b32 4154 (gdb-init-buffer)))))
691cf4a0
NR
4155
4156(defun gdb-get-main-selected-frame ()
6ff2c8f1
JPG
4157 "Trigger for `gdb-frame-handler' which uses main current thread.
4158Called from `gdb-update'."
691cf4a0
NR
4159 (if (not (gdb-pending-p 'gdb-get-main-selected-frame))
4160 (progn
2170cb53
CY
4161 (gdb-input (gdb-current-context-command "-stack-info-frame")
4162 'gdb-frame-handler)
691cf4a0
NR
4163 (gdb-add-pending 'gdb-get-main-selected-frame))))
4164
4165(defun gdb-frame-handler ()
6ff2c8f1 4166 "Set `gdb-selected-frame' and `gdb-selected-file' to show
691cf4a0
NR
4167overlay arrow in source buffer."
4168 (gdb-delete-pending 'gdb-get-main-selected-frame)
4169 (let ((frame (bindat-get-field (gdb-json-partial-output) 'frame)))
4170 (when frame
4171 (setq gdb-selected-frame (bindat-get-field frame 'func))
4172 (setq gdb-selected-file (bindat-get-field frame 'fullname))
4173 (setq gdb-frame-number (bindat-get-field frame 'level))
4174 (setq gdb-frame-address (bindat-get-field frame 'addr))
4175 (let ((line (bindat-get-field frame 'line)))
4176 (setq gdb-selected-line (and line (string-to-number line)))
4177 (when (and gdb-selected-file gdb-selected-line)
4178 (setq gud-last-frame (cons gdb-selected-file gdb-selected-line))
4179 (gud-display-frame)))
4180 (if gud-overlay-arrow-position
4181 (let ((buffer (marker-buffer gud-overlay-arrow-position))
4182 (position (marker-position gud-overlay-arrow-position)))
4183 (when buffer
4184 (with-current-buffer buffer
4185 (setq fringe-indicator-alist
4186 (if (string-equal gdb-frame-number "0")
4187 nil
4188 '((overlay-arrow . hollow-right-triangle))))
4189 (setq gud-overlay-arrow-position (make-marker))
4190 (set-marker gud-overlay-arrow-position position))))))))
4191
4192(defvar gdb-prompt-name-regexp "value=\"\\(.*?\\)\"")
4193
4194(defun gdb-get-prompt ()
4195 "Find prompt for GDB session."
4196 (goto-char (point-min))
4197 (setq gdb-prompt-name nil)
4198 (re-search-forward gdb-prompt-name-regexp nil t)
4199 (setq gdb-prompt-name (match-string 1))
4200 ;; Insert first prompt.
4201 (setq gdb-filter-output (concat gdb-filter-output gdb-prompt-name)))
4202
4203;;;; Window management
d97af5a0
CY
4204(defun gdb-display-buffer (buf)
4205 "Show buffer BUF, and make that window dedicated."
4206 (let ((window (display-buffer buf)))
4207 (set-window-dedicated-p window t)
4208 window))
4209
4210 ;; (let ((answer (get-buffer-window buf 0)))
4211 ;; (if answer
4212 ;; (display-buffer buf nil 0) ;Deiconify frame if necessary.
4213 ;; (let ((window (get-lru-window)))
4214 ;; (if (eq (buffer-local-value 'gud-minor-mode (window-buffer window))
4215 ;; 'gdbmi)
4216 ;; (let ((largest (get-largest-window)))
4217 ;; (setq answer (split-window largest))
4218 ;; (set-window-buffer answer buf)
4219 ;; (set-window-dedicated-p answer t)
4220 ;; answer)
4221 ;; (set-window-buffer window buf)
4222 ;; window)))))
4223
691cf4a0
NR
4224
4225(defun gdb-preempt-existing-or-display-buffer (buf &optional split-horizontal)
4226 "Find window displaying a buffer with the same
6ff2c8f1
JPG
4227`gdb-buffer-type' as BUF and show BUF there. If no such window
4228exists, just call `gdb-display-buffer' for BUF. If the window
691cf4a0
NR
4229found is already dedicated, split window according to
4230SPLIT-HORIZONTAL and show BUF in the new window."
4231 (if buf
4232 (when (not (get-buffer-window buf))
4233 (let* ((buf-type (gdb-buffer-type buf))
4234 (existing-window
4235 (get-window-with-predicate
4236 #'(lambda (w)
4237 (and (eq buf-type
4238 (gdb-buffer-type (window-buffer w)))
4239 (not (window-dedicated-p w)))))))
4240 (if existing-window
4241 (set-window-buffer existing-window buf)
4242 (let ((dedicated-window
4243 (get-window-with-predicate
4244 #'(lambda (w)
4245 (eq buf-type
4246 (gdb-buffer-type (window-buffer w)))))))
4247 (if dedicated-window
4248 (set-window-buffer
4249 (split-window dedicated-window nil split-horizontal) buf)
d97af5a0 4250 (gdb-display-buffer buf))))))
691cf4a0
NR
4251 (error "Null buffer")))
4252\f
4253;;; Shared keymap initialization:
4254
4255(let ((menu (make-sparse-keymap "GDB-Windows")))
4256 (define-key gud-menu-map [displays]
4257 `(menu-item "GDB-Windows" ,menu
4258 :visible (eq gud-minor-mode 'gdbmi)))
4259 (define-key menu [gdb] '("Gdb" . gdb-display-gdb-buffer))
4260 (define-key menu [threads] '("Threads" . gdb-display-threads-buffer))
4261 (define-key menu [memory] '("Memory" . gdb-display-memory-buffer))
4262 (define-key menu [disassembly]
4263 '("Disassembly" . gdb-display-disassembly-buffer))
4264 (define-key menu [registers] '("Registers" . gdb-display-registers-buffer))
4265 (define-key menu [inferior]
4266 '("IO" . gdb-display-io-buffer))
4267 (define-key menu [locals] '("Locals" . gdb-display-locals-buffer))
4268 (define-key menu [frames] '("Stack" . gdb-display-stack-buffer))
4269 (define-key menu [breakpoints]
4270 '("Breakpoints" . gdb-display-breakpoints-buffer)))
4271
4272(let ((menu (make-sparse-keymap "GDB-Frames")))
4273 (define-key gud-menu-map [frames]
4274 `(menu-item "GDB-Frames" ,menu
4275 :visible (eq gud-minor-mode 'gdbmi)))
4276 (define-key menu [gdb] '("Gdb" . gdb-frame-gdb-buffer))
4277 (define-key menu [threads] '("Threads" . gdb-frame-threads-buffer))
4278 (define-key menu [memory] '("Memory" . gdb-frame-memory-buffer))
3db614b0
SM
4279 (define-key menu [disassembly]
4280 '("Disassembly" . gdb-frame-disassembly-buffer))
691cf4a0
NR
4281 (define-key menu [registers] '("Registers" . gdb-frame-registers-buffer))
4282 (define-key menu [inferior]
4283 '("IO" . gdb-frame-io-buffer))
4284 (define-key menu [locals] '("Locals" . gdb-frame-locals-buffer))
4285 (define-key menu [frames] '("Stack" . gdb-frame-stack-buffer))
4286 (define-key menu [breakpoints]
4287 '("Breakpoints" . gdb-frame-breakpoints-buffer)))
4288
4289(let ((menu (make-sparse-keymap "GDB-MI")))
4290 (define-key menu [gdb-customize]
3db614b0
SM
4291 '(menu-item "Customize" (lambda () (interactive) (customize-group 'gdb))
4292 :help "Customize Gdb Graphical Mode options."))
691cf4a0 4293 (define-key menu [gdb-many-windows]
3db614b0
SM
4294 '(menu-item "Display Other Windows" gdb-many-windows
4295 :help "Toggle display of locals, stack and breakpoint information"
4296 :button (:toggle . gdb-many-windows)))
691cf4a0 4297 (define-key menu [gdb-restore-windows]
3db614b0
SM
4298 '(menu-item "Restore Window Layout" gdb-restore-windows
4299 :help "Restore standard layout for debug session."))
691cf4a0
NR
4300 (define-key menu [sep1]
4301 '(menu-item "--"))
4302 (define-key menu [all-threads]
4303 '(menu-item "GUD controls all threads"
3db614b0
SM
4304 (lambda ()
4305 (interactive)
4306 (setq gdb-gud-control-all-threads t))
4307 :help "GUD start/stop commands apply to all threads"
4308 :button (:radio . gdb-gud-control-all-threads)))
691cf4a0
NR
4309 (define-key menu [current-thread]
4310 '(menu-item "GUD controls current thread"
3db614b0
SM
4311 (lambda ()
4312 (interactive)
4313 (setq gdb-gud-control-all-threads nil))
4314 :help "GUD start/stop commands apply to current thread only"
4315 :button (:radio . (not gdb-gud-control-all-threads))))
691cf4a0
NR
4316 (define-key menu [sep2]
4317 '(menu-item "--"))
4318 (define-key menu [gdb-customize-reasons]
4319 '(menu-item "Customize switching..."
3db614b0
SM
4320 (lambda ()
4321 (interactive)
4322 (customize-option 'gdb-switch-reasons))))
691cf4a0 4323 (define-key menu [gdb-switch-when-another-stopped]
3db614b0
SM
4324 (menu-bar-make-toggle gdb-toggle-switch-when-another-stopped
4325 gdb-switch-when-another-stopped
691cf4a0
NR
4326 "Automatically switch to stopped thread"
4327 "GDB thread switching %s"
4328 "Switch to stopped thread"))
4329 (define-key gud-menu-map [mi]
4330 `(menu-item "GDB-MI" ,menu :visible (eq gud-minor-mode 'gdbmi))))
4331
4332;; TODO Fit these into tool-bar-local-item-from-menu call in gud.el.
4333;; GDB-MI menu will need to be moved to gud.el. We can't use
4334;; tool-bar-local-item-from-menu here because it appends new buttons
4335;; to toolbar from right to left while we want our A/T throttle to
4336;; show up right before Run button.
4337(define-key-after gud-tool-bar-map [all-threads]
4338 '(menu-item "Switch to non-stop/A mode" gdb-control-all-threads
3db614b0
SM
4339 :image (find-image '((:type xpm :file "gud/thread.xpm")))
4340 :visible (and (eq gud-minor-mode 'gdbmi)
4341 gdb-non-stop
4342 (not gdb-gud-control-all-threads)))
691cf4a0
NR
4343 'run)
4344
4345(define-key-after gud-tool-bar-map [current-thread]
4346 '(menu-item "Switch to non-stop/T mode" gdb-control-current-thread
3db614b0
SM
4347 :image (find-image '((:type xpm :file "gud/all.xpm")))
4348 :visible (and (eq gud-minor-mode 'gdbmi)
4349 gdb-non-stop
4350 gdb-gud-control-all-threads))
691cf4a0
NR
4351 'all-threads)
4352
4353(defun gdb-frame-gdb-buffer ()
d97af5a0 4354 "Display GUD buffer in another frame."
691cf4a0 4355 (interactive)
3199b96f 4356 (display-buffer-other-frame gud-comint-buffer))
691cf4a0
NR
4357
4358(defun gdb-display-gdb-buffer ()
4359 "Display GUD buffer."
4360 (interactive)
3199b96f 4361 (pop-to-buffer gud-comint-buffer nil 0))
691cf4a0 4362
3db614b0 4363(defun gdb-set-window-buffer (name &optional ignore-dedicated window)
691cf4a0
NR
4364 "Set buffer of selected window to NAME and dedicate window.
4365
4366When IGNORE-DEDICATED is non-nil, buffer is set even if selected
4367window is dedicated."
3db614b0 4368 (unless window (setq window (selected-window)))
691cf4a0 4369 (when ignore-dedicated
3db614b0
SM
4370 (set-window-dedicated-p window nil))
4371 (set-window-buffer window (get-buffer name))
4372 (set-window-dedicated-p window t))
691cf4a0
NR
4373
4374(defun gdb-setup-windows ()
9fc9a531 4375 "Layout the window pattern for option `gdb-many-windows'."
d97af5a0
CY
4376 (gdb-get-buffer-create 'gdb-locals-buffer)
4377 (gdb-get-buffer-create 'gdb-stack-buffer)
4378 (gdb-get-buffer-create 'gdb-breakpoints-buffer)
4379 (set-window-dedicated-p (selected-window) nil)
37ac18a3 4380 (switch-to-buffer gud-comint-buffer)
d97af5a0 4381 (delete-other-windows)
3db614b0
SM
4382 (let ((win0 (selected-window))
4383 (win1 (split-window nil ( / ( * (window-height) 3) 4)))
4384 (win2 (split-window nil ( / (window-height) 3)))
2d197ffb 4385 (win3 (split-window-right)))
3db614b0
SM
4386 (gdb-set-window-buffer (gdb-locals-buffer-name) nil win3)
4387 (select-window win2)
4388 (set-window-buffer
4389 win2
4390 (if gud-last-last-frame
4391 (gud-find-file (car gud-last-last-frame))
4392 (if gdb-main-file
4393 (gud-find-file gdb-main-file)
4394 ;; Put buffer list in window if we
4395 ;; can't find a source file.
4396 (list-buffers-noselect))))
4397 (setq gdb-source-window (selected-window))
2d197ffb 4398 (let ((win4 (split-window-right)))
3db614b0
SM
4399 (gdb-set-window-buffer
4400 (gdb-get-buffer-create 'gdb-inferior-io) nil win4))
4401 (select-window win1)
4402 (gdb-set-window-buffer (gdb-stack-buffer-name))
2d197ffb 4403 (let ((win5 (split-window-right)))
3db614b0
SM
4404 (gdb-set-window-buffer (if gdb-show-threads-by-default
4405 (gdb-threads-buffer-name)
4406 (gdb-breakpoints-buffer-name))
4407 nil win5))
4408 (select-window win0)))
691cf4a0 4409
e7e85dc0 4410(define-minor-mode gdb-many-windows
691cf4a0
NR
4411 "If nil just pop up the GUD buffer unless `gdb-show-main' is t.
4412In this case it starts with two windows: one displaying the GUD
4413buffer and the other with the source file with the main routine
4414of the debugged program. Non-nil means display the layout shown for
4415`gdb'."
e7e85dc0 4416 :global t
691cf4a0 4417 :group 'gdb
e7e85dc0 4418 :version "22.1"
691cf4a0 4419 (if (and gud-comint-buffer
3db614b0 4420 (buffer-name gud-comint-buffer))
e7e85dc0
SM
4421 (ignore-errors
4422 (gdb-restore-windows))))
691cf4a0
NR
4423
4424(defun gdb-restore-windows ()
4425 "Restore the basic arrangement of windows used by gdb.
9fc9a531 4426This arrangement depends on the value of option `gdb-many-windows'."
691cf4a0 4427 (interactive)
37ac18a3 4428 (switch-to-buffer gud-comint-buffer) ;Select the right window and frame.
3db614b0 4429 (delete-other-windows)
691cf4a0
NR
4430 (if gdb-many-windows
4431 (gdb-setup-windows)
4432 (when (or gud-last-last-frame gdb-show-main)
3db614b0
SM
4433 (let ((win (split-window)))
4434 (set-window-buffer
4435 win
4436 (if gud-last-last-frame
4437 (gud-find-file (car gud-last-last-frame))
4438 (gud-find-file gdb-main-file)))
4439 (setq gdb-source-window win)))))
691cf4a0 4440
b668fa6e 4441;; Called from `gud-sentinel' in gud.el:
691cf4a0
NR
4442(defun gdb-reset ()
4443 "Exit a debugging session cleanly.
4444Kills the gdb buffers, and resets variables and the source buffers."
b668fa6e
CY
4445 ;; The gdb-inferior buffer has a pty hooked up to the main gdb
4446 ;; process. This pty must be deleted explicitly.
f30d612a
CY
4447 (let ((pty (get-process "gdb-inferior")))
4448 (if pty (delete-process pty)))
4449 ;; Find gdb-mi buffers and kill them.
691cf4a0
NR
4450 (dolist (buffer (buffer-list))
4451 (unless (eq buffer gud-comint-buffer)
4452 (with-current-buffer buffer
3db614b0
SM
4453 (if (eq gud-minor-mode 'gdbmi)
4454 (if (string-match "\\` ?\\*.+\\*\\'" (buffer-name))
4455 (kill-buffer nil)
4456 (gdb-remove-breakpoint-icons (point-min) (point-max) t)
4457 (setq gud-minor-mode nil)
4458 (kill-local-variable 'tool-bar-map)
4459 (kill-local-variable 'gdb-define-alist))))))
691cf4a0
NR
4460 (setq gdb-disassembly-position nil)
4461 (setq overlay-arrow-variable-list
3db614b0 4462 (delq 'gdb-disassembly-position overlay-arrow-variable-list))
691cf4a0
NR
4463 (setq fringe-indicator-alist '((overlay-arrow . right-triangle)))
4464 (setq gdb-stack-position nil)
4465 (setq overlay-arrow-variable-list
3db614b0 4466 (delq 'gdb-stack-position overlay-arrow-variable-list))
691cf4a0
NR
4467 (setq gdb-thread-position nil)
4468 (setq overlay-arrow-variable-list
3db614b0 4469 (delq 'gdb-thread-position overlay-arrow-variable-list))
691cf4a0
NR
4470 (if (boundp 'speedbar-frame) (speedbar-timer-fn))
4471 (setq gud-running nil)
4472 (setq gdb-active-process nil)
4473 (remove-hook 'after-save-hook 'gdb-create-define-alist t))
4474
4475(defun gdb-get-source-file ()
4476 "Find the source file where the program starts and display it with related
4477buffers, if required."
4478 (goto-char (point-min))
4479 (if (re-search-forward gdb-source-file-regexp nil t)
4480 (setq gdb-main-file (match-string 1)))
3db614b0 4481 (if gdb-many-windows
691cf4a0 4482 (gdb-setup-windows)
3db614b0 4483 (gdb-get-buffer-create 'gdb-breakpoints-buffer)
8c27235e
CY
4484 (and gdb-show-main
4485 gdb-main-file
4486 (display-buffer (gud-find-file gdb-main-file))))
51281b32
CY
4487 (gdb-force-mode-line-update
4488 (propertize "ready" 'face font-lock-variable-name-face)))
691cf4a0
NR
4489
4490;;from put-image
4491(defun gdb-put-string (putstring pos &optional dprop &rest sprops)
4492 "Put string PUTSTRING in front of POS in the current buffer.
4493PUTSTRING is displayed by putting an overlay into the current buffer with a
4494`before-string' string that has a `display' property whose value is
4495PUTSTRING."
4496 (let ((string (make-string 1 ?x))
3db614b0 4497 (buffer (current-buffer)))
691cf4a0
NR
4498 (setq putstring (copy-sequence putstring))
4499 (let ((overlay (make-overlay pos pos buffer))
3db614b0
SM
4500 (prop (or dprop
4501 (list (list 'margin 'left-margin) putstring))))
691cf4a0
NR
4502 (put-text-property 0 1 'display prop string)
4503 (if sprops
3db614b0 4504 (add-text-properties 0 1 sprops string))
691cf4a0
NR
4505 (overlay-put overlay 'put-break t)
4506 (overlay-put overlay 'before-string string))))
4507
4508;;from remove-images
4509(defun gdb-remove-strings (start end &optional buffer)
4510 "Remove strings between START and END in BUFFER.
4511Remove only strings that were put in BUFFER with calls to `gdb-put-string'.
4512BUFFER nil or omitted means use the current buffer."
4513 (unless buffer
4514 (setq buffer (current-buffer)))
4515 (dolist (overlay (overlays-in start end))
4516 (when (overlay-get overlay 'put-break)
3db614b0 4517 (delete-overlay overlay))))
691cf4a0
NR
4518
4519(defun gdb-put-breakpoint-icon (enabled bptno &optional line)
4520 (let* ((posns (gdb-line-posns (or line (line-number-at-pos))))
4521 (start (- (car posns) 1))
4522 (end (+ (cdr posns) 1))
4523 (putstring (if enabled "B" "b"))
4524 (source-window (get-buffer-window (current-buffer) 0)))
4525 (add-text-properties
4526 0 1 '(help-echo "mouse-1: clear bkpt, mouse-3: enable/disable bkpt")
4527 putstring)
4528 (if enabled
3db614b0
SM
4529 (add-text-properties
4530 0 1 `(gdb-bptno ,bptno gdb-enabled t) putstring)
691cf4a0
NR
4531 (add-text-properties
4532 0 1 `(gdb-bptno ,bptno gdb-enabled nil) putstring))
4533 (gdb-remove-breakpoint-icons start end)
4534 (if (display-images-p)
3db614b0
SM
4535 (if (>= (or left-fringe-width
4536 (if source-window (car (window-fringes source-window)))
4537 gdb-buffer-fringe-width) 8)
4538 (gdb-put-string
4539 nil (1+ start)
4540 `(left-fringe breakpoint
4541 ,(if enabled
4542 'breakpoint-enabled
4543 'breakpoint-disabled))
4544 'gdb-bptno bptno
4545 'gdb-enabled enabled)
4546 (when (< left-margin-width 2)
4547 (save-current-buffer
4548 (setq left-margin-width 2)
4549 (if source-window
4550 (set-window-margins
4551 source-window
4552 left-margin-width right-margin-width))))
4553 (put-image
4554 (if enabled
4555 (or breakpoint-enabled-icon
4556 (setq breakpoint-enabled-icon
4557 (find-image `((:type xpm :data
4558 ,breakpoint-xpm-data
4559 :ascent 100 :pointer hand)
4560 (:type pbm :data
4561 ,breakpoint-enabled-pbm-data
4562 :ascent 100 :pointer hand)))))
4563 (or breakpoint-disabled-icon
4564 (setq breakpoint-disabled-icon
4565 (find-image `((:type xpm :data
4566 ,breakpoint-xpm-data
4567 :conversion disabled
4568 :ascent 100 :pointer hand)
4569 (:type pbm :data
4570 ,breakpoint-disabled-pbm-data
4571 :ascent 100 :pointer hand))))))
4572 (+ start 1)
4573 putstring
4574 'left-margin))
691cf4a0 4575 (when (< left-margin-width 2)
3db614b0
SM
4576 (save-current-buffer
4577 (setq left-margin-width 2)
4578 (let ((window (get-buffer-window (current-buffer) 0)))
4579 (if window
4580 (set-window-margins
4581 window left-margin-width right-margin-width)))))
691cf4a0
NR
4582 (gdb-put-string
4583 (propertize putstring
3db614b0
SM
4584 'face (if enabled
4585 'breakpoint-enabled 'breakpoint-disabled))
691cf4a0
NR
4586 (1+ start)))))
4587
4588(defun gdb-remove-breakpoint-icons (start end &optional remove-margin)
4589 (gdb-remove-strings start end)
4590 (if (display-images-p)
4591 (remove-images start end))
4592 (when remove-margin
4593 (setq left-margin-width 0)
4594 (let ((window (get-buffer-window (current-buffer) 0)))
4595 (if window
3db614b0
SM
4596 (set-window-margins
4597 window left-margin-width right-margin-width)))))
691cf4a0 4598
2170cb53
CY
4599\f
4600;;; Functions for inline completion.
4601
4602(defvar gud-gdb-fetch-lines-in-progress)
4603(defvar gud-gdb-fetch-lines-string)
4604(defvar gud-gdb-fetch-lines-break)
4605(defvar gud-gdb-fetched-lines)
4606
4607(defun gud-gdbmi-completions (context command)
4608 "Completion table for GDB/MI commands.
4609COMMAND is the prefix for which we seek completion.
4610CONTEXT is the text before COMMAND on the line."
4611 (let ((gud-gdb-fetch-lines-in-progress t)
4612 (gud-gdb-fetch-lines-string nil)
4613 (gud-gdb-fetch-lines-break (length context))
4614 (gud-gdb-fetched-lines nil)
4615 ;; This filter dumps output lines to `gud-gdb-fetched-lines'.
6ff2c8f1 4616 (gud-marker-filter #'gud-gdbmi-fetch-lines-filter))
2170cb53
CY
4617 (with-current-buffer (gdb-get-buffer 'gdb-partial-output-buffer)
4618 (gdb-input (concat "complete " context command)
4619 (lambda () (setq gud-gdb-fetch-lines-in-progress nil)))
4620 (while gud-gdb-fetch-lines-in-progress
4621 (accept-process-output (get-buffer-process gud-comint-buffer))))
4622 (gud-gdb-completions-1 gud-gdb-fetched-lines)))
4623
4624(defun gud-gdbmi-fetch-lines-filter (string)
4625 "Custom filter function for `gud-gdbmi-completions'."
4626 (setq string (concat gud-gdb-fetch-lines-string
4627 (gud-gdbmi-marker-filter string)))
4628 (while (string-match "\n" string)
4629 (push (substring string gud-gdb-fetch-lines-break (match-beginning 0))
4630 gud-gdb-fetched-lines)
4631 (setq string (substring string (match-end 0))))
4632 "")
4633
691cf4a0
NR
4634(provide 'gdb-mi)
4635
691cf4a0 4636;;; gdb-mi.el ends here