(gdb-resync): New function.
[bpt/emacs.git] / lisp / progmodes / gdb-ui.el
1 ;;; gdb-ui.el --- User Interface for running GDB
2
3 ;; Author: Nick Roberts <nickrob@gnu.org>
4 ;; Maintainer: FSF
5 ;; Keywords: unix, tools
6
7 ;; Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
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
28 ;; This mode acts as a graphical user interface to GDB. You can interact with
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.
31 ;; It separates the input/output of your program from that of GDB, if
32 ;; required, and watches expressions in the speedbar. It also uses features of
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).
35
36 ;; Start the debugger with M-x gdba.
37
38 ;; This file has evolved from gdba.el from GDB 5.0 written by Tom Lord and Jim
39 ;; Kingdon and uses GDB's annotation interface. You don't need to know about
40 ;; annotations to use this mode as a debugger, but if you are interested
41 ;; developing the mode itself, then see the Annotations section in the GDB
42 ;; info manual.
43 ;;
44 ;; GDB developers plan to make the annotation interface obsolete. A new
45 ;; interface called GDB/MI (machine interface) has been designed to replace
46 ;; it. Some GDB/MI commands are used in this file through the CLI command
47 ;; 'interpreter mi <mi-command>'. A file called gdb-mi.el is included in the
48 ;; GDB repository for future releases (6.2 onwards) that uses GDB/MI as the
49 ;; primary interface to GDB. It is still under development and is part of a
50 ;; process to migrate Emacs from annotations to GDB/MI.
51 ;;
52 ;; Known Bugs:
53 ;;
54
55 ;;; Code:
56
57 (require 'gud)
58
59 (defvar gdb-current-address "main" "Initialisation for Assembler buffer.")
60 (defvar gdb-previous-address nil)
61 (defvar gdb-previous-frame nil)
62 (defvar gdb-current-frame nil)
63 (defvar gdb-current-stack-level nil)
64 (defvar gdb-current-language nil)
65 (defvar gdb-view-source t "Non-nil means that source code can be viewed.")
66 (defvar gdb-selected-view 'source "Code type that user wishes to view.")
67 (defvar gdb-var-list nil "List of variables in watch window.")
68 (defvar gdb-var-changed nil "Non-nil means that gdb-var-list has changed.")
69 (defvar gdb-buffer-type nil)
70 (defvar gdb-overlay-arrow-position nil)
71 (defvar gdb-server-prefix nil)
72
73 (defvar gdb-buffer-type nil
74 "One of the symbols bound in `gdb-buffer-rules'.")
75
76 (defvar gdb-input-queue ()
77 "A list of gdb command objects.")
78
79 (defvar gdb-prompting nil
80 "True when gdb is idle with no pending input.")
81
82 (defvar gdb-output-sink 'user
83 "The disposition of the output of the current gdb command.
84 Possible values are these symbols:
85
86 `user' -- gdb output should be copied to the GUD buffer
87 for the user to see.
88
89 `inferior' -- gdb output should be copied to the inferior-io buffer
90
91 `pre-emacs' -- output should be ignored util the post-prompt
92 annotation is received. Then the output-sink
93 becomes:...
94 `emacs' -- output should be collected in the partial-output-buffer
95 for subsequent processing by a command. This is the
96 disposition of output generated by commands that
97 gdb mode sends to gdb on its own behalf.
98 `post-emacs' -- ignore output until the prompt annotation is
99 received, then go to USER disposition.
100
101 gdba (gdb-ui.el) uses all five values, gdbmi (gdb-mi.el) only two
102 \(`user' and `emacs').")
103
104 (defvar gdb-current-item nil
105 "The most recent command item sent to gdb.")
106
107 (defvar gdb-pending-triggers '()
108 "A list of trigger functions that have run later than their output
109 handlers.")
110
111 ;; end of gdb variables
112
113 ;;;###autoload
114 (defun gdba (command-line)
115 "Run gdb on program FILE in buffer *gud-FILE*.
116 The directory containing FILE becomes the initial working directory
117 and source-file directory for your debugger.
118
119 If `gdb-many-windows' is nil (the default value) then gdb just
120 pops up the GUD buffer unless `gdb-show-main' is t. In this case
121 it starts with two windows: one displaying the GUD buffer and the
122 other with the source file with the main routine of the inferior.
123
124 If `gdb-many-windows' is t, regardless of the value of
125 `gdb-show-main', the layout below will appear unless
126 `gdb-use-inferior-io-buffer' is nil when the source buffer
127 occupies the full width of the frame. Keybindings are given in
128 relevant buffer.
129
130 Watch expressions appear in the speedbar/slowbar.
131
132 The following commands help control operation :
133
134 `gdb-many-windows' - Toggle the number of windows gdb uses.
135 `gdb-restore-windows' - To restore the window layout.
136
137 See Info node `(emacs)GDB Graphical Interface' for a more
138 detailed description of this mode.
139
140
141 ---------------------------------------------------------------------
142 GDB Toolbar
143 ---------------------------------------------------------------------
144 GUD buffer (I/O of GDB) | Locals buffer
145 |
146 |
147 |
148 ---------------------------------------------------------------------
149 Source buffer | Input/Output (of inferior) buffer
150 | (comint-mode)
151 |
152 |
153 |
154 |
155 |
156 |
157 ---------------------------------------------------------------------
158 Stack buffer | Breakpoints buffer
159 RET gdb-frames-select | SPC gdb-toggle-breakpoint
160 | RET gdb-goto-breakpoint
161 | d gdb-delete-breakpoint
162 ---------------------------------------------------------------------"
163 ;;
164 (interactive (list (gud-query-cmdline 'gdba)))
165 ;;
166 ;; Let's start with a basic gud-gdb buffer and then modify it a bit.
167 (gdb command-line)
168 (gdb-ann3))
169
170 (defvar gdb-debug-log nil)
171
172 (defcustom gdb-enable-debug-log nil
173 "Non-nil means record the process input and output in `gdb-debug-log'."
174 :type 'boolean
175 :group 'gud
176 :version "21.4")
177
178 (defcustom gdb-use-inferior-io-buffer nil
179 "Non-nil means display output from the inferior in a separate buffer."
180 :type 'boolean
181 :group 'gud
182 :version "21.4")
183
184 (defun gdb-ann3 ()
185 (setq gdb-debug-log nil)
186 (set (make-local-variable 'gud-minor-mode) 'gdba)
187 (set (make-local-variable 'gud-marker-filter) 'gud-gdba-marker-filter)
188 ;;
189 (gud-def gud-break (if (not (string-equal mode-name "Machine"))
190 (gud-call "break %f:%l" arg)
191 (save-excursion
192 (beginning-of-line)
193 (forward-char 2)
194 (gud-call "break *%a" arg)))
195 "\C-b" "Set breakpoint at current line or address.")
196 ;;
197 (gud-def gud-remove (if (not (string-equal mode-name "Machine"))
198 (gud-call "clear %f:%l" arg)
199 (save-excursion
200 (beginning-of-line)
201 (forward-char 2)
202 (gud-call "clear *%a" arg)))
203 "\C-d" "Remove breakpoint at current line or address.")
204 ;;
205 (gud-def gud-until (if (not (string-equal mode-name "Machine"))
206 (gud-call "until %f:%l" arg)
207 (save-excursion
208 (beginning-of-line)
209 (forward-char 2)
210 (gud-call "until *%a" arg)))
211 "\C-u" "Continue to current line or address.")
212
213 (define-key gud-minor-mode-map [left-margin mouse-1]
214 'gdb-mouse-toggle-breakpoint)
215 (define-key gud-minor-mode-map [left-fringe mouse-1]
216 'gdb-mouse-toggle-breakpoint)
217
218 (setq comint-input-sender 'gdb-send)
219 ;;
220 ;; (re-)initialize
221 (setq gdb-current-address "main")
222 (setq gdb-previous-address nil)
223 (setq gdb-previous-frame nil)
224 (setq gdb-current-frame nil)
225 (setq gdb-current-stack-level nil)
226 (setq gdb-view-source t)
227 (setq gdb-selected-view 'source)
228 (setq gdb-var-list nil)
229 (setq gdb-var-changed nil)
230 (setq gdb-first-prompt nil)
231 (setq gdb-prompting nil)
232 (setq gdb-input-queue nil)
233 (setq gdb-current-item nil)
234 (setq gdb-pending-triggers nil)
235 (setq gdb-output-sink 'user)
236 (setq gdb-server-prefix "server ")
237 ;;
238 (setq gdb-buffer-type 'gdba)
239 ;;
240 (if gdb-use-inferior-io-buffer (gdb-clear-inferior-io))
241 ;;
242 (if (eq window-system 'w32)
243 (gdb-enqueue-input (list "set new-console off\n" 'ignore)))
244 (gdb-enqueue-input (list "set height 0\n" 'ignore))
245 ;; find source file and compilation directory here
246 (gdb-enqueue-input (list "server list main\n" 'ignore)) ; C program
247 (gdb-enqueue-input (list "server list MAIN__\n" 'ignore)) ; Fortran program
248 (gdb-enqueue-input (list "server info source\n" 'gdb-source-info))
249 ;;
250 (run-hooks 'gdba-mode-hook))
251
252 (defcustom gdb-use-colon-colon-notation nil
253 "If non-nil use FUN::VAR format to display variables in the speedbar." ;
254 :type 'boolean
255 :group 'gud
256 :version "21.4")
257
258 (defun gud-watch ()
259 "Watch expression at point."
260 (interactive)
261 (require 'tooltip)
262 (let ((expr (tooltip-identifier-from-point (point))))
263 (if (and (string-equal gdb-current-language "c")
264 gdb-use-colon-colon-notation gdb-current-frame)
265 (setq expr (concat gdb-current-frame "::" expr)))
266 (catch 'already-watched
267 (dolist (var gdb-var-list)
268 (if (string-equal expr (car var)) (throw 'already-watched nil)))
269 (set-text-properties 0 (length expr) nil expr)
270 (gdb-enqueue-input
271 (list
272 (if (eq gud-minor-mode 'gdba)
273 (concat "server interpreter mi \"-var-create - * " expr "\"\n")
274 (concat"-var-create - * " expr "\n"))
275 `(lambda () (gdb-var-create-handler ,expr))))))
276 (select-window (get-buffer-window gud-comint-buffer 'visible)))
277
278 (defun gdb-goto-info ()
279 "Go to Emacs info node: GDB Graphical Interface."
280 (interactive)
281 (select-frame (make-frame))
282 (require 'info)
283 (Info-goto-node "(emacs)GDB Graphical Interface"))
284
285 (defconst gdb-var-create-regexp
286 "name=\"\\(.*?\\)\",numchild=\"\\(.*?\\)\",type=\"\\(.*?\\)\"")
287
288 (defun gdb-var-create-handler (expr)
289 (with-current-buffer (gdb-get-create-buffer 'gdb-partial-output-buffer)
290 (goto-char (point-min))
291 (if (re-search-forward gdb-var-create-regexp nil t)
292 (let ((var (list expr
293 (match-string 1)
294 (match-string 2)
295 (match-string 3)
296 nil nil)))
297 (push var gdb-var-list)
298 (setq speedbar-update-flag t)
299 (speedbar 1)
300 (if (equal (nth 2 var) "0")
301 (gdb-enqueue-input
302 (list (concat "server interpreter mi \"-var-evaluate-expression "
303 (nth 1 var) "\"\n")
304 `(lambda () (gdb-var-evaluate-expression-handler
305 ,(nth 1 var) nil))))
306 (setq gdb-var-changed t)))
307 (if (re-search-forward "Undefined command" nil t)
308 (message "Watching expressions requires gdb 6.0 onwards")
309 (message "No symbol %s in current context." expr)))))
310
311 (defun gdb-var-evaluate-expression-handler (varnum changed)
312 (with-current-buffer (gdb-get-create-buffer 'gdb-partial-output-buffer)
313 (goto-char (point-min))
314 (re-search-forward ".*value=\"\\(.*?\\)\"" nil t)
315 (catch 'var-found
316 (let ((var-list nil) (num 0))
317 (dolist (var gdb-var-list)
318 (if (string-equal varnum (cadr var))
319 (progn
320 (if changed (setcar (nthcdr 5 var) t))
321 (setcar (nthcdr 4 var) (match-string 1))
322 (setcar (nthcdr num gdb-var-list) var)
323 (throw 'var-found nil)))
324 (setq num (+ num 1))))))
325 (setq gdb-var-changed t))
326
327 (defun gdb-var-list-children (varnum)
328 (gdb-enqueue-input
329 (list (concat "server interpreter mi \"-var-list-children " varnum "\"\n")
330 `(lambda () (gdb-var-list-children-handler ,varnum)))))
331
332 (defconst gdb-var-list-children-regexp
333 "name=\"\\(.*?\\)\",exp=\"\\(.*?\\)\",numchild=\"\\(.*?\\)\"")
334
335 (defun gdb-var-list-children-handler (varnum)
336 (with-current-buffer (gdb-get-create-buffer 'gdb-partial-output-buffer)
337 (goto-char (point-min))
338 (let ((var-list nil))
339 (catch 'child-already-watched
340 (dolist (var gdb-var-list)
341 (if (string-equal varnum (cadr var))
342 (progn
343 (push var var-list)
344 (while (re-search-forward gdb-var-list-children-regexp nil t)
345 (let ((varchild (list (match-string 2)
346 (match-string 1)
347 (match-string 3)
348 nil nil nil)))
349 (if (looking-at ",type=\"\\(.*?\\)\"")
350 (setcar (nthcdr 3 varchild) (match-string 1)))
351 (dolist (var1 gdb-var-list)
352 (if (string-equal (cadr var1) (cadr varchild))
353 (throw 'child-already-watched nil)))
354 (push varchild var-list)
355 (if (equal (nth 2 varchild) "0")
356 (gdb-enqueue-input
357 (list
358 (concat
359 "server interpreter mi \"-var-evaluate-expression "
360 (nth 1 varchild) "\"\n")
361 `(lambda () (gdb-var-evaluate-expression-handler
362 ,(nth 1 varchild) nil))))))))
363 (push var var-list)))
364 (setq gdb-var-list (nreverse var-list))))))
365
366 (defun gdb-var-update ()
367 (if (not (member 'gdb-var-update gdb-pending-triggers))
368 (progn
369 (gdb-enqueue-input
370 (list
371 (if (with-current-buffer gud-comint-buffer (eq gud-minor-mode 'gdba))
372 "server interpreter mi \"-var-update *\"\n"
373 "-var-update *\n")
374 'gdb-var-update-handler))
375 (push 'gdb-var-update gdb-pending-triggers))))
376
377 (defconst gdb-var-update-regexp "name=\"\\(.*?\\)\"")
378
379 (defun gdb-var-update-handler ()
380 (with-current-buffer (gdb-get-create-buffer 'gdb-partial-output-buffer)
381 (goto-char (point-min))
382 (while (re-search-forward gdb-var-update-regexp nil t)
383 (let ((varnum (match-string 1)))
384 (gdb-enqueue-input
385 (list
386 (if (with-current-buffer gud-comint-buffer (eq gud-minor-mode 'gdba))
387 (concat "server interpreter mi \"-var-evaluate-expression "
388 varnum "\"\n")
389 (concat "-var-evaluate-expression " varnum "\n"))
390 `(lambda () (gdb-var-evaluate-expression-handler
391 ,varnum t)))))))
392 (setq gdb-pending-triggers
393 (delq 'gdb-var-update gdb-pending-triggers)))
394
395 (defun gdb-var-delete ()
396 "Delete watched expression from the speedbar."
397 (interactive)
398 (if (with-current-buffer gud-comint-buffer (eq gud-minor-mode 'gdba))
399 (let ((text (speedbar-line-text)))
400 (string-match "\\(\\S-+\\)" text)
401 (let* ((expr (match-string 1 text))
402 (var (assoc expr gdb-var-list))
403 (varnum (cadr var)))
404 (unless (string-match "\\." varnum)
405 (gdb-enqueue-input
406 (list
407 (if (with-current-buffer gud-comint-buffer
408 (eq gud-minor-mode 'gdba))
409 (concat "server interpreter mi \"-var-delete " varnum "\"\n")
410 (concat "-var-delete " varnum "\n"))
411 'ignore))
412 (setq gdb-var-list (delq var gdb-var-list))
413 (dolist (varchild gdb-var-list)
414 (if (string-match (concat (nth 1 var) "\\.") (nth 1 varchild))
415 (setq gdb-var-list (delq varchild gdb-var-list))))
416 (setq gdb-var-changed t))))))
417
418 (defun gdb-edit-value (text token indent)
419 "Assign a value to a variable displayed in the speedbar."
420 (let* ((var (nth (- (count-lines (point-min) (point)) 2) gdb-var-list))
421 (varnum (cadr var)) (value))
422 (setq value (read-string "New value: "))
423 (gdb-enqueue-input
424 (list
425 (if (with-current-buffer gud-comint-buffer
426 (eq gud-minor-mode 'gdba))
427 (concat "server interpreter mi \"-var-assign " varnum " " value "\"\n")
428 (concat "-var-assign " varnum " " value "\n"))
429 'ignore))))
430
431 (defcustom gdb-show-changed-values t
432 "If non-nil highlight values that have recently changed in the speedbar.
433 The highlighting is done with `font-lock-warning-face'."
434 :type 'boolean
435 :group 'gud
436 :version "21.4")
437
438 (defun gdb-speedbar-expand-node (text token indent)
439 "Expand the node the user clicked on.
440 TEXT is the text of the button we clicked on, a + or - item.
441 TOKEN is data related to this node.
442 INDENT is the current indentation depth."
443 (cond ((string-match "+" text) ;expand this node
444 (if (with-current-buffer gud-comint-buffer (eq gud-minor-mode 'gdba))
445 (gdb-var-list-children token)
446 (gdbmi-var-list-children token)))
447 ((string-match "-" text) ;contract this node
448 (dolist (var gdb-var-list)
449 (if (string-match (concat token "\\.") (nth 1 var))
450 (setq gdb-var-list (delq var gdb-var-list))))
451 (setq gdb-var-changed t))))
452
453 (defun gdb-get-target-string ()
454 (with-current-buffer gud-comint-buffer
455 gud-target-name))
456 \f
457
458 ;;
459 ;; gdb buffers.
460 ;;
461 ;; Each buffer has a TYPE -- a symbol that identifies the function
462 ;; of that particular buffer.
463 ;;
464 ;; The usual gdb interaction buffer is given the type `gdba' and
465 ;; is constructed specially.
466 ;;
467 ;; Others are constructed by gdb-get-create-buffer and
468 ;; named according to the rules set forth in the gdb-buffer-rules-assoc
469
470 (defvar gdb-buffer-rules-assoc '())
471
472 (defun gdb-get-buffer (key)
473 "Return the gdb buffer tagged with type KEY.
474 The key should be one of the cars in `gdb-buffer-rules-assoc'."
475 (save-excursion
476 (gdb-look-for-tagged-buffer key (buffer-list))))
477
478 (defun gdb-get-create-buffer (key)
479 "Create a new gdb buffer of the type specified by KEY.
480 The key should be one of the cars in `gdb-buffer-rules-assoc'."
481 (or (gdb-get-buffer key)
482 (let* ((rules (assoc key gdb-buffer-rules-assoc))
483 (name (funcall (gdb-rules-name-maker rules)))
484 (new (get-buffer-create name)))
485 (with-current-buffer new
486 (let ((trigger))
487 (if (cdr (cdr rules))
488 (setq trigger (funcall (car (cdr (cdr rules))))))
489 (set (make-local-variable 'gdb-buffer-type) key)
490 (set (make-local-variable 'gud-minor-mode)
491 (with-current-buffer gud-comint-buffer gud-minor-mode))
492 (set (make-local-variable 'tool-bar-map) gud-tool-bar-map)
493 (if trigger (funcall trigger)))
494 new))))
495
496 (defun gdb-rules-name-maker (rules) (car (cdr rules)))
497
498 (defun gdb-look-for-tagged-buffer (key bufs)
499 (let ((retval nil))
500 (while (and (not retval) bufs)
501 (set-buffer (car bufs))
502 (if (eq gdb-buffer-type key)
503 (setq retval (car bufs)))
504 (setq bufs (cdr bufs)))
505 retval))
506
507 ;;
508 ;; This assoc maps buffer type symbols to rules. Each rule is a list of
509 ;; at least one and possible more functions. The functions have these
510 ;; roles in defining a buffer type:
511 ;;
512 ;; NAME - Return a name for this buffer type.
513 ;;
514 ;; The remaining function(s) are optional:
515 ;;
516 ;; MODE - called in a new buffer with no arguments, should establish
517 ;; the proper mode for the buffer.
518 ;;
519
520 (defun gdb-set-buffer-rules (buffer-type &rest rules)
521 (let ((binding (assoc buffer-type gdb-buffer-rules-assoc)))
522 (if binding
523 (setcdr binding rules)
524 (push (cons buffer-type rules)
525 gdb-buffer-rules-assoc))))
526
527 ;; GUD buffers are an exception to the rules
528 (gdb-set-buffer-rules 'gdba 'error)
529
530 ;;
531 ;; Partial-output buffer : This accumulates output from a command executed on
532 ;; behalf of emacs (rather than the user).
533 ;;
534 (gdb-set-buffer-rules 'gdb-partial-output-buffer
535 'gdb-partial-output-name)
536
537 (defun gdb-partial-output-name ()
538 (concat "*partial-output-"
539 (gdb-get-target-string)
540 "*"))
541
542 \f
543 (gdb-set-buffer-rules 'gdb-inferior-io
544 'gdb-inferior-io-name
545 'gdb-inferior-io-mode)
546
547 (defun gdb-inferior-io-name ()
548 (concat "*input/output of "
549 (gdb-get-target-string)
550 "*"))
551
552 (defvar gdb-inferior-io-mode-map
553 (let ((map (make-sparse-keymap)))
554 (define-key map "\C-c\C-c" 'gdb-inferior-io-interrupt)
555 (define-key map "\C-c\C-z" 'gdb-inferior-io-stop)
556 (define-key map "\C-c\C-\\" 'gdb-inferior-io-quit)
557 (define-key map "\C-c\C-d" 'gdb-inferior-io-eof)
558 map))
559
560 (define-derived-mode gdb-inferior-io-mode comint-mode "Inferior I/O"
561 "Major mode for gdb inferior-io."
562 :syntax-table nil :abbrev-table nil
563 ;; We want to use comint because it has various nifty and familiar
564 ;; features. We don't need a process, but comint wants one, so create
565 ;; a dummy one.
566 (make-comint-in-buffer
567 (substring (buffer-name) 1 (- (length (buffer-name)) 1))
568 (current-buffer) "hexl")
569 (setq comint-input-sender 'gdb-inferior-io-sender))
570
571 (defun gdb-inferior-io-sender (proc string)
572 ;; PROC is the pseudo-process created to satisfy comint.
573 (with-current-buffer (process-buffer proc)
574 (setq proc (get-buffer-process gud-comint-buffer))
575 (process-send-string proc string)
576 (process-send-string proc "\n")))
577
578 (defun gdb-inferior-io-interrupt ()
579 "Interrupt the program being debugged."
580 (interactive)
581 (interrupt-process
582 (get-buffer-process gud-comint-buffer) comint-ptyp))
583
584 (defun gdb-inferior-io-quit ()
585 "Send quit signal to the program being debugged."
586 (interactive)
587 (quit-process
588 (get-buffer-process gud-comint-buffer) comint-ptyp))
589
590 (defun gdb-inferior-io-stop ()
591 "Stop the program being debugged."
592 (interactive)
593 (stop-process
594 (get-buffer-process gud-comint-buffer) comint-ptyp))
595
596 (defun gdb-inferior-io-eof ()
597 "Send end-of-file to the program being debugged."
598 (interactive)
599 (process-send-eof
600 (get-buffer-process gud-comint-buffer)))
601 \f
602
603 ;;
604 ;; gdb communications
605 ;;
606
607 ;; INPUT: things sent to gdb
608 ;;
609 ;; The queues are lists. Each element is either a string (indicating user or
610 ;; user-like input) or a list of the form:
611 ;;
612 ;; (INPUT-STRING HANDLER-FN)
613 ;;
614 ;; The handler function will be called from the partial-output buffer when the
615 ;; command completes. This is the way to write commands which invoke gdb
616 ;; commands autonomously.
617 ;;
618 ;; These lists are consumed tail first.
619 ;;
620
621 (defun gdb-send (proc string)
622 "A comint send filter for gdb.
623 This filter may simply queue input for a later time."
624 (if gud-running
625 (process-send-string proc (concat string "\n"))
626 (gdb-enqueue-input (concat string "\n"))))
627
628 ;; Note: Stuff enqueued here will be sent to the next prompt, even if it
629 ;; is a query, or other non-top-level prompt.
630
631 (defun gdb-enqueue-input (item)
632 (if gdb-prompting
633 (progn
634 (gdb-send-item item)
635 (setq gdb-prompting nil))
636 (push item gdb-input-queue)))
637
638 (defun gdb-dequeue-input ()
639 (let ((queue gdb-input-queue))
640 (and queue
641 (let ((last (car (last queue))))
642 (unless (nbutlast queue) (setq gdb-input-queue '()))
643 last))))
644
645 (defun gdb-send-item (item)
646 (if gdb-enable-debug-log (push (cons 'send item) gdb-debug-log))
647 (setq gdb-current-item item)
648 (with-current-buffer gud-comint-buffer
649 (if (eq gud-minor-mode 'gdba)
650 (if (stringp item)
651 (progn
652 (setq gdb-output-sink 'user)
653 (process-send-string (get-buffer-process gud-comint-buffer) item))
654 (progn
655 (gdb-clear-partial-output)
656 (setq gdb-output-sink 'pre-emacs)
657 (process-send-string (get-buffer-process gud-comint-buffer)
658 (car item))))
659 ;; case: eq gud-minor-mode 'gdbmi
660 (gdb-clear-partial-output)
661 (setq gdb-output-sink 'emacs)
662 (process-send-string (get-buffer-process gud-comint-buffer)
663 (car item)))))
664 \f
665 ;;
666 ;; output -- things gdb prints to emacs
667 ;;
668 ;; GDB output is a stream interrupted by annotations.
669 ;; Annotations can be recognized by their beginning
670 ;; with \C-j\C-z\C-z<tag><opt>\C-j
671 ;;
672 ;; The tag is a string obeying symbol syntax.
673 ;;
674 ;; The optional part `<opt>' can be either the empty string
675 ;; or a space followed by more data relating to the annotation.
676 ;; For example, the SOURCE annotation is followed by a filename,
677 ;; line number and various useless goo. This data must not include
678 ;; any newlines.
679 ;;
680
681 (defcustom gud-gdba-command-name "gdb -annotate=3"
682 "Default command to execute an executable under the GDB-UI debugger."
683 :type 'string
684 :group 'gud
685 :version "21.4")
686
687 (defvar gdb-annotation-rules
688 '(("pre-prompt" gdb-pre-prompt)
689 ("prompt" gdb-prompt)
690 ("commands" gdb-subprompt)
691 ("overload-choice" gdb-subprompt)
692 ("query" gdb-subprompt)
693 ;; Need this prompt for GDB 6.1
694 ("nquery" gdb-subprompt)
695 ("prompt-for-continue" gdb-subprompt)
696 ("post-prompt" gdb-post-prompt)
697 ("source" gdb-source)
698 ("starting" gdb-starting)
699 ("exited" gdb-stopping)
700 ("signalled" gdb-stopping)
701 ("signal" gdb-stopping)
702 ("breakpoint" gdb-stopping)
703 ("watchpoint" gdb-stopping)
704 ("frame-begin" gdb-frame-begin)
705 ("stopped" gdb-stopped)
706 ) "An assoc mapping annotation tags to functions which process them.")
707
708 (defun gdb-resync()
709 (setq gud-running nil)
710 (setq gdb-output-sink 'user)
711 (setq gdb-input-queue nil)
712 (setq gdb-pending-triggers nil)
713 (setq gdb-prompting t))
714
715 (defconst gdb-source-spec-regexp
716 "\\(.*\\):\\([0-9]*\\):[0-9]*:[a-z]*:\\(0x[a-f0-9]*\\)")
717
718 ;; Do not use this except as an annotation handler.
719 (defun gdb-source (args)
720 (string-match gdb-source-spec-regexp args)
721 ;; Extract the frame position from the marker.
722 (setq gud-last-frame
723 (cons
724 (match-string 1 args)
725 (string-to-int (match-string 2 args))))
726 (setq gdb-current-address (match-string 3 args))
727 (setq gdb-view-source t)
728 ;; cover for auto-display output which comes *before*
729 ;; stopped annotation
730 (if (eq gdb-output-sink 'inferior) (setq gdb-output-sink 'user)))
731
732 (defun gdb-pre-prompt (ignored)
733 "An annotation handler for `pre-prompt'.
734 This terminates the collection of output from a previous command if that
735 happens to be in effect."
736 (let ((sink gdb-output-sink))
737 (cond
738 ((eq sink 'user) t)
739 ((eq sink 'emacs)
740 (setq gdb-output-sink 'post-emacs))
741 (t
742 (gdb-resync)
743 (error "Phase error in gdb-pre-prompt (got %s)" sink)))))
744
745 (defun gdb-prompt (ignored)
746 "An annotation handler for `prompt'.
747 This sends the next command (if any) to gdb."
748 (when gdb-first-prompt (gdb-ann3))
749 (let ((sink gdb-output-sink))
750 (cond
751 ((eq sink 'user) t)
752 ((eq sink 'post-emacs)
753 (setq gdb-output-sink 'user)
754 (let ((handler
755 (car (cdr gdb-current-item))))
756 (with-current-buffer (gdb-get-create-buffer 'gdb-partial-output-buffer)
757 (funcall handler))))
758 (t
759 (gdb-resync)
760 (error "Phase error in gdb-prompt (got %s)" sink))))
761 (let ((input (gdb-dequeue-input)))
762 (if input
763 (gdb-send-item input)
764 (progn
765 (setq gdb-prompting t)
766 (gud-display-frame)))))
767
768 (defun gdb-subprompt (ignored)
769 "An annotation handler for non-top-level prompts."
770 (setq gdb-prompting t))
771
772 (defun gdb-starting (ignored)
773 "An annotation handler for `starting'.
774 This says that I/O for the subprocess is now the program being debugged,
775 not GDB."
776 (let ((sink gdb-output-sink))
777 (cond
778 ((eq sink 'user)
779 (progn
780 (setq gud-running t)
781 (if gdb-use-inferior-io-buffer
782 (setq gdb-output-sink 'inferior))))
783 (t
784 (gdb-resync)
785 (error "Unexpected `starting' annotation")))))
786
787 (defun gdb-stopping (ignored)
788 "An annotation handler for `exited' and other annotations.
789 They say that I/O for the subprocess is now GDB, not the program
790 being debugged."
791 (if gdb-use-inferior-io-buffer
792 (let ((sink gdb-output-sink))
793 (cond
794 ((eq sink 'inferior)
795 (setq gdb-output-sink 'user))
796 (t
797 (gdb-resync)
798 (error "Unexpected stopping annotation"))))))
799
800 (defun gdb-frame-begin (ignored)
801 (let ((sink gdb-output-sink))
802 (cond
803 ((eq sink 'inferior)
804 (setq gdb-output-sink 'user))
805 ((eq sink 'user) t)
806 ((eq sink 'emacs) t)
807 (t
808 (gdb-resync)
809 (error "Unexpected frame-begin annotation (%S)" sink)))))
810
811 (defun gdb-stopped (ignored)
812 "An annotation handler for `stopped'.
813 It is just like `gdb-stopping', except that if we already set the output
814 sink to `user' in `gdb-stopping', that is fine."
815 (setq gud-running nil)
816 (let ((sink gdb-output-sink))
817 (cond
818 ((eq sink 'inferior)
819 (setq gdb-output-sink 'user))
820 ((eq sink 'user) t)
821 (t
822 (gdb-resync)
823 (error "Unexpected stopped annotation")))))
824
825 (defun gdb-post-prompt (ignored)
826 "An annotation handler for `post-prompt'.
827 This begins the collection of output from the current command if that
828 happens to be appropriate."
829 (if (not gdb-pending-triggers)
830 (progn
831 (gdb-get-current-frame)
832 (gdb-invalidate-frames)
833 (gdb-invalidate-breakpoints)
834 (gdb-invalidate-assembler)
835 (gdb-invalidate-registers)
836 (gdb-invalidate-locals)
837 (gdb-invalidate-threads)
838 (unless (eq system-type 'darwin) ;Breaks on Darwin's GDB-5.3.
839 ;; FIXME: with GDB-6 on Darwin, this might very well work.
840 (dolist (frame (frame-list))
841 (when (string-equal (frame-parameter frame 'name) "Speedbar")
842 (setq gdb-var-changed t) ; force update
843 (dolist (var gdb-var-list)
844 (setcar (nthcdr 5 var) nil))))
845 (gdb-var-update))))
846 (let ((sink gdb-output-sink))
847 (cond
848 ((eq sink 'user) t)
849 ((eq sink 'pre-emacs)
850 (setq gdb-output-sink 'emacs))
851 (t
852 (gdb-resync)
853 (error "Phase error in gdb-post-prompt (got %s)" sink)))))
854
855 (defun gud-gdba-marker-filter (string)
856 "A gud marker filter for gdb. Handle a burst of output from GDB."
857 (if gdb-enable-debug-log (push (cons 'recv string) gdb-debug-log))
858 ;; Recall the left over gud-marker-acc from last time
859 (setq gud-marker-acc (concat gud-marker-acc string))
860 ;; Start accumulating output for the GUD buffer
861 (let ((output ""))
862 ;;
863 ;; Process all the complete markers in this chunk.
864 (while (string-match "\n\032\032\\(.*\\)\n" gud-marker-acc)
865 (let ((annotation (match-string 1 gud-marker-acc)))
866 ;;
867 ;; Stuff prior to the match is just ordinary output.
868 ;; It is either concatenated to OUTPUT or directed
869 ;; elsewhere.
870 (setq output
871 (gdb-concat-output
872 output
873 (substring gud-marker-acc 0 (match-beginning 0))))
874 ;;
875 ;; Take that stuff off the gud-marker-acc.
876 (setq gud-marker-acc (substring gud-marker-acc (match-end 0)))
877 ;;
878 ;; Parse the tag from the annotation, and maybe its arguments.
879 (string-match "\\(\\S-*\\) ?\\(.*\\)" annotation)
880 (let* ((annotation-type (match-string 1 annotation))
881 (annotation-arguments (match-string 2 annotation))
882 (annotation-rule (assoc annotation-type
883 gdb-annotation-rules)))
884 ;; Call the handler for this annotation.
885 (if annotation-rule
886 (funcall (car (cdr annotation-rule))
887 annotation-arguments)
888 ;; Else the annotation is not recognized. Ignore it silently,
889 ;; so that GDB can add new annotations without causing
890 ;; us to blow up.
891 ))))
892 ;;
893 ;; Does the remaining text end in a partial line?
894 ;; If it does, then keep part of the gud-marker-acc until we get more.
895 (if (string-match "\n\\'\\|\n\032\\'\\|\n\032\032.*\\'"
896 gud-marker-acc)
897 (progn
898 ;; Everything before the potential marker start can be output.
899 (setq output
900 (gdb-concat-output output
901 (substring gud-marker-acc 0
902 (match-beginning 0))))
903 ;;
904 ;; Everything after, we save, to combine with later input.
905 (setq gud-marker-acc (substring gud-marker-acc (match-beginning 0))))
906 ;;
907 ;; In case we know the gud-marker-acc contains no partial annotations:
908 (progn
909 (setq output (gdb-concat-output output gud-marker-acc))
910 (setq gud-marker-acc "")))
911 output))
912
913 (defun gdb-concat-output (so-far new)
914 (let ((sink gdb-output-sink))
915 (cond
916 ((eq sink 'user) (concat so-far new))
917 ((or (eq sink 'pre-emacs) (eq sink 'post-emacs)) so-far)
918 ((eq sink 'emacs)
919 (gdb-append-to-partial-output new)
920 so-far)
921 ((eq sink 'inferior)
922 (gdb-append-to-inferior-io new)
923 so-far)
924 (t
925 (gdb-resync)
926 (error "Bogon output sink %S" sink)))))
927
928 (defun gdb-append-to-partial-output (string)
929 (with-current-buffer (gdb-get-create-buffer 'gdb-partial-output-buffer)
930 (goto-char (point-max))
931 (insert string)))
932
933 (defun gdb-clear-partial-output ()
934 (with-current-buffer (gdb-get-create-buffer 'gdb-partial-output-buffer)
935 (erase-buffer)))
936
937 (defun gdb-append-to-inferior-io (string)
938 (with-current-buffer (gdb-get-create-buffer 'gdb-inferior-io)
939 (goto-char (point-max))
940 (insert-before-markers string))
941 (if (not (string-equal string ""))
942 (gdb-display-buffer (gdb-get-create-buffer 'gdb-inferior-io))))
943
944 (defun gdb-clear-inferior-io ()
945 (with-current-buffer (gdb-get-create-buffer 'gdb-inferior-io)
946 (erase-buffer)))
947 \f
948
949 ;; One trick is to have a command who's output is always available in a buffer
950 ;; of it's own, and is always up to date. We build several buffers of this
951 ;; type.
952 ;;
953 ;; There are two aspects to this: gdb has to tell us when the output for that
954 ;; command might have changed, and we have to be able to run the command
955 ;; behind the user's back.
956 ;;
957 ;; The output phasing associated with the variable gdb-output-sink
958 ;; help us to run commands behind the user's back.
959 ;;
960 ;; Below is the code for specificly managing buffers of output from one
961 ;; command.
962 ;;
963
964 ;; The trigger function is suitable for use in the assoc GDB-ANNOTATION-RULES
965 ;; It adds an input for the command we are tracking. It should be the
966 ;; annotation rule binding of whatever gdb sends to tell us this command
967 ;; might have changed it's output.
968 ;;
969 ;; NAME is the function name. DEMAND-PREDICATE tests if output is really needed.
970 ;; GDB-COMMAND is a string of such. OUTPUT-HANDLER is the function bound to the
971 ;; input in the input queue (see comment about ``gdb communications'' above).
972
973 (defmacro def-gdb-auto-update-trigger (name demand-predicate gdb-command
974 output-handler)
975 `(defun ,name (&optional ignored)
976 (if (and (,demand-predicate)
977 (not (member ',name
978 gdb-pending-triggers)))
979 (progn
980 (gdb-enqueue-input
981 (list ,gdb-command ',output-handler))
982 (push ',name gdb-pending-triggers)))))
983
984 (defmacro def-gdb-auto-update-handler (name trigger buf-key custom-defun)
985 `(defun ,name ()
986 (setq gdb-pending-triggers
987 (delq ',trigger
988 gdb-pending-triggers))
989 (let ((buf (gdb-get-buffer ',buf-key)))
990 (and buf
991 (with-current-buffer buf
992 (let ((p (point))
993 (buffer-read-only nil))
994 (erase-buffer)
995 (insert-buffer-substring (gdb-get-create-buffer
996 'gdb-partial-output-buffer))
997 (goto-char p)))))
998 ;; put customisation here
999 (,custom-defun)))
1000
1001 (defmacro def-gdb-auto-updated-buffer (buffer-key trigger-name gdb-command
1002 output-handler-name custom-defun)
1003 `(progn
1004 (def-gdb-auto-update-trigger ,trigger-name
1005 ;; The demand predicate:
1006 (lambda () (gdb-get-buffer ',buffer-key))
1007 ,gdb-command
1008 ,output-handler-name)
1009 (def-gdb-auto-update-handler ,output-handler-name
1010 ,trigger-name ,buffer-key ,custom-defun)))
1011
1012 \f
1013 ;;
1014 ;; Breakpoint buffer : This displays the output of `info breakpoints'.
1015 ;;
1016 (gdb-set-buffer-rules 'gdb-breakpoints-buffer
1017 'gdb-breakpoints-buffer-name
1018 'gdb-breakpoints-mode)
1019
1020 (def-gdb-auto-updated-buffer gdb-breakpoints-buffer
1021 ;; This defines the auto update rule for buffers of type
1022 ;; `gdb-breakpoints-buffer'.
1023 ;;
1024 ;; It defines a function to serve as the annotation handler that
1025 ;; handles the `foo-invalidated' message. That function is called:
1026 gdb-invalidate-breakpoints
1027 ;;
1028 ;; To update the buffer, this command is sent to gdb.
1029 "server info breakpoints\n"
1030 ;;
1031 ;; This also defines a function to be the handler for the output
1032 ;; from the command above. That function will copy the output into
1033 ;; the appropriately typed buffer. That function will be called:
1034 gdb-info-breakpoints-handler
1035 ;; buffer specific functions
1036 gdb-info-breakpoints-custom)
1037
1038 (defvar gdb-cdir nil "Compilation directory.")
1039
1040 (defconst breakpoint-xpm-data "/* XPM */
1041 static char *magick[] = {
1042 /* columns rows colors chars-per-pixel */
1043 \"10 10 2 1\",
1044 \" c red\",
1045 \"+ c None\",
1046 /* pixels */
1047 \"+++ +++\",
1048 \"++ ++\",
1049 \"+ +\",
1050 \" \",
1051 \" \",
1052 \" \",
1053 \" \",
1054 \"+ +\",
1055 \"++ ++\",
1056 \"+++ +++\",
1057 };"
1058 "XPM data used for breakpoint icon.")
1059
1060 (defconst breakpoint-enabled-pbm-data
1061 "P1
1062 10 10\",
1063 0 0 0 0 1 1 1 1 0 0 0 0
1064 0 0 0 1 1 1 1 1 1 0 0 0
1065 0 0 1 1 1 1 1 1 1 1 0 0
1066 0 1 1 1 1 1 1 1 1 1 1 0
1067 0 1 1 1 1 1 1 1 1 1 1 0
1068 0 1 1 1 1 1 1 1 1 1 1 0
1069 0 1 1 1 1 1 1 1 1 1 1 0
1070 0 0 1 1 1 1 1 1 1 1 0 0
1071 0 0 0 1 1 1 1 1 1 0 0 0
1072 0 0 0 0 1 1 1 1 0 0 0 0"
1073 "PBM data used for enabled breakpoint icon.")
1074
1075 (defconst breakpoint-disabled-pbm-data
1076 "P1
1077 10 10\",
1078 0 0 1 0 1 0 1 0 0 0
1079 0 1 0 1 0 1 0 1 0 0
1080 1 0 1 0 1 0 1 0 1 0
1081 0 1 0 1 0 1 0 1 0 1
1082 1 0 1 0 1 0 1 0 1 0
1083 0 1 0 1 0 1 0 1 0 1
1084 1 0 1 0 1 0 1 0 1 0
1085 0 1 0 1 0 1 0 1 0 1
1086 0 0 1 0 1 0 1 0 1 0
1087 0 0 0 1 0 1 0 1 0 0"
1088 "PBM data used for disabled breakpoint icon.")
1089
1090 (defvar breakpoint-enabled-icon nil
1091 "Icon for enabled breakpoint in display margin.")
1092
1093 (defvar breakpoint-disabled-icon nil
1094 "Icon for disabled breakpoint in display margin.")
1095
1096 ;; Bitmap for breakpoint in fringe
1097 (and (display-images-p)
1098 (define-fringe-bitmap 'breakpoint
1099 "\x3c\x7e\xff\xff\xff\xff\x7e\x3c"))
1100
1101 (defface breakpoint-enabled-bitmap-face
1102 '((t
1103 :inherit fringe
1104 :foreground "red"))
1105 "Face for enabled breakpoint icon in fringe."
1106 :group 'gud)
1107
1108 (defface breakpoint-disabled-bitmap-face
1109 '((t
1110 :inherit fringe
1111 :foreground "grey60"))
1112 "Face for disabled breakpoint icon in fringe."
1113 :group 'gud)
1114
1115
1116 ;;-put breakpoint icons in relevant margins (even those set in the GUD buffer)
1117 (defun gdb-info-breakpoints-custom ()
1118 (let ((flag)(address))
1119 ;;
1120 ;; remove all breakpoint-icons in source buffers but not assembler buffer
1121 (dolist (buffer (buffer-list))
1122 (with-current-buffer buffer
1123 (if (and (eq gud-minor-mode 'gdba)
1124 (not (string-match "\\`\\*.+\\*\\'" (buffer-name))))
1125 (gdb-remove-breakpoint-icons (point-min) (point-max)))))
1126 (with-current-buffer (gdb-get-buffer 'gdb-breakpoints-buffer)
1127 (save-excursion
1128 (goto-char (point-min))
1129 (while (< (point) (- (point-max) 1))
1130 (forward-line 1)
1131 (if (looking-at "[^\t].*breakpoint")
1132 (progn
1133 (looking-at "[0-9]*\\s-*\\S-*\\s-*\\S-*\\s-*\\(.\\)")
1134 (setq flag (char-after (match-beginning 1)))
1135 (beginning-of-line)
1136 (if (re-search-forward "in\\s-+\\S-+\\s-+at\\s-+" nil t)
1137 (progn
1138 (looking-at "\\(\\S-*\\):\\([0-9]+\\)")
1139 (let ((line (match-string 2)) (buffer-read-only nil)
1140 (file (match-string 1)))
1141 (add-text-properties (point-at-bol) (point-at-eol)
1142 '(mouse-face highlight
1143 help-echo "mouse-2, RET: visit breakpoint"))
1144 (with-current-buffer
1145 (find-file-noselect
1146 (if (file-exists-p file) file
1147 (expand-file-name file gdb-cdir)))
1148 (save-current-buffer
1149 (set (make-local-variable 'gud-minor-mode) 'gdba)
1150 (set (make-local-variable 'tool-bar-map)
1151 gud-tool-bar-map))
1152 ;; only want one breakpoint icon at each location
1153 (save-excursion
1154 (goto-line (string-to-number line))
1155 (gdb-put-breakpoint-icon (eq flag ?y)))))))))
1156 (end-of-line)))))
1157 (if (gdb-get-buffer 'gdb-assembler-buffer) (gdb-assembler-custom)))
1158
1159 (defun gdb-mouse-toggle-breakpoint (event)
1160 "Toggle breakpoint in left fringe/margin with mouse click."
1161 (interactive "e")
1162 (mouse-minibuffer-check event)
1163 (let ((posn (event-end event)))
1164 (if (numberp (posn-point posn))
1165 (with-selected-window (posn-window posn)
1166 (save-excursion
1167 (goto-char (posn-point posn))
1168 (if (or (posn-object posn)
1169 (eq (car (fringe-bitmaps-at-pos (posn-point posn)))
1170 'breakpoint))
1171 (gud-remove nil)
1172 (gud-break nil)))))))
1173
1174 (defun gdb-breakpoints-buffer-name ()
1175 (with-current-buffer gud-comint-buffer
1176 (concat "*breakpoints of " (gdb-get-target-string) "*")))
1177
1178 (defun gdb-display-breakpoints-buffer ()
1179 "Display status of user-settable breakpoints."
1180 (interactive)
1181 (gdb-display-buffer
1182 (gdb-get-create-buffer 'gdb-breakpoints-buffer)))
1183
1184 (defconst gdb-frame-parameters
1185 '((height . 12) (width . 60)
1186 (unsplittable . t)
1187 (tool-bar-lines . nil)
1188 (menu-bar-lines . nil)
1189 (minibuffer . nil)))
1190
1191 (defun gdb-frame-breakpoints-buffer ()
1192 "Display status of user-settable breakpoints in a new frame."
1193 (interactive)
1194 (select-frame (make-frame gdb-frame-parameters))
1195 (switch-to-buffer (gdb-get-create-buffer 'gdb-breakpoints-buffer))
1196 (set-window-dedicated-p (selected-window) t))
1197
1198 (defvar gdb-breakpoints-mode-map
1199 (let ((map (make-sparse-keymap))
1200 (menu (make-sparse-keymap "Breakpoints")))
1201 (define-key menu [toggle] '("Toggle" . gdb-toggle-breakpoint))
1202 (define-key menu [delete] '("Delete" . gdb-delete-breakpoint))
1203 (define-key menu [goto] '("Goto" . gdb-goto-breakpoint))
1204
1205 (suppress-keymap map)
1206 (define-key map [menu-bar breakpoints] (cons "Breakpoints" menu))
1207 (define-key map " " 'gdb-toggle-breakpoint)
1208 (define-key map "d" 'gdb-delete-breakpoint)
1209 (define-key map "\r" 'gdb-goto-breakpoint)
1210 (define-key map [mouse-2] 'gdb-mouse-goto-breakpoint)
1211 map))
1212
1213 (defun gdb-breakpoints-mode ()
1214 "Major mode for gdb breakpoints.
1215
1216 \\{gdb-breakpoints-mode-map}"
1217 (kill-all-local-variables)
1218 (setq major-mode 'gdb-breakpoints-mode)
1219 (setq mode-name "Breakpoints")
1220 (use-local-map gdb-breakpoints-mode-map)
1221 (setq buffer-read-only t)
1222 (run-mode-hooks 'gdb-breakpoints-mode-hook)
1223 (if (with-current-buffer gud-comint-buffer (eq gud-minor-mode 'gdba))
1224 'gdb-invalidate-breakpoints
1225 'gdbmi-invalidate-breakpoints))
1226
1227 (defun gdb-toggle-breakpoint ()
1228 "Enable/disable the breakpoint at current line."
1229 (interactive)
1230 (save-excursion
1231 (beginning-of-line 1)
1232 (if (if (with-current-buffer gud-comint-buffer (eq gud-minor-mode 'gdba))
1233 (looking-at "\\([0-9]+\\).*point\\s-*\\S-*\\s-*\\(.\\)")
1234 (looking-at
1235 "\\([0-9]+\\)\\s-*\\S-*\\s-*\\S-*\\s-*\\(.\\)\\s-*\\S-*\\s-*\\S-*:[0-9]+"))
1236 (gdb-enqueue-input
1237 (list
1238 (concat gdb-server-prefix
1239 (if (eq ?y (char-after (match-beginning 2)))
1240 "disable "
1241 "enable ")
1242 (match-string 1) "\n") 'ignore))
1243 (error "Not recognized as break/watchpoint line"))))
1244
1245 (defun gdb-delete-breakpoint ()
1246 "Delete the breakpoint at current line."
1247 (interactive)
1248 (beginning-of-line 1)
1249 (if (if (with-current-buffer gud-comint-buffer (eq gud-minor-mode 'gdba))
1250 (looking-at "\\([0-9]+\\).*point\\s-*\\S-*\\s-*\\(.\\)")
1251 (looking-at
1252 "\\([0-9]+\\)\\s-*\\S-*\\s-*\\S-*\\s-*.\\s-*\\S-*\\s-*\\S-*:[0-9]+"))
1253 (gdb-enqueue-input
1254 (list
1255 (concat gdb-server-prefix "delete " (match-string 1) "\n") 'ignore))
1256 (error "Not recognized as break/watchpoint line")))
1257
1258 (defun gdb-goto-breakpoint ()
1259 "Display the breakpoint location specified at current line."
1260 (interactive)
1261 (save-excursion
1262 (beginning-of-line 1)
1263 (if (if (with-current-buffer gud-comint-buffer (eq gud-minor-mode 'gdba))
1264 (looking-at ".*in\\s-+\\S-+\\s-+at\\s-+\\(\\S-*\\):\\([0-9]+\\)")
1265 (looking-at
1266 "[0-9]+\\s-*\\S-*\\s-*\\S-*\\s-*.\\s-*\\S-*\\s-*\\(\\S-*\\):\\([0-9]+\\)"))
1267 (let ((line (match-string 2))
1268 (file (match-string 1)))
1269 (save-selected-window
1270 (let* ((buf (find-file-noselect (if (file-exists-p file)
1271 file
1272 (expand-file-name file gdb-cdir))))
1273 (window (gdb-display-buffer buf)))
1274 (with-current-buffer buf
1275 (goto-line (string-to-number line))
1276 (set-window-point window (point))))))
1277 (error "Not recognized as break/watchpoint line"))))
1278
1279 (defun gdb-mouse-goto-breakpoint (event)
1280 "Display the breakpoint location that you click on."
1281 (interactive "e")
1282 (mouse-set-point event)
1283 (gdb-goto-breakpoint))
1284 \f
1285 ;;
1286 ;; Frames buffer. This displays a perpetually correct bactracktrace
1287 ;; (from the command `where').
1288 ;;
1289 ;; Alas, if your stack is deep, it is costly.
1290 ;;
1291 (gdb-set-buffer-rules 'gdb-stack-buffer
1292 'gdb-stack-buffer-name
1293 'gdb-frames-mode)
1294
1295 (def-gdb-auto-updated-buffer gdb-stack-buffer
1296 gdb-invalidate-frames
1297 "server where\n"
1298 gdb-info-frames-handler
1299 gdb-info-frames-custom)
1300
1301 (defun gdb-info-frames-custom ()
1302 (with-current-buffer (gdb-get-buffer 'gdb-stack-buffer)
1303 (save-excursion
1304 (let ((buffer-read-only nil))
1305 (goto-char (point-min))
1306 (while (< (point) (point-max))
1307 (add-text-properties (point-at-bol) (point-at-eol)
1308 '(mouse-face highlight
1309 help-echo "mouse-2, RET: Select frame"))
1310 (beginning-of-line)
1311 (when (and (looking-at "^#\\([0-9]+\\)")
1312 (equal (match-string 1) gdb-current-stack-level))
1313 (put-text-property (point-at-bol) (point-at-eol)
1314 'face '(:inverse-video t)))
1315 (forward-line 1))))))
1316
1317 (defun gdb-stack-buffer-name ()
1318 (with-current-buffer gud-comint-buffer
1319 (concat "*stack frames of " (gdb-get-target-string) "*")))
1320
1321 (defun gdb-display-stack-buffer ()
1322 "Display backtrace of current stack."
1323 (interactive)
1324 (gdb-display-buffer
1325 (gdb-get-create-buffer 'gdb-stack-buffer)))
1326
1327 (defun gdb-frame-stack-buffer ()
1328 "Display backtrace of current stack in a new frame."
1329 (interactive)
1330 (select-frame (make-frame gdb-frame-parameters))
1331 (switch-to-buffer (gdb-get-create-buffer 'gdb-stack-buffer))
1332 (set-window-dedicated-p (selected-window) t))
1333
1334 (defvar gdb-frames-mode-map
1335 (let ((map (make-sparse-keymap)))
1336 (suppress-keymap map)
1337 (define-key map "\r" 'gdb-frames-select)
1338 (define-key map [mouse-2] 'gdb-frames-mouse-select)
1339 map))
1340
1341 (defun gdb-frames-mode ()
1342 "Major mode for gdb frames.
1343
1344 \\{gdb-frames-mode-map}"
1345 (kill-all-local-variables)
1346 (setq major-mode 'gdb-frames-mode)
1347 (setq mode-name "Frames")
1348 (setq buffer-read-only t)
1349 (use-local-map gdb-frames-mode-map)
1350 (font-lock-mode -1)
1351 (run-mode-hooks 'gdb-frames-mode-hook)
1352 (if (with-current-buffer gud-comint-buffer (eq gud-minor-mode 'gdba))
1353 'gdb-invalidate-frames
1354 'gdbmi-invalidate-frames))
1355
1356 (defun gdb-get-frame-number ()
1357 (save-excursion
1358 (let* ((pos (re-search-backward "^#*\\([0-9]*\\)" nil t))
1359 (n (or (and pos (match-string-no-properties 1)) "0")))
1360 n)))
1361
1362 (defun gdb-frames-select ()
1363 "Select the frame and display the relevant source."
1364 (interactive)
1365 (gdb-enqueue-input
1366 (list (concat gdb-server-prefix "frame " (gdb-get-frame-number) "\n") 'ignore))
1367 (gud-display-frame))
1368
1369 (defun gdb-frames-mouse-select (event)
1370 "Select the frame you click on and display the relevant source."
1371 (interactive "e")
1372 (mouse-set-point event)
1373 (gdb-frames-select))
1374 \f
1375 ;;
1376 ;; Threads buffer. This displays a selectable thread list.
1377 ;;
1378 (gdb-set-buffer-rules 'gdb-threads-buffer
1379 'gdb-threads-buffer-name
1380 'gdb-threads-mode)
1381
1382 (def-gdb-auto-updated-buffer gdb-threads-buffer
1383 gdb-invalidate-threads
1384 (concat gdb-server-prefix "info threads\n")
1385 gdb-info-threads-handler
1386 gdb-info-threads-custom)
1387
1388 (defun gdb-info-threads-custom ()
1389 (with-current-buffer (gdb-get-buffer 'gdb-threads-buffer)
1390 (let ((buffer-read-only nil))
1391 (goto-char (point-min))
1392 (while (< (point) (point-max))
1393 (add-text-properties (point-at-bol) (point-at-eol)
1394 '(mouse-face highlight
1395 help-echo "mouse-2, RET: select thread"))
1396 (forward-line 1)))))
1397
1398 (defun gdb-threads-buffer-name ()
1399 (with-current-buffer gud-comint-buffer
1400 (concat "*threads of " (gdb-get-target-string) "*")))
1401
1402 (defun gdb-display-threads-buffer ()
1403 "Display IDs of currently known threads."
1404 (interactive)
1405 (gdb-display-buffer
1406 (gdb-get-create-buffer 'gdb-threads-buffer)))
1407
1408 (defun gdb-frame-threads-buffer ()
1409 "Display IDs of currently known threads in a new frame."
1410 (interactive)
1411 (select-frame (make-frame gdb-frame-parameters))
1412 (switch-to-buffer (gdb-get-create-buffer 'gdb-threads-buffer))
1413 (set-window-dedicated-p (selected-window) t))
1414
1415 (defvar gdb-threads-mode-map
1416 (let ((map (make-sparse-keymap)))
1417 (suppress-keymap map)
1418 (define-key map "\r" 'gdb-threads-select)
1419 (define-key map [mouse-2] 'gdb-threads-mouse-select)
1420 map))
1421
1422 (defun gdb-threads-mode ()
1423 "Major mode for gdb frames.
1424
1425 \\{gdb-threads-mode-map}"
1426 (kill-all-local-variables)
1427 (setq major-mode 'gdb-threads-mode)
1428 (setq mode-name "Threads")
1429 (setq buffer-read-only t)
1430 (use-local-map gdb-threads-mode-map)
1431 (run-mode-hooks 'gdb-threads-mode-hook)
1432 'gdb-invalidate-threads)
1433
1434 (defun gdb-get-thread-number ()
1435 (save-excursion
1436 (re-search-backward "^\\s-*\\([0-9]*\\)" nil t)
1437 (match-string-no-properties 1)))
1438
1439 (defun gdb-threads-select ()
1440 "Select the thread and display the relevant source."
1441 (interactive)
1442 (gdb-enqueue-input
1443 (list (concat "thread " (gdb-get-thread-number) "\n") 'ignore))
1444 (gud-display-frame))
1445
1446 (defun gdb-threads-mouse-select (event)
1447 "Select the thread you click on and display the relevant source."
1448 (interactive "e")
1449 (mouse-set-point event)
1450 (gdb-threads-select))
1451 \f
1452 ;;
1453 ;; Registers buffer.
1454 ;;
1455 (gdb-set-buffer-rules 'gdb-registers-buffer
1456 'gdb-registers-buffer-name
1457 'gdb-registers-mode)
1458
1459 (def-gdb-auto-updated-buffer gdb-registers-buffer
1460 gdb-invalidate-registers
1461 (concat gdb-server-prefix "info registers\n")
1462 gdb-info-registers-handler
1463 gdb-info-registers-custom)
1464
1465 (defun gdb-info-registers-custom ())
1466
1467 (defvar gdb-registers-mode-map
1468 (let ((map (make-sparse-keymap)))
1469 (suppress-keymap map)
1470 map))
1471
1472 (defun gdb-registers-mode ()
1473 "Major mode for gdb registers.
1474
1475 \\{gdb-registers-mode-map}"
1476 (kill-all-local-variables)
1477 (setq major-mode 'gdb-registers-mode)
1478 (setq mode-name "Registers")
1479 (setq buffer-read-only t)
1480 (use-local-map gdb-registers-mode-map)
1481 (run-mode-hooks 'gdb-registers-mode-hook)
1482 'gdb-invalidate-registers)
1483
1484 (defun gdb-registers-buffer-name ()
1485 (with-current-buffer gud-comint-buffer
1486 (concat "*registers of " (gdb-get-target-string) "*")))
1487
1488 (defun gdb-display-registers-buffer ()
1489 "Display integer register contents."
1490 (interactive)
1491 (gdb-display-buffer
1492 (gdb-get-create-buffer 'gdb-registers-buffer)))
1493
1494 (defun gdb-frame-registers-buffer ()
1495 "Display integer register contents in a new frame."
1496 (interactive)
1497 (select-frame (make-frame gdb-frame-parameters))
1498 (switch-to-buffer (gdb-get-create-buffer 'gdb-registers-buffer))
1499 (set-window-dedicated-p (selected-window) t))
1500 \f
1501 ;;
1502 ;; Locals buffer.
1503 ;;
1504 (gdb-set-buffer-rules 'gdb-locals-buffer
1505 'gdb-locals-buffer-name
1506 'gdb-locals-mode)
1507
1508 (def-gdb-auto-updated-buffer gdb-locals-buffer
1509 gdb-invalidate-locals
1510 "server info locals\n"
1511 gdb-info-locals-handler
1512 gdb-info-locals-custom)
1513
1514 ;; Abbreviate for arrays and structures.
1515 ;; These can be expanded using gud-display.
1516 (defun gdb-info-locals-handler nil
1517 (setq gdb-pending-triggers (delq 'gdb-invalidate-locals
1518 gdb-pending-triggers))
1519 (let ((buf (gdb-get-buffer 'gdb-partial-output-buffer)))
1520 (with-current-buffer buf
1521 (goto-char (point-min))
1522 (while (re-search-forward "^ .*\n" nil t)
1523 (replace-match "" nil nil))
1524 (goto-char (point-min))
1525 (while (re-search-forward "{[-0-9, {}\]*\n" nil t)
1526 (replace-match "(array);\n" nil nil))
1527 (goto-char (point-min))
1528 (while (re-search-forward "{.*=.*\n" nil t)
1529 (replace-match "(structure);\n" nil nil))))
1530 (let ((buf (gdb-get-buffer 'gdb-locals-buffer)))
1531 (and buf (with-current-buffer buf
1532 (let ((p (point))
1533 (buffer-read-only nil))
1534 (delete-region (point-min) (point-max))
1535 (insert-buffer-substring (gdb-get-create-buffer
1536 'gdb-partial-output-buffer))
1537 (goto-char p)))))
1538 (run-hooks 'gdb-info-locals-hook))
1539
1540 (defun gdb-info-locals-custom ()
1541 nil)
1542
1543 (defvar gdb-locals-mode-map
1544 (let ((map (make-sparse-keymap)))
1545 (suppress-keymap map)
1546 map))
1547
1548 (defun gdb-locals-mode ()
1549 "Major mode for gdb locals.
1550
1551 \\{gdb-locals-mode-map}"
1552 (kill-all-local-variables)
1553 (setq major-mode 'gdb-locals-mode)
1554 (setq mode-name (concat "Locals:" gdb-current-frame))
1555 (setq buffer-read-only t)
1556 (use-local-map gdb-locals-mode-map)
1557 (run-mode-hooks 'gdb-locals-mode-hook)
1558 (if (with-current-buffer gud-comint-buffer (eq gud-minor-mode 'gdba))
1559 'gdb-invalidate-locals
1560 'gdbmi-invalidate-locals))
1561
1562 (defun gdb-locals-buffer-name ()
1563 (with-current-buffer gud-comint-buffer
1564 (concat "*locals of " (gdb-get-target-string) "*")))
1565
1566 (defun gdb-display-locals-buffer ()
1567 "Display local variables of current stack and their values."
1568 (interactive)
1569 (gdb-display-buffer
1570 (gdb-get-create-buffer 'gdb-locals-buffer)))
1571
1572 (defun gdb-frame-locals-buffer ()
1573 "Display local variables of current stack and their values in a new frame."
1574 (interactive)
1575 (select-frame (make-frame gdb-frame-parameters))
1576 (switch-to-buffer (gdb-get-create-buffer 'gdb-locals-buffer))
1577 (set-window-dedicated-p (selected-window) t))
1578 \f
1579
1580 ;;;; Window management
1581
1582 ;;; The way we abuse the dedicated-p flag is pretty gross, but seems
1583 ;;; to do the right thing. Seeing as there is no way for Lisp code to
1584 ;;; get at the use_time field of a window, I'm not sure there exists a
1585 ;;; more elegant solution without writing C code.
1586
1587 (defun gdb-display-buffer (buf &optional size)
1588 (let ((must-split nil)
1589 (answer nil))
1590 (unwind-protect
1591 (progn
1592 (walk-windows
1593 #'(lambda (win)
1594 (if (eq gud-comint-buffer (window-buffer win))
1595 (set-window-dedicated-p win t))))
1596 (setq answer (get-buffer-window buf 'visible))
1597 (if (not answer)
1598 (let ((window (get-lru-window 'visible)))
1599 (if window
1600 (progn
1601 (set-window-buffer window buf)
1602 (setq answer window))
1603 (setq must-split t)))))
1604 (walk-windows
1605 #'(lambda (win)
1606 (if (eq gud-comint-buffer (window-buffer win))
1607 (set-window-dedicated-p win nil)))))
1608 (if must-split
1609 (let* ((largest (get-largest-window 'visible))
1610 (cur-size (window-height largest))
1611 (new-size (and size (< size cur-size) (- cur-size size))))
1612 (setq answer (split-window largest new-size))
1613 (set-window-buffer answer buf)))
1614 answer))
1615
1616 (defun gdb-display-source-buffer (buffer)
1617 (if (eq gdb-selected-view 'source)
1618 (gdb-display-buffer buffer)
1619 (gdb-display-buffer (gdb-get-buffer 'gdb-assembler-buffer)))
1620 (get-buffer-window buffer 'visible))
1621
1622 \f
1623 ;;; Shared keymap initialization:
1624
1625 (let ((menu (make-sparse-keymap "GDB-Frames")))
1626 (define-key gud-menu-map [frames]
1627 `(menu-item "GDB-Frames" ,menu :visible (eq gud-minor-mode 'gdba)))
1628 (define-key menu [gdb] '("Gdb" . gdb-frame-gdb-buffer))
1629 (define-key menu [threads] '("Threads" . gdb-frame-threads-buffer))
1630 (define-key menu [assembler] '("Machine" . gdb-frame-assembler-buffer))
1631 (define-key menu [registers] '("Registers" . gdb-frame-registers-buffer))
1632 (define-key menu [locals] '("Locals" . gdb-frame-locals-buffer))
1633 (define-key menu [frames] '("Stack" . gdb-frame-stack-buffer))
1634 (define-key menu [breakpoints] '("Breakpoints" . gdb-frame-breakpoints-buffer)))
1635
1636 (let ((menu (make-sparse-keymap "GDB-Windows")))
1637 (define-key gud-menu-map [displays]
1638 `(menu-item "GDB-Windows" ,menu :visible (eq gud-minor-mode 'gdba)))
1639 (define-key menu [gdb] '("Gdb" . gdb-display-gdb-buffer))
1640 (define-key menu [assembler] '("Machine" . gdb-display-assembler-buffer))
1641 (define-key menu [threads] '("Threads" . gdb-display-threads-buffer))
1642 (define-key menu [registers] '("Registers" . gdb-display-registers-buffer))
1643 (define-key menu [locals] '("Locals" . gdb-display-locals-buffer))
1644 (define-key menu [frames] '("Stack" . gdb-display-stack-buffer))
1645 (define-key menu [breakpoints] '("Breakpoints" . gdb-display-breakpoints-buffer)))
1646
1647 (let ((menu (make-sparse-keymap "View")))
1648 (define-key gud-menu-map [view]
1649 `(menu-item "View" ,menu :visible (eq gud-minor-mode 'gdba)))
1650 ; (define-key menu [both] '(menu-item "Both" gdb-view-both
1651 ; :help "Display both source and assembler"
1652 ; :button (:radio . (eq gdb-selected-view 'both))))
1653 (define-key menu [assembler] '(menu-item "Machine" gdb-view-assembler
1654 :help "Display assembler only"
1655 :button (:radio . (eq gdb-selected-view 'assembler))))
1656 (define-key menu [source] '(menu-item "Source" gdb-view-source-function
1657 :help "Display source only"
1658 :button (:radio . (eq gdb-selected-view 'source)))))
1659
1660 (let ((menu (make-sparse-keymap "GDB-UI")))
1661 (define-key gud-menu-map [ui]
1662 `(menu-item "GDB-UI" ,menu :visible (eq gud-minor-mode 'gdba)))
1663 (define-key menu [gdb-restore-windows]
1664 '("Restore window layout" . gdb-restore-windows))
1665 (define-key menu [gdb-many-windows]
1666 (menu-bar-make-toggle gdb-many-windows gdb-many-windows
1667 "Display other windows" "Many Windows %s"
1668 "Display locals, stack and breakpoint information")))
1669
1670 (defun gdb-frame-gdb-buffer ()
1671 "Display GUD buffer in a new frame."
1672 (interactive)
1673 (select-frame (make-frame gdb-frame-parameters))
1674 (switch-to-buffer (gdb-get-create-buffer 'gdba))
1675 (set-window-dedicated-p (selected-window) t))
1676
1677 (defun gdb-display-gdb-buffer ()
1678 "Display GUD buffer."
1679 (interactive)
1680 (gdb-display-buffer
1681 (gdb-get-create-buffer 'gdba)))
1682
1683 (defvar gdb-main-file nil "Source file from which program execution begins.")
1684
1685 (defun gdb-view-source-function ()
1686 "Select source view."
1687 (interactive)
1688 (if gdb-view-source
1689 (gdb-display-buffer
1690 (if gud-last-last-frame
1691 (gud-find-file (car gud-last-last-frame))
1692 (gud-find-file gdb-main-file))))
1693 (setq gdb-selected-view 'source))
1694
1695 (defun gdb-view-assembler()
1696 "Select disassembly view."
1697 (interactive)
1698 (gdb-display-buffer (gdb-get-create-buffer 'gdb-assembler-buffer))
1699 (gdb-invalidate-assembler)
1700 (setq gdb-selected-view 'assembler))
1701
1702 ;(defun gdb-view-both()
1703 ;(interactive)
1704 ;(setq gdb-selected-view 'both))
1705
1706 (defcustom gdb-show-main nil
1707 "Nil means don't display source file containing the main routine."
1708 :type 'boolean
1709 :group 'gud
1710 :version "21.4")
1711
1712 (defun gdb-setup-windows ()
1713 "Layout the window pattern for gdb-many-windows."
1714 (gdb-display-locals-buffer)
1715 (gdb-display-stack-buffer)
1716 (delete-other-windows)
1717 (gdb-display-breakpoints-buffer)
1718 (delete-other-windows)
1719 (switch-to-buffer gud-comint-buffer)
1720 (split-window nil ( / ( * (window-height) 3) 4))
1721 (split-window nil ( / (window-height) 3))
1722 (split-window-horizontally)
1723 (other-window 1)
1724 (switch-to-buffer (gdb-locals-buffer-name))
1725 (other-window 1)
1726 (switch-to-buffer
1727 (if (and gdb-view-source
1728 (eq gdb-selected-view 'source))
1729 (if gud-last-last-frame
1730 (gud-find-file (car gud-last-last-frame))
1731 (gud-find-file gdb-main-file))
1732 (gdb-get-create-buffer 'gdb-assembler-buffer)))
1733 (when gdb-use-inferior-io-buffer
1734 (split-window-horizontally)
1735 (other-window 1)
1736 (switch-to-buffer (gdb-inferior-io-name)))
1737 (other-window 1)
1738 (switch-to-buffer (gdb-stack-buffer-name))
1739 (split-window-horizontally)
1740 (other-window 1)
1741 (switch-to-buffer (gdb-breakpoints-buffer-name))
1742 (other-window 1))
1743
1744 (defcustom gdb-many-windows nil
1745 "Nil means just pop up the GUD buffer unless `gdb-show-main' is t.
1746 In this case it starts with two windows: one displaying the GUD
1747 buffer and the other with the source file with the main routine
1748 of the inferior. Non-nil means display the layout shown for
1749 `gdba'."
1750 :type 'boolean
1751 :group 'gud
1752 :version "21.4")
1753
1754 (defun gdb-many-windows (arg)
1755 "Toggle the number of windows in the basic arrangement."
1756 (interactive "P")
1757 (setq gdb-many-windows
1758 (if (null arg)
1759 (not gdb-many-windows)
1760 (> (prefix-numeric-value arg) 0)))
1761 (condition-case nil
1762 (gdb-restore-windows)
1763 (error nil)))
1764
1765 (defun gdb-restore-windows ()
1766 "Restore the basic arrangement of windows used by gdba.
1767 This arrangement depends on the value of `gdb-many-windows'."
1768 (interactive)
1769 (if gdb-many-windows
1770 (progn
1771 (switch-to-buffer gud-comint-buffer)
1772 (delete-other-windows)
1773 (gdb-setup-windows))
1774 (switch-to-buffer gud-comint-buffer)
1775 (delete-other-windows)
1776 (split-window)
1777 (other-window 1)
1778 (switch-to-buffer
1779 (if (and gdb-view-source
1780 (eq gdb-selected-view 'source))
1781 (if gud-last-last-frame
1782 (gud-find-file (car gud-last-last-frame))
1783 (gud-find-file gdb-main-file))
1784 (gdb-get-create-buffer 'gdb-assembler-buffer)))
1785 (other-window 1)))
1786
1787 (defun gdb-reset ()
1788 "Exit a debugging session cleanly.
1789 Kills the gdb buffers and resets the source buffers."
1790 (dolist (buffer (buffer-list))
1791 (unless (eq buffer gud-comint-buffer)
1792 (with-current-buffer buffer
1793 (if (memq gud-minor-mode '(gdbmi gdba))
1794 (if (string-match "\\`\\*.+\\*\\'" (buffer-name))
1795 (kill-buffer nil)
1796 (gdb-remove-breakpoint-icons (point-min) (point-max) t)
1797 (setq gud-minor-mode nil)
1798 (kill-local-variable 'tool-bar-map)
1799 (setq gud-running nil))))))
1800 (when (markerp gdb-overlay-arrow-position)
1801 (move-marker gdb-overlay-arrow-position nil)
1802 (setq gdb-overlay-arrow-position nil))
1803 (setq overlay-arrow-variable-list
1804 (delq 'gdb-overlay-arrow-position overlay-arrow-variable-list)))
1805
1806 (defun gdb-source-info ()
1807 "Find the source file where the program starts and displays it with related
1808 buffers."
1809 (goto-char (point-min))
1810 (if (search-forward "directory is " nil t)
1811 (if (looking-at "\\S-*:\\(\\S-*\\)")
1812 (setq gdb-cdir (match-string 1))
1813 (looking-at "\\S-*")
1814 (setq gdb-cdir (match-string 0))))
1815 (if (search-forward "Located in " nil t)
1816 (if (looking-at "\\S-*")
1817 (setq gdb-main-file (match-string 0)))
1818 (setq gdb-view-source nil))
1819 (if gdb-many-windows
1820 (gdb-setup-windows)
1821 (gdb-get-create-buffer 'gdb-breakpoints-buffer)
1822 (when gdb-show-main
1823 (switch-to-buffer gud-comint-buffer)
1824 (delete-other-windows)
1825 (split-window)
1826 (other-window 1)
1827 (switch-to-buffer
1828 (if gdb-view-source
1829 (gud-find-file gdb-main-file)
1830 (gdb-get-create-buffer 'gdb-assembler-buffer)))
1831 (other-window 1))))
1832
1833 ;;from put-image
1834 (defun gdb-put-string (putstring pos &optional dprop)
1835 "Put string PUTSTRING in front of POS in the current buffer.
1836 PUTSTRING is displayed by putting an overlay into the current buffer with a
1837 `before-string' STRING that has a `display' property whose value is
1838 PUTSTRING."
1839 (let ((gdb-string "x")
1840 (buffer (current-buffer)))
1841 (let ((overlay (make-overlay pos pos buffer))
1842 (prop (or dprop
1843 (list (list 'margin 'left-margin) putstring))))
1844 (put-text-property 0 (length gdb-string) 'display prop gdb-string)
1845 (overlay-put overlay 'put-break t)
1846 (overlay-put overlay 'before-string gdb-string))))
1847
1848 ;;from remove-images
1849 (defun gdb-remove-strings (start end &optional buffer)
1850 "Remove strings between START and END in BUFFER.
1851 Remove only strings that were put in BUFFER with calls to `gdb-put-string'.
1852 BUFFER nil or omitted means use the current buffer."
1853 (unless buffer
1854 (setq buffer (current-buffer)))
1855 (let ((overlays (overlays-in start end)))
1856 (while overlays
1857 (let ((overlay (car overlays)))
1858 (when (overlay-get overlay 'put-break)
1859 (delete-overlay overlay)))
1860 (setq overlays (cdr overlays)))))
1861
1862 (defun gdb-put-breakpoint-icon (enabled)
1863 (let ((start (progn (beginning-of-line) (- (point) 1)))
1864 (end (progn (end-of-line) (+ (point) 1))))
1865 (gdb-remove-breakpoint-icons start end)
1866 (if (display-images-p)
1867 (if (>= (car (window-fringes)) 8)
1868 (gdb-put-string
1869 nil (1+ start)
1870 `(left-fringe breakpoint
1871 ,(if enabled
1872 'breakpoint-enabled-bitmap-face
1873 'breakpoint-disabled-bitmap-face)))
1874 (when (< left-margin-width 2)
1875 (save-current-buffer
1876 (setq left-margin-width 2)
1877 (if (get-buffer-window (current-buffer) 'visible)
1878 (set-window-margins
1879 (get-buffer-window (current-buffer) 'visible)
1880 left-margin-width right-margin-width))))
1881 (put-image
1882 (if enabled
1883 (or breakpoint-enabled-icon
1884 (setq breakpoint-enabled-icon
1885 (find-image `((:type xpm :data
1886 ,breakpoint-xpm-data
1887 :ascent 100 :pointer hand)
1888 (:type pbm :data
1889 ,breakpoint-enabled-pbm-data
1890 :ascent 100 :pointer hand)))))
1891 (or breakpoint-disabled-icon
1892 (setq breakpoint-disabled-icon
1893 (find-image `((:type xpm :data
1894 ,breakpoint-xpm-data
1895 :conversion disabled
1896 :ascent 100)
1897 (:type pbm :data
1898 ,breakpoint-disabled-pbm-data
1899 :ascent 100))))))
1900 (+ start 1) nil 'left-margin))
1901 (when (< left-margin-width 2)
1902 (save-current-buffer
1903 (setq left-margin-width 2)
1904 (if (get-buffer-window (current-buffer) 'visible)
1905 (set-window-margins
1906 (get-buffer-window (current-buffer) 'visible)
1907 left-margin-width right-margin-width))))
1908 (gdb-put-string (if enabled "B" "b") (1+ start)))))
1909
1910 (defun gdb-remove-breakpoint-icons (start end &optional remove-margin)
1911 (gdb-remove-strings start end)
1912 (if (display-images-p)
1913 (remove-images start end))
1914 (when remove-margin
1915 (setq left-margin-width 0)
1916 (if (get-buffer-window (current-buffer) 'visible)
1917 (set-window-margins
1918 (get-buffer-window (current-buffer) 'visible)
1919 left-margin-width right-margin-width))))
1920
1921 \f
1922 ;;
1923 ;; Assembler buffer.
1924 ;;
1925 (gdb-set-buffer-rules 'gdb-assembler-buffer
1926 'gdb-assembler-buffer-name
1927 'gdb-assembler-mode)
1928
1929 (def-gdb-auto-updated-buffer gdb-assembler-buffer
1930 gdb-invalidate-assembler
1931 (concat gdb-server-prefix "disassemble " gdb-current-address "\n")
1932 gdb-assembler-handler
1933 gdb-assembler-custom)
1934
1935 (defun gdb-assembler-custom ()
1936 (let ((buffer (gdb-get-buffer 'gdb-assembler-buffer))
1937 (pos 1) (address) (flag))
1938 (with-current-buffer buffer
1939 (if (not (equal gdb-current-address "main"))
1940 (progn
1941 (goto-char (point-min))
1942 (if (re-search-forward gdb-current-address nil t)
1943 (progn
1944 (setq pos (point))
1945 (beginning-of-line)
1946 (or gdb-overlay-arrow-position
1947 (setq gdb-overlay-arrow-position (make-marker)))
1948 (set-marker gdb-overlay-arrow-position
1949 (point) (current-buffer))))))
1950 ;; remove all breakpoint-icons in assembler buffer before updating.
1951 (gdb-remove-breakpoint-icons (point-min) (point-max)))
1952 (with-current-buffer (gdb-get-buffer 'gdb-breakpoints-buffer)
1953 (goto-char (point-min))
1954 (while (< (point) (- (point-max) 1))
1955 (forward-line 1)
1956 (if (looking-at "[^\t].*breakpoint")
1957 (progn
1958 (looking-at
1959 "[0-9]*\\s-*\\S-*\\s-*\\S-*\\s-*\\(.\\)\\s-*0x\\(\\S-*\\)")
1960 (setq flag (char-after (match-beginning 1)))
1961 (setq address (match-string 2))
1962 ;; remove leading 0s from output of info break.
1963 (if (string-match "^0+\\(.*\\)" address)
1964 (setq address (match-string 1 address)))
1965 (with-current-buffer buffer
1966 (goto-char (point-min))
1967 (if (re-search-forward address nil t)
1968 (gdb-put-breakpoint-icon (eq flag ?y))))))))
1969 (if (not (equal gdb-current-address "main"))
1970 (set-window-point (get-buffer-window buffer 'visible) pos))))
1971
1972 (defvar gdb-assembler-mode-map
1973 (let ((map (make-sparse-keymap)))
1974 (suppress-keymap map)
1975 map))
1976
1977 (defvar gdb-assembler-font-lock-keywords
1978 '(;; <__function.name+n>
1979 ("<\\(\\(\\sw\\|[_.]\\)+\\)\\(\\+[0-9]+\\)?>"
1980 (1 font-lock-function-name-face))
1981 ;; 0xNNNNNNNN <__function.name+n>: opcode
1982 ("^0x[0-9a-f]+ \\(<\\(\\(\\sw\\|[_.]\\)+\\)\\+[0-9]+>\\)?:[ \t]+\\(\\sw+\\)"
1983 (4 font-lock-keyword-face))
1984 ;; %register(at least i386)
1985 ("%\\sw+" . font-lock-variable-name-face)
1986 ("^\\(Dump of assembler code for function\\) \\(.+\\):"
1987 (1 font-lock-comment-face)
1988 (2 font-lock-function-name-face))
1989 ("^\\(End of assembler dump\\.\\)" . font-lock-comment-face))
1990 "Font lock keywords used in `gdb-assembler-mode'.")
1991
1992 (defun gdb-assembler-mode ()
1993 "Major mode for viewing code assembler.
1994
1995 \\{gdb-assembler-mode-map}"
1996 (kill-all-local-variables)
1997 (setq major-mode 'gdb-assembler-mode)
1998 (setq mode-name "Machine")
1999 (setq gdb-overlay-arrow-position nil)
2000 (add-to-list 'overlay-arrow-variable-list 'gdb-overlay-arrow-position)
2001 (put 'gdb-overlay-arrow-position 'overlay-arrow-string "=>")
2002 (setq fringes-outside-margins t)
2003 (setq buffer-read-only t)
2004 (use-local-map gdb-assembler-mode-map)
2005 (gdb-invalidate-assembler)
2006 (set (make-local-variable 'font-lock-defaults)
2007 '(gdb-assembler-font-lock-keywords))
2008 (run-mode-hooks 'gdb-assembler-mode-hook)
2009 'gdb-invalidate-assembler)
2010
2011 (defun gdb-assembler-buffer-name ()
2012 (with-current-buffer gud-comint-buffer
2013 (concat "*Machine Code " (gdb-get-target-string) "*")))
2014
2015 (defun gdb-display-assembler-buffer ()
2016 "Display disassembly view."
2017 (interactive)
2018 (gdb-display-buffer
2019 (gdb-get-create-buffer 'gdb-assembler-buffer)))
2020
2021 (defun gdb-frame-assembler-buffer ()
2022 "Display disassembly view in a new frame."
2023 (interactive)
2024 (select-frame (make-frame gdb-frame-parameters))
2025 (switch-to-buffer (gdb-get-create-buffer 'gdb-assembler-buffer))
2026 (set-window-dedicated-p (selected-window) t))
2027
2028 ;; modified because if gdb-current-address has changed value a new command
2029 ;; must be enqueued to update the buffer with the new output
2030 (defun gdb-invalidate-assembler (&optional ignored)
2031 (if (gdb-get-buffer 'gdb-assembler-buffer)
2032 (progn
2033 (unless (string-equal gdb-current-frame gdb-previous-frame)
2034 (if (or (not (member 'gdb-invalidate-assembler
2035 gdb-pending-triggers))
2036 (not (string-equal gdb-current-address
2037 gdb-previous-address)))
2038 (progn
2039 ;; take previous disassemble command off the queue
2040 (with-current-buffer gud-comint-buffer
2041 (let ((queue gdb-input-queue) (item))
2042 (dolist (item queue)
2043 (if (equal (cdr item) '(gdb-assembler-handler))
2044 (setq gdb-input-queue
2045 (delete item gdb-input-queue))))))
2046 (gdb-enqueue-input
2047 (list (concat gdb-server-prefix "disassemble " gdb-current-address "\n")
2048 'gdb-assembler-handler))
2049 (push 'gdb-invalidate-assembler gdb-pending-triggers)
2050 (setq gdb-previous-address gdb-current-address)
2051 (setq gdb-previous-frame gdb-current-frame)))))))
2052
2053 (defun gdb-get-current-frame ()
2054 (if (not (member 'gdb-get-current-frame gdb-pending-triggers))
2055 (progn
2056 (gdb-enqueue-input
2057 (list (concat gdb-server-prefix "info frame\n") 'gdb-frame-handler))
2058 (push 'gdb-get-current-frame
2059 gdb-pending-triggers))))
2060
2061 (defun gdb-frame-handler ()
2062 (setq gdb-pending-triggers
2063 (delq 'gdb-get-current-frame gdb-pending-triggers))
2064 (with-current-buffer (gdb-get-create-buffer 'gdb-partial-output-buffer)
2065 (goto-char (point-min))
2066 (if (looking-at "Stack level \\([0-9]+\\)")
2067 (setq gdb-current-stack-level (match-string 1)))
2068 (forward-line)
2069 (if (looking-at ".*=\\s-+0x\\(\\S-*\\)\\s-+in\\s-+\\(\\S-*?\\);? ")
2070 (progn
2071 (setq gdb-current-frame (match-string 2))
2072 (if (gdb-get-buffer 'gdb-locals-buffer)
2073 (with-current-buffer (gdb-get-buffer 'gdb-locals-buffer)
2074 (setq mode-name (concat "Locals:" gdb-current-frame))))
2075 (let ((address (match-string 1)))
2076 ;; remove leading 0s from output of info frame command.
2077 (if (string-match "^0+\\(.*\\)" address)
2078 (setq gdb-current-address
2079 (concat "0x" (match-string 1 address)))
2080 (setq gdb-current-address (concat "0x" address))))
2081 (if (or (if (not (re-search-forward "(\\S-*:[0-9]*);" nil t))
2082 (progn (setq gdb-view-source nil) t))
2083 (eq gdb-selected-view 'assembler))
2084 (progn
2085 (gdb-display-buffer
2086 (gdb-get-create-buffer 'gdb-assembler-buffer))
2087 ;;update with new frame for machine code if necessary
2088 (gdb-invalidate-assembler))))))
2089 (if (re-search-forward " source language \\(\\S-*\\)\." nil t)
2090 (setq gdb-current-language (match-string 1))))
2091
2092 (provide 'gdb-ui)
2093
2094 ;; arch-tag: e9fb00c5-74ef-469f-a088-37384caae352
2095 ;;; gdb-ui.el ends here