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