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