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