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