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