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