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