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