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