]> code.delx.au - gnu-emacs/blob - lisp/progmodes/gdb-ui.el
(gdb-reset): Update speedbar if necessary.
[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, 2006
8 ;; Free Software Foundation, Inc.
9
10 ;; This file is part of GNU Emacs.
11
12 ;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; any later version.
16
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 ;; Boston, MA 02110-1301, USA.
26
27 ;;; Commentary:
28
29 ;; This mode acts as a graphical user interface to GDB. You can interact with
30 ;; GDB through the GUD buffer in the usual way, but there are also further
31 ;; buffers which control the execution and describe the state of your program.
32 ;; It separates the input/output of your program from that of GDB, if
33 ;; required, and watches expressions in the speedbar. It also uses features of
34 ;; Emacs 21 such as the fringe/display margin for breakpoints, and the toolbar
35 ;; (see the GDB Graphical Interface section in the Emacs info manual).
36
37 ;; By default, M-x gdb will start the debugger. However, if you have customised
38 ;; gud-gdb-command-name, then start it with M-x gdba.
39
40 ;; This file has evolved from gdba.el that was included with GDB 5.0 and
41 ;; written by Tom Lord and Jim Kingdon. It uses GDB's annotation interface.
42 ;; You don't need to know about annotations to use this mode as a debugger,
43 ;; but if you are interested developing the mode itself, then see the
44 ;; Annotations section in the GDB info manual.
45
46 ;; GDB developers plan to make the annotation interface obsolete. A new
47 ;; interface called GDB/MI (machine interface) has been designed to replace
48 ;; it. Some GDB/MI commands are used in this file through the CLI command
49 ;; 'interpreter mi <mi-command>'. A file called gdb-mi.el is included with
50 ;; GDB (6.2 onwards) that uses GDB/MI as the primary interface to GDB. It is
51 ;; still under development and is part of a process to migrate Emacs from
52 ;; annotations to GDB/MI.
53
54 ;; This mode SHOULD WORK WITH GDB 5.0 onwards but you will NEED GDB 6.0
55 ;; onwards to use watch expressions. It works best with GDB 6.4 where
56 ;; watch expressions will update more quickly.
57
58 ;;; Windows Platforms:
59
60 ;; If you are using Emacs and GDB on Windows you will need to flush the buffer
61 ;; explicitly in your program if you want timely display of I/O in Emacs.
62 ;; Alternatively you can make the output stream unbuffered, for example, by
63 ;; using a macro:
64
65 ;; #ifdef UNBUFFERED
66 ;; setvbuf (stdout, (char *) NULL, _IONBF, 0);
67 ;; #endif
68
69 ;; and compiling with -DUNBUFFERED while debugging.
70
71 ;;; Known Bugs:
72
73 ;; 1) Strings that are watched don't update in the speedbar when their
74 ;; contents change unless the first character changes.
75 ;; 2) Cannot handle multiple debug sessions.
76 ;; 3) Initially, the assembler buffer does not display the cursor at the
77 ;; current line if the line is not visible in the window (but when testing
78 ;; gdb-assembler-custom with a lisp debugger it does!).
79
80 ;;; Problems with watch expressions, GDB/MI:
81 ;; 1) They go out of scope when the inferior is re-run.
82 ;; 2) -stack-list-locals has a type field but also prints type in values field.
83 ;; 3) VARNUM increments even when variable object is not created
84 ;; (maybe trivial).
85
86 ;; Known Bugs:
87 ;; 1) M-x gdb doesn't work with "run" command in .gdbinit, use M-x gdba instead.
88
89 ;;; TODO:
90 ;; 1) Use MI command -data-read-memory for memory window.
91 ;; 2) Use tree-widget.el instead of the speedbar for watch-expressions?
92 ;; 3) Mark breakpoint locations on scroll-bar of source buffer?
93 ;; 4) With gud-print and gud-pstar, print the variable name in the GUD
94 ;; buffer instead of the value's history number.
95
96 ;;; Code:
97
98 (require 'gud)
99
100 (defvar tool-bar-map)
101 (defvar speedbar-initial-expansion-list-name)
102
103 (defvar gdb-pc-address nil "Initialization for Assembler buffer.
104 Set to \"main\" at start if gdb-show-main is t.")
105 (defvar gdb-frame-address nil "Identity of frame for watch expression.")
106 (defvar gdb-previous-frame-address nil)
107 (defvar gdb-memory-address "main")
108 (defvar gdb-previous-frame nil)
109 (defvar gdb-selected-frame nil)
110 (defvar gdb-frame-number nil)
111 (defvar gdb-current-language nil)
112 (defvar gdb-var-list nil
113 "List of variables in watch window.
114 Each element has the form (VARNUM EXPRESSION NUMCHILD TYPE VALUE STATUS FP)
115 where STATUS is nil (unchanged), `changed' or `out-of-scope', FP the frame
116 address for root variables.")
117 (defvar gdb-main-file nil "Source file from which program execution begins.")
118 (defvar gdb-overlay-arrow-position nil)
119 (defvar gdb-server-prefix nil)
120 (defvar gdb-flush-pending-output nil)
121 (defvar gdb-location-alist nil
122 "Alist of breakpoint numbers and full filenames.")
123 (defvar gdb-active-process nil "GUD tooltips display variable values when t, \
124 and #define directives otherwise.")
125 (defvar gdb-error "Non-nil when GDB is reporting an error.")
126 (defvar gdb-macro-info nil
127 "Non-nil if GDB knows that the inferior includes preprocessor macro info.")
128 (defvar gdb-buffer-fringe-width nil)
129 (defvar gdb-signalled nil)
130 (defvar gdb-source-window nil)
131 (defvar gdb-inferior-status nil)
132 (defvar gdb-continuation nil)
133
134 (defvar gdb-buffer-type nil
135 "One of the symbols bound in `gdb-buffer-rules'.")
136 (make-variable-buffer-local 'gdb-buffer-type)
137
138 (defvar gdb-input-queue ()
139 "A list of gdb command objects.")
140
141 (defvar gdb-prompting nil
142 "True when gdb is idle with no pending input.")
143
144 (defvar gdb-output-sink 'user
145 "The disposition of the output of the current gdb command.
146 Possible values are these symbols:
147
148 `user' -- gdb output should be copied to the GUD buffer
149 for the user to see.
150
151 `inferior' -- gdb output should be copied to the inferior-io buffer.
152
153 `pre-emacs' -- output should be ignored util the post-prompt
154 annotation is received. Then the output-sink
155 becomes:...
156 `emacs' -- output should be collected in the partial-output-buffer
157 for subsequent processing by a command. This is the
158 disposition of output generated by commands that
159 gdb mode sends to gdb on its own behalf.
160 `post-emacs' -- ignore output until the prompt annotation is
161 received, then go to USER disposition.
162
163 gdba (gdb-ui.el) uses all five values, gdbmi (gdb-mi.el) only two
164 \(`user' and `emacs').")
165
166 (defvar gdb-current-item nil
167 "The most recent command item sent to gdb.")
168
169 (defvar gdb-pending-triggers '()
170 "A list of trigger functions that have run later than their output
171 handlers.")
172
173 (defvar gdb-first-post-prompt nil)
174 (defvar gdb-version nil)
175 (defvar gdb-locals-font-lock-keywords nil)
176 (defvar gdb-source-file-list nil
177 "List of source files for the current executable")
178 (defconst gdb-error-regexp "\\^error,msg=\"\\(.+\\)\"")
179
180 (defvar gdb-locals-font-lock-keywords-1
181 '(
182 ;; var = (struct struct_tag) value
183 ( "\\(^\\(\\sw\\|[_.]\\)+\\) += +(\\(struct\\) \\(\\(\\sw\\|[_.]\\)+\\)"
184 (1 font-lock-variable-name-face)
185 (3 font-lock-keyword-face)
186 (4 font-lock-type-face))
187 ;; var = (type) value
188 ( "\\(^\\(\\sw\\|[_.]\\)+\\) += +(\\(\\(\\sw\\|[_.]\\)+\\)"
189 (1 font-lock-variable-name-face)
190 (3 font-lock-type-face))
191 ;; var = val
192 ( "\\(^\\(\\sw\\|[_.]\\)+\\) += +[^(]"
193 (1 font-lock-variable-name-face))
194 )
195 "Font lock keywords used in `gdb-local-mode'.")
196
197 (defvar gdb-locals-font-lock-keywords-2
198 '(
199 ;; var = type value
200 ( "\\(^\\(\\sw\\|[_.]\\)+\\)\t+\\(\\(\\sw\\|[_.]\\)+\\)"
201 (1 font-lock-variable-name-face)
202 (3 font-lock-type-face))
203 )
204 "Font lock keywords used in `gdb-local-mode'.")
205
206 ;; Variables for GDB 6.4+
207 (defvar gdb-register-names nil "List of register names.")
208 (defvar gdb-changed-registers nil
209 "List of changed register numbers (strings).")
210
211 ;;;###autoload
212 (defun gdba (command-line)
213 "Run gdb on program FILE in buffer *gud-FILE*.
214 The directory containing FILE becomes the initial working directory
215 and source-file directory for your debugger.
216
217 If `gdb-many-windows' is nil (the default value) then gdb just
218 pops up the GUD buffer unless `gdb-show-main' is t. In this case
219 it starts with two windows: one displaying the GUD buffer and the
220 other with the source file with the main routine of the inferior.
221
222 If `gdb-many-windows' is t, regardless of the value of
223 `gdb-show-main', the layout below will appear unless
224 `gdb-use-separate-io-buffer' is nil when the source buffer
225 occupies the full width of the frame. Keybindings are shown in
226 some of the buffers.
227
228 Watch expressions appear in the speedbar/slowbar.
229
230 The following commands help control operation :
231
232 `gdb-many-windows' - Toggle the number of windows gdb uses.
233 `gdb-restore-windows' - To restore the window layout.
234
235 See Info node `(emacs)GDB Graphical Interface' for a more
236 detailed description of this mode.
237
238
239 +----------------------------------------------------------------------+
240 | GDB Toolbar |
241 +-----------------------------------+----------------------------------+
242 | GUD buffer (I/O of GDB) | Locals buffer |
243 | | |
244 | | |
245 | | |
246 +-----------------------------------+----------------------------------+
247 | Source buffer | I/O buffer (of debugged program) |
248 | | (comint-mode) |
249 | | |
250 | | |
251 | | |
252 | | |
253 | | |
254 | | |
255 +-----------------------------------+----------------------------------+
256 | Stack buffer | Breakpoints buffer |
257 | RET gdb-frames-select | SPC gdb-toggle-breakpoint |
258 | | RET gdb-goto-breakpoint |
259 | | D gdb-delete-breakpoint |
260 +-----------------------------------+----------------------------------+"
261 ;;
262 (interactive (list (gud-query-cmdline 'gdba)))
263 ;;
264 ;; Let's start with a basic gud-gdb buffer and then modify it a bit.
265 (gdb command-line)
266 (gdb-init-1))
267
268 (defcustom gdb-debug-ring-max 128
269 "Maximum size of `gdb-debug-ring'."
270 :group 'gud
271 :type 'integer
272 :version "22.1")
273
274 (defvar gdb-debug-ring nil
275 "List of commands, most recent first, sent to and replies received from GDB.
276 This variable is used to debug GDB-UI.")
277
278 ;;;###autoload
279 (defcustom gdb-enable-debug nil
280 "Non-nil means record the process input and output in `gdb-debug-ring'."
281 :type 'boolean
282 :group 'gud
283 :version "22.1")
284
285 (defcustom gdb-cpp-define-alist-program "gcc -E -dM -"
286 "Shell command for generating a list of defined macros in a source file.
287 This list is used to display the #define directive associated
288 with an identifier as a tooltip. It works in a debug session with
289 GDB, when gud-tooltip-mode is t.
290
291 Set `gdb-cpp-define-alist-flags' for any include paths or
292 predefined macros."
293 :type 'string
294 :group 'gud
295 :version "22.1")
296
297 (defcustom gdb-cpp-define-alist-flags ""
298 "Preprocessor flags for `gdb-cpp-define-alist-program'."
299 :type 'string
300 :group 'gud
301 :version "22.1")
302
303 (defcustom gdb-show-main nil
304 "Non-nil means display source file containing the main routine at startup.
305 Also display the main routine in the disassembly buffer if present."
306 :type 'boolean
307 :group 'gud
308 :version "22.1")
309
310 (defcustom gdb-many-windows nil
311 "Nil means just pop up the GUD buffer unless `gdb-show-main' is t.
312 In this case it starts with two windows: one displaying the GUD
313 buffer and the other with the source file with the main routine
314 of the inferior. Non-nil means display the layout shown for
315 `gdba'."
316 :type 'boolean
317 :group 'gud
318 :version "22.1")
319
320 (defcustom gdb-use-separate-io-buffer nil
321 "Non-nil means display output from the inferior in a separate buffer."
322 :type 'boolean
323 :group 'gud
324 :version "22.1")
325
326 (defun gdb-force-mode-line-update (status)
327 (let ((buffer gud-comint-buffer))
328 (if (and buffer (buffer-name buffer))
329 (with-current-buffer buffer
330 (setq mode-line-process
331 (format ":%s [%s]"
332 (process-status (get-buffer-process buffer)) status))
333 ;; Force mode line redisplay soon.
334 (force-mode-line-update)))))
335
336 (defun gdb-many-windows (arg)
337 "Toggle the number of windows in the basic arrangement.
338 With arg, display additional buffers iff arg is positive."
339 (interactive "P")
340 (setq gdb-many-windows
341 (if (null arg)
342 (not gdb-many-windows)
343 (> (prefix-numeric-value arg) 0)))
344 (message (format "Display of other windows %sabled"
345 (if gdb-many-windows "en" "dis")))
346 (if (and gud-comint-buffer
347 (buffer-name gud-comint-buffer))
348 (condition-case nil
349 (gdb-restore-windows)
350 (error nil))))
351
352 (defun gdb-use-separate-io-buffer (arg)
353 "Toggle separate IO for inferior.
354 With arg, use separate IO iff arg is positive."
355 (interactive "P")
356 (setq gdb-use-separate-io-buffer
357 (if (null arg)
358 (not gdb-use-separate-io-buffer)
359 (> (prefix-numeric-value arg) 0)))
360 (message (format "Separate inferior IO %sabled"
361 (if gdb-use-separate-io-buffer "en" "dis")))
362 (if (and gud-comint-buffer
363 (buffer-name gud-comint-buffer))
364 (condition-case nil
365 (if gdb-use-separate-io-buffer
366 (if gdb-many-windows (gdb-restore-windows))
367 (kill-buffer (gdb-inferior-io-name)))
368 (error nil))))
369
370 (defvar gdb-define-alist nil "Alist of #define directives for GUD tooltips.")
371
372 (defun gdb-create-define-alist ()
373 "Create an alist of #define directives for GUD tooltips."
374 (let* ((file (buffer-file-name))
375 (output
376 (with-output-to-string
377 (with-current-buffer standard-output
378 (call-process shell-file-name
379 (if (file-exists-p file) file nil)
380 (list t nil) nil "-c"
381 (concat gdb-cpp-define-alist-program " "
382 gdb-cpp-define-alist-flags)))))
383 (define-list (split-string output "\n" t))
384 (name))
385 (setq gdb-define-alist nil)
386 (dolist (define define-list)
387 (setq name (nth 1 (split-string define "[( ]")))
388 (push (cons name define) gdb-define-alist))))
389
390 (defun gdb-tooltip-print (expr)
391 (tooltip-show
392 (with-current-buffer (gdb-get-buffer 'gdb-partial-output-buffer)
393 (goto-char (point-min))
394 (let ((string
395 (if (search-forward "=" nil t)
396 (concat expr (buffer-substring (- (point) 2) (point-max)))
397 (buffer-string))))
398 ;; remove newline for gud-tooltip-echo-area
399 (substring string 0 (- (length string) 1))))
400 (or gud-tooltip-echo-area tooltip-use-echo-area)))
401
402 ;; If expr is a macro for a function don't print because of possible dangerous
403 ;; side-effects. Also printing a function within a tooltip generates an
404 ;; unexpected starting annotation (phase error).
405 (defun gdb-tooltip-print-1 (expr)
406 (with-current-buffer (gdb-get-buffer 'gdb-partial-output-buffer)
407 (goto-char (point-min))
408 (if (search-forward "expands to: " nil t)
409 (unless (looking-at "\\S-+.*(.*).*")
410 (gdb-enqueue-input
411 (list (concat gdb-server-prefix "print " expr "\n")
412 `(lambda () (gdb-tooltip-print ,expr))))))))
413
414 (defconst gdb-source-file-regexp "\\(.+?\\), \\|\\([^, \n].*$\\)")
415
416 (defun gdb-set-gud-minor-mode-existing-buffers ()
417 "Create list of source files for current GDB session."
418 (goto-char (point-min))
419 (when (search-forward "read in on demand:" nil t)
420 (while (re-search-forward gdb-source-file-regexp nil t)
421 (push (file-name-nondirectory (or (match-string 1) (match-string 2)))
422 gdb-source-file-list))
423 (dolist (buffer (buffer-list))
424 (with-current-buffer buffer
425 (when (and buffer-file-name
426 (member (file-name-nondirectory buffer-file-name)
427 gdb-source-file-list))
428 (set (make-local-variable 'gud-minor-mode) 'gdba)
429 (set (make-local-variable 'tool-bar-map) gud-tool-bar-map)
430 (when gud-tooltip-mode
431 (make-local-variable 'gdb-define-alist)
432 (gdb-create-define-alist)
433 (add-hook 'after-save-hook 'gdb-create-define-alist nil t)))))))
434
435 (defun gdb-find-watch-expression ()
436 (let* ((var (nth (- (line-number-at-pos (point)) 2) gdb-var-list))
437 (varnum (car var)) expr array)
438 (string-match "\\(var[0-9]+\\)\\.\\(.*\\)" varnum)
439 (let ((var1 (assoc (match-string 1 varnum) gdb-var-list)) var2 varnumlet
440 (component-list (split-string (match-string 2 varnum) "\\." t)))
441 (setq expr (nth 1 var1))
442 (setq varnumlet (car var1))
443 (dolist (component component-list)
444 (setq var2 (assoc varnumlet gdb-var-list))
445 (setq expr (concat expr
446 (if (string-match ".*\\[[0-9]+\\]$" (nth 3 var2))
447 (concat "[" component "]")
448 (concat "." component))))
449 (setq varnumlet (concat varnumlet "." component)))
450 expr)))
451
452 (defun gdb-init-1 ()
453 (set (make-local-variable 'gud-minor-mode) 'gdba)
454 (set (make-local-variable 'gud-marker-filter) 'gud-gdba-marker-filter)
455 ;;
456 (gud-def gud-break (if (not (string-match "Machine" mode-name))
457 (gud-call "break %f:%l" arg)
458 (save-excursion
459 (beginning-of-line)
460 (forward-char 2)
461 (gud-call "break *%a" arg)))
462 "\C-b" "Set breakpoint at current line or address.")
463 ;;
464 (gud-def gud-remove (if (not (string-match "Machine" mode-name))
465 (gud-call "clear %f:%l" arg)
466 (save-excursion
467 (beginning-of-line)
468 (forward-char 2)
469 (gud-call "clear *%a" arg)))
470 "\C-d" "Remove breakpoint at current line or address.")
471 ;;
472 (gud-def gud-until (if (not (string-match "Machine" mode-name))
473 (gud-call "until %f:%l" arg)
474 (save-excursion
475 (beginning-of-line)
476 (forward-char 2)
477 (gud-call "until *%a" arg)))
478 "\C-u" "Continue to current line or address.")
479 ;;
480 (gud-def gud-go (gud-call (if gdb-active-process "continue" "run") arg)
481 nil "Start or continue execution.")
482
483 ;; For debugging Emacs only.
484 (gud-def gud-pp
485 (gud-call
486 (concat
487 "pp1 " (if (eq (buffer-local-value
488 'major-mode (window-buffer)) 'speedbar-mode)
489 (gdb-find-watch-expression) "%e")) arg)
490 nil "Print the emacs s-expression.")
491
492 (define-key gud-minor-mode-map [left-margin mouse-1]
493 'gdb-mouse-set-clear-breakpoint)
494 (define-key gud-minor-mode-map [left-fringe mouse-1]
495 'gdb-mouse-set-clear-breakpoint)
496 (define-key gud-minor-mode-map [left-fringe mouse-2]
497 'gdb-mouse-until)
498 (define-key gud-minor-mode-map [left-margin drag-mouse-1]
499 'gdb-mouse-until)
500 (define-key gud-minor-mode-map [left-fringe drag-mouse-1]
501 'gdb-mouse-until)
502 (define-key gud-minor-mode-map [left-margin mouse-2]
503 'gdb-mouse-until)
504 (define-key gud-minor-mode-map [left-margin C-drag-mouse-1]
505 'gdb-mouse-jump)
506 (define-key gud-minor-mode-map [left-fringe C-drag-mouse-1]
507 'gdb-mouse-jump)
508 (define-key gud-minor-mode-map [left-fringe C-mouse-2]
509 'gdb-mouse-jump)
510 (define-key gud-minor-mode-map [left-margin C-mouse-2]
511 'gdb-mouse-jump)
512 (define-key gud-minor-mode-map [left-margin mouse-3]
513 'gdb-mouse-toggle-breakpoint-margin)
514 (define-key gud-minor-mode-map [left-fringe mouse-3]
515 'gdb-mouse-toggle-breakpoint-fringe)
516
517 (setq comint-input-sender 'gdb-send)
518
519 ;; (re-)initialize
520 (setq gdb-pc-address (if gdb-show-main "main" nil))
521 (setq gdb-previous-frame-address nil
522 gdb-memory-address "main"
523 gdb-previous-frame nil
524 gdb-selected-frame nil
525 gdb-current-language nil
526 gdb-frame-number nil
527 gdb-var-list nil
528 gdb-main-file nil
529 gdb-first-post-prompt t
530 gdb-prompting nil
531 gdb-input-queue nil
532 gdb-current-item nil
533 gdb-pending-triggers nil
534 gdb-output-sink 'user
535 gdb-server-prefix "server "
536 gdb-flush-pending-output nil
537 gdb-location-alist nil
538 gdb-source-file-list nil
539 gdb-error nil
540 gdb-macro-info nil
541 gdb-buffer-fringe-width (car (window-fringes))
542 gdb-debug-ring nil
543 gdb-signalled nil
544 gdb-source-window nil
545 gdb-inferior-status nil
546 gdb-continuation nil)
547
548 (setq gdb-buffer-type 'gdba)
549
550 (if gdb-use-separate-io-buffer (gdb-clear-inferior-io))
551
552 ;; Hack to see test for GDB 6.4+ (-stack-info-frame was implemented in 6.4)
553 (gdb-enqueue-input (list "server interpreter mi -stack-info-frame\n"
554 'gdb-get-version)))
555
556 (defun gdb-init-2 ()
557 (if (eq window-system 'w32)
558 (gdb-enqueue-input (list "set new-console off\n" 'ignore)))
559 (gdb-enqueue-input (list "set height 0\n" 'ignore))
560 (gdb-enqueue-input (list "set width 0\n" 'ignore))
561
562 (if (string-equal gdb-version "pre-6.4")
563 (progn
564 (gdb-enqueue-input (list (concat gdb-server-prefix "info sources\n")
565 'gdb-set-gud-minor-mode-existing-buffers))
566 (setq gdb-locals-font-lock-keywords gdb-locals-font-lock-keywords-1))
567 (gdb-enqueue-input
568 (list "server interpreter mi -data-list-register-names\n"
569 'gdb-get-register-names))
570 ; Needs GDB 6.2 onwards.
571 (gdb-enqueue-input
572 (list "server interpreter mi \"-file-list-exec-source-files\"\n"
573 'gdb-set-gud-minor-mode-existing-buffers-1))
574 (setq gdb-locals-font-lock-keywords gdb-locals-font-lock-keywords-2))
575
576 ;; Find source file and compilation directory here.
577 ;; Works for C, C++, Fortran and Ada but not Java (GDB 6.4)
578 (gdb-enqueue-input (list "server list\n" 'ignore))
579 (gdb-enqueue-input (list "server info source\n" 'gdb-source-info))
580
581 (run-hooks 'gdba-mode-hook))
582
583 (defun gdb-get-version ()
584 (goto-char (point-min))
585 (if (re-search-forward "Undefined\\( mi\\)* command:" nil t)
586 (setq gdb-version "pre-6.4")
587 (setq gdb-version "6.4+"))
588 (gdb-init-2))
589
590 (defun gdb-mouse-until (event)
591 "Continue running until a source line past the current line.
592 The destination source line can be selected either by clicking with mouse-2
593 on the fringe/margin or dragging the arrow with mouse-1 (default bindings)."
594 (interactive "e")
595 (if gud-overlay-arrow-position
596 (let ((start (event-start event))
597 (end (event-end event))
598 (buffer (marker-buffer gud-overlay-arrow-position)) (line))
599 (if (not (string-match "Machine" mode-name))
600 (if (equal buffer (window-buffer (posn-window end)))
601 (with-current-buffer buffer
602 (when (or (equal start end)
603 (equal (posn-point start)
604 (marker-position
605 gud-overlay-arrow-position)))
606 (setq line (line-number-at-pos (posn-point end)))
607 (gud-call (concat "until " (number-to-string line))))))
608 (if (equal (marker-buffer gdb-overlay-arrow-position)
609 (window-buffer (posn-window end)))
610 (when (or (equal start end)
611 (equal (posn-point start)
612 (marker-position
613 gdb-overlay-arrow-position)))
614 (save-excursion
615 (goto-line (line-number-at-pos (posn-point end)))
616 (forward-char 2)
617 (gud-call (concat "until *%a")))))))))
618
619 (defun gdb-mouse-jump (event)
620 "Set execution address/line.
621 The destination source line can be selected either by clicking with mouse-2
622 on the fringe/margin or dragging the arrow with mouse-1 (default bindings).
623 Unlike gdb-mouse-until the destination address can be before the current
624 line, and no execution takes place."
625 (interactive "e")
626 (if gud-overlay-arrow-position
627 (let ((start (event-start event))
628 (end (event-end event))
629 (buffer (marker-buffer gud-overlay-arrow-position)) (line))
630 (if (not (string-match "Machine" mode-name))
631 (if (equal buffer (window-buffer (posn-window end)))
632 (with-current-buffer buffer
633 (when (or (equal start end)
634 (equal (posn-point start)
635 (marker-position
636 gud-overlay-arrow-position)))
637 (setq line (line-number-at-pos (posn-point end)))
638 (progn (gud-call (concat "tbreak " (number-to-string line)))
639 (gud-call (concat "jump " (number-to-string line)))))))
640 (if (equal (marker-buffer gdb-overlay-arrow-position)
641 (window-buffer (posn-window end)))
642 (when (or (equal start end)
643 (equal (posn-point start)
644 (marker-position
645 gdb-overlay-arrow-position)))
646 (save-excursion
647 (goto-line (line-number-at-pos (posn-point end)))
648 (forward-char 2)
649 (progn
650 (gud-call (concat "tbreak *%a"))
651 (gud-call (concat "jump *%a"))))))))))
652
653 (defcustom gdb-speedbar-auto-raise nil
654 "If non-nil raise speedbar every time display of watch expressions is\
655 updated."
656 :type 'boolean
657 :group 'gud
658 :version "22.1")
659
660 (defun gdb-speedbar-auto-raise (arg)
661 "Toggle automatic raising of the speedbar for watch expressions.
662 With arg, automatically raise speedbar iff arg is positive."
663 (interactive "P")
664 (setq gdb-speedbar-auto-raise
665 (if (null arg)
666 (not gdb-speedbar-auto-raise)
667 (> (prefix-numeric-value arg) 0)))
668 (message (format "Auto raising %sabled"
669 (if gdb-speedbar-auto-raise "en" "dis"))))
670
671 (defcustom gdb-use-colon-colon-notation nil
672 "If non-nil use FUN::VAR format to display variables in the speedbar."
673 :type 'boolean
674 :group 'gud
675 :version "22.1")
676
677 (define-key gud-minor-mode-map "\C-c\C-w" 'gud-watch)
678 (define-key global-map (concat gud-key-prefix "\C-w") 'gud-watch)
679
680 (defun gud-watch (&optional arg event)
681 "Watch expression at point.
682 With arg, enter name of variable to be watched in the minibuffer."
683 (interactive (list current-prefix-arg last-input-event))
684 (let ((minor-mode (buffer-local-value 'gud-minor-mode gud-comint-buffer)))
685 (if (memq minor-mode '(gdbmi gdba))
686 (progn
687 (if event (posn-set-point (event-end event)))
688 (require 'tooltip)
689 (save-selected-window
690 (let ((expr
691 (if arg
692 (completing-read "Name of variable: "
693 'gud-gdb-complete-command)
694 (if (and transient-mark-mode mark-active)
695 (buffer-substring (region-beginning) (region-end))
696 (tooltip-identifier-from-point (point))))))
697 (speedbar 1)
698 (catch 'already-watched
699 (dolist (var gdb-var-list)
700 (unless (string-match "\\." (car var))
701 (if (string-equal expr (nth 1 var))
702 (throw 'already-watched nil))))
703 (set-text-properties 0 (length expr) nil expr)
704 (gdb-enqueue-input
705 (list
706 (if (eq minor-mode 'gdba)
707 (concat
708 "server interpreter mi \"-var-create - * " expr "\"\n")
709 (concat"-var-create - * " expr "\n"))
710 `(lambda () (gdb-var-create-handler ,expr))))))))
711 (message "gud-watch is a no-op in this mode."))))
712
713 (defconst gdb-var-create-regexp
714 "name=\"\\(.*?\\)\",.*numchild=\"\\(.*?\\)\",.*type=\"\\(.*?\\)\"")
715
716 (defun gdb-var-create-handler (expr)
717 (goto-char (point-min))
718 (if (re-search-forward gdb-var-create-regexp nil t)
719 (let ((var (list
720 (match-string 1)
721 (if (and (string-equal gdb-current-language "c")
722 gdb-use-colon-colon-notation gdb-selected-frame)
723 (setq expr (concat gdb-selected-frame "::" expr))
724 expr)
725 (match-string 2)
726 (match-string 3)
727 nil nil gdb-frame-address)))
728 (push var gdb-var-list)
729 (unless (string-equal
730 speedbar-initial-expansion-list-name "GUD")
731 (speedbar-change-initial-expansion-list "GUD"))
732 (gdb-enqueue-input
733 (list
734 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
735 (concat "server interpreter mi \"0-var-evaluate-expression "
736 (car var) "\"\n")
737 (concat "0-var-evaluate-expression " (car var) "\n"))
738 `(lambda () (gdb-var-evaluate-expression-handler
739 ,(car var) nil)))))
740 (if (search-forward "Undefined command" nil t)
741 (message-box "Watching expressions requires gdb 6.0 onwards")
742 (message-box "No symbol \"%s\" in current context." expr))))
743
744 (defun gdb-speedbar-update ()
745 (when (and (boundp 'speedbar-frame) (frame-live-p speedbar-frame))
746 ;; Dummy command to update speedbar even when idle.
747 (gdb-enqueue-input (list "server pwd\n" 'gdb-speedbar-timer-fn))
748 ;; Keep gdb-pending-triggers non-nil till end.
749 (push 'gdb-speedbar-timer gdb-pending-triggers)))
750
751 (defun gdb-speedbar-timer-fn ()
752 (setq gdb-pending-triggers
753 (delq 'gdb-speedbar-timer gdb-pending-triggers))
754 (speedbar-timer-fn))
755
756 (defun gdb-var-evaluate-expression-handler (varnum changed)
757 (goto-char (point-min))
758 (re-search-forward "\\(.+\\)\\^done,value=\\(\".*\"\\)" nil t)
759 (setq gdb-pending-triggers
760 (delq (string-to-number (match-string 1)) gdb-pending-triggers))
761 (let ((var (assoc varnum gdb-var-list)))
762 (when var
763 (if changed (setcar (nthcdr 5 var) 'changed))
764 (setcar (nthcdr 4 var) (read (match-string 2)))))
765 (gdb-speedbar-update))
766
767 (defun gdb-var-list-children (varnum)
768 (gdb-enqueue-input
769 (list (concat "server interpreter mi \"-var-list-children " varnum "\"\n")
770 `(lambda () (gdb-var-list-children-handler ,varnum)))))
771
772 (defconst gdb-var-list-children-regexp
773 "child={.*?name=\"\\(.*?\\)\",.*?exp=\"\\(.*?\\)\",.*?\
774 numchild=\"\\(.*?\\)\",.*?type=\"\\(.*?\\)\".*?}")
775
776 (defun gdb-var-list-children-handler (varnum)
777 (goto-char (point-min))
778 (let ((var-list nil))
779 (catch 'child-already-watched
780 (dolist (var gdb-var-list)
781 (if (string-equal varnum (car var))
782 (progn
783 (push var var-list)
784 (while (re-search-forward gdb-var-list-children-regexp nil t)
785 (let ((varchild (list (match-string 1)
786 (match-string 2)
787 (match-string 3)
788 (match-string 4)
789 nil nil)))
790 (if (assoc (car varchild) gdb-var-list)
791 (throw 'child-already-watched nil))
792 (push varchild var-list)
793 (gdb-enqueue-input
794 (list
795 (concat
796 "server interpreter mi \"0-var-evaluate-expression "
797 (car varchild) "\"\n")
798 `(lambda () (gdb-var-evaluate-expression-handler
799 ,(car varchild) nil)))))))
800 (push var var-list)))
801 (setq gdb-var-list (nreverse var-list)))))
802
803 (defun gdb-var-update ()
804 (when (not (member 'gdb-var-update gdb-pending-triggers))
805 (gdb-enqueue-input
806 (list "server interpreter mi \"-var-update *\"\n"
807 'gdb-var-update-handler))
808 (push 'gdb-var-update gdb-pending-triggers)))
809
810 (defconst gdb-var-update-regexp
811 "{.*?name=\"\\(.*?\\)\",.*?in_scope=\"\\(.*?\\)\",.*?\
812 type_changed=\".*?\".*?}")
813
814 (defun gdb-var-update-handler ()
815 (dolist (var gdb-var-list)
816 (setcar (nthcdr 5 var) nil))
817 (goto-char (point-min))
818 (let ((n 0))
819 (while (re-search-forward gdb-var-update-regexp nil t)
820 (let ((varnum (match-string 1)))
821 (if (string-equal (match-string 2) "false")
822 (let ((var (assoc varnum gdb-var-list)))
823 (if var (setcar (nthcdr 5 var) 'out-of-scope)))
824 (setq n (1+ n))
825 (push n gdb-pending-triggers)
826 (gdb-enqueue-input
827 (list
828 (concat "server interpreter mi \"" (number-to-string n)
829 "-var-evaluate-expression " varnum "\"\n")
830 `(lambda () (gdb-var-evaluate-expression-handler ,varnum t))))))))
831 (setq gdb-pending-triggers
832 (delq 'gdb-var-update gdb-pending-triggers)))
833
834 (defun gdb-var-delete ()
835 "Delete watch expression at point from the speedbar."
836 (interactive)
837 (if (memq (buffer-local-value 'gud-minor-mode gud-comint-buffer)
838 '(gdbmi gdba))
839 (let ((text (speedbar-line-text)))
840 ;; Can't use \\S-+ for whitespace because
841 ;; speedbar has a whacky syntax table.
842 (string-match "\\([^ \t]+\\)" text)
843 (let ((expr (match-string 1 text)) var varnum)
844 (catch 'expr-found
845 (dolist (var1 gdb-var-list)
846 (when (string-equal expr (nth 1 var1))
847 (setq var var1)
848 (setq varnum (car var1))
849 (throw 'expr-found nil))))
850 (unless (string-match "\\." (car var))
851 (gdb-enqueue-input
852 (list
853 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer)
854 'gdba)
855 (concat "server interpreter mi \"-var-delete " varnum "\"\n")
856 (concat "-var-delete " varnum "\n"))
857 'ignore))
858 (setq gdb-var-list (delq var gdb-var-list))
859 (dolist (varchild gdb-var-list)
860 (if (string-match (concat (car var) "\\.") (car varchild))
861 (setq gdb-var-list (delq varchild gdb-var-list)))))))))
862
863 (defun gdb-edit-value (text token indent)
864 "Assign a value to a variable displayed in the speedbar."
865 (let* ((var (nth (- (count-lines (point-min) (point)) 2) gdb-var-list))
866 (varnum (car var)) (value))
867 (setq value (read-string "New value: "))
868 (gdb-enqueue-input
869 (list
870 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
871 (concat "server interpreter mi \"-var-assign "
872 varnum " " value "\"\n")
873 (concat "-var-assign " varnum " " value "\n"))
874 `(lambda () (gdb-edit-value-handler ,value))))))
875
876 (defun gdb-edit-value-handler (value)
877 (goto-char (point-min))
878 (if (re-search-forward gdb-error-regexp nil t)
879 (message-box "Invalid number or expression (%s)" value)))
880
881 (defcustom gdb-show-changed-values t
882 "If non-nil change the face of out of scope variables and changed values.
883 Out of scope variables are suppressed with `shadow' face.
884 Changed values are highlighted with the face `font-lock-warning-face'."
885 :type 'boolean
886 :group 'gud
887 :version "22.1")
888
889 (defun gdb-speedbar-expand-node (text token indent)
890 "Expand the node the user clicked on.
891 TEXT is the text of the button we clicked on, a + or - item.
892 TOKEN is data related to this node.
893 INDENT is the current indentation depth."
894 (cond ((string-match "+" text) ;expand this node
895 (if (and
896 (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
897 (string-equal gdb-version "pre-6.4"))
898 (gdb-var-list-children token)
899 (gdb-var-list-children-1 token)))
900 ((string-match "-" text) ;contract this node
901 (dolist (var gdb-var-list)
902 (if (string-match (concat token "\\.") (car var))
903 (setq gdb-var-list (delq var gdb-var-list))))
904 (speedbar-change-expand-button-char ?+)
905 (speedbar-delete-subblock indent))
906 (t (error "Ooops... not sure what to do")))
907 (speedbar-center-buffer-smartly))
908
909 (defun gdb-get-target-string ()
910 (with-current-buffer gud-comint-buffer
911 gud-target-name))
912 \f
913
914 ;;
915 ;; gdb buffers.
916 ;;
917 ;; Each buffer has a TYPE -- a symbol that identifies the function
918 ;; of that particular buffer.
919 ;;
920 ;; The usual gdb interaction buffer is given the type `gdba' and
921 ;; is constructed specially.
922 ;;
923 ;; Others are constructed by gdb-get-buffer-create and
924 ;; named according to the rules set forth in the gdb-buffer-rules-assoc
925
926 (defvar gdb-buffer-rules-assoc '())
927
928 (defun gdb-get-buffer (key)
929 "Return the gdb buffer tagged with type KEY.
930 The key should be one of the cars in `gdb-buffer-rules-assoc'."
931 (save-excursion
932 (gdb-look-for-tagged-buffer key (buffer-list))))
933
934 (defun gdb-get-buffer-create (key)
935 "Create a new gdb buffer of the type specified by KEY.
936 The key should be one of the cars in `gdb-buffer-rules-assoc'."
937 (or (gdb-get-buffer key)
938 (let* ((rules (assoc key gdb-buffer-rules-assoc))
939 (name (funcall (gdb-rules-name-maker rules)))
940 (new (get-buffer-create name)))
941 (with-current-buffer new
942 (let ((trigger))
943 (if (cdr (cdr rules))
944 (setq trigger (funcall (car (cdr (cdr rules))))))
945 (setq gdb-buffer-type key)
946 (set (make-local-variable 'gud-minor-mode)
947 (buffer-local-value 'gud-minor-mode gud-comint-buffer))
948 (set (make-local-variable 'tool-bar-map) gud-tool-bar-map)
949 (if trigger (funcall trigger)))
950 new))))
951
952 (defun gdb-rules-name-maker (rules) (car (cdr rules)))
953
954 (defun gdb-look-for-tagged-buffer (key bufs)
955 (let ((retval nil))
956 (while (and (not retval) bufs)
957 (set-buffer (car bufs))
958 (if (eq gdb-buffer-type key)
959 (setq retval (car bufs)))
960 (setq bufs (cdr bufs)))
961 retval))
962
963 ;;
964 ;; This assoc maps buffer type symbols to rules. Each rule is a list of
965 ;; at least one and possible more functions. The functions have these
966 ;; roles in defining a buffer type:
967 ;;
968 ;; NAME - Return a name for this buffer type.
969 ;;
970 ;; The remaining function(s) are optional:
971 ;;
972 ;; MODE - called in a new buffer with no arguments, should establish
973 ;; the proper mode for the buffer.
974 ;;
975
976 (defun gdb-set-buffer-rules (buffer-type &rest rules)
977 (let ((binding (assoc buffer-type gdb-buffer-rules-assoc)))
978 (if binding
979 (setcdr binding rules)
980 (push (cons buffer-type rules)
981 gdb-buffer-rules-assoc))))
982
983 ;; GUD buffers are an exception to the rules
984 (gdb-set-buffer-rules 'gdba 'error)
985
986 ;; Partial-output buffer : This accumulates output from a command executed on
987 ;; behalf of emacs (rather than the user).
988 ;;
989 (gdb-set-buffer-rules 'gdb-partial-output-buffer
990 'gdb-partial-output-name)
991
992 (defun gdb-partial-output-name ()
993 (concat "*partial-output-"
994 (gdb-get-target-string)
995 "*"))
996
997 \f
998 (gdb-set-buffer-rules 'gdb-inferior-io
999 'gdb-inferior-io-name
1000 'gdb-inferior-io-mode)
1001
1002 (defun gdb-inferior-io-name ()
1003 (concat "*input/output of "
1004 (gdb-get-target-string)
1005 "*"))
1006
1007 (defun gdb-display-separate-io-buffer ()
1008 "Display IO of debugged program in a separate window."
1009 (interactive)
1010 (if gdb-use-separate-io-buffer
1011 (gdb-display-buffer
1012 (gdb-get-buffer-create 'gdb-inferior-io))))
1013
1014 (defconst gdb-frame-parameters
1015 '((height . 14) (width . 80)
1016 (unsplittable . t)
1017 (tool-bar-lines . nil)
1018 (menu-bar-lines . nil)
1019 (minibuffer . nil)))
1020
1021 (defun gdb-frame-separate-io-buffer ()
1022 "Display IO of inferior in a new frame."
1023 (interactive)
1024 (if gdb-use-separate-io-buffer
1025 (let ((special-display-regexps (append special-display-regexps '(".*")))
1026 (special-display-frame-alist gdb-frame-parameters))
1027 (display-buffer (gdb-get-buffer-create 'gdb-inferior-io)))))
1028
1029 (defvar gdb-inferior-io-mode-map
1030 (let ((map (make-sparse-keymap)))
1031 (define-key map "\C-c\C-c" 'gdb-separate-io-interrupt)
1032 (define-key map "\C-c\C-z" 'gdb-separate-io-stop)
1033 (define-key map "\C-c\C-\\" 'gdb-separate-io-quit)
1034 (define-key map "\C-c\C-d" 'gdb-separate-io-eof)
1035 (define-key map "\C-d" 'gdb-separate-io-eof)
1036 map))
1037
1038 (define-derived-mode gdb-inferior-io-mode comint-mode "Inferior I/O"
1039 "Major mode for gdb inferior-io."
1040 :syntax-table nil :abbrev-table nil
1041 ;; We want to use comint because it has various nifty and familiar
1042 ;; features. We don't need a process, but comint wants one, so create
1043 ;; a dummy one.
1044 (make-comint-in-buffer
1045 (substring (buffer-name) 1 (- (length (buffer-name)) 1))
1046 (current-buffer) "hexl")
1047 (setq comint-input-sender 'gdb-inferior-io-sender))
1048
1049 (defun gdb-inferior-io-sender (proc string)
1050 ;; PROC is the pseudo-process created to satisfy comint.
1051 (with-current-buffer (process-buffer proc)
1052 (setq proc (get-buffer-process gud-comint-buffer))
1053 (process-send-string proc string)
1054 (process-send-string proc "\n")))
1055
1056 (defun gdb-separate-io-interrupt ()
1057 "Interrupt the program being debugged."
1058 (interactive)
1059 (interrupt-process
1060 (get-buffer-process gud-comint-buffer) comint-ptyp))
1061
1062 (defun gdb-separate-io-quit ()
1063 "Send quit signal to the program being debugged."
1064 (interactive)
1065 (quit-process
1066 (get-buffer-process gud-comint-buffer) comint-ptyp))
1067
1068 (defun gdb-separate-io-stop ()
1069 "Stop the program being debugged."
1070 (interactive)
1071 (stop-process
1072 (get-buffer-process gud-comint-buffer) comint-ptyp))
1073
1074 (defun gdb-separate-io-eof ()
1075 "Send end-of-file to the program being debugged."
1076 (interactive)
1077 (process-send-eof
1078 (get-buffer-process gud-comint-buffer)))
1079 \f
1080
1081 ;; gdb communications
1082 ;;
1083
1084 ;; INPUT: things sent to gdb
1085 ;;
1086 ;; The queues are lists. Each element is either a string (indicating user or
1087 ;; user-like input) or a list of the form:
1088 ;;
1089 ;; (INPUT-STRING HANDLER-FN)
1090 ;;
1091 ;; The handler function will be called from the partial-output buffer when the
1092 ;; command completes. This is the way to write commands which invoke gdb
1093 ;; commands autonomously.
1094 ;;
1095 ;; These lists are consumed tail first.
1096 ;;
1097
1098 (defun gdb-send (proc string)
1099 "A comint send filter for gdb.
1100 This filter may simply queue input for a later time."
1101 (with-current-buffer gud-comint-buffer
1102 (let ((inhibit-read-only t))
1103 (remove-text-properties (point-min) (point-max) '(face))))
1104 (if gud-running
1105 (progn
1106 (let ((item (concat string "\n")))
1107 (if gdb-enable-debug (push (cons 'send item) gdb-debug-ring))
1108 (process-send-string proc item)))
1109 (if (string-match "\\\\$" string)
1110 (setq gdb-continuation (concat gdb-continuation string "\n"))
1111 (let ((item (concat gdb-continuation string "\n")))
1112 (gdb-enqueue-input item)
1113 (setq gdb-continuation nil)))))
1114
1115 ;; Note: Stuff enqueued here will be sent to the next prompt, even if it
1116 ;; is a query, or other non-top-level prompt.
1117
1118 (defun gdb-enqueue-input (item)
1119 (if (not gud-running)
1120 (if gdb-prompting
1121 (progn
1122 (gdb-send-item item)
1123 (setq gdb-prompting nil))
1124 (push item gdb-input-queue))))
1125
1126 (defun gdb-dequeue-input ()
1127 (let ((queue gdb-input-queue))
1128 (and queue
1129 (let ((last (car (last queue))))
1130 (unless (nbutlast queue) (setq gdb-input-queue '()))
1131 last))))
1132
1133 (defun gdb-send-item (item)
1134 (setq gdb-flush-pending-output nil)
1135 (if gdb-enable-debug (push (cons 'send-item item) gdb-debug-ring))
1136 (setq gdb-current-item item)
1137 (let ((process (get-buffer-process gud-comint-buffer)))
1138 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
1139 (if (stringp item)
1140 (progn
1141 (setq gdb-output-sink 'user)
1142 (process-send-string process item))
1143 (progn
1144 (gdb-clear-partial-output)
1145 (setq gdb-output-sink 'pre-emacs)
1146 (process-send-string process
1147 (car item))))
1148 ;; case: eq gud-minor-mode 'gdbmi
1149 (gdb-clear-partial-output)
1150 (setq gdb-output-sink 'emacs)
1151 (process-send-string process (car item)))))
1152 \f
1153 ;;
1154 ;; output -- things gdb prints to emacs
1155 ;;
1156 ;; GDB output is a stream interrupted by annotations.
1157 ;; Annotations can be recognized by their beginning
1158 ;; with \C-j\C-z\C-z<tag><opt>\C-j
1159 ;;
1160 ;; The tag is a string obeying symbol syntax.
1161 ;;
1162 ;; The optional part `<opt>' can be either the empty string
1163 ;; or a space followed by more data relating to the annotation.
1164 ;; For example, the SOURCE annotation is followed by a filename,
1165 ;; line number and various useless goo. This data must not include
1166 ;; any newlines.
1167 ;;
1168
1169 (defcustom gud-gdba-command-name "gdb -annotate=3"
1170 "Default command to execute an executable under the GDB-UI debugger."
1171 :type 'string
1172 :group 'gud
1173 :version "22.1")
1174
1175 (defvar gdb-annotation-rules
1176 '(("pre-prompt" gdb-pre-prompt)
1177 ("prompt" gdb-prompt)
1178 ("commands" gdb-subprompt)
1179 ("overload-choice" gdb-subprompt)
1180 ("query" gdb-subprompt)
1181 ;; Need this prompt for GDB 6.1
1182 ("nquery" gdb-subprompt)
1183 ("prompt-for-continue" gdb-subprompt)
1184 ("post-prompt" gdb-post-prompt)
1185 ("source" gdb-source)
1186 ("starting" gdb-starting)
1187 ("exited" gdb-exited)
1188 ("signalled" gdb-signalled)
1189 ("signal" gdb-signal)
1190 ("breakpoint" gdb-stopping)
1191 ("watchpoint" gdb-stopping)
1192 ("frame-begin" gdb-frame-begin)
1193 ("stopped" gdb-stopped)
1194 ("error-begin" gdb-error)
1195 ("error" gdb-error)
1196 ) "An assoc mapping annotation tags to functions which process them.")
1197
1198 (defun gdb-resync()
1199 (setq gdb-flush-pending-output t)
1200 (setq gud-running nil)
1201 (gdb-force-mode-line-update "stopped")
1202 (setq gdb-output-sink 'user)
1203 (setq gdb-input-queue nil)
1204 (setq gdb-pending-triggers nil)
1205 (setq gdb-prompting t))
1206
1207 (defconst gdb-source-spec-regexp
1208 "\\(.*\\):\\([0-9]*\\):[0-9]*:[a-z]*:0x0*\\([a-f0-9]*\\)")
1209
1210 ;; Do not use this except as an annotation handler.
1211 (defun gdb-source (args)
1212 (string-match gdb-source-spec-regexp args)
1213 ;; Extract the frame position from the marker.
1214 (setq gud-last-frame
1215 (cons
1216 (match-string 1 args)
1217 (string-to-number (match-string 2 args))))
1218 (setq gdb-pc-address (match-string 3 args))
1219 ;; cover for auto-display output which comes *before*
1220 ;; stopped annotation
1221 (if (eq gdb-output-sink 'inferior) (setq gdb-output-sink 'user)))
1222
1223 (defun gdb-pre-prompt (ignored)
1224 "An annotation handler for `pre-prompt'.
1225 This terminates the collection of output from a previous command if that
1226 happens to be in effect."
1227 (setq gdb-error nil)
1228 (let ((sink gdb-output-sink))
1229 (cond
1230 ((eq sink 'user) t)
1231 ((eq sink 'emacs)
1232 (setq gdb-output-sink 'post-emacs))
1233 (t
1234 (gdb-resync)
1235 (error "Phase error in gdb-pre-prompt (got %s)" sink)))))
1236
1237 (defun gdb-prompt (ignored)
1238 "An annotation handler for `prompt'.
1239 This sends the next command (if any) to gdb."
1240 (when gdb-first-prompt
1241 (gdb-init-1)
1242 (setq gdb-first-prompt nil))
1243 (let ((sink gdb-output-sink))
1244 (cond
1245 ((eq sink 'user) t)
1246 ((eq sink 'post-emacs)
1247 (setq gdb-output-sink 'user)
1248 (let ((handler
1249 (car (cdr gdb-current-item))))
1250 (with-current-buffer (gdb-get-buffer-create 'gdb-partial-output-buffer)
1251 (funcall handler))))
1252 (t
1253 (gdb-resync)
1254 (error "Phase error in gdb-prompt (got %s)" sink))))
1255 (let ((input (gdb-dequeue-input)))
1256 (if input
1257 (gdb-send-item input)
1258 (progn
1259 (setq gdb-prompting t)
1260 (gud-display-frame)))))
1261
1262 (defun gdb-subprompt (ignored)
1263 "An annotation handler for non-top-level prompts."
1264 (setq gdb-prompting t))
1265
1266 (defun gdb-starting (ignored)
1267 "An annotation handler for `starting'.
1268 This says that I/O for the subprocess is now the program being debugged,
1269 not GDB."
1270 (setq gdb-active-process t)
1271 (let ((sink gdb-output-sink))
1272 (cond
1273 ((eq sink 'user)
1274 (progn
1275 (setq gud-running t)
1276 (setq gdb-inferior-status "running")
1277 (gdb-force-mode-line-update gdb-inferior-status)
1278 (gdb-remove-text-properties)
1279 (setq gud-overlay-arrow-position nil)
1280 (setq gdb-overlay-arrow-position nil)
1281 (if gdb-use-separate-io-buffer
1282 (setq gdb-output-sink 'inferior))))
1283 (t
1284 (gdb-resync)
1285 (error "Unexpected `starting' annotation")))))
1286
1287 (defun gdb-signal (ignored)
1288 (setq gdb-inferior-status "signal")
1289 (gdb-force-mode-line-update gdb-inferior-status)
1290 (gdb-stopping ignored))
1291
1292 (defun gdb-stopping (ignored)
1293 "An annotation handler for `breakpoint' and other annotations.
1294 They say that I/O for the subprocess is now GDB, not the program
1295 being debugged."
1296 (if gdb-use-separate-io-buffer
1297 (let ((sink gdb-output-sink))
1298 (cond
1299 ((eq sink 'inferior)
1300 (setq gdb-output-sink 'user))
1301 (t
1302 (gdb-resync)
1303 (error "Unexpected stopping annotation"))))))
1304
1305 (defun gdb-exited (ignored)
1306 "An annotation handler for `exited' and `signalled'.
1307 They say that I/O for the subprocess is now GDB, not the program
1308 being debugged and that the program is no longer running. This
1309 function is used to change the focus of GUD tooltips to #define
1310 directives."
1311 (setq gdb-active-process nil)
1312 (setq gud-overlay-arrow-position nil)
1313 (setq gdb-overlay-arrow-position nil)
1314 (setq gdb-inferior-status "exited")
1315 (gdb-force-mode-line-update gdb-inferior-status)
1316 (gdb-stopping ignored))
1317
1318 (defun gdb-signalled (ignored)
1319 (setq gdb-signalled t))
1320
1321 (defun gdb-frame-begin (ignored)
1322 (let ((sink gdb-output-sink))
1323 (cond
1324 ((eq sink 'inferior)
1325 (setq gdb-output-sink 'user))
1326 ((eq sink 'user) t)
1327 ((eq sink 'emacs) t)
1328 (t
1329 (gdb-resync)
1330 (error "Unexpected frame-begin annotation (%S)" sink)))))
1331
1332 (defun gdb-stopped (ignored)
1333 "An annotation handler for `stopped'.
1334 It is just like `gdb-stopping', except that if we already set the output
1335 sink to `user' in `gdb-stopping', that is fine."
1336 (setq gud-running nil)
1337 (unless (or gud-overlay-arrow-position gud-last-frame
1338 (not gud-last-last-frame))
1339 (gud-display-line (car gud-last-last-frame) (cdr gud-last-last-frame)))
1340 (unless (member gdb-inferior-status '("exited" "signal"))
1341 (setq gdb-inferior-status "stopped")
1342 (gdb-force-mode-line-update gdb-inferior-status))
1343 (let ((sink gdb-output-sink))
1344 (cond
1345 ((eq sink 'inferior)
1346 (setq gdb-output-sink 'user))
1347 ((eq sink 'user) t)
1348 (t
1349 (gdb-resync)
1350 (error "Unexpected stopped annotation"))))
1351 (if gdb-signalled (gdb-exited ignored)))
1352
1353 (defun gdb-error (ignored)
1354 (setq gdb-error (not gdb-error)))
1355
1356 (defun gdb-post-prompt (ignored)
1357 "An annotation handler for `post-prompt'.
1358 This begins the collection of output from the current command if that
1359 happens to be appropriate."
1360 ;; Don't add to queue if there outstanding items or gdb-version is not known
1361 ;; yet.
1362 (unless (or gdb-pending-triggers gdb-first-post-prompt)
1363 (gdb-get-selected-frame)
1364 (gdb-invalidate-frames)
1365 ;; Regenerate breakpoints buffer in case it has been inadvertantly deleted.
1366 (gdb-get-buffer-create 'gdb-breakpoints-buffer)
1367 (gdb-invalidate-breakpoints)
1368 ;; Do this through gdb-get-selected-frame -> gdb-frame-handler
1369 ;; so gdb-pc-address is updated.
1370 ;; (gdb-invalidate-assembler)
1371
1372 (if (string-equal gdb-version "pre-6.4")
1373 (gdb-invalidate-registers)
1374 (gdb-get-changed-registers)
1375 (gdb-invalidate-registers-1))
1376
1377 (gdb-invalidate-memory)
1378 (if (string-equal gdb-version "pre-6.4")
1379 (gdb-invalidate-locals)
1380 (gdb-invalidate-locals-1))
1381
1382 (gdb-invalidate-threads)
1383 (unless (eq system-type 'darwin) ;Breaks on Darwin's GDB-5.3.
1384 ;; FIXME: with GDB-6 on Darwin, this might very well work.
1385 ;; Only needed/used with speedbar/watch expressions.
1386 (when (and (boundp 'speedbar-frame) (frame-live-p speedbar-frame))
1387 (if (string-equal gdb-version "pre-6.4")
1388 (gdb-var-update)
1389 (gdb-var-update-1)))))
1390 (setq gdb-first-post-prompt nil)
1391 (let ((sink gdb-output-sink))
1392 (cond
1393 ((eq sink 'user) t)
1394 ((eq sink 'pre-emacs)
1395 (setq gdb-output-sink 'emacs))
1396 (t
1397 (gdb-resync)
1398 (error "Phase error in gdb-post-prompt (got %s)" sink)))))
1399
1400 (defconst gdb-buffer-list
1401 '(gdb-stack-buffer gdb-locals-buffer gdb-registers-buffer gdb-threads-buffer))
1402
1403 (defun gdb-remove-text-properties ()
1404 (dolist (buffertype gdb-buffer-list)
1405 (let ((buffer (gdb-get-buffer buffertype)))
1406 (if buffer
1407 (with-current-buffer buffer
1408 (let ((inhibit-read-only t))
1409 (remove-text-properties
1410 (point-min) (point-max) '(mouse-face nil help-echo nil))))))))
1411
1412 ;; GUD displays the selected GDB frame. This might might not be the current
1413 ;; GDB frame (after up, down etc). If no GDB frame is visible but the last
1414 ;; visited breakpoint is, use that window.
1415 (defun gdb-display-source-buffer (buffer)
1416 (let* ((last-window (if gud-last-last-frame
1417 (get-buffer-window
1418 (gud-find-file (car gud-last-last-frame)))))
1419 (source-window (or last-window
1420 (if (and gdb-source-window
1421 (window-live-p gdb-source-window))
1422 gdb-source-window))))
1423 (when source-window
1424 (setq gdb-source-window source-window)
1425 (set-window-buffer source-window buffer))
1426 source-window))
1427
1428 (defun gud-gdba-marker-filter (string)
1429 "A gud marker filter for gdb. Handle a burst of output from GDB."
1430 (if gdb-flush-pending-output
1431 nil
1432 (when gdb-enable-debug
1433 (push (cons 'recv string) gdb-debug-ring)
1434 (if (> (length gdb-debug-ring) gdb-debug-ring-max)
1435 (setcdr (nthcdr (1- gdb-debug-ring-max) gdb-debug-ring) nil)))
1436 ;; Recall the left over gud-marker-acc from last time.
1437 (setq gud-marker-acc (concat gud-marker-acc string))
1438 ;; Start accumulating output for the GUD buffer.
1439 (let ((output ""))
1440 ;;
1441 ;; Process all the complete markers in this chunk.
1442 (while (string-match "\n\032\032\\(.*\\)\n" gud-marker-acc)
1443 (let ((annotation (match-string 1 gud-marker-acc)))
1444 ;;
1445 ;; Stuff prior to the match is just ordinary output.
1446 ;; It is either concatenated to OUTPUT or directed
1447 ;; elsewhere.
1448 (setq output
1449 (gdb-concat-output
1450 output
1451 (substring gud-marker-acc 0 (match-beginning 0))))
1452 ;;
1453 ;; Take that stuff off the gud-marker-acc.
1454 (setq gud-marker-acc (substring gud-marker-acc (match-end 0)))
1455 ;;
1456 ;; Parse the tag from the annotation, and maybe its arguments.
1457 (string-match "\\(\\S-*\\) ?\\(.*\\)" annotation)
1458 (let* ((annotation-type (match-string 1 annotation))
1459 (annotation-arguments (match-string 2 annotation))
1460 (annotation-rule (assoc annotation-type
1461 gdb-annotation-rules)))
1462 ;; Call the handler for this annotation.
1463 (if annotation-rule
1464 (funcall (car (cdr annotation-rule))
1465 annotation-arguments)
1466 ;; Else the annotation is not recognized. Ignore it silently,
1467 ;; so that GDB can add new annotations without causing
1468 ;; us to blow up.
1469 ))))
1470 ;;
1471 ;; Does the remaining text end in a partial line?
1472 ;; If it does, then keep part of the gud-marker-acc until we get more.
1473 (if (string-match "\n\\'\\|\n\032\\'\\|\n\032\032.*\\'"
1474 gud-marker-acc)
1475 (progn
1476 ;; Everything before the potential marker start can be output.
1477 (setq output
1478 (gdb-concat-output output
1479 (substring gud-marker-acc 0
1480 (match-beginning 0))))
1481 ;;
1482 ;; Everything after, we save, to combine with later input.
1483 (setq gud-marker-acc (substring gud-marker-acc
1484 (match-beginning 0))))
1485 ;;
1486 ;; In case we know the gud-marker-acc contains no partial annotations:
1487 (progn
1488 (setq output (gdb-concat-output output gud-marker-acc))
1489 (setq gud-marker-acc "")))
1490 output)))
1491
1492 (defun gdb-concat-output (so-far new)
1493 (if gdb-error
1494 (put-text-property 0 (length new) 'face font-lock-warning-face new))
1495 (let ((sink gdb-output-sink))
1496 (cond
1497 ((eq sink 'user) (concat so-far new))
1498 ((or (eq sink 'pre-emacs) (eq sink 'post-emacs)) so-far)
1499 ((eq sink 'emacs)
1500 (gdb-append-to-partial-output new)
1501 so-far)
1502 ((eq sink 'inferior)
1503 (gdb-append-to-inferior-io new)
1504 so-far)
1505 (t
1506 (gdb-resync)
1507 (error "Bogon output sink %S" sink)))))
1508
1509 (defun gdb-append-to-partial-output (string)
1510 (with-current-buffer (gdb-get-buffer-create 'gdb-partial-output-buffer)
1511 (goto-char (point-max))
1512 (insert string)))
1513
1514 (defun gdb-clear-partial-output ()
1515 (with-current-buffer (gdb-get-buffer-create 'gdb-partial-output-buffer)
1516 (erase-buffer)))
1517
1518 (defun gdb-append-to-inferior-io (string)
1519 (with-current-buffer (gdb-get-buffer-create 'gdb-inferior-io)
1520 (goto-char (point-max))
1521 (insert-before-markers string))
1522 (if (not (string-equal string ""))
1523 (gdb-display-buffer (gdb-get-buffer-create 'gdb-inferior-io))))
1524
1525 (defun gdb-clear-inferior-io ()
1526 (with-current-buffer (gdb-get-buffer-create 'gdb-inferior-io)
1527 (erase-buffer)))
1528 \f
1529
1530 ;; One trick is to have a command who's output is always available in a buffer
1531 ;; of it's own, and is always up to date. We build several buffers of this
1532 ;; type.
1533 ;;
1534 ;; There are two aspects to this: gdb has to tell us when the output for that
1535 ;; command might have changed, and we have to be able to run the command
1536 ;; behind the user's back.
1537 ;;
1538 ;; The output phasing associated with the variable gdb-output-sink
1539 ;; help us to run commands behind the user's back.
1540 ;;
1541 ;; Below is the code for specificly managing buffers of output from one
1542 ;; command.
1543 ;;
1544
1545 ;; The trigger function is suitable for use in the assoc GDB-ANNOTATION-RULES
1546 ;; It adds an input for the command we are tracking. It should be the
1547 ;; annotation rule binding of whatever gdb sends to tell us this command
1548 ;; might have changed it's output.
1549 ;;
1550 ;; NAME is the function name. DEMAND-PREDICATE tests if output is really needed.
1551 ;; GDB-COMMAND is a string of such. OUTPUT-HANDLER is the function bound to the
1552 ;; input in the input queue (see comment about ``gdb communications'' above).
1553
1554 (defmacro def-gdb-auto-update-trigger (name demand-predicate gdb-command
1555 output-handler)
1556 `(defun ,name (&optional ignored)
1557 (if (and ,demand-predicate
1558 (not (member ',name
1559 gdb-pending-triggers)))
1560 (progn
1561 (gdb-enqueue-input
1562 (list ,gdb-command ',output-handler))
1563 (push ',name gdb-pending-triggers)))))
1564
1565 (defmacro def-gdb-auto-update-handler (name trigger buf-key custom-defun)
1566 `(defun ,name ()
1567 (setq gdb-pending-triggers
1568 (delq ',trigger
1569 gdb-pending-triggers))
1570 (let ((buf (gdb-get-buffer ',buf-key)))
1571 (and buf
1572 (with-current-buffer buf
1573 (let* ((window (get-buffer-window buf 0))
1574 (start (window-start window))
1575 (p (window-point window))
1576 (buffer-read-only nil))
1577 (erase-buffer)
1578 (insert-buffer-substring (gdb-get-buffer-create
1579 'gdb-partial-output-buffer))
1580 (set-window-start window start)
1581 (set-window-point window p)))))
1582 ;; put customisation here
1583 (,custom-defun)))
1584
1585 (defmacro def-gdb-auto-updated-buffer (buffer-key
1586 trigger-name gdb-command
1587 output-handler-name custom-defun)
1588 `(progn
1589 (def-gdb-auto-update-trigger ,trigger-name
1590 ;; The demand predicate:
1591 (gdb-get-buffer ',buffer-key)
1592 ,gdb-command
1593 ,output-handler-name)
1594 (def-gdb-auto-update-handler ,output-handler-name
1595 ,trigger-name ,buffer-key ,custom-defun)))
1596
1597 \f
1598 ;;
1599 ;; Breakpoint buffer : This displays the output of `info breakpoints'.
1600 ;;
1601 (gdb-set-buffer-rules 'gdb-breakpoints-buffer
1602 'gdb-breakpoints-buffer-name
1603 'gdb-breakpoints-mode)
1604
1605 (def-gdb-auto-updated-buffer gdb-breakpoints-buffer
1606 ;; This defines the auto update rule for buffers of type
1607 ;; `gdb-breakpoints-buffer'.
1608 ;;
1609 ;; It defines a function to serve as the annotation handler that
1610 ;; handles the `foo-invalidated' message. That function is called:
1611 gdb-invalidate-breakpoints
1612 ;;
1613 ;; To update the buffer, this command is sent to gdb.
1614 "server info breakpoints\n"
1615 ;;
1616 ;; This also defines a function to be the handler for the output
1617 ;; from the command above. That function will copy the output into
1618 ;; the appropriately typed buffer. That function will be called:
1619 gdb-info-breakpoints-handler
1620 ;; buffer specific functions
1621 gdb-info-breakpoints-custom)
1622
1623 (defconst breakpoint-xpm-data
1624 "/* XPM */
1625 static char *magick[] = {
1626 /* columns rows colors chars-per-pixel */
1627 \"10 10 2 1\",
1628 \" c red\",
1629 \"+ c None\",
1630 /* pixels */
1631 \"+++ +++\",
1632 \"++ ++\",
1633 \"+ +\",
1634 \" \",
1635 \" \",
1636 \" \",
1637 \" \",
1638 \"+ +\",
1639 \"++ ++\",
1640 \"+++ +++\",
1641 };"
1642 "XPM data used for breakpoint icon.")
1643
1644 (defconst breakpoint-enabled-pbm-data
1645 "P1
1646 10 10\",
1647 0 0 0 0 1 1 1 1 0 0 0 0
1648 0 0 0 1 1 1 1 1 1 0 0 0
1649 0 0 1 1 1 1 1 1 1 1 0 0
1650 0 1 1 1 1 1 1 1 1 1 1 0
1651 0 1 1 1 1 1 1 1 1 1 1 0
1652 0 1 1 1 1 1 1 1 1 1 1 0
1653 0 1 1 1 1 1 1 1 1 1 1 0
1654 0 0 1 1 1 1 1 1 1 1 0 0
1655 0 0 0 1 1 1 1 1 1 0 0 0
1656 0 0 0 0 1 1 1 1 0 0 0 0"
1657 "PBM data used for enabled breakpoint icon.")
1658
1659 (defconst breakpoint-disabled-pbm-data
1660 "P1
1661 10 10\",
1662 0 0 1 0 1 0 1 0 0 0
1663 0 1 0 1 0 1 0 1 0 0
1664 1 0 1 0 1 0 1 0 1 0
1665 0 1 0 1 0 1 0 1 0 1
1666 1 0 1 0 1 0 1 0 1 0
1667 0 1 0 1 0 1 0 1 0 1
1668 1 0 1 0 1 0 1 0 1 0
1669 0 1 0 1 0 1 0 1 0 1
1670 0 0 1 0 1 0 1 0 1 0
1671 0 0 0 1 0 1 0 1 0 0"
1672 "PBM data used for disabled breakpoint icon.")
1673
1674 (defvar breakpoint-enabled-icon nil
1675 "Icon for enabled breakpoint in display margin.")
1676
1677 (defvar breakpoint-disabled-icon nil
1678 "Icon for disabled breakpoint in display margin.")
1679
1680 (and (display-images-p)
1681 ;; Bitmap for breakpoint in fringe
1682 (define-fringe-bitmap 'breakpoint
1683 "\x3c\x7e\xff\xff\xff\xff\x7e\x3c")
1684 ;; Bitmap for gud-overlay-arrow in fringe
1685 (define-fringe-bitmap 'hollow-right-triangle
1686 "\xe0\x90\x88\x84\x84\x88\x90\xe0"))
1687
1688 (defface breakpoint-enabled
1689 '((t
1690 :foreground "red"
1691 :weight bold))
1692 "Face for enabled breakpoint icon in fringe."
1693 :group 'gud)
1694
1695 (defface breakpoint-disabled
1696 ;; We use different values of grey for different background types,
1697 ;; so that on low-color displays it will end up as something visible
1698 ;; if it has to be approximated.
1699 '((t :foreground "grey70"))
1700 "Face for disabled breakpoint icon in fringe."
1701 :group 'gud)
1702
1703 ;; Put breakpoint icons in relevant margins (even those set in the GUD buffer).
1704 (defun gdb-info-breakpoints-custom ()
1705 (let ((flag) (bptno))
1706 ;; Remove all breakpoint-icons in source buffers but not assembler buffer.
1707 (dolist (buffer (buffer-list))
1708 (with-current-buffer buffer
1709 (if (and (memq gud-minor-mode '(gdba gdbmi))
1710 (not (string-match "\\`\\*.+\\*\\'" (buffer-name))))
1711 (gdb-remove-breakpoint-icons (point-min) (point-max)))))
1712 (with-current-buffer (gdb-get-buffer 'gdb-breakpoints-buffer)
1713 (save-excursion
1714 (goto-char (point-min))
1715 (while (< (point) (- (point-max) 1))
1716 (forward-line 1)
1717 (if (looking-at "[^\t].*?breakpoint")
1718 (progn
1719 (looking-at "\\([0-9]+\\)\\s-+\\S-+\\s-+\\S-+\\s-+\\(.\\)")
1720 (setq bptno (match-string 1))
1721 (setq flag (char-after (match-beginning 2)))
1722 (beginning-of-line)
1723 (if (re-search-forward " in \\(.*\\) at\\s-+" nil t)
1724 (progn
1725 (let ((buffer-read-only nil))
1726 (add-text-properties (match-beginning 1) (match-end 1)
1727 '(face font-lock-function-name-face)))
1728 (looking-at "\\(\\S-+\\):\\([0-9]+\\)")
1729 (let ((line (match-string 2)) (buffer-read-only nil)
1730 (file (match-string 1)))
1731 (add-text-properties (line-beginning-position)
1732 (line-end-position)
1733 '(mouse-face highlight
1734 help-echo "mouse-2, RET: visit breakpoint"))
1735 (unless (file-exists-p file)
1736 (setq file (cdr (assoc bptno gdb-location-alist))))
1737 (if (and file
1738 (not (string-equal file "File not found")))
1739 (with-current-buffer
1740 (find-file-noselect file 'nowarn)
1741 (set (make-local-variable 'gud-minor-mode)
1742 'gdba)
1743 (set (make-local-variable 'tool-bar-map)
1744 gud-tool-bar-map)
1745 ;; Only want one breakpoint icon at each
1746 ;; location.
1747 (save-excursion
1748 (goto-line (string-to-number line))
1749 (gdb-put-breakpoint-icon (eq flag ?y) bptno)))
1750 (gdb-enqueue-input
1751 (list
1752 (concat gdb-server-prefix "list "
1753 (match-string-no-properties 1) ":1\n")
1754 'ignore))
1755 (gdb-enqueue-input
1756 (list (concat gdb-server-prefix "info source\n")
1757 `(lambda () (gdb-get-location
1758 ,bptno ,line ,flag))))))))))
1759 (end-of-line)))))
1760 (if (gdb-get-buffer 'gdb-assembler-buffer) (gdb-assembler-custom)))
1761
1762 (defun gdb-mouse-set-clear-breakpoint (event)
1763 "Set/clear breakpoint in left fringe/margin with mouse click."
1764 (interactive "e")
1765 (mouse-minibuffer-check event)
1766 (let ((posn (event-end event)))
1767 (if (numberp (posn-point posn))
1768 (with-selected-window (posn-window posn)
1769 (save-excursion
1770 (goto-char (posn-point posn))
1771 (if (or (posn-object posn)
1772 (eq (car (fringe-bitmaps-at-pos (posn-point posn)))
1773 'breakpoint))
1774 (gud-remove nil)
1775 (gud-break nil)))))))
1776
1777 (defun gdb-mouse-toggle-breakpoint-margin (event)
1778 "Enable/disable breakpoint in left margin with mouse click."
1779 (interactive "e")
1780 (mouse-minibuffer-check event)
1781 (let ((posn (event-end event)))
1782 (if (numberp (posn-point posn))
1783 (with-selected-window (posn-window posn)
1784 (save-excursion
1785 (goto-char (posn-point posn))
1786 (if (posn-object posn)
1787 (gdb-enqueue-input
1788 (list
1789 (let ((bptno (get-text-property
1790 0 'gdb-bptno (car (posn-string posn)))))
1791 (concat gdb-server-prefix
1792 (if (get-text-property
1793 0 'gdb-enabled (car (posn-string posn)))
1794 "disable "
1795 "enable ")
1796 bptno "\n"))
1797 'ignore))))))))
1798
1799 (defun gdb-mouse-toggle-breakpoint-fringe (event)
1800 "Enable/disable breakpoint in left fringe with mouse click."
1801 (interactive "e")
1802 (mouse-minibuffer-check event)
1803 (let* ((posn (event-end event))
1804 (pos (posn-point posn))
1805 obj)
1806 (when (numberp pos)
1807 (with-selected-window (posn-window posn)
1808 (save-excursion
1809 (set-buffer (window-buffer (selected-window)))
1810 (goto-char pos)
1811 (dolist (overlay (overlays-in pos pos))
1812 (when (overlay-get overlay 'put-break)
1813 (setq obj (overlay-get overlay 'before-string))))
1814 (when (stringp obj)
1815 (gdb-enqueue-input
1816 (list
1817 (concat gdb-server-prefix
1818 (if (get-text-property 0 'gdb-enabled obj)
1819 "disable "
1820 "enable ")
1821 (get-text-property 0 'gdb-bptno obj) "\n")
1822 'ignore))))))))
1823
1824 (defun gdb-breakpoints-buffer-name ()
1825 (with-current-buffer gud-comint-buffer
1826 (concat "*breakpoints of " (gdb-get-target-string) "*")))
1827
1828 (defun gdb-display-breakpoints-buffer ()
1829 "Display status of user-settable breakpoints."
1830 (interactive)
1831 (gdb-display-buffer
1832 (gdb-get-buffer-create 'gdb-breakpoints-buffer)))
1833
1834 (defun gdb-frame-breakpoints-buffer ()
1835 "Display status of user-settable breakpoints in a new frame."
1836 (interactive)
1837 (let ((special-display-regexps (append special-display-regexps '(".*")))
1838 (special-display-frame-alist gdb-frame-parameters))
1839 (display-buffer (gdb-get-buffer-create 'gdb-breakpoints-buffer))))
1840
1841 (defvar gdb-breakpoints-mode-map
1842 (let ((map (make-sparse-keymap))
1843 (menu (make-sparse-keymap "Breakpoints")))
1844 (define-key menu [quit] '("Quit" . gdb-delete-frame-or-window))
1845 (define-key menu [goto] '("Goto" . gdb-goto-breakpoint))
1846 (define-key menu [delete] '("Delete" . gdb-delete-breakpoint))
1847 (define-key menu [toggle] '("Toggle" . gdb-toggle-breakpoint))
1848 (suppress-keymap map)
1849 (define-key map [menu-bar breakpoints] (cons "Breakpoints" menu))
1850 (define-key map " " 'gdb-toggle-breakpoint)
1851 (define-key map "D" 'gdb-delete-breakpoint)
1852 ;; Don't bind "q" to kill-this-buffer as we need it for breakpoint icons.
1853 (define-key map "q" 'gdb-delete-frame-or-window)
1854 (define-key map "\r" 'gdb-goto-breakpoint)
1855 (define-key map [mouse-2] 'gdb-goto-breakpoint)
1856 (define-key map [follow-link] 'mouse-face)
1857 map))
1858
1859 (defun gdb-delete-frame-or-window ()
1860 "Delete frame if there is only one window. Otherwise delete the window."
1861 (interactive)
1862 (if (one-window-p) (delete-frame)
1863 (delete-window)))
1864
1865 (defun gdb-breakpoints-mode ()
1866 "Major mode for gdb breakpoints.
1867
1868 \\{gdb-breakpoints-mode-map}"
1869 (kill-all-local-variables)
1870 (setq major-mode 'gdb-breakpoints-mode)
1871 (setq mode-name "Breakpoints")
1872 (use-local-map gdb-breakpoints-mode-map)
1873 (setq buffer-read-only t)
1874 (run-mode-hooks 'gdb-breakpoints-mode-hook)
1875 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
1876 'gdb-invalidate-breakpoints
1877 'gdbmi-invalidate-breakpoints))
1878
1879 (defconst gdb-breakpoint-regexp
1880 "\\([0-9]+\\).*?\\(?:point\\|catch\\s-+\\S-+\\)\\s-+\\S-+\\s-+\\(.\\)\\s-+")
1881
1882 (defun gdb-toggle-breakpoint ()
1883 "Enable/disable breakpoint at current line."
1884 (interactive)
1885 (save-excursion
1886 (beginning-of-line 1)
1887 (if (looking-at gdb-breakpoint-regexp)
1888 (gdb-enqueue-input
1889 (list
1890 (concat gdb-server-prefix
1891 (if (eq ?y (char-after (match-beginning 2)))
1892 "disable "
1893 "enable ")
1894 (match-string 1) "\n") 'ignore))
1895 (error "Not recognized as break/watchpoint line"))))
1896
1897 (defun gdb-delete-breakpoint ()
1898 "Delete the breakpoint at current line."
1899 (interactive)
1900 (beginning-of-line 1)
1901 (if (looking-at gdb-breakpoint-regexp)
1902 (gdb-enqueue-input
1903 (list
1904 (concat gdb-server-prefix "delete " (match-string 1) "\n") 'ignore))
1905 (error "Not recognized as break/watchpoint line")))
1906
1907 (defun gdb-goto-breakpoint (&optional event)
1908 "Display the breakpoint location specified at current line."
1909 (interactive (list last-input-event))
1910 (if event (posn-set-point (event-end event)))
1911 (save-excursion
1912 (beginning-of-line 1)
1913 (if (looking-at "\\([0-9]+\\) .+ in .+ at\\s-+\\(\\S-+\\):\\([0-9]+\\)")
1914 (let ((bptno (match-string 1))
1915 (file (match-string 2))
1916 (line (match-string 3)))
1917 (save-selected-window
1918 (let* ((buffer (find-file-noselect
1919 (if (file-exists-p file) file
1920 (cdr (assoc bptno gdb-location-alist)))))
1921 (window (or (gdb-display-source-buffer buffer)
1922 (display-buffer buffer))))
1923 (setq gdb-source-window window)
1924 (with-current-buffer buffer
1925 (goto-line (string-to-number line))
1926 (set-window-point window (point))))))
1927 (error "No location specified."))))
1928 \f
1929
1930 ;; Frames buffer. This displays a perpetually correct bactracktrace
1931 ;; (from the command `where').
1932 ;;
1933 ;; Alas, if your stack is deep, it is costly.
1934 ;;
1935 (gdb-set-buffer-rules 'gdb-stack-buffer
1936 'gdb-stack-buffer-name
1937 'gdb-frames-mode)
1938
1939 (def-gdb-auto-updated-buffer gdb-stack-buffer
1940 gdb-invalidate-frames
1941 "server info stack\n"
1942 gdb-info-stack-handler
1943 gdb-info-stack-custom)
1944
1945 (defun gdb-info-stack-custom ()
1946 (with-current-buffer (gdb-get-buffer 'gdb-stack-buffer)
1947 (save-excursion
1948 (let ((buffer-read-only nil)
1949 bl el)
1950 (goto-char (point-min))
1951 (while (< (point) (point-max))
1952 (setq bl (line-beginning-position)
1953 el (line-end-position))
1954 (when (looking-at "#")
1955 (add-text-properties bl el
1956 '(mouse-face highlight
1957 help-echo "mouse-2, RET: Select frame")))
1958 (goto-char bl)
1959 (when (looking-at "^#\\([0-9]+\\)")
1960 (when (string-equal (match-string 1) gdb-frame-number)
1961 (put-text-property bl (+ bl 4)
1962 'face '(:inverse-video t)))
1963 (when (re-search-forward
1964 (concat
1965 (if (string-equal (match-string 1) "0") "" " in ")
1966 "\\([^ ]+\\) (") el t)
1967 (put-text-property (match-beginning 1) (match-end 1)
1968 'face font-lock-function-name-face)
1969 (setq bl (match-end 0))
1970 (while (re-search-forward "<\\([^>]+\\)>" el t)
1971 (put-text-property (match-beginning 1) (match-end 1)
1972 'face font-lock-function-name-face))
1973 (goto-char bl)
1974 (while (re-search-forward "\\(\\(\\sw\\|[_.]\\)+\\)=" el t)
1975 (put-text-property (match-beginning 1) (match-end 1)
1976 'face font-lock-variable-name-face))))
1977 (forward-line 1))))))
1978
1979 (defun gdb-stack-buffer-name ()
1980 (with-current-buffer gud-comint-buffer
1981 (concat "*stack frames of " (gdb-get-target-string) "*")))
1982
1983 (defun gdb-display-stack-buffer ()
1984 "Display backtrace of current stack."
1985 (interactive)
1986 (gdb-display-buffer
1987 (gdb-get-buffer-create 'gdb-stack-buffer)))
1988
1989 (defun gdb-frame-stack-buffer ()
1990 "Display backtrace of current stack in a new frame."
1991 (interactive)
1992 (let ((special-display-regexps (append special-display-regexps '(".*")))
1993 (special-display-frame-alist gdb-frame-parameters))
1994 (display-buffer (gdb-get-buffer-create 'gdb-stack-buffer))))
1995
1996 (defvar gdb-frames-mode-map
1997 (let ((map (make-sparse-keymap)))
1998 (suppress-keymap map)
1999 (define-key map "q" 'kill-this-buffer)
2000 (define-key map "\r" 'gdb-frames-select)
2001 (define-key map [mouse-2] 'gdb-frames-select)
2002 (define-key map [follow-link] 'mouse-face)
2003 map))
2004
2005 (defun gdb-frames-mode ()
2006 "Major mode for gdb call stack.
2007
2008 \\{gdb-frames-mode-map}"
2009 (kill-all-local-variables)
2010 (setq major-mode 'gdb-frames-mode)
2011 (setq mode-name "Frames")
2012 (setq buffer-read-only t)
2013 (use-local-map gdb-frames-mode-map)
2014 (run-mode-hooks 'gdb-frames-mode-hook)
2015 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
2016 'gdb-invalidate-frames
2017 'gdbmi-invalidate-frames))
2018
2019 (defun gdb-get-frame-number ()
2020 (save-excursion
2021 (end-of-line)
2022 (let* ((start (line-beginning-position))
2023 (pos (re-search-backward "^#*\\([0-9]+\\)" start t))
2024 (n (or (and pos (match-string-no-properties 1)) "0")))
2025 n)))
2026
2027 (defun gdb-frames-select (&optional event)
2028 "Select the frame and display the relevant source."
2029 (interactive (list last-input-event))
2030 (if event (posn-set-point (event-end event)))
2031 (gdb-enqueue-input
2032 (list (concat gdb-server-prefix "frame "
2033 (gdb-get-frame-number) "\n") 'ignore))
2034 (gud-display-frame))
2035 \f
2036
2037 ;; Threads buffer. This displays a selectable thread list.
2038 ;;
2039 (gdb-set-buffer-rules 'gdb-threads-buffer
2040 'gdb-threads-buffer-name
2041 'gdb-threads-mode)
2042
2043 (def-gdb-auto-updated-buffer gdb-threads-buffer
2044 gdb-invalidate-threads
2045 (concat gdb-server-prefix "info threads\n")
2046 gdb-info-threads-handler
2047 gdb-info-threads-custom)
2048
2049 (defun gdb-info-threads-custom ()
2050 (with-current-buffer (gdb-get-buffer 'gdb-threads-buffer)
2051 (let ((buffer-read-only nil))
2052 (goto-char (point-min))
2053 (while (< (point) (point-max))
2054 (unless (looking-at "No ")
2055 (add-text-properties (line-beginning-position) (line-end-position)
2056 '(mouse-face highlight
2057 help-echo "mouse-2, RET: select thread")))
2058 (forward-line 1)))))
2059
2060 (defun gdb-threads-buffer-name ()
2061 (with-current-buffer gud-comint-buffer
2062 (concat "*threads of " (gdb-get-target-string) "*")))
2063
2064 (defun gdb-display-threads-buffer ()
2065 "Display IDs of currently known threads."
2066 (interactive)
2067 (gdb-display-buffer
2068 (gdb-get-buffer-create 'gdb-threads-buffer)))
2069
2070 (defun gdb-frame-threads-buffer ()
2071 "Display IDs of currently known threads in a new frame."
2072 (interactive)
2073 (let ((special-display-regexps (append special-display-regexps '(".*")))
2074 (special-display-frame-alist gdb-frame-parameters))
2075 (display-buffer (gdb-get-buffer-create 'gdb-threads-buffer))))
2076
2077 (defvar gdb-threads-mode-map
2078 (let ((map (make-sparse-keymap)))
2079 (suppress-keymap map)
2080 (define-key map "q" 'kill-this-buffer)
2081 (define-key map "\r" 'gdb-threads-select)
2082 (define-key map [mouse-2] 'gdb-threads-select)
2083 (define-key map [follow-link] 'mouse-face)
2084 map))
2085
2086 (defvar gdb-threads-font-lock-keywords
2087 '((") +\\([^ ]+\\) (" (1 font-lock-function-name-face))
2088 ("in \\([^ ]+\\) (" (1 font-lock-function-name-face))
2089 ("\\(\\(\\sw\\|[_.]\\)+\\)=" (1 font-lock-variable-name-face)))
2090 "Font lock keywords used in `gdb-threads-mode'.")
2091
2092 (defun gdb-threads-mode ()
2093 "Major mode for gdb threads.
2094
2095 \\{gdb-threads-mode-map}"
2096 (kill-all-local-variables)
2097 (setq major-mode 'gdb-threads-mode)
2098 (setq mode-name "Threads")
2099 (setq buffer-read-only t)
2100 (use-local-map gdb-threads-mode-map)
2101 (set (make-local-variable 'font-lock-defaults)
2102 '(gdb-threads-font-lock-keywords))
2103 (run-mode-hooks 'gdb-threads-mode-hook)
2104 'gdb-invalidate-threads)
2105
2106 (defun gdb-get-thread-number ()
2107 (save-excursion
2108 (re-search-backward "^\\s-*\\([0-9]*\\)" nil t)
2109 (match-string-no-properties 1)))
2110
2111 (defun gdb-threads-select (&optional event)
2112 "Select the thread and display the relevant source."
2113 (interactive (list last-input-event))
2114 (if event (posn-set-point (event-end event)))
2115 (gdb-enqueue-input
2116 (list (concat gdb-server-prefix "thread "
2117 (gdb-get-thread-number) "\n") 'ignore))
2118 (gud-display-frame))
2119 \f
2120
2121 ;; Registers buffer.
2122 ;;
2123 (defcustom gdb-all-registers nil
2124 "Non-nil means include floating-point registers."
2125 :type 'boolean
2126 :group 'gud
2127 :version "22.1")
2128
2129 (gdb-set-buffer-rules 'gdb-registers-buffer
2130 'gdb-registers-buffer-name
2131 'gdb-registers-mode)
2132
2133 (def-gdb-auto-updated-buffer gdb-registers-buffer
2134 gdb-invalidate-registers
2135 (concat
2136 gdb-server-prefix "info " (if gdb-all-registers "all-") "registers\n")
2137 gdb-info-registers-handler
2138 gdb-info-registers-custom)
2139
2140 (defun gdb-info-registers-custom ()
2141 (with-current-buffer (gdb-get-buffer 'gdb-registers-buffer)
2142 (save-excursion
2143 (let ((buffer-read-only nil)
2144 start end)
2145 (goto-char (point-min))
2146 (while (< (point) (point-max))
2147 (setq start (line-beginning-position))
2148 (setq end (line-end-position))
2149 (when (looking-at "^[^ ]+")
2150 (unless (string-equal (match-string 0) "The")
2151 (put-text-property start (match-end 0)
2152 'face font-lock-variable-name-face)
2153 (add-text-properties start end
2154 '(help-echo "mouse-2: edit value"
2155 mouse-face highlight))))
2156 (forward-line 1))))))
2157
2158 (defun gdb-edit-register-value (&optional event)
2159 (interactive (list last-input-event))
2160 (save-excursion
2161 (if event (posn-set-point (event-end event)))
2162 (beginning-of-line)
2163 (let* ((register (current-word))
2164 (value (read-string (format "New value (%s): " register))))
2165 (gdb-enqueue-input
2166 (list (concat gdb-server-prefix "set $" register "=" value "\n")
2167 'ignore)))))
2168
2169 (defvar gdb-registers-mode-map
2170 (let ((map (make-sparse-keymap)))
2171 (suppress-keymap map)
2172 (define-key map "\r" 'gdb-edit-register-value)
2173 (define-key map [mouse-2] 'gdb-edit-register-value)
2174 (define-key map " " 'gdb-all-registers)
2175 (define-key map "q" 'kill-this-buffer)
2176 map))
2177
2178 (defun gdb-registers-mode ()
2179 "Major mode for gdb registers.
2180
2181 \\{gdb-registers-mode-map}"
2182 (kill-all-local-variables)
2183 (setq major-mode 'gdb-registers-mode)
2184 (setq mode-name "Registers")
2185 (setq buffer-read-only t)
2186 (use-local-map gdb-registers-mode-map)
2187 (run-mode-hooks 'gdb-registers-mode-hook)
2188 (if (string-equal gdb-version "pre-6.4")
2189 (progn
2190 (if gdb-all-registers (setq mode-name "Registers:All"))
2191 'gdb-invalidate-registers)
2192 'gdb-invalidate-registers-1))
2193
2194 (defun gdb-registers-buffer-name ()
2195 (with-current-buffer gud-comint-buffer
2196 (concat "*registers of " (gdb-get-target-string) "*")))
2197
2198 (defun gdb-display-registers-buffer ()
2199 "Display integer register contents."
2200 (interactive)
2201 (gdb-display-buffer
2202 (gdb-get-buffer-create 'gdb-registers-buffer)))
2203
2204 (defun gdb-frame-registers-buffer ()
2205 "Display integer register contents in a new frame."
2206 (interactive)
2207 (let ((special-display-regexps (append special-display-regexps '(".*")))
2208 (special-display-frame-alist gdb-frame-parameters))
2209 (display-buffer (gdb-get-buffer-create 'gdb-registers-buffer))))
2210
2211 (defun gdb-all-registers ()
2212 "Toggle the display of floating-point registers (pre GDB 6.4 only)."
2213 (interactive)
2214 (when (string-equal gdb-version "pre-6.4")
2215 (if gdb-all-registers
2216 (progn
2217 (setq gdb-all-registers nil)
2218 (with-current-buffer (gdb-get-buffer-create 'gdb-registers-buffer)
2219 (setq mode-name "Registers")))
2220 (setq gdb-all-registers t)
2221 (with-current-buffer (gdb-get-buffer-create 'gdb-registers-buffer)
2222 (setq mode-name "Registers:All")))
2223 (message (format "Display of floating-point registers %sabled"
2224 (if gdb-all-registers "en" "dis")))
2225 (gdb-invalidate-registers)))
2226 \f
2227
2228 ;; Memory buffer.
2229 ;;
2230 (defcustom gdb-memory-repeat-count 32
2231 "Number of data items in memory window."
2232 :type 'integer
2233 :group 'gud
2234 :version "22.1")
2235
2236 (defcustom gdb-memory-format "x"
2237 "Display format of data items in memory window."
2238 :type '(choice (const :tag "Hexadecimal" "x")
2239 (const :tag "Signed decimal" "d")
2240 (const :tag "Unsigned decimal" "u")
2241 (const :tag "Octal" "o")
2242 (const :tag "Binary" "t"))
2243 :group 'gud
2244 :version "22.1")
2245
2246 (defcustom gdb-memory-unit "w"
2247 "Unit size of data items in memory window."
2248 :type '(choice (const :tag "Byte" "b")
2249 (const :tag "Halfword" "h")
2250 (const :tag "Word" "w")
2251 (const :tag "Giant word" "g"))
2252 :group 'gud
2253 :version "22.1")
2254
2255 (gdb-set-buffer-rules 'gdb-memory-buffer
2256 'gdb-memory-buffer-name
2257 'gdb-memory-mode)
2258
2259 (def-gdb-auto-updated-buffer gdb-memory-buffer
2260 gdb-invalidate-memory
2261 (concat gdb-server-prefix "x/" (number-to-string gdb-memory-repeat-count)
2262 gdb-memory-format gdb-memory-unit " " gdb-memory-address "\n")
2263 gdb-read-memory-handler
2264 gdb-read-memory-custom)
2265
2266 (defun gdb-read-memory-custom ()
2267 (save-excursion
2268 (goto-char (point-min))
2269 (if (looking-at "0x[[:xdigit:]]+")
2270 (setq gdb-memory-address (match-string 0)))))
2271
2272 (defvar gdb-memory-mode-map
2273 (let ((map (make-sparse-keymap)))
2274 (suppress-keymap map)
2275 (define-key map "q" 'kill-this-buffer)
2276 map))
2277
2278 (defun gdb-memory-set-address (event)
2279 "Set the start memory address."
2280 (interactive "e")
2281 (save-selected-window
2282 (select-window (posn-window (event-start event)))
2283 (let ((arg (read-from-minibuffer "Memory address: ")))
2284 (setq gdb-memory-address arg))
2285 (gdb-invalidate-memory)))
2286
2287 (defun gdb-memory-set-repeat-count (event)
2288 "Set the number of data items in memory window."
2289 (interactive "e")
2290 (save-selected-window
2291 (select-window (posn-window (event-start event)))
2292 (let* ((arg (read-from-minibuffer "Repeat count: "))
2293 (count (string-to-number arg)))
2294 (if (<= count 0)
2295 (error "Positive numbers only")
2296 (customize-set-variable 'gdb-memory-repeat-count count)
2297 (gdb-invalidate-memory)))))
2298
2299 (defun gdb-memory-format-binary ()
2300 "Set the display format to binary."
2301 (interactive)
2302 (customize-set-variable 'gdb-memory-format "t")
2303 (gdb-invalidate-memory))
2304
2305 (defun gdb-memory-format-octal ()
2306 "Set the display format to octal."
2307 (interactive)
2308 (customize-set-variable 'gdb-memory-format "o")
2309 (gdb-invalidate-memory))
2310
2311 (defun gdb-memory-format-unsigned ()
2312 "Set the display format to unsigned decimal."
2313 (interactive)
2314 (customize-set-variable 'gdb-memory-format "u")
2315 (gdb-invalidate-memory))
2316
2317 (defun gdb-memory-format-signed ()
2318 "Set the display format to decimal."
2319 (interactive)
2320 (customize-set-variable 'gdb-memory-format "d")
2321 (gdb-invalidate-memory))
2322
2323 (defun gdb-memory-format-hexadecimal ()
2324 "Set the display format to hexadecimal."
2325 (interactive)
2326 (customize-set-variable 'gdb-memory-format "x")
2327 (gdb-invalidate-memory))
2328
2329 (defvar gdb-memory-format-map
2330 (let ((map (make-sparse-keymap)))
2331 (define-key map [header-line down-mouse-3] 'gdb-memory-format-menu-1)
2332 map)
2333 "Keymap to select format in the header line.")
2334
2335 (defvar gdb-memory-format-menu (make-sparse-keymap "Format")
2336 "Menu of display formats in the header line.")
2337
2338 (define-key gdb-memory-format-menu [binary]
2339 '(menu-item "Binary" gdb-memory-format-binary
2340 :button (:radio . (equal gdb-memory-format "t"))))
2341 (define-key gdb-memory-format-menu [octal]
2342 '(menu-item "Octal" gdb-memory-format-octal
2343 :button (:radio . (equal gdb-memory-format "o"))))
2344 (define-key gdb-memory-format-menu [unsigned]
2345 '(menu-item "Unsigned Decimal" gdb-memory-format-unsigned
2346 :button (:radio . (equal gdb-memory-format "u"))))
2347 (define-key gdb-memory-format-menu [signed]
2348 '(menu-item "Signed Decimal" gdb-memory-format-signed
2349 :button (:radio . (equal gdb-memory-format "d"))))
2350 (define-key gdb-memory-format-menu [hexadecimal]
2351 '(menu-item "Hexadecimal" gdb-memory-format-hexadecimal
2352 :button (:radio . (equal gdb-memory-format "x"))))
2353
2354 (defun gdb-memory-format-menu (event)
2355 (interactive "@e")
2356 (x-popup-menu event gdb-memory-format-menu))
2357
2358 (defun gdb-memory-format-menu-1 (event)
2359 (interactive "e")
2360 (save-selected-window
2361 (select-window (posn-window (event-start event)))
2362 (let* ((selection (gdb-memory-format-menu event))
2363 (binding (and selection (lookup-key gdb-memory-format-menu
2364 (vector (car selection))))))
2365 (if binding (call-interactively binding)))))
2366
2367 (defun gdb-memory-unit-giant ()
2368 "Set the unit size to giant words (eight bytes)."
2369 (interactive)
2370 (customize-set-variable 'gdb-memory-unit "g")
2371 (gdb-invalidate-memory))
2372
2373 (defun gdb-memory-unit-word ()
2374 "Set the unit size to words (four bytes)."
2375 (interactive)
2376 (customize-set-variable 'gdb-memory-unit "w")
2377 (gdb-invalidate-memory))
2378
2379 (defun gdb-memory-unit-halfword ()
2380 "Set the unit size to halfwords (two bytes)."
2381 (interactive)
2382 (customize-set-variable 'gdb-memory-unit "h")
2383 (gdb-invalidate-memory))
2384
2385 (defun gdb-memory-unit-byte ()
2386 "Set the unit size to bytes."
2387 (interactive)
2388 (customize-set-variable 'gdb-memory-unit "b")
2389 (gdb-invalidate-memory))
2390
2391 (defvar gdb-memory-unit-map
2392 (let ((map (make-sparse-keymap)))
2393 (define-key map [header-line down-mouse-3] 'gdb-memory-unit-menu-1)
2394 map)
2395 "Keymap to select units in the header line.")
2396
2397 (defvar gdb-memory-unit-menu (make-sparse-keymap "Unit")
2398 "Menu of units in the header line.")
2399
2400 (define-key gdb-memory-unit-menu [giantwords]
2401 '(menu-item "Giant words" gdb-memory-unit-giant
2402 :button (:radio . (equal gdb-memory-unit "g"))))
2403 (define-key gdb-memory-unit-menu [words]
2404 '(menu-item "Words" gdb-memory-unit-word
2405 :button (:radio . (equal gdb-memory-unit "w"))))
2406 (define-key gdb-memory-unit-menu [halfwords]
2407 '(menu-item "Halfwords" gdb-memory-unit-halfword
2408 :button (:radio . (equal gdb-memory-unit "h"))))
2409 (define-key gdb-memory-unit-menu [bytes]
2410 '(menu-item "Bytes" gdb-memory-unit-byte
2411 :button (:radio . (equal gdb-memory-unit "b"))))
2412
2413 (defun gdb-memory-unit-menu (event)
2414 (interactive "@e")
2415 (x-popup-menu event gdb-memory-unit-menu))
2416
2417 (defun gdb-memory-unit-menu-1 (event)
2418 (interactive "e")
2419 (save-selected-window
2420 (select-window (posn-window (event-start event)))
2421 (let* ((selection (gdb-memory-unit-menu event))
2422 (binding (and selection (lookup-key gdb-memory-unit-menu
2423 (vector (car selection))))))
2424 (if binding (call-interactively binding)))))
2425
2426 ;;from make-mode-line-mouse-map
2427 (defun gdb-make-header-line-mouse-map (mouse function) "\
2428 Return a keymap with single entry for mouse key MOUSE on the header line.
2429 MOUSE is defined to run function FUNCTION with no args in the buffer
2430 corresponding to the mode line clicked."
2431 (let ((map (make-sparse-keymap)))
2432 (define-key map (vector 'header-line mouse) function)
2433 (define-key map (vector 'header-line 'down-mouse-1) 'ignore)
2434 map))
2435
2436 (defvar gdb-memory-font-lock-keywords
2437 '(;; <__function.name+n>
2438 ("<\\(\\(\\sw\\|[_.]\\)+\\)\\(\\+[0-9]+\\)?>" (1 font-lock-function-name-face))
2439 )
2440 "Font lock keywords used in `gdb-memory-mode'.")
2441
2442 (defun gdb-memory-mode ()
2443 "Major mode for examining memory.
2444
2445 \\{gdb-memory-mode-map}"
2446 (kill-all-local-variables)
2447 (setq major-mode 'gdb-memory-mode)
2448 (setq mode-name "Memory")
2449 (setq buffer-read-only t)
2450 (use-local-map gdb-memory-mode-map)
2451 (setq header-line-format
2452 '(:eval
2453 (concat
2454 "Read address["
2455 (propertize
2456 "-"
2457 'face font-lock-warning-face
2458 'help-echo "mouse-1: Decrement address"
2459 'mouse-face 'mode-line-highlight
2460 'local-map
2461 (gdb-make-header-line-mouse-map
2462 'mouse-1
2463 #'(lambda () (interactive)
2464 (let ((gdb-memory-address
2465 ;; Let GDB do the arithmetic.
2466 (concat
2467 gdb-memory-address " - "
2468 (number-to-string
2469 (* gdb-memory-repeat-count
2470 (cond ((string= gdb-memory-unit "b") 1)
2471 ((string= gdb-memory-unit "h") 2)
2472 ((string= gdb-memory-unit "w") 4)
2473 ((string= gdb-memory-unit "g") 8)))))))
2474 (gdb-invalidate-memory)))))
2475 "|"
2476 (propertize "+"
2477 'face font-lock-warning-face
2478 'help-echo "mouse-1: Increment address"
2479 'mouse-face 'mode-line-highlight
2480 'local-map (gdb-make-header-line-mouse-map
2481 'mouse-1
2482 #'(lambda () (interactive)
2483 (let ((gdb-memory-address nil))
2484 (gdb-invalidate-memory)))))
2485 "]: "
2486 (propertize gdb-memory-address
2487 'face font-lock-warning-face
2488 'help-echo "mouse-1: Set memory address"
2489 'mouse-face 'mode-line-highlight
2490 'local-map (gdb-make-header-line-mouse-map
2491 'mouse-1
2492 #'gdb-memory-set-address))
2493 " Repeat Count: "
2494 (propertize (number-to-string gdb-memory-repeat-count)
2495 'face font-lock-warning-face
2496 'help-echo "mouse-1: Set repeat count"
2497 'mouse-face 'mode-line-highlight
2498 'local-map (gdb-make-header-line-mouse-map
2499 'mouse-1
2500 #'gdb-memory-set-repeat-count))
2501 " Display Format: "
2502 (propertize gdb-memory-format
2503 'face font-lock-warning-face
2504 'help-echo "mouse-3: Select display format"
2505 'mouse-face 'mode-line-highlight
2506 'local-map gdb-memory-format-map)
2507 " Unit Size: "
2508 (propertize gdb-memory-unit
2509 'face font-lock-warning-face
2510 'help-echo "mouse-3: Select unit size"
2511 'mouse-face 'mode-line-highlight
2512 'local-map gdb-memory-unit-map))))
2513 (set (make-local-variable 'font-lock-defaults)
2514 '(gdb-memory-font-lock-keywords))
2515 (run-mode-hooks 'gdb-memory-mode-hook)
2516 'gdb-invalidate-memory)
2517
2518 (defun gdb-memory-buffer-name ()
2519 (with-current-buffer gud-comint-buffer
2520 (concat "*memory of " (gdb-get-target-string) "*")))
2521
2522 (defun gdb-display-memory-buffer ()
2523 "Display memory contents."
2524 (interactive)
2525 (gdb-display-buffer
2526 (gdb-get-buffer-create 'gdb-memory-buffer)))
2527
2528 (defun gdb-frame-memory-buffer ()
2529 "Display memory contents in a new frame."
2530 (interactive)
2531 (let ((special-display-regexps (append special-display-regexps '(".*")))
2532 (special-display-frame-alist gdb-frame-parameters))
2533 (display-buffer (gdb-get-buffer-create 'gdb-memory-buffer))))
2534 \f
2535
2536 ;; Locals buffer.
2537 ;;
2538 (gdb-set-buffer-rules 'gdb-locals-buffer
2539 'gdb-locals-buffer-name
2540 'gdb-locals-mode)
2541
2542 (def-gdb-auto-update-trigger gdb-invalidate-locals
2543 (gdb-get-buffer 'gdb-locals-buffer)
2544 "server info locals\n"
2545 gdb-info-locals-handler)
2546
2547 (defvar gdb-locals-watch-map
2548 (let ((map (make-sparse-keymap)))
2549 (define-key map "\r" '(lambda () (interactive)
2550 (beginning-of-line)
2551 (gud-watch)))
2552 (define-key map [mouse-2] '(lambda (event) (interactive "e")
2553 (mouse-set-point event)
2554 (beginning-of-line)
2555 (gud-watch)))
2556 map)
2557 "Keymap to create watch expression of a complex data type local variable.")
2558
2559 (defconst gdb-struct-string
2560 (concat (propertize "[struct/union]"
2561 'mouse-face 'highlight
2562 'help-echo "mouse-2: create watch expression"
2563 'local-map gdb-locals-watch-map) "\n"))
2564
2565 (defconst gdb-array-string
2566 (concat " " (propertize "[array]"
2567 'mouse-face 'highlight
2568 'help-echo "mouse-2: create watch expression"
2569 'local-map gdb-locals-watch-map) "\n"))
2570
2571 ;; Abbreviate for arrays and structures.
2572 ;; These can be expanded using gud-display.
2573 (defun gdb-info-locals-handler ()
2574 (setq gdb-pending-triggers (delq 'gdb-invalidate-locals
2575 gdb-pending-triggers))
2576 (let ((buf (gdb-get-buffer 'gdb-partial-output-buffer)))
2577 (with-current-buffer buf
2578 (goto-char (point-min))
2579 (while (re-search-forward "^[ }].*\n" nil t)
2580 (replace-match "" nil nil))
2581 (goto-char (point-min))
2582 (while (re-search-forward "{\\(.*=.*\n\\|\n\\)" nil t)
2583 (replace-match gdb-struct-string nil nil))
2584 (goto-char (point-min))
2585 (while (re-search-forward "\\s-*{.*\n" nil t)
2586 (replace-match gdb-array-string nil nil))))
2587 (let ((buf (gdb-get-buffer 'gdb-locals-buffer)))
2588 (and buf
2589 (with-current-buffer buf
2590 (let* ((window (get-buffer-window buf 0))
2591 (start (window-start window))
2592 (p (window-point window))
2593 (buffer-read-only nil))
2594 (erase-buffer)
2595 (insert-buffer-substring (gdb-get-buffer-create
2596 'gdb-partial-output-buffer))
2597 (set-window-start window start)
2598 (set-window-point window p))
2599 )))
2600 (run-hooks 'gdb-info-locals-hook))
2601
2602 (defvar gdb-locals-mode-map
2603 (let ((map (make-sparse-keymap)))
2604 (suppress-keymap map)
2605 (define-key map "q" 'kill-this-buffer)
2606 map))
2607
2608 (defun gdb-locals-mode ()
2609 "Major mode for gdb locals.
2610
2611 \\{gdb-locals-mode-map}"
2612 (kill-all-local-variables)
2613 (setq major-mode 'gdb-locals-mode)
2614 (setq mode-name (concat "Locals:" gdb-selected-frame))
2615 (setq buffer-read-only t)
2616 (use-local-map gdb-locals-mode-map)
2617 (set (make-local-variable 'font-lock-defaults)
2618 '(gdb-locals-font-lock-keywords))
2619 (run-mode-hooks 'gdb-locals-mode-hook)
2620 (if (and (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
2621 (string-equal gdb-version "pre-6.4"))
2622 'gdb-invalidate-locals
2623 'gdb-invalidate-locals-1))
2624
2625 (defun gdb-locals-buffer-name ()
2626 (with-current-buffer gud-comint-buffer
2627 (concat "*locals of " (gdb-get-target-string) "*")))
2628
2629 (defun gdb-display-locals-buffer ()
2630 "Display local variables of current stack and their values."
2631 (interactive)
2632 (gdb-display-buffer
2633 (gdb-get-buffer-create 'gdb-locals-buffer)))
2634
2635 (defun gdb-frame-locals-buffer ()
2636 "Display local variables of current stack and their values in a new frame."
2637 (interactive)
2638 (let ((special-display-regexps (append special-display-regexps '(".*")))
2639 (special-display-frame-alist gdb-frame-parameters))
2640 (display-buffer (gdb-get-buffer-create 'gdb-locals-buffer))))
2641 \f
2642
2643 ;;;; Window management
2644 (defun gdb-display-buffer (buf &optional size)
2645 (let ((answer (get-buffer-window buf 0))
2646 (must-split nil))
2647 (if answer
2648 (display-buffer buf nil 0) ;Raise the frame if necessary.
2649 ;; The buffer is not yet displayed.
2650 (pop-to-buffer gud-comint-buffer) ;Select the right frame.
2651 (let ((window (get-lru-window)))
2652 (if (and window
2653 (not (eq window (get-buffer-window gud-comint-buffer))))
2654 (progn
2655 (set-window-buffer window buf)
2656 (setq answer window))
2657 (setq must-split t)))
2658 (if must-split
2659 (let* ((largest (get-largest-window))
2660 (cur-size (window-height largest))
2661 (new-size (and size (< size cur-size) (- cur-size size))))
2662 (setq answer (split-window largest new-size))
2663 (set-window-buffer answer buf)
2664 (set-window-dedicated-p answer t)))
2665 answer)))
2666
2667 \f
2668 ;;; Shared keymap initialization:
2669
2670 (let ((menu (make-sparse-keymap "GDB-Windows")))
2671 (define-key gud-menu-map [displays]
2672 `(menu-item "GDB-Windows" ,menu
2673 :visible (memq gud-minor-mode '(gdbmi gdba))))
2674 (define-key menu [gdb] '("Gdb" . gdb-display-gdb-buffer))
2675 (define-key menu [threads] '("Threads" . gdb-display-threads-buffer))
2676 (define-key menu [inferior]
2677 '(menu-item "Inferior IO" gdb-display-separate-io-buffer
2678 :enable gdb-use-separate-io-buffer))
2679 (define-key menu [memory] '("Memory" . gdb-display-memory-buffer))
2680 (define-key menu [registers] '("Registers" . gdb-display-registers-buffer))
2681 (define-key menu [disassembly]
2682 '("Disassembly" . gdb-display-assembler-buffer))
2683 (define-key menu [breakpoints]
2684 '("Breakpoints" . gdb-display-breakpoints-buffer))
2685 (define-key menu [locals] '("Locals" . gdb-display-locals-buffer))
2686 (define-key menu [frames] '("Stack" . gdb-display-stack-buffer)))
2687
2688 (let ((menu (make-sparse-keymap "GDB-Frames")))
2689 (define-key gud-menu-map [frames]
2690 `(menu-item "GDB-Frames" ,menu
2691 :visible (memq gud-minor-mode '(gdbmi gdba))))
2692 (define-key menu [gdb] '("Gdb" . gdb-frame-gdb-buffer))
2693 (define-key menu [threads] '("Threads" . gdb-frame-threads-buffer))
2694 (define-key menu [memory] '("Memory" . gdb-frame-memory-buffer))
2695 (define-key menu [inferior]
2696 '(menu-item "Inferior IO" gdb-frame-separate-io-buffer
2697 :enable gdb-use-separate-io-buffer))
2698 (define-key menu [registers] '("Registers" . gdb-frame-registers-buffer))
2699 (define-key menu [disassembly] '("Disassembly" . gdb-frame-assembler-buffer))
2700 (define-key menu [breakpoints]
2701 '("Breakpoints" . gdb-frame-breakpoints-buffer))
2702 (define-key menu [locals] '("Locals" . gdb-frame-locals-buffer))
2703 (define-key menu [frames] '("Stack" . gdb-frame-stack-buffer)))
2704
2705 (let ((menu (make-sparse-keymap "GDB-UI/MI")))
2706 (define-key gud-menu-map [ui]
2707 `(menu-item (if (eq gud-minor-mode 'gdba) "GDB-UI" "GDB-MI")
2708 ,menu :visible (memq gud-minor-mode '(gdbmi gdba))))
2709 (define-key menu [gdb-use-separate-io]
2710 '(menu-item "Separate inferior IO" gdb-use-separate-io-buffer
2711 :visible (eq gud-minor-mode 'gdba)
2712 :help "Toggle separate IO for inferior."
2713 :button (:toggle . gdb-use-separate-io-buffer)))
2714 (define-key menu [gdb-many-windows]
2715 '(menu-item "Display Other Windows" gdb-many-windows
2716 :help "Toggle display of locals, stack and breakpoint information"
2717 :button (:toggle . gdb-many-windows)))
2718 (define-key menu [gdb-restore-windows]
2719 '(menu-item "Restore Window Layout" gdb-restore-windows
2720 :help "Restore standard layout for debug session.")))
2721
2722 (defun gdb-frame-gdb-buffer ()
2723 "Display GUD buffer in a new frame."
2724 (interactive)
2725 (let ((special-display-regexps (append special-display-regexps '(".*")))
2726 (special-display-frame-alist gdb-frame-parameters)
2727 (same-window-regexps nil))
2728 (display-buffer gud-comint-buffer)))
2729
2730 (defun gdb-display-gdb-buffer ()
2731 "Display GUD buffer."
2732 (interactive)
2733 (let ((same-window-regexps nil))
2734 (pop-to-buffer gud-comint-buffer)))
2735
2736 (defun gdb-set-window-buffer (name)
2737 (set-window-buffer (selected-window) (get-buffer name))
2738 (set-window-dedicated-p (selected-window) t))
2739
2740 (defun gdb-setup-windows ()
2741 "Layout the window pattern for `gdb-many-windows'."
2742 (gdb-display-locals-buffer)
2743 (gdb-display-stack-buffer)
2744 (delete-other-windows)
2745 (gdb-display-breakpoints-buffer)
2746 (delete-other-windows)
2747 ; Don't dedicate.
2748 (pop-to-buffer gud-comint-buffer)
2749 (split-window nil ( / ( * (window-height) 3) 4))
2750 (split-window nil ( / (window-height) 3))
2751 (split-window-horizontally)
2752 (other-window 1)
2753 (gdb-set-window-buffer (gdb-locals-buffer-name))
2754 (other-window 1)
2755 (switch-to-buffer
2756 (if gud-last-last-frame
2757 (gud-find-file (car gud-last-last-frame))
2758 (if gdb-main-file
2759 (gud-find-file gdb-main-file)
2760 ;; Put buffer list in window if we
2761 ;; can't find a source file.
2762 (list-buffers-noselect))))
2763 (setq gdb-source-window (selected-window))
2764 (when gdb-use-separate-io-buffer
2765 (split-window-horizontally)
2766 (other-window 1)
2767 (gdb-set-window-buffer
2768 (gdb-get-buffer-create 'gdb-inferior-io)))
2769 (other-window 1)
2770 (gdb-set-window-buffer (gdb-stack-buffer-name))
2771 (split-window-horizontally)
2772 (other-window 1)
2773 (gdb-set-window-buffer (gdb-breakpoints-buffer-name))
2774 (other-window 1))
2775
2776 (defun gdb-restore-windows ()
2777 "Restore the basic arrangement of windows used by gdba.
2778 This arrangement depends on the value of `gdb-many-windows'."
2779 (interactive)
2780 (pop-to-buffer gud-comint-buffer) ;Select the right window and frame.
2781 (delete-other-windows)
2782 (if gdb-many-windows
2783 (gdb-setup-windows)
2784 (when (or gud-last-last-frame gdb-show-main)
2785 (split-window)
2786 (other-window 1)
2787 (switch-to-buffer
2788 (if gud-last-last-frame
2789 (gud-find-file (car gud-last-last-frame))
2790 (gud-find-file gdb-main-file)))
2791 (setq gdb-source-window (selected-window))
2792 (other-window 1))))
2793
2794 (defun gdb-reset ()
2795 "Exit a debugging session cleanly.
2796 Kills the gdb buffers, and resets variables and the source buffers."
2797 (dolist (buffer (buffer-list))
2798 (unless (eq buffer gud-comint-buffer)
2799 (with-current-buffer buffer
2800 (if (memq gud-minor-mode '(gdbmi gdba))
2801 (if (string-match "\\`\\*.+\\*\\'" (buffer-name))
2802 (kill-buffer nil)
2803 (gdb-remove-breakpoint-icons (point-min) (point-max) t)
2804 (setq gud-minor-mode nil)
2805 (kill-local-variable 'tool-bar-map)
2806 (kill-local-variable 'gdb-define-alist))))))
2807 (when (markerp gdb-overlay-arrow-position)
2808 (move-marker gdb-overlay-arrow-position nil)
2809 (setq gdb-overlay-arrow-position nil))
2810 (setq overlay-arrow-variable-list
2811 (delq 'gdb-overlay-arrow-position overlay-arrow-variable-list))
2812 (setq fringe-indicator-alist '((overlay-arrow . right-triangle)))
2813 (if (boundp 'speedbar-frame) (speedbar-timer-fn))
2814 (setq gud-running nil)
2815 (setq gdb-active-process nil)
2816 (setq gdb-var-list nil)
2817 (remove-hook 'after-save-hook 'gdb-create-define-alist t))
2818
2819 (defun gdb-source-info ()
2820 "Find the source file where the program starts and displays it with related
2821 buffers."
2822 (goto-char (point-min))
2823 (if (and (search-forward "Located in " nil t)
2824 (looking-at "\\S-+"))
2825 (setq gdb-main-file (match-string 0)))
2826 (goto-char (point-min))
2827 (if (search-forward "Includes preprocessor macro info." nil t)
2828 (setq gdb-macro-info t))
2829 (if gdb-many-windows
2830 (gdb-setup-windows)
2831 (gdb-get-buffer-create 'gdb-breakpoints-buffer)
2832 (if gdb-show-main
2833 (let ((pop-up-windows t))
2834 (display-buffer (gud-find-file gdb-main-file))))))
2835
2836 (defun gdb-get-location (bptno line flag)
2837 "Find the directory containing the relevant source file.
2838 Put in buffer and place breakpoint icon."
2839 (goto-char (point-min))
2840 (catch 'file-not-found
2841 (if (search-forward "Located in " nil t)
2842 (when (looking-at "\\S-+")
2843 (delete (cons bptno "File not found") gdb-location-alist)
2844 (push (cons bptno (match-string 0)) gdb-location-alist))
2845 (gdb-resync)
2846 (unless (assoc bptno gdb-location-alist)
2847 (push (cons bptno "File not found") gdb-location-alist)
2848 (message-box "Cannot find source file for breakpoint location.\n\
2849 Add directory to search path for source files using the GDB command, dir."))
2850 (throw 'file-not-found nil))
2851 (with-current-buffer
2852 (find-file-noselect (match-string 0))
2853 (save-current-buffer
2854 (set (make-local-variable 'gud-minor-mode) 'gdba)
2855 (set (make-local-variable 'tool-bar-map) gud-tool-bar-map))
2856 ;; only want one breakpoint icon at each location
2857 (save-excursion
2858 (goto-line (string-to-number line))
2859 (gdb-put-breakpoint-icon (eq flag ?y) bptno)))))
2860
2861 (add-hook 'find-file-hook 'gdb-find-file-hook)
2862
2863 (defun gdb-find-file-hook ()
2864 "Set up buffer for debugging if file is part of the source code
2865 of the current session."
2866 (if (and (buffer-name gud-comint-buffer)
2867 ;; in case gud or gdb-ui is just loaded
2868 gud-comint-buffer
2869 (memq (buffer-local-value 'gud-minor-mode gud-comint-buffer)
2870 '(gdba gdbmi)))
2871 (if (member buffer-file-name gdb-source-file-list)
2872 (with-current-buffer (find-buffer-visiting buffer-file-name)
2873 (set (make-local-variable 'gud-minor-mode)
2874 (buffer-local-value 'gud-minor-mode gud-comint-buffer))
2875 (set (make-local-variable 'tool-bar-map) gud-tool-bar-map)))))
2876
2877 ;;from put-image
2878 (defun gdb-put-string (putstring pos &optional dprop &rest sprops)
2879 "Put string PUTSTRING in front of POS in the current buffer.
2880 PUTSTRING is displayed by putting an overlay into the current buffer with a
2881 `before-string' string that has a `display' property whose value is
2882 PUTSTRING."
2883 (let ((string (make-string 1 ?x))
2884 (buffer (current-buffer)))
2885 (setq putstring (copy-sequence putstring))
2886 (let ((overlay (make-overlay pos pos buffer))
2887 (prop (or dprop
2888 (list (list 'margin 'left-margin) putstring))))
2889 (put-text-property 0 1 'display prop string)
2890 (if sprops
2891 (add-text-properties 0 1 sprops string))
2892 (overlay-put overlay 'put-break t)
2893 (overlay-put overlay 'before-string string))))
2894
2895 ;;from remove-images
2896 (defun gdb-remove-strings (start end &optional buffer)
2897 "Remove strings between START and END in BUFFER.
2898 Remove only strings that were put in BUFFER with calls to `gdb-put-string'.
2899 BUFFER nil or omitted means use the current buffer."
2900 (unless buffer
2901 (setq buffer (current-buffer)))
2902 (dolist (overlay (overlays-in start end))
2903 (when (overlay-get overlay 'put-break)
2904 (delete-overlay overlay))))
2905
2906 (defun gdb-put-breakpoint-icon (enabled bptno)
2907 (let ((start (- (line-beginning-position) 1))
2908 (end (+ (line-end-position) 1))
2909 (putstring (if enabled "B" "b"))
2910 (source-window (get-buffer-window (current-buffer) 0)))
2911 (add-text-properties
2912 0 1 '(help-echo "mouse-1: clear bkpt, mouse-3: enable/disable bkpt")
2913 putstring)
2914 (if enabled
2915 (add-text-properties
2916 0 1 `(gdb-bptno ,bptno gdb-enabled t) putstring)
2917 (add-text-properties
2918 0 1 `(gdb-bptno ,bptno gdb-enabled nil) putstring))
2919 (gdb-remove-breakpoint-icons start end)
2920 (if (display-images-p)
2921 (if (>= (or left-fringe-width
2922 (if source-window (car (window-fringes source-window)))
2923 gdb-buffer-fringe-width) 8)
2924 (gdb-put-string
2925 nil (1+ start)
2926 `(left-fringe breakpoint
2927 ,(if enabled
2928 'breakpoint-enabled
2929 'breakpoint-disabled))
2930 'gdb-bptno bptno
2931 'gdb-enabled enabled)
2932 (when (< left-margin-width 2)
2933 (save-current-buffer
2934 (setq left-margin-width 2)
2935 (if source-window
2936 (set-window-margins
2937 source-window
2938 left-margin-width right-margin-width))))
2939 (put-image
2940 (if enabled
2941 (or breakpoint-enabled-icon
2942 (setq breakpoint-enabled-icon
2943 (find-image `((:type xpm :data
2944 ,breakpoint-xpm-data
2945 :ascent 100 :pointer hand)
2946 (:type pbm :data
2947 ,breakpoint-enabled-pbm-data
2948 :ascent 100 :pointer hand)))))
2949 (or breakpoint-disabled-icon
2950 (setq breakpoint-disabled-icon
2951 (find-image `((:type xpm :data
2952 ,breakpoint-xpm-data
2953 :conversion disabled
2954 :ascent 100 :pointer hand)
2955 (:type pbm :data
2956 ,breakpoint-disabled-pbm-data
2957 :ascent 100 :pointer hand))))))
2958 (+ start 1)
2959 putstring
2960 'left-margin))
2961 (when (< left-margin-width 2)
2962 (save-current-buffer
2963 (setq left-margin-width 2)
2964 (let ((window (get-buffer-window (current-buffer) 0)))
2965 (if window
2966 (set-window-margins
2967 window left-margin-width right-margin-width)))))
2968 (gdb-put-string
2969 (propertize putstring
2970 'face (if enabled 'breakpoint-enabled 'breakpoint-disabled))
2971 (1+ start)))))
2972
2973 (defun gdb-remove-breakpoint-icons (start end &optional remove-margin)
2974 (gdb-remove-strings start end)
2975 (if (display-images-p)
2976 (remove-images start end))
2977 (when remove-margin
2978 (setq left-margin-width 0)
2979 (let ((window (get-buffer-window (current-buffer) 0)))
2980 (if window
2981 (set-window-margins
2982 window left-margin-width right-margin-width)))))
2983
2984 \f
2985 ;;
2986 ;; Assembler buffer.
2987 ;;
2988 (gdb-set-buffer-rules 'gdb-assembler-buffer
2989 'gdb-assembler-buffer-name
2990 'gdb-assembler-mode)
2991
2992 ;; We can't use def-gdb-auto-update-handler because we don't want to use
2993 ;; window-start but keep the overlay arrow/current line visible.
2994 (defun gdb-assembler-handler ()
2995 (setq gdb-pending-triggers
2996 (delq 'gdb-invalidate-assembler
2997 gdb-pending-triggers))
2998 (let ((buf (gdb-get-buffer 'gdb-assembler-buffer)))
2999 (and buf
3000 (with-current-buffer buf
3001 (let* ((window (get-buffer-window buf 0))
3002 (p (window-point window))
3003 (buffer-read-only nil))
3004 (erase-buffer)
3005 (insert-buffer-substring (gdb-get-buffer-create
3006 'gdb-partial-output-buffer))
3007 (set-window-point window p)))))
3008 ;; put customisation here
3009 (gdb-assembler-custom))
3010
3011 (defun gdb-assembler-custom ()
3012 (let ((buffer (gdb-get-buffer 'gdb-assembler-buffer))
3013 (pos 1) (address) (flag) (bptno))
3014 (with-current-buffer buffer
3015 (save-excursion
3016 (if (not (equal gdb-pc-address "main"))
3017 (progn
3018 (goto-char (point-min))
3019 (if (and gdb-pc-address
3020 (search-forward gdb-pc-address nil t))
3021 (progn
3022 (setq pos (point))
3023 (beginning-of-line)
3024 (setq fringe-indicator-alist
3025 (if (string-equal gdb-frame-number "0")
3026 nil
3027 '((overlay-arrow . hollow-right-triangle))))
3028 (or gdb-overlay-arrow-position
3029 (setq gdb-overlay-arrow-position (make-marker)))
3030 (set-marker gdb-overlay-arrow-position
3031 (point) (current-buffer))))))
3032 ;; remove all breakpoint-icons in assembler buffer before updating.
3033 (gdb-remove-breakpoint-icons (point-min) (point-max))))
3034 (with-current-buffer (gdb-get-buffer 'gdb-breakpoints-buffer)
3035 (goto-char (point-min))
3036 (while (< (point) (- (point-max) 1))
3037 (forward-line 1)
3038 (if (looking-at "[^\t].*?breakpoint")
3039 (progn
3040 (looking-at
3041 "\\([0-9]+\\)\\s-+\\S-+\\s-+\\S-+\\s-+\\(.\\)\\s-+0x0*\\(\\S-+\\)")
3042 (setq bptno (match-string 1))
3043 (setq flag (char-after (match-beginning 2)))
3044 (setq address (match-string 3))
3045 (with-current-buffer buffer
3046 (save-excursion
3047 (goto-char (point-min))
3048 (if (search-forward address nil t)
3049 (gdb-put-breakpoint-icon (eq flag ?y) bptno))))))))
3050 (if (not (equal gdb-pc-address "main"))
3051 (with-current-buffer buffer
3052 (set-window-point (get-buffer-window buffer 0) pos)))))
3053
3054 (defvar gdb-assembler-mode-map
3055 (let ((map (make-sparse-keymap)))
3056 (suppress-keymap map)
3057 (define-key map "q" 'kill-this-buffer)
3058 map))
3059
3060 (defvar gdb-assembler-font-lock-keywords
3061 '(;; <__function.name+n>
3062 ("<\\(\\(\\sw\\|[_.]\\)+\\)\\(\\+[0-9]+\\)?>"
3063 (1 font-lock-function-name-face))
3064 ;; 0xNNNNNNNN <__function.name+n>: opcode
3065 ("^0x[0-9a-f]+ \\(<\\(\\(\\sw\\|[_.]\\)+\\)\\+[0-9]+>\\)?:[ \t]+\\(\\sw+\\)"
3066 (4 font-lock-keyword-face))
3067 ;; %register(at least i386)
3068 ("%\\sw+" . font-lock-variable-name-face)
3069 ("^\\(Dump of assembler code for function\\) \\(.+\\):"
3070 (1 font-lock-comment-face)
3071 (2 font-lock-function-name-face))
3072 ("^\\(End of assembler dump\\.\\)" . font-lock-comment-face))
3073 "Font lock keywords used in `gdb-assembler-mode'.")
3074
3075 (defun gdb-assembler-mode ()
3076 "Major mode for viewing code assembler.
3077
3078 \\{gdb-assembler-mode-map}"
3079 (kill-all-local-variables)
3080 (setq major-mode 'gdb-assembler-mode)
3081 (setq mode-name (concat "Machine:" gdb-selected-frame))
3082 (setq gdb-overlay-arrow-position nil)
3083 (add-to-list 'overlay-arrow-variable-list 'gdb-overlay-arrow-position)
3084 (setq fringes-outside-margins t)
3085 (setq buffer-read-only t)
3086 (use-local-map gdb-assembler-mode-map)
3087 (gdb-invalidate-assembler)
3088 (set (make-local-variable 'font-lock-defaults)
3089 '(gdb-assembler-font-lock-keywords))
3090 (run-mode-hooks 'gdb-assembler-mode-hook)
3091 'gdb-invalidate-assembler)
3092
3093 (defun gdb-assembler-buffer-name ()
3094 (with-current-buffer gud-comint-buffer
3095 (concat "*disassembly of " (gdb-get-target-string) "*")))
3096
3097 (defun gdb-display-assembler-buffer ()
3098 "Display disassembly view."
3099 (interactive)
3100 (setq gdb-previous-frame nil)
3101 (gdb-display-buffer
3102 (gdb-get-buffer-create 'gdb-assembler-buffer)))
3103
3104 (defun gdb-frame-assembler-buffer ()
3105 "Display disassembly view in a new frame."
3106 (interactive)
3107 (setq gdb-previous-frame nil)
3108 (let ((special-display-regexps (append special-display-regexps '(".*")))
3109 (special-display-frame-alist gdb-frame-parameters))
3110 (display-buffer (gdb-get-buffer-create 'gdb-assembler-buffer))))
3111
3112 ;; modified because if gdb-pc-address has changed value a new command
3113 ;; must be enqueued to update the buffer with the new output
3114 (defun gdb-invalidate-assembler (&optional ignored)
3115 (if (gdb-get-buffer 'gdb-assembler-buffer)
3116 (progn
3117 (unless (and gdb-selected-frame
3118 (string-equal gdb-selected-frame gdb-previous-frame))
3119 (if (or (not (member 'gdb-invalidate-assembler
3120 gdb-pending-triggers))
3121 (not (string-equal gdb-pc-address
3122 gdb-previous-frame-address)))
3123 (progn
3124 ;; take previous disassemble command, if any, off the queue
3125 (with-current-buffer gud-comint-buffer
3126 (let ((queue gdb-input-queue))
3127 (dolist (item queue)
3128 (if (equal (cdr item) '(gdb-assembler-handler))
3129 (setq gdb-input-queue
3130 (delete item gdb-input-queue))))))
3131 (gdb-enqueue-input
3132 (list
3133 (concat gdb-server-prefix "disassemble "
3134 (if (member gdb-pc-address '(nil "main")) nil "0x")
3135 gdb-pc-address "\n")
3136 'gdb-assembler-handler))
3137 (push 'gdb-invalidate-assembler gdb-pending-triggers)
3138 (setq gdb-previous-frame-address gdb-pc-address)
3139 (setq gdb-previous-frame gdb-selected-frame)))))))
3140
3141 (defun gdb-get-selected-frame ()
3142 (if (not (member 'gdb-get-selected-frame gdb-pending-triggers))
3143 (progn
3144 (gdb-enqueue-input
3145 (list (concat gdb-server-prefix "info frame\n") 'gdb-frame-handler))
3146 (push 'gdb-get-selected-frame
3147 gdb-pending-triggers))))
3148
3149 (defun gdb-frame-handler ()
3150 (setq gdb-pending-triggers
3151 (delq 'gdb-get-selected-frame gdb-pending-triggers))
3152 (goto-char (point-min))
3153 (when (re-search-forward
3154 "Stack level \\([0-9]+\\), frame at \\(0x[[:xdigit:]]+\\)" nil t)
3155 (setq gdb-frame-number (match-string 1))
3156 (setq gdb-frame-address (match-string 2)))
3157 (goto-char (point-min))
3158 (when (re-search-forward ".*=\\s-+0x0*\\(\\S-*\\)\\s-+in\\s-+\\(\\S-+?\\)\
3159 \\(?: (\\(\\S-+?\\):[0-9]+?)\\)*;? "
3160 nil t)
3161 (setq gdb-selected-frame (match-string 2))
3162 (if (gdb-get-buffer 'gdb-locals-buffer)
3163 (with-current-buffer (gdb-get-buffer 'gdb-locals-buffer)
3164 (setq mode-name (concat "Locals:" gdb-selected-frame))))
3165 (if (gdb-get-buffer 'gdb-assembler-buffer)
3166 (with-current-buffer (gdb-get-buffer 'gdb-assembler-buffer)
3167 (setq mode-name (concat "Machine:" gdb-selected-frame))))
3168 (setq gdb-pc-address (match-string 1))
3169 (if (and (match-string 3) gud-overlay-arrow-position)
3170 (let ((buffer (marker-buffer gud-overlay-arrow-position))
3171 (position (marker-position gud-overlay-arrow-position)))
3172 (when (and buffer
3173 (string-equal (buffer-name buffer)
3174 (file-name-nondirectory (match-string 3))))
3175 (with-current-buffer buffer
3176 (setq fringe-indicator-alist
3177 (if (string-equal gdb-frame-number "0")
3178 nil
3179 '((overlay-arrow . hollow-right-triangle))))
3180 (set-marker gud-overlay-arrow-position position))))))
3181 (goto-char (point-min))
3182 (if (re-search-forward " source language \\(\\S-+\\)\." nil t)
3183 (setq gdb-current-language (match-string 1)))
3184 (gdb-invalidate-assembler))
3185
3186 \f
3187 ;; Code specific to GDB 6.4
3188 (defconst gdb-source-file-regexp-1 "fullname=\"\\(.*?\\)\"")
3189
3190 (defun gdb-set-gud-minor-mode-existing-buffers-1 ()
3191 "Create list of source files for current GDB session.
3192 If buffers already exist for any of these files, gud-minor-mode
3193 is set in them."
3194 (goto-char (point-min))
3195 (while (re-search-forward gdb-source-file-regexp-1 nil t)
3196 (push (match-string 1) gdb-source-file-list))
3197 (dolist (buffer (buffer-list))
3198 (with-current-buffer buffer
3199 (when (member buffer-file-name gdb-source-file-list)
3200 (set (make-local-variable 'gud-minor-mode)
3201 (buffer-local-value 'gud-minor-mode gud-comint-buffer))
3202 (set (make-local-variable 'tool-bar-map) gud-tool-bar-map)
3203 (when gud-tooltip-mode
3204 (make-local-variable 'gdb-define-alist)
3205 (gdb-create-define-alist)
3206 (add-hook 'after-save-hook 'gdb-create-define-alist nil t))))))
3207
3208 ; Uses "-var-list-children --all-values". Needs GDB 6.1 onwards.
3209 (defun gdb-var-list-children-1 (varnum)
3210 (gdb-enqueue-input
3211 (list
3212 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
3213 (concat "server interpreter mi \"-var-list-children --all-values "
3214 varnum "\"\n")
3215 (concat "-var-list-children --all-values " varnum "\n"))
3216 `(lambda () (gdb-var-list-children-handler-1 ,varnum)))))
3217
3218 (defconst gdb-var-list-children-regexp-1
3219 "child={.*?name=\"\\(.+?\\)\",.*?exp=\"\\(.+?\\)\",.*?\
3220 numchild=\"\\(.+?\\)\",.*?value=\\(\".*?\"\\),.*?type=\"\\(.+?\\)\".*?}")
3221
3222 (defun gdb-var-list-children-handler-1 (varnum)
3223 (goto-char (point-min))
3224 (let ((var-list nil))
3225 (catch 'child-already-watched
3226 (dolist (var gdb-var-list)
3227 (if (string-equal varnum (car var))
3228 (progn
3229 (push var var-list)
3230 (while (re-search-forward gdb-var-list-children-regexp-1 nil t)
3231 (let ((varchild (list (match-string 1)
3232 (match-string 2)
3233 (match-string 3)
3234 (match-string 5)
3235 (read (match-string 4))
3236 nil)))
3237 (if (assoc (car varchild) gdb-var-list)
3238 (throw 'child-already-watched nil))
3239 (push varchild var-list))))
3240 (push var var-list)))
3241 (setq gdb-var-list (nreverse var-list))))
3242 (gdb-speedbar-update))
3243
3244 ; Uses "-var-update --all-values". Needs GDB 6.4 onwards.
3245 (defun gdb-var-update-1 ()
3246 (if (not (member 'gdb-var-update gdb-pending-triggers))
3247 (progn
3248 (gdb-enqueue-input
3249 (list
3250 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
3251 "server interpreter mi \"-var-update --all-values *\"\n"
3252 "-var-update --all-values *\n")
3253 'gdb-var-update-handler-1))
3254 (push 'gdb-var-update gdb-pending-triggers))))
3255
3256 (defconst gdb-var-update-regexp-1
3257 "{.*?name=\"\\(.*?\\)\",.*?\\(?:value=\\(\".*?\"\\),\\)?.*?\
3258 in_scope=\"\\(.*?\\)\".*?}")
3259
3260 (defun gdb-var-update-handler-1 ()
3261 (dolist (var gdb-var-list)
3262 (setcar (nthcdr 5 var) nil))
3263 (goto-char (point-min))
3264 (while (re-search-forward gdb-var-update-regexp-1 nil t)
3265 (let* ((varnum (match-string 1))
3266 (var (assoc varnum gdb-var-list)))
3267 (when var
3268 (if (string-equal (match-string 3) "false")
3269 (setcar (nthcdr 5 var) 'out-of-scope)
3270 (setcar (nthcdr 5 var) 'changed)
3271 (setcar (nthcdr 4 var)
3272 (read (match-string 2)))))))
3273 (setq gdb-pending-triggers
3274 (delq 'gdb-var-update gdb-pending-triggers))
3275 (gdb-speedbar-update))
3276
3277 ;; Registers buffer.
3278 ;;
3279 (gdb-set-buffer-rules 'gdb-registers-buffer
3280 'gdb-registers-buffer-name
3281 'gdb-registers-mode)
3282
3283 (def-gdb-auto-update-trigger gdb-invalidate-registers-1
3284 (gdb-get-buffer 'gdb-registers-buffer)
3285 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
3286 "server interpreter mi \"-data-list-register-values x\"\n"
3287 "-data-list-register-values x\n")
3288 gdb-data-list-register-values-handler)
3289
3290 (defconst gdb-data-list-register-values-regexp
3291 "{.*?number=\"\\(.*?\\)\",.*?value=\"\\(.*?\\)\".*?}")
3292
3293 (defun gdb-data-list-register-values-handler ()
3294 (setq gdb-pending-triggers (delq 'gdb-invalidate-registers-1
3295 gdb-pending-triggers))
3296 (goto-char (point-min))
3297 (if (re-search-forward gdb-error-regexp nil t)
3298 (let ((err (match-string 1)))
3299 (with-current-buffer (gdb-get-buffer 'gdb-registers-buffer)
3300 (let ((buffer-read-only nil))
3301 (erase-buffer)
3302 (put-text-property 0 (length err) 'face font-lock-warning-face err)
3303 (insert err)
3304 (goto-char (point-min)))))
3305 (let ((register-list (reverse gdb-register-names))
3306 (register nil) (register-string nil) (register-values nil))
3307 (goto-char (point-min))
3308 (while (re-search-forward gdb-data-list-register-values-regexp nil t)
3309 (setq register (pop register-list))
3310 (setq register-string (concat register "\t" (match-string 2) "\n"))
3311 (if (member (match-string 1) gdb-changed-registers)
3312 (put-text-property 0 (length register-string)
3313 'face 'font-lock-warning-face
3314 register-string))
3315 (setq register-values
3316 (concat register-values register-string)))
3317 (let ((buf (gdb-get-buffer 'gdb-registers-buffer)))
3318 (with-current-buffer buf
3319 (let* ((window (get-buffer-window buf 0))
3320 (start (window-start window))
3321 (p (window-point window))
3322 (buffer-read-only nil))
3323 (erase-buffer)
3324 (insert register-values)
3325 (set-window-start window start)
3326 (set-window-point window p))))))
3327 (gdb-data-list-register-values-custom))
3328
3329 (defun gdb-data-list-register-values-custom ()
3330 (with-current-buffer (gdb-get-buffer 'gdb-registers-buffer)
3331 (save-excursion
3332 (let ((buffer-read-only nil)
3333 start end)
3334 (goto-char (point-min))
3335 (while (< (point) (point-max))
3336 (setq start (line-beginning-position))
3337 (setq end (line-end-position))
3338 (when (looking-at "^[^\t]+")
3339 (unless (string-equal (match-string 0) "No registers.")
3340 (put-text-property start (match-end 0)
3341 'face font-lock-variable-name-face)
3342 (add-text-properties start end
3343 '(help-echo "mouse-2: edit value"
3344 mouse-face highlight))))
3345 (forward-line 1))))))
3346
3347 ;; Needs GDB 6.4 onwards (used to fail with no stack).
3348 (defun gdb-get-changed-registers ()
3349 (if (and (gdb-get-buffer 'gdb-registers-buffer)
3350 (not (member 'gdb-get-changed-registers gdb-pending-triggers)))
3351 (progn
3352 (gdb-enqueue-input
3353 (list
3354 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
3355 "server interpreter mi -data-list-changed-registers\n"
3356 "-data-list-changed-registers\n")
3357 'gdb-get-changed-registers-handler))
3358 (push 'gdb-get-changed-registers gdb-pending-triggers))))
3359
3360 (defconst gdb-data-list-register-names-regexp "\"\\(.*?\\)\"")
3361
3362 (defun gdb-get-changed-registers-handler ()
3363 (setq gdb-pending-triggers
3364 (delq 'gdb-get-changed-registers gdb-pending-triggers))
3365 (setq gdb-changed-registers nil)
3366 (goto-char (point-min))
3367 (while (re-search-forward gdb-data-list-register-names-regexp nil t)
3368 (push (match-string 1) gdb-changed-registers)))
3369 \f
3370
3371 ;; Locals buffer.
3372 ;;
3373 ;; uses "-stack-list-locals --simple-values". Needs GDB 6.1 onwards.
3374 (gdb-set-buffer-rules 'gdb-locals-buffer
3375 'gdb-locals-buffer-name
3376 'gdb-locals-mode)
3377
3378 (def-gdb-auto-update-trigger gdb-invalidate-locals-1
3379 (gdb-get-buffer 'gdb-locals-buffer)
3380 (if (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer) 'gdba)
3381 "server interpreter mi -\"stack-list-locals --simple-values\"\n"
3382 "-stack-list-locals --simple-values\n")
3383 gdb-stack-list-locals-handler)
3384
3385 (defconst gdb-stack-list-locals-regexp
3386 "{.*?name=\"\\(.*?\\)\",.*?type=\"\\(.*?\\)\"")
3387
3388 (defvar gdb-locals-watch-map-1
3389 (let ((map (make-sparse-keymap)))
3390 (define-key map [mouse-2] 'gud-watch)
3391 map)
3392 "Keymap to create watch expression of a complex data type local variable.")
3393
3394 ;; Dont display values of arrays or structures.
3395 ;; These can be expanded using gud-watch.
3396 (defun gdb-stack-list-locals-handler ()
3397 (setq gdb-pending-triggers (delq 'gdb-invalidate-locals-1
3398 gdb-pending-triggers))
3399 (goto-char (point-min))
3400 (if (re-search-forward gdb-error-regexp nil t)
3401 (let ((err (match-string 1)))
3402 (with-current-buffer (gdb-get-buffer 'gdb-locals-buffer)
3403 (let ((buffer-read-only nil))
3404 (erase-buffer)
3405 (insert err)
3406 (goto-char (point-min)))))
3407 (let (local locals-list)
3408 (goto-char (point-min))
3409 (while (re-search-forward gdb-stack-list-locals-regexp nil t)
3410 (let ((local (list (match-string 1)
3411 (match-string 2)
3412 nil)))
3413 (if (looking-at ",value=\\(\".*\"\\).*?}")
3414 (setcar (nthcdr 2 local) (read (match-string 1))))
3415 (push local locals-list)))
3416 (let ((buf (gdb-get-buffer 'gdb-locals-buffer)))
3417 (and buf (with-current-buffer buf
3418 (let* ((window (get-buffer-window buf 0))
3419 (start (window-start window))
3420 (p (window-point window))
3421 (buffer-read-only nil))
3422 (erase-buffer)
3423 (dolist (local locals-list)
3424 (setq name (car local))
3425 (if (or (not (nth 2 local))
3426 (string-match "^\\0x" (nth 2 local)))
3427 (add-text-properties 0 (length name)
3428 `(mouse-face highlight
3429 help-echo "mouse-2: create watch expression"
3430 local-map ,gdb-locals-watch-map-1)
3431 name))
3432 (insert
3433 (concat name "\t" (nth 1 local)
3434 "\t" (nth 2 local) "\n")))
3435 (set-window-start window start)
3436 (set-window-point window p))))))))
3437
3438 (defun gdb-get-register-names ()
3439 "Create a list of register names."
3440 (goto-char (point-min))
3441 (setq gdb-register-names nil)
3442 (while (re-search-forward gdb-data-list-register-names-regexp nil t)
3443 (push (match-string 1) gdb-register-names)))
3444
3445 (provide 'gdb-ui)
3446
3447 ;; arch-tag: e9fb00c5-74ef-469f-a088-37384caae352
3448 ;;; gdb-ui.el ends here