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