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