* play/solitaire.el (solitaire-mode): Fix typo in docstring.
[bpt/emacs.git] / lisp / progmodes / gdb-ui.el
CommitLineData
1ffac268
NR
1;;; gdb-ui.el --- User Interface for running GDB
2
95cc50b6 3;; Author: Nick Roberts <nickrob@gnu.org>
1ffac268
NR
4;; Maintainer: FSF
5;; Keywords: unix, tools
6
4e643dd2 7;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008
d91362c9 8;; Free Software Foundation, Inc.
1ffac268
NR
9
10;; This file is part of GNU Emacs.
11
b1fc2b50 12;; GNU Emacs is free software: you can redistribute it and/or modify
1ffac268 13;; it under the terms of the GNU General Public License as published by
b1fc2b50
GM
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
1ffac268
NR
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
b1fc2b50 23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
1ffac268
NR
24
25;;; Commentary:
26
d94dccc6 27;; This mode acts as a graphical user interface to GDB. You can interact with
1ffac268
NR
28;; GDB through the GUD buffer in the usual way, but there are also further
29;; buffers which control the execution and describe the state of your program.
614963ba 30;; It separates the input/output of your program from that of GDB, if
d94dccc6 31;; required, and watches expressions in the speedbar. It also uses features of
2101105e
NR
32;; Emacs 21 such as the fringe/display margin for breakpoints, and the toolbar
33;; (see the GDB Graphical Interface section in the Emacs info manual).
1ffac268 34
4d4cc780 35;; By default, M-x gdb will start the debugger.
b6d0e4da
NR
36
37;; This file has evolved from gdba.el that was included with GDB 5.0 and
38;; written by Tom Lord and Jim Kingdon. It uses GDB's annotation interface.
39;; You don't need to know about annotations to use this mode as a debugger,
9106c6ae
NR
40;; but if you are interested developing the mode itself, see the Annotations
41;; section in the GDB info manual.
9f6efa0c 42
d94dccc6 43;; GDB developers plan to make the annotation interface obsolete. A new
cc6546c9
NR
44;; interface called GDB/MI (machine interface) has been designed to replace it.
45;; Some GDB/MI commands are used in this file through the CLI command
46;; 'interpreter mi <mi-command>'. To help with the process of fully migrating
47;; Emacs from annotations to GDB/MI, there is an experimental package called
48;; gdb-mi in the Emacs Lisp Package Archive ("http://tromey.com/elpa/"). It
49;; comprises of modified gud.el and a file called gdb-mi.el which replaces
50;; gdb-ui.el. When installed, this overrides the current files and invoking
51;; M-x gdb will use GDB/MI directly (starts with "gdb -i=mi"). When deleted
52;; ('d' followed by 'x' in Package Menu mode), the files are deleted and old
53;; functionality restored. This provides a convenient way to review the
54;; current status/contribute to its improvement. For someone who just wants to
55;; use GDB, however, the current mode in Emacs 22 is a much better option.
56;; There is also a file, also called gdb-mi.el, a version of which is included
57;; the GDB distribution. This will probably only work with versions
58;; distributed with GDB 6.5 or later. Unlike the version in ELPA it works on
59;; top of gdb-ui.el and you can only start it with M-x gdbmi.
9f6efa0c 60
9106c6ae
NR
61;; This mode SHOULD WORK WITH GDB 5.0 or later but you will NEED AT LEAST
62;; GDB 6.0 to use watch expressions. It works best with GDB 6.4 or later
63;; where watch expressions will update more quickly.
9f6efa0c
NR
64
65;;; Windows Platforms:
66
658d7393
NR
67;; If you are using Emacs and GDB on Windows you will need to flush the buffer
68;; explicitly in your program if you want timely display of I/O in Emacs.
69;; Alternatively you can make the output stream unbuffered, for example, by
70;; using a macro:
9f6efa0c 71
658d7393 72;; #ifdef UNBUFFERED
f95e8d97 73;; setvbuf (stdout, (char *) NULL, _IONBF, 0);
658d7393 74;; #endif
9f6efa0c 75
658d7393 76;; and compiling with -DUNBUFFERED while debugging.
9f6efa0c 77
1109332f
NR
78;; If you are using Cygwin GDB and find that the source is not being displayed
79;; in Emacs when you step through it, possible solutions are to:
80
81;; 1) Use Cygwin X Windows and Cygwin Emacs.
82;; (Since 22.1 Emacs builds under Cygwin.)
83;; 2) Use MinGW GDB instead.
84;; 3) Use cygwin-mount.el
85
9f6efa0c
NR
86;;; Known Bugs:
87
cc6546c9
NR
88;; 1) Cannot handle multiple debug sessions.
89;; 2) If you wish to call procedures from your program in GDB
3e0b9c08
NR
90;; e.g "call myproc ()", "p mysquare (5)" then use level 2 annotations
91;; "gdb --annotate=2 myprog" to keep source buffer/selected frame fixed.
cc6546c9 92;; 3) After detaching from a process, clicking on the "GO" icon on toolbar
82bc67b8 93;; (gud-go) sends "continue" to GDB (should be "run").
b32d1b9b 94
b19f3205 95;;; TODO:
9106c6ae 96
37ebd64b 97;; 1) Use MI command -data-read-memory for memory window.
72ba4f36
NR
98;; 2) Use tree-buffer.el (from ECB) instead of the speedbar for
99;; watch-expressions? Handling of watch-expressions needs to be
100;; overhauled to work for large arrays/structures by creating variable
101;; objects for visible watch-expressions only.
d47c318c 102;; 3) Mark breakpoint locations on scroll-bar of source buffer?
1ffac268
NR
103
104;;; Code:
105
106(require 'gud)
107
bf1d7e44 108(defvar tool-bar-map)
25c7f315 109(defvar speedbar-initial-expansion-list-name)
bf1d7e44 110
ec180a26 111(defvar gdb-pc-address nil "Initialization for Assembler buffer.
55222dc8 112Set to \"main\" at start if `gdb-show-main' is t.")
ec180a26 113(defvar gdb-frame-address nil "Identity of frame for watch expression.")
7446b657 114(defvar gdb-previous-frame-pc-address nil)
37ebd64b 115(defvar gdb-memory-address "main")
1ffac268 116(defvar gdb-previous-frame nil)
5770a942
NR
117(defvar gdb-selected-frame nil)
118(defvar gdb-frame-number nil)
1ffac268 119(defvar gdb-current-language nil)
b32d1b9b 120(defvar gdb-var-list nil
55222dc8 121 "List of variables in watch window.
ec180a26 122Each element has the form (VARNUM EXPRESSION NUMCHILD TYPE VALUE STATUS FP)
b41a7569 123where STATUS is nil (`unchanged'), `changed' or `out-of-scope', FP the frame
ec180a26 124address for root variables.")
8da4dd76 125(defvar gdb-main-file nil "Source file from which program execution begins.")
3e0b9c08 126(defvar gud-old-arrow nil)
59ae3049 127(defvar gdb-thread-indicator nil)
1ffac268 128(defvar gdb-overlay-arrow-position nil)
9143202c 129(defvar gdb-stack-position nil)
2cec1d1a 130(defvar gdb-server-prefix nil)
7c511b96 131(defvar gdb-flush-pending-output nil)
a0091778 132(defvar gdb-location-alist nil
0ebd837a
NR
133 "Alist of breakpoint numbers and full filenames. Only used for files that
134Emacs can't find.")
135(defvar gdb-active-process nil
136 "GUD tooltips display variable values when t, and macro definitions otherwise.")
98c751fe 137(defvar gdb-error "Non-nil when GDB is reporting an error.")
89d8189a
NR
138(defvar gdb-macro-info nil
139 "Non-nil if GDB knows that the inferior includes preprocessor macro info.")
6bef9fd7 140(defvar gdb-buffer-fringe-width nil)
e75116ed 141(defvar gdb-signalled nil)
f27d4d6c 142(defvar gdb-source-window nil)
be08da22 143(defvar gdb-inferior-status nil)
201f5b5f 144(defvar gdb-continuation nil)
c1719ebf 145(defvar gdb-look-up-stack nil)
3e0b9c08
NR
146(defvar gdb-frame-begin nil
147 "Non-nil when GDB generates frame-begin annotation.")
148(defvar gdb-printing t)
266e779b 149(defvar gdb-parent-bptno-enabled nil)
ef6cb9e8 150(defvar gdb-ready nil)
551b23f3 151(defvar gdb-stack-update nil)
ef6cb9e8 152(defvar gdb-early-user-input nil)
619b6adb 153
cc615d5a
NR
154(defvar gdb-buffer-type nil
155 "One of the symbols bound in `gdb-buffer-rules'.")
6c8909e7 156(make-variable-buffer-local 'gdb-buffer-type)
cc615d5a
NR
157
158(defvar gdb-input-queue ()
159 "A list of gdb command objects.")
160
161(defvar gdb-prompting nil
162 "True when gdb is idle with no pending input.")
163
57e828ae 164(defvar gdb-output-sink nil
cc615d5a
NR
165 "The disposition of the output of the current gdb command.
166Possible values are these symbols:
167
168 `user' -- gdb output should be copied to the GUD buffer
169 for the user to see.
170
1e5b5dc0 171 `inferior' -- gdb output should be copied to the inferior-io buffer.
cc615d5a
NR
172
173 `pre-emacs' -- output should be ignored util the post-prompt
174 annotation is received. Then the output-sink
175 becomes:...
176 `emacs' -- output should be collected in the partial-output-buffer
177 for subsequent processing by a command. This is the
178 disposition of output generated by commands that
179 gdb mode sends to gdb on its own behalf.
180 `post-emacs' -- ignore output until the prompt annotation is
181 received, then go to USER disposition.
182
1e5b5dc0 183gdba (gdb-ui.el) uses all five values, gdbmi (gdb-mi.el) only two
cc615d5a
NR
184\(`user' and `emacs').")
185
186(defvar gdb-current-item nil
187 "The most recent command item sent to gdb.")
188
189(defvar gdb-pending-triggers '()
55222dc8 190 "A list of trigger functions that have run later than their output handlers.")
cc615d5a 191
25c7f315
NR
192(defvar gdb-first-post-prompt nil)
193(defvar gdb-version nil)
194(defvar gdb-locals-font-lock-keywords nil)
c05ba081 195(defvar gdb-source-file-list nil
55222dc8 196 "List of source files for the current executable.")
25c7f315
NR
197(defconst gdb-error-regexp "\\^error,msg=\"\\(.+\\)\"")
198
199(defvar gdb-locals-font-lock-keywords-1
4eb19544 200 '(;; var = (struct struct_tag) value
25c7f315
NR
201 ( "\\(^\\(\\sw\\|[_.]\\)+\\) += +(\\(struct\\) \\(\\(\\sw\\|[_.]\\)+\\)"
202 (1 font-lock-variable-name-face)
203 (3 font-lock-keyword-face)
204 (4 font-lock-type-face))
205 ;; var = (type) value
206 ( "\\(^\\(\\sw\\|[_.]\\)+\\) += +(\\(\\(\\sw\\|[_.]\\)+\\)"
207 (1 font-lock-variable-name-face)
208 (3 font-lock-type-face))
209 ;; var = val
210 ( "\\(^\\(\\sw\\|[_.]\\)+\\) += +[^(]"
4eb19544 211 (1 font-lock-variable-name-face)))
25c7f315
NR
212 "Font lock keywords used in `gdb-local-mode'.")
213
214(defvar gdb-locals-font-lock-keywords-2
4eb19544 215 '(;; var = type value
25c7f315
NR
216 ( "\\(^\\(\\sw\\|[_.]\\)+\\)\t+\\(\\(\\sw\\|[_.]\\)+\\)"
217 (1 font-lock-variable-name-face)
4eb19544 218 (3 font-lock-type-face)))
25c7f315
NR
219 "Font lock keywords used in `gdb-local-mode'.")
220
221;; Variables for GDB 6.4+
25c7f315
NR
222(defvar gdb-register-names nil "List of register names.")
223(defvar gdb-changed-registers nil
224 "List of changed register numbers (strings).")
cc615d5a 225
1ffac268 226;;;###autoload
4d4cc780 227(defun gdb (command-line)
1ffac268 228 "Run gdb on program FILE in buffer *gud-FILE*.
4d4cc780
NR
229The directory containing FILE becomes the initial working
230directory and source-file directory for your debugger.
1ffac268 231
188590b5 232If `gdb-many-windows' is nil (the default value) then gdb just
1e5b5dc0 233pops up the GUD buffer unless `gdb-show-main' is t. In this case
188590b5 234it starts with two windows: one displaying the GUD buffer and the
2cec1d1a 235other with the source file with the main routine of the inferior.
188590b5 236
717e5022
NR
237If `gdb-many-windows' is t, regardless of the value of
238`gdb-show-main', the layout below will appear unless
b5e5e9f2 239`gdb-use-separate-io-buffer' is nil when the source buffer
b5c5d216
NR
240occupies the full width of the frame. Keybindings are shown in
241some of the buffers.
1ffac268 242
717e5022
NR
243Watch expressions appear in the speedbar/slowbar.
244
d94dccc6 245The following commands help control operation :
717e5022
NR
246
247`gdb-many-windows' - Toggle the number of windows gdb uses.
248`gdb-restore-windows' - To restore the window layout.
249
250See Info node `(emacs)GDB Graphical Interface' for a more
251detailed description of this mode.
252
b5c5d216
NR
253+----------------------------------------------------------------------+
254| GDB Toolbar |
255+-----------------------------------+----------------------------------+
b06e477e
NR
256| GUD buffer (I/O of GDB) | Locals buffer |
257|-----------------------------------+----------------------------------+
b5c5d216 258| | |
b06e477e 259| Source buffer | I/O buffer for debugged program |
b5c5d216 260| | |
b06e477e
NR
261|-----------------------------------+----------------------------------+
262| Stack buffer | Breakpoints/threads buffer |
4d4cc780 263+-----------------------------------+----------------------------------+
9558a54a 264
14b26c33
NR
265The option \"--annotate=3\" must be included in this value. To
266run GDB in text command mode, use `gud-gdb'. You need to use
4d4cc780
NR
267text command mode to debug multiple programs within one Emacs
268session."
269 (interactive (list (gud-query-cmdline 'gdb)))
270
271 (when (and gud-comint-buffer
272 (buffer-name gud-comint-buffer)
273 (get-buffer-process gud-comint-buffer)
274 (with-current-buffer gud-comint-buffer (eq gud-minor-mode 'gdba)))
275 (gdb-restore-windows)
276 (error
277 "Multiple debugging requires restarting in text command mode"))
278
279 (gud-common-init command-line nil 'gud-gdba-marker-filter)
280 (set (make-local-variable 'gud-minor-mode) 'gdba)
ef6cb9e8 281 (setq comint-input-sender 'gdb-send)
4d4cc780
NR
282
283 (gud-def gud-break "break %f:%l" "\C-b" "Set breakpoint at current line.")
284 (gud-def gud-tbreak "tbreak %f:%l" "\C-t"
285 "Set temporary breakpoint at current line.")
55222dc8 286 (gud-def gud-remove "clear %f:%l" "\C-d" "Remove breakpoint at current line.")
4d4cc780
NR
287 (gud-def gud-step "step %p" "\C-s" "Step one source line with display.")
288 (gud-def gud-stepi "stepi %p" "\C-i" "Step one instruction with display.")
289 (gud-def gud-next "next %p" "\C-n" "Step one line (skip functions).")
290 (gud-def gud-nexti "nexti %p" nil "Step one instruction (skip functions).")
291 (gud-def gud-cont "cont" "\C-r" "Continue with display.")
292 (gud-def gud-finish "finish" "\C-f" "Finish executing current function.")
293 (gud-def gud-jump
294 (progn (gud-call "tbreak %f:%l") (gud-call "jump %f:%l"))
295 "\C-j" "Set execution address to current line.")
296
297 (gud-def gud-up "up %p" "<" "Up N stack frames (numeric arg).")
298 (gud-def gud-down "down %p" ">" "Down N stack frames (numeric arg).")
299 (gud-def gud-print "print %e" "\C-p" "Evaluate C expression at point.")
300 (gud-def gud-pstar "print* %e" nil
301 "Evaluate C dereferenced pointer expression at point.")
302
303 ;; For debugging Emacs only.
304 (gud-def gud-pv "pv1 %e" "\C-v" "Print the value of the lisp variable.")
305
306 (gud-def gud-until "until %l" "\C-u" "Continue to current line.")
307 (gud-def gud-run "run" nil "Run the program.")
308
309 (local-set-key "\C-i" 'gud-gdb-complete-command)
310 (setq comint-prompt-regexp "^(.*gdb[+]?) *")
311 (setq paragraph-start comint-prompt-regexp)
57e828ae 312 (setq gdb-output-sink 'user)
4d4cc780
NR
313 (setq gdb-first-prompt t)
314 (setq gud-running nil)
315 (setq gdb-ready nil)
551b23f3 316 (setq gdb-stack-update nil)
ef6cb9e8
NR
317 (setq gdb-flush-pending-output nil)
318 (setq gdb-early-user-input nil)
4d4cc780 319 (setq gud-filter-pending-text nil)
b06e477e 320 (gdb-thread-identification)
4d4cc780 321 (run-hooks 'gdb-mode-hook))
1ffac268 322
27acfab3
NR
323;; Keep as an alias for compatibility with Emacs 22.1.
324;;;###autoload
325(defalias 'gdba 'gdb)
326
86af339a
NR
327(defgroup gdb nil
328 "Gdb Graphical Mode options specifically for running Gdb in Emacs."
329 :group 'processes
330 :group 'tools)
331
b35ef705
NR
332(defcustom gdb-debug-log-max 128
333 "Maximum size of `gdb-debug-log'. If nil, size is unlimited."
86af339a 334 :group 'gdb
b35ef705
NR
335 :type '(choice (integer :tag "Number of elements")
336 (const :tag "Unlimited" nil))
e75116ed
NR
337 :version "22.1")
338
b35ef705 339(defvar gdb-debug-log nil
55222dc8
JB
340 "List of commands sent to and replies received from GDB.
341Most recent commands are listed first. This list stores only the last
342`gdb-debug-log-max' values. This variable is used to debug GDB-UI.")
dbefaa00 343
bfa93501 344;;;###autoload
a5de7508 345(defcustom gdb-enable-debug nil
b35ef705 346 "Non-nil means record the process input and output in `gdb-debug-log'."
dbefaa00 347 :type 'boolean
86af339a 348 :group 'gdb
bf247b6e 349 :version "22.1")
dbefaa00 350
83ef7c48
EZ
351(defcustom gdb-cpp-define-alist-program "gcc -E -dM -"
352 "Shell command for generating a list of defined macros in a source file.
5c66660f 353This list is used to display the #define directive associated
1e5b5dc0 354with an identifier as a tooltip. It works in a debug session with
55222dc8 355GDB, when `gud-tooltip-mode' is t.
226c2e40
NR
356
357Set `gdb-cpp-define-alist-flags' for any include paths or
358predefined macros."
5c66660f 359 :type 'string
86af339a 360 :group 'gdb
5c66660f
NR
361 :version "22.1")
362
4c192d5a 363(defcustom gdb-cpp-define-alist-flags ""
8da4dd76 364 "Preprocessor flags for `gdb-cpp-define-alist-program'."
4c192d5a 365 :type 'string
86af339a 366 :group 'gdb
4c192d5a
NR
367 :version "22.1")
368
959005e4
NR
369(defcustom gdb-create-source-file-list t
370 "Non-nil means create a list of files from which the executable was built.
371Set this to nil if the GUD buffer displays \"initializing...\" in the mode
372line for a long time when starting, possibly because your executable was
373built from a large number of files. This allows quicker initialization
374but means that these files are not automatically enabled for debugging,
375e.g., you won't be able to click in the fringe to set a breakpoint until
376execution has already stopped there."
377 :type 'boolean
378 :group 'gdb
379 :version "23.1")
380
8da4dd76
NR
381(defcustom gdb-show-main nil
382 "Non-nil means display source file containing the main routine at startup.
383Also display the main routine in the disassembly buffer if present."
384 :type 'boolean
86af339a 385 :group 'gdb
8da4dd76
NR
386 :version "22.1")
387
374f0c91 388(defcustom gdb-many-windows nil
b35ef705 389 "If nil, just pop up the GUD buffer unless `gdb-show-main' is t.
ae4c58a7 390In this case start with two windows: one displaying the GUD
374f0c91 391buffer and the other with the source file with the main routine
ae4c58a7
NR
392of the debugged program. Non-nil means display the layout shown
393for `gdba'."
374f0c91 394 :type 'boolean
86af339a 395 :group 'gdb
374f0c91
NR
396 :version "22.1")
397
b5e5e9f2 398(defcustom gdb-use-separate-io-buffer nil
7443a638 399 "Non-nil means display output from the debugged program in a separate buffer."
671d498f 400 :type 'boolean
86af339a 401 :group 'gdb
671d498f
NR
402 :version "22.1")
403
be08da22
NR
404(defun gdb-force-mode-line-update (status)
405 (let ((buffer gud-comint-buffer))
406 (if (and buffer (buffer-name buffer))
407 (with-current-buffer buffer
408 (setq mode-line-process
409 (format ":%s [%s]"
410 (process-status (get-buffer-process buffer)) status))
411 ;; Force mode line redisplay soon.
412 (force-mode-line-update)))))
4b479fae 413
22b6cf48
NR
414(defun gdb-enable-debug (arg)
415 "Toggle logging of transaction between Emacs and Gdb.
416The log is stored in `gdb-debug-log' as an alist with elements
417whose cons is send, send-item or recv and whose cdr is the string
418being transferred. This list may grow up to a size of
419`gdb-debug-log-max' after which the oldest element (at the end of
420the list) is deleted every time a new one is added (at the front)."
421 (interactive "P")
422 (setq gdb-enable-debug
423 (if (null arg)
424 (not gdb-enable-debug)
425 (> (prefix-numeric-value arg) 0)))
426 (message (format "Logging of transaction %sabled"
427 (if gdb-enable-debug "en" "dis"))))
428
374f0c91
NR
429(defun gdb-many-windows (arg)
430 "Toggle the number of windows in the basic arrangement.
e7f767c2
GM
431With prefix argument ARG, display additional buffers if ARG is positive,
432otherwise use a single window."
374f0c91
NR
433 (interactive "P")
434 (setq gdb-many-windows
435 (if (null arg)
436 (not gdb-many-windows)
437 (> (prefix-numeric-value arg) 0)))
438 (message (format "Display of other windows %sabled"
439 (if gdb-many-windows "en" "dis")))
440 (if (and gud-comint-buffer
441 (buffer-name gud-comint-buffer))
442 (condition-case nil
443 (gdb-restore-windows)
444 (error nil))))
445
b5e5e9f2 446(defun gdb-use-separate-io-buffer (arg)
7443a638 447 "Toggle separate IO for debugged program.
e7f767c2
GM
448With prefix argument ARG, use separate IO if ARG is positive,
449otherwise do not."
671d498f 450 (interactive "P")
b5e5e9f2 451 (setq gdb-use-separate-io-buffer
671d498f 452 (if (null arg)
b5e5e9f2 453 (not gdb-use-separate-io-buffer)
671d498f 454 (> (prefix-numeric-value arg) 0)))
7443a638 455 (message (format "Separate IO %sabled"
b5e5e9f2 456 (if gdb-use-separate-io-buffer "en" "dis")))
671d498f
NR
457 (if (and gud-comint-buffer
458 (buffer-name gud-comint-buffer))
459 (condition-case nil
b5e5e9f2 460 (if gdb-use-separate-io-buffer
4a7d75e8 461 (if gdb-many-windows (gdb-restore-windows))
671d498f
NR
462 (kill-buffer (gdb-inferior-io-name)))
463 (error nil))))
464
5c66660f
NR
465(defvar gdb-define-alist nil "Alist of #define directives for GUD tooltips.")
466
467(defun gdb-create-define-alist ()
4c192d5a 468 "Create an alist of #define directives for GUD tooltips."
5c66660f
NR
469 (let* ((file (buffer-file-name))
470 (output
471 (with-output-to-string
472 (with-current-buffer standard-output
cf7238ad
NR
473 (and file
474 (file-exists-p file)
475 ;; call-process doesn't work with remote file names.
476 (not (file-remote-p default-directory))
477 (call-process shell-file-name file
478 (list t nil) nil "-c"
479 (concat gdb-cpp-define-alist-program " "
480 gdb-cpp-define-alist-flags))))))
38a52690 481 (define-list (split-string output "\n" t)) (name))
5c66660f
NR
482 (setq gdb-define-alist nil)
483 (dolist (define define-list)
484 (setq name (nth 1 (split-string define "[( ]")))
485 (push (cons name define) gdb-define-alist))))
486
aa360da1
GM
487(declare-function tooltip-show "tooltip" (text &optional use-echo-area))
488(defvar tooltip-use-echo-area)
489
d0b9c14d 490(defun gdb-tooltip-print (expr)
226c2e40
NR
491 (tooltip-show
492 (with-current-buffer (gdb-get-buffer 'gdb-partial-output-buffer)
d0b9c14d
NR
493 (goto-char (point-min))
494 (let ((string
495 (if (search-forward "=" nil t)
496 (concat expr (buffer-substring (- (point) 2) (point-max)))
497 (buffer-string))))
226c2e40
NR
498 ;; remove newline for gud-tooltip-echo-area
499 (substring string 0 (- (length string) 1))))
b6363524 500 (or gud-tooltip-echo-area tooltip-use-echo-area)))
226c2e40 501
89d8189a
NR
502;; If expr is a macro for a function don't print because of possible dangerous
503;; side-effects. Also printing a function within a tooltip generates an
504;; unexpected starting annotation (phase error).
505(defun gdb-tooltip-print-1 (expr)
506 (with-current-buffer (gdb-get-buffer 'gdb-partial-output-buffer)
507 (goto-char (point-min))
508 (if (search-forward "expands to: " nil t)
7c8bd6a4 509 (unless (looking-at "\\S-+.*(.*).*")
89d8189a
NR
510 (gdb-enqueue-input
511 (list (concat gdb-server-prefix "print " expr "\n")
d0b9c14d 512 `(lambda () (gdb-tooltip-print ,expr))))))))
89d8189a 513
c05ba081 514(defconst gdb-source-file-regexp "\\(.+?\\), \\|\\([^, \n].*$\\)")
e7212bb3 515
6c6273c6
NR
516(defun gdb-init-buffer ()
517 (set (make-local-variable 'gud-minor-mode)
518 (buffer-local-value 'gud-minor-mode gud-comint-buffer))
519 (set (make-local-variable 'tool-bar-map) gud-tool-bar-map)
520 (when gud-tooltip-mode
521 (make-local-variable 'gdb-define-alist)
522 (gdb-create-define-alist)
523 (add-hook 'after-save-hook 'gdb-create-define-alist nil t)))
524
e7212bb3 525(defun gdb-set-gud-minor-mode-existing-buffers ()
c05ba081
NR
526 "Create list of source files for current GDB session."
527 (goto-char (point-min))
528 (when (search-forward "read in on demand:" nil t)
529 (while (re-search-forward gdb-source-file-regexp nil t)
12c83f52
NR
530 (push (file-name-nondirectory (or (match-string 1) (match-string 2)))
531 gdb-source-file-list))
c05ba081
NR
532 (dolist (buffer (buffer-list))
533 (with-current-buffer buffer
534 (when (and buffer-file-name
535 (member (file-name-nondirectory buffer-file-name)
536 gdb-source-file-list))
6c6273c6 537 (gdb-init-buffer)))))
303b246d
NR
538 (gdb-force-mode-line-update
539 (propertize "ready" 'face font-lock-variable-name-face)))
e7212bb3 540
4130aa2c
NR
541(defun gdb-find-watch-expression ()
542 (let* ((var (nth (- (line-number-at-pos (point)) 2) gdb-var-list))
37c7ef17
NR
543 (varnum (car var)) expr array)
544 (string-match "\\(var[0-9]+\\)\\.\\(.*\\)" varnum)
545 (let ((var1 (assoc (match-string 1 varnum) gdb-var-list)) var2 varnumlet
546 (component-list (split-string (match-string 2 varnum) "\\." t)))
547 (setq expr (nth 1 var1))
548 (setq varnumlet (car var1))
549 (dolist (component component-list)
550 (setq var2 (assoc varnumlet gdb-var-list))
551 (setq expr (concat expr
552 (if (string-match ".*\\[[0-9]+\\]$" (nth 3 var2))
553 (concat "[" component "]")
554 (concat "." component))))
555 (setq varnumlet (concat varnumlet "." component)))
556 expr)))
4130aa2c 557
25c7f315 558(defun gdb-init-1 ()
5770a942 559 (gud-def gud-break (if (not (string-match "Machine" mode-name))
1ffac268
NR
560 (gud-call "break %f:%l" arg)
561 (save-excursion
562 (beginning-of-line)
563 (forward-char 2)
564 (gud-call "break *%a" arg)))
565 "\C-b" "Set breakpoint at current line or address.")
566 ;;
5770a942 567 (gud-def gud-remove (if (not (string-match "Machine" mode-name))
1ffac268
NR
568 (gud-call "clear %f:%l" arg)
569 (save-excursion
570 (beginning-of-line)
571 (forward-char 2)
572 (gud-call "clear *%a" arg)))
573 "\C-d" "Remove breakpoint at current line or address.")
574 ;;
ba5ff011 575 (gud-def gud-until (if (not (string-match "Machine" mode-name))
67afa80d
NR
576 (gud-call "until %f:%l" arg)
577 (save-excursion
578 (beginning-of-line)
579 (forward-char 2)
580 (gud-call "until *%a" arg)))
1ffac268 581 "\C-u" "Continue to current line or address.")
ba5ff011
NR
582 ;;
583 (gud-def gud-go (gud-call (if gdb-active-process "continue" "run") arg)
584 nil "Start or continue execution.")
1ffac268 585
4130aa2c
NR
586 ;; For debugging Emacs only.
587 (gud-def gud-pp
588 (gud-call
589 (concat
590 "pp1 " (if (eq (buffer-local-value
591 'major-mode (window-buffer)) 'speedbar-mode)
592 (gdb-find-watch-expression) "%e")) arg)
55222dc8 593 nil "Print the Emacs s-expression.")
4130aa2c 594
1ffac268 595 (define-key gud-minor-mode-map [left-margin mouse-1]
b6d0e4da 596 'gdb-mouse-set-clear-breakpoint)
1ffac268 597 (define-key gud-minor-mode-map [left-fringe mouse-1]
b6d0e4da 598 'gdb-mouse-set-clear-breakpoint)
8a464f1b
NR
599 (define-key gud-minor-mode-map [left-margin C-mouse-1]
600 'gdb-mouse-toggle-breakpoint-margin)
601 (define-key gud-minor-mode-map [left-fringe C-mouse-1]
602 'gdb-mouse-toggle-breakpoint-fringe)
603
a5de7508
NR
604 (define-key gud-minor-mode-map [left-margin drag-mouse-1]
605 'gdb-mouse-until)
dcc91606
NR
606 (define-key gud-minor-mode-map [left-fringe drag-mouse-1]
607 'gdb-mouse-until)
8a464f1b 608 (define-key gud-minor-mode-map [left-margin mouse-3]
9f6efa0c 609 'gdb-mouse-until)
8a464f1b
NR
610 (define-key gud-minor-mode-map [left-fringe mouse-3]
611 'gdb-mouse-until)
612
a5de7508
NR
613 (define-key gud-minor-mode-map [left-margin C-drag-mouse-1]
614 'gdb-mouse-jump)
615 (define-key gud-minor-mode-map [left-fringe C-drag-mouse-1]
616 'gdb-mouse-jump)
8a464f1b 617 (define-key gud-minor-mode-map [left-fringe C-mouse-3]
a5de7508 618 'gdb-mouse-jump)
8a464f1b 619 (define-key gud-minor-mode-map [left-margin C-mouse-3]
a5de7508 620 'gdb-mouse-jump)
1ffac268 621
3988d9c6 622 ;; (re-)initialize
ec180a26 623 (setq gdb-pc-address (if gdb-show-main "main" nil))
7446b657 624 (setq gdb-previous-frame-pc-address nil
5770a942
NR
625 gdb-memory-address "main"
626 gdb-previous-frame nil
627 gdb-selected-frame nil
628 gdb-current-language nil
629 gdb-frame-number nil
630 gdb-var-list nil
caf2f944 631 gdb-main-file nil
25c7f315 632 gdb-first-post-prompt t
5770a942
NR
633 gdb-prompting nil
634 gdb-input-queue nil
635 gdb-current-item nil
636 gdb-pending-triggers nil
637 gdb-output-sink 'user
638 gdb-server-prefix "server "
5770a942 639 gdb-location-alist nil
25c7f315 640 gdb-source-file-list nil
98c751fe 641 gdb-error nil
6a8a087a 642 gdb-macro-info nil
e75116ed 643 gdb-buffer-fringe-width (car (window-fringes))
b35ef705 644 gdb-debug-log nil
f27d4d6c 645 gdb-signalled nil
be08da22 646 gdb-source-window nil
2a166e26 647 gdb-inferior-status nil
c1719ebf 648 gdb-continuation nil
3e0b9c08
NR
649 gdb-look-up-stack nil
650 gdb-frame-begin nil
651 gdb-printing t
59ae3049
NR
652 gud-old-arrow nil
653 gdb-thread-indicator nil)
25c7f315 654
1ffac268 655 (setq gdb-buffer-type 'gdba)
25c7f315 656
b5e5e9f2 657 (if gdb-use-separate-io-buffer (gdb-clear-inferior-io))
25c7f315
NR
658
659 ;; Hack to see test for GDB 6.4+ (-stack-info-frame was implemented in 6.4)
25c7f315
NR
660 (gdb-enqueue-input (list "server interpreter mi -stack-info-frame\n"
661 'gdb-get-version)))
662
663(defun gdb-init-2 ()
1ffac268
NR
664 (if (eq window-system 'w32)
665 (gdb-enqueue-input (list "set new-console off\n" 'ignore)))
666 (gdb-enqueue-input (list "set height 0\n" 'ignore))
ae61773c 667 (gdb-enqueue-input (list "set width 0\n" 'ignore))
25c7f315
NR
668
669 (if (string-equal gdb-version "pre-6.4")
959005e4 670 (if gdb-create-source-file-list
c05ba081
NR
671 (gdb-enqueue-input (list (concat gdb-server-prefix "info sources\n")
672 'gdb-set-gud-minor-mode-existing-buffers))
25c7f315
NR
673 (setq gdb-locals-font-lock-keywords gdb-locals-font-lock-keywords-1))
674 (gdb-enqueue-input
675 (list "server interpreter mi -data-list-register-names\n"
676 'gdb-get-register-names))
677 ; Needs GDB 6.2 onwards.
959005e4
NR
678 (if gdb-create-source-file-list
679 (gdb-enqueue-input
680 (list "server interpreter mi \"-file-list-exec-source-files\"\n"
681 'gdb-set-gud-minor-mode-existing-buffers-1)))
25c7f315
NR
682 (setq gdb-locals-font-lock-keywords gdb-locals-font-lock-keywords-2))
683
4d91dd05
NR
684 ;; Find source file and compilation directory here.
685 ;; Works for C, C++, Fortran and Ada but not Java (GDB 6.4)
686 (gdb-enqueue-input (list "server list\n" 'ignore))
959005e4 687 (gdb-enqueue-input (list "server info source\n" 'gdb-source-info)))
1ffac268 688
25c7f315
NR
689(defun gdb-get-version ()
690 (goto-char (point-min))
caf2f944 691 (if (re-search-forward "Undefined\\( mi\\)* command:" nil t)
25c7f315
NR
692 (setq gdb-version "pre-6.4")
693 (setq gdb-version "6.4+"))
694 (gdb-init-2))
695
f7ddc2ce
NR
696(defmacro gdb-if-arrow (arrow-position &rest body)
697 `(if ,arrow-position
698 (let ((buffer (marker-buffer ,arrow-position)) (line))
699 (if (equal buffer (window-buffer (posn-window end)))
700 (with-current-buffer buffer
701 (when (or (equal start end)
702 (equal (posn-point start)
703 (marker-position ,arrow-position)))
704 ,@body))))))
705
dcc91606 706(defun gdb-mouse-until (event)
a5de7508 707 "Continue running until a source line past the current line.
20864cf0
NR
708The destination source line can be selected either by clicking
709with mouse-3 on the fringe/margin or dragging the arrow
710with mouse-1 (default bindings)."
dcc91606 711 (interactive "e")
45ab7a66
NR
712 (let ((start (event-start event))
713 (end (event-end event)))
f7ddc2ce 714 (gdb-if-arrow gud-overlay-arrow-position
45ab7a66 715 (setq line (line-number-at-pos (posn-point end)))
f7ddc2ce
NR
716 (gud-call (concat "until " (number-to-string line))))
717 (gdb-if-arrow gdb-overlay-arrow-position
718 (save-excursion
719 (goto-line (line-number-at-pos (posn-point end)))
720 (forward-char 2)
721 (gud-call (concat "until *%a"))))))
dcc91606 722
a5de7508
NR
723(defun gdb-mouse-jump (event)
724 "Set execution address/line.
20864cf0
NR
725The destination source line can be selected either by clicking with C-mouse-3
726on the fringe/margin or dragging the arrow with C-mouse-1 (default bindings).
55222dc8 727Unlike `gdb-mouse-until' the destination address can be before the current
a5de7508
NR
728line, and no execution takes place."
729 (interactive "e")
45ab7a66
NR
730 (let ((start (event-start event))
731 (end (event-end event)))
f7ddc2ce 732 (gdb-if-arrow gud-overlay-arrow-position
45ab7a66 733 (setq line (line-number-at-pos (posn-point end)))
a5de7508 734 (progn
45ab7a66 735 (gud-call (concat "tbreak " (number-to-string line)))
f7ddc2ce
NR
736 (gud-call (concat "jump " (number-to-string line)))))
737 (gdb-if-arrow gdb-overlay-arrow-position
45ab7a66
NR
738 (save-excursion
739 (goto-line (line-number-at-pos (posn-point end)))
740 (forward-char 2)
741 (progn
742 (gud-call (concat "tbreak *%a"))
f7ddc2ce 743 (gud-call (concat "jump *%a")))))))
a5de7508 744
958ac655 745(defcustom gdb-speedbar-auto-raise nil
66395e6b
NR
746 "If non-nil raise speedbar every time display of watch expressions is\
747 updated."
748 :type 'boolean
86af339a 749 :group 'gdb
66395e6b
NR
750 :version "22.1")
751
752(defun gdb-speedbar-auto-raise (arg)
d0b9c14d 753 "Toggle automatic raising of the speedbar for watch expressions.
e7f767c2
GM
754With prefix argument ARG, automatically raise speedbar if ARG is
755positive, otherwise don't automatically raise it."
66395e6b
NR
756 (interactive "P")
757 (setq gdb-speedbar-auto-raise
758 (if (null arg)
759 (not gdb-speedbar-auto-raise)
67afa80d
NR
760 (> (prefix-numeric-value arg) 0)))
761 (message (format "Auto raising %sabled"
762 (if gdb-speedbar-auto-raise "en" "dis"))))
66395e6b 763
1ffac268 764(defcustom gdb-use-colon-colon-notation nil
a0091778 765 "If non-nil use FUN::VAR format to display variables in the speedbar."
1ffac268 766 :type 'boolean
86af339a 767 :group 'gdb
bf247b6e 768 :version "22.1")
1ffac268 769
37c7ef17
NR
770(define-key gud-minor-mode-map "\C-c\C-w" 'gud-watch)
771(define-key global-map (concat gud-key-prefix "\C-w") 'gud-watch)
772
aa360da1
GM
773(declare-function tooltip-identifier-from-point "tooltip" (point))
774
37c7ef17
NR
775(defun gud-watch (&optional arg event)
776 "Watch expression at point.
777With arg, enter name of variable to be watched in the minibuffer."
778 (interactive (list current-prefix-arg last-input-event))
779 (let ((minor-mode (buffer-local-value 'gud-minor-mode gud-comint-buffer)))
780 (if (memq minor-mode '(gdbmi gdba))
781 (progn
782 (if event (posn-set-point (event-end event)))
783 (require 'tooltip)
784 (save-selected-window
9d6bb9e0
NR
785 (let ((expr
786 (if arg
787 (completing-read "Name of variable: "
788 'gud-gdb-complete-command)
789 (if (and transient-mark-mode mark-active)
790 (buffer-substring (region-beginning) (region-end))
01a36903
NR
791 (concat (if (eq major-mode 'gdb-registers-mode) "$")
792 (tooltip-identifier-from-point (point)))))))
34fb82b8
NR
793 (set-text-properties 0 (length expr) nil expr)
794 (gdb-enqueue-input
795 (list
796 (if (eq minor-mode 'gdba)
797 (concat
798 "server interpreter mi \"-var-create - * " expr "\"\n")
799 (concat"-var-create - * " expr "\n"))
800 `(lambda () (gdb-var-create-handler ,expr)))))))
37c7ef17 801 (message "gud-watch is a no-op in this mode."))))
1ffac268
NR
802
803(defconst gdb-var-create-regexp
0ebd837a 804 "name=\"\\(.*?\\)\",.*numchild=\"\\(.*?\\)\",\\(?:.*value=\\(\".*\"\\),\\)?.*type=\"\\(.*?\\)\"")
1ffac268
NR
805
806(defun gdb-var-create-handler (expr)
564b25a4
NR
807 (goto-char (point-min))
808 (if (re-search-forward gdb-var-create-regexp nil t)
e75116ed 809 (let ((var (list
37c7ef17 810 (match-string 1)
e75116ed
NR
811 (if (and (string-equal gdb-current-language "c")
812 gdb-use-colon-colon-notation gdb-selected-frame)
813 (setq expr (concat gdb-selected-frame "::" expr))
814 expr)
e75116ed 815 (match-string 2)
0ebd837a
NR
816 (match-string 4)
817 (if (match-string 3) (read (match-string 3)))
b41a7569 818 nil gdb-frame-address)))
564b25a4 819 (push var gdb-var-list)
34fb82b8 820 (speedbar 1)
564b25a4
NR
821 (unless (string-equal
822 speedbar-initial-expansion-list-name "GUD")
823 (speedbar-change-initial-expansion-list "GUD"))
0ebd837a
NR
824 (unless (nth 4 var)
825 (gdb-enqueue-input
826 (list
827 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer)
828 'gdba)
829 (concat "server interpreter mi \"0-var-evaluate-expression "
830 (car var) "\"\n")
831 (concat "0-var-evaluate-expression " (car var) "\n"))
832 `(lambda () (gdb-var-evaluate-expression-handler
833 ,(car var) nil))))))
564b25a4 834 (if (search-forward "Undefined command" nil t)
8a464f1b 835 (message-box "Watching expressions requires GDB 6.0 onwards")
e75116ed 836 (message-box "No symbol \"%s\" in current context." expr))))
1ffac268 837
51158d69 838(defun gdb-speedbar-update ()
b41a7569
NR
839 (when (and (boundp 'speedbar-frame) (frame-live-p speedbar-frame)
840 (not (member 'gdb-speedbar-timer gdb-pending-triggers)))
51158d69
NR
841 ;; Dummy command to update speedbar even when idle.
842 (gdb-enqueue-input (list "server pwd\n" 'gdb-speedbar-timer-fn))
843 ;; Keep gdb-pending-triggers non-nil till end.
844 (push 'gdb-speedbar-timer gdb-pending-triggers)))
845
846(defun gdb-speedbar-timer-fn ()
05dfe89a
NR
847 (if gdb-speedbar-auto-raise
848 (raise-frame speedbar-frame))
51158d69
NR
849 (setq gdb-pending-triggers
850 (delq 'gdb-speedbar-timer gdb-pending-triggers))
851 (speedbar-timer-fn))
852
1ffac268 853(defun gdb-var-evaluate-expression-handler (varnum changed)
564b25a4 854 (goto-char (point-min))
d22b968f
NR
855 (re-search-forward "\\(.+\\)\\^done,value=\\(\".*\"\\)" nil t)
856 (setq gdb-pending-triggers
857 (delq (string-to-number (match-string 1)) gdb-pending-triggers))
37c7ef17
NR
858 (let ((var (assoc varnum gdb-var-list)))
859 (when var
860 (if changed (setcar (nthcdr 5 var) 'changed))
d22b968f 861 (setcar (nthcdr 4 var) (read (match-string 2)))))
51158d69 862 (gdb-speedbar-update))
1ffac268
NR
863
864(defun gdb-var-list-children (varnum)
865 (gdb-enqueue-input
bd7a628a
NR
866 (list (concat "server interpreter mi \"-var-list-children " varnum "\"\n")
867 `(lambda () (gdb-var-list-children-handler ,varnum)))))
1ffac268
NR
868
869(defconst gdb-var-list-children-regexp
959005e4
NR
870 "child={.*?name=\"\\(.*?\\)\".*?,exp=\"\\(.*?\\)\".*?,\
871numchild=\"\\(.*?\\)\"\\(}\\|.*?,\\(type=\"\\(.*?\\)\"\\)?.*?}\\)")
1ffac268
NR
872
873(defun gdb-var-list-children-handler (varnum)
564b25a4
NR
874 (goto-char (point-min))
875 (let ((var-list nil))
876 (catch 'child-already-watched
877 (dolist (var gdb-var-list)
37c7ef17 878 (if (string-equal varnum (car var))
564b25a4
NR
879 (progn
880 (push var var-list)
881 (while (re-search-forward gdb-var-list-children-regexp nil t)
37c7ef17
NR
882 (let ((varchild (list (match-string 1)
883 (match-string 2)
564b25a4 884 (match-string 3)
8687849b 885 (match-string 6)
564b25a4 886 nil nil)))
37c7ef17
NR
887 (if (assoc (car varchild) gdb-var-list)
888 (throw 'child-already-watched nil))
564b25a4
NR
889 (push varchild var-list)
890 (gdb-enqueue-input
891 (list
892 (concat
d22b968f 893 "server interpreter mi \"0-var-evaluate-expression "
37c7ef17 894 (car varchild) "\"\n")
564b25a4 895 `(lambda () (gdb-var-evaluate-expression-handler
37c7ef17 896 ,(car varchild) nil)))))))
564b25a4
NR
897 (push var var-list)))
898 (setq gdb-var-list (nreverse var-list)))))
1ffac268
NR
899
900(defun gdb-var-update ()
4c199fce
NR
901 (when (not (member 'gdb-var-update gdb-pending-triggers))
902 (gdb-enqueue-input
903 (list "server interpreter mi \"-var-update *\"\n"
904 'gdb-var-update-handler))
905 (push 'gdb-var-update gdb-pending-triggers)))
1ffac268 906
8928c512 907(defconst gdb-var-update-regexp
959005e4 908 "{.*?name=\"\\(.*?\\)\".*?,in_scope=\"\\(.*?\\)\".*?,\
8928c512 909type_changed=\".*?\".*?}")
1ffac268
NR
910
911(defun gdb-var-update-handler ()
054d409e 912 (dolist (var gdb-var-list)
054d409e
NR
913 (setcar (nthcdr 5 var) nil))
914 (goto-char (point-min))
d22b968f
NR
915 (let ((n 0))
916 (while (re-search-forward gdb-var-update-regexp nil t)
917 (let ((varnum (match-string 1)))
918 (if (string-equal (match-string 2) "false")
919 (let ((var (assoc varnum gdb-var-list)))
920 (if var (setcar (nthcdr 5 var) 'out-of-scope)))
921 (setq n (1+ n))
922 (push n gdb-pending-triggers)
923 (gdb-enqueue-input
924 (list
925 (concat "server interpreter mi \"" (number-to-string n)
926 "-var-evaluate-expression " varnum "\"\n")
927 `(lambda () (gdb-var-evaluate-expression-handler ,varnum t))))))))
2cec1d1a 928 (setq gdb-pending-triggers
51158d69 929 (delq 'gdb-var-update gdb-pending-triggers)))
1ffac268 930
b3dac329
NR
931(defun gdb-var-set-format (format)
932 "Set the output format for a variable displayed in the speedbar."
933 (let* ((var (nth (- (count-lines (point-min) (point)) 2) gdb-var-list))
934 (varnum (car var)))
935 (gdb-enqueue-input
473a20b8 936 (list
b3dac329
NR
937 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
938 (concat "server interpreter mi \"-var-set-format "
939 varnum " " format "\"\n")
940 (concat "-var-set-format " varnum " " format "\n"))
473a20b8
NR
941 `(lambda () (gdb-var-set-format-handler ,varnum))))))
942
943(defconst gdb-var-set-format-regexp
944 "format=\"\\(.*?\\)\",.*value=\"\\(.*?\\)\"")
945
946(defun gdb-var-set-format-handler (varnum)
947 (goto-char (point-min))
948 (if (re-search-forward gdb-var-set-format-regexp nil t)
949 (let ((var (assoc varnum gdb-var-list)))
950 (setcar (nthcdr 4 var) (match-string 2))
951 (gdb-var-update-1))))
b3dac329 952
01b8fc60
NR
953(defun gdb-var-delete-1 (varnum)
954 (gdb-enqueue-input
955 (list
b3dac329 956 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
01b8fc60
NR
957 (concat "server interpreter mi \"-var-delete " varnum "\"\n")
958 (concat "-var-delete " varnum "\n"))
959 'ignore))
960 (setq gdb-var-list (delq var gdb-var-list))
961 (dolist (varchild gdb-var-list)
962 (if (string-match (concat (car var) "\\.") (car varchild))
963 (setq gdb-var-list (delq varchild gdb-var-list)))))
964
1ffac268 965(defun gdb-var-delete ()
4c199fce 966 "Delete watch expression at point from the speedbar."
1ffac268 967 (interactive)
36188c5e
NR
968 (if (memq (buffer-local-value 'gud-minor-mode gud-comint-buffer)
969 '(gdbmi gdba))
6c8aa2cd
NR
970 (let* ((var (nth (- (count-lines (point-min) (point)) 2) gdb-var-list))
971 (varnum (car var)))
972 (if (string-match "\\." (car var))
973 (message-box "Can only delete a root expression")
01b8fc60 974 (gdb-var-delete-1 varnum)))))
1ffac268 975
9106c6ae 976(defun gdb-var-delete-children (varnum)
82bc67b8 977 "Delete children of variable object at point from the speedbar."
9106c6ae
NR
978 (gdb-enqueue-input
979 (list
980 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
981 (concat "server interpreter mi \"-var-delete -c " varnum "\"\n")
982 (concat "-var-delete -c " varnum "\n")) 'ignore)))
983
1ffac268 984(defun gdb-edit-value (text token indent)
d94dccc6 985 "Assign a value to a variable displayed in the speedbar."
1ffac268 986 (let* ((var (nth (- (count-lines (point-min) (point)) 2) gdb-var-list))
37c7ef17 987 (varnum (car var)) (value))
1ffac268
NR
988 (setq value (read-string "New value: "))
989 (gdb-enqueue-input
39043abb 990 (list
36188c5e 991 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
a0091778
NR
992 (concat "server interpreter mi \"-var-assign "
993 varnum " " value "\"\n")
39043abb 994 (concat "-var-assign " varnum " " value "\n"))
d35e063a
NR
995 `(lambda () (gdb-edit-value-handler ,value))))))
996
997(defun gdb-edit-value-handler (value)
998 (goto-char (point-min))
999 (if (re-search-forward gdb-error-regexp nil t)
1000 (message-box "Invalid number or expression (%s)" value)))
1ffac268
NR
1001
1002(defcustom gdb-show-changed-values t
bbcc5215
NR
1003 "If non-nil change the face of out of scope variables and changed values.
1004Out of scope variables are suppressed with `shadow' face.
1005Changed values are highlighted with the face `font-lock-warning-face'."
1ffac268 1006 :type 'boolean
86af339a 1007 :group 'gdb
bf247b6e 1008 :version "22.1")
1ffac268 1009
e1204172 1010(defcustom gdb-max-children 40
0ebd837a 1011 "Maximum number of children before expansion requires confirmation."
e1204172 1012 :type 'integer
86af339a 1013 :group 'gdb
e1204172
NR
1014 :version "22.1")
1015
f8fef1ce
NR
1016(defcustom gdb-delete-out-of-scope t
1017 "If non-nil delete watch expressions automatically when they go out of scope."
1018 :type 'boolean
86af339a 1019 :group 'gdb
f8fef1ce
NR
1020 :version "22.2")
1021
1ffac268
NR
1022(defun gdb-speedbar-expand-node (text token indent)
1023 "Expand the node the user clicked on.
1024TEXT is the text of the button we clicked on, a + or - item.
1025TOKEN is data related to this node.
1026INDENT is the current indentation depth."
02974d02
NR
1027 (if (and gud-comint-buffer (buffer-name gud-comint-buffer))
1028 (progn
1029 (cond ((string-match "+" text) ;expand this node
e1204172
NR
1030 (let* ((var (assoc token gdb-var-list))
1031 (expr (nth 1 var)) (children (nth 2 var)))
1032 (if (or (<= (string-to-number children) gdb-max-children)
1033 (y-or-n-p
1034 (format
1035 "%s has %s children. Continue? " expr children)))
1036 (if (and (eq (buffer-local-value
1037 'gud-minor-mode gud-comint-buffer) 'gdba)
1038 (string-equal gdb-version "pre-6.4"))
1039 (gdb-var-list-children token)
1040 (gdb-var-list-children-1 token)))))
02974d02
NR
1041 ((string-match "-" text) ;contract this node
1042 (dolist (var gdb-var-list)
1043 (if (string-match (concat token "\\.") (car var))
1044 (setq gdb-var-list (delq var gdb-var-list))))
9106c6ae 1045 (gdb-var-delete-children token)
02974d02
NR
1046 (speedbar-change-expand-button-char ?+)
1047 (speedbar-delete-subblock indent))
1048 (t (error "Ooops... not sure what to do")))
1049 (speedbar-center-buffer-smartly))
1050 (message-box "GUD session has been killed")))
1ffac268
NR
1051
1052(defun gdb-get-target-string ()
1053 (with-current-buffer gud-comint-buffer
1054 gud-target-name))
1055\f
1056
1057;;
1058;; gdb buffers.
1059;;
1060;; Each buffer has a TYPE -- a symbol that identifies the function
1061;; of that particular buffer.
1062;;
1063;; The usual gdb interaction buffer is given the type `gdba' and
1064;; is constructed specially.
1065;;
f27d4d6c 1066;; Others are constructed by gdb-get-buffer-create and
1ffac268
NR
1067;; named according to the rules set forth in the gdb-buffer-rules-assoc
1068
1069(defvar gdb-buffer-rules-assoc '())
1070
1071(defun gdb-get-buffer (key)
1072 "Return the gdb buffer tagged with type KEY.
1073The key should be one of the cars in `gdb-buffer-rules-assoc'."
1074 (save-excursion
1075 (gdb-look-for-tagged-buffer key (buffer-list))))
1076
f27d4d6c 1077(defun gdb-get-buffer-create (key)
55222dc8 1078 "Create a new gdb buffer of the type specified by KEY.
1ffac268
NR
1079The key should be one of the cars in `gdb-buffer-rules-assoc'."
1080 (or (gdb-get-buffer key)
1081 (let* ((rules (assoc key gdb-buffer-rules-assoc))
1082 (name (funcall (gdb-rules-name-maker rules)))
1083 (new (get-buffer-create name)))
1084 (with-current-buffer new
bf247b6e 1085 (let ((trigger))
fad137cd
NR
1086 (if (cdr (cdr rules))
1087 (setq trigger (funcall (car (cdr (cdr rules))))))
6c8909e7 1088 (setq gdb-buffer-type key)
fad137cd 1089 (set (make-local-variable 'gud-minor-mode)
36188c5e 1090 (buffer-local-value 'gud-minor-mode gud-comint-buffer))
fad137cd
NR
1091 (set (make-local-variable 'tool-bar-map) gud-tool-bar-map)
1092 (if trigger (funcall trigger)))
1ffac268
NR
1093 new))))
1094
1095(defun gdb-rules-name-maker (rules) (car (cdr rules)))
1096
1097(defun gdb-look-for-tagged-buffer (key bufs)
1098 (let ((retval nil))
1099 (while (and (not retval) bufs)
1100 (set-buffer (car bufs))
1101 (if (eq gdb-buffer-type key)
1102 (setq retval (car bufs)))
1103 (setq bufs (cdr bufs)))
1104 retval))
1105
1106;;
1107;; This assoc maps buffer type symbols to rules. Each rule is a list of
1108;; at least one and possible more functions. The functions have these
1109;; roles in defining a buffer type:
1110;;
1111;; NAME - Return a name for this buffer type.
1112;;
1113;; The remaining function(s) are optional:
1114;;
1115;; MODE - called in a new buffer with no arguments, should establish
1116;; the proper mode for the buffer.
1117;;
1118
1119(defun gdb-set-buffer-rules (buffer-type &rest rules)
1120 (let ((binding (assoc buffer-type gdb-buffer-rules-assoc)))
1121 (if binding
1122 (setcdr binding rules)
1123 (push (cons buffer-type rules)
1124 gdb-buffer-rules-assoc))))
1125
1126;; GUD buffers are an exception to the rules
1127(gdb-set-buffer-rules 'gdba 'error)
1128
1ffac268
NR
1129;; Partial-output buffer : This accumulates output from a command executed on
1130;; behalf of emacs (rather than the user).
1131;;
1132(gdb-set-buffer-rules 'gdb-partial-output-buffer
1133 'gdb-partial-output-name)
1134
1135(defun gdb-partial-output-name ()
6c8aa2cd 1136 (concat " *partial-output-"
1ffac268
NR
1137 (gdb-get-target-string)
1138 "*"))
1139
1140\f
1141(gdb-set-buffer-rules 'gdb-inferior-io
1142 'gdb-inferior-io-name
1143 'gdb-inferior-io-mode)
1144
1145(defun gdb-inferior-io-name ()
1146 (concat "*input/output of "
1147 (gdb-get-target-string)
1148 "*"))
1149
b5e5e9f2 1150(defun gdb-display-separate-io-buffer ()
e75116ed 1151 "Display IO of debugged program in a separate window."
1a032087 1152 (interactive)
cb851ef5 1153 (if gdb-use-separate-io-buffer
1a032087 1154 (gdb-display-buffer
d138996e 1155 (gdb-get-buffer-create 'gdb-inferior-io) t)))
1a032087 1156
bf1d7e44
JB
1157(defconst gdb-frame-parameters
1158 '((height . 14) (width . 80)
1159 (unsplittable . t)
1160 (tool-bar-lines . nil)
1161 (menu-bar-lines . nil)
1162 (minibuffer . nil)))
1163
b5e5e9f2 1164(defun gdb-frame-separate-io-buffer ()
7443a638 1165 "Display IO of debugged program in a new frame."
1a032087 1166 (interactive)
b5e5e9f2 1167 (if gdb-use-separate-io-buffer
1a032087
NR
1168 (let ((special-display-regexps (append special-display-regexps '(".*")))
1169 (special-display-frame-alist gdb-frame-parameters))
f27d4d6c 1170 (display-buffer (gdb-get-buffer-create 'gdb-inferior-io)))))
1a032087 1171
1ffac268
NR
1172(defvar gdb-inferior-io-mode-map
1173 (let ((map (make-sparse-keymap)))
b5e5e9f2
NR
1174 (define-key map "\C-c\C-c" 'gdb-separate-io-interrupt)
1175 (define-key map "\C-c\C-z" 'gdb-separate-io-stop)
1176 (define-key map "\C-c\C-\\" 'gdb-separate-io-quit)
1177 (define-key map "\C-c\C-d" 'gdb-separate-io-eof)
1178 (define-key map "\C-d" 'gdb-separate-io-eof)
1ffac268
NR
1179 map))
1180
2cec1d1a 1181(define-derived-mode gdb-inferior-io-mode comint-mode "Inferior I/O"
1ffac268
NR
1182 "Major mode for gdb inferior-io."
1183 :syntax-table nil :abbrev-table nil
1184 ;; We want to use comint because it has various nifty and familiar
1185 ;; features. We don't need a process, but comint wants one, so create
1186 ;; a dummy one.
1187 (make-comint-in-buffer
1188 (substring (buffer-name) 1 (- (length (buffer-name)) 1))
1189 (current-buffer) "hexl")
1190 (setq comint-input-sender 'gdb-inferior-io-sender))
1191
1192(defun gdb-inferior-io-sender (proc string)
1193 ;; PROC is the pseudo-process created to satisfy comint.
1194 (with-current-buffer (process-buffer proc)
1195 (setq proc (get-buffer-process gud-comint-buffer))
1196 (process-send-string proc string)
1197 (process-send-string proc "\n")))
1198
b5e5e9f2 1199(defun gdb-separate-io-interrupt ()
1ffac268
NR
1200 "Interrupt the program being debugged."
1201 (interactive)
1202 (interrupt-process
1203 (get-buffer-process gud-comint-buffer) comint-ptyp))
1204
b5e5e9f2 1205(defun gdb-separate-io-quit ()
1ffac268
NR
1206 "Send quit signal to the program being debugged."
1207 (interactive)
1208 (quit-process
1209 (get-buffer-process gud-comint-buffer) comint-ptyp))
1210
b5e5e9f2 1211(defun gdb-separate-io-stop ()
1ffac268
NR
1212 "Stop the program being debugged."
1213 (interactive)
1214 (stop-process
1215 (get-buffer-process gud-comint-buffer) comint-ptyp))
1216
b5e5e9f2 1217(defun gdb-separate-io-eof ()
1ffac268
NR
1218 "Send end-of-file to the program being debugged."
1219 (interactive)
1220 (process-send-eof
1221 (get-buffer-process gud-comint-buffer)))
1222\f
1223
1ffac268
NR
1224;; gdb communications
1225;;
1226
1227;; INPUT: things sent to gdb
1228;;
1229;; The queues are lists. Each element is either a string (indicating user or
1230;; user-like input) or a list of the form:
1231;;
1232;; (INPUT-STRING HANDLER-FN)
1233;;
1234;; The handler function will be called from the partial-output buffer when the
1235;; command completes. This is the way to write commands which invoke gdb
1236;; commands autonomously.
1237;;
1238;; These lists are consumed tail first.
1239;;
1240
1241(defun gdb-send (proc string)
1242 "A comint send filter for gdb.
d94dccc6 1243This filter may simply queue input for a later time."
ef6cb9e8
NR
1244 (if gdb-ready
1245 (progn
1246 (with-current-buffer gud-comint-buffer
1247 (let ((inhibit-read-only t))
1248 (remove-text-properties (point-min) (point-max) '(face))))
1249 (if gud-running
1250 (progn
1251 (let ((item (concat string "\n")))
1252 (if gdb-enable-debug (push (cons 'send item) gdb-debug-log))
1253 (process-send-string proc item)))
1254 (if (string-match "\\\\\\'" string)
1255 (setq gdb-continuation (concat gdb-continuation string "\n"))
1256 (let ((item (concat
1257 gdb-continuation string
1258 (if (not comint-input-sender-no-newline) "\n"))))
1259 (gdb-enqueue-input item)
1260 (setq gdb-continuation nil)))))
1261 (push (concat string "\n") gdb-early-user-input)))
1ffac268
NR
1262
1263;; Note: Stuff enqueued here will be sent to the next prompt, even if it
1264;; is a query, or other non-top-level prompt.
1265
1266(defun gdb-enqueue-input (item)
a2c7d24f
NR
1267 (if (not gud-running)
1268 (if gdb-prompting
1269 (progn
1270 (gdb-send-item item)
02974d02 1271 (setq gdb-prompting nil))
a2c7d24f 1272 (push item gdb-input-queue))))
1ffac268
NR
1273
1274(defun gdb-dequeue-input ()
2cec1d1a 1275 (let ((queue gdb-input-queue))
78971dff
NR
1276 (if queue
1277 (let ((last (car (last queue))))
1278 (unless (nbutlast queue) (setq gdb-input-queue '()))
1279 last)
1280 ;; This should be nil here anyway but set it just to make sure.
1281 (setq gdb-pending-triggers nil))))
cc615d5a
NR
1282
1283(defun gdb-send-item (item)
7c511b96 1284 (setq gdb-flush-pending-output nil)
b35ef705 1285 (if gdb-enable-debug (push (cons 'send-item item) gdb-debug-log))
cc615d5a 1286 (setq gdb-current-item item)
36188c5e
NR
1287 (let ((process (get-buffer-process gud-comint-buffer)))
1288 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
cc615d5a
NR
1289 (if (stringp item)
1290 (progn
1291 (setq gdb-output-sink 'user)
36188c5e 1292 (process-send-string process item))
cc615d5a
NR
1293 (progn
1294 (gdb-clear-partial-output)
1295 (setq gdb-output-sink 'pre-emacs)
36188c5e 1296 (process-send-string process
cc615d5a
NR
1297 (car item))))
1298 ;; case: eq gud-minor-mode 'gdbmi
1299 (gdb-clear-partial-output)
1300 (setq gdb-output-sink 'emacs)
36188c5e 1301 (process-send-string process (car item)))))
1ffac268
NR
1302\f
1303;;
1304;; output -- things gdb prints to emacs
1305;;
1306;; GDB output is a stream interrupted by annotations.
1307;; Annotations can be recognized by their beginning
1308;; with \C-j\C-z\C-z<tag><opt>\C-j
1309;;
1310;; The tag is a string obeying symbol syntax.
1311;;
1312;; The optional part `<opt>' can be either the empty string
1313;; or a space followed by more data relating to the annotation.
1314;; For example, the SOURCE annotation is followed by a filename,
1315;; line number and various useless goo. This data must not include
1316;; any newlines.
1317;;
1318
4d4cc780 1319(defcustom gud-gdb-command-name "gdb --annotate=3"
6e498a97
NR
1320 "Default command to execute an executable under the GDB debugger.
1321The option \"--annotate=3\" must be included in this value if you
1322want the GDB Graphical Interface."
1ffac268 1323 :type 'string
27b3b9d3 1324 :group 'gud
bf247b6e 1325 :version "22.1")
1ffac268
NR
1326
1327(defvar gdb-annotation-rules
1328 '(("pre-prompt" gdb-pre-prompt)
1329 ("prompt" gdb-prompt)
1330 ("commands" gdb-subprompt)
1331 ("overload-choice" gdb-subprompt)
1332 ("query" gdb-subprompt)
2cec1d1a 1333 ;; Need this prompt for GDB 6.1
42fd213b 1334 ("nquery" gdb-subprompt)
1ffac268
NR
1335 ("prompt-for-continue" gdb-subprompt)
1336 ("post-prompt" gdb-post-prompt)
1337 ("source" gdb-source)
1338 ("starting" gdb-starting)
9cc4d7dd 1339 ("exited" gdb-exited)
e75116ed 1340 ("signalled" gdb-signalled)
be08da22 1341 ("signal" gdb-signal)
1ffac268
NR
1342 ("breakpoint" gdb-stopping)
1343 ("watchpoint" gdb-stopping)
1344 ("frame-begin" gdb-frame-begin)
1345 ("stopped" gdb-stopped)
98c751fe
NR
1346 ("error-begin" gdb-error)
1347 ("error" gdb-error)
22b6cf48
NR
1348 ("new-thread" (lambda (ignored)
1349 (gdb-get-buffer-create 'gdb-threads-buffer)))
1350 ("thread-changed" gdb-thread-changed))
59ae3049 1351 "An assoc mapping annotation tags to functions which process them.")
1ffac268 1352
cc615d5a 1353(defun gdb-resync()
7c511b96 1354 (setq gdb-flush-pending-output t)
cc615d5a 1355 (setq gud-running nil)
303b246d 1356 (gdb-force-mode-line-update
59ae3049 1357 (propertize "stopped" 'face font-lock-warning-face))
cc615d5a
NR
1358 (setq gdb-output-sink 'user)
1359 (setq gdb-input-queue nil)
1360 (setq gdb-pending-triggers nil)
1361 (setq gdb-prompting t))
1362
1ffac268 1363(defconst gdb-source-spec-regexp
5770a942 1364 "\\(.*\\):\\([0-9]*\\):[0-9]*:[a-z]*:0x0*\\([a-f0-9]*\\)")
1ffac268
NR
1365
1366;; Do not use this except as an annotation handler.
1367(defun gdb-source (args)
1368 (string-match gdb-source-spec-regexp args)
1369 ;; Extract the frame position from the marker.
1370 (setq gud-last-frame
1371 (cons
1372 (match-string 1 args)
5c66660f 1373 (string-to-number (match-string 2 args))))
ec180a26 1374 (setq gdb-pc-address (match-string 3 args))
b65a2dbf
NR
1375 ;; cover for auto-display output which comes *before*
1376 ;; stopped annotation
2cec1d1a 1377 (if (eq gdb-output-sink 'inferior) (setq gdb-output-sink 'user)))
1ffac268 1378
1ffac268 1379(defun gdb-pre-prompt (ignored)
d94dccc6
SM
1380 "An annotation handler for `pre-prompt'.
1381This terminates the collection of output from a previous command if that
1382happens to be in effect."
55cd42a4 1383 (setq gdb-error nil)
2cec1d1a 1384 (let ((sink gdb-output-sink))
1ffac268
NR
1385 (cond
1386 ((eq sink 'user) t)
1387 ((eq sink 'emacs)
2cec1d1a 1388 (setq gdb-output-sink 'post-emacs))
1ffac268 1389 (t
cc615d5a 1390 (gdb-resync)
1ffac268
NR
1391 (error "Phase error in gdb-pre-prompt (got %s)" sink)))))
1392
1393(defun gdb-prompt (ignored)
1394 "An annotation handler for `prompt'.
1395This sends the next command (if any) to gdb."
25c7f315 1396 (when gdb-first-prompt
55222dc8 1397 (gdb-force-mode-line-update
303b246d 1398 (propertize "initializing..." 'face font-lock-variable-name-face))
25c7f315
NR
1399 (gdb-init-1)
1400 (setq gdb-first-prompt nil))
2cec1d1a 1401 (let ((sink gdb-output-sink))
1ffac268
NR
1402 (cond
1403 ((eq sink 'user) t)
1404 ((eq sink 'post-emacs)
2cec1d1a 1405 (setq gdb-output-sink 'user)
1ffac268 1406 (let ((handler
2cec1d1a 1407 (car (cdr gdb-current-item))))
f27d4d6c 1408 (with-current-buffer (gdb-get-buffer-create 'gdb-partial-output-buffer)
1ffac268
NR
1409 (funcall handler))))
1410 (t
cc615d5a 1411 (gdb-resync)
1ffac268
NR
1412 (error "Phase error in gdb-prompt (got %s)" sink))))
1413 (let ((input (gdb-dequeue-input)))
1414 (if input
1415 (gdb-send-item input)
1416 (progn
2cec1d1a 1417 (setq gdb-prompting t)
ef6cb9e8
NR
1418 (gud-display-frame)
1419 (setq gdb-early-user-input (nreverse gdb-early-user-input))
1420 (while gdb-early-user-input
1421 (gdb-enqueue-input (car gdb-early-user-input))
1422 (setq gdb-early-user-input (cdr gdb-early-user-input)))))))
1ffac268
NR
1423
1424(defun gdb-subprompt (ignored)
1425 "An annotation handler for non-top-level prompts."
2cec1d1a 1426 (setq gdb-prompting t))
1ffac268
NR
1427
1428(defun gdb-starting (ignored)
d94dccc6
SM
1429 "An annotation handler for `starting'.
1430This says that I/O for the subprocess is now the program being debugged,
1431not GDB."
9cc4d7dd 1432 (setq gdb-active-process t)
3e0b9c08 1433 (setq gdb-printing t)
2cec1d1a 1434 (let ((sink gdb-output-sink))
1ffac268
NR
1435 (cond
1436 ((eq sink 'user)
1437 (progn
1438 (setq gud-running t)
551b23f3
NR
1439 (setq gdb-stack-update t)
1440 ;; Temporarily set gud-running to nil to force "info stack" onto queue.
1441 (let ((gud-running nil))
1442 (gdb-invalidate-frames))
be08da22 1443 (setq gdb-inferior-status "running")
31af85eb 1444 (setq gdb-signalled nil)
303b246d
NR
1445 (gdb-force-mode-line-update
1446 (propertize gdb-inferior-status 'face font-lock-type-face))
a2c7d24f 1447 (gdb-remove-text-properties)
3e0b9c08 1448 (setq gud-old-arrow gud-overlay-arrow-position)
37c7ef17
NR
1449 (setq gud-overlay-arrow-position nil)
1450 (setq gdb-overlay-arrow-position nil)
9143202c 1451 (setq gdb-stack-position nil)
b5e5e9f2 1452 (if gdb-use-separate-io-buffer
2cec1d1a 1453 (setq gdb-output-sink 'inferior))))
bf247b6e 1454 (t
cc615d5a
NR
1455 (gdb-resync)
1456 (error "Unexpected `starting' annotation")))))
1ffac268 1457
be08da22
NR
1458(defun gdb-signal (ignored)
1459 (setq gdb-inferior-status "signal")
303b246d
NR
1460 (gdb-force-mode-line-update
1461 (propertize gdb-inferior-status 'face font-lock-warning-face))
be08da22
NR
1462 (gdb-stopping ignored))
1463
1ffac268 1464(defun gdb-stopping (ignored)
9cc4d7dd 1465 "An annotation handler for `breakpoint' and other annotations.
d94dccc6
SM
1466They say that I/O for the subprocess is now GDB, not the program
1467being debugged."
b5e5e9f2 1468 (if gdb-use-separate-io-buffer
2cec1d1a 1469 (let ((sink gdb-output-sink))
614963ba
NR
1470 (cond
1471 ((eq sink 'inferior)
2cec1d1a 1472 (setq gdb-output-sink 'user))
cc615d5a
NR
1473 (t
1474 (gdb-resync)
1475 (error "Unexpected stopping annotation"))))))
1ffac268 1476
9cc4d7dd
NR
1477(defun gdb-exited (ignored)
1478 "An annotation handler for `exited' and `signalled'.
1479They say that I/O for the subprocess is now GDB, not the program
1e5b5dc0 1480being debugged and that the program is no longer running. This
9cc4d7dd
NR
1481function is used to change the focus of GUD tooltips to #define
1482directives."
1483 (setq gdb-active-process nil)
4d7e2741
NR
1484 (setq gud-overlay-arrow-position nil)
1485 (setq gdb-overlay-arrow-position nil)
9143202c 1486 (setq gdb-stack-position nil)
3cfc0f43 1487 (setq gud-old-arrow nil)
be08da22 1488 (setq gdb-inferior-status "exited")
303b246d
NR
1489 (gdb-force-mode-line-update
1490 (propertize gdb-inferior-status 'face font-lock-warning-face))
9cc4d7dd 1491 (gdb-stopping ignored))
086d0593 1492
e75116ed
NR
1493(defun gdb-signalled (ignored)
1494 (setq gdb-signalled t))
1495
1ffac268 1496(defun gdb-frame-begin (ignored)
3e0b9c08
NR
1497 (setq gdb-frame-begin t)
1498 (setq gdb-printing nil)
2cec1d1a 1499 (let ((sink gdb-output-sink))
1ffac268
NR
1500 (cond
1501 ((eq sink 'inferior)
2cec1d1a 1502 (setq gdb-output-sink 'user))
1ffac268
NR
1503 ((eq sink 'user) t)
1504 ((eq sink 'emacs) t)
cc615d5a
NR
1505 (t
1506 (gdb-resync)
1507 (error "Unexpected frame-begin annotation (%S)" sink)))))
1ffac268 1508
05dfe89a 1509(defcustom gdb-same-frame (not focus-follows-mouse)
3e0b9c08 1510 "Non-nil means pop up GUD buffer in same frame."
86af339a 1511 :group 'gdb
3e0b9c08
NR
1512 :type 'boolean
1513 :version "22.1")
1514
a6c7c026
NR
1515(defcustom gdb-find-source-frame nil
1516 "Non-nil means try to find a source frame further up stack e.g after signal."
86af339a 1517 :group 'gdb
2b63aedb
NR
1518 :type 'boolean
1519 :version "22.1")
1520
a6c7c026 1521(defun gdb-find-source-frame (arg)
aa72bfb2
NR
1522 "Toggle looking for a source frame further up call stack.
1523The code associated with current (innermost) frame may not have
1524been compiled with debug information, e.g., C library routine.
e7f767c2 1525With prefix argument ARG, look for a source frame further up
aa72bfb2
NR
1526stack to display in the source buffer if ARG is positive,
1527otherwise don't look further up."
a6c7c026
NR
1528 (interactive "P")
1529 (setq gdb-find-source-frame
1530 (if (null arg)
1531 (not gdb-find-source-frame)
1532 (> (prefix-numeric-value arg) 0)))
1533 (message (format "Looking for source frame %sabled"
1534 (if gdb-find-source-frame "en" "dis"))))
1535
1ffac268 1536(defun gdb-stopped (ignored)
d94dccc6
SM
1537 "An annotation handler for `stopped'.
1538It is just like `gdb-stopping', except that if we already set the output
1539sink to `user' in `gdb-stopping', that is fine."
1ffac268 1540 (setq gud-running nil)
c1719ebf 1541 (unless (or gud-overlay-arrow-position gud-last-frame)
3e0b9c08
NR
1542 (if (and gdb-frame-begin gdb-printing)
1543 (setq gud-overlay-arrow-position gud-old-arrow)
c1719ebf 1544 ;;Pop up GUD buffer to display current frame when it doesn't have source
82bc67b8 1545 ;;information i.e if not compiled with -g as with libc routines generally.
3e0b9c08
NR
1546 (if gdb-same-frame
1547 (gdb-display-gdb-buffer)
1548 (gdb-frame-gdb-buffer))
2b63aedb 1549 (if gdb-find-source-frame
c1719ebf 1550 ;;Try to find source further up stack e.g after signal.
2b63aedb
NR
1551 (setq gdb-look-up-stack
1552 (if (gdb-get-buffer 'gdb-stack-buffer)
1553 'keep
1554 (progn
1555 (gdb-get-buffer-create 'gdb-stack-buffer)
1556 (gdb-invalidate-frames)
1557 'delete))))))
be08da22 1558 (unless (member gdb-inferior-status '("exited" "signal"))
82bc67b8 1559 (setq gdb-active-process t) ;Just for attaching case.
be08da22 1560 (setq gdb-inferior-status "stopped")
303b246d
NR
1561 (gdb-force-mode-line-update
1562 (propertize gdb-inferior-status 'face font-lock-warning-face)))
2cec1d1a 1563 (let ((sink gdb-output-sink))
1ffac268
NR
1564 (cond
1565 ((eq sink 'inferior)
2cec1d1a 1566 (setq gdb-output-sink 'user))
1ffac268 1567 ((eq sink 'user) t)
cc615d5a
NR
1568 (t
1569 (gdb-resync)
e75116ed
NR
1570 (error "Unexpected stopped annotation"))))
1571 (if gdb-signalled (gdb-exited ignored)))
1ffac268 1572
98c751fe
NR
1573(defun gdb-error (ignored)
1574 (setq gdb-error (not gdb-error)))
1575
22b6cf48
NR
1576(defun gdb-thread-changed (ignored)
1577 (gdb-frames-force-update))
1578
1ffac268 1579(defun gdb-post-prompt (ignored)
d94dccc6
SM
1580 "An annotation handler for `post-prompt'.
1581This begins the collection of output from the current command if that
1582happens to be appropriate."
92219924
NR
1583 ;; Don't add to queue if there outstanding items or gdb-version is not known
1584 ;; yet.
25c7f315 1585 (unless (or gdb-pending-triggers gdb-first-post-prompt)
1e539d25
NR
1586 (gdb-get-selected-frame)
1587 (gdb-invalidate-frames)
d47c318c 1588 ;; Regenerate breakpoints buffer in case it has been inadvertantly deleted.
f27d4d6c 1589 (gdb-get-buffer-create 'gdb-breakpoints-buffer)
1e539d25
NR
1590 (gdb-invalidate-breakpoints)
1591 ;; Do this through gdb-get-selected-frame -> gdb-frame-handler
ec180a26 1592 ;; so gdb-pc-address is updated.
1e539d25 1593 ;; (gdb-invalidate-assembler)
25c7f315
NR
1594
1595 (if (string-equal gdb-version "pre-6.4")
1596 (gdb-invalidate-registers)
621b3aac 1597 (gdb-get-changed-registers)
25c7f315
NR
1598 (gdb-invalidate-registers-1))
1599
1e539d25 1600 (gdb-invalidate-memory)
25c7f315
NR
1601 (if (string-equal gdb-version "pre-6.4")
1602 (gdb-invalidate-locals)
1603 (gdb-invalidate-locals-1))
1604
1e539d25 1605 (gdb-invalidate-threads)
34fb82b8
NR
1606 (unless (or (null gdb-var-list)
1607 (eq system-type 'darwin)) ;Breaks on Darwin's GDB-5.3.
1e539d25 1608 ;; FIXME: with GDB-6 on Darwin, this might very well work.
0fc89500 1609 ;; Only needed/used with speedbar/watch expressions.
1e539d25 1610 (when (and (boundp 'speedbar-frame) (frame-live-p speedbar-frame))
25c7f315
NR
1611 (if (string-equal gdb-version "pre-6.4")
1612 (gdb-var-update)
1613 (gdb-var-update-1)))))
1614 (setq gdb-first-post-prompt nil)
2cec1d1a 1615 (let ((sink gdb-output-sink))
1ffac268
NR
1616 (cond
1617 ((eq sink 'user) t)
1618 ((eq sink 'pre-emacs)
2cec1d1a 1619 (setq gdb-output-sink 'emacs))
1ffac268 1620 (t
cc615d5a 1621 (gdb-resync)
1ffac268
NR
1622 (error "Phase error in gdb-post-prompt (got %s)" sink)))))
1623
4a7d75e8
NR
1624(defconst gdb-buffer-list
1625'(gdb-stack-buffer gdb-locals-buffer gdb-registers-buffer gdb-threads-buffer))
1626
a2c7d24f 1627(defun gdb-remove-text-properties ()
4a7d75e8
NR
1628 (dolist (buffertype gdb-buffer-list)
1629 (let ((buffer (gdb-get-buffer buffertype)))
1630 (if buffer
1631 (with-current-buffer buffer
1632 (let ((inhibit-read-only t))
1633 (remove-text-properties
a2c7d24f 1634 (point-min) (point-max) '(mouse-face nil help-echo nil))))))))
4a7d75e8 1635
f27d4d6c
NR
1636;; GUD displays the selected GDB frame. This might might not be the current
1637;; GDB frame (after up, down etc). If no GDB frame is visible but the last
1638;; visited breakpoint is, use that window.
1639(defun gdb-display-source-buffer (buffer)
1640 (let* ((last-window (if gud-last-last-frame
1641 (get-buffer-window
1642 (gud-find-file (car gud-last-last-frame)))))
1643 (source-window (or last-window
1644 (if (and gdb-source-window
1645 (window-live-p gdb-source-window))
1646 gdb-source-window))))
1647 (when source-window
1648 (setq gdb-source-window source-window)
1649 (set-window-buffer source-window buffer))
1650 source-window))
1651
89525f8b
NR
1652;; Derived from gud-gdb-marker-regexp
1653(defvar gdb-fullname-regexp
1654 (concat "\\(.:?[^" ":" "\n]*\\)" ":" "\\([0-9]*\\)" ":" ".*"))
1655
1ffac268 1656(defun gud-gdba-marker-filter (string)
d94dccc6 1657 "A gud marker filter for gdb. Handle a burst of output from GDB."
7c511b96
NR
1658 (if gdb-flush-pending-output
1659 nil
a5de7508 1660 (when gdb-enable-debug
b35ef705
NR
1661 (push (cons 'recv string) gdb-debug-log)
1662 (if (and gdb-debug-log-max
1663 (> (length gdb-debug-log) gdb-debug-log-max))
1664 (setcdr (nthcdr (1- gdb-debug-log-max) gdb-debug-log) nil)))
0fc89500 1665 ;; Recall the left over gud-marker-acc from last time.
7c511b96 1666 (setq gud-marker-acc (concat gud-marker-acc string))
0fc89500 1667 ;; Start accumulating output for the GUD buffer.
7c511b96
NR
1668 (let ((output ""))
1669 ;;
1670 ;; Process all the complete markers in this chunk.
1671 (while (string-match "\n\032\032\\(.*\\)\n" gud-marker-acc)
89525f8b
NR
1672 (let ((annotation (match-string 1 gud-marker-acc))
1673 (before (substring gud-marker-acc 0 (match-beginning 0)))
1674 (after (substring gud-marker-acc (match-end 0))))
1ffac268 1675 ;;
7c511b96
NR
1676 ;; Parse the tag from the annotation, and maybe its arguments.
1677 (string-match "\\(\\S-*\\) ?\\(.*\\)" annotation)
1678 (let* ((annotation-type (match-string 1 annotation))
1679 (annotation-arguments (match-string 2 annotation))
1680 (annotation-rule (assoc annotation-type
14b26c33 1681 gdb-annotation-rules)))
89525f8b
NR
1682
1683 ;; Stuff prior to the match is just ordinary output.
1684 ;; It is either concatenated to OUTPUT or directed
1685 ;; elsewhere.
14b26c33 1686 (setq output (gdb-concat-output output before))
89525f8b
NR
1687
1688 ;; Take that stuff off the gud-marker-acc.
1689 (setq gud-marker-acc after)
1690
7c511b96
NR
1691 ;; Call the handler for this annotation.
1692 (if annotation-rule
1693 (funcall (car (cdr annotation-rule))
14b26c33 1694 annotation-arguments))
89525f8b
NR
1695
1696 ;; Else the annotation is not recognized. Ignore it silently,
1697 ;; so that GDB can add new annotations without causing
1698 ;; us to blow up.
1699 )))
1700
7c511b96
NR
1701 ;; Does the remaining text end in a partial line?
1702 ;; If it does, then keep part of the gud-marker-acc until we get more.
1703 (if (string-match "\n\\'\\|\n\032\\'\\|\n\032\032.*\\'"
1704 gud-marker-acc)
1705 (progn
1706 ;; Everything before the potential marker start can be output.
1707 (setq output
1708 (gdb-concat-output output
1709 (substring gud-marker-acc 0
1710 (match-beginning 0))))
1711 ;;
1712 ;; Everything after, we save, to combine with later input.
a0091778
NR
1713 (setq gud-marker-acc (substring gud-marker-acc
1714 (match-beginning 0))))
7c511b96
NR
1715 ;;
1716 ;; In case we know the gud-marker-acc contains no partial annotations:
1717 (progn
1718 (setq output (gdb-concat-output output gud-marker-acc))
1719 (setq gud-marker-acc "")))
1720 output)))
1ffac268
NR
1721
1722(defun gdb-concat-output (so-far new)
98c751fe
NR
1723 (if gdb-error
1724 (put-text-property 0 (length new) 'face font-lock-warning-face new))
2cec1d1a 1725 (let ((sink gdb-output-sink))
1ffac268
NR
1726 (cond
1727 ((eq sink 'user) (concat so-far new))
1728 ((or (eq sink 'pre-emacs) (eq sink 'post-emacs)) so-far)
1729 ((eq sink 'emacs)
1730 (gdb-append-to-partial-output new)
1731 so-far)
1732 ((eq sink 'inferior)
1733 (gdb-append-to-inferior-io new)
1734 so-far)
cc615d5a
NR
1735 (t
1736 (gdb-resync)
1737 (error "Bogon output sink %S" sink)))))
1ffac268
NR
1738
1739(defun gdb-append-to-partial-output (string)
f27d4d6c 1740 (with-current-buffer (gdb-get-buffer-create 'gdb-partial-output-buffer)
1ffac268
NR
1741 (goto-char (point-max))
1742 (insert string)))
1743
1744(defun gdb-clear-partial-output ()
f27d4d6c 1745 (with-current-buffer (gdb-get-buffer-create 'gdb-partial-output-buffer)
1ffac268
NR
1746 (erase-buffer)))
1747
1748(defun gdb-append-to-inferior-io (string)
f27d4d6c 1749 (with-current-buffer (gdb-get-buffer-create 'gdb-inferior-io)
1ffac268
NR
1750 (goto-char (point-max))
1751 (insert-before-markers string))
1752 (if (not (string-equal string ""))
d138996e 1753 (gdb-display-buffer (gdb-get-buffer-create 'gdb-inferior-io) t)))
1ffac268
NR
1754
1755(defun gdb-clear-inferior-io ()
f27d4d6c 1756 (with-current-buffer (gdb-get-buffer-create 'gdb-inferior-io)
1ffac268
NR
1757 (erase-buffer)))
1758\f
1759
1760;; One trick is to have a command who's output is always available in a buffer
1761;; of it's own, and is always up to date. We build several buffers of this
1762;; type.
1763;;
1764;; There are two aspects to this: gdb has to tell us when the output for that
1765;; command might have changed, and we have to be able to run the command
1766;; behind the user's back.
1767;;
1768;; The output phasing associated with the variable gdb-output-sink
1769;; help us to run commands behind the user's back.
1770;;
1771;; Below is the code for specificly managing buffers of output from one
1772;; command.
1773;;
1774
1775;; The trigger function is suitable for use in the assoc GDB-ANNOTATION-RULES
1776;; It adds an input for the command we are tracking. It should be the
1777;; annotation rule binding of whatever gdb sends to tell us this command
1778;; might have changed it's output.
1779;;
a0091778 1780;; NAME is the function name. DEMAND-PREDICATE tests if output is really needed.
1ffac268
NR
1781;; GDB-COMMAND is a string of such. OUTPUT-HANDLER is the function bound to the
1782;; input in the input queue (see comment about ``gdb communications'' above).
1783
1784(defmacro def-gdb-auto-update-trigger (name demand-predicate gdb-command
1785 output-handler)
1786 `(defun ,name (&optional ignored)
9317517c 1787 (if (and ,demand-predicate
1ffac268 1788 (not (member ',name
2cec1d1a 1789 gdb-pending-triggers)))
1ffac268
NR
1790 (progn
1791 (gdb-enqueue-input
1792 (list ,gdb-command ',output-handler))
2cec1d1a 1793 (push ',name gdb-pending-triggers)))))
1ffac268
NR
1794
1795(defmacro def-gdb-auto-update-handler (name trigger buf-key custom-defun)
1796 `(defun ,name ()
2cec1d1a 1797 (setq gdb-pending-triggers
1ffac268 1798 (delq ',trigger
2cec1d1a 1799 gdb-pending-triggers))
1ffac268
NR
1800 (let ((buf (gdb-get-buffer ',buf-key)))
1801 (and buf
1802 (with-current-buffer buf
974be7ce 1803 (let* ((window (get-buffer-window buf 0))
f27d4d6c 1804 (start (window-start window))
974be7ce 1805 (p (window-point window))
1ffac268
NR
1806 (buffer-read-only nil))
1807 (erase-buffer)
f27d4d6c 1808 (insert-buffer-substring (gdb-get-buffer-create
1ffac268 1809 'gdb-partial-output-buffer))
f27d4d6c 1810 (set-window-start window start)
974be7ce 1811 (set-window-point window p)))))
1ffac268
NR
1812 ;; put customisation here
1813 (,custom-defun)))
1814
a0091778
NR
1815(defmacro def-gdb-auto-updated-buffer (buffer-key
1816 trigger-name gdb-command
1817 output-handler-name custom-defun)
1ffac268
NR
1818 `(progn
1819 (def-gdb-auto-update-trigger ,trigger-name
1820 ;; The demand predicate:
9317517c 1821 (gdb-get-buffer ',buffer-key)
1ffac268
NR
1822 ,gdb-command
1823 ,output-handler-name)
1824 (def-gdb-auto-update-handler ,output-handler-name
1825 ,trigger-name ,buffer-key ,custom-defun)))
1826
1827\f
1828;;
1829;; Breakpoint buffer : This displays the output of `info breakpoints'.
1830;;
1831(gdb-set-buffer-rules 'gdb-breakpoints-buffer
1832 'gdb-breakpoints-buffer-name
1833 'gdb-breakpoints-mode)
1834
1835(def-gdb-auto-updated-buffer gdb-breakpoints-buffer
1836 ;; This defines the auto update rule for buffers of type
1837 ;; `gdb-breakpoints-buffer'.
1838 ;;
1839 ;; It defines a function to serve as the annotation handler that
1840 ;; handles the `foo-invalidated' message. That function is called:
1841 gdb-invalidate-breakpoints
1842 ;;
1843 ;; To update the buffer, this command is sent to gdb.
1844 "server info breakpoints\n"
1845 ;;
1846 ;; This also defines a function to be the handler for the output
1847 ;; from the command above. That function will copy the output into
1848 ;; the appropriately typed buffer. That function will be called:
1849 gdb-info-breakpoints-handler
1850 ;; buffer specific functions
1851 gdb-info-breakpoints-custom)
1852
b6d0e4da
NR
1853(defconst breakpoint-xpm-data
1854 "/* XPM */
1ffac268
NR
1855static char *magick[] = {
1856/* columns rows colors chars-per-pixel */
1857\"10 10 2 1\",
1858\" c red\",
1859\"+ c None\",
1860/* pixels */
1861\"+++ +++\",
1862\"++ ++\",
1863\"+ +\",
1864\" \",
1865\" \",
1866\" \",
1867\" \",
1868\"+ +\",
1869\"++ ++\",
1870\"+++ +++\",
1871};"
1872 "XPM data used for breakpoint icon.")
1873
1874(defconst breakpoint-enabled-pbm-data
b6d0e4da 1875 "P1
1ffac268
NR
187610 10\",
18770 0 0 0 1 1 1 1 0 0 0 0
18780 0 0 1 1 1 1 1 1 0 0 0
18790 0 1 1 1 1 1 1 1 1 0 0
18800 1 1 1 1 1 1 1 1 1 1 0
18810 1 1 1 1 1 1 1 1 1 1 0
18820 1 1 1 1 1 1 1 1 1 1 0
18830 1 1 1 1 1 1 1 1 1 1 0
18840 0 1 1 1 1 1 1 1 1 0 0
18850 0 0 1 1 1 1 1 1 0 0 0
18860 0 0 0 1 1 1 1 0 0 0 0"
1887 "PBM data used for enabled breakpoint icon.")
1888
1889(defconst breakpoint-disabled-pbm-data
b6d0e4da 1890 "P1
1ffac268
NR
189110 10\",
18920 0 1 0 1 0 1 0 0 0
18930 1 0 1 0 1 0 1 0 0
18941 0 1 0 1 0 1 0 1 0
18950 1 0 1 0 1 0 1 0 1
18961 0 1 0 1 0 1 0 1 0
18970 1 0 1 0 1 0 1 0 1
18981 0 1 0 1 0 1 0 1 0
18990 1 0 1 0 1 0 1 0 1
19000 0 1 0 1 0 1 0 1 0
19010 0 0 1 0 1 0 1 0 0"
1902 "PBM data used for disabled breakpoint icon.")
1903
1904(defvar breakpoint-enabled-icon nil
d94dccc6 1905 "Icon for enabled breakpoint in display margin.")
1ffac268
NR
1906
1907(defvar breakpoint-disabled-icon nil
d94dccc6 1908 "Icon for disabled breakpoint in display margin.")
1ffac268 1909
aa360da1
GM
1910(declare-function define-fringe-bitmap "fringe.c"
1911 (bitmap bits &optional height width align))
1912
9788e74e 1913(and (display-images-p)
5dfe9b2b 1914 ;; Bitmap for breakpoint in fringe
9788e74e 1915 (define-fringe-bitmap 'breakpoint
5dfe9b2b
NR
1916 "\x3c\x7e\xff\xff\xff\xff\x7e\x3c")
1917 ;; Bitmap for gud-overlay-arrow in fringe
1918 (define-fringe-bitmap 'hollow-right-triangle
1919 "\xe0\x90\x88\x84\x84\x88\x90\xe0"))
1ffac268 1920
e38b967a 1921(defface breakpoint-enabled
c29749e7 1922 '((t
5183d4c9 1923 :foreground "red1"
c29749e7 1924 :weight bold))
619b6adb 1925 "Face for enabled breakpoint icon in fringe."
86af339a 1926 :group 'gdb)
1ffac268 1927
e38b967a 1928(defface breakpoint-disabled
109a7709
NR
1929 '((((class color) (min-colors 88)) :foreground "grey70")
1930 ;; Ensure that on low-color displays that we end up something visible.
1931 (((class color) (min-colors 8) (background light))
1932 :foreground "black")
1933 (((class color) (min-colors 8) (background dark))
1934 :foreground "white")
1935 (((type tty) (class mono))
1936 :inverse-video t)
1937 (t :background "gray"))
619b6adb 1938 "Face for disabled breakpoint icon in fringe."
86af339a 1939 :group 'gdb)
1ffac268 1940
5754d11f 1941(defconst gdb-breakpoint-regexp
266e779b 1942 "\\(?:\\([0-9]+\\).*?\\(?:point\\|catch\\s-+\\S-+\\)\\s-+\\S-+\\|\\([0-9]+\\.[0-9]+\\)\\)\\s-+\\(.\\)\\s-+")
5754d11f 1943
0fc89500 1944;; Put breakpoint icons in relevant margins (even those set in the GUD buffer).
1ffac268 1945(defun gdb-info-breakpoints-custom ()
b6d0e4da 1946 (let ((flag) (bptno))
0fc89500 1947 ;; Remove all breakpoint-icons in source buffers but not assembler buffer.
1ffac268
NR
1948 (dolist (buffer (buffer-list))
1949 (with-current-buffer buffer
621b3aac 1950 (if (and (memq gud-minor-mode '(gdba gdbmi))
6c8aa2cd 1951 (not (string-match "\\` ?\\*.+\\*\\'" (buffer-name))))
1ffac268
NR
1952 (gdb-remove-breakpoint-icons (point-min) (point-max)))))
1953 (with-current-buffer (gdb-get-buffer 'gdb-breakpoints-buffer)
1954 (save-excursion
a9502111 1955 (let ((buffer-read-only nil))
05a27ce5
NR
1956 (goto-char (point-min))
1957 (while (< (point) (- (point-max) 1))
1958 (forward-line 1)
1959 (if (looking-at gdb-breakpoint-regexp)
1960 (progn
1961 (setq bptno (or (match-string 1) (match-string 2)))
1962 (setq flag (char-after (match-beginning 3)))
1963 (if (match-string 1)
1964 (setq gdb-parent-bptno-enabled (eq flag ?y)))
1965 (add-text-properties
1966 (match-beginning 3) (match-end 3)
1967 (if (eq flag ?y)
1968 '(face font-lock-warning-face)
1969 '(face font-lock-type-face)))
1970 (let ((bl (point))
1971 (el (line-end-position)))
1972 (when (re-search-forward " in \\(.*\\) at" el t)
a9502111
NR
1973 (add-text-properties
1974 (match-beginning 1) (match-end 1)
05a27ce5 1975 '(face font-lock-function-name-face)))
d5ec6bc0 1976 (if (re-search-forward
959005e4 1977 ".*\\s-+\\(\\S-+\\):\\([0-9]+\\)$" el t)
7443a638
NR
1978 (let ((line (match-string 2))
1979 (file (match-string 1)))
1980 (add-text-properties bl el
d5ec6bc0
NR
1981 '(mouse-face highlight
1982 help-echo "mouse-2, RET: visit breakpoint"))
7443a638
NR
1983 (unless (file-exists-p file)
1984 (setq file (cdr (assoc bptno gdb-location-alist))))
1985 (if (and file
1986 (not (string-equal file "File not found")))
1987 (with-current-buffer
1988 (find-file-noselect file 'nowarn)
6c6273c6 1989 (gdb-init-buffer)
7443a638
NR
1990 ;; Only want one breakpoint icon at each
1991 ;; location.
1992 (save-excursion
1993 (goto-line (string-to-number line))
1994 (gdb-put-breakpoint-icon (eq flag ?y) bptno)))
1995 (gdb-enqueue-input
1996 (list
1997 (concat gdb-server-prefix "list "
1998 (match-string-no-properties 1) ":1\n")
1999 'ignore))
2000 (gdb-enqueue-input
2001 (list (concat gdb-server-prefix "info source\n")
2002 `(lambda () (gdb-get-location
05a27ce5
NR
2003 ,bptno ,line ,flag))))))
2004 (if (re-search-forward
2005 "<\\(\\(\\sw\\|[_.]\\)+\\)\\(\\+[0-9]+\\)?>"
2006 el t)
2007 (add-text-properties
2008 (match-beginning 1) (match-end 1)
2009 '(face font-lock-function-name-face))
2010 (end-of-line)
2011 (re-search-backward "\\s-\\(\\S-*\\)"
2012 bl t)
7443a638
NR
2013 (add-text-properties
2014 (match-beginning 1) (match-end 1)
05a27ce5
NR
2015 '(face font-lock-variable-name-face)))))))
2016 (end-of-line))))))
551b23f3
NR
2017 (if (gdb-get-buffer 'gdb-assembler-buffer) (gdb-assembler-custom))
2018
2019 ;; Breakpoints buffer is always present. Hack to just update
2020 ;; current frame if there's been no execution.
2021 (if gdb-stack-update
2022 (setq gdb-stack-update nil)
2023 (if (gdb-get-buffer 'gdb-stack-buffer) (gdb-info-stack-custom))))
1ffac268 2024
3092d1fb
GM
2025(declare-function gud-remove "gdb-ui" t t) ; gud-def
2026(declare-function gud-break "gdb-ui" t t) ; gud-def
aa360da1 2027(declare-function fringe-bitmaps-at-pos "fringe.c" (&optional pos window))
3092d1fb 2028
b6d0e4da 2029(defun gdb-mouse-set-clear-breakpoint (event)
79669f88
NR
2030 "Set/clear breakpoint in left fringe/margin at mouse click.
2031If not in a source or disassembly buffer just set point."
1ffac268
NR
2032 (interactive "e")
2033 (mouse-minibuffer-check event)
2034 (let ((posn (event-end event)))
b06e477e
NR
2035 (with-selected-window (posn-window posn)
2036 (if (or (buffer-file-name) (eq major-mode 'gdb-assembler-mode))
2037 (if (numberp (posn-point posn))
a03392ff
NR
2038 (save-excursion
2039 (goto-char (posn-point posn))
2040 (if (or (posn-object posn)
2041 (eq (car (fringe-bitmaps-at-pos (posn-point posn)))
2042 'breakpoint))
2043 (gud-remove nil)
2044 (gud-break nil)))))
2045 (posn-set-point posn))))
1ffac268 2046
64ef03e9
KS
2047(defun gdb-mouse-toggle-breakpoint-margin (event)
2048 "Enable/disable breakpoint in left margin with mouse click."
b6d0e4da
NR
2049 (interactive "e")
2050 (mouse-minibuffer-check event)
2051 (let ((posn (event-end event)))
2052 (if (numberp (posn-point posn))
2053 (with-selected-window (posn-window posn)
2054 (save-excursion
2055 (goto-char (posn-point posn))
0fc89500 2056 (if (posn-object posn)
266e779b
NR
2057 (let* ((bptno (get-text-property
2058 0 'gdb-bptno (car (posn-string posn)))))
2059 (string-match "\\([0-9+]\\)*" bptno)
2060 (gdb-enqueue-input
2061 (list
be1c9844 2062 (concat gdb-server-prefix
b6d0e4da
NR
2063 (if (get-text-property
2064 0 'gdb-enabled (car (posn-string posn)))
2065 "disable "
2066 "enable ")
266e779b
NR
2067 (match-string 1 bptno) "\n")
2068 'ignore)))))))))
64ef03e9
KS
2069
2070(defun gdb-mouse-toggle-breakpoint-fringe (event)
2071 "Enable/disable breakpoint in left fringe with mouse click."
2072 (interactive "e")
2073 (mouse-minibuffer-check event)
2074 (let* ((posn (event-end event))
2075 (pos (posn-point posn))
2076 obj)
2077 (when (numberp pos)
2078 (with-selected-window (posn-window posn)
2079 (save-excursion
2080 (set-buffer (window-buffer (selected-window)))
2081 (goto-char pos)
2082 (dolist (overlay (overlays-in pos pos))
2083 (when (overlay-get overlay 'put-break)
2084 (setq obj (overlay-get overlay 'before-string))))
2085 (when (stringp obj)
266e779b
NR
2086 (let* ((bptno (get-text-property 0 'gdb-bptno obj)))
2087 (string-match "\\([0-9+]\\)*" bptno)
2088 (gdb-enqueue-input
2089 (list
2090 (concat gdb-server-prefix
2091 (if (get-text-property 0 'gdb-enabled obj)
2092 "disable "
2093 "enable ")
2094 (match-string 1 bptno) "\n")
2095 'ignore)))))))))
b6d0e4da 2096
1ffac268
NR
2097(defun gdb-breakpoints-buffer-name ()
2098 (with-current-buffer gud-comint-buffer
2099 (concat "*breakpoints of " (gdb-get-target-string) "*")))
2100
2101(defun gdb-display-breakpoints-buffer ()
f6a2315e 2102 "Display status of user-settable breakpoints."
1ffac268
NR
2103 (interactive)
2104 (gdb-display-buffer
d138996e 2105 (gdb-get-buffer-create 'gdb-breakpoints-buffer) t))
1ffac268
NR
2106
2107(defun gdb-frame-breakpoints-buffer ()
f6a2315e 2108 "Display status of user-settable breakpoints in a new frame."
1ffac268 2109 (interactive)
1a9203d0
NR
2110 (let ((special-display-regexps (append special-display-regexps '(".*")))
2111 (special-display-frame-alist gdb-frame-parameters))
f27d4d6c 2112 (display-buffer (gdb-get-buffer-create 'gdb-breakpoints-buffer))))
1ffac268
NR
2113
2114(defvar gdb-breakpoints-mode-map
2115 (let ((map (make-sparse-keymap))
2116 (menu (make-sparse-keymap "Breakpoints")))
621b3aac 2117 (define-key menu [quit] '("Quit" . gdb-delete-frame-or-window))
1ffac268 2118 (define-key menu [goto] '("Goto" . gdb-goto-breakpoint))
0d43db4d
NR
2119 (define-key menu [delete] '("Delete" . gdb-delete-breakpoint))
2120 (define-key menu [toggle] '("Toggle" . gdb-toggle-breakpoint))
1ffac268
NR
2121 (suppress-keymap map)
2122 (define-key map [menu-bar breakpoints] (cons "Breakpoints" menu))
2123 (define-key map " " 'gdb-toggle-breakpoint)
9f6efa0c 2124 (define-key map "D" 'gdb-delete-breakpoint)
d47c318c
NR
2125 ;; Don't bind "q" to kill-this-buffer as we need it for breakpoint icons.
2126 (define-key map "q" 'gdb-delete-frame-or-window)
1ffac268 2127 (define-key map "\r" 'gdb-goto-breakpoint)
f2fc1724 2128 (define-key map [mouse-2] 'gdb-goto-breakpoint)
0d43db4d 2129 (define-key map [follow-link] 'mouse-face)
1ffac268
NR
2130 map))
2131
d47c318c
NR
2132(defun gdb-delete-frame-or-window ()
2133 "Delete frame if there is only one window. Otherwise delete the window."
2134 (interactive)
2135 (if (one-window-p) (delete-frame)
2136 (delete-window)))
2137
b06e477e
NR
2138;;from make-mode-line-mouse-map
2139(defun gdb-make-header-line-mouse-map (mouse function) "\
2140Return a keymap with single entry for mouse key MOUSE on the header line.
2141MOUSE is defined to run function FUNCTION with no args in the buffer
2142corresponding to the mode line clicked."
2143 (let ((map (make-sparse-keymap)))
2144 (define-key map (vector 'header-line mouse) function)
2145 (define-key map (vector 'header-line 'down-mouse-1) 'ignore)
2146 map))
2147
2148(defvar gdb-breakpoints-header
2149 `(,(propertize "Breakpoints"
2150 'help-echo "mouse-1: select"
2151 'mouse-face 'mode-line-highlight
2152 'face 'mode-line
2153 'local-map
2154 (gdb-make-header-line-mouse-map
2155 'mouse-1
2156 (lambda (event) (interactive "e")
2157 (save-selected-window
2158 (select-window (posn-window (event-start event)))
2159 (set-window-dedicated-p (selected-window) nil)
2160 (switch-to-buffer
2161 (gdb-get-buffer-create 'gdb-breakpoints-buffer))
2162 (set-window-dedicated-p (selected-window) t)))))
2163 " "
2164 ,(propertize "Threads"
2165 'help-echo "mouse-1: select"
2166 'mouse-face 'mode-line-highlight
2167 'face 'mode-line
2168 'local-map
2169 (gdb-make-header-line-mouse-map
2170 'mouse-1
2171 (lambda (event) (interactive "e")
2172 (save-selected-window
2173 (select-window (posn-window (event-start event)))
2174 (set-window-dedicated-p (selected-window) nil)
2175 (switch-to-buffer
2176 (gdb-get-buffer-create 'gdb-threads-buffer))
2177 (set-window-dedicated-p (selected-window) t)))))))
2178
1ffac268
NR
2179(defun gdb-breakpoints-mode ()
2180 "Major mode for gdb breakpoints.
2181
2182\\{gdb-breakpoints-mode-map}"
fad137cd 2183 (kill-all-local-variables)
1ffac268
NR
2184 (setq major-mode 'gdb-breakpoints-mode)
2185 (setq mode-name "Breakpoints")
2186 (use-local-map gdb-breakpoints-mode-map)
2187 (setq buffer-read-only t)
5a1ad629 2188 (buffer-disable-undo)
b06e477e 2189 (setq header-line-format gdb-breakpoints-header)
fad137cd 2190 (run-mode-hooks 'gdb-breakpoints-mode-hook)
36188c5e 2191 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
fad137cd
NR
2192 'gdb-invalidate-breakpoints
2193 'gdbmi-invalidate-breakpoints))
1ffac268
NR
2194
2195(defun gdb-toggle-breakpoint ()
b6d0e4da 2196 "Enable/disable breakpoint at current line."
1ffac268
NR
2197 (interactive)
2198 (save-excursion
2199 (beginning-of-line 1)
621b3aac 2200 (if (looking-at gdb-breakpoint-regexp)
7731023b
NR
2201 (gdb-enqueue-input
2202 (list
2203 (concat gdb-server-prefix
266e779b 2204 (if (eq ?y (char-after (match-beginning 3)))
7731023b
NR
2205 "disable "
2206 "enable ")
266e779b 2207 (or (match-string 1) (match-string 2)) "\n") 'ignore))
7731023b 2208 (error "Not recognized as break/watchpoint line"))))
1ffac268
NR
2209
2210(defun gdb-delete-breakpoint ()
2211 "Delete the breakpoint at current line."
2212 (interactive)
266e779b
NR
2213 (save-excursion
2214 (beginning-of-line 1)
2215 (if (looking-at gdb-breakpoint-regexp)
2216 (if (match-string 1)
2217 (gdb-enqueue-input
2218 (list
2219 (concat gdb-server-prefix "delete " (match-string 1) "\n")
2220 'ignore))
2221 (message-box "This breakpoint cannot be deleted on its own."))
2222 (error "Not recognized as break/watchpoint line"))))
1ffac268 2223
f2fc1724 2224(defun gdb-goto-breakpoint (&optional event)
f6a2315e 2225 "Display the breakpoint location specified at current line."
f2fc1724 2226 (interactive (list last-input-event))
53f18ed2 2227 (if event (posn-set-point (event-end event)))
1ffac268
NR
2228 (save-excursion
2229 (beginning-of-line 1)
841b19a0 2230 (if (looking-at "\\([0-9]+\\.?[0-9]*\\) .*\\s-+\\(\\S-+\\):\\([0-9]+\\)$")
94cd554a
NR
2231 (let ((bptno (match-string 1))
2232 (file (match-string 2))
2233 (line (match-string 3)))
7731023b 2234 (save-selected-window
f27d4d6c 2235 (let* ((buffer (find-file-noselect
1a032087 2236 (if (file-exists-p file) file
a0091778 2237 (cdr (assoc bptno gdb-location-alist)))))
0745bc2e 2238 (window (or (gdb-display-source-buffer buffer)
f27d4d6c
NR
2239 (display-buffer buffer))))
2240 (setq gdb-source-window window)
2241 (with-current-buffer buffer
7731023b
NR
2242 (goto-line (string-to-number line))
2243 (set-window-point window (point))))))
621b3aac 2244 (error "No location specified."))))
1ffac268 2245\f
f2fc1724 2246
841b19a0 2247;; Frames buffer. This displays a perpetually correct backtrace
1ffac268
NR
2248;; (from the command `where').
2249;;
2250;; Alas, if your stack is deep, it is costly.
2251;;
0ebd837a
NR
2252(defcustom gdb-max-frames 40
2253 "Maximum number of frames displayed in call stack."
2254 :type 'integer
86af339a 2255 :group 'gdb
0ebd837a
NR
2256 :version "22.1")
2257
1ffac268
NR
2258(gdb-set-buffer-rules 'gdb-stack-buffer
2259 'gdb-stack-buffer-name
2260 'gdb-frames-mode)
2261
2262(def-gdb-auto-updated-buffer gdb-stack-buffer
2263 gdb-invalidate-frames
0ebd837a 2264 (concat "server info stack " (number-to-string gdb-max-frames) "\n")
5dfe9b2b
NR
2265 gdb-info-stack-handler
2266 gdb-info-stack-custom)
1ffac268 2267
551b23f3
NR
2268;; This may be more important for embedded targets where unwinding the
2269;; stack may take a long time.
2270(defadvice gdb-invalidate-frames (around gdb-invalidate-frames-advice
2271 (&optional ignored) activate compile)
2272 "Only queue \"info stack\" if execution has occurred."
2273 (if gdb-stack-update ad-do-it))
2274
5dfe9b2b 2275(defun gdb-info-stack-custom ()
1ffac268 2276 (with-current-buffer (gdb-get-buffer 'gdb-stack-buffer)
31c4b81d
NR
2277 (let (move-to)
2278 (save-excursion
2279 (unless (eq gdb-look-up-stack 'delete)
2280 (let ((buffer-read-only nil)
2281 bl el)
c1719ebf 2282 (goto-char (point-min))
31c4b81d
NR
2283 (while (< (point) (point-max))
2284 (setq bl (line-beginning-position)
2285 el (line-end-position))
2286 (when (looking-at "#")
2287 (add-text-properties bl el
72ba4f36
NR
2288 '(mouse-face highlight
2289 help-echo "mouse-2, RET: Select frame")))
31c4b81d
NR
2290 (goto-char bl)
2291 (when (looking-at "^#\\([0-9]+\\)")
2292 (when (string-equal (match-string 1) gdb-frame-number)
72ba4f36 2293 (if (gud-tool-bar-item-visible-no-fringe)
31c4b81d 2294 (progn
72ba4f36
NR
2295 (put-text-property bl (+ bl 4)
2296 'face '(:inverse-video t))
2297 (setq move-to bl))
2298 (or gdb-stack-position
2299 (setq gdb-stack-position (make-marker)))
2300 (set-marker gdb-stack-position (point))
2301 (setq move-to gdb-stack-position)))
707ae152 2302 (when (re-search-forward "\\([^ ]+\\) (" el t)
31c4b81d
NR
2303 (put-text-property (match-beginning 1) (match-end 1)
2304 'face font-lock-function-name-face)
2305 (setq bl (match-end 0))
2306 (while (re-search-forward "<\\([^>]+\\)>" el t)
2307 (put-text-property (match-beginning 1) (match-end 1)
2308 'face font-lock-function-name-face))
2309 (goto-char bl)
2310 (while (re-search-forward "\\(\\(\\sw\\|[_.]\\)+\\)=" el t)
2311 (put-text-property (match-beginning 1) (match-end 1)
2312 'face font-lock-variable-name-face))))
2313 (forward-line 1))
2314 (forward-line -1)
2315 (when (looking-at "(More stack frames follow...)")
37c72343
NR
2316 (add-text-properties
2317 (match-beginning 0) (match-end 0)
2318 '(mouse-face highlight
2319 gdb-max-frames t
2320 help-echo
2321 "mouse-2, RET: customize gdb-max-frames to see more frames"
2322 )))))
31c4b81d
NR
2323 (when gdb-look-up-stack
2324 (goto-char (point-min))
2325 (when (re-search-forward "\\(\\S-+?\\):\\([0-9]+\\)" nil t)
2326 (let ((start (line-beginning-position))
2327 (file (match-string 1))
2328 (line (match-string 2)))
2329 (re-search-backward "^#*\\([0-9]+\\)" start t)
2330 (gdb-enqueue-input
2331 (list (concat gdb-server-prefix "frame "
2332 (match-string 1) "\n") 'gdb-set-hollow))
2333 (gdb-enqueue-input
2334 (list (concat gdb-server-prefix "frame 0\n") 'ignore))))))
2335 (when move-to
2336 (let ((window (get-buffer-window (current-buffer) 0)))
2337 (when window
2338 (with-selected-window window
2339 (goto-char move-to)
2340 (unless (pos-visible-in-window-p)
2341 (recenter '(center)))))))))
c1719ebf
NR
2342 (if (eq gdb-look-up-stack 'delete)
2343 (kill-buffer (gdb-get-buffer 'gdb-stack-buffer)))
2344 (setq gdb-look-up-stack nil))
2345
2346(defun gdb-set-hollow ()
c534076c
NR
2347 (if gud-last-last-frame
2348 (with-current-buffer (gud-find-file (car gud-last-last-frame))
2349 (setq fringe-indicator-alist
2350 '((overlay-arrow . hollow-right-triangle))))))
1ffac268
NR
2351
2352(defun gdb-stack-buffer-name ()
2353 (with-current-buffer gud-comint-buffer
2354 (concat "*stack frames of " (gdb-get-target-string) "*")))
2355
2356(defun gdb-display-stack-buffer ()
f6a2315e 2357 "Display backtrace of current stack."
1ffac268
NR
2358 (interactive)
2359 (gdb-display-buffer
d138996e 2360 (gdb-get-buffer-create 'gdb-stack-buffer) t))
1ffac268
NR
2361
2362(defun gdb-frame-stack-buffer ()
f6a2315e 2363 "Display backtrace of current stack in a new frame."
1ffac268 2364 (interactive)
1a9203d0
NR
2365 (let ((special-display-regexps (append special-display-regexps '(".*")))
2366 (special-display-frame-alist gdb-frame-parameters))
f27d4d6c 2367 (display-buffer (gdb-get-buffer-create 'gdb-stack-buffer))))
1ffac268
NR
2368
2369(defvar gdb-frames-mode-map
2370 (let ((map (make-sparse-keymap)))
2371 (suppress-keymap map)
12032009 2372 (define-key map "q" 'kill-this-buffer)
1ffac268 2373 (define-key map "\r" 'gdb-frames-select)
551b23f3 2374 (define-key map "F" 'gdb-frames-force-update)
f2fc1724 2375 (define-key map [mouse-2] 'gdb-frames-select)
0d43db4d 2376 (define-key map [follow-link] 'mouse-face)
1ffac268
NR
2377 map))
2378
b218f371
GM
2379(declare-function gdbmi-invalidate-frames "ext:gdb-mi" nil t)
2380
551b23f3
NR
2381(defun gdb-frames-force-update ()
2382 "Force update of call stack.
2383Use when the displayed call stack gets out of sync with the
2384actual one, e.g after using the Gdb command \"return\" or setting
2385$pc directly from the GUD buffer. This command isn't normally needed."
2386 (interactive)
2387 (setq gdb-stack-update t)
2388 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
2389 (gdb-invalidate-frames)
2390 (gdbmi-invalidate-frames)))
2391
1ffac268 2392(defun gdb-frames-mode ()
5dfe9b2b 2393 "Major mode for gdb call stack.
1ffac268
NR
2394
2395\\{gdb-frames-mode-map}"
fad137cd 2396 (kill-all-local-variables)
1ffac268
NR
2397 (setq major-mode 'gdb-frames-mode)
2398 (setq mode-name "Frames")
55222dc8 2399 (setq gdb-stack-position nil)
9143202c 2400 (add-to-list 'overlay-arrow-variable-list 'gdb-stack-position)
d4a574c0 2401 (setq truncate-lines t) ;; Make it easier to see overlay arrow.
1ffac268 2402 (setq buffer-read-only t)
5a1ad629 2403 (buffer-disable-undo)
59ae3049 2404 (gdb-thread-identification)
1ffac268 2405 (use-local-map gdb-frames-mode-map)
fad137cd 2406 (run-mode-hooks 'gdb-frames-mode-hook)
551b23f3 2407 (setq gdb-stack-update t)
36188c5e 2408 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
fad137cd
NR
2409 'gdb-invalidate-frames
2410 'gdbmi-invalidate-frames))
1ffac268
NR
2411
2412(defun gdb-get-frame-number ()
2413 (save-excursion
475a41c9 2414 (end-of-line)
9f6efa0c
NR
2415 (let* ((start (line-beginning-position))
2416 (pos (re-search-backward "^#*\\([0-9]+\\)" start t))
0ebd837a 2417 (n (or (and pos (match-string 1)) "0")))
1ffac268
NR
2418 n)))
2419
f2fc1724 2420(defun gdb-frames-select (&optional event)
f6a2315e 2421 "Select the frame and display the relevant source."
f2fc1724 2422 (interactive (list last-input-event))
53f18ed2 2423 (if event (posn-set-point (event-end event)))
0ebd837a
NR
2424 (if (get-text-property (point) 'gdb-max-frames)
2425 (progn
2426 (message-box "After setting gdb-max-frames, you need to enter\n\
2427another GDB command e.g pwd, to see new frames")
2428 (customize-variable-other-window 'gdb-max-frames))
2429 (gdb-enqueue-input
2430 (list (concat gdb-server-prefix "frame "
2431 (gdb-get-frame-number) "\n") 'ignore))))
1ffac268 2432\f
f2fc1724 2433
1ffac268
NR
2434;; Threads buffer. This displays a selectable thread list.
2435;;
2436(gdb-set-buffer-rules 'gdb-threads-buffer
2437 'gdb-threads-buffer-name
2438 'gdb-threads-mode)
2439
2440(def-gdb-auto-updated-buffer gdb-threads-buffer
2441 gdb-invalidate-threads
2cec1d1a 2442 (concat gdb-server-prefix "info threads\n")
1ffac268
NR
2443 gdb-info-threads-handler
2444 gdb-info-threads-custom)
2445
2446(defun gdb-info-threads-custom ()
2447 (with-current-buffer (gdb-get-buffer 'gdb-threads-buffer)
2448 (let ((buffer-read-only nil))
c1719ebf
NR
2449 (save-excursion
2450 (goto-char (point-min))
59ae3049
NR
2451 (if (re-search-forward "\\* \\([0-9]+\\)" nil t)
2452 (setq gdb-thread-indicator
2453 (propertize (concat " [" (match-string 1) "]")
2454 ; FIXME: this help-echo doesn't work
2455 'help-echo "thread id")))
2456 (goto-char (point-min))
c1719ebf
NR
2457 (while (< (point) (point-max))
2458 (unless (looking-at "No ")
2459 (add-text-properties (line-beginning-position) (line-end-position)
2460 '(mouse-face highlight
4d7e2741 2461 help-echo "mouse-2, RET: select thread")))
c1719ebf 2462 (forward-line 1))))))
1ffac268
NR
2463
2464(defun gdb-threads-buffer-name ()
2465 (with-current-buffer gud-comint-buffer
2466 (concat "*threads of " (gdb-get-target-string) "*")))
2467
2468(defun gdb-display-threads-buffer ()
f6a2315e 2469 "Display IDs of currently known threads."
1ffac268
NR
2470 (interactive)
2471 (gdb-display-buffer
d138996e 2472 (gdb-get-buffer-create 'gdb-threads-buffer) t))
1ffac268
NR
2473
2474(defun gdb-frame-threads-buffer ()
f6a2315e 2475 "Display IDs of currently known threads in a new frame."
1ffac268 2476 (interactive)
1a9203d0
NR
2477 (let ((special-display-regexps (append special-display-regexps '(".*")))
2478 (special-display-frame-alist gdb-frame-parameters))
f27d4d6c 2479 (display-buffer (gdb-get-buffer-create 'gdb-threads-buffer))))
1ffac268
NR
2480
2481(defvar gdb-threads-mode-map
2482 (let ((map (make-sparse-keymap)))
2483 (suppress-keymap map)
12032009 2484 (define-key map "q" 'kill-this-buffer)
1ffac268 2485 (define-key map "\r" 'gdb-threads-select)
f2fc1724 2486 (define-key map [mouse-2] 'gdb-threads-select)
9f6efa0c 2487 (define-key map [follow-link] 'mouse-face)
1ffac268
NR
2488 map))
2489
20ef8673 2490(defvar gdb-threads-font-lock-keywords
5dfe9b2b 2491 '((") +\\([^ ]+\\) (" (1 font-lock-function-name-face))
20ef8673 2492 ("in \\([^ ]+\\) (" (1 font-lock-function-name-face))
5dfe9b2b 2493 ("\\(\\(\\sw\\|[_.]\\)+\\)=" (1 font-lock-variable-name-face)))
20ef8673
MY
2494 "Font lock keywords used in `gdb-threads-mode'.")
2495
1ffac268 2496(defun gdb-threads-mode ()
5dfe9b2b 2497 "Major mode for gdb threads.
1ffac268 2498
2cec1d1a 2499\\{gdb-threads-mode-map}"
fad137cd 2500 (kill-all-local-variables)
1ffac268
NR
2501 (setq major-mode 'gdb-threads-mode)
2502 (setq mode-name "Threads")
2503 (setq buffer-read-only t)
5a1ad629 2504 (buffer-disable-undo)
b06e477e 2505 (setq header-line-format gdb-breakpoints-header)
1ffac268 2506 (use-local-map gdb-threads-mode-map)
20ef8673
MY
2507 (set (make-local-variable 'font-lock-defaults)
2508 '(gdb-threads-font-lock-keywords))
fad137cd 2509 (run-mode-hooks 'gdb-threads-mode-hook)
59ae3049
NR
2510 ;; Force "info threads" onto queue.
2511 (lambda () (let ((gud-running nil)) (gdb-invalidate-threads))))
1ffac268
NR
2512
2513(defun gdb-get-thread-number ()
2514 (save-excursion
2515 (re-search-backward "^\\s-*\\([0-9]*\\)" nil t)
2516 (match-string-no-properties 1)))
2517
f2fc1724 2518(defun gdb-threads-select (&optional event)
f6a2315e 2519 "Select the thread and display the relevant source."
f2fc1724 2520 (interactive (list last-input-event))
53f18ed2 2521 (if event (posn-set-point (event-end event)))
1ffac268 2522 (gdb-enqueue-input
be1c9844
NR
2523 (list (concat gdb-server-prefix "thread "
2524 (gdb-get-thread-number) "\n") 'ignore))
1ffac268 2525 (gud-display-frame))
f2fc1724 2526
59ae3049
NR
2527(defun gdb-thread-identification ()
2528 (setq mode-line-buffer-identification
2529 (list (car mode-line-buffer-identification)
2530 '(gdb-thread-indicator gdb-thread-indicator))))
2531\f
1ffac268
NR
2532;; Registers buffer.
2533;;
9594f929
NR
2534(defcustom gdb-all-registers nil
2535 "Non-nil means include floating-point registers."
2536 :type 'boolean
86af339a 2537 :group 'gdb
9594f929
NR
2538 :version "22.1")
2539
1ffac268
NR
2540(gdb-set-buffer-rules 'gdb-registers-buffer
2541 'gdb-registers-buffer-name
2542 'gdb-registers-mode)
2543
2544(def-gdb-auto-updated-buffer gdb-registers-buffer
2545 gdb-invalidate-registers
9594f929
NR
2546 (concat
2547 gdb-server-prefix "info " (if gdb-all-registers "all-") "registers\n")
1ffac268
NR
2548 gdb-info-registers-handler
2549 gdb-info-registers-custom)
2550
7c8bd6a4
NR
2551(defun gdb-info-registers-custom ()
2552 (with-current-buffer (gdb-get-buffer 'gdb-registers-buffer)
2553 (save-excursion
2554 (let ((buffer-read-only nil)
be1c9844 2555 start end)
7c8bd6a4
NR
2556 (goto-char (point-min))
2557 (while (< (point) (point-max))
be1c9844
NR
2558 (setq start (line-beginning-position))
2559 (setq end (line-end-position))
7c8bd6a4 2560 (when (looking-at "^[^ ]+")
4d7e2741 2561 (unless (string-equal (match-string 0) "The")
be1c9844
NR
2562 (put-text-property start (match-end 0)
2563 'face font-lock-variable-name-face)
4b479fae 2564 (add-text-properties start end
be1c9844
NR
2565 '(help-echo "mouse-2: edit value"
2566 mouse-face highlight))))
7c8bd6a4 2567 (forward-line 1))))))
1ffac268 2568
be1c9844
NR
2569(defun gdb-edit-register-value (&optional event)
2570 (interactive (list last-input-event))
2571 (save-excursion
940ed7e4 2572 (if event (posn-set-point (event-end event)))
be1c9844
NR
2573 (beginning-of-line)
2574 (let* ((register (current-word))
2575 (value (read-string (format "New value (%s): " register))))
2576 (gdb-enqueue-input
2577 (list (concat gdb-server-prefix "set $" register "=" value "\n")
2578 'ignore)))))
2579
1ffac268
NR
2580(defvar gdb-registers-mode-map
2581 (let ((map (make-sparse-keymap)))
2582 (suppress-keymap map)
be1c9844
NR
2583 (define-key map "\r" 'gdb-edit-register-value)
2584 (define-key map [mouse-2] 'gdb-edit-register-value)
67afa80d 2585 (define-key map " " 'gdb-all-registers)
12032009
NR
2586 (define-key map "q" 'kill-this-buffer)
2587 map))
1ffac268 2588
4eb19544
NR
2589(defvar gdb-locals-header
2590 `(,(propertize "Locals"
2591 'help-echo "mouse-1: select"
2592 'mouse-face 'mode-line-highlight
2593 'face 'mode-line
2594 'local-map
2595 (gdb-make-header-line-mouse-map
2596 'mouse-1
2597 (lambda (event) (interactive "e")
2598 (save-selected-window
2599 (select-window (posn-window (event-start event)))
2600 (set-window-dedicated-p (selected-window) nil)
2601 (switch-to-buffer
2602 (gdb-get-buffer-create 'gdb-locals-buffer))
2603 (set-window-dedicated-p (selected-window) t)))))
2604 " "
2605 ,(propertize "Registers"
2606 'help-echo "mouse-1: select"
2607 'mouse-face 'mode-line-highlight
2608 'face 'mode-line
2609 'local-map
2610 (gdb-make-header-line-mouse-map
2611 'mouse-1
2612 (lambda (event) (interactive "e")
2613 (save-selected-window
2614 (select-window (posn-window (event-start event)))
2615 (set-window-dedicated-p (selected-window) nil)
2616 (switch-to-buffer
2617 (gdb-get-buffer-create 'gdb-registers-buffer))
2618 (set-window-dedicated-p (selected-window) t)))))))
2619
1ffac268
NR
2620(defun gdb-registers-mode ()
2621 "Major mode for gdb registers.
2622
2623\\{gdb-registers-mode-map}"
fad137cd 2624 (kill-all-local-variables)
1ffac268 2625 (setq major-mode 'gdb-registers-mode)
25c7f315 2626 (setq mode-name "Registers")
4eb19544 2627 (setq header-line-format gdb-locals-header)
1ffac268 2628 (setq buffer-read-only t)
5a1ad629 2629 (buffer-disable-undo)
59ae3049 2630 (gdb-thread-identification)
1ffac268 2631 (use-local-map gdb-registers-mode-map)
fad137cd 2632 (run-mode-hooks 'gdb-registers-mode-hook)
25c7f315
NR
2633 (if (string-equal gdb-version "pre-6.4")
2634 (progn
2635 (if gdb-all-registers (setq mode-name "Registers:All"))
2636 'gdb-invalidate-registers)
2637 'gdb-invalidate-registers-1))
1ffac268
NR
2638
2639(defun gdb-registers-buffer-name ()
2640 (with-current-buffer gud-comint-buffer
2641 (concat "*registers of " (gdb-get-target-string) "*")))
2642
2643(defun gdb-display-registers-buffer ()
f6a2315e 2644 "Display integer register contents."
1ffac268
NR
2645 (interactive)
2646 (gdb-display-buffer
d138996e 2647 (gdb-get-buffer-create 'gdb-registers-buffer) t))
1ffac268
NR
2648
2649(defun gdb-frame-registers-buffer ()
f6a2315e 2650 "Display integer register contents in a new frame."
1ffac268 2651 (interactive)
1a9203d0
NR
2652 (let ((special-display-regexps (append special-display-regexps '(".*")))
2653 (special-display-frame-alist gdb-frame-parameters))
f27d4d6c 2654 (display-buffer (gdb-get-buffer-create 'gdb-registers-buffer))))
37ebd64b 2655
67afa80d 2656(defun gdb-all-registers ()
25c7f315 2657 "Toggle the display of floating-point registers (pre GDB 6.4 only)."
9594f929 2658 (interactive)
25c7f315
NR
2659 (when (string-equal gdb-version "pre-6.4")
2660 (if gdb-all-registers
2661 (progn
2662 (setq gdb-all-registers nil)
f27d4d6c 2663 (with-current-buffer (gdb-get-buffer-create 'gdb-registers-buffer)
25c7f315
NR
2664 (setq mode-name "Registers")))
2665 (setq gdb-all-registers t)
f27d4d6c 2666 (with-current-buffer (gdb-get-buffer-create 'gdb-registers-buffer)
25c7f315
NR
2667 (setq mode-name "Registers:All")))
2668 (message (format "Display of floating-point registers %sabled"
2669 (if gdb-all-registers "en" "dis")))
2670 (gdb-invalidate-registers)))
9594f929
NR
2671\f
2672
37ebd64b 2673;; Memory buffer.
1ffac268 2674;;
37ebd64b
NR
2675(defcustom gdb-memory-repeat-count 32
2676 "Number of data items in memory window."
2677 :type 'integer
86af339a 2678 :group 'gdb
bf247b6e 2679 :version "22.1")
37ebd64b
NR
2680
2681(defcustom gdb-memory-format "x"
2682 "Display format of data items in memory window."
2683 :type '(choice (const :tag "Hexadecimal" "x")
2684 (const :tag "Signed decimal" "d")
2685 (const :tag "Unsigned decimal" "u")
2686 (const :tag "Octal" "o")
2687 (const :tag "Binary" "t"))
86af339a 2688 :group 'gdb
bf247b6e 2689 :version "22.1")
37ebd64b
NR
2690
2691(defcustom gdb-memory-unit "w"
2692 "Unit size of data items in memory window."
2693 :type '(choice (const :tag "Byte" "b")
2694 (const :tag "Halfword" "h")
2695 (const :tag "Word" "w")
2696 (const :tag "Giant word" "g"))
86af339a 2697 :group 'gdb
bf247b6e 2698 :version "22.1")
37ebd64b
NR
2699
2700(gdb-set-buffer-rules 'gdb-memory-buffer
2701 'gdb-memory-buffer-name
2702 'gdb-memory-mode)
2703
2704(def-gdb-auto-updated-buffer gdb-memory-buffer
2705 gdb-invalidate-memory
2706 (concat gdb-server-prefix "x/" (number-to-string gdb-memory-repeat-count)
2707 gdb-memory-format gdb-memory-unit " " gdb-memory-address "\n")
2708 gdb-read-memory-handler
2709 gdb-read-memory-custom)
2710
1f1f4de2
NR
2711(defun gdb-read-memory-custom ()
2712 (save-excursion
2713 (goto-char (point-min))
2714 (if (looking-at "0x[[:xdigit:]]+")
2715 (setq gdb-memory-address (match-string 0)))))
37ebd64b
NR
2716
2717(defvar gdb-memory-mode-map
2718 (let ((map (make-sparse-keymap)))
2719 (suppress-keymap map)
d91e2cb6
NR
2720 (define-key map "S" 'gdb-memory-set-address)
2721 (define-key map "N" 'gdb-memory-set-repeat-count)
37ebd64b
NR
2722 (define-key map "q" 'kill-this-buffer)
2723 map))
2724
d91e2cb6 2725(defun gdb-memory-set-address (&optional event)
37ebd64b 2726 "Set the start memory address."
d91e2cb6
NR
2727 (interactive)
2728 (let ((arg (read-from-minibuffer "Start address: ")))
2729 (setq gdb-memory-address arg))
2730 (gdb-invalidate-memory))
37ebd64b 2731
d91e2cb6 2732(defun gdb-memory-set-repeat-count (&optional event)
37ebd64b 2733 "Set the number of data items in memory window."
d91e2cb6
NR
2734 (interactive)
2735 (let* ((arg (read-from-minibuffer "Repeat count: "))
2736 (count (string-to-number arg)))
2737 (if (<= count 0)
2738 (error "Positive numbers only")
2739 (customize-set-variable 'gdb-memory-repeat-count count)
2740 (gdb-invalidate-memory))))
37ebd64b
NR
2741
2742(defun gdb-memory-format-binary ()
2743 "Set the display format to binary."
2744 (interactive)
2745 (customize-set-variable 'gdb-memory-format "t")
2746 (gdb-invalidate-memory))
2747
2748(defun gdb-memory-format-octal ()
2749 "Set the display format to octal."
2750 (interactive)
2751 (customize-set-variable 'gdb-memory-format "o")
2752 (gdb-invalidate-memory))
2753
2754(defun gdb-memory-format-unsigned ()
2755 "Set the display format to unsigned decimal."
2756 (interactive)
2757 (customize-set-variable 'gdb-memory-format "u")
2758 (gdb-invalidate-memory))
2759
2760(defun gdb-memory-format-signed ()
2761 "Set the display format to decimal."
2762 (interactive)
2763 (customize-set-variable 'gdb-memory-format "d")
2764 (gdb-invalidate-memory))
2765
2766(defun gdb-memory-format-hexadecimal ()
2767 "Set the display format to hexadecimal."
2768 (interactive)
2769 (customize-set-variable 'gdb-memory-format "x")
2770 (gdb-invalidate-memory))
2771
25c7f315 2772(defvar gdb-memory-format-map
37ebd64b
NR
2773 (let ((map (make-sparse-keymap)))
2774 (define-key map [header-line down-mouse-3] 'gdb-memory-format-menu-1)
2775 map)
55222dc8 2776 "Keymap to select format in the header line.")
37ebd64b
NR
2777
2778(defvar gdb-memory-format-menu (make-sparse-keymap "Format")
55222dc8 2779 "Menu of display formats in the header line.")
37ebd64b
NR
2780
2781(define-key gdb-memory-format-menu [binary]
2782 '(menu-item "Binary" gdb-memory-format-binary
2783 :button (:radio . (equal gdb-memory-format "t"))))
2784(define-key gdb-memory-format-menu [octal]
2785 '(menu-item "Octal" gdb-memory-format-octal
2786 :button (:radio . (equal gdb-memory-format "o"))))
2787(define-key gdb-memory-format-menu [unsigned]
2788 '(menu-item "Unsigned Decimal" gdb-memory-format-unsigned
2789 :button (:radio . (equal gdb-memory-format "u"))))
2790(define-key gdb-memory-format-menu [signed]
2791 '(menu-item "Signed Decimal" gdb-memory-format-signed
2792 :button (:radio . (equal gdb-memory-format "d"))))
2793(define-key gdb-memory-format-menu [hexadecimal]
2794 '(menu-item "Hexadecimal" gdb-memory-format-hexadecimal
2795 :button (:radio . (equal gdb-memory-format "x"))))
2796
2797(defun gdb-memory-format-menu (event)
2798 (interactive "@e")
2799 (x-popup-menu event gdb-memory-format-menu))
2800
2801(defun gdb-memory-format-menu-1 (event)
2802 (interactive "e")
2803 (save-selected-window
2804 (select-window (posn-window (event-start event)))
2805 (let* ((selection (gdb-memory-format-menu event))
2806 (binding (and selection (lookup-key gdb-memory-format-menu
2807 (vector (car selection))))))
2808 (if binding (call-interactively binding)))))
2809
2810(defun gdb-memory-unit-giant ()
2811 "Set the unit size to giant words (eight bytes)."
2812 (interactive)
2813 (customize-set-variable 'gdb-memory-unit "g")
2814 (gdb-invalidate-memory))
2815
2816(defun gdb-memory-unit-word ()
2817 "Set the unit size to words (four bytes)."
2818 (interactive)
2819 (customize-set-variable 'gdb-memory-unit "w")
2820 (gdb-invalidate-memory))
2821
2822(defun gdb-memory-unit-halfword ()
2823 "Set the unit size to halfwords (two bytes)."
2824 (interactive)
2825 (customize-set-variable 'gdb-memory-unit "h")
2826 (gdb-invalidate-memory))
2827
2828(defun gdb-memory-unit-byte ()
2829 "Set the unit size to bytes."
2830 (interactive)
2831 (customize-set-variable 'gdb-memory-unit "b")
2832 (gdb-invalidate-memory))
2833
25c7f315 2834(defvar gdb-memory-unit-map
37ebd64b
NR
2835 (let ((map (make-sparse-keymap)))
2836 (define-key map [header-line down-mouse-3] 'gdb-memory-unit-menu-1)
2837 map)
55222dc8 2838 "Keymap to select units in the header line.")
37ebd64b
NR
2839
2840(defvar gdb-memory-unit-menu (make-sparse-keymap "Unit")
55222dc8 2841 "Menu of units in the header line.")
37ebd64b
NR
2842
2843(define-key gdb-memory-unit-menu [giantwords]
2844 '(menu-item "Giant words" gdb-memory-unit-giant
2845 :button (:radio . (equal gdb-memory-unit "g"))))
2846(define-key gdb-memory-unit-menu [words]
2847 '(menu-item "Words" gdb-memory-unit-word
2848 :button (:radio . (equal gdb-memory-unit "w"))))
2849(define-key gdb-memory-unit-menu [halfwords]
2850 '(menu-item "Halfwords" gdb-memory-unit-halfword
2851 :button (:radio . (equal gdb-memory-unit "h"))))
2852(define-key gdb-memory-unit-menu [bytes]
2853 '(menu-item "Bytes" gdb-memory-unit-byte
2854 :button (:radio . (equal gdb-memory-unit "b"))))
2855
2856(defun gdb-memory-unit-menu (event)
2857 (interactive "@e")
2858 (x-popup-menu event gdb-memory-unit-menu))
2859
2860(defun gdb-memory-unit-menu-1 (event)
2861 (interactive "e")
2862 (save-selected-window
2863 (select-window (posn-window (event-start event)))
2864 (let* ((selection (gdb-memory-unit-menu event))
2865 (binding (and selection (lookup-key gdb-memory-unit-menu
2866 (vector (car selection))))))
2867 (if binding (call-interactively binding)))))
2868
20ef8673
MY
2869(defvar gdb-memory-font-lock-keywords
2870 '(;; <__function.name+n>
2871 ("<\\(\\(\\sw\\|[_.]\\)+\\)\\(\\+[0-9]+\\)?>" (1 font-lock-function-name-face))
2872 )
2873 "Font lock keywords used in `gdb-memory-mode'.")
2874
37ebd64b
NR
2875(defun gdb-memory-mode ()
2876 "Major mode for examining memory.
2877
2878\\{gdb-memory-mode-map}"
2879 (kill-all-local-variables)
2880 (setq major-mode 'gdb-memory-mode)
2881 (setq mode-name "Memory")
2882 (setq buffer-read-only t)
5a1ad629 2883 (buffer-disable-undo)
37ebd64b
NR
2884 (use-local-map gdb-memory-mode-map)
2885 (setq header-line-format
2886 '(:eval
bf247b6e 2887 (concat
d91e2cb6 2888 "Start address["
1f1f4de2
NR
2889 (propertize
2890 "-"
2891 'face font-lock-warning-face
0ebd837a 2892 'help-echo "mouse-1: decrement address"
1f1f4de2
NR
2893 'mouse-face 'mode-line-highlight
2894 'local-map
2895 (gdb-make-header-line-mouse-map
2896 'mouse-1
7443a638
NR
2897 (lambda () (interactive)
2898 (let ((gdb-memory-address
2899 ;; Let GDB do the arithmetic.
2900 (concat
2901 gdb-memory-address " - "
2902 (number-to-string
2903 (* gdb-memory-repeat-count
2904 (cond ((string= gdb-memory-unit "b") 1)
2905 ((string= gdb-memory-unit "h") 2)
2906 ((string= gdb-memory-unit "w") 4)
2907 ((string= gdb-memory-unit "g") 8)))))))
2908 (gdb-invalidate-memory)))))
1f1f4de2
NR
2909 "|"
2910 (propertize "+"
2911 'face font-lock-warning-face
0ebd837a 2912 'help-echo "mouse-1: increment address"
1f1f4de2
NR
2913 'mouse-face 'mode-line-highlight
2914 'local-map (gdb-make-header-line-mouse-map
2915 'mouse-1
7443a638
NR
2916 (lambda () (interactive)
2917 (let ((gdb-memory-address nil))
2918 (gdb-invalidate-memory)))))
1f1f4de2 2919 "]: "
37ebd64b
NR
2920 (propertize gdb-memory-address
2921 'face font-lock-warning-face
d91e2cb6 2922 'help-echo "mouse-1: set start address"
5770a942 2923 'mouse-face 'mode-line-highlight
1a032087
NR
2924 'local-map (gdb-make-header-line-mouse-map
2925 'mouse-1
2926 #'gdb-memory-set-address))
37ebd64b
NR
2927 " Repeat Count: "
2928 (propertize (number-to-string gdb-memory-repeat-count)
2929 'face font-lock-warning-face
0ebd837a 2930 'help-echo "mouse-1: set repeat count"
5770a942 2931 'mouse-face 'mode-line-highlight
1a032087
NR
2932 'local-map (gdb-make-header-line-mouse-map
2933 'mouse-1
2934 #'gdb-memory-set-repeat-count))
37ebd64b
NR
2935 " Display Format: "
2936 (propertize gdb-memory-format
2937 'face font-lock-warning-face
0ebd837a 2938 'help-echo "mouse-3: select display format"
5770a942 2939 'mouse-face 'mode-line-highlight
25c7f315 2940 'local-map gdb-memory-format-map)
37ebd64b
NR
2941 " Unit Size: "
2942 (propertize gdb-memory-unit
2943 'face font-lock-warning-face
0ebd837a 2944 'help-echo "mouse-3: select unit size"
5770a942 2945 'mouse-face 'mode-line-highlight
25c7f315 2946 'local-map gdb-memory-unit-map))))
20ef8673
MY
2947 (set (make-local-variable 'font-lock-defaults)
2948 '(gdb-memory-font-lock-keywords))
37ebd64b
NR
2949 (run-mode-hooks 'gdb-memory-mode-hook)
2950 'gdb-invalidate-memory)
2951
2952(defun gdb-memory-buffer-name ()
2953 (with-current-buffer gud-comint-buffer
2954 (concat "*memory of " (gdb-get-target-string) "*")))
2955
2956(defun gdb-display-memory-buffer ()
2957 "Display memory contents."
2958 (interactive)
2959 (gdb-display-buffer
d138996e 2960 (gdb-get-buffer-create 'gdb-memory-buffer) t))
37ebd64b
NR
2961
2962(defun gdb-frame-memory-buffer ()
2963 "Display memory contents in a new frame."
2964 (interactive)
b2f5a4ac
NR
2965 (let* ((special-display-regexps (append special-display-regexps '(".*")))
2966 (special-display-frame-alist
2967 (cons '(left-fringe . 0)
2968 (cons '(right-fringe . 0)
2969 (cons '(width . 83) gdb-frame-parameters)))))
f27d4d6c 2970 (display-buffer (gdb-get-buffer-create 'gdb-memory-buffer))))
37ebd64b
NR
2971\f
2972
1ffac268
NR
2973;; Locals buffer.
2974;;
2975(gdb-set-buffer-rules 'gdb-locals-buffer
2976 'gdb-locals-buffer-name
2977 'gdb-locals-mode)
2978
9317517c
NR
2979(def-gdb-auto-update-trigger gdb-invalidate-locals
2980 (gdb-get-buffer 'gdb-locals-buffer)
1ffac268 2981 "server info locals\n"
9317517c 2982 gdb-info-locals-handler)
1ffac268 2983
25c7f315 2984(defvar gdb-locals-watch-map
e03a33ea 2985 (let ((map (make-sparse-keymap)))
38a52690 2986 (suppress-keymap map)
7443a638
NR
2987 (define-key map "\r" (lambda () (interactive)
2988 (beginning-of-line)
2989 (gud-watch)))
2990 (define-key map [mouse-2] (lambda (event) (interactive "e")
2991 (mouse-set-point event)
2992 (beginning-of-line)
2993 (gud-watch)))
e03a33ea 2994 map)
55222dc8 2995 "Keymap to create watch expression of a complex data type local variable.")
e03a33ea
NR
2996
2997(defconst gdb-struct-string
be1c9844 2998 (concat (propertize "[struct/union]"
e03a33ea
NR
2999 'mouse-face 'highlight
3000 'help-echo "mouse-2: create watch expression"
25c7f315 3001 'local-map gdb-locals-watch-map) "\n"))
e03a33ea
NR
3002
3003(defconst gdb-array-string
be1c9844 3004 (concat " " (propertize "[array]"
e03a33ea
NR
3005 'mouse-face 'highlight
3006 'help-echo "mouse-2: create watch expression"
25c7f315 3007 'local-map gdb-locals-watch-map) "\n"))
e03a33ea 3008
1ffac268
NR
3009;; Abbreviate for arrays and structures.
3010;; These can be expanded using gud-display.
7c8bd6a4 3011(defun gdb-info-locals-handler ()
2cec1d1a
NR
3012 (setq gdb-pending-triggers (delq 'gdb-invalidate-locals
3013 gdb-pending-triggers))
1ffac268
NR
3014 (let ((buf (gdb-get-buffer 'gdb-partial-output-buffer)))
3015 (with-current-buffer buf
3016 (goto-char (point-min))
34fb82b8 3017 ;; Need this in case "set print pretty" is on.
453b7959 3018 (while (re-search-forward "^[ }].*\n" nil t)
1ffac268
NR
3019 (replace-match "" nil nil))
3020 (goto-char (point-min))
453b7959 3021 (while (re-search-forward "{\\(.*=.*\n\\|\n\\)" nil t)
e03a33ea 3022 (replace-match gdb-struct-string nil nil))
1ffac268 3023 (goto-char (point-min))
34fb82b8 3024 (while (re-search-forward "\\s-*{[^.].*\n" nil t)
e03a33ea 3025 (replace-match gdb-array-string nil nil))))
1ffac268 3026 (let ((buf (gdb-get-buffer 'gdb-locals-buffer)))
974be7ce
NR
3027 (and buf
3028 (with-current-buffer buf
3029 (let* ((window (get-buffer-window buf 0))
f27d4d6c 3030 (start (window-start window))
974be7ce 3031 (p (window-point window))
1ffac268 3032 (buffer-read-only nil))
2884ae6d 3033 (erase-buffer)
f27d4d6c 3034 (insert-buffer-substring (gdb-get-buffer-create
1ffac268 3035 'gdb-partial-output-buffer))
f27d4d6c 3036 (set-window-start window start)
72ba4f36 3037 (set-window-point window p)))))
1ffac268
NR
3038 (run-hooks 'gdb-info-locals-hook))
3039
1ffac268
NR
3040(defvar gdb-locals-mode-map
3041 (let ((map (make-sparse-keymap)))
3042 (suppress-keymap map)
12032009
NR
3043 (define-key map "q" 'kill-this-buffer)
3044 map))
1ffac268
NR
3045
3046(defun gdb-locals-mode ()
3047 "Major mode for gdb locals.
3048
3049\\{gdb-locals-mode-map}"
fad137cd 3050 (kill-all-local-variables)
1ffac268 3051 (setq major-mode 'gdb-locals-mode)
5770a942 3052 (setq mode-name (concat "Locals:" gdb-selected-frame))
4eb19544 3053 (use-local-map gdb-locals-mode-map)
1ffac268 3054 (setq buffer-read-only t)
5a1ad629 3055 (buffer-disable-undo)
4eb19544 3056 (setq header-line-format gdb-locals-header)
59ae3049 3057 (gdb-thread-identification)
20ef8673 3058 (set (make-local-variable 'font-lock-defaults)
7c8bd6a4 3059 '(gdb-locals-font-lock-keywords))
fad137cd 3060 (run-mode-hooks 'gdb-locals-mode-hook)
621b3aac
NR
3061 (if (and (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
3062 (string-equal gdb-version "pre-6.4"))
3063 'gdb-invalidate-locals
3064 'gdb-invalidate-locals-1))
1ffac268
NR
3065
3066(defun gdb-locals-buffer-name ()
3067 (with-current-buffer gud-comint-buffer
3068 (concat "*locals of " (gdb-get-target-string) "*")))
3069
3070(defun gdb-display-locals-buffer ()
f6a2315e 3071 "Display local variables of current stack and their values."
1ffac268
NR
3072 (interactive)
3073 (gdb-display-buffer
d138996e 3074 (gdb-get-buffer-create 'gdb-locals-buffer) t))
1ffac268
NR
3075
3076(defun gdb-frame-locals-buffer ()
f6a2315e 3077 "Display local variables of current stack and their values in a new frame."
1ffac268 3078 (interactive)
1a9203d0
NR
3079 (let ((special-display-regexps (append special-display-regexps '(".*")))
3080 (special-display-frame-alist gdb-frame-parameters))
f27d4d6c 3081 (display-buffer (gdb-get-buffer-create 'gdb-locals-buffer))))
1ffac268
NR
3082\f
3083
3084;;;; Window management
72ba4f36 3085(defun gdb-display-buffer (buf dedicated &optional frame)
05dfe89a 3086 (let ((answer (get-buffer-window buf (or frame 0))))
12032009 3087 (if answer
72ba4f36 3088 (display-buffer buf nil (or frame 0)) ;Deiconify the frame if necessary.
f2dab427 3089 (let ((window (get-lru-window)))
95741663
NR
3090 (if (memq (buffer-local-value 'gud-minor-mode (window-buffer window))
3091 '(gdba gdbmi))
3092 (let* ((largest (get-largest-window))
3093 (cur-size (window-height largest)))
3094 (setq answer (split-window largest))
3095 (set-window-buffer answer buf)
3096 (set-window-dedicated-p answer dedicated)
3097 answer)
3098 (set-window-buffer window buf)
3099 window)))))
1ffac268 3100
1ffac268
NR
3101\f
3102;;; Shared keymap initialization:
3103
1ffac268
NR
3104(let ((menu (make-sparse-keymap "GDB-Windows")))
3105 (define-key gud-menu-map [displays]
5c66660f 3106 `(menu-item "GDB-Windows" ,menu
aa72bfb2 3107 :help "Open a GDB-UI buffer in a new window."
5c66660f 3108 :visible (memq gud-minor-mode '(gdbmi gdba))))
1ffac268 3109 (define-key menu [gdb] '("Gdb" . gdb-display-gdb-buffer))
2b63b80f 3110 (define-key menu [threads] '("Threads" . gdb-display-threads-buffer))
1a032087 3111 (define-key menu [inferior]
7443a638 3112 '(menu-item "Separate IO" gdb-display-separate-io-buffer
b5e5e9f2 3113 :enable gdb-use-separate-io-buffer))
b5c5d216
NR
3114 (define-key menu [memory] '("Memory" . gdb-display-memory-buffer))
3115 (define-key menu [registers] '("Registers" . gdb-display-registers-buffer))
3116 (define-key menu [disassembly]
3117 '("Disassembly" . gdb-display-assembler-buffer))
a0091778 3118 (define-key menu [breakpoints]
b5c5d216
NR
3119 '("Breakpoints" . gdb-display-breakpoints-buffer))
3120 (define-key menu [locals] '("Locals" . gdb-display-locals-buffer))
3121 (define-key menu [frames] '("Stack" . gdb-display-stack-buffer)))
1ffac268 3122
b29ef159
NR
3123(let ((menu (make-sparse-keymap "GDB-Frames")))
3124 (define-key gud-menu-map [frames]
5c66660f 3125 `(menu-item "GDB-Frames" ,menu
aa72bfb2 3126 :help "Open a GDB-UI buffer in a new frame."
5c66660f 3127 :visible (memq gud-minor-mode '(gdbmi gdba))))
b29ef159
NR
3128 (define-key menu [gdb] '("Gdb" . gdb-frame-gdb-buffer))
3129 (define-key menu [threads] '("Threads" . gdb-frame-threads-buffer))
3130 (define-key menu [memory] '("Memory" . gdb-frame-memory-buffer))
1a032087 3131 (define-key menu [inferior]
7443a638 3132 '(menu-item "Separate IO" gdb-frame-separate-io-buffer
b5e5e9f2 3133 :enable gdb-use-separate-io-buffer))
b5c5d216 3134 (define-key menu [registers] '("Registers" . gdb-frame-registers-buffer))
9d6bb9e0 3135 (define-key menu [disassembly] '("Disassembly" . gdb-frame-assembler-buffer))
a0091778 3136 (define-key menu [breakpoints]
b5c5d216
NR
3137 '("Breakpoints" . gdb-frame-breakpoints-buffer))
3138 (define-key menu [locals] '("Locals" . gdb-frame-locals-buffer))
3139 (define-key menu [frames] '("Stack" . gdb-frame-stack-buffer)))
b29ef159 3140
ba5ff011 3141(let ((menu (make-sparse-keymap "GDB-UI/MI")))
1ffac268 3142 (define-key gud-menu-map [ui]
ba5ff011
NR
3143 `(menu-item (if (eq gud-minor-mode 'gdba) "GDB-UI" "GDB-MI")
3144 ,menu :visible (memq gud-minor-mode '(gdbmi gdba))))
86af339a
NR
3145 (define-key menu [gdb-customize]
3146 '(menu-item "Customize" (lambda () (interactive) (customize-group 'gdb))
3147 :help "Customize Gdb Graphical Mode options."))
a6c7c026
NR
3148 (define-key menu [gdb-find-source-frame]
3149 '(menu-item "Look For Source Frame" gdb-find-source-frame
3150 :visible (eq gud-minor-mode 'gdba)
aa72bfb2 3151 :help "Toggle looking for source frame further up call stack."
a6c7c026 3152 :button (:toggle . gdb-find-source-frame)))
b5e5e9f2 3153 (define-key menu [gdb-use-separate-io]
7443a638 3154 '(menu-item "Separate IO" gdb-use-separate-io-buffer
ba5ff011 3155 :visible (eq gud-minor-mode 'gdba)
7443a638 3156 :help "Toggle separate IO for debugged program."
b5e5e9f2 3157 :button (:toggle . gdb-use-separate-io-buffer)))
b6363524
NR
3158 (define-key menu [gdb-many-windows]
3159 '(menu-item "Display Other Windows" gdb-many-windows
3160 :help "Toggle display of locals, stack and breakpoint information"
3161 :button (:toggle . gdb-many-windows)))
3162 (define-key menu [gdb-restore-windows]
3163 '(menu-item "Restore Window Layout" gdb-restore-windows
3164 :help "Restore standard layout for debug session.")))
1a032087 3165
1ffac268 3166(defun gdb-frame-gdb-buffer ()
f6a2315e 3167 "Display GUD buffer in a new frame."
1ffac268 3168 (interactive)
bfd21f54 3169 (let ((special-display-regexps (append special-display-regexps '(".*")))
3e0b9c08
NR
3170 (special-display-frame-alist
3171 (remove '(menu-bar-lines) (remove '(tool-bar-lines)
3172 gdb-frame-parameters)))
6c8909e7
NR
3173 (same-window-regexps nil))
3174 (display-buffer gud-comint-buffer)))
1ffac268
NR
3175
3176(defun gdb-display-gdb-buffer ()
f6a2315e 3177 "Display GUD buffer."
1ffac268 3178 (interactive)
6c8909e7 3179 (let ((same-window-regexps nil))
05dfe89a 3180 (select-window (display-buffer gud-comint-buffer nil 0))))
1ffac268 3181
12032009
NR
3182(defun gdb-set-window-buffer (name)
3183 (set-window-buffer (selected-window) (get-buffer name))
3184 (set-window-dedicated-p (selected-window) t))
4e607b59 3185
1ffac268 3186(defun gdb-setup-windows ()
1e5b5dc0 3187 "Layout the window pattern for `gdb-many-windows'."
1ffac268
NR
3188 (gdb-display-locals-buffer)
3189 (gdb-display-stack-buffer)
3190 (delete-other-windows)
3191 (gdb-display-breakpoints-buffer)
3192 (delete-other-windows)
f2dab427
NR
3193 ; Don't dedicate.
3194 (pop-to-buffer gud-comint-buffer)
1ffac268
NR
3195 (split-window nil ( / ( * (window-height) 3) 4))
3196 (split-window nil ( / (window-height) 3))
3197 (split-window-horizontally)
3198 (other-window 1)
12032009 3199 (gdb-set-window-buffer (gdb-locals-buffer-name))
1ffac268 3200 (other-window 1)
f2dab427 3201 (switch-to-buffer
1ffac268
NR
3202 (if gud-last-last-frame
3203 (gud-find-file (car gud-last-last-frame))
caf2f944
NR
3204 (if gdb-main-file
3205 (gud-find-file gdb-main-file)
3206 ;; Put buffer list in window if we
3207 ;; can't find a source file.
3208 (list-buffers-noselect))))
0745bc2e 3209 (setq gdb-source-window (selected-window))
b5e5e9f2 3210 (when gdb-use-separate-io-buffer
614963ba
NR
3211 (split-window-horizontally)
3212 (other-window 1)
1a032087 3213 (gdb-set-window-buffer
f27d4d6c 3214 (gdb-get-buffer-create 'gdb-inferior-io)))
1ffac268 3215 (other-window 1)
12032009 3216 (gdb-set-window-buffer (gdb-stack-buffer-name))
1ffac268
NR
3217 (split-window-horizontally)
3218 (other-window 1)
12032009 3219 (gdb-set-window-buffer (gdb-breakpoints-buffer-name))
1ffac268
NR
3220 (other-window 1))
3221
1ffac268
NR
3222(defun gdb-restore-windows ()
3223 "Restore the basic arrangement of windows used by gdba.
3224This arrangement depends on the value of `gdb-many-windows'."
3225 (interactive)
12032009 3226 (pop-to-buffer gud-comint-buffer) ;Select the right window and frame.
1ffac268 3227 (delete-other-windows)
12032009
NR
3228 (if gdb-many-windows
3229 (gdb-setup-windows)
bfd21f54
NR
3230 (when (or gud-last-last-frame gdb-show-main)
3231 (split-window)
3232 (other-window 1)
3233 (switch-to-buffer
3234 (if gud-last-last-frame
3235 (gud-find-file (car gud-last-last-frame))
3236 (gud-find-file gdb-main-file)))
0745bc2e 3237 (setq gdb-source-window (selected-window))
bfd21f54 3238 (other-window 1))))
1ffac268
NR
3239
3240(defun gdb-reset ()
d94dccc6 3241 "Exit a debugging session cleanly.
7dda1909 3242Kills the gdb buffers, and resets variables and the source buffers."
1ffac268 3243 (dolist (buffer (buffer-list))
d490ebbe
SM
3244 (unless (eq buffer gud-comint-buffer)
3245 (with-current-buffer buffer
2cec1d1a 3246 (if (memq gud-minor-mode '(gdbmi gdba))
6c8aa2cd 3247 (if (string-match "\\` ?\\*.+\\*\\'" (buffer-name))
d490ebbe
SM
3248 (kill-buffer nil)
3249 (gdb-remove-breakpoint-icons (point-min) (point-max) t)
3250 (setq gud-minor-mode nil)
3251 (kill-local-variable 'tool-bar-map)
5c66660f 3252 (kill-local-variable 'gdb-define-alist))))))
9143202c 3253 (setq gdb-overlay-arrow-position nil)
1ffac268 3254 (setq overlay-arrow-variable-list
5c66660f 3255 (delq 'gdb-overlay-arrow-position overlay-arrow-variable-list))
4b479fae 3256 (setq fringe-indicator-alist '((overlay-arrow . right-triangle)))
9143202c
NR
3257 (setq gdb-stack-position nil)
3258 (setq overlay-arrow-variable-list
3259 (delq 'gdb-stack-position overlay-arrow-variable-list))
d22b968f 3260 (if (boundp 'speedbar-frame) (speedbar-timer-fn))
5c66660f
NR
3261 (setq gud-running nil)
3262 (setq gdb-active-process nil)
e03a33ea 3263 (setq gdb-var-list nil)
5c66660f 3264 (remove-hook 'after-save-hook 'gdb-create-define-alist t))
1ffac268
NR
3265
3266(defun gdb-source-info ()
14b26c33 3267 "Find the source file where the program starts and display it with related
1ffac268
NR
3268buffers."
3269 (goto-char (point-min))
e7212bb3 3270 (if (and (search-forward "Located in " nil t)
4cbf6601 3271 (looking-at "\\S-+"))
e7212bb3 3272 (setq gdb-main-file (match-string 0)))
89d8189a
NR
3273 (goto-char (point-min))
3274 (if (search-forward "Includes preprocessor macro info." nil t)
3275 (setq gdb-macro-info t))
59ae3049 3276 (if gdb-many-windows
1ffac268 3277 (gdb-setup-windows)
f27d4d6c 3278 (gdb-get-buffer-create 'gdb-breakpoints-buffer)
cf7238ad 3279 (if (and gdb-show-main gdb-main-file)
e7212bb3 3280 (let ((pop-up-windows t))
9558a54a
NR
3281 (display-buffer (gud-find-file gdb-main-file)))))
3282 (setq gdb-ready t))
1ffac268 3283
94cd554a
NR
3284(defun gdb-get-location (bptno line flag)
3285 "Find the directory containing the relevant source file.
3286Put in buffer and place breakpoint icon."
3287 (goto-char (point-min))
50af6c66
NR
3288 (catch 'file-not-found
3289 (if (search-forward "Located in " nil t)
4cbf6601 3290 (when (looking-at "\\S-+")
89d8189a
NR
3291 (delete (cons bptno "File not found") gdb-location-alist)
3292 (push (cons bptno (match-string 0)) gdb-location-alist))
50af6c66 3293 (gdb-resync)
89d8189a
NR
3294 (unless (assoc bptno gdb-location-alist)
3295 (push (cons bptno "File not found") gdb-location-alist)
3296 (message-box "Cannot find source file for breakpoint location.\n\
3297Add directory to search path for source files using the GDB command, dir."))
50af6c66
NR
3298 (throw 'file-not-found nil))
3299 (with-current-buffer
3300 (find-file-noselect (match-string 0))
6c6273c6 3301 (gdb-init-buffer)
50af6c66
NR
3302 ;; only want one breakpoint icon at each location
3303 (save-excursion
3304 (goto-line (string-to-number line))
3305 (gdb-put-breakpoint-icon (eq flag ?y) bptno)))))
94cd554a 3306
e7212bb3
NR
3307(add-hook 'find-file-hook 'gdb-find-file-hook)
3308
3309(defun gdb-find-file-hook ()
25c7f315 3310 "Set up buffer for debugging if file is part of the source code
2884ae6d 3311of the current session."
25c7f315 3312 (if (and (buffer-name gud-comint-buffer)
e7212bb3
NR
3313 ;; in case gud or gdb-ui is just loaded
3314 gud-comint-buffer
621b3aac
NR
3315 (memq (buffer-local-value 'gud-minor-mode gud-comint-buffer)
3316 '(gdba gdbmi)))
c1719ebf
NR
3317 ;;Pre GDB 6.3 "info sources" doesn't give absolute file name.
3318 (if (member (if (string-equal gdb-version "pre-6.4")
3319 (file-name-nondirectory buffer-file-name)
3320 buffer-file-name)
0ebd837a 3321 gdb-source-file-list)
c05ba081 3322 (with-current-buffer (find-buffer-visiting buffer-file-name)
6c6273c6 3323 (gdb-init-buffer)))))
e7212bb3 3324
1ffac268 3325;;from put-image
64ef03e9 3326(defun gdb-put-string (putstring pos &optional dprop &rest sprops)
1ffac268
NR
3327 "Put string PUTSTRING in front of POS in the current buffer.
3328PUTSTRING is displayed by putting an overlay into the current buffer with a
1e5b5dc0 3329`before-string' string that has a `display' property whose value is
1ffac268 3330PUTSTRING."
b6d0e4da 3331 (let ((string (make-string 1 ?x))
1ffac268 3332 (buffer (current-buffer)))
b6d0e4da 3333 (setq putstring (copy-sequence putstring))
1ffac268
NR
3334 (let ((overlay (make-overlay pos pos buffer))
3335 (prop (or dprop
3336 (list (list 'margin 'left-margin) putstring))))
64ef03e9
KS
3337 (put-text-property 0 1 'display prop string)
3338 (if sprops
3339 (add-text-properties 0 1 sprops string))
1ffac268 3340 (overlay-put overlay 'put-break t)
b6d0e4da 3341 (overlay-put overlay 'before-string string))))
1ffac268
NR
3342
3343;;from remove-images
3344(defun gdb-remove-strings (start end &optional buffer)
3345 "Remove strings between START and END in BUFFER.
3346Remove only strings that were put in BUFFER with calls to `gdb-put-string'.
3347BUFFER nil or omitted means use the current buffer."
3348 (unless buffer
3349 (setq buffer (current-buffer)))
b6d0e4da 3350 (dolist (overlay (overlays-in start end))
a0091778 3351 (when (overlay-get overlay 'put-break)
b6d0e4da 3352 (delete-overlay overlay))))
1ffac268 3353
b6d0e4da 3354(defun gdb-put-breakpoint-icon (enabled bptno)
266e779b
NR
3355 (if (string-match "[0-9+]+\\." bptno)
3356 (setq enabled gdb-parent-bptno-enabled))
453b7959
NR
3357 (let ((start (- (line-beginning-position) 1))
3358 (end (+ (line-end-position) 1))
6a8a087a
NR
3359 (putstring (if enabled "B" "b"))
3360 (source-window (get-buffer-window (current-buffer) 0)))
f3094341 3361 (add-text-properties
d12d5866 3362 0 1 '(help-echo "mouse-1: clear bkpt, mouse-3: enable/disable bkpt")
f3094341 3363 putstring)
64ef03e9
KS
3364 (if enabled
3365 (add-text-properties
3366 0 1 `(gdb-bptno ,bptno gdb-enabled t) putstring)
b6d0e4da
NR
3367 (add-text-properties
3368 0 1 `(gdb-bptno ,bptno gdb-enabled nil) putstring))
1ffac268
NR
3369 (gdb-remove-breakpoint-icons start end)
3370 (if (display-images-p)
6a8a087a 3371 (if (>= (or left-fringe-width
64ef03e9
KS
3372 (if source-window (car (window-fringes source-window)))
3373 gdb-buffer-fringe-width) 8)
188590b5 3374 (gdb-put-string
1ffac268 3375 nil (1+ start)
a9c65ba5 3376 `(left-fringe breakpoint
b6d0e4da 3377 ,(if enabled
e38b967a 3378 'breakpoint-enabled
64ef03e9
KS
3379 'breakpoint-disabled))
3380 'gdb-bptno bptno
3381 'gdb-enabled enabled)
1ffac268
NR
3382 (when (< left-margin-width 2)
3383 (save-current-buffer
3384 (setq left-margin-width 2)
6a8a087a 3385 (if source-window
619b6adb 3386 (set-window-margins
6a8a087a 3387 source-window
2b63b80f 3388 left-margin-width right-margin-width))))
1ffac268
NR
3389 (put-image
3390 (if enabled
3391 (or breakpoint-enabled-icon
3392 (setq breakpoint-enabled-icon
188590b5 3393 (find-image `((:type xpm :data
1ffac268
NR
3394 ,breakpoint-xpm-data
3395 :ascent 100 :pointer hand)
3396 (:type pbm :data
3397 ,breakpoint-enabled-pbm-data
3398 :ascent 100 :pointer hand)))))
3399 (or breakpoint-disabled-icon
3400 (setq breakpoint-disabled-icon
3401 (find-image `((:type xpm :data
3402 ,breakpoint-xpm-data
3403 :conversion disabled
d12d5866 3404 :ascent 100 :pointer hand)
1ffac268
NR
3405 (:type pbm :data
3406 ,breakpoint-disabled-pbm-data
d12d5866 3407 :ascent 100 :pointer hand))))))
b6d0e4da
NR
3408 (+ start 1)
3409 putstring
3410 'left-margin))
1ffac268
NR
3411 (when (< left-margin-width 2)
3412 (save-current-buffer
3413 (setq left-margin-width 2)
974be7ce
NR
3414 (let ((window (get-buffer-window (current-buffer) 0)))
3415 (if window
266e779b
NR
3416 (set-window-margins
3417 window left-margin-width right-margin-width)))))
e38b967a
MB
3418 (gdb-put-string
3419 (propertize putstring
3420 'face (if enabled 'breakpoint-enabled 'breakpoint-disabled))
3421 (1+ start)))))
1ffac268
NR
3422
3423(defun gdb-remove-breakpoint-icons (start end &optional remove-margin)
3424 (gdb-remove-strings start end)
3425 (if (display-images-p)
3426 (remove-images start end))
3427 (when remove-margin
3428 (setq left-margin-width 0)
974be7ce
NR
3429 (let ((window (get-buffer-window (current-buffer) 0)))
3430 (if window
3431 (set-window-margins
3432 window left-margin-width right-margin-width)))))
1ffac268
NR
3433
3434\f
3435;;
3436;; Assembler buffer.
3437;;
3438(gdb-set-buffer-rules 'gdb-assembler-buffer
3439 'gdb-assembler-buffer-name
3440 'gdb-assembler-mode)
3441
8928c512
NR
3442;; We can't use def-gdb-auto-update-handler because we don't want to use
3443;; window-start but keep the overlay arrow/current line visible.
3444(defun gdb-assembler-handler ()
3445 (setq gdb-pending-triggers
3446 (delq 'gdb-invalidate-assembler
3447 gdb-pending-triggers))
3448 (let ((buf (gdb-get-buffer 'gdb-assembler-buffer)))
3449 (and buf
3450 (with-current-buffer buf
3451 (let* ((window (get-buffer-window buf 0))
3452 (p (window-point window))
3453 (buffer-read-only nil))
3454 (erase-buffer)
3455 (insert-buffer-substring (gdb-get-buffer-create
3456 'gdb-partial-output-buffer))
3457 (set-window-point window p)))))
3458 ;; put customisation here
3459 (gdb-assembler-custom))
1ffac268
NR
3460
3461(defun gdb-assembler-custom ()
3462 (let ((buffer (gdb-get-buffer 'gdb-assembler-buffer))
190def62 3463 (pos 1) (address) (flag) (bptno))
1ffac268 3464 (with-current-buffer buffer
81649041 3465 (save-excursion
ec180a26 3466 (if (not (equal gdb-pc-address "main"))
81649041
NR
3467 (progn
3468 (goto-char (point-min))
ec180a26
NR
3469 (if (and gdb-pc-address
3470 (search-forward gdb-pc-address nil t))
81649041
NR
3471 (progn
3472 (setq pos (point))
3473 (beginning-of-line)
201f5b5f
NR
3474 (setq fringe-indicator-alist
3475 (if (string-equal gdb-frame-number "0")
3476 nil
3477 '((overlay-arrow . hollow-right-triangle))))
81649041
NR
3478 (or gdb-overlay-arrow-position
3479 (setq gdb-overlay-arrow-position (make-marker)))
9143202c 3480 (set-marker gdb-overlay-arrow-position (point))))))
81649041
NR
3481 ;; remove all breakpoint-icons in assembler buffer before updating.
3482 (gdb-remove-breakpoint-icons (point-min) (point-max))))
1ffac268
NR
3483 (with-current-buffer (gdb-get-buffer 'gdb-breakpoints-buffer)
3484 (goto-char (point-min))
3485 (while (< (point) (- (point-max) 1))
3486 (forward-line 1)
266e779b
NR
3487 (when (looking-at
3488 "\\([0-9]+\\.?[0-9]*\\).*?\\s-+\\(.\\)\\s-+0x0*\\(\\S-+\\)")
3489 (setq bptno (match-string 1))
3490 (setq flag (char-after (match-beginning 2)))
3491 (setq address (match-string 3))
3492 (with-current-buffer buffer
3493 (save-excursion
3494 (goto-char (point-min))
841b19a0 3495 (if (re-search-forward (concat "^0x0*" address) nil t)
266e779b 3496 (gdb-put-breakpoint-icon (eq flag ?y) bptno)))))))
ec180a26 3497 (if (not (equal gdb-pc-address "main"))
ba5ff011
NR
3498 (with-current-buffer buffer
3499 (set-window-point (get-buffer-window buffer 0) pos)))))
1ffac268
NR
3500
3501(defvar gdb-assembler-mode-map
3502 (let ((map (make-sparse-keymap)))
3503 (suppress-keymap map)
12032009
NR
3504 (define-key map "q" 'kill-this-buffer)
3505 map))
1ffac268 3506
fad137cd 3507(defvar gdb-assembler-font-lock-keywords
3988d9c6
MY
3508 '(;; <__function.name+n>
3509 ("<\\(\\(\\sw\\|[_.]\\)+\\)\\(\\+[0-9]+\\)?>"
3510 (1 font-lock-function-name-face))
3511 ;; 0xNNNNNNNN <__function.name+n>: opcode
3512 ("^0x[0-9a-f]+ \\(<\\(\\(\\sw\\|[_.]\\)+\\)\\+[0-9]+>\\)?:[ \t]+\\(\\sw+\\)"
fad137cd 3513 (4 font-lock-keyword-face))
3988d9c6 3514 ;; %register(at least i386)
fad137cd 3515 ("%\\sw+" . font-lock-variable-name-face)
3988d9c6 3516 ("^\\(Dump of assembler code for function\\) \\(.+\\):"
fad137cd
NR
3517 (1 font-lock-comment-face)
3518 (2 font-lock-function-name-face))
3519 ("^\\(End of assembler dump\\.\\)" . font-lock-comment-face))
3520 "Font lock keywords used in `gdb-assembler-mode'.")
3521
1ffac268
NR
3522(defun gdb-assembler-mode ()
3523 "Major mode for viewing code assembler.
3524
3525\\{gdb-assembler-mode-map}"
fad137cd 3526 (kill-all-local-variables)
1ffac268 3527 (setq major-mode 'gdb-assembler-mode)
5770a942 3528 (setq mode-name (concat "Machine:" gdb-selected-frame))
1ffac268
NR
3529 (setq gdb-overlay-arrow-position nil)
3530 (add-to-list 'overlay-arrow-variable-list 'gdb-overlay-arrow-position)
1ffac268
NR
3531 (setq fringes-outside-margins t)
3532 (setq buffer-read-only t)
5a1ad629 3533 (buffer-disable-undo)
59ae3049 3534 (gdb-thread-identification)
1ffac268 3535 (use-local-map gdb-assembler-mode-map)
fad137cd
NR
3536 (gdb-invalidate-assembler)
3537 (set (make-local-variable 'font-lock-defaults)
3538 '(gdb-assembler-font-lock-keywords))
3539 (run-mode-hooks 'gdb-assembler-mode-hook)
3540 'gdb-invalidate-assembler)
1ffac268
NR
3541
3542(defun gdb-assembler-buffer-name ()
3543 (with-current-buffer gud-comint-buffer
bfd21f54 3544 (concat "*disassembly of " (gdb-get-target-string) "*")))
1ffac268
NR
3545
3546(defun gdb-display-assembler-buffer ()
f6a2315e 3547 "Display disassembly view."
1ffac268 3548 (interactive)
af3f7411 3549 (setq gdb-previous-frame nil)
1ffac268 3550 (gdb-display-buffer
d138996e 3551 (gdb-get-buffer-create 'gdb-assembler-buffer) t))
1ffac268
NR
3552
3553(defun gdb-frame-assembler-buffer ()
f6a2315e 3554 "Display disassembly view in a new frame."
1ffac268 3555 (interactive)
af3f7411 3556 (setq gdb-previous-frame nil)
1a9203d0
NR
3557 (let ((special-display-regexps (append special-display-regexps '(".*")))
3558 (special-display-frame-alist gdb-frame-parameters))
f27d4d6c 3559 (display-buffer (gdb-get-buffer-create 'gdb-assembler-buffer))))
1ffac268 3560
ec180a26 3561;; modified because if gdb-pc-address has changed value a new command
1ffac268
NR
3562;; must be enqueued to update the buffer with the new output
3563(defun gdb-invalidate-assembler (&optional ignored)
3564 (if (gdb-get-buffer 'gdb-assembler-buffer)
3565 (progn
5770a942
NR
3566 (unless (and gdb-selected-frame
3567 (string-equal gdb-selected-frame gdb-previous-frame))
1ffac268 3568 (if (or (not (member 'gdb-invalidate-assembler
2cec1d1a 3569 gdb-pending-triggers))
3ed96733
NR
3570 (not (equal (string-to-number gdb-pc-address)
3571 (string-to-number
3572 gdb-previous-frame-pc-address))))
1ffac268 3573 (progn
5770a942 3574 ;; take previous disassemble command, if any, off the queue
1ffac268 3575 (with-current-buffer gud-comint-buffer
12032009 3576 (let ((queue gdb-input-queue))
1ffac268
NR
3577 (dolist (item queue)
3578 (if (equal (cdr item) '(gdb-assembler-handler))
2cec1d1a
NR
3579 (setq gdb-input-queue
3580 (delete item gdb-input-queue))))))
1ffac268 3581 (gdb-enqueue-input
5770a942 3582 (list
3ed96733 3583 (concat gdb-server-prefix "disassemble " gdb-pc-address "\n")
1ffac268 3584 'gdb-assembler-handler))
2cec1d1a 3585 (push 'gdb-invalidate-assembler gdb-pending-triggers)
7446b657 3586 (setq gdb-previous-frame-pc-address gdb-pc-address)
5770a942 3587 (setq gdb-previous-frame gdb-selected-frame)))))))
1ffac268 3588
5770a942
NR
3589(defun gdb-get-selected-frame ()
3590 (if (not (member 'gdb-get-selected-frame gdb-pending-triggers))
1ffac268 3591 (progn
7446b657
NR
3592 (if (string-equal gdb-version "pre-6.4")
3593 (gdb-enqueue-input
3594 (list (concat gdb-server-prefix "info frame\n")
3595 'gdb-frame-handler))
3596 (gdb-enqueue-input
3597 (list "server interpreter mi -stack-info-frame\n"
3598 'gdb-frame-handler-1)))
3599 (push 'gdb-get-selected-frame gdb-pending-triggers))))
1ffac268
NR
3600
3601(defun gdb-frame-handler ()
2cec1d1a 3602 (setq gdb-pending-triggers
5770a942 3603 (delq 'gdb-get-selected-frame gdb-pending-triggers))
564b25a4 3604 (goto-char (point-min))
ec180a26
NR
3605 (when (re-search-forward
3606 "Stack level \\([0-9]+\\), frame at \\(0x[[:xdigit:]]+\\)" nil t)
3607 (setq gdb-frame-number (match-string 1))
3608 (setq gdb-frame-address (match-string 2)))
564b25a4 3609 (goto-char (point-min))
3ed96733 3610 (when (re-search-forward ".*=\\s-+\\(\\S-*\\)\\s-+in\\s-+\\(.*?\\)\
3cfc0f43 3611\\(?: (\\(\\S-+?\\):[0-9]+?)\\)*; "
caf2f944
NR
3612 nil t)
3613 (setq gdb-selected-frame (match-string 2))
3614 (if (gdb-get-buffer 'gdb-locals-buffer)
3615 (with-current-buffer (gdb-get-buffer 'gdb-locals-buffer)
3616 (setq mode-name (concat "Locals:" gdb-selected-frame))))
3617 (if (gdb-get-buffer 'gdb-assembler-buffer)
3618 (with-current-buffer (gdb-get-buffer 'gdb-assembler-buffer)
3619 (setq mode-name (concat "Machine:" gdb-selected-frame))))
ec180a26 3620 (setq gdb-pc-address (match-string 1))
caf2f944 3621 (if (and (match-string 3) gud-overlay-arrow-position)
8928c512
NR
3622 (let ((buffer (marker-buffer gud-overlay-arrow-position))
3623 (position (marker-position gud-overlay-arrow-position)))
6f095055 3624 (when (and buffer
78971dff
NR
3625 (string-equal (file-name-nondirectory
3626 (buffer-file-name buffer))
6f095055 3627 (file-name-nondirectory (match-string 3))))
8928c512
NR
3628 (with-current-buffer buffer
3629 (setq fringe-indicator-alist
3630 (if (string-equal gdb-frame-number "0")
3631 nil
3632 '((overlay-arrow . hollow-right-triangle))))
caf2f944 3633 (set-marker gud-overlay-arrow-position position))))))
564b25a4 3634 (goto-char (point-min))
caf2f944 3635 (if (re-search-forward " source language \\(\\S-+\\)\." nil t)
564b25a4
NR
3636 (setq gdb-current-language (match-string 1)))
3637 (gdb-invalidate-assembler))
d91362c9 3638
b5e5e9f2 3639\f
25c7f315 3640;; Code specific to GDB 6.4
c05ba081 3641(defconst gdb-source-file-regexp-1 "fullname=\"\\(.*?\\)\"")
25c7f315
NR
3642
3643(defun gdb-set-gud-minor-mode-existing-buffers-1 ()
b5e5e9f2 3644 "Create list of source files for current GDB session.
55222dc8 3645If buffers already exist for any of these files, `gud-minor-mode'
b5e5e9f2 3646is set in them."
25c7f315 3647 (goto-char (point-min))
c05ba081 3648 (while (re-search-forward gdb-source-file-regexp-1 nil t)
25c7f315
NR
3649 (push (match-string 1) gdb-source-file-list))
3650 (dolist (buffer (buffer-list))
3651 (with-current-buffer buffer
3652 (when (member buffer-file-name gdb-source-file-list)
6c6273c6 3653 (gdb-init-buffer))))
303b246d
NR
3654 (gdb-force-mode-line-update
3655 (propertize "ready" 'face font-lock-variable-name-face)))
25c7f315 3656
7446b657
NR
3657;; Used for -stack-info-frame but could be used for -stack-list-frames too.
3658(defconst gdb-stack-list-frames-regexp
959005e4
NR
3659".*?level=\"\\(.*?\\)\".*?,addr=\"\\(.*?\\)\".*?,func=\"\\(.*?\\)\",\
3660\\(?:.*?file=\".*?\".*?,fullname=\"\\(.*?\\)\".*?,line=\"\\(.*?\\)\".*?}\\|\
7446b657
NR
3661from=\"\\(.*?\\)\"\\)")
3662
3663(defun gdb-frame-handler-1 ()
3664 (setq gdb-pending-triggers
3665 (delq 'gdb-get-selected-frame gdb-pending-triggers))
3666 (goto-char (point-min))
3667 (when (re-search-forward gdb-stack-list-frames-regexp nil t)
3668 (setq gdb-frame-number (match-string 1))
3669 (setq gdb-pc-address (match-string 2))
3670 (setq gdb-selected-frame (match-string 3))
3671 (if (gdb-get-buffer 'gdb-locals-buffer)
3672 (with-current-buffer (gdb-get-buffer 'gdb-locals-buffer)
3673 (setq mode-name (concat "Locals:" gdb-selected-frame))))
3674 (if (gdb-get-buffer 'gdb-assembler-buffer)
3675 (with-current-buffer (gdb-get-buffer 'gdb-assembler-buffer)
3676 (setq mode-name (concat "Machine:" gdb-selected-frame)))))
37c72343
NR
3677 (if (and (match-string 4) (match-string 5) gud-overlay-arrow-position)
3678 (let ((buffer (marker-buffer gud-overlay-arrow-position))
3679 (position (marker-position gud-overlay-arrow-position)))
3680 (when (and buffer
3681 (string-equal (file-name-nondirectory
3682 (buffer-file-name buffer))
3683 (file-name-nondirectory (match-string 4))))
3684 (with-current-buffer buffer
3685 (setq fringe-indicator-alist
3686 (if (string-equal gdb-frame-number "0")
3687 nil
3688 '((overlay-arrow . hollow-right-triangle))))
3689 (set-marker gud-overlay-arrow-position position)))))
7446b657
NR
3690 (gdb-invalidate-assembler))
3691
266e779b 3692; Uses "-var-list-children --all-values". Needs GDB 6.4 onwards.
25c7f315
NR
3693(defun gdb-var-list-children-1 (varnum)
3694 (gdb-enqueue-input
621b3aac
NR
3695 (list
3696 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
bc676c58
NR
3697 (concat "server interpreter mi \"-var-list-children --all-values \\\""
3698 varnum "\\\"\"\n")
3699 (concat "-var-list-children --all-values \"" varnum "\"\n"))
621b3aac 3700 `(lambda () (gdb-var-list-children-handler-1 ,varnum)))))
25c7f315
NR
3701
3702(defconst gdb-var-list-children-regexp-1
959005e4
NR
3703 "child={.*?name=\"\\(.+?\\)\".*?,exp=\"\\(.+?\\)\".*?,\
3704numchild=\"\\(.+?\\)\".*?,value=\\(\".*?\"\\)\
3705\\(}\\|.*?,\\(type=\"\\(.+?\\)\"\\)?.*?}\\)")
25c7f315
NR
3706
3707(defun gdb-var-list-children-handler-1 (varnum)
3708 (goto-char (point-min))
3709 (let ((var-list nil))
3710 (catch 'child-already-watched
3711 (dolist (var gdb-var-list)
37c7ef17 3712 (if (string-equal varnum (car var))
25c7f315
NR
3713 (progn
3714 (push var var-list)
3715 (while (re-search-forward gdb-var-list-children-regexp-1 nil t)
37c7ef17
NR
3716 (let ((varchild (list (match-string 1)
3717 (match-string 2)
25c7f315 3718 (match-string 3)
8687849b 3719 (match-string 7)
25c7f315
NR
3720 (read (match-string 4))
3721 nil)))
37c7ef17
NR
3722 (if (assoc (car varchild) gdb-var-list)
3723 (throw 'child-already-watched nil))
25c7f315
NR
3724 (push varchild var-list))))
3725 (push var var-list)))
51158d69
NR
3726 (setq gdb-var-list (nreverse var-list))))
3727 (gdb-speedbar-update))
25c7f315
NR
3728
3729; Uses "-var-update --all-values". Needs GDB 6.4 onwards.
3730(defun gdb-var-update-1 ()
3731 (if (not (member 'gdb-var-update gdb-pending-triggers))
3732 (progn
3733 (gdb-enqueue-input
3734 (list
621b3aac 3735 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
25c7f315
NR
3736 "server interpreter mi \"-var-update --all-values *\"\n"
3737 "-var-update --all-values *\n")
621b3aac 3738 'gdb-var-update-handler-1))
25c7f315
NR
3739 (push 'gdb-var-update gdb-pending-triggers))))
3740
b32d1b9b 3741(defconst gdb-var-update-regexp-1
959005e4 3742 "{.*?name=\"\\(.*?\\)\".*?,\\(?:value=\\(\".*?\"\\),\\)?.*?\
8928c512 3743in_scope=\"\\(.*?\\)\".*?}")
25c7f315
NR
3744
3745(defun gdb-var-update-handler-1 ()
054d409e 3746 (dolist (var gdb-var-list)
054d409e
NR
3747 (setcar (nthcdr 5 var) nil))
3748 (goto-char (point-min))
25c7f315 3749 (while (re-search-forward gdb-var-update-regexp-1 nil t)
37c7ef17
NR
3750 (let* ((varnum (match-string 1))
3751 (var (assoc varnum gdb-var-list)))
3752 (when var
5754d11f
NR
3753 (let ((match (match-string 3)))
3754 (cond ((string-equal match "false")
f8fef1ce
NR
3755 (if gdb-delete-out-of-scope
3756 (gdb-var-delete-1 varnum)
3757 (setcar (nthcdr 5 var) 'out-of-scope)))
5754d11f
NR
3758 ((string-equal match "true")
3759 (setcar (nthcdr 5 var) 'changed)
3760 (setcar (nthcdr 4 var)
3761 (read (match-string 2))))
01b8fc60
NR
3762 ((string-equal match "invalid")
3763 (gdb-var-delete-1 varnum)))))))
5754d11f
NR
3764 (setq gdb-pending-triggers
3765 (delq 'gdb-var-update gdb-pending-triggers))
3766 (gdb-speedbar-update))
25c7f315
NR
3767
3768;; Registers buffer.
3769;;
3770(gdb-set-buffer-rules 'gdb-registers-buffer
3771 'gdb-registers-buffer-name
3772 'gdb-registers-mode)
3773
3774(def-gdb-auto-update-trigger gdb-invalidate-registers-1
3775 (gdb-get-buffer 'gdb-registers-buffer)
621b3aac 3776 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
25c7f315
NR
3777 "server interpreter mi \"-data-list-register-values x\"\n"
3778 "-data-list-register-values x\n")
3779 gdb-data-list-register-values-handler)
3780
3781(defconst gdb-data-list-register-values-regexp
959005e4 3782 "{.*?number=\"\\(.*?\\)\".*?,value=\"\\(.*?\\)\".*?}")
25c7f315
NR
3783
3784(defun gdb-data-list-register-values-handler ()
c05ba081 3785 (setq gdb-pending-triggers (delq 'gdb-invalidate-registers-1
25c7f315
NR
3786 gdb-pending-triggers))
3787 (goto-char (point-min))
3788 (if (re-search-forward gdb-error-regexp nil t)
caf2f944
NR
3789 (let ((err (match-string 1)))
3790 (with-current-buffer (gdb-get-buffer 'gdb-registers-buffer)
3791 (let ((buffer-read-only nil))
3792 (erase-buffer)
eff8536f 3793 (put-text-property 0 (length err) 'face font-lock-warning-face err)
caf2f944
NR
3794 (insert err)
3795 (goto-char (point-min)))))
25c7f315
NR
3796 (let ((register-list (reverse gdb-register-names))
3797 (register nil) (register-string nil) (register-values nil))
3798 (goto-char (point-min))
3799 (while (re-search-forward gdb-data-list-register-values-regexp nil t)
3800 (setq register (pop register-list))
3801 (setq register-string (concat register "\t" (match-string 2) "\n"))
3802 (if (member (match-string 1) gdb-changed-registers)
3803 (put-text-property 0 (length register-string)
3804 'face 'font-lock-warning-face
3805 register-string))
3806 (setq register-values
3807 (concat register-values register-string)))
3808 (let ((buf (gdb-get-buffer 'gdb-registers-buffer)))
3809 (with-current-buffer buf
f27d4d6c
NR
3810 (let* ((window (get-buffer-window buf 0))
3811 (start (window-start window))
3812 (p (window-point window))
3813 (buffer-read-only nil))
25c7f315
NR
3814 (erase-buffer)
3815 (insert register-values)
f27d4d6c
NR
3816 (set-window-start window start)
3817 (set-window-point window p))))))
25c7f315
NR
3818 (gdb-data-list-register-values-custom))
3819
3820(defun gdb-data-list-register-values-custom ()
3821 (with-current-buffer (gdb-get-buffer 'gdb-registers-buffer)
3822 (save-excursion
3823 (let ((buffer-read-only nil)
3824 start end)
3825 (goto-char (point-min))
3826 (while (< (point) (point-max))
3827 (setq start (line-beginning-position))
3828 (setq end (line-end-position))
3829 (when (looking-at "^[^\t]+")
3830 (unless (string-equal (match-string 0) "No registers.")
3831 (put-text-property start (match-end 0)
3832 'face font-lock-variable-name-face)
4b479fae 3833 (add-text-properties start end
25c7f315
NR
3834 '(help-echo "mouse-2: edit value"
3835 mouse-face highlight))))
3836 (forward-line 1))))))
3837
3838;; Needs GDB 6.4 onwards (used to fail with no stack).
3839(defun gdb-get-changed-registers ()
621b3aac
NR
3840 (if (and (gdb-get-buffer 'gdb-registers-buffer)
3841 (not (member 'gdb-get-changed-registers gdb-pending-triggers)))
25c7f315
NR
3842 (progn
3843 (gdb-enqueue-input
3844 (list
621b3aac 3845 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
25c7f315
NR
3846 "server interpreter mi -data-list-changed-registers\n"
3847 "-data-list-changed-registers\n")
621b3aac 3848 'gdb-get-changed-registers-handler))
25c7f315
NR
3849 (push 'gdb-get-changed-registers gdb-pending-triggers))))
3850
3851(defconst gdb-data-list-register-names-regexp "\"\\(.*?\\)\"")
3852
3853(defun gdb-get-changed-registers-handler ()
3854 (setq gdb-pending-triggers
3855 (delq 'gdb-get-changed-registers gdb-pending-triggers))
3856 (setq gdb-changed-registers nil)
3857 (goto-char (point-min))
3858 (while (re-search-forward gdb-data-list-register-names-regexp nil t)
3859 (push (match-string 1) gdb-changed-registers)))
3860\f
3861
3862;; Locals buffer.
3863;;
3864;; uses "-stack-list-locals --simple-values". Needs GDB 6.1 onwards.
3865(gdb-set-buffer-rules 'gdb-locals-buffer
3866 'gdb-locals-buffer-name
3867 'gdb-locals-mode)
3868
3869(def-gdb-auto-update-trigger gdb-invalidate-locals-1
3870 (gdb-get-buffer 'gdb-locals-buffer)
621b3aac
NR
3871 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
3872 "server interpreter mi -\"stack-list-locals --simple-values\"\n"
3873 "-stack-list-locals --simple-values\n")
25c7f315
NR
3874 gdb-stack-list-locals-handler)
3875
3876(defconst gdb-stack-list-locals-regexp
959005e4 3877 "{.*?name=\"\\(.*?\\)\".*?,type=\"\\(.*?\\)\"")
25c7f315
NR
3878
3879(defvar gdb-locals-watch-map-1
3880 (let ((map (make-sparse-keymap)))
38a52690
NR
3881 (suppress-keymap map)
3882 (define-key map "\r" 'gud-watch)
25c7f315
NR
3883 (define-key map [mouse-2] 'gud-watch)
3884 map)
55222dc8 3885 "Keymap to create watch expression of a complex data type local variable.")
25c7f315 3886
38a52690
NR
3887(defvar gdb-edit-locals-map-1
3888 (let ((map (make-sparse-keymap)))
3889 (suppress-keymap map)
3890 (define-key map "\r" 'gdb-edit-locals-value)
3891 (define-key map [mouse-2] 'gdb-edit-locals-value)
3892 map)
55222dc8 3893 "Keymap to edit value of a simple data type local variable.")
38a52690
NR
3894
3895(defun gdb-edit-locals-value (&optional event)
3896 "Assign a value to a variable displayed in the locals buffer."
3897 (interactive (list last-input-event))
3898 (save-excursion
3899 (if event (posn-set-point (event-end event)))
3900 (beginning-of-line)
3901 (let* ((var (current-word))
3902 (value (read-string (format "New value (%s): " var))))
3903 (gdb-enqueue-input
959005e4 3904 (list (concat gdb-server-prefix "set variable " var " = " value "\n")
bfe0c147 3905 'ignore)))))
38a52690 3906
25c7f315
NR
3907;; Dont display values of arrays or structures.
3908;; These can be expanded using gud-watch.
3909(defun gdb-stack-list-locals-handler ()
3910 (setq gdb-pending-triggers (delq 'gdb-invalidate-locals-1
3911 gdb-pending-triggers))
eff8536f
NR
3912 (goto-char (point-min))
3913 (if (re-search-forward gdb-error-regexp nil t)
3914 (let ((err (match-string 1)))
3915 (with-current-buffer (gdb-get-buffer 'gdb-locals-buffer)
3916 (let ((buffer-read-only nil))
3917 (erase-buffer)
3918 (insert err)
3919 (goto-char (point-min)))))
3920 (let (local locals-list)
3921 (goto-char (point-min))
3922 (while (re-search-forward gdb-stack-list-locals-regexp nil t)
3923 (let ((local (list (match-string 1)
3924 (match-string 2)
3925 nil)))
3926 (if (looking-at ",value=\\(\".*\"\\).*?}")
3927 (setcar (nthcdr 2 local) (read (match-string 1))))
3928 (push local locals-list)))
3929 (let ((buf (gdb-get-buffer 'gdb-locals-buffer)))
3930 (and buf (with-current-buffer buf
3931 (let* ((window (get-buffer-window buf 0))
3932 (start (window-start window))
3933 (p (window-point window))
38a52690 3934 (buffer-read-only nil) (name) (value))
eff8536f
NR
3935 (erase-buffer)
3936 (dolist (local locals-list)
3937 (setq name (car local))
38a52690
NR
3938 (setq value (nth 2 local))
3939 (if (or (not value)
3940 (string-match "^\\0x" value))
eff8536f
NR
3941 (add-text-properties 0 (length name)
3942 `(mouse-face highlight
3943 help-echo "mouse-2: create watch expression"
3944 local-map ,gdb-locals-watch-map-1)
38a52690
NR
3945 name)
3946 (add-text-properties 0 (length value)
3947 `(mouse-face highlight
3948 help-echo "mouse-2: edit value"
3949 local-map ,gdb-edit-locals-map-1)
3950 value))
4b479fae 3951 (insert
25c7f315 3952 (concat name "\t" (nth 1 local)
b2f5a4ac 3953 "\t" value "\n")))
eff8536f
NR
3954 (set-window-start window start)
3955 (set-window-point window p))))))))
25c7f315
NR
3956
3957(defun gdb-get-register-names ()
3958 "Create a list of register names."
3959 (goto-char (point-min))
3960 (setq gdb-register-names nil)
3961 (while (re-search-forward gdb-data-list-register-names-regexp nil t)
3962 (push (match-string 1) gdb-register-names)))
3963
1ffac268
NR
3964(provide 'gdb-ui)
3965
d490ebbe 3966;; arch-tag: e9fb00c5-74ef-469f-a088-37384caae352
1ffac268 3967;;; gdb-ui.el ends here