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