*** 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")))
0d43db4d 1302 (define-key menu [quit] '("Quit" . kill-this-buffer))
1ffac268 1303 (define-key menu [goto] '("Goto" . gdb-goto-breakpoint))
0d43db4d
NR
1304 (define-key menu [delete] '("Delete" . gdb-delete-breakpoint))
1305 (define-key menu [toggle] '("Toggle" . gdb-toggle-breakpoint))
1ffac268
NR
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)
0d43db4d 1313 (define-key map [follow-link] 'mouse-face)
1ffac268
NR
1314 map))
1315
1316(defun gdb-breakpoints-mode ()
1317 "Major mode for gdb breakpoints.
1318
1319\\{gdb-breakpoints-mode-map}"
fad137cd 1320 (kill-all-local-variables)
1ffac268
NR
1321 (setq major-mode 'gdb-breakpoints-mode)
1322 (setq mode-name "Breakpoints")
1323 (use-local-map gdb-breakpoints-mode-map)
1324 (setq buffer-read-only t)
fad137cd 1325 (run-mode-hooks 'gdb-breakpoints-mode-hook)
9f438d80 1326 (if (with-current-buffer gud-comint-buffer (eq gud-minor-mode 'gdba))
fad137cd
NR
1327 'gdb-invalidate-breakpoints
1328 'gdbmi-invalidate-breakpoints))
1ffac268
NR
1329
1330(defun gdb-toggle-breakpoint ()
b6d0e4da 1331 "Enable/disable breakpoint at current line."
1ffac268
NR
1332 (interactive)
1333 (save-excursion
1334 (beginning-of-line 1)
7731023b
NR
1335 (if (if (with-current-buffer gud-comint-buffer (eq gud-minor-mode 'gdba))
1336 (looking-at "\\([0-9]+\\).*point\\s-*\\S-*\\s-*\\(.\\)")
1337 (looking-at
1338 "\\([0-9]+\\)\\s-*\\S-*\\s-*\\S-*\\s-*\\(.\\)\\s-*\\S-*\\s-*\\S-*:[0-9]+"))
1339 (gdb-enqueue-input
1340 (list
1341 (concat gdb-server-prefix
1342 (if (eq ?y (char-after (match-beginning 2)))
1343 "disable "
1344 "enable ")
1345 (match-string 1) "\n") 'ignore))
1346 (error "Not recognized as break/watchpoint line"))))
1ffac268
NR
1347
1348(defun gdb-delete-breakpoint ()
1349 "Delete the breakpoint at current line."
1350 (interactive)
1351 (beginning-of-line 1)
7731023b
NR
1352 (if (if (with-current-buffer gud-comint-buffer (eq gud-minor-mode 'gdba))
1353 (looking-at "\\([0-9]+\\).*point\\s-*\\S-*\\s-*\\(.\\)")
1354 (looking-at
1355 "\\([0-9]+\\)\\s-*\\S-*\\s-*\\S-*\\s-*.\\s-*\\S-*\\s-*\\S-*:[0-9]+"))
1356 (gdb-enqueue-input
1357 (list
1358 (concat gdb-server-prefix "delete " (match-string 1) "\n") 'ignore))
1359 (error "Not recognized as break/watchpoint line")))
1ffac268 1360
f2fc1724 1361(defun gdb-goto-breakpoint (&optional event)
f6a2315e 1362 "Display the breakpoint location specified at current line."
f2fc1724
NR
1363 (interactive (list last-input-event))
1364 (if event (mouse-set-point event))
1ffac268
NR
1365 (save-excursion
1366 (beginning-of-line 1)
7731023b 1367 (if (if (with-current-buffer gud-comint-buffer (eq gud-minor-mode 'gdba))
94cd554a 1368 (looking-at "\\([0-9]+\\) .* in .* at\\s-+\\(\\S-*\\):\\([0-9]+\\)")
7731023b 1369 (looking-at
94cd554a
NR
1370 "\\([0-9]+\\)\\s-*\\S-*\\s-*\\S-*\\s-*.\\s-*\\S-*\\s-*\\(\\S-*\\):\\([0-9]+\\)"))
1371 (let ((bptno (match-string 1))
1372 (file (match-string 2))
1373 (line (match-string 3)))
7731023b
NR
1374 (save-selected-window
1375 (let* ((buf (find-file-noselect (if (file-exists-p file)
1376 file
94cd554a 1377 (cdr (assoc bptno gdb-location-list)))))
f2dab427 1378 (window (display-buffer buf)))
7731023b
NR
1379 (with-current-buffer buf
1380 (goto-line (string-to-number line))
1381 (set-window-point window (point))))))
1382 (error "Not recognized as break/watchpoint line"))))
1ffac268 1383\f
f2fc1724 1384
1ffac268
NR
1385;; Frames buffer. This displays a perpetually correct bactracktrace
1386;; (from the command `where').
1387;;
1388;; Alas, if your stack is deep, it is costly.
1389;;
1390(gdb-set-buffer-rules 'gdb-stack-buffer
1391 'gdb-stack-buffer-name
1392 'gdb-frames-mode)
1393
1394(def-gdb-auto-updated-buffer gdb-stack-buffer
1395 gdb-invalidate-frames
1396 "server where\n"
1397 gdb-info-frames-handler
1398 gdb-info-frames-custom)
1399
1400(defun gdb-info-frames-custom ()
1401 (with-current-buffer (gdb-get-buffer 'gdb-stack-buffer)
1402 (save-excursion
1403 (let ((buffer-read-only nil))
1404 (goto-char (point-min))
1405 (while (< (point) (point-max))
1406 (add-text-properties (point-at-bol) (point-at-eol)
1407 '(mouse-face highlight
1408 help-echo "mouse-2, RET: Select frame"))
1409 (beginning-of-line)
de1b8112
NR
1410 (when (and (looking-at "^#\\([0-9]+\\)")
1411 (equal (match-string 1) gdb-current-stack-level))
1ffac268
NR
1412 (put-text-property (point-at-bol) (point-at-eol)
1413 'face '(:inverse-video t)))
1414 (forward-line 1))))))
1415
1416(defun gdb-stack-buffer-name ()
1417 (with-current-buffer gud-comint-buffer
1418 (concat "*stack frames of " (gdb-get-target-string) "*")))
1419
1420(defun gdb-display-stack-buffer ()
f6a2315e 1421 "Display backtrace of current stack."
1ffac268
NR
1422 (interactive)
1423 (gdb-display-buffer
1424 (gdb-get-create-buffer 'gdb-stack-buffer)))
1425
1426(defun gdb-frame-stack-buffer ()
f6a2315e 1427 "Display backtrace of current stack in a new frame."
1ffac268 1428 (interactive)
1a9203d0
NR
1429 (let ((special-display-regexps (append special-display-regexps '(".*")))
1430 (special-display-frame-alist gdb-frame-parameters))
1431 (display-buffer (gdb-get-create-buffer 'gdb-stack-buffer))))
1ffac268
NR
1432
1433(defvar gdb-frames-mode-map
1434 (let ((map (make-sparse-keymap)))
1435 (suppress-keymap map)
12032009 1436 (define-key map "q" 'kill-this-buffer)
1ffac268 1437 (define-key map "\r" 'gdb-frames-select)
f2fc1724 1438 (define-key map [mouse-2] 'gdb-frames-select)
0d43db4d 1439 (define-key map [follow-link] 'mouse-face)
1ffac268
NR
1440 map))
1441
1442(defun gdb-frames-mode ()
1443 "Major mode for gdb frames.
1444
1445\\{gdb-frames-mode-map}"
fad137cd 1446 (kill-all-local-variables)
1ffac268
NR
1447 (setq major-mode 'gdb-frames-mode)
1448 (setq mode-name "Frames")
1449 (setq buffer-read-only t)
1450 (use-local-map gdb-frames-mode-map)
1451 (font-lock-mode -1)
fad137cd 1452 (run-mode-hooks 'gdb-frames-mode-hook)
9f438d80 1453 (if (with-current-buffer gud-comint-buffer (eq gud-minor-mode 'gdba))
fad137cd
NR
1454 'gdb-invalidate-frames
1455 'gdbmi-invalidate-frames))
1ffac268
NR
1456
1457(defun gdb-get-frame-number ()
1458 (save-excursion
f2f82fa4 1459 (let* ((pos (re-search-backward "^#*\\([0-9]*\\)" nil t))
1ffac268
NR
1460 (n (or (and pos (match-string-no-properties 1)) "0")))
1461 n)))
1462
f2fc1724 1463(defun gdb-frames-select (&optional event)
f6a2315e 1464 "Select the frame and display the relevant source."
f2fc1724
NR
1465 (interactive (list last-input-event))
1466 (if event (mouse-set-point event))
1ffac268 1467 (gdb-enqueue-input
2cec1d1a 1468 (list (concat gdb-server-prefix "frame " (gdb-get-frame-number) "\n") 'ignore))
1ffac268 1469 (gud-display-frame))
1ffac268 1470\f
f2fc1724 1471
1ffac268
NR
1472;; Threads buffer. This displays a selectable thread list.
1473;;
1474(gdb-set-buffer-rules 'gdb-threads-buffer
1475 'gdb-threads-buffer-name
1476 'gdb-threads-mode)
1477
1478(def-gdb-auto-updated-buffer gdb-threads-buffer
1479 gdb-invalidate-threads
2cec1d1a 1480 (concat gdb-server-prefix "info threads\n")
1ffac268
NR
1481 gdb-info-threads-handler
1482 gdb-info-threads-custom)
1483
1484(defun gdb-info-threads-custom ()
1485 (with-current-buffer (gdb-get-buffer 'gdb-threads-buffer)
1486 (let ((buffer-read-only nil))
1487 (goto-char (point-min))
1488 (while (< (point) (point-max))
1489 (add-text-properties (point-at-bol) (point-at-eol)
1490 '(mouse-face highlight
1491 help-echo "mouse-2, RET: select thread"))
1492 (forward-line 1)))))
1493
1494(defun gdb-threads-buffer-name ()
1495 (with-current-buffer gud-comint-buffer
1496 (concat "*threads of " (gdb-get-target-string) "*")))
1497
1498(defun gdb-display-threads-buffer ()
f6a2315e 1499 "Display IDs of currently known threads."
1ffac268
NR
1500 (interactive)
1501 (gdb-display-buffer
1502 (gdb-get-create-buffer 'gdb-threads-buffer)))
1503
1504(defun gdb-frame-threads-buffer ()
f6a2315e 1505 "Display IDs of currently known threads in a new frame."
1ffac268 1506 (interactive)
1a9203d0
NR
1507 (let ((special-display-regexps (append special-display-regexps '(".*")))
1508 (special-display-frame-alist gdb-frame-parameters))
1509 (display-buffer (gdb-get-create-buffer 'gdb-threads-buffer))))
1ffac268
NR
1510
1511(defvar gdb-threads-mode-map
1512 (let ((map (make-sparse-keymap)))
1513 (suppress-keymap map)
12032009 1514 (define-key map "q" 'kill-this-buffer)
1ffac268 1515 (define-key map "\r" 'gdb-threads-select)
f2fc1724 1516 (define-key map [mouse-2] 'gdb-threads-select)
1ffac268
NR
1517 map))
1518
1519(defun gdb-threads-mode ()
1520 "Major mode for gdb frames.
1521
2cec1d1a 1522\\{gdb-threads-mode-map}"
fad137cd 1523 (kill-all-local-variables)
1ffac268
NR
1524 (setq major-mode 'gdb-threads-mode)
1525 (setq mode-name "Threads")
1526 (setq buffer-read-only t)
1527 (use-local-map gdb-threads-mode-map)
fad137cd
NR
1528 (run-mode-hooks 'gdb-threads-mode-hook)
1529 'gdb-invalidate-threads)
1ffac268
NR
1530
1531(defun gdb-get-thread-number ()
1532 (save-excursion
1533 (re-search-backward "^\\s-*\\([0-9]*\\)" nil t)
1534 (match-string-no-properties 1)))
1535
f2fc1724 1536(defun gdb-threads-select (&optional event)
f6a2315e 1537 "Select the thread and display the relevant source."
f2fc1724
NR
1538 (interactive (list last-input-event))
1539 (if event (mouse-set-point event))
1ffac268
NR
1540 (gdb-enqueue-input
1541 (list (concat "thread " (gdb-get-thread-number) "\n") 'ignore))
1542 (gud-display-frame))
1ffac268 1543\f
f2fc1724 1544
1ffac268
NR
1545;; Registers buffer.
1546;;
1547(gdb-set-buffer-rules 'gdb-registers-buffer
1548 'gdb-registers-buffer-name
1549 'gdb-registers-mode)
1550
1551(def-gdb-auto-updated-buffer gdb-registers-buffer
1552 gdb-invalidate-registers
2cec1d1a 1553 (concat gdb-server-prefix "info registers\n")
1ffac268
NR
1554 gdb-info-registers-handler
1555 gdb-info-registers-custom)
1556
1557(defun gdb-info-registers-custom ())
1558
1559(defvar gdb-registers-mode-map
1560 (let ((map (make-sparse-keymap)))
1561 (suppress-keymap map)
12032009
NR
1562 (define-key map "q" 'kill-this-buffer)
1563 map))
1ffac268
NR
1564
1565(defun gdb-registers-mode ()
1566 "Major mode for gdb registers.
1567
1568\\{gdb-registers-mode-map}"
fad137cd 1569 (kill-all-local-variables)
1ffac268
NR
1570 (setq major-mode 'gdb-registers-mode)
1571 (setq mode-name "Registers")
1572 (setq buffer-read-only t)
1573 (use-local-map gdb-registers-mode-map)
fad137cd
NR
1574 (run-mode-hooks 'gdb-registers-mode-hook)
1575 'gdb-invalidate-registers)
1ffac268
NR
1576
1577(defun gdb-registers-buffer-name ()
1578 (with-current-buffer gud-comint-buffer
1579 (concat "*registers of " (gdb-get-target-string) "*")))
1580
1581(defun gdb-display-registers-buffer ()
f6a2315e 1582 "Display integer register contents."
1ffac268
NR
1583 (interactive)
1584 (gdb-display-buffer
1585 (gdb-get-create-buffer 'gdb-registers-buffer)))
1586
1587(defun gdb-frame-registers-buffer ()
f6a2315e 1588 "Display integer register contents in a new frame."
1ffac268 1589 (interactive)
1a9203d0
NR
1590 (let ((special-display-regexps (append special-display-regexps '(".*")))
1591 (special-display-frame-alist gdb-frame-parameters))
1592 (display-buffer (gdb-get-create-buffer 'gdb-registers-buffer))))
37ebd64b
NR
1593
1594;; Memory buffer.
1ffac268 1595;;
37ebd64b
NR
1596(defcustom gdb-memory-repeat-count 32
1597 "Number of data items in memory window."
1598 :type 'integer
1599 :group 'gud
bf247b6e 1600 :version "22.1")
37ebd64b
NR
1601
1602(defcustom gdb-memory-format "x"
1603 "Display format of data items in memory window."
1604 :type '(choice (const :tag "Hexadecimal" "x")
1605 (const :tag "Signed decimal" "d")
1606 (const :tag "Unsigned decimal" "u")
1607 (const :tag "Octal" "o")
1608 (const :tag "Binary" "t"))
1609 :group 'gud
bf247b6e 1610 :version "22.1")
37ebd64b
NR
1611
1612(defcustom gdb-memory-unit "w"
1613 "Unit size of data items in memory window."
1614 :type '(choice (const :tag "Byte" "b")
1615 (const :tag "Halfword" "h")
1616 (const :tag "Word" "w")
1617 (const :tag "Giant word" "g"))
1618 :group 'gud
bf247b6e 1619 :version "22.1")
37ebd64b
NR
1620
1621(gdb-set-buffer-rules 'gdb-memory-buffer
1622 'gdb-memory-buffer-name
1623 'gdb-memory-mode)
1624
1625(def-gdb-auto-updated-buffer gdb-memory-buffer
1626 gdb-invalidate-memory
1627 (concat gdb-server-prefix "x/" (number-to-string gdb-memory-repeat-count)
1628 gdb-memory-format gdb-memory-unit " " gdb-memory-address "\n")
1629 gdb-read-memory-handler
1630 gdb-read-memory-custom)
1631
1632(defun gdb-read-memory-custom ())
1633
1634(defvar gdb-memory-mode-map
1635 (let ((map (make-sparse-keymap)))
1636 (suppress-keymap map)
1637 (define-key map "q" 'kill-this-buffer)
1638 map))
1639
1640(defun gdb-memory-set-address (event)
1641 "Set the start memory address."
1642 (interactive "e")
1643 (save-selected-window
1644 (select-window (posn-window (event-start event)))
1645 (let ((arg (read-from-minibuffer "Memory address: ")))
1646 (setq gdb-memory-address arg))
1647 (gdb-invalidate-memory)))
1648
1649(defun gdb-memory-set-repeat-count (event)
1650 "Set the number of data items in memory window."
1651 (interactive "e")
1652 (save-selected-window
1653 (select-window (posn-window (event-start event)))
1654 (let* ((arg (read-from-minibuffer "Repeat count: "))
1655 (count (string-to-int arg)))
1656 (if (< count 0)
1657 (error "Non-negative numbers only")
1658 (customize-set-variable 'gdb-memory-repeat-count count)
1659 (gdb-invalidate-memory)))))
1660
1661(defun gdb-memory-format-binary ()
1662 "Set the display format to binary."
1663 (interactive)
1664 (customize-set-variable 'gdb-memory-format "t")
1665 (gdb-invalidate-memory))
1666
1667(defun gdb-memory-format-octal ()
1668 "Set the display format to octal."
1669 (interactive)
1670 (customize-set-variable 'gdb-memory-format "o")
1671 (gdb-invalidate-memory))
1672
1673(defun gdb-memory-format-unsigned ()
1674 "Set the display format to unsigned decimal."
1675 (interactive)
1676 (customize-set-variable 'gdb-memory-format "u")
1677 (gdb-invalidate-memory))
1678
1679(defun gdb-memory-format-signed ()
1680 "Set the display format to decimal."
1681 (interactive)
1682 (customize-set-variable 'gdb-memory-format "d")
1683 (gdb-invalidate-memory))
1684
1685(defun gdb-memory-format-hexadecimal ()
1686 "Set the display format to hexadecimal."
1687 (interactive)
1688 (customize-set-variable 'gdb-memory-format "x")
1689 (gdb-invalidate-memory))
1690
1691(defvar gdb-memory-format-keymap
1692 (let ((map (make-sparse-keymap)))
1693 (define-key map [header-line down-mouse-3] 'gdb-memory-format-menu-1)
1694 map)
1695 "Keymap to select format in the header line.")
1696
1697(defvar gdb-memory-format-menu (make-sparse-keymap "Format")
1698 "Menu of display formats in the header line.")
1699
1700(define-key gdb-memory-format-menu [binary]
1701 '(menu-item "Binary" gdb-memory-format-binary
1702 :button (:radio . (equal gdb-memory-format "t"))))
1703(define-key gdb-memory-format-menu [octal]
1704 '(menu-item "Octal" gdb-memory-format-octal
1705 :button (:radio . (equal gdb-memory-format "o"))))
1706(define-key gdb-memory-format-menu [unsigned]
1707 '(menu-item "Unsigned Decimal" gdb-memory-format-unsigned
1708 :button (:radio . (equal gdb-memory-format "u"))))
1709(define-key gdb-memory-format-menu [signed]
1710 '(menu-item "Signed Decimal" gdb-memory-format-signed
1711 :button (:radio . (equal gdb-memory-format "d"))))
1712(define-key gdb-memory-format-menu [hexadecimal]
1713 '(menu-item "Hexadecimal" gdb-memory-format-hexadecimal
1714 :button (:radio . (equal gdb-memory-format "x"))))
1715
1716(defun gdb-memory-format-menu (event)
1717 (interactive "@e")
1718 (x-popup-menu event gdb-memory-format-menu))
1719
1720(defun gdb-memory-format-menu-1 (event)
1721 (interactive "e")
1722 (save-selected-window
1723 (select-window (posn-window (event-start event)))
1724 (let* ((selection (gdb-memory-format-menu event))
1725 (binding (and selection (lookup-key gdb-memory-format-menu
1726 (vector (car selection))))))
1727 (if binding (call-interactively binding)))))
1728
1729(defun gdb-memory-unit-giant ()
1730 "Set the unit size to giant words (eight bytes)."
1731 (interactive)
1732 (customize-set-variable 'gdb-memory-unit "g")
1733 (gdb-invalidate-memory))
1734
1735(defun gdb-memory-unit-word ()
1736 "Set the unit size to words (four bytes)."
1737 (interactive)
1738 (customize-set-variable 'gdb-memory-unit "w")
1739 (gdb-invalidate-memory))
1740
1741(defun gdb-memory-unit-halfword ()
1742 "Set the unit size to halfwords (two bytes)."
1743 (interactive)
1744 (customize-set-variable 'gdb-memory-unit "h")
1745 (gdb-invalidate-memory))
1746
1747(defun gdb-memory-unit-byte ()
1748 "Set the unit size to bytes."
1749 (interactive)
1750 (customize-set-variable 'gdb-memory-unit "b")
1751 (gdb-invalidate-memory))
1752
1753(defvar gdb-memory-unit-keymap
1754 (let ((map (make-sparse-keymap)))
1755 (define-key map [header-line down-mouse-3] 'gdb-memory-unit-menu-1)
1756 map)
1757 "Keymap to select units in the header line.")
1758
1759(defvar gdb-memory-unit-menu (make-sparse-keymap "Unit")
1760 "Menu of units in the header line.")
1761
1762(define-key gdb-memory-unit-menu [giantwords]
1763 '(menu-item "Giant words" gdb-memory-unit-giant
1764 :button (:radio . (equal gdb-memory-unit "g"))))
1765(define-key gdb-memory-unit-menu [words]
1766 '(menu-item "Words" gdb-memory-unit-word
1767 :button (:radio . (equal gdb-memory-unit "w"))))
1768(define-key gdb-memory-unit-menu [halfwords]
1769 '(menu-item "Halfwords" gdb-memory-unit-halfword
1770 :button (:radio . (equal gdb-memory-unit "h"))))
1771(define-key gdb-memory-unit-menu [bytes]
1772 '(menu-item "Bytes" gdb-memory-unit-byte
1773 :button (:radio . (equal gdb-memory-unit "b"))))
1774
1775(defun gdb-memory-unit-menu (event)
1776 (interactive "@e")
1777 (x-popup-menu event gdb-memory-unit-menu))
1778
1779(defun gdb-memory-unit-menu-1 (event)
1780 (interactive "e")
1781 (save-selected-window
1782 (select-window (posn-window (event-start event)))
1783 (let* ((selection (gdb-memory-unit-menu event))
1784 (binding (and selection (lookup-key gdb-memory-unit-menu
1785 (vector (car selection))))))
1786 (if binding (call-interactively binding)))))
1787
1788;;from make-mode-line-mouse-map
1789(defun gdb-make-header-line-mouse-map (mouse function) "\
1790Return a keymap with single entry for mouse key MOUSE on the header line.
1791MOUSE is defined to run function FUNCTION with no args in the buffer
1792corresponding to the mode line clicked."
1793 (let ((map (make-sparse-keymap)))
1794 (define-key map (vector 'header-line mouse) function)
1795 (define-key map (vector 'header-line 'down-mouse-1) 'ignore)
1796 map))
1797
1798(defun gdb-memory-mode ()
1799 "Major mode for examining memory.
1800
1801\\{gdb-memory-mode-map}"
1802 (kill-all-local-variables)
1803 (setq major-mode 'gdb-memory-mode)
1804 (setq mode-name "Memory")
1805 (setq buffer-read-only t)
1806 (use-local-map gdb-memory-mode-map)
1807 (setq header-line-format
1808 '(:eval
bf247b6e 1809 (concat
37ebd64b
NR
1810 "Read address: "
1811 (propertize gdb-memory-address
1812 'face font-lock-warning-face
1813 'help-echo (purecopy "mouse-1: Set memory address")
1814 'local-map (purecopy (gdb-make-header-line-mouse-map
1815 'mouse-1
1816 #'gdb-memory-set-address)))
1817 " Repeat Count: "
1818 (propertize (number-to-string gdb-memory-repeat-count)
1819 'face font-lock-warning-face
1820 'help-echo (purecopy "mouse-1: Set repeat count")
1821 'local-map (purecopy (gdb-make-header-line-mouse-map
1822 'mouse-1
1823 #'gdb-memory-set-repeat-count)))
1824 " Display Format: "
1825 (propertize gdb-memory-format
1826 'face font-lock-warning-face
1827 'help-echo (purecopy "mouse-3: Select display format")
1828 'local-map gdb-memory-format-keymap)
1829 " Unit Size: "
1830 (propertize gdb-memory-unit
1831 'face font-lock-warning-face
1832 'help-echo (purecopy "mouse-3: Select unit size")
1833 'local-map gdb-memory-unit-keymap))))
1834 (run-mode-hooks 'gdb-memory-mode-hook)
1835 'gdb-invalidate-memory)
1836
1837(defun gdb-memory-buffer-name ()
1838 (with-current-buffer gud-comint-buffer
1839 (concat "*memory of " (gdb-get-target-string) "*")))
1840
1841(defun gdb-display-memory-buffer ()
1842 "Display memory contents."
1843 (interactive)
1844 (gdb-display-buffer
1845 (gdb-get-create-buffer 'gdb-memory-buffer)))
1846
1847(defun gdb-frame-memory-buffer ()
1848 "Display memory contents in a new frame."
1849 (interactive)
1850 (let ((special-display-regexps (append special-display-regexps '(".*")))
1851 (special-display-frame-alist gdb-frame-parameters))
1852 (display-buffer (gdb-get-create-buffer 'gdb-memory-buffer))))
1853\f
1854
1ffac268
NR
1855;; Locals buffer.
1856;;
1857(gdb-set-buffer-rules 'gdb-locals-buffer
1858 'gdb-locals-buffer-name
1859 'gdb-locals-mode)
1860
1861(def-gdb-auto-updated-buffer gdb-locals-buffer
1862 gdb-invalidate-locals
1863 "server info locals\n"
1864 gdb-info-locals-handler
1865 gdb-info-locals-custom)
1866
1867;; Abbreviate for arrays and structures.
1868;; These can be expanded using gud-display.
1869(defun gdb-info-locals-handler nil
2cec1d1a
NR
1870 (setq gdb-pending-triggers (delq 'gdb-invalidate-locals
1871 gdb-pending-triggers))
1ffac268
NR
1872 (let ((buf (gdb-get-buffer 'gdb-partial-output-buffer)))
1873 (with-current-buffer buf
1874 (goto-char (point-min))
1875 (while (re-search-forward "^ .*\n" nil t)
1876 (replace-match "" nil nil))
1877 (goto-char (point-min))
1878 (while (re-search-forward "{[-0-9, {}\]*\n" nil t)
1879 (replace-match "(array);\n" nil nil))
1880 (goto-char (point-min))
1881 (while (re-search-forward "{.*=.*\n" nil t)
1882 (replace-match "(structure);\n" nil nil))))
1883 (let ((buf (gdb-get-buffer 'gdb-locals-buffer)))
1884 (and buf (with-current-buffer buf
1885 (let ((p (point))
1886 (buffer-read-only nil))
1887 (delete-region (point-min) (point-max))
1888 (insert-buffer-substring (gdb-get-create-buffer
1889 'gdb-partial-output-buffer))
1890 (goto-char p)))))
1891 (run-hooks 'gdb-info-locals-hook))
1892
1893(defun gdb-info-locals-custom ()
1894 nil)
1895
1896(defvar gdb-locals-mode-map
1897 (let ((map (make-sparse-keymap)))
1898 (suppress-keymap map)
12032009
NR
1899 (define-key map "q" 'kill-this-buffer)
1900 map))
1ffac268
NR
1901
1902(defun gdb-locals-mode ()
1903 "Major mode for gdb locals.
1904
1905\\{gdb-locals-mode-map}"
fad137cd 1906 (kill-all-local-variables)
1ffac268 1907 (setq major-mode 'gdb-locals-mode)
f2f82fa4 1908 (setq mode-name (concat "Locals:" gdb-current-frame))
1ffac268
NR
1909 (setq buffer-read-only t)
1910 (use-local-map gdb-locals-mode-map)
fad137cd 1911 (run-mode-hooks 'gdb-locals-mode-hook)
9f438d80 1912 (if (with-current-buffer gud-comint-buffer (eq gud-minor-mode 'gdba))
fad137cd
NR
1913 'gdb-invalidate-locals
1914 'gdbmi-invalidate-locals))
1ffac268
NR
1915
1916(defun gdb-locals-buffer-name ()
1917 (with-current-buffer gud-comint-buffer
1918 (concat "*locals of " (gdb-get-target-string) "*")))
1919
1920(defun gdb-display-locals-buffer ()
f6a2315e 1921 "Display local variables of current stack and their values."
1ffac268
NR
1922 (interactive)
1923 (gdb-display-buffer
1924 (gdb-get-create-buffer 'gdb-locals-buffer)))
1925
1926(defun gdb-frame-locals-buffer ()
f6a2315e 1927 "Display local variables of current stack and their values in a new frame."
1ffac268 1928 (interactive)
1a9203d0
NR
1929 (let ((special-display-regexps (append special-display-regexps '(".*")))
1930 (special-display-frame-alist gdb-frame-parameters))
1931 (display-buffer (gdb-get-create-buffer 'gdb-locals-buffer))))
1ffac268
NR
1932\f
1933
1934;;;; Window management
1ffac268 1935(defun gdb-display-buffer (buf &optional size)
12032009
NR
1936 (let ((answer (get-buffer-window buf 0))
1937 (must-split nil))
1938 (if answer
f2dab427 1939 (display-buffer buf) ;Raise the frame if necessary.
12032009
NR
1940 ;; The buffer is not yet displayed.
1941 (pop-to-buffer gud-comint-buffer) ;Select the right frame.
f2dab427
NR
1942 (let ((window (get-lru-window)))
1943 (if window
1944 (progn
1945 (set-window-buffer window buf)
1946 (setq answer window))
12032009 1947 (setq must-split t)))
f2dab427
NR
1948 (if must-split
1949 (let* ((largest (get-largest-window))
1950 (cur-size (window-height largest))
1951 (new-size (and size (< size cur-size) (- cur-size size))))
1952 (setq answer (split-window largest new-size))
1953 (set-window-buffer answer buf)
1954 (set-window-dedicated-p answer t)))
12032009 1955 answer)))
1ffac268 1956
1ffac268
NR
1957\f
1958;;; Shared keymap initialization:
1959
1ffac268
NR
1960(let ((menu (make-sparse-keymap "GDB-Windows")))
1961 (define-key gud-menu-map [displays]
1962 `(menu-item "GDB-Windows" ,menu :visible (eq gud-minor-mode 'gdba)))
1963 (define-key menu [gdb] '("Gdb" . gdb-display-gdb-buffer))
2b63b80f 1964 (define-key menu [threads] '("Threads" . gdb-display-threads-buffer))
37ebd64b
NR
1965 (define-key menu [memory] '("Memory" . gdb-display-memory-buffer))
1966 (define-key menu [assembler] '("Machine" . gdb-display-assembler-buffer))
1ffac268 1967 (define-key menu [registers] '("Registers" . gdb-display-registers-buffer))
2b63b80f 1968 (define-key menu [locals] '("Locals" . gdb-display-locals-buffer))
1ffac268 1969 (define-key menu [frames] '("Stack" . gdb-display-stack-buffer))
2cec1d1a 1970 (define-key menu [breakpoints] '("Breakpoints" . gdb-display-breakpoints-buffer)))
1ffac268 1971
b29ef159
NR
1972(let ((menu (make-sparse-keymap "GDB-Frames")))
1973 (define-key gud-menu-map [frames]
1974 `(menu-item "GDB-Frames" ,menu :visible (eq gud-minor-mode 'gdba)))
1975 (define-key menu [gdb] '("Gdb" . gdb-frame-gdb-buffer))
1976 (define-key menu [threads] '("Threads" . gdb-frame-threads-buffer))
1977 (define-key menu [memory] '("Memory" . gdb-frame-memory-buffer))
1978 (define-key menu [assembler] '("Machine" . gdb-frame-assembler-buffer))
1979 (define-key menu [registers] '("Registers" . gdb-frame-registers-buffer))
1980 (define-key menu [locals] '("Locals" . gdb-frame-locals-buffer))
1981 (define-key menu [frames] '("Stack" . gdb-frame-stack-buffer))
1982 (define-key menu [breakpoints] '("Breakpoints" . gdb-frame-breakpoints-buffer)))
1983
1ffac268
NR
1984(let ((menu (make-sparse-keymap "GDB-UI")))
1985 (define-key gud-menu-map [ui]
1986 `(menu-item "GDB-UI" ,menu :visible (eq gud-minor-mode 'gdba)))
1987 (define-key menu [gdb-restore-windows]
b29ef159 1988 '("Restore Window Layout" . gdb-restore-windows))
1ffac268
NR
1989 (define-key menu [gdb-many-windows]
1990 (menu-bar-make-toggle gdb-many-windows gdb-many-windows
b29ef159
NR
1991 "Display Other Windows" "Many windows %s"
1992 "Toggle display of locals, stack and breakpoint information")))
1ffac268
NR
1993
1994(defun gdb-frame-gdb-buffer ()
f6a2315e 1995 "Display GUD buffer in a new frame."
1ffac268 1996 (interactive)
95cc50b6
NR
1997 (select-frame (make-frame gdb-frame-parameters))
1998 (switch-to-buffer (gdb-get-create-buffer 'gdba))
8ce7881f 1999 (set-window-dedicated-p (selected-window) t))
1ffac268
NR
2000
2001(defun gdb-display-gdb-buffer ()
f6a2315e 2002 "Display GUD buffer."
1ffac268
NR
2003 (interactive)
2004 (gdb-display-buffer
2005 (gdb-get-create-buffer 'gdba)))
2006
2007(defvar gdb-main-file nil "Source file from which program execution begins.")
2008
188590b5
NR
2009(defcustom gdb-show-main nil
2010 "Nil means don't display source file containing the main routine."
2011 :type 'boolean
27b3b9d3 2012 :group 'gud
bf247b6e 2013 :version "22.1")
188590b5 2014
12032009
NR
2015(defun gdb-set-window-buffer (name)
2016 (set-window-buffer (selected-window) (get-buffer name))
2017 (set-window-dedicated-p (selected-window) t))
4e607b59 2018
1ffac268 2019(defun gdb-setup-windows ()
188590b5 2020 "Layout the window pattern for gdb-many-windows."
1ffac268
NR
2021 (gdb-display-locals-buffer)
2022 (gdb-display-stack-buffer)
2023 (delete-other-windows)
2024 (gdb-display-breakpoints-buffer)
2025 (delete-other-windows)
f2dab427
NR
2026 ; Don't dedicate.
2027 (pop-to-buffer gud-comint-buffer)
1ffac268
NR
2028 (split-window nil ( / ( * (window-height) 3) 4))
2029 (split-window nil ( / (window-height) 3))
2030 (split-window-horizontally)
2031 (other-window 1)
12032009 2032 (gdb-set-window-buffer (gdb-locals-buffer-name))
1ffac268 2033 (other-window 1)
f2dab427 2034 (switch-to-buffer
1ffac268
NR
2035 (if gud-last-last-frame
2036 (gud-find-file (car gud-last-last-frame))
f2dab427 2037 (gud-find-file gdb-main-file)))
614963ba
NR
2038 (when gdb-use-inferior-io-buffer
2039 (split-window-horizontally)
2040 (other-window 1)
12032009 2041 (gdb-set-window-buffer (gdb-inferior-io-name)))
1ffac268 2042 (other-window 1)
12032009 2043 (gdb-set-window-buffer (gdb-stack-buffer-name))
1ffac268
NR
2044 (split-window-horizontally)
2045 (other-window 1)
12032009 2046 (gdb-set-window-buffer (gdb-breakpoints-buffer-name))
1ffac268
NR
2047 (other-window 1))
2048
2049(defcustom gdb-many-windows nil
d94dccc6
SM
2050 "Nil means just pop up the GUD buffer unless `gdb-show-main' is t.
2051In this case it starts with two windows: one displaying the GUD
2052buffer and the other with the source file with the main routine
2053of the inferior. Non-nil means display the layout shown for
2054`gdba'."
1ffac268 2055 :type 'boolean
27b3b9d3 2056 :group 'gud
bf247b6e 2057 :version "22.1")
1ffac268
NR
2058
2059(defun gdb-many-windows (arg)
b6d0e4da 2060 "Toggle the number of windows in the basic arrangement."
1ffac268
NR
2061 (interactive "P")
2062 (setq gdb-many-windows
2063 (if (null arg)
2064 (not gdb-many-windows)
2065 (> (prefix-numeric-value arg) 0)))
91e88cea
NR
2066 (condition-case nil
2067 (gdb-restore-windows)
2068 (error nil)))
1ffac268
NR
2069
2070(defun gdb-restore-windows ()
2071 "Restore the basic arrangement of windows used by gdba.
2072This arrangement depends on the value of `gdb-many-windows'."
2073 (interactive)
12032009 2074 (pop-to-buffer gud-comint-buffer) ;Select the right window and frame.
1ffac268 2075 (delete-other-windows)
12032009
NR
2076 (if gdb-many-windows
2077 (gdb-setup-windows)
1ffac268
NR
2078 (split-window)
2079 (other-window 1)
f2dab427 2080 (switch-to-buffer
1ffac268
NR
2081 (if gud-last-last-frame
2082 (gud-find-file (car gud-last-last-frame))
f2dab427 2083 (gud-find-file gdb-main-file)))
1ffac268
NR
2084 (other-window 1)))
2085
2086(defun gdb-reset ()
d94dccc6
SM
2087 "Exit a debugging session cleanly.
2088Kills the gdb buffers and resets the source buffers."
1ffac268 2089 (dolist (buffer (buffer-list))
d490ebbe
SM
2090 (unless (eq buffer gud-comint-buffer)
2091 (with-current-buffer buffer
2cec1d1a 2092 (if (memq gud-minor-mode '(gdbmi gdba))
d490ebbe
SM
2093 (if (string-match "\\`\\*.+\\*\\'" (buffer-name))
2094 (kill-buffer nil)
2095 (gdb-remove-breakpoint-icons (point-min) (point-max) t)
2096 (setq gud-minor-mode nil)
2097 (kill-local-variable 'tool-bar-map)
2098 (setq gud-running nil))))))
1ffac268
NR
2099 (when (markerp gdb-overlay-arrow-position)
2100 (move-marker gdb-overlay-arrow-position nil)
2101 (setq gdb-overlay-arrow-position nil))
2102 (setq overlay-arrow-variable-list
2103 (delq 'gdb-overlay-arrow-position overlay-arrow-variable-list)))
2104
2105(defun gdb-source-info ()
2106 "Find the source file where the program starts and displays it with related
2107buffers."
2108 (goto-char (point-min))
e7212bb3
NR
2109 (if (and (search-forward "Located in " nil t)
2110 (looking-at "\\S-*"))
2111 (setq gdb-main-file (match-string 0)))
f2dab427 2112 (if gdb-many-windows
1ffac268 2113 (gdb-setup-windows)
94cd554a 2114 (gdb-get-create-buffer 'gdb-breakpoints-buffer)
e7212bb3
NR
2115 (if gdb-show-main
2116 (let ((pop-up-windows t))
2117 (display-buffer (gud-find-file gdb-main-file))))))
1ffac268 2118
94cd554a
NR
2119(defun gdb-get-location (bptno line flag)
2120 "Find the directory containing the relevant source file.
2121Put in buffer and place breakpoint icon."
2122 (goto-char (point-min))
50af6c66
NR
2123 (catch 'file-not-found
2124 (if (search-forward "Located in " nil t)
2125 (if (looking-at "\\S-*")
2126 (push (cons bptno (match-string 0)) gdb-location-list))
2127 (gdb-resync)
2128 (push (cons bptno "File not found") gdb-location-list)
2e8c13b4
NR
2129 (message-box "Cannot find source file for breakpoint location.\n\
2130Add directory to search path for source files using the GDB command, dir.")
50af6c66
NR
2131 (throw 'file-not-found nil))
2132 (with-current-buffer
2133 (find-file-noselect (match-string 0))
2134 (save-current-buffer
2135 (set (make-local-variable 'gud-minor-mode) 'gdba)
2136 (set (make-local-variable 'tool-bar-map) gud-tool-bar-map))
2137 ;; only want one breakpoint icon at each location
2138 (save-excursion
2139 (goto-line (string-to-number line))
2140 (gdb-put-breakpoint-icon (eq flag ?y) bptno)))))
94cd554a 2141
e7212bb3
NR
2142(add-hook 'find-file-hook 'gdb-find-file-hook)
2143
2144(defun gdb-find-file-hook ()
2145 (if (and (not gdb-find-file-unhook)
2146 ;; in case gud or gdb-ui is just loaded
2147 gud-comint-buffer
2148 (buffer-name gud-comint-buffer)
2149 (with-current-buffer gud-comint-buffer
2150 (eq gud-minor-mode 'gdba)))
2151 (condition-case nil
2152 (gdb-enqueue-input
262ba701
NR
2153 (list (concat gdb-server-prefix "list "
2154 (file-name-nondirectory buffer-file-name)
e7212bb3
NR
2155 ":1\n")
2156 `(lambda () (gdb-set-gud-minor-mode ,(current-buffer)))))
2157 (error (setq gdb-find-file-unhook t)))))
2158
1ffac268
NR
2159;;from put-image
2160(defun gdb-put-string (putstring pos &optional dprop)
2161 "Put string PUTSTRING in front of POS in the current buffer.
2162PUTSTRING is displayed by putting an overlay into the current buffer with a
2163`before-string' STRING that has a `display' property whose value is
2164PUTSTRING."
b6d0e4da 2165 (let ((string (make-string 1 ?x))
1ffac268 2166 (buffer (current-buffer)))
b6d0e4da 2167 (setq putstring (copy-sequence putstring))
1ffac268
NR
2168 (let ((overlay (make-overlay pos pos buffer))
2169 (prop (or dprop
2170 (list (list 'margin 'left-margin) putstring))))
b6d0e4da 2171 (put-text-property 0 (length string) 'display prop string)
1ffac268 2172 (overlay-put overlay 'put-break t)
b6d0e4da 2173 (overlay-put overlay 'before-string string))))
1ffac268
NR
2174
2175;;from remove-images
2176(defun gdb-remove-strings (start end &optional buffer)
2177 "Remove strings between START and END in BUFFER.
2178Remove only strings that were put in BUFFER with calls to `gdb-put-string'.
2179BUFFER nil or omitted means use the current buffer."
2180 (unless buffer
2181 (setq buffer (current-buffer)))
b6d0e4da 2182 (dolist (overlay (overlays-in start end))
1ffac268 2183 (when (overlay-get overlay 'put-break)
b6d0e4da 2184 (delete-overlay overlay))))
1ffac268 2185
b6d0e4da 2186(defun gdb-put-breakpoint-icon (enabled bptno)
1ffac268 2187 (let ((start (progn (beginning-of-line) (- (point) 1)))
b6d0e4da
NR
2188 (end (progn (end-of-line) (+ (point) 1)))
2189 (putstring (if enabled "B" "b")))
f3094341
NR
2190 (add-text-properties
2191 0 1 '(help-echo "mouse-1: set/clear bkpt, mouse-3: enable/disable bkpt")
2192 putstring)
b6d0e4da
NR
2193 (if enabled (add-text-properties
2194 0 1 `(gdb-bptno ,bptno gdb-enabled t) putstring)
2195 (add-text-properties
2196 0 1 `(gdb-bptno ,bptno gdb-enabled nil) putstring))
1ffac268
NR
2197 (gdb-remove-breakpoint-icons start end)
2198 (if (display-images-p)
2199 (if (>= (car (window-fringes)) 8)
188590b5 2200 (gdb-put-string
1ffac268 2201 nil (1+ start)
a9c65ba5 2202 `(left-fringe breakpoint
b6d0e4da 2203 ,(if enabled
e38b967a
MB
2204 'breakpoint-enabled
2205 'breakpoint-disabled)))
1ffac268
NR
2206 (when (< left-margin-width 2)
2207 (save-current-buffer
2208 (setq left-margin-width 2)
f2dab427 2209 (if (get-buffer-window (current-buffer) 0)
619b6adb 2210 (set-window-margins
f2dab427 2211 (get-buffer-window (current-buffer) 0)
2b63b80f 2212 left-margin-width right-margin-width))))
1ffac268
NR
2213 (put-image
2214 (if enabled
2215 (or breakpoint-enabled-icon
2216 (setq breakpoint-enabled-icon
188590b5 2217 (find-image `((:type xpm :data
1ffac268
NR
2218 ,breakpoint-xpm-data
2219 :ascent 100 :pointer hand)
2220 (:type pbm :data
2221 ,breakpoint-enabled-pbm-data
2222 :ascent 100 :pointer hand)))))
2223 (or breakpoint-disabled-icon
2224 (setq breakpoint-disabled-icon
2225 (find-image `((:type xpm :data
2226 ,breakpoint-xpm-data
2227 :conversion disabled
2228 :ascent 100)
2229 (:type pbm :data
2230 ,breakpoint-disabled-pbm-data
2231 :ascent 100))))))
b6d0e4da
NR
2232 (+ start 1)
2233 putstring
2234 'left-margin))
1ffac268
NR
2235 (when (< left-margin-width 2)
2236 (save-current-buffer
2237 (setq left-margin-width 2)
f2dab427 2238 (if (get-buffer-window (current-buffer) 0)
619b6adb 2239 (set-window-margins
f2dab427 2240 (get-buffer-window (current-buffer) 0)
2b63b80f 2241 left-margin-width right-margin-width))))
e38b967a
MB
2242 (gdb-put-string
2243 (propertize putstring
2244 'face (if enabled 'breakpoint-enabled 'breakpoint-disabled))
2245 (1+ start)))))
1ffac268
NR
2246
2247(defun gdb-remove-breakpoint-icons (start end &optional remove-margin)
2248 (gdb-remove-strings start end)
2249 (if (display-images-p)
2250 (remove-images start end))
2251 (when remove-margin
2252 (setq left-margin-width 0)
f2dab427 2253 (if (get-buffer-window (current-buffer) 0)
619b6adb 2254 (set-window-margins
f2dab427 2255 (get-buffer-window (current-buffer) 0)
2b63b80f 2256 left-margin-width right-margin-width))))
1ffac268
NR
2257
2258\f
2259;;
2260;; Assembler buffer.
2261;;
2262(gdb-set-buffer-rules 'gdb-assembler-buffer
2263 'gdb-assembler-buffer-name
2264 'gdb-assembler-mode)
2265
2266(def-gdb-auto-updated-buffer gdb-assembler-buffer
2267 gdb-invalidate-assembler
2cec1d1a 2268 (concat gdb-server-prefix "disassemble " gdb-current-address "\n")
1ffac268
NR
2269 gdb-assembler-handler
2270 gdb-assembler-custom)
2271
2272(defun gdb-assembler-custom ()
2273 (let ((buffer (gdb-get-buffer 'gdb-assembler-buffer))
190def62 2274 (pos 1) (address) (flag) (bptno))
1ffac268
NR
2275 (with-current-buffer buffer
2276 (if (not (equal gdb-current-address "main"))
2277 (progn
2278 (goto-char (point-min))
2279 (if (re-search-forward gdb-current-address nil t)
2280 (progn
2281 (setq pos (point))
2282 (beginning-of-line)
2283 (or gdb-overlay-arrow-position
2284 (setq gdb-overlay-arrow-position (make-marker)))
2285 (set-marker gdb-overlay-arrow-position
2286 (point) (current-buffer))))))
2287 ;; remove all breakpoint-icons in assembler buffer before updating.
2288 (gdb-remove-breakpoint-icons (point-min) (point-max)))
2289 (with-current-buffer (gdb-get-buffer 'gdb-breakpoints-buffer)
2290 (goto-char (point-min))
2291 (while (< (point) (- (point-max) 1))
2292 (forward-line 1)
2293 (if (looking-at "[^\t].*breakpoint")
2294 (progn
2295 (looking-at
190def62
NR
2296 "\\([0-9]+\\)\\s-+\\S-+\\s-+\\S-+\\s-+\\(.\\)\\s-+0x\\(\\S-+\\)")
2297 (setq bptno (match-string 1))
2298 (setq flag (char-after (match-beginning 2)))
2299 (setq address (match-string 3))
1ffac268
NR
2300 ;; remove leading 0s from output of info break.
2301 (if (string-match "^0+\\(.*\\)" address)
2302 (setq address (match-string 1 address)))
2303 (with-current-buffer buffer
2304 (goto-char (point-min))
2305 (if (re-search-forward address nil t)
190def62 2306 (gdb-put-breakpoint-icon (eq flag ?y) bptno)))))))
1ffac268 2307 (if (not (equal gdb-current-address "main"))
f2dab427 2308 (set-window-point (get-buffer-window buffer 0) pos))))
1ffac268
NR
2309
2310(defvar gdb-assembler-mode-map
2311 (let ((map (make-sparse-keymap)))
2312 (suppress-keymap map)
12032009
NR
2313 (define-key map "q" 'kill-this-buffer)
2314 map))
1ffac268 2315
fad137cd 2316(defvar gdb-assembler-font-lock-keywords
3988d9c6
MY
2317 '(;; <__function.name+n>
2318 ("<\\(\\(\\sw\\|[_.]\\)+\\)\\(\\+[0-9]+\\)?>"
2319 (1 font-lock-function-name-face))
2320 ;; 0xNNNNNNNN <__function.name+n>: opcode
2321 ("^0x[0-9a-f]+ \\(<\\(\\(\\sw\\|[_.]\\)+\\)\\+[0-9]+>\\)?:[ \t]+\\(\\sw+\\)"
fad137cd 2322 (4 font-lock-keyword-face))
3988d9c6 2323 ;; %register(at least i386)
fad137cd 2324 ("%\\sw+" . font-lock-variable-name-face)
3988d9c6 2325 ("^\\(Dump of assembler code for function\\) \\(.+\\):"
fad137cd
NR
2326 (1 font-lock-comment-face)
2327 (2 font-lock-function-name-face))
2328 ("^\\(End of assembler dump\\.\\)" . font-lock-comment-face))
2329 "Font lock keywords used in `gdb-assembler-mode'.")
2330
1ffac268
NR
2331(defun gdb-assembler-mode ()
2332 "Major mode for viewing code assembler.
2333
2334\\{gdb-assembler-mode-map}"
fad137cd 2335 (kill-all-local-variables)
1ffac268
NR
2336 (setq major-mode 'gdb-assembler-mode)
2337 (setq mode-name "Machine")
2338 (setq gdb-overlay-arrow-position nil)
2339 (add-to-list 'overlay-arrow-variable-list 'gdb-overlay-arrow-position)
2340 (put 'gdb-overlay-arrow-position 'overlay-arrow-string "=>")
2341 (setq fringes-outside-margins t)
2342 (setq buffer-read-only t)
2343 (use-local-map gdb-assembler-mode-map)
fad137cd
NR
2344 (gdb-invalidate-assembler)
2345 (set (make-local-variable 'font-lock-defaults)
2346 '(gdb-assembler-font-lock-keywords))
2347 (run-mode-hooks 'gdb-assembler-mode-hook)
2348 'gdb-invalidate-assembler)
1ffac268
NR
2349
2350(defun gdb-assembler-buffer-name ()
2351 (with-current-buffer gud-comint-buffer
2352 (concat "*Machine Code " (gdb-get-target-string) "*")))
2353
2354(defun gdb-display-assembler-buffer ()
f6a2315e 2355 "Display disassembly view."
1ffac268
NR
2356 (interactive)
2357 (gdb-display-buffer
2358 (gdb-get-create-buffer 'gdb-assembler-buffer)))
2359
2360(defun gdb-frame-assembler-buffer ()
f6a2315e 2361 "Display disassembly view in a new frame."
1ffac268 2362 (interactive)
1a9203d0
NR
2363 (let ((special-display-regexps (append special-display-regexps '(".*")))
2364 (special-display-frame-alist gdb-frame-parameters))
2365 (display-buffer (gdb-get-create-buffer 'gdb-assembler-buffer))))
1ffac268
NR
2366
2367;; modified because if gdb-current-address has changed value a new command
2368;; must be enqueued to update the buffer with the new output
2369(defun gdb-invalidate-assembler (&optional ignored)
2370 (if (gdb-get-buffer 'gdb-assembler-buffer)
2371 (progn
2372 (unless (string-equal gdb-current-frame gdb-previous-frame)
2373 (if (or (not (member 'gdb-invalidate-assembler
2cec1d1a 2374 gdb-pending-triggers))
1ffac268
NR
2375 (not (string-equal gdb-current-address
2376 gdb-previous-address)))
2377 (progn
2378 ;; take previous disassemble command off the queue
2379 (with-current-buffer gud-comint-buffer
12032009 2380 (let ((queue gdb-input-queue))
1ffac268
NR
2381 (dolist (item queue)
2382 (if (equal (cdr item) '(gdb-assembler-handler))
2cec1d1a
NR
2383 (setq gdb-input-queue
2384 (delete item gdb-input-queue))))))
1ffac268 2385 (gdb-enqueue-input
2cec1d1a 2386 (list (concat gdb-server-prefix "disassemble " gdb-current-address "\n")
1ffac268 2387 'gdb-assembler-handler))
2cec1d1a 2388 (push 'gdb-invalidate-assembler gdb-pending-triggers)
1ffac268
NR
2389 (setq gdb-previous-address gdb-current-address)
2390 (setq gdb-previous-frame gdb-current-frame)))))))
2391
2392(defun gdb-get-current-frame ()
2cec1d1a 2393 (if (not (member 'gdb-get-current-frame gdb-pending-triggers))
1ffac268
NR
2394 (progn
2395 (gdb-enqueue-input
2cec1d1a
NR
2396 (list (concat gdb-server-prefix "info frame\n") 'gdb-frame-handler))
2397 (push 'gdb-get-current-frame
2398 gdb-pending-triggers))))
1ffac268
NR
2399
2400(defun gdb-frame-handler ()
2cec1d1a
NR
2401 (setq gdb-pending-triggers
2402 (delq 'gdb-get-current-frame gdb-pending-triggers))
1ffac268
NR
2403 (with-current-buffer (gdb-get-create-buffer 'gdb-partial-output-buffer)
2404 (goto-char (point-min))
de1b8112
NR
2405 (if (looking-at "Stack level \\([0-9]+\\)")
2406 (setq gdb-current-stack-level (match-string 1)))
1ffac268 2407 (forward-line)
b65a2dbf 2408 (if (looking-at ".*=\\s-+0x\\(\\S-*\\)\\s-+in\\s-+\\(\\S-*?\\);? ")
1ffac268
NR
2409 (progn
2410 (setq gdb-current-frame (match-string 2))
f2f82fa4
NR
2411 (if (gdb-get-buffer 'gdb-locals-buffer)
2412 (with-current-buffer (gdb-get-buffer 'gdb-locals-buffer)
2413 (setq mode-name (concat "Locals:" gdb-current-frame))))
1ffac268
NR
2414 (let ((address (match-string 1)))
2415 ;; remove leading 0s from output of info frame command.
2416 (if (string-match "^0+\\(.*\\)" address)
2417 (setq gdb-current-address
2418 (concat "0x" (match-string 1 address)))
2419 (setq gdb-current-address (concat "0x" address))))
f2dab427 2420 (if (not (re-search-forward "(\\S-*:[0-9]*);" nil t))
1ffac268 2421 ;;update with new frame for machine code if necessary
f2dab427 2422 (gdb-invalidate-assembler)))))
1ffac268
NR
2423 (if (re-search-forward " source language \\(\\S-*\\)\." nil t)
2424 (setq gdb-current-language (match-string 1))))
2425
2426(provide 'gdb-ui)
2427
d490ebbe 2428;; arch-tag: e9fb00c5-74ef-469f-a088-37384caae352
1ffac268 2429;;; gdb-ui.el ends here