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