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