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