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