]> code.delx.au - gnu-emacs/blob - lisp/progmodes/gdb-mi.el
gdb-mi.el: Now using bindat-get-field instead of fadr functions.
[gnu-emacs] / lisp / progmodes / gdb-mi.el
1 ;;; gdb-mi.el --- User Interface for running GDB
2
3 ;; Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
4
5 ;; Author: Nick Roberts <nickrob@gnu.org>
6 ;; Maintainer: FSF
7 ;; Keywords: unix, tools
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 3 of the License, or
14 ;; (at your option) 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. If not, see <http://www.gnu.org/licenses/>.
23
24 ;;; Credits:
25
26 ;; This file was written by by Nick Roberts following the general design
27 ;; used in gdb-ui.el for Emacs 22.1 - 23.1. It is currently being developed
28 ;; by Dmitry Dzhus <dima@sphinx.net.ru> as part of the Google Summer
29 ;; of Code 2009 Project "Emacs GDB/MI migration".
30
31 ;;; Commentary:
32
33 ;; This mode acts as a graphical user interface to GDB. You can interact with
34 ;; GDB through the GUD buffer in the usual way, but there are also further
35 ;; buffers which control the execution and describe the state of your program.
36 ;; It separates the input/output of your program from that of GDB and displays
37 ;; expressions and their current values in their own buffers. It also uses
38 ;; features of Emacs 21 such as the fringe/display margin for breakpoints, and
39 ;; the toolbar (see the GDB Graphical Interface section in the Emacs info
40 ;; manual).
41
42 ;; M-x gdb will start the debugger.
43
44 ;; This file uses GDB/MI as the primary interface to GDB. It is still under
45 ;; development and is part of a process to migrate Emacs from annotations (as
46 ;; used in gdb-ui.el) to GDB/MI. It runs gdb with GDB/MI (-interp=mi) and
47 ;; access CLI using "-interpreter-exec console cli-command". This code works
48 ;; without gdb-ui.el and uses MI tokens instead of queues. Eventually MI
49 ;; should be asynchronous.
50
51 ;; This mode will PARTLY WORK WITH RECENT GDB RELEASES (status in modeline
52 ;; doesn't update properly when execution commands are issued from GUD buffer)
53 ;; and WORKS BEST when GDB runs asynchronously: maint set linux-async on.
54 ;;
55 ;; You need development version of GDB 7.0 for the thread buffer to work.
56
57 ;; This file replaces gdb-ui.el and is for development with GDB. Use the
58 ;; release branch of Emacs 22 for the latest version of gdb-ui.el.
59
60 ;; Windows Platforms:
61
62 ;; If you are using Emacs and GDB on Windows you will need to flush the buffer
63 ;; explicitly in your program if you want timely display of I/O in Emacs.
64 ;; Alternatively you can make the output stream unbuffered, for example, by
65 ;; using a macro:
66
67 ;; #ifdef UNBUFFERED
68 ;; setvbuf (stdout, (char *) NULL, _IONBF, 0);
69 ;; #endif
70
71 ;; and compiling with -DUNBUFFERED while debugging.
72
73 ;; If you are using Cygwin GDB and find that the source is not being displayed
74 ;; in Emacs when you step through it, possible solutions are to:
75
76 ;; 1) Use Cygwin X Windows and Cygwin Emacs.
77 ;; (Since 22.1 Emacs builds under Cygwin.)
78 ;; 2) Use MinGW GDB instead.
79 ;; 3) Use cygwin-mount.el
80
81 ;;; Mac OSX:
82
83 ;; GDB in Emacs on Mac OSX works best with FSF GDB as Apple have made
84 ;; some changes to the version that they include as part of Mac OSX.
85 ;; This requires GDB version 7.0 or later (estimated release date Aug 2009)
86 ;; as earlier versions don not compile on Mac OSX.
87
88 ;;; Known Bugs:
89
90 ;; 1) Stack buffer doesn't parse MI output if you stop in a routine without
91 ;; line information, e.g., a routine in libc (just a TODO item).
92
93 ;; TODO:
94 ;; 2) Watch windows to work with threads.
95 ;; 3) Use treebuffer.el instead of the speedbar for watch-expressions?
96 ;; 4) Mark breakpoint locations on scroll-bar of source buffer?
97
98 ;;; Code:
99
100 (require 'gud)
101 (require 'json)
102 (require 'bindat)
103
104 (defvar tool-bar-map)
105 (defvar speedbar-initial-expansion-list-name)
106
107 (defvar gdb-pc-address nil "Initialization for Assembler buffer.
108 Set to \"main\" at start if `gdb-show-main' is t.")
109 (defvar gdb-memory-address "main")
110 (defvar gdb-memory-last-address nil
111 "Last successfully accessed memory address.")
112 (defvar gdb-memory-next-page nil
113 "Address of next memory page for program memory buffer.")
114 (defvar gdb-memory-prev-page nil
115 "Address of previous memory page for program memory buffer.")
116
117 (defvar gdb-selected-frame nil)
118 (defvar gdb-selected-file nil)
119 (defvar gdb-selected-line nil)
120 (defvar gdb-frame-number nil)
121 (defvar gdb-current-language nil)
122 (defvar gdb-var-list nil
123 "List of variables in watch window.
124 Each element has the form (VARNUM EXPRESSION NUMCHILD TYPE VALUE STATUS) where
125 STATUS is nil (unchanged), `changed' or `out-of-scope'.")
126 (defvar gdb-main-file nil "Source file from which program execution begins.")
127 (defvar gdb-overlay-arrow-position nil)
128 (defvar gdb-stack-position nil)
129 (defvar gdb-location-alist nil
130 "Alist of breakpoint numbers and full filenames. Only used for files that
131 Emacs can't find.")
132 (defvar gdb-active-process nil
133 "GUD tooltips display variable values when t, and macro definitions otherwise.")
134 (defvar gdb-error "Non-nil when GDB is reporting an error.")
135 (defvar gdb-macro-info nil
136 "Non-nil if GDB knows that the inferior includes preprocessor macro info.")
137 (defvar gdb-register-names nil "List of register names.")
138 (defvar gdb-changed-registers nil
139 "List of changed register numbers (strings).")
140 (defvar gdb-buffer-fringe-width nil)
141 (defvar gdb-last-command nil)
142 (defvar gdb-prompt-name nil)
143 (defvar gdb-token-number 0)
144 (defvar gdb-handler-alist '())
145 (defvar gdb-handler-number nil)
146 (defvar gdb-source-file-list nil
147 "List of source files for the current executable.")
148 (defvar gdb-first-done-or-error t)
149 (defvar gdb-source-window nil)
150 (defvar gdb-inferior-status nil)
151 (defvar gdb-continuation nil)
152 (defvar gdb-filter-output nil
153 "Message to be shown in GUD console.
154
155 This variable is updated in `gdb-done-or-error' and returned by
156 `gud-gdbmi-marker-filter'.")
157
158 (defvar gdb-buffer-type nil
159 "One of the symbols bound in `gdb-buffer-rules'.")
160 (make-variable-buffer-local 'gdb-buffer-type)
161
162 (defvar gdb-output-sink 'nil
163 "The disposition of the output of the current gdb command.
164 Possible values are these symbols:
165
166 `user' -- gdb output should be copied to the GUD buffer
167 for the user to see.
168
169 `emacs' -- output should be collected in the partial-output-buffer
170 for subsequent processing by a command. This is the
171 disposition of output generated by commands that
172 gdb mode sends to gdb on its own behalf.")
173
174 (defvar gdb-pending-triggers '()
175 "A list of trigger functions that have run later than their output handlers.")
176
177 (defcustom gdb-debug-log-max 128
178 "Maximum size of `gdb-debug-log'. If nil, size is unlimited."
179 :group 'gdb
180 :type '(choice (integer :tag "Number of elements")
181 (const :tag "Unlimited" nil))
182 :version "22.1")
183
184 (defvar gdb-debug-log nil
185 "List of commands sent to and replies received from GDB.
186 Most recent commands are listed first. This list stores only the last
187 `gdb-debug-log-max' values. This variable is used to debug GDB-MI.")
188
189 ;;;###autoload
190 (defcustom gdb-enable-debug nil
191 "Non-nil means record the process input and output in `gdb-debug-log'."
192 :type 'boolean
193 :group 'gdb
194 :version "22.1")
195
196 (defcustom gdb-cpp-define-alist-program "gcc -E -dM -"
197 "Shell command for generating a list of defined macros in a source file.
198 This list is used to display the #define directive associated
199 with an identifier as a tooltip. It works in a debug session with
200 GDB, when `gud-tooltip-mode' is t.
201
202 Set `gdb-cpp-define-alist-flags' for any include paths or
203 predefined macros."
204 :type 'string
205 :group 'gdb
206 :version "22.1")
207
208 (defcustom gdb-cpp-define-alist-flags ""
209 "Preprocessor flags for `gdb-cpp-define-alist-program'."
210 :type 'string
211 :group 'gdb
212 :version "22.1")
213
214 (defcustom gdb-create-source-file-list t
215 "Non-nil means create a list of files from which the executable was built.
216 Set this to nil if the GUD buffer displays \"initializing...\" in the mode
217 line for a long time when starting, possibly because your executable was
218 built from a large number of files. This allows quicker initialization
219 but means that these files are not automatically enabled for debugging,
220 e.g., you won't be able to click in the fringe to set a breakpoint until
221 execution has already stopped there."
222 :type 'boolean
223 :group 'gdb
224 :version "23.1")
225
226 (defcustom gdb-show-main nil
227 "Non-nil means display source file containing the main routine at startup.
228 Also display the main routine in the disassembly buffer if present."
229 :type 'boolean
230 :group 'gdb
231 :version "22.1")
232
233 ; Note: This mode requires a separate buffer for inferior IO.
234 (defconst gdb-use-separate-io-buffer t)
235
236 (defun gdb-force-mode-line-update (status)
237 (let ((buffer gud-comint-buffer))
238 (if (and buffer (buffer-name buffer))
239 (with-current-buffer buffer
240 (setq mode-line-process
241 (format ":%s [%s]"
242 (process-status (get-buffer-process buffer)) status))
243 ;; Force mode line redisplay soon.
244 (force-mode-line-update)))))
245
246 (defun gdb-enable-debug (arg)
247 "Toggle logging of transaction between Emacs and Gdb.
248 The log is stored in `gdb-debug-log' as an alist with elements
249 whose cons is send, send-item or recv and whose cdr is the string
250 being transferred. This list may grow up to a size of
251 `gdb-debug-log-max' after which the oldest element (at the end of
252 the list) is deleted every time a new one is added (at the front)."
253 (interactive "P")
254 (setq gdb-enable-debug
255 (if (null arg)
256 (not gdb-enable-debug)
257 (> (prefix-numeric-value arg) 0)))
258 (message (format "Logging of transaction %sabled"
259 (if gdb-enable-debug "en" "dis"))))
260
261 (defun gdb-find-watch-expression ()
262 (let* ((var (nth (- (line-number-at-pos (point)) 2) gdb-var-list))
263 (varnum (car var)) expr array)
264 (string-match "\\(var[0-9]+\\)\\.\\(.*\\)" varnum)
265 (let ((var1 (assoc (match-string 1 varnum) gdb-var-list)) var2 varnumlet
266 (component-list (split-string (match-string 2 varnum) "\\." t)))
267 (setq expr (nth 1 var1))
268 (setq varnumlet (car var1))
269 (dolist (component component-list)
270 (setq var2 (assoc varnumlet gdb-var-list))
271 (setq expr (concat expr
272 (if (string-match ".*\\[[0-9]+\\]$" (nth 3 var2))
273 (concat "[" component "]")
274 (concat "." component))))
275 (setq varnumlet (concat varnumlet "." component)))
276 expr)))
277
278 (defvar gdb-locals-font-lock-keywords
279 '(
280 ;; var = type value
281 ( "\\(^\\(\\sw\\|[_.]\\)+\\)\t+\\(\\(\\sw\\|[_.]\\)+\\)"
282 (1 font-lock-variable-name-face)
283 (3 font-lock-type-face))
284 )
285 "Font lock keywords used in `gdb-local-mode'.")
286
287 ;;;###autoload
288 (defun gdb (command-line)
289 "Run gdb on program FILE in buffer *gud-FILE*.
290 The directory containing FILE becomes the initial working directory
291 and source-file directory for your debugger.
292
293 If `gdb-many-windows' is nil (the default value) then gdb just
294 pops up the GUD buffer unless `gdb-show-main' is t. In this case
295 it starts with two windows: one displaying the GUD buffer and the
296 other with the source file with the main routine of the inferior.
297
298 If `gdb-many-windows' is t, regardless of the value of
299 `gdb-show-main', the layout below will appear unless
300 `gdb-use-separate-io-buffer' is nil when the source buffer
301 occupies the full width of the frame. Keybindings are shown in
302 some of the buffers.
303
304 Watch expressions appear in the speedbar/slowbar.
305
306 The following commands help control operation :
307
308 `gdb-many-windows' - Toggle the number of windows gdb uses.
309 `gdb-restore-windows' - To restore the window layout.
310
311 See Info node `(emacs)GDB Graphical Interface' for a more
312 detailed description of this mode.
313
314
315 +----------------------------------------------------------------------+
316 | GDB Toolbar |
317 +-----------------------------------+----------------------------------+
318 | GUD buffer (I/O of GDB) | Locals buffer |
319 | | |
320 | | |
321 | | |
322 +-----------------------------------+----------------------------------+
323 | Source buffer | I/O buffer (of debugged program) |
324 | | (comint-mode) |
325 | | |
326 | | |
327 | | |
328 | | |
329 | | |
330 | | |
331 +-----------------------------------+----------------------------------+
332 | Stack buffer | Breakpoints buffer |
333 | RET gdb-frames-select | SPC gdb-toggle-breakpoint |
334 | | RET gdb-goto-breakpoint |
335 | | D gdb-delete-breakpoint |
336 +-----------------------------------+----------------------------------+"
337 ;;
338 (interactive (list (gud-query-cmdline 'gdb)))
339
340 (when (and gud-comint-buffer
341 (buffer-name gud-comint-buffer)
342 (get-buffer-process gud-comint-buffer)
343 (with-current-buffer gud-comint-buffer (eq gud-minor-mode 'gdba)))
344 (gdb-restore-windows)
345 (error
346 "Multiple debugging requires restarting in text command mode"))
347 ;;
348 (gud-common-init command-line nil 'gud-gdbmi-marker-filter)
349 (set (make-local-variable 'gud-minor-mode) 'gdbmi)
350 (setq comint-input-sender 'gdb-send)
351
352 (gud-def gud-tbreak "tbreak %f:%l" "\C-t"
353 "Set temporary breakpoint at current line.")
354 (gud-def gud-jump
355 (progn (gud-call "tbreak %f:%l") (gud-call "jump %f:%l"))
356 "\C-j" "Set execution address to current line.")
357
358 (gud-def gud-up "up %p" "<" "Up N stack frames (numeric arg).")
359 (gud-def gud-down "down %p" ">" "Down N stack frames (numeric arg).")
360 (gud-def gud-print "print %e" "\C-p" "Evaluate C expression at point.")
361 (gud-def gud-pstar "print* %e" nil
362 "Evaluate C dereferenced pointer expression at point.")
363
364 (gud-def gud-step "-exec-step %p" "\C-s"
365 "Step one source line with display.")
366 (gud-def gud-stepi "-exec-step-instruction %p" "\C-i"
367 "Step one instruction with display.")
368 (gud-def gud-next "-exec-next %p" "\C-n"
369 "Step one line (skip functions).")
370 (gud-def gud-nexti "nexti %p" nil
371 "Step one instruction (skip functions).")
372 (gud-def gud-cont "-exec-continue" "\C-r"
373 "Continue with display.")
374 (gud-def gud-finish "-exec-finish" "\C-f"
375 "Finish executing current function.")
376 (gud-def gud-run "-exec-run" nil "Runn the program.")
377
378 (local-set-key "\C-i" 'gud-gdb-complete-command)
379 (setq gdb-first-prompt t)
380 (setq gud-running nil)
381 (gdb-update)
382 (run-hooks 'gdb-mode-hook))
383
384 (defun gdb-init-1 ()
385 (gud-def gud-break (if (not (string-equal mode-name "Machine"))
386 (gud-call "break %f:%l" arg)
387 (save-excursion
388 (beginning-of-line)
389 (forward-char 2)
390 (gud-call "break *%a" arg)))
391 "\C-b" "Set breakpoint at current line or address.")
392 ;;
393 (gud-def gud-remove (if (not (string-equal mode-name "Machine"))
394 (gud-call "clear %f:%l" arg)
395 (save-excursion
396 (beginning-of-line)
397 (forward-char 2)
398 (gud-call "clear *%a" arg)))
399 "\C-d" "Remove breakpoint at current line or address.")
400 ;;
401 (gud-def gud-until (if (not (string-equal mode-name "Machine"))
402 (gud-call "-exec-until %f:%l" arg)
403 (save-excursion
404 (beginning-of-line)
405 (forward-char 2)
406 (gud-call "-exec-until *%a" arg)))
407 "\C-u" "Continue to current line or address.")
408 ;;
409 (gud-def
410 gud-go (gud-call (if gdb-active-process "-exec-continue" "-exec-run") arg)
411 nil "Start or continue execution.")
412
413 ;; For debugging Emacs only.
414 (gud-def gud-pp
415 (gud-call
416 (concat
417 "pp1 " (if (eq (buffer-local-value
418 'major-mode (window-buffer)) 'speedbar-mode)
419 (gdb-find-watch-expression) "%e")) arg)
420 nil "Print the Emacs s-expression.")
421
422 (define-key gud-minor-mode-map [left-margin mouse-1]
423 'gdb-mouse-set-clear-breakpoint)
424 (define-key gud-minor-mode-map [left-fringe mouse-1]
425 'gdb-mouse-set-clear-breakpoint)
426 (define-key gud-minor-mode-map [left-margin C-mouse-1]
427 'gdb-mouse-toggle-breakpoint-margin)
428 (define-key gud-minor-mode-map [left-fringe C-mouse-1]
429 'gdb-mouse-toggle-breakpoint-fringe)
430
431 (define-key gud-minor-mode-map [left-margin drag-mouse-1]
432 'gdb-mouse-until)
433 (define-key gud-minor-mode-map [left-fringe drag-mouse-1]
434 'gdb-mouse-until)
435 (define-key gud-minor-mode-map [left-margin mouse-3]
436 'gdb-mouse-until)
437 (define-key gud-minor-mode-map [left-fringe mouse-3]
438 'gdb-mouse-until)
439
440 (define-key gud-minor-mode-map [left-margin C-drag-mouse-1]
441 'gdb-mouse-jump)
442 (define-key gud-minor-mode-map [left-fringe C-drag-mouse-1]
443 'gdb-mouse-jump)
444 (define-key gud-minor-mode-map [left-fringe C-mouse-3]
445 'gdb-mouse-jump)
446 (define-key gud-minor-mode-map [left-margin C-mouse-3]
447 'gdb-mouse-jump)
448 ;;
449 ;; (re-)initialise
450 (setq gdb-pc-address (if gdb-show-main "main" nil))
451 (setq gdb-selected-frame nil
452 gdb-frame-number nil
453 gdb-var-list nil
454 gdb-pending-triggers nil
455 gdb-output-sink 'user
456 gdb-location-alist nil
457 gdb-source-file-list nil
458 gdb-last-command nil
459 gdb-token-number 0
460 gdb-handler-alist '()
461 gdb-handler-number nil
462 gdb-prompt-name nil
463 gdb-first-done-or-error t
464 gdb-buffer-fringe-width (car (window-fringes))
465 gdb-debug-log nil
466 gdb-source-window nil
467 gdb-inferior-status nil
468 gdb-continuation nil)
469 ;;
470 (setq gdb-buffer-type 'gdbmi)
471 ;;
472 (gdb-force-mode-line-update
473 (propertize "initializing..." 'face font-lock-variable-name-face))
474
475 (when gdb-use-separate-io-buffer
476 (gdb-get-buffer-create 'gdb-inferior-io)
477 (gdb-clear-inferior-io)
478 (set-process-filter (get-process "gdb-inferior") 'gdb-inferior-filter)
479 (gdb-input
480 ;; Needs GDB 6.4 onwards
481 (list (concat "-inferior-tty-set "
482 (process-tty-name (get-process "gdb-inferior")) "\n")
483 'ignore)))
484 (if (eq window-system 'w32)
485 (gdb-input (list "-gdb-set new-console off\n" 'ignore)))
486 (gdb-input (list "-gdb-set height 0\n" 'ignore))
487 ;; find source file and compilation directory here
488 (gdb-input
489 ; Needs GDB 6.2 onwards.
490 (list "-file-list-exec-source-files\n" 'gdb-get-source-file-list))
491 (if gdb-create-source-file-list
492 (gdb-input
493 ; Needs GDB 6.0 onwards.
494 (list "-file-list-exec-source-file\n" 'gdb-get-source-file)))
495 (gdb-input
496 (list "-data-list-register-names\n" 'gdb-get-register-names))
497 (gdb-input
498 (list "-gdb-show prompt\n" 'gdb-get-prompt)))
499
500 (defvar gdb-define-alist nil "Alist of #define directives for GUD tooltips.")
501
502 (defun gdb-create-define-alist ()
503 "Create an alist of #define directives for GUD tooltips."
504 (let* ((file (buffer-file-name))
505 (output
506 (with-output-to-string
507 (with-current-buffer standard-output
508 (and file
509 (file-exists-p file)
510 ;; call-process doesn't work with remote file names.
511 (not (file-remote-p default-directory))
512 (call-process shell-file-name file
513 (list t nil) nil "-c"
514 (concat gdb-cpp-define-alist-program " "
515 gdb-cpp-define-alist-flags))))))
516 (define-list (split-string output "\n" t))
517 (name))
518 (setq gdb-define-alist nil)
519 (dolist (define define-list)
520 (setq name (nth 1 (split-string define "[( ]")))
521 (push (cons name define) gdb-define-alist))))
522
523 (declare-function tooltip-show "tooltip" (text &optional use-echo-area))
524 (defvar tooltip-use-echo-area)
525
526 (defun gdb-tooltip-print (expr)
527 (tooltip-show
528 (with-current-buffer (gdb-get-buffer 'gdb-partial-output-buffer)
529 (goto-char (point-min))
530 (let ((string
531 (if (search-forward "=" nil t)
532 (concat expr (buffer-substring (- (point) 2) (point-max)))
533 (buffer-string))))
534 ;; remove newline for gud-tooltip-echo-area
535 (substring string 0 (- (length string) 1))))
536 (or gud-tooltip-echo-area tooltip-use-echo-area
537 (not (display-graphic-p)))))
538
539 ;; If expr is a macro for a function don't print because of possible dangerous
540 ;; side-effects. Also printing a function within a tooltip generates an
541 ;; unexpected starting annotation (phase error).
542 (defun gdb-tooltip-print-1 (expr)
543 (with-current-buffer (gdb-get-buffer 'gdb-partial-output-buffer)
544 (goto-char (point-min))
545 (if (search-forward "expands to: " nil t)
546 (unless (looking-at "\\S-+.*(.*).*")
547 (gdb-input
548 (list (concat "print " expr "\n")
549 `(lambda () (gdb-tooltip-print ,expr))))))))
550
551 (defun gdb-init-buffer ()
552 (set (make-local-variable 'gud-minor-mode) 'gdbmi)
553 (set (make-local-variable 'tool-bar-map) gud-tool-bar-map)
554 (when gud-tooltip-mode
555 (make-local-variable 'gdb-define-alist)
556 (gdb-create-define-alist)
557 (add-hook 'after-save-hook 'gdb-create-define-alist nil t)))
558
559 (defmacro gdb-if-arrow (arrow-position &rest body)
560 `(if ,arrow-position
561 (let ((buffer (marker-buffer ,arrow-position)) (line))
562 (if (equal buffer (window-buffer (posn-window end)))
563 (with-current-buffer buffer
564 (when (or (equal start end)
565 (equal (posn-point start)
566 (marker-position ,arrow-position)))
567 ,@body))))))
568
569 (defun gdb-mouse-until (event)
570 "Continue running until a source line past the current line.
571 The destination source line can be selected either by clicking
572 with mouse-3 on the fringe/margin or dragging the arrow
573 with mouse-1 (default bindings)."
574 (interactive "e")
575 (let ((start (event-start event))
576 (end (event-end event)))
577 (gdb-if-arrow gud-overlay-arrow-position
578 (setq line (line-number-at-pos (posn-point end)))
579 (gud-call (concat "until " (number-to-string line))))
580 (gdb-if-arrow gdb-overlay-arrow-position
581 (save-excursion
582 (goto-line (line-number-at-pos (posn-point end)))
583 (forward-char 2)
584 (gud-call (concat "until *%a"))))))
585
586 (defun gdb-mouse-jump (event)
587 "Set execution address/line.
588 The destination source line can be selected either by clicking with C-mouse-3
589 on the fringe/margin or dragging the arrow with C-mouse-1 (default bindings).
590 Unlike `gdb-mouse-until' the destination address can be before the current
591 line, and no execution takes place."
592 (interactive "e")
593 (let ((start (event-start event))
594 (end (event-end event)))
595 (gdb-if-arrow gud-overlay-arrow-position
596 (setq line (line-number-at-pos (posn-point end)))
597 (progn
598 (gud-call (concat "tbreak " (number-to-string line)))
599 (gud-call (concat "jump " (number-to-string line)))))
600 (gdb-if-arrow gdb-overlay-arrow-position
601 (save-excursion
602 (goto-line (line-number-at-pos (posn-point end)))
603 (forward-char 2)
604 (progn
605 (gud-call (concat "tbreak *%a"))
606 (gud-call (concat "jump *%a")))))))
607
608 (defcustom gdb-show-changed-values t
609 "If non-nil change the face of out of scope variables and changed values.
610 Out of scope variables are suppressed with `shadow' face.
611 Changed values are highlighted with the face `font-lock-warning-face'."
612 :type 'boolean
613 :group 'gdb
614 :version "22.1")
615
616 (defcustom gdb-max-children 40
617 "Maximum number of children before expansion requires confirmation."
618 :type 'integer
619 :group 'gdb
620 :version "22.1")
621
622 (defcustom gdb-delete-out-of-scope t
623 "If non-nil delete watch expressions automatically when they go out of scope."
624 :type 'boolean
625 :group 'gdb
626 :version "22.2")
627
628 (defcustom gdb-speedbar-auto-raise nil
629 "If non-nil raise speedbar every time display of watch expressions is\
630 updated."
631 :type 'boolean
632 :group 'gdb
633 :version "22.1")
634
635 (defcustom gdb-use-colon-colon-notation nil
636 "If non-nil use FUN::VAR format to display variables in the speedbar."
637 :type 'boolean
638 :group 'gdb
639 :version "22.1")
640
641 (defun gdb-speedbar-auto-raise (arg)
642 "Toggle automatic raising of the speedbar for watch expressions.
643 With prefix argument ARG, automatically raise speedbar if ARG is
644 positive, otherwise don't automatically raise it."
645 (interactive "P")
646 (setq gdb-speedbar-auto-raise
647 (if (null arg)
648 (not gdb-speedbar-auto-raise)
649 (> (prefix-numeric-value arg) 0)))
650 (message (format "Auto raising %sabled"
651 (if gdb-speedbar-auto-raise "en" "dis"))))
652
653 (define-key gud-minor-mode-map "\C-c\C-w" 'gud-watch)
654 (define-key global-map (concat gud-key-prefix "\C-w") 'gud-watch)
655
656 (declare-function tooltip-identifier-from-point "tooltip" (point))
657
658 (defun gud-watch (&optional arg event)
659 "Watch expression at point.
660 With arg, enter name of variable to be watched in the minibuffer."
661 (interactive (list current-prefix-arg last-input-event))
662 (let ((minor-mode (buffer-local-value 'gud-minor-mode gud-comint-buffer)))
663 (if (eq minor-mode 'gdbmi)
664 (progn
665 (if event (posn-set-point (event-end event)))
666 (require 'tooltip)
667 (save-selected-window
668 (let ((expr
669 (if arg
670 (completing-read "Name of variable: "
671 'gud-gdb-complete-command)
672 (if (and transient-mark-mode mark-active)
673 (buffer-substring (region-beginning) (region-end))
674 (concat (if (eq major-mode 'gdb-registers-mode) "$")
675 (tooltip-identifier-from-point (point)))))))
676 (set-text-properties 0 (length expr) nil expr)
677 (gdb-input
678 (list (concat"-var-create - * " expr "\n")
679 `(lambda () (gdb-var-create-handler ,expr)))))))
680 (message "gud-watch is a no-op in this mode."))))
681
682 (defconst gdb-var-create-regexp
683 "name=\"\\(.*?\\)\",.*numchild=\"\\(.*?\\)\",\\(?:.*value=\\(\".*\"\\),\\)?.*type=\"\\(.*?\\)\"")
684
685 (defun gdb-var-create-handler (expr)
686 (goto-char (point-min))
687 (if (re-search-forward gdb-var-create-regexp nil t)
688 (let ((var (list
689 (match-string 1)
690 (if (and (string-equal gdb-current-language "c")
691 gdb-use-colon-colon-notation gdb-selected-frame)
692 (setq expr (concat gdb-selected-frame "::" expr))
693 expr)
694 (match-string 2)
695 (match-string 4)
696 (if (match-string 3) (read (match-string 3)))
697 nil)))
698 (push var gdb-var-list)
699 (speedbar 1)
700 (unless (string-equal
701 speedbar-initial-expansion-list-name "GUD")
702 (speedbar-change-initial-expansion-list "GUD"))
703 (gdb-input
704 (list
705 (concat "-var-evaluate-expression " (car var) "\n")
706 `(lambda () (gdb-var-evaluate-expression-handler
707 ,(car var) nil)))))
708 (message-box "No symbol \"%s\" in current context." expr)))
709
710 (defun gdb-speedbar-update ()
711 (when (and (boundp 'speedbar-frame) (frame-live-p speedbar-frame)
712 (not (member 'gdb-speedbar-timer gdb-pending-triggers)))
713 ;; Dummy command to update speedbar even when idle.
714 (gdb-input (list "-environment-pwd\n" 'gdb-speedbar-timer-fn))
715 ;; Keep gdb-pending-triggers non-nil till end.
716 (push 'gdb-speedbar-timer gdb-pending-triggers)))
717
718 (defun gdb-speedbar-timer-fn ()
719 (if gdb-speedbar-auto-raise
720 (raise-frame speedbar-frame))
721 (setq gdb-pending-triggers
722 (delq 'gdb-speedbar-timer gdb-pending-triggers))
723 (speedbar-timer-fn))
724
725 (defun gdb-var-evaluate-expression-handler (varnum changed)
726 (goto-char (point-min))
727 (re-search-forward ".*value=\\(\".*\"\\)" nil t)
728 (let ((var (assoc varnum gdb-var-list)))
729 (when var
730 (if changed (setcar (nthcdr 5 var) 'changed))
731 (setcar (nthcdr 4 var) (read (match-string 1)))))
732 (gdb-speedbar-update))
733
734 ; Uses "-var-list-children --all-values". Needs GDB 6.1 onwards.
735 (defun gdb-var-list-children (varnum)
736 (gdb-input
737 (list (concat "-var-update " varnum "\n") 'ignore))
738 (gdb-input
739 (list (concat "-var-list-children --all-values "
740 varnum "\n")
741 `(lambda () (gdb-var-list-children-handler ,varnum)))))
742
743 (defconst gdb-var-list-children-regexp
744 "child={.*?name=\"\\(.+?\\)\".*?,exp=\"\\(.+?\\)\".*?,\
745 numchild=\"\\(.+?\\)\".*?,value=\\(\".*?\"\\).*?,type=\"\\(.+?\\)\".*?}")
746
747 (defun gdb-var-list-children-handler (varnum)
748 (goto-char (point-min))
749 (let ((var-list nil))
750 (catch 'child-already-watched
751 (dolist (var gdb-var-list)
752 (if (string-equal varnum (car var))
753 (progn
754 (push var var-list)
755 (while (re-search-forward gdb-var-list-children-regexp nil t)
756 (let ((varchild (list (match-string 1)
757 (match-string 2)
758 (match-string 3)
759 (match-string 5)
760 (read (match-string 4))
761 nil)))
762 (if (assoc (car varchild) gdb-var-list)
763 (throw 'child-already-watched nil))
764 (push varchild var-list))))
765 (push var var-list)))
766 (setq gdb-var-list (nreverse var-list))))
767 (gdb-speedbar-update))
768
769 (defun gdb-var-set-format (format)
770 "Set the output format for a variable displayed in the speedbar."
771 (let* ((var (nth (- (count-lines (point-min) (point)) 2) gdb-var-list))
772 (varnum (car var)))
773 (gdb-input
774 (list (concat "-var-set-format " varnum " " format "\n") 'ignore))
775 (gdb-var-update)))
776
777 (defun gdb-var-delete-1 (varnum)
778 (gdb-input
779 (list (concat "-var-delete " varnum "\n") 'ignore))
780 (setq gdb-var-list (delq var gdb-var-list))
781 (dolist (varchild gdb-var-list)
782 (if (string-match (concat (car var) "\\.") (car varchild))
783 (setq gdb-var-list (delq varchild gdb-var-list)))))
784
785 (defun gdb-var-delete ()
786 "Delete watch expression at point from the speedbar."
787 (interactive)
788 (let ((text (speedbar-line-text)))
789 (string-match "\\(\\S-+\\)" text)
790 (let* ((var (nth (- (count-lines (point-min) (point)) 2) gdb-var-list))
791 (varnum (car var)))
792 (if (string-match "\\." (car var))
793 (message-box "Can only delete a root expression")
794 (gdb-var-delete-1 varnum)))))
795
796 (defun gdb-var-delete-children (varnum)
797 "Delete children of variable object at point from the speedbar."
798 (gdb-input
799 (list (concat "-var-delete -c " varnum "\n") 'ignore)))
800
801 (defun gdb-edit-value (text token indent)
802 "Assign a value to a variable displayed in the speedbar."
803 (let* ((var (nth (- (count-lines (point-min) (point)) 2) gdb-var-list))
804 (varnum (car var)) (value))
805 (setq value (read-string "New value: "))
806 (gdb-input
807 (list (concat "-var-assign " varnum " " value "\n")
808 `(lambda () (gdb-edit-value-handler ,value))))))
809
810 (defconst gdb-error-regexp "\\^error,msg=\\(\".+\"\\)")
811
812 (defun gdb-edit-value-handler (value)
813 (goto-char (point-min))
814 (if (re-search-forward gdb-error-regexp nil t)
815 (message-box "Invalid number or expression (%s)" value)))
816
817 ; Uses "-var-update --all-values". Needs GDB 6.4 onwards.
818 (defun gdb-var-update ()
819 (if (not (member 'gdb-var-update gdb-pending-triggers))
820 (gdb-input
821 (list "-var-update --all-values *\n" 'gdb-var-update-handler)))
822 (push 'gdb-var-update gdb-pending-triggers))
823
824 (defconst gdb-var-update-regexp
825 "{.*?name=\"\\(.*?\\)\".*?,\\(?:value=\\(\".*?\"\\),\\)?.*?\
826 in_scope=\"\\(.*?\\)\".*?}")
827
828 (defun gdb-var-update-handler ()
829 (dolist (var gdb-var-list)
830 (setcar (nthcdr 5 var) nil))
831 (goto-char (point-min))
832 (while (re-search-forward gdb-var-update-regexp nil t)
833 (let* ((varnum (match-string 1))
834 (var (assoc varnum gdb-var-list)))
835 (when var
836 (let ((match (match-string 3)))
837 (cond ((string-equal match "false")
838 (if gdb-delete-out-of-scope
839 (gdb-var-delete-1 varnum)
840 (setcar (nthcdr 5 var) 'out-of-scope)))
841 ((string-equal match "true")
842 (setcar (nthcdr 5 var) 'changed)
843 (setcar (nthcdr 4 var)
844 (read (match-string 2))))
845 ((string-equal match "invalid")
846 (gdb-var-delete-1 varnum)))))))
847 (setq gdb-pending-triggers
848 (delq 'gdb-var-update gdb-pending-triggers))
849 (gdb-speedbar-update))
850
851 (defun gdb-speedbar-expand-node (text token indent)
852 "Expand the node the user clicked on.
853 TEXT is the text of the button we clicked on, a + or - item.
854 TOKEN is data related to this node.
855 INDENT is the current indentation depth."
856 (cond ((string-match "+" text) ;expand this node
857 (let* ((var (assoc token gdb-var-list))
858 (expr (nth 1 var)) (children (nth 2 var)))
859 (if (or (<= (string-to-number children) gdb-max-children)
860 (y-or-n-p
861 (format "%s has %s children. Continue? " expr children)))
862 (gdb-var-list-children token))))
863 ((string-match "-" text) ;contract this node
864 (dolist (var gdb-var-list)
865 (if (string-match (concat token "\\.") (car var))
866 (setq gdb-var-list (delq var gdb-var-list))))
867 (gdb-var-delete-children token)
868 (speedbar-change-expand-button-char ?+)
869 (speedbar-delete-subblock indent))
870 (t (error "Ooops... not sure what to do")))
871 (speedbar-center-buffer-smartly))
872
873 (defun gdb-get-target-string ()
874 (with-current-buffer gud-comint-buffer
875 gud-target-name))
876 \f
877
878 ;;
879 ;; gdb buffers.
880 ;;
881 ;; Each buffer has a TYPE -- a symbol that identifies the function
882 ;; of that particular buffer.
883 ;;
884 ;; The usual gdb interaction buffer is given the type `gdbmi' and
885 ;; is constructed specially.
886 ;;
887 ;; Others are constructed by gdb-get-buffer-create and
888 ;; named according to the rules set forth in the gdb-buffer-rules-assoc
889
890 (defvar gdb-buffer-rules-assoc '())
891
892 (defun gdb-get-buffer (key)
893 "Return the gdb buffer tagged with type KEY.
894 The key should be one of the cars in `gdb-buffer-rules-assoc'."
895 (save-excursion
896 (gdb-look-for-tagged-buffer key (buffer-list))))
897
898 (defun gdb-get-buffer-create (key)
899 "Create a new gdb buffer of the type specified by KEY.
900 The key should be one of the cars in `gdb-buffer-rules-assoc'."
901 (or (gdb-get-buffer key)
902 (let* ((rules (assoc key gdb-buffer-rules-assoc))
903 (name (funcall (gdb-rules-name-maker rules)))
904 (new (get-buffer-create name)))
905 (with-current-buffer new
906 (let ((trigger))
907 (if (cdr (cdr rules))
908 (setq trigger (funcall (car (cdr (cdr rules))))))
909 (setq gdb-buffer-type key)
910 (set (make-local-variable 'gud-minor-mode)
911 (buffer-local-value 'gud-minor-mode gud-comint-buffer))
912 (set (make-local-variable 'tool-bar-map) gud-tool-bar-map)
913 (if trigger (funcall trigger)))
914 new))))
915
916 (defun gdb-rules-name-maker (rules) (car (cdr rules)))
917
918 (defun gdb-look-for-tagged-buffer (key bufs)
919 (let ((retval nil))
920 (while (and (not retval) bufs)
921 (set-buffer (car bufs))
922 (if (eq gdb-buffer-type key)
923 (setq retval (car bufs)))
924 (setq bufs (cdr bufs)))
925 retval))
926
927 ;; Used to define all gdb-frame-*-buffer functions except
928 ;; `gdb-frame-separate-io-buffer'
929 (defmacro def-gdb-frame-for-buffer (name buffer &optional doc)
930 "Define a function NAME which shows gdb BUFFER in a separate frame.
931
932 DOC is an optional documentation string."
933 `(defun ,name ()
934 ,(when doc doc)
935 (interactive)
936 (let ((special-display-regexps (append special-display-regexps '(".*")))
937 (special-display-frame-alist gdb-frame-parameters))
938 (display-buffer (gdb-get-buffer-create ,buffer)))))
939
940 (defmacro def-gdb-display-buffer (name buffer &optional doc)
941 "Define a function NAME which shows gdb BUFFER.
942
943 DOC is an optional documentation string."
944 `(defun ,name ()
945 ,(when doc doc)
946 (interactive)
947 (gdb-display-buffer
948 (gdb-get-buffer-create ,buffer) t)))
949
950 ;;
951 ;; This assoc maps buffer type symbols to rules. Each rule is a list of
952 ;; at least one and possible more functions. The functions have these
953 ;; roles in defining a buffer type:
954 ;;
955 ;; NAME - Return a name for this buffer type.
956 ;;
957 ;; The remaining function(s) are optional:
958 ;;
959 ;; MODE - called in a new buffer with no arguments, should establish
960 ;; the proper mode for the buffer.
961 ;;
962
963 (defun gdb-set-buffer-rules (buffer-type &rest rules)
964 (let ((binding (assoc buffer-type gdb-buffer-rules-assoc)))
965 (if binding
966 (setcdr binding rules)
967 (push (cons buffer-type rules)
968 gdb-buffer-rules-assoc))))
969
970 ;; GUD buffers are an exception to the rules
971 (gdb-set-buffer-rules 'gdbmi 'error)
972
973 ;; Partial-output buffer : This accumulates output from a command executed on
974 ;; behalf of emacs (rather than the user).
975 ;;
976 (gdb-set-buffer-rules 'gdb-partial-output-buffer
977 'gdb-partial-output-name)
978
979 (defun gdb-partial-output-name ()
980 (concat " *partial-output-"
981 (gdb-get-target-string)
982 "*"))
983
984 \f
985 (gdb-set-buffer-rules 'gdb-inferior-io
986 'gdb-inferior-io-name
987 'gdb-inferior-io-mode)
988
989 (defun gdb-inferior-io-name ()
990 (concat "*input/output of "
991 (gdb-get-target-string)
992 "*"))
993
994 (defun gdb-display-separate-io-buffer ()
995 "Display IO of debugged program in a separate window."
996 (interactive)
997 (if gdb-use-separate-io-buffer
998 (gdb-display-buffer
999 (gdb-get-buffer-create 'gdb-inferior-io) t)))
1000
1001 (defconst gdb-frame-parameters
1002 '((height . 14) (width . 80)
1003 (unsplittable . t)
1004 (tool-bar-lines . nil)
1005 (menu-bar-lines . nil)
1006 (minibuffer . nil)))
1007
1008 (defun gdb-frame-separate-io-buffer ()
1009 "Display IO of debugged program in a new frame."
1010 (interactive)
1011 (if gdb-use-separate-io-buffer
1012 (let ((special-display-regexps (append special-display-regexps '(".*")))
1013 (special-display-frame-alist gdb-frame-parameters))
1014 (display-buffer (gdb-get-buffer-create 'gdb-inferior-io)))))
1015
1016 (defvar gdb-inferior-io-mode-map
1017 (let ((map (make-sparse-keymap)))
1018 (define-key map "\C-c\C-c" 'gdb-separate-io-interrupt)
1019 (define-key map "\C-c\C-z" 'gdb-separate-io-stop)
1020 (define-key map "\C-c\C-\\" 'gdb-separate-io-quit)
1021 (define-key map "\C-c\C-d" 'gdb-separate-io-eof)
1022 (define-key map "\C-d" 'gdb-separate-io-eof)
1023 map))
1024
1025 (define-derived-mode gdb-inferior-io-mode comint-mode "Inferior I/O"
1026 "Major mode for gdb inferior-io."
1027 :syntax-table nil :abbrev-table nil
1028 ;; We want to use comint because it has various nifty and familiar
1029 ;; features. We don't need a process, but comint wants one, so create
1030 ;; a dummy one.
1031 (make-comint-in-buffer
1032 "gdb-inferior" (current-buffer) "sleep" nil "1000000000"))
1033
1034 (defun gdb-inferior-filter (proc string)
1035 (unless (string-equal string "")
1036 (gdb-display-buffer (gdb-get-buffer-create 'gdb-inferior-io) t))
1037 (with-current-buffer (gdb-get-buffer-create 'gdb-inferior-io)
1038 (insert-before-markers string)))
1039
1040 (defun gdb-separate-io-interrupt ()
1041 "Interrupt the program being debugged."
1042 (interactive)
1043 (interrupt-process
1044 (get-buffer-process gud-comint-buffer) comint-ptyp))
1045
1046 (defun gdb-separate-io-quit ()
1047 "Send quit signal to the program being debugged."
1048 (interactive)
1049 (quit-process
1050 (get-buffer-process gud-comint-buffer) comint-ptyp))
1051
1052 (defun gdb-separate-io-stop ()
1053 "Stop the program being debugged."
1054 (interactive)
1055 (stop-process
1056 (get-buffer-process gud-comint-buffer) comint-ptyp))
1057
1058 (defun gdb-separate-io-eof ()
1059 "Send end-of-file to the program being debugged."
1060 (interactive)
1061 (process-send-eof
1062 (get-buffer-process gud-comint-buffer)))
1063
1064 (defun gdb-clear-inferior-io ()
1065 (with-current-buffer (gdb-get-buffer-create 'gdb-inferior-io)
1066 (erase-buffer)))
1067 \f
1068
1069 (defconst breakpoint-xpm-data
1070 "/* XPM */
1071 static char *magick[] = {
1072 /* columns rows colors chars-per-pixel */
1073 \"10 10 2 1\",
1074 \" c red\",
1075 \"+ c None\",
1076 /* pixels */
1077 \"+++ +++\",
1078 \"++ ++\",
1079 \"+ +\",
1080 \" \",
1081 \" \",
1082 \" \",
1083 \" \",
1084 \"+ +\",
1085 \"++ ++\",
1086 \"+++ +++\",
1087 };"
1088 "XPM data used for breakpoint icon.")
1089
1090 (defconst breakpoint-enabled-pbm-data
1091 "P1
1092 10 10\",
1093 0 0 0 0 1 1 1 1 0 0 0 0
1094 0 0 0 1 1 1 1 1 1 0 0 0
1095 0 0 1 1 1 1 1 1 1 1 0 0
1096 0 1 1 1 1 1 1 1 1 1 1 0
1097 0 1 1 1 1 1 1 1 1 1 1 0
1098 0 1 1 1 1 1 1 1 1 1 1 0
1099 0 1 1 1 1 1 1 1 1 1 1 0
1100 0 0 1 1 1 1 1 1 1 1 0 0
1101 0 0 0 1 1 1 1 1 1 0 0 0
1102 0 0 0 0 1 1 1 1 0 0 0 0"
1103 "PBM data used for enabled breakpoint icon.")
1104
1105 (defconst breakpoint-disabled-pbm-data
1106 "P1
1107 10 10\",
1108 0 0 1 0 1 0 1 0 0 0
1109 0 1 0 1 0 1 0 1 0 0
1110 1 0 1 0 1 0 1 0 1 0
1111 0 1 0 1 0 1 0 1 0 1
1112 1 0 1 0 1 0 1 0 1 0
1113 0 1 0 1 0 1 0 1 0 1
1114 1 0 1 0 1 0 1 0 1 0
1115 0 1 0 1 0 1 0 1 0 1
1116 0 0 1 0 1 0 1 0 1 0
1117 0 0 0 1 0 1 0 1 0 0"
1118 "PBM data used for disabled breakpoint icon.")
1119
1120 (defvar breakpoint-enabled-icon nil
1121 "Icon for enabled breakpoint in display margin.")
1122
1123 (defvar breakpoint-disabled-icon nil
1124 "Icon for disabled breakpoint in display margin.")
1125
1126 (declare-function define-fringe-bitmap "fringe.c"
1127 (bitmap bits &optional height width align))
1128
1129 (and (display-images-p)
1130 ;; Bitmap for breakpoint in fringe
1131 (define-fringe-bitmap 'breakpoint
1132 "\x3c\x7e\xff\xff\xff\xff\x7e\x3c")
1133 ;; Bitmap for gud-overlay-arrow in fringe
1134 (define-fringe-bitmap 'hollow-right-triangle
1135 "\xe0\x90\x88\x84\x84\x88\x90\xe0"))
1136
1137 (defface breakpoint-enabled
1138 '((t
1139 :foreground "red1"
1140 :weight bold))
1141 "Face for enabled breakpoint icon in fringe."
1142 :group 'gdb)
1143
1144 (defface breakpoint-disabled
1145 '((((class color) (min-colors 88)) :foreground "grey70")
1146 ;; Ensure that on low-color displays that we end up something visible.
1147 (((class color) (min-colors 8) (background light))
1148 :foreground "black")
1149 (((class color) (min-colors 8) (background dark))
1150 :foreground "white")
1151 (((type tty) (class mono))
1152 :inverse-video t)
1153 (t :background "gray"))
1154 "Face for disabled breakpoint icon in fringe."
1155 :group 'gdb)
1156
1157 \f
1158 (defun gdb-send (proc string)
1159 "A comint send filter for gdb."
1160 (with-current-buffer gud-comint-buffer
1161 (let ((inhibit-read-only t))
1162 (remove-text-properties (point-min) (point-max) '(face))))
1163 ;; mimic <RET> key to repeat previous command in GDB
1164 (if (not (string-match "^\\s+$" string))
1165 (setq gdb-last-command string)
1166 (if gdb-last-command (setq string gdb-last-command)))
1167 (if gdb-enable-debug
1168 (push (cons 'mi-send (concat string "\n")) gdb-debug-log))
1169 (if (string-match "^-" string)
1170 ;; MI command
1171 (progn
1172 (setq gdb-first-done-or-error t)
1173 (process-send-string proc (concat string "\n")))
1174 ;; CLI command
1175 (if (string-match "\\\\$" string)
1176 (setq gdb-continuation (concat gdb-continuation string "\n"))
1177 (setq gdb-first-done-or-error t)
1178 (process-send-string proc (concat "-interpreter-exec console \""
1179 gdb-continuation string "\"\n"))
1180 (setq gdb-continuation nil))))
1181
1182 (defun gdb-input (item)
1183 (if gdb-enable-debug (push (cons 'send-item item) gdb-debug-log))
1184 (setq gdb-token-number (1+ gdb-token-number))
1185 (setcar item (concat (number-to-string gdb-token-number) (car item)))
1186 (push (cons gdb-token-number (car (cdr item))) gdb-handler-alist)
1187 (process-send-string (get-buffer-process gud-comint-buffer)
1188 (car item)))
1189 \f
1190
1191 (defcustom gud-gdb-command-name "gdb -i=mi"
1192 "Default command to execute an executable under the GDB debugger."
1193 :type 'string
1194 :group 'gdb)
1195
1196 (defun gdb-resync()
1197 (setq gud-running nil)
1198 (setq gdb-output-sink 'user)
1199 (setq gdb-pending-triggers nil))
1200
1201 (defun gdb-update ()
1202 "Update buffers showing status of debug session."
1203 (when gdb-first-prompt
1204 (gdb-force-mode-line-update
1205 (propertize "initializing..." 'face font-lock-variable-name-face))
1206 (gdb-init-1)
1207 (setq gdb-first-prompt nil))
1208 (gdb-get-selected-frame)
1209 (gdb-invalidate-frames)
1210 ;; Regenerate breakpoints buffer in case it has been inadvertantly deleted.
1211 (gdb-get-buffer-create 'gdb-breakpoints-buffer)
1212 (gdb-invalidate-breakpoints)
1213 (gdb-invalidate-threads)
1214 (gdb-get-changed-registers)
1215 (gdb-invalidate-registers)
1216 (gdb-invalidate-locals)
1217 (gdb-invalidate-memory)
1218 (when (and (boundp 'speedbar-frame) (frame-live-p speedbar-frame))
1219 (dolist (var gdb-var-list)
1220 (setcar (nthcdr 5 var) nil))
1221 (gdb-var-update)))
1222
1223 ;; GUD displays the selected GDB frame. This might might not be the current
1224 ;; GDB frame (after up, down etc). If no GDB frame is visible but the last
1225 ;; visited breakpoint is, use that window.
1226 (defun gdb-display-source-buffer (buffer)
1227 (let* ((last-window (if gud-last-last-frame
1228 (get-buffer-window
1229 (gud-find-file (car gud-last-last-frame)))))
1230 (source-window (or last-window
1231 (if (and gdb-source-window
1232 (window-live-p gdb-source-window))
1233 gdb-source-window))))
1234 (when source-window
1235 (setq gdb-source-window source-window)
1236 (set-window-buffer source-window buffer))
1237 source-window))
1238
1239 (defun gdb-car< (a b)
1240 (< (car a) (car b)))
1241
1242 (defvar gdbmi-record-list
1243 '((gdb-gdb . "(gdb) \n")
1244 (gdb-done . "\\([0-9]*\\)\\^done,?\\(.*?\\)\n")
1245 (gdb-starting . "\\([0-9]*\\)\\^running\n")
1246 (gdb-error . "\\([0-9]*\\)\\^error,\\(.*?\\)\n")
1247 (gdb-console . "~\\(\".*?\"\\)\n")
1248 (gdb-internals . "&\\(\".*?\"\\)\n")
1249 (gdb-stopped . "\\*stopped,?\\(.*?\n\\)")
1250 (gdb-running . "\\*running,\\(.*?\n\\)")
1251 (gdb-thread-created . "=thread-created,\\(.*?\n\\)")
1252 (gdb-thread-exited . "=thread-exited,\\(.*?\n\\)")))
1253
1254 (defun gud-gdbmi-marker-filter (string)
1255 "Filter GDB/MI output."
1256
1257 ;; Record transactions if logging is enabled.
1258 (when gdb-enable-debug
1259 (push (cons 'recv string) gdb-debug-log)
1260 (if (and gdb-debug-log-max
1261 (> (length gdb-debug-log) gdb-debug-log-max))
1262 (setcdr (nthcdr (1- gdb-debug-log-max) gdb-debug-log) nil)))
1263
1264 ;; Recall the left over gud-marker-acc from last time
1265 (setq gud-marker-acc (concat gud-marker-acc string))
1266
1267 ;; Start accumulating output for the GUD buffer
1268 (setq gdb-filter-output "")
1269 (let ((output-record) (output-record-list))
1270
1271 ;; Process all the complete markers in this chunk.
1272 (dolist (gdbmi-record gdbmi-record-list)
1273 (while (string-match (cdr gdbmi-record) gud-marker-acc)
1274 (push (list (match-beginning 0)
1275 (car gdbmi-record)
1276 (match-string 1 gud-marker-acc)
1277 (match-string 2 gud-marker-acc)
1278 (match-end 0))
1279 output-record-list)
1280 (setq gud-marker-acc
1281 (concat (substring gud-marker-acc 0 (match-beginning 0))
1282 ;; Pad with spaces to preserve position.
1283 (make-string (length (match-string 0 gud-marker-acc)) 32)
1284 (substring gud-marker-acc (match-end 0))))))
1285
1286 (setq output-record-list (sort output-record-list 'gdb-car<))
1287
1288 (dolist (output-record output-record-list)
1289 (let ((record-type (cadr output-record))
1290 (arg1 (nth 2 output-record))
1291 (arg2 (nth 3 output-record)))
1292 (if (eq record-type 'gdb-error)
1293 (gdb-done-or-error arg2 arg1 'error)
1294 (if (eq record-type 'gdb-done)
1295 (gdb-done-or-error arg2 arg1 'done)
1296 ;; Suppress "No registers." since GDB 6.8 and earlier duplicates MI
1297 ;; error message on internal stream. Don't print to GUD buffer.
1298 (unless (and (eq record-type 'gdb-internals)
1299 (string-equal (read arg1) "No registers.\n"))
1300 (funcall record-type arg1))))))
1301
1302 (setq gdb-output-sink 'user)
1303 ;; Remove padding.
1304 (string-match "^ *" gud-marker-acc)
1305 (setq gud-marker-acc (substring gud-marker-acc (match-end 0)))
1306
1307 gdb-filter-output))
1308
1309 (defun gdb-gdb (output-field))
1310 (defun gdb-thread-created (output-field))
1311 (defun gdb-thread-exited (output-field))
1312
1313 (defun gdb-running (output-field)
1314 (setq gdb-inferior-status "running")
1315 (gdb-force-mode-line-update
1316 (propertize gdb-inferior-status 'face font-lock-type-face))
1317 (setq gdb-active-process t)
1318 (setq gud-running t))
1319
1320 (defun gdb-starting (output-field)
1321 ;; CLI commands don't emit ^running at the moment so use gdb-running too.
1322 (setq gdb-inferior-status "running")
1323 (gdb-force-mode-line-update
1324 (propertize gdb-inferior-status 'face font-lock-type-face))
1325 (setq gdb-active-process t)
1326 (setq gud-running t))
1327
1328 ;; -break-insert -t didn't give a reason before gdb 6.9
1329 (defconst gdb-stopped-regexp
1330 "\\(reason=\"\\(.*?\\)\"\\)?\\(\\(,exit-code=.*?\\)*\n\\|.*?,file=\".*?\".*?,fullname=\"\\(.*?\\)\".*?,line=\"\\(.*?\\)\".*?\n\\)")
1331
1332 (defun gdb-stopped (output-field)
1333 (setq gud-running nil)
1334 (string-match gdb-stopped-regexp output-field)
1335 (let ((reason (match-string 2 output-field))
1336 (file (match-string 5 output-field)))
1337
1338 ;;; Don't set gud-last-frame here as it's currently done in gdb-frame-handler
1339 ;;; because synchronous GDB doesn't give these fields with CLI.
1340 ;;; (when file
1341 ;;; (setq
1342 ;;; ;; Extract the frame position from the marker.
1343 ;;; gud-last-frame (cons file
1344 ;;; (string-to-number
1345 ;;; (match-string 6 gud-marker-acc)))))
1346
1347 (setq gdb-inferior-status (if reason reason "unknown"))
1348 (gdb-force-mode-line-update
1349 (propertize gdb-inferior-status 'face font-lock-warning-face))
1350 (if (string-equal reason "exited-normally")
1351 (setq gdb-active-process nil)))
1352
1353 (when gdb-first-done-or-error
1354 (setq gdb-filter-output (concat gdb-filter-output gdb-prompt-name))
1355 (gdb-update)
1356 (setq gdb-first-done-or-error nil)))
1357
1358 ;; Remove the trimmings from log stream containing debugging messages
1359 ;; being produced by GDB's internals, use warning face and send to GUD
1360 ;; buffer.
1361 (defun gdb-internals (output-field)
1362 (setq gdb-filter-output
1363 (gdb-concat-output
1364 gdb-filter-output
1365 (let ((error-message
1366 (read output-field)))
1367 (put-text-property
1368 0 (length error-message)
1369 'face font-lock-warning-face
1370 error-message)
1371 error-message))))
1372
1373 ;; Remove the trimmings from the console stream and send to GUD buffer
1374 ;; (frontend MI commands should not print to this stream)
1375 (defun gdb-console (output-field)
1376 (setq gdb-filter-output
1377 (gdb-concat-output
1378 gdb-filter-output
1379 (read output-field))))
1380
1381 (defun gdb-done-or-error (output-field token-number type)
1382 (if (string-equal token-number "")
1383 ;; Output from command entered by user
1384 (progn
1385 (setq gdb-output-sink 'user)
1386 (setq token-number nil)
1387 ;; MI error - send to minibuffer
1388 (when (eq type 'error)
1389 ;; Skip "msg=" from `output-field'
1390 (message (read (substring output-field 4)))
1391 ;; Don't send to the console twice. (If it is a console error
1392 ;; it is also in the console stream.)
1393 (setq output-field nil)))
1394 ;; Output from command from frontend.
1395 (setq gdb-output-sink 'emacs))
1396
1397 (gdb-clear-partial-output)
1398 (when gdb-first-done-or-error
1399 (unless (or token-number gud-running)
1400 (setq gdb-filter-output (concat gdb-filter-output gdb-prompt-name)))
1401 (gdb-update)
1402 (setq gdb-first-done-or-error nil))
1403
1404 (setq gdb-filter-output
1405 (gdb-concat-output gdb-filter-output output-field))
1406
1407 (if token-number
1408 (progn
1409 (with-current-buffer
1410 (gdb-get-buffer-create 'gdb-partial-output-buffer)
1411 (funcall
1412 (cdr (assoc (string-to-number token-number) gdb-handler-alist))))
1413 (setq gdb-handler-alist
1414 (assq-delete-all token-number gdb-handler-alist)))))
1415
1416 (defun gdb-concat-output (so-far new)
1417 (let ((sink gdb-output-sink))
1418 (cond
1419 ((eq sink 'user) (concat so-far new))
1420 ((eq sink 'emacs)
1421 (gdb-append-to-partial-output new)
1422 so-far))))
1423
1424 (defun gdb-append-to-partial-output (string)
1425 (with-current-buffer (gdb-get-buffer-create 'gdb-partial-output-buffer)
1426 (goto-char (point-max))
1427 (insert string)))
1428
1429 (defun gdb-clear-partial-output ()
1430 (with-current-buffer (gdb-get-buffer-create 'gdb-partial-output-buffer)
1431 (erase-buffer)))
1432
1433 (defun json-partial-output (&optional fix-key)
1434 "Parse gdb-partial-output-buffer with `json-read'.
1435
1436 If FIX-KEY is non-nil, strip all \"FIX-KEY=\" occurences from
1437 partial output. This is used to get rid of useless keys in lists
1438 in MI messages, e.g.: [key=.., key=..]. -stack-list-frames and
1439 -break-info are examples of MI commands which issue such
1440 responses.
1441
1442 Note that GDB/MI output syntax is different from JSON both
1443 cosmetically and (in some cases) structurally, so correct results
1444 are not guaranteed."
1445 (with-current-buffer (gdb-get-buffer-create 'gdb-partial-output-buffer)
1446 (goto-char (point-min))
1447 (while (re-search-forward (concat "[\\[,]\\(" fix-key "=\\)") nil t)
1448 (replace-match "" nil nil nil 1))
1449 (goto-char (point-min))
1450 (insert "{")
1451 ;; Wrap field names in double quotes and replace equal sign with
1452 ;; semicolon.
1453 ;; TODO: This breaks badly with foo= inside constants
1454 (while (re-search-forward "\\([[:alpha:]-_]+\\)=" nil t)
1455 (replace-match "\"\\1\":" nil nil))
1456 (goto-char (point-max))
1457 (insert "}")
1458 (goto-char (point-min))
1459 (let ((json-array-type 'list))
1460 (json-read))))
1461
1462 (defalias 'gdb-get-field 'bindat-get-field)
1463
1464 (defun gdb-get-many-fields (struct &rest fields)
1465 "Return a list of FIELDS values from STRUCT."
1466 (let ((values))
1467 (dolist (field fields values)
1468 (setq values (append values (list (gdb-get-field struct field)))))))
1469
1470 ;; NAME is the function name. DEMAND-PREDICATE tests if output is really needed.
1471 ;; GDB-COMMAND is a string of such. OUTPUT-HANDLER is the function bound to the
1472 ;; current input.
1473
1474 (defmacro def-gdb-auto-update-trigger (name demand-predicate gdb-command
1475 output-handler)
1476 `(defun ,name (&optional ignored)
1477 (if (and ,demand-predicate
1478 (not (member ',name
1479 gdb-pending-triggers)))
1480 (progn
1481 (gdb-input
1482 (list ,gdb-command ',output-handler))
1483 (push ',name gdb-pending-triggers)))))
1484
1485 (defmacro def-gdb-auto-update-handler (name trigger buf-key custom-defun)
1486 "Define a handler NAME for TRIGGER acting in BUF-KEY with CUSTOM-DEFUN.
1487
1488 Delete TRIGGER from `gdb-pending-triggers', switch to gdb BUF-KEY
1489 buffer using `gdb-get-buffer', erase it and evalueat
1490 CUSTOM-DEFUN."
1491 `(defun ,name ()
1492 (setq gdb-pending-triggers
1493 (delq ',trigger
1494 gdb-pending-triggers))
1495 (let ((buf (gdb-get-buffer ',buf-key)))
1496 (and buf
1497 (with-current-buffer buf
1498 (let* ((window (get-buffer-window buf 0))
1499 (start (window-start window))
1500 (p (window-point window))
1501 (buffer-read-only nil))
1502 (erase-buffer)
1503 (set-window-start window start)
1504 (set-window-point window p)
1505 (,custom-defun)))))))
1506
1507 (defmacro def-gdb-auto-updated-buffer (buf-key
1508 trigger-name gdb-command
1509 output-handler-name custom-defun)
1510 "Define a trigger and its handler for buffers of type BUF-KEY.
1511
1512 TRIGGER-NAME trigger is defined to send GDB-COMMAND if BUF-KEY
1513 exists.
1514
1515 OUTPUT-HANDLER-NAME handler uses customization of CUSTOM-DEFUN."
1516 `(progn
1517 (def-gdb-auto-update-trigger ,trigger-name
1518 ;; The demand predicate:
1519 (gdb-get-buffer ',buf-key)
1520 ,gdb-command
1521 ,output-handler-name)
1522 (def-gdb-auto-update-handler ,output-handler-name
1523 ,trigger-name ,buf-key ,custom-defun)))
1524
1525 \f
1526
1527 ;; Breakpoint buffer : This displays the output of `-break-list'.
1528 ;;
1529 (gdb-set-buffer-rules 'gdb-breakpoints-buffer
1530 'gdb-breakpoints-buffer-name
1531 'gdb-breakpoints-mode)
1532
1533 (def-gdb-auto-update-trigger gdb-invalidate-breakpoints
1534 (gdb-get-buffer 'gdb-breakpoints-buffer)
1535 "-break-list\n"
1536 gdb-break-list-handler)
1537
1538 (defconst gdb-break-list-regexp
1539 "bkpt={.*?number=\"\\(.*?\\)\".*?,type=\"\\(.*?\\)\".*?,disp=\"\\(.*?\\)\".*?,\
1540 enabled=\"\\(.\\)\".*?,addr=\"\\(.*?\\)\",\\(?:.*?func=\"\\(.*?\\)\".*?,\
1541 file=\"\\(.*?\\)\".*?,fullname=\".*?\".*?,line=\"\\(.*?\\)\",\
1542 \\|\\(?:.*?what=\"\\(.*?\\)\",\\)*\\).*?times=\"\\(.*?\\)\".*?}")
1543
1544 (defun gdb-break-list-handler ()
1545 (setq gdb-pending-triggers (delq 'gdb-invalidate-breakpoints
1546 gdb-pending-triggers))
1547 (let ((breakpoint) (breakpoints-list))
1548 (with-current-buffer (gdb-get-buffer-create 'gdb-partial-output-buffer)
1549 (goto-char (point-min))
1550 (while (re-search-forward gdb-break-list-regexp nil t)
1551 (let ((breakpoint (list (match-string 1)
1552 (match-string 2)
1553 (match-string 3)
1554 (match-string 4)
1555 (match-string 5)
1556 (match-string 6)
1557 (match-string 7)
1558 (match-string 8)
1559 (match-string 9)
1560 (match-string 10))))
1561 (push breakpoint breakpoints-list))))
1562 (let ((buf (gdb-get-buffer 'gdb-breakpoints-buffer)))
1563 (and buf (with-current-buffer buf
1564 (let ((p (point))
1565 (buffer-read-only nil))
1566 (erase-buffer)
1567 (insert "Num Type Disp Enb Hits Addr What\n")
1568 (dolist (breakpoint breakpoints-list)
1569 (insert
1570 (concat
1571 (nth 0 breakpoint) " "
1572 (nth 1 breakpoint) " "
1573 (nth 2 breakpoint) " "
1574 (propertize (nth 3 breakpoint)
1575 'face (if (eq (string-to-char (nth 3 breakpoint)) ?y)
1576 font-lock-warning-face
1577 font-lock-type-face)) " "
1578 (nth 9 breakpoint) " "
1579 (nth 4 breakpoint) " "
1580 (if (nth 5 breakpoint)
1581 (concat "in " (nth 5 breakpoint) " at " (nth 6 breakpoint) ":" (nth 7 breakpoint) "\n")
1582 (concat (nth 8 breakpoint) "\n")))))
1583 (goto-char p))))))
1584 (gdb-break-list-custom))
1585
1586 ;; Put breakpoint icons in relevant margins (even those set in the GUD buffer).
1587 (defun gdb-break-list-custom ()
1588 (let ((flag) (bptno))
1589 ;; Remove all breakpoint-icons in source buffers but not assembler buffer.
1590 (dolist (buffer (buffer-list))
1591 (with-current-buffer buffer
1592 (if (and (eq gud-minor-mode 'gdbmi)
1593 (not (string-match "\\` ?\\*.+\\*\\'" (buffer-name))))
1594 (gdb-remove-breakpoint-icons (point-min) (point-max)))))
1595 (with-current-buffer (gdb-get-buffer 'gdb-breakpoints-buffer)
1596 (save-excursion
1597 (goto-char (point-min))
1598 (while (< (point) (- (point-max) 1))
1599 (forward-line 1)
1600 (if (looking-at "[^\t].*?breakpoint")
1601 (progn
1602 (looking-at "\\([0-9]+\\)\\s-+\\S-+\\s-+\\S-+\\s-+\\(.\\)")
1603 (setq bptno (match-string 1))
1604 (setq flag (char-after (match-beginning 2)))
1605 (beginning-of-line)
1606 (if (re-search-forward " in \\(.*\\) at\\s-+" nil t)
1607 (progn
1608 (let ((buffer-read-only nil))
1609 (add-text-properties (match-beginning 1) (match-end 1)
1610 '(face font-lock-function-name-face)))
1611 (looking-at "\\(\\S-+\\):\\([0-9]+\\)")
1612 (let ((line (match-string 2)) (buffer-read-only nil)
1613 (file (match-string 1)))
1614 (add-text-properties (line-beginning-position)
1615 (line-end-position)
1616 '(mouse-face highlight
1617 help-echo "mouse-2, RET: visit breakpoint"))
1618 (unless (file-exists-p file)
1619 (setq file (cdr (assoc bptno gdb-location-alist))))
1620 (if (and file
1621 (not (string-equal file "File not found")))
1622 (with-current-buffer
1623 (find-file-noselect file 'nowarn)
1624 (gdb-init-buffer)
1625 ;; Only want one breakpoint icon at each location.
1626 (save-excursion
1627 (goto-line (string-to-number line))
1628 (gdb-put-breakpoint-icon (eq flag ?y) bptno)))
1629 (gdb-input
1630 (list (concat "list "
1631 (match-string-no-properties 3) ":1\n")
1632 'ignore))
1633 (gdb-input
1634 (list "-file-list-exec-source-file\n"
1635 `(lambda () (gdb-get-location
1636 ,bptno ,line ,flag))))))))))))
1637 (end-of-line))))
1638
1639 (defvar gdb-source-file-regexp "fullname=\"\\(.*?\\)\"")
1640
1641 (defun gdb-get-location (bptno line flag)
1642 "Find the directory containing the relevant source file.
1643 Put in buffer and place breakpoint icon."
1644 (goto-char (point-min))
1645 (catch 'file-not-found
1646 (if (re-search-forward gdb-source-file-regexp nil t)
1647 (delete (cons bptno "File not found") gdb-location-alist)
1648 (push (cons bptno (match-string 1)) gdb-location-alist)
1649 (gdb-resync)
1650 (unless (assoc bptno gdb-location-alist)
1651 (push (cons bptno "File not found") gdb-location-alist)
1652 (message-box "Cannot find source file for breakpoint location.
1653 Add directory to search path for source files using the GDB command, dir."))
1654 (throw 'file-not-found nil))
1655 (with-current-buffer (find-file-noselect (match-string 1))
1656 (gdb-init-buffer)
1657 ;; only want one breakpoint icon at each location
1658 (save-excursion
1659 (goto-line (string-to-number line))
1660 (gdb-put-breakpoint-icon (eq flag ?y) bptno)))))
1661
1662 (add-hook 'find-file-hook 'gdb-find-file-hook)
1663
1664 (defun gdb-find-file-hook ()
1665 "Set up buffer for debugging if file is part of the source code
1666 of the current session."
1667 (if (and (buffer-name gud-comint-buffer)
1668 ;; in case gud or gdb-ui is just loaded
1669 gud-comint-buffer
1670 (eq (buffer-local-value 'gud-minor-mode gud-comint-buffer)
1671 'gdbmi))
1672 (if (member buffer-file-name gdb-source-file-list)
1673 (with-current-buffer (find-buffer-visiting buffer-file-name)
1674 (gdb-init-buffer)))))
1675
1676 (declare-function gud-remove "gdb-mi" t t) ; gud-def
1677 (declare-function gud-break "gdb-mi" t t) ; gud-def
1678 (declare-function fringe-bitmaps-at-pos "fringe.c" (&optional pos window))
1679
1680 (defun gdb-mouse-set-clear-breakpoint (event)
1681 "Set/clear breakpoint in left fringe/margin at mouse click.
1682 If not in a source or disassembly buffer just set point."
1683 (interactive "e")
1684 (mouse-minibuffer-check event)
1685 (let ((posn (event-end event)))
1686 (with-selected-window (posn-window posn)
1687 (if (or (buffer-file-name) (eq major-mode 'gdb-assembler-mode))
1688 (if (numberp (posn-point posn))
1689 (save-excursion
1690 (goto-char (posn-point posn))
1691 (if (or (posn-object posn)
1692 (eq (car (fringe-bitmaps-at-pos (posn-point posn)))
1693 'breakpoint))
1694 (gud-remove nil)
1695 (gud-break nil)))))
1696 (posn-set-point posn))))
1697
1698 (defun gdb-mouse-toggle-breakpoint-margin (event)
1699 "Enable/disable breakpoint in left margin with mouse click."
1700 (interactive "e")
1701 (mouse-minibuffer-check event)
1702 (let ((posn (event-end event)))
1703 (if (numberp (posn-point posn))
1704 (with-selected-window (posn-window posn)
1705 (save-excursion
1706 (goto-char (posn-point posn))
1707 (if (posn-object posn)
1708 (gud-basic-call
1709 (let ((bptno (get-text-property
1710 0 'gdb-bptno (car (posn-string posn)))))
1711 (concat
1712 (if (get-text-property
1713 0 'gdb-enabled (car (posn-string posn)))
1714 "-break-disable "
1715 "-break-enable ")
1716 bptno "\n")))))))))
1717
1718 (defun gdb-mouse-toggle-breakpoint-fringe (event)
1719 "Enable/disable breakpoint in left fringe with mouse click."
1720 (interactive "e")
1721 (mouse-minibuffer-check event)
1722 (let* ((posn (event-end event))
1723 (pos (posn-point posn))
1724 obj)
1725 (when (numberp pos)
1726 (with-selected-window (posn-window posn)
1727 (save-excursion
1728 (set-buffer (window-buffer (selected-window)))
1729 (goto-char pos)
1730 (dolist (overlay (overlays-in pos pos))
1731 (when (overlay-get overlay 'put-break)
1732 (setq obj (overlay-get overlay 'before-string))))
1733 (when (stringp obj)
1734 (gud-basic-call
1735 (concat
1736 (if (get-text-property 0 'gdb-enabled obj)
1737 "-break-disable "
1738 "-break-enable ")
1739 (get-text-property 0 'gdb-bptno obj) "\n"))))))))
1740
1741 (defun gdb-breakpoints-buffer-name ()
1742 (with-current-buffer gud-comint-buffer
1743 (concat "*breakpoints of " (gdb-get-target-string) "*")))
1744
1745 (def-gdb-display-buffer
1746 gdb-display-breakpoints-buffer
1747 'gdb-breakpoints-buffer
1748 "Display status of user-settable breakpoints.")
1749
1750 (def-gdb-frame-for-buffer
1751 gdb-frame-breakpoints-buffer
1752 'gdb-breakpoints-buffer
1753 "Display status of user-settable breakpoints in a new frame.")
1754
1755 (defvar gdb-breakpoints-mode-map
1756 (let ((map (make-sparse-keymap))
1757 (menu (make-sparse-keymap "Breakpoints")))
1758 (define-key menu [quit] '("Quit" . gdb-delete-frame-or-window))
1759 (define-key menu [goto] '("Goto" . gdb-goto-breakpoint))
1760 (define-key menu [delete] '("Delete" . gdb-delete-breakpoint))
1761 (define-key menu [toggle] '("Toggle" . gdb-toggle-breakpoint))
1762 (suppress-keymap map)
1763 (define-key map [menu-bar breakpoints] (cons "Breakpoints" menu))
1764 (define-key map " " 'gdb-toggle-breakpoint)
1765 (define-key map "D" 'gdb-delete-breakpoint)
1766 ;; Don't bind "q" to kill-this-buffer as we need it for breakpoint icons.
1767 (define-key map "q" 'gdb-delete-frame-or-window)
1768 (define-key map "\r" 'gdb-goto-breakpoint)
1769 (define-key map [mouse-2] 'gdb-goto-breakpoint)
1770 (define-key map [follow-link] 'mouse-face)
1771 map))
1772
1773 (defun gdb-delete-frame-or-window ()
1774 "Delete frame if there is only one window. Otherwise delete the window."
1775 (interactive)
1776 (if (one-window-p) (delete-frame)
1777 (delete-window)))
1778
1779 ;;from make-mode-line-mouse-map
1780 (defun gdb-make-header-line-mouse-map (mouse function) "\
1781 Return a keymap with single entry for mouse key MOUSE on the header line.
1782 MOUSE is defined to run function FUNCTION with no args in the buffer
1783 corresponding to the mode line clicked."
1784 (let ((map (make-sparse-keymap)))
1785 (define-key map (vector 'header-line mouse) function)
1786 (define-key map (vector 'header-line 'down-mouse-1) 'ignore)
1787 map))
1788
1789 \f
1790 ;; uses "-thread-info". Needs GDB 7.0 onwards.
1791 ;;; Threads view
1792
1793 (defun gdb-jump-to (file line)
1794 (find-file-other-window file)
1795 (goto-line line))
1796
1797 (define-button-type 'gdb-file-button
1798 'help-echo "Push to jump to source code"
1799 ; 'face 'bold
1800 'action
1801 (lambda (b)
1802 (gdb-jump-to (button-get b 'file)
1803 (button-get b 'line))))
1804
1805 (defun gdb-insert-file-location-button (file line)
1806 "Insert text button which allows jumping to FILE:LINE.
1807
1808 FILE is a full path."
1809 (insert-text-button
1810 (format "%s:%d" (file-name-nondirectory file) line)
1811 :type 'gdb-file-button
1812 'file file
1813 'line line))
1814
1815 (defun gdb-threads-buffer-name ()
1816 (concat "*threads of " (gdb-get-target-string) "*"))
1817
1818 (def-gdb-display-buffer
1819 gdb-display-threads-buffer
1820 'gdb-threads-buffer
1821 "Display GDB threads.")
1822
1823 (def-gdb-frame-for-buffer
1824 gdb-frame-threads-buffer
1825 'gdb-threads-buffer
1826 "Display GDB threads in a new frame.")
1827
1828 (gdb-set-buffer-rules 'gdb-threads-buffer
1829 'gdb-threads-buffer-name
1830 'gdb-threads-mode)
1831
1832 (def-gdb-auto-updated-buffer gdb-threads-buffer
1833 gdb-invalidate-threads "-thread-info\n"
1834 gdb-thread-list-handler gdb-thread-list-handler-custom)
1835
1836
1837 (defvar gdb-threads-font-lock-keywords
1838 '(("in \\([^ ]+\\) (" (1 font-lock-function-name-face))
1839 (" \\(stopped\\) in " (1 font-lock-warning-face))
1840 ("\\(\\(\\sw\\|[_.]\\)+\\)=" (1 font-lock-variable-name-face)))
1841 "Font lock keywords used in `gdb-threads-mode'.")
1842
1843 (defvar gdb-threads-mode-map
1844 ;; TODO
1845 (make-sparse-keymap))
1846
1847 (defun gdb-threads-mode ()
1848 "Major mode for GDB threads.
1849
1850 \\{gdb-threads-mode-map}"
1851 (kill-all-local-variables)
1852 (setq major-mode 'gdb-threads-mode)
1853 (setq mode-name "Threads")
1854 (use-local-map gdb-threads-mode-map)
1855 (setq buffer-read-only t)
1856 (buffer-disable-undo)
1857 (setq header-line-format gdb-breakpoints-header)
1858 (set (make-local-variable 'font-lock-defaults)
1859 '(gdb-threads-font-lock-keywords))
1860 (run-mode-hooks 'gdb-threads-mode-hook)
1861 'gdb-invalidate-threads)
1862
1863 (defun gdb-thread-list-handler-custom ()
1864 (let* ((res (json-partial-output))
1865 (threads-list (gdb-get-field res 'threads)))
1866 (dolist (thread threads-list)
1867 (insert (apply 'format `("%s (%s) %s in %s "
1868 ,@(gdb-get-many-fields thread 'id 'target-id 'state)
1869 ,(gdb-get-field thread 'frame 'func))))
1870 ;; Arguments
1871 (insert "(")
1872 (let ((args (gdb-get-field thread 'frame 'args)))
1873 (dolist (arg args)
1874 (insert (apply 'format `("%s=%s" ,@(gdb-get-many-fields arg 'name 'value)))))
1875 (when args (kill-backward-chars 1)))
1876 (insert ")")
1877 (gdb-insert-frame-location (gdb-get-field thread 'frame))
1878 (insert (format " at %s\n" (gdb-get-field thread 'frame 'addr))))))
1879
1880 \f
1881 ;;; Memory view
1882
1883 (defcustom gdb-memory-rows 8
1884 "Number of data rows in memory window."
1885 :type 'integer
1886 :group 'gud
1887 :version "23.2")
1888
1889 (defcustom gdb-memory-columns 4
1890 "Number of data columns in memory window."
1891 :type 'integer
1892 :group 'gud
1893 :version "23.2")
1894
1895 (defcustom gdb-memory-format "x"
1896 "Display format of data items in memory window."
1897 :type '(choice (const :tag "Hexadecimal" "x")
1898 (const :tag "Signed decimal" "d")
1899 (const :tag "Unsigned decimal" "u")
1900 (const :tag "Octal" "o")
1901 (const :tag "Binary" "t"))
1902 :group 'gud
1903 :version "22.1")
1904
1905 (defcustom gdb-memory-unit 4
1906 "Unit size of data items in memory window."
1907 :type '(choice (const :tag "Byte" 1)
1908 (const :tag "Halfword" 2)
1909 (const :tag "Word" 4)
1910 (const :tag "Giant word" 8))
1911 :group 'gud
1912 :version "23.2")
1913
1914 (gdb-set-buffer-rules 'gdb-memory-buffer
1915 'gdb-memory-buffer-name
1916 'gdb-memory-mode)
1917
1918 (def-gdb-auto-updated-buffer gdb-memory-buffer
1919 gdb-invalidate-memory
1920 (format "-data-read-memory %s %s %d %d %d\n"
1921 gdb-memory-address
1922 gdb-memory-format
1923 gdb-memory-unit
1924 gdb-memory-rows
1925 gdb-memory-columns)
1926 gdb-read-memory-handler
1927 gdb-read-memory-custom)
1928
1929 (defun gdb-read-memory-custom ()
1930 (let* ((res (json-partial-output))
1931 (err-msg (gdb-get-field res 'msg)))
1932 (if (not err-msg)
1933 (let ((memory (gdb-get-field res 'memory)))
1934 (setq gdb-memory-address (gdb-get-field res 'addr))
1935 (setq gdb-memory-next-page (gdb-get-field res 'next-page))
1936 (setq gdb-memory-prev-page (gdb-get-field res 'prev-page))
1937 (setq gdb-memory-last-address gdb-memory-address)
1938 (dolist (row memory)
1939 (insert (concat (gdb-get-field row 'addr) ": "))
1940 (dolist (column (gdb-get-field row 'data))
1941 (insert (concat column "\t")))
1942 (newline)))
1943 ;; Show last page instead of empty buffer when out of bounds
1944 (progn
1945 (let ((gdb-memory-address gdb-memory-last-address))
1946 (gdb-invalidate-memory)
1947 (error err-msg))))))
1948
1949 (defvar gdb-memory-mode-map
1950 (let ((map (make-sparse-keymap)))
1951 (suppress-keymap map t)
1952 (define-key map "q" 'kill-this-buffer)
1953 (define-key map "n" 'gdb-memory-show-next-page)
1954 (define-key map "p" 'gdb-memory-show-previous-page)
1955 (define-key map "a" 'gdb-memory-set-address)
1956 (define-key map "t" 'gdb-memory-format-binary)
1957 (define-key map "o" 'gdb-memory-format-octal)
1958 (define-key map "u" 'gdb-memory-format-unsigned)
1959 (define-key map "d" 'gdb-memory-format-signed)
1960 (define-key map "x" 'gdb-memory-format-hexadecimal)
1961 (define-key map "b" 'gdb-memory-unit-byte)
1962 (define-key map "h" 'gdb-memory-unit-halfword)
1963 (define-key map "w" 'gdb-memory-unit-word)
1964 (define-key map "g" 'gdb-memory-unit-giant)
1965 (define-key map "R" 'gdb-memory-set-rows)
1966 (define-key map "C" 'gdb-memory-set-columns)
1967 map))
1968
1969 (defun gdb-memory-set-address-event (event)
1970 "Handle a click on address field in memory buffer header."
1971 (interactive "e")
1972 (save-selected-window
1973 (select-window (posn-window (event-start event)))
1974 (gdb-memory-set-address-1)))
1975
1976 ;; Non-event version for use within keymap
1977 (defun gdb-memory-set-address ()
1978 "Set the start memory address."
1979 (interactive)
1980 (let ((arg (read-from-minibuffer "Memory address: ")))
1981 (setq gdb-memory-address arg))
1982 (gdb-invalidate-memory))
1983
1984 (defmacro def-gdb-set-positive-number (name variable echo-string &optional doc)
1985 "Define a function NAME which reads new VAR value from minibuffer."
1986 `(defun ,name (event)
1987 ,(when doc doc)
1988 (interactive "e")
1989 (save-selected-window
1990 (select-window (posn-window (event-start event)))
1991 (let* ((arg (read-from-minibuffer ,echo-string))
1992 (count (string-to-number arg)))
1993 (if (<= count 0)
1994 (error "Positive number only")
1995 (customize-set-variable ',variable count)
1996 (gdb-invalidate-memory))))))
1997
1998 (def-gdb-set-positive-number
1999 gdb-memory-set-rows
2000 gdb-memory-rows
2001 "Rows: "
2002 "Set the number of data rows in memory window.")
2003
2004 (def-gdb-set-positive-number
2005 gdb-memory-set-columns
2006 gdb-memory-columns
2007 "Columns: "
2008 "Set the number of data columns in memory window.")
2009
2010 (defmacro def-gdb-memory-format (name format doc)
2011 "Define a function NAME to switch memory buffer to use FORMAT.
2012
2013 DOC is an optional documentation string."
2014 `(defun ,name () ,(when doc doc)
2015 (interactive)
2016 (customize-set-variable 'gdb-memory-format ,format)
2017 (gdb-invalidate-memory)))
2018
2019 (def-gdb-memory-format
2020 gdb-memory-format-binary "t"
2021 "Set the display format to binary.")
2022
2023 (def-gdb-memory-format
2024 gdb-memory-format-octal "o"
2025 "Set the display format to octal.")
2026
2027 (def-gdb-memory-format
2028 gdb-memory-format-unsigned "u"
2029 "Set the display format to unsigned decimal.")
2030
2031 (def-gdb-memory-format
2032 gdb-memory-format-signed "d"
2033 "Set the display format to decimal.")
2034
2035 (def-gdb-memory-format
2036 gdb-memory-format-hexadecimal "x"
2037 "Set the display format to hexadecimal.")
2038
2039 (defvar gdb-memory-format-map
2040 (let ((map (make-sparse-keymap)))
2041 (define-key map [header-line down-mouse-3] 'gdb-memory-format-menu-1)
2042 map)
2043 "Keymap to select format in the header line.")
2044
2045 (defvar gdb-memory-format-menu (make-sparse-keymap "Format")
2046 "Menu of display formats in the header line.")
2047
2048 (define-key gdb-memory-format-menu [binary]
2049 '(menu-item "Binary" gdb-memory-format-binary
2050 :button (:radio . (equal gdb-memory-format "t"))))
2051 (define-key gdb-memory-format-menu [octal]
2052 '(menu-item "Octal" gdb-memory-format-octal
2053 :button (:radio . (equal gdb-memory-format "o"))))
2054 (define-key gdb-memory-format-menu [unsigned]
2055 '(menu-item "Unsigned Decimal" gdb-memory-format-unsigned
2056 :button (:radio . (equal gdb-memory-format "u"))))
2057 (define-key gdb-memory-format-menu [signed]
2058 '(menu-item "Signed Decimal" gdb-memory-format-signed
2059 :button (:radio . (equal gdb-memory-format "d"))))
2060 (define-key gdb-memory-format-menu [hexadecimal]
2061 '(menu-item "Hexadecimal" gdb-memory-format-hexadecimal
2062 :button (:radio . (equal gdb-memory-format "x"))))
2063
2064 (defun gdb-memory-format-menu (event)
2065 (interactive "@e")
2066 (x-popup-menu event gdb-memory-format-menu))
2067
2068 (defun gdb-memory-format-menu-1 (event)
2069 (interactive "e")
2070 (save-selected-window
2071 (select-window (posn-window (event-start event)))
2072 (let* ((selection (gdb-memory-format-menu event))
2073 (binding (and selection (lookup-key gdb-memory-format-menu
2074 (vector (car selection))))))
2075 (if binding (call-interactively binding)))))
2076
2077 (defun gdb-memory-unit-giant ()
2078 "Set the unit size to giant words (eight bytes)."
2079 (interactive)
2080 (customize-set-variable 'gdb-memory-unit 8)
2081 (gdb-invalidate-memory))
2082
2083 (defun gdb-memory-unit-word ()
2084 "Set the unit size to words (four bytes)."
2085 (interactive)
2086 (customize-set-variable 'gdb-memory-unit 4)
2087 (gdb-invalidate-memory))
2088
2089 (defun gdb-memory-unit-halfword ()
2090 "Set the unit size to halfwords (two bytes)."
2091 (interactive)
2092 (customize-set-variable 'gdb-memory-unit 2)
2093 (gdb-invalidate-memory))
2094
2095 (defun gdb-memory-unit-byte ()
2096 "Set the unit size to bytes."
2097 (interactive)
2098 (customize-set-variable 'gdb-memory-unit 1)
2099 (gdb-invalidate-memory))
2100
2101 (defmacro def-gdb-memory-show-page (name address-var &optional doc)
2102 "Define a function NAME which show new address in memory buffer.
2103
2104 The defined function switches Memory buffer to show address
2105 stored in ADDRESS-VAR variable.
2106
2107 DOC is an optional documentation string."
2108 `(defun ,name
2109 ,(when doc doc)
2110 (interactive)
2111 (let ((gdb-memory-address ,address-var))
2112 (gdb-invalidate-memory))))
2113
2114 (def-gdb-memory-show-page gdb-memory-show-previous-page
2115 gdb-memory-prev-page)
2116
2117 (def-gdb-memory-show-page gdb-memory-show-next-page
2118 gdb-memory-next-page)
2119
2120 (defvar gdb-memory-unit-map
2121 (let ((map (make-sparse-keymap)))
2122 (define-key map [header-line down-mouse-3] 'gdb-memory-unit-menu-1)
2123 map)
2124 "Keymap to select units in the header line.")
2125
2126 (defvar gdb-memory-unit-menu (make-sparse-keymap "Unit")
2127 "Menu of units in the header line.")
2128
2129 (define-key gdb-memory-unit-menu [giantwords]
2130 '(menu-item "Giant words" gdb-memory-unit-giant
2131 :button (:radio . (equal gdb-memory-unit 8))))
2132 (define-key gdb-memory-unit-menu [words]
2133 '(menu-item "Words" gdb-memory-unit-word
2134 :button (:radio . (equal gdb-memory-unit 4))))
2135 (define-key gdb-memory-unit-menu [halfwords]
2136 '(menu-item "Halfwords" gdb-memory-unit-halfword
2137 :button (:radio . (equal gdb-memory-unit 2))))
2138 (define-key gdb-memory-unit-menu [bytes]
2139 '(menu-item "Bytes" gdb-memory-unit-byte
2140 :button (:radio . (equal gdb-memory-unit 1))))
2141
2142 (defun gdb-memory-unit-menu (event)
2143 (interactive "@e")
2144 (x-popup-menu event gdb-memory-unit-menu))
2145
2146 (defun gdb-memory-unit-menu-1 (event)
2147 (interactive "e")
2148 (save-selected-window
2149 (select-window (posn-window (event-start event)))
2150 (let* ((selection (gdb-memory-unit-menu event))
2151 (binding (and selection (lookup-key gdb-memory-unit-menu
2152 (vector (car selection))))))
2153 (if binding (call-interactively binding)))))
2154
2155 ;;from make-mode-line-mouse-map
2156 (defun gdb-make-header-line-mouse-map (mouse function) "\
2157 Return a keymap with single entry for mouse key MOUSE on the header line.
2158 MOUSE is defined to run function FUNCTION with no args in the buffer
2159 corresponding to the mode line clicked."
2160 (let ((map (make-sparse-keymap)))
2161 (define-key map (vector 'header-line mouse) function)
2162 (define-key map (vector 'header-line 'down-mouse-1) 'ignore)
2163 map))
2164
2165 (defvar gdb-memory-font-lock-keywords
2166 '(;; <__function.name+n>
2167 ("<\\(\\(\\sw\\|[_.]\\)+\\)\\(\\+[0-9]+\\)?>" (1 font-lock-function-name-face))
2168 )
2169 "Font lock keywords used in `gdb-memory-mode'.")
2170
2171 (defvar gdb-memory-header
2172 '(:eval
2173 (concat
2174 "Start address["
2175 (propertize "-"
2176 'face font-lock-warning-face
2177 'help-echo "mouse-1: decrement address"
2178 'mouse-face 'mode-line-highlight
2179 'local-map (gdb-make-header-line-mouse-map
2180 'mouse-1
2181 #'gdb-memory-show-previous-page))
2182 "|"
2183 (propertize "+"
2184 'face font-lock-warning-face
2185 'help-echo "mouse-1: increment address"
2186 'mouse-face 'mode-line-highlight
2187 'local-map (gdb-make-header-line-mouse-map
2188 'mouse-1
2189 #'gdb-memory-show-next-page))
2190 "]: "
2191 (propertize gdb-memory-address
2192 'face font-lock-warning-face
2193 'help-echo "mouse-1: set start address"
2194 'mouse-face 'mode-line-highlight
2195 'local-map (gdb-make-header-line-mouse-map
2196 'mouse-1
2197 #'gdb-memory-set-address-event))
2198 " Rows: "
2199 (propertize (number-to-string gdb-memory-rows)
2200 'face font-lock-warning-face
2201 'help-echo "mouse-1: set number of columns"
2202 'mouse-face 'mode-line-highlight
2203 'local-map (gdb-make-header-line-mouse-map
2204 'mouse-1
2205 #'gdb-memory-set-rows))
2206 " Columns: "
2207 (propertize (number-to-string gdb-memory-columns)
2208 'face font-lock-warning-face
2209 'help-echo "mouse-1: set number of columns"
2210 'mouse-face 'mode-line-highlight
2211 'local-map (gdb-make-header-line-mouse-map
2212 'mouse-1
2213 #'gdb-memory-set-columns))
2214 " Display Format: "
2215 (propertize gdb-memory-format
2216 'face font-lock-warning-face
2217 'help-echo "mouse-3: select display format"
2218 'mouse-face 'mode-line-highlight
2219 'local-map gdb-memory-format-map)
2220 " Unit Size: "
2221 (propertize (number-to-string gdb-memory-unit)
2222 'face font-lock-warning-face
2223 'help-echo "mouse-3: select unit size"
2224 'mouse-face 'mode-line-highlight
2225 'local-map gdb-memory-unit-map)))
2226 "Header line used in `gdb-memory-mode'.")
2227
2228 (defun gdb-memory-mode ()
2229 "Major mode for examining memory.
2230
2231 \\{gdb-memory-mode-map}"
2232 (kill-all-local-variables)
2233 (setq major-mode 'gdb-memory-mode)
2234 (setq mode-name "Memory")
2235 (use-local-map gdb-memory-mode-map)
2236 (setq buffer-read-only t)
2237 (setq header-line-format gdb-memory-header)
2238 (set (make-local-variable 'font-lock-defaults)
2239 '(gdb-memory-font-lock-keywords))
2240 (run-mode-hooks 'gdb-memory-mode-hook)
2241 'gdb-invalidate-memory)
2242
2243 (defun gdb-memory-buffer-name ()
2244 (with-current-buffer gud-comint-buffer
2245 (concat "*memory of " (gdb-get-target-string) "*")))
2246
2247 (def-gdb-display-buffer
2248 gdb-display-memory-buffer
2249 'gdb-memory-buffer
2250 "Display memory contents.")
2251
2252 (defun gdb-frame-memory-buffer ()
2253 "Display memory contents in a new frame."
2254 (interactive)
2255 (let* ((special-display-regexps (append special-display-regexps '(".*")))
2256 (special-display-frame-alist
2257 (cons '(left-fringe . 0)
2258 (cons '(right-fringe . 0)
2259 (cons '(width . 83) gdb-frame-parameters)))))
2260 (display-buffer (gdb-get-buffer-create 'gdb-memory-buffer))))
2261
2262 \f
2263 ;;; Disassembly view
2264
2265 (defun gdb-disassembly-buffer-name ()
2266 (concat "*disassembly of " (gdb-get-target-string) "*"))
2267
2268 (def-gdb-display-buffer
2269 gdb-display-disassembly-buffer
2270 'gdb-disassembly-buffer
2271 "Display disassembly for current stack frame.")
2272
2273 (def-gdb-frame-for-buffer
2274 gdb-frame-disassembly-buffer
2275 'gdb-disassembly-buffer
2276 "Display disassembly in a new frame.")
2277
2278 (gdb-set-buffer-rules 'gdb-disassembly-buffer
2279 'gdb-disassembly-buffer-name
2280 'gdb-disassembly-mode)
2281
2282 (def-gdb-auto-update-trigger gdb-invalidate-disassembly
2283 (gdb-get-buffer-create 'gdb-disassembly-buffer)
2284 (let ((file (or gdb-selected-file gdb-main-file))
2285 (line (or gdb-selected-line 1)))
2286 (if file
2287 (format "-data-disassemble -f %s -l %d -n -1 -- 0\n" file line)
2288 ""))
2289 gdb-disassembly-handler)
2290
2291 (def-gdb-auto-update-handler
2292 gdb-disassembly-handler
2293 gdb-invalidate-disassembly
2294 gdb-disassembly-buffer
2295 gdb-disassembly-handler-custom)
2296
2297 (defvar gdb-disassembly-font-lock-keywords
2298 '(;; <__function.name+n>
2299 ("<\\(\\(\\sw\\|[_.]\\)+\\)\\(\\+[0-9]+\\)?>"
2300 (1 font-lock-function-name-face))
2301 ;; 0xNNNNNNNN <__function.name+n>: opcode
2302 ("^0x[0-9a-f]+ \\(<\\(\\(\\sw\\|[_.]\\)+\\)\\+[0-9]+>\\)?:[ \t]+\\(\\sw+\\)"
2303 (4 font-lock-keyword-face))
2304 ;; %register(at least i386)
2305 ("%\\sw+" . font-lock-variable-name-face)
2306 ("^\\(Dump of assembler code for function\\) \\(.+\\):"
2307 (1 font-lock-comment-face)
2308 (2 font-lock-function-name-face))
2309 ("^\\(End of assembler dump\\.\\)" . font-lock-comment-face))
2310 "Font lock keywords used in `gdb-disassembly-mode'.")
2311
2312 (defvar gdb-disassembly-mode-map
2313 ;; TODO
2314 (make-sparse-keymap))
2315
2316 (defun gdb-disassembly-mode ()
2317 "Major mode for GDB disassembly information.
2318
2319 \\{gdb-disassembly-mode-map}"
2320 (kill-all-local-variables)
2321 (setq major-mode 'gdb-disassembly-mode)
2322 (setq mode-name "Disassembly")
2323 (use-local-map gdb-disassembly-mode-map)
2324 (setq buffer-read-only t)
2325 (buffer-disable-undo)
2326 (set (make-local-variable 'font-lock-defaults)
2327 '(gdb-disassembly-font-lock-keywords))
2328 (run-mode-hooks 'gdb-disassembly-mode-hook)
2329 'gdb-invalidate-disassembly)
2330
2331 (defun gdb-disassembly-handler-custom ()
2332 (let* ((res (json-partial-output))
2333 (instructions (gdb-get-field res 'asm_insns)))
2334 (dolist (instr instructions)
2335 (insert (apply 'format `("%s <%s+%s>:\t%s\n"
2336 ,@(gdb-get-many-fields instr 'address 'func-name 'offset 'inst)))))))
2337
2338 \f
2339 ;;; Breakpoints view
2340 (defvar gdb-breakpoints-header
2341 `(,(propertize "Breakpoints"
2342 'help-echo "mouse-1: select"
2343 'mouse-face 'mode-line-highlight
2344 'face 'mode-line
2345 'local-map
2346 (gdb-make-header-line-mouse-map
2347 'mouse-1
2348 (lambda (event) (interactive "e")
2349 (save-selected-window
2350 (select-window (posn-window (event-start event)))
2351 (set-window-dedicated-p (selected-window) nil)
2352 (switch-to-buffer
2353 (gdb-get-buffer-create 'gdb-breakpoints-buffer))
2354 (set-window-dedicated-p (selected-window) t)))))
2355 " "
2356 ,(propertize "Threads"
2357 'help-echo "mouse-1: select"
2358 'mouse-face 'mode-line-highlight
2359 'face 'mode-line
2360 'local-map
2361 (gdb-make-header-line-mouse-map
2362 'mouse-1
2363 ;; TODO: same code few lines above
2364 (lambda (event) (interactive "e")
2365 (save-selected-window
2366 (select-window (posn-window (event-start event)))
2367 (set-window-dedicated-p (selected-window) nil)
2368 (switch-to-buffer
2369 (gdb-get-buffer-create 'gdb-threads-buffer))
2370 (set-window-dedicated-p (selected-window) t)))
2371 ))))
2372
2373 (defun gdb-breakpoints-mode ()
2374 "Major mode for gdb breakpoints.
2375
2376 \\{gdb-breakpoints-mode-map}"
2377 (kill-all-local-variables)
2378 (setq major-mode 'gdb-breakpoints-mode)
2379 (setq mode-name "Breakpoints")
2380 (use-local-map gdb-breakpoints-mode-map)
2381 (setq buffer-read-only t)
2382 (buffer-disable-undo)
2383 (setq header-line-format gdb-breakpoints-header)
2384 (run-mode-hooks 'gdb-breakpoints-mode-hook)
2385 'gdb-invalidate-breakpoints)
2386
2387 (defconst gdb-breakpoint-regexp
2388 "\\([0-9]+\\).*?\\(?:point\\|catch\\s-+\\S-+\\)\\s-+\\S-+\\s-+\\(.\\)\\s-+")
2389
2390 (defun gdb-toggle-breakpoint ()
2391 "Enable/disable breakpoint at current line."
2392 (interactive)
2393 (save-excursion
2394 (beginning-of-line 1)
2395 (if (looking-at gdb-breakpoint-regexp)
2396 (gud-basic-call
2397 (concat (if (eq ?y (char-after (match-beginning 2)))
2398 "-break-disable "
2399 "-break-enable ")
2400 (match-string 1)))
2401 (error "Not recognized as break/watchpoint line"))))
2402
2403 (defun gdb-delete-breakpoint ()
2404 "Delete the breakpoint at current line."
2405 (interactive)
2406 (save-excursion
2407 (beginning-of-line 1)
2408 (if (looking-at gdb-breakpoint-regexp)
2409 (gud-basic-call (concat "-break-delete " (match-string 1)))
2410 (error "Not recognized as break/watchpoint line"))))
2411
2412 (defun gdb-goto-breakpoint (&optional event)
2413 "Display the breakpoint location specified at current line."
2414 (interactive (list last-input-event))
2415 (if event (posn-set-point (event-end event)))
2416 ;; Hack to stop gdb-goto-breakpoint displaying in GUD buffer.
2417 (let ((window (get-buffer-window gud-comint-buffer)))
2418 (if window (save-selected-window (select-window window))))
2419 (save-excursion
2420 (beginning-of-line 1)
2421 (if (looking-at "\\([0-9]+\\) .+ in .+ at\\s-+\\(\\S-+\\):\\([0-9]+\\)")
2422 (let ((bptno (match-string 1))
2423 (file (match-string 2))
2424 (line (match-string 3)))
2425 (save-selected-window
2426 (let* ((buffer (find-file-noselect
2427 (if (file-exists-p file) file
2428 (cdr (assoc bptno gdb-location-alist)))))
2429 (window (or (gdb-display-source-buffer buffer)
2430 (display-buffer buffer))))
2431 (setq gdb-source-window window)
2432 (with-current-buffer buffer
2433 (goto-line (string-to-number line))
2434 (set-window-point window (point))))))
2435 (error "Not recognized as break/watchpoint line"))))
2436
2437 \f
2438 ;; Frames buffer. This displays a perpetually correct bactrack trace.
2439 ;;
2440 (gdb-set-buffer-rules 'gdb-stack-buffer
2441 'gdb-stack-buffer-name
2442 'gdb-frames-mode)
2443
2444 (def-gdb-auto-update-trigger gdb-invalidate-frames
2445 (gdb-get-buffer 'gdb-stack-buffer)
2446 "-stack-list-frames\n"
2447 gdb-stack-list-frames-handler)
2448
2449 (defun gdb-insert-frame-location (frame)
2450 "Insert \"file:line\" button or library name for FRAME object."
2451 (let ((file (gdb-get-field frame 'fullname))
2452 (line (gdb-get-field frame 'line))
2453 (from (gdb-get-field frame 'from)))
2454 (cond (file
2455 ;; Filename with line number
2456 (insert " of ")
2457 (gdb-insert-file-location-button
2458 file (string-to-number line)))
2459 ;; Library
2460 (from (insert (format " of %s" from))))))
2461
2462 (defun gdb-stack-list-frames-handler ()
2463 (setq gdb-pending-triggers (delq 'gdb-invalidate-frames
2464 gdb-pending-triggers))
2465 (with-current-buffer (gdb-get-buffer-create 'gdb-partial-output-buffer)
2466 (let* ((res (json-partial-output "frame"))
2467 (stack (gdb-get-field res 'stack))
2468 (buf (gdb-get-buffer 'gdb-stack-buffer)))
2469 (and buf
2470 (with-current-buffer buf
2471 (let ((buffer-read-only nil))
2472 (erase-buffer)
2473 (dolist (frame (nreverse stack))
2474 (insert (apply 'format `("%s in %s" ,@(gdb-get-many-fields frame 'level 'func))))
2475 (gdb-insert-frame-location frame)
2476 (newline))
2477 (gdb-stack-list-frames-custom)))))))
2478
2479 (defun gdb-stack-list-frames-custom ()
2480 (with-current-buffer (gdb-get-buffer 'gdb-stack-buffer)
2481 (save-excursion
2482 (let ((buffer-read-only nil))
2483 (goto-char (point-min))
2484 (forward-line 1)
2485 (while (< (point) (point-max))
2486 (add-text-properties (point-at-bol) (1+ (point-at-bol))
2487 '(mouse-face highlight
2488 help-echo "mouse-2, RET: Select frame"))
2489 (beginning-of-line)
2490 (when (and (looking-at "^[0-9]+\\s-+\\S-+\\s-+\\(\\S-+\\)")
2491 (equal (match-string 1) gdb-selected-frame))
2492 (if (> (car (window-fringes)) 0)
2493 (progn
2494 (or gdb-stack-position
2495 (setq gdb-stack-position (make-marker)))
2496 (set-marker gdb-stack-position (point)))
2497 (let ((bl (point-at-bol)))
2498 (put-text-property bl (+ bl 4)
2499 'face '(:inverse-video t)))))
2500 (forward-line 1))))))
2501
2502 (defun gdb-stack-buffer-name ()
2503 (with-current-buffer gud-comint-buffer
2504 (concat "*stack frames of " (gdb-get-target-string) "*")))
2505
2506 (def-gdb-display-buffer
2507 gdb-display-stack-buffer
2508 'gdb-stack-buffer
2509 "Display backtrace of current stack.")
2510
2511 (def-gdb-frame-for-buffer
2512 gdb-frame-stack-buffer
2513 'gdb-stack-buffer
2514 "Display backtrace of current stack in a new frame.")
2515
2516 (defvar gdb-frames-mode-map
2517 (let ((map (make-sparse-keymap)))
2518 (suppress-keymap map)
2519 (define-key map "q" 'kill-this-buffer)
2520 (define-key map "\r" 'gdb-frames-select)
2521 (define-key map [mouse-2] 'gdb-frames-select)
2522 (define-key map [follow-link] 'mouse-face)
2523 map))
2524
2525 (defvar gdb-frames-font-lock-keywords
2526 '(("in \\([^ ]+\\) of " (1 font-lock-function-name-face)))
2527 "Font lock keywords used in `gdb-frames-mode'.")
2528
2529 (defun gdb-frames-mode ()
2530 "Major mode for gdb call stack.
2531
2532 \\{gdb-frames-mode-map}"
2533 (kill-all-local-variables)
2534 (setq major-mode 'gdb-frames-mode)
2535 (setq mode-name "Frames")
2536 (setq gdb-stack-position nil)
2537 (add-to-list 'overlay-arrow-variable-list 'gdb-stack-position)
2538 (setq truncate-lines t) ;; Make it easier to see overlay arrow.
2539 (setq buffer-read-only t)
2540 (buffer-disable-undo)
2541 (use-local-map gdb-frames-mode-map)
2542 (set (make-local-variable 'font-lock-defaults)
2543 '(gdb-frames-font-lock-keywords))
2544 (run-mode-hooks 'gdb-frames-mode-hook)
2545 'gdb-invalidate-frames)
2546
2547 (defun gdb-get-frame-number ()
2548 (save-excursion
2549 (end-of-line)
2550 (let* ((pos (re-search-backward "^\\([0-9]+\\)" nil t))
2551 (n (or (and pos (match-string-no-properties 1)) "0")))
2552 n)))
2553
2554 (defun gdb-frames-select (&optional event)
2555 "Select the frame and display the relevant source."
2556 (interactive (list last-input-event))
2557 (if event (posn-set-point (event-end event)))
2558 (gud-basic-call (concat "-stack-select-frame " (gdb-get-frame-number))))
2559
2560 \f
2561 ;; Locals buffer.
2562 ;; uses "-stack-list-locals --simple-values". Needs GDB 6.1 onwards.
2563 (gdb-set-buffer-rules 'gdb-locals-buffer
2564 'gdb-locals-buffer-name
2565 'gdb-locals-mode)
2566
2567 (def-gdb-auto-update-trigger gdb-invalidate-locals
2568 (gdb-get-buffer 'gdb-locals-buffer)
2569 "-stack-list-locals --simple-values\n"
2570 gdb-stack-list-locals-handler)
2571
2572 (defconst gdb-stack-list-locals-regexp
2573 (concat "name=\"\\(.*?\\)\",type=\"\\(.*?\\)\""))
2574
2575 (defvar gdb-locals-watch-map
2576 (let ((map (make-sparse-keymap)))
2577 (suppress-keymap map)
2578 (define-key map "\r" 'gud-watch)
2579 (define-key map [mouse-2] 'gud-watch)
2580 map)
2581 "Keymap to create watch expression of a complex data type local variable.")
2582
2583 (defvar gdb-edit-locals-map-1
2584 (let ((map (make-sparse-keymap)))
2585 (suppress-keymap map)
2586 (define-key map "\r" 'gdb-edit-locals-value)
2587 (define-key map [mouse-2] 'gdb-edit-locals-value)
2588 map)
2589 "Keymap to edit value of a simple data type local variable.")
2590
2591 (defun gdb-edit-locals-value (&optional event)
2592 "Assign a value to a variable displayed in the locals buffer."
2593 (interactive (list last-input-event))
2594 (save-excursion
2595 (if event (posn-set-point (event-end event)))
2596 (beginning-of-line)
2597 (let* ((var (current-word))
2598 (value (read-string (format "New value (%s): " var))))
2599 (gud-basic-call
2600 (concat "-gdb-set variable " var " = " value)))))
2601
2602 ;; Dont display values of arrays or structures.
2603 ;; These can be expanded using gud-watch.
2604 (defun gdb-stack-list-locals-handler nil
2605 (setq gdb-pending-triggers (delq 'gdb-invalidate-locals
2606 gdb-pending-triggers))
2607 (let (local locals-list)
2608 (goto-char (point-min))
2609 (while (re-search-forward gdb-stack-list-locals-regexp nil t)
2610 (let ((local (list (match-string 1)
2611 (match-string 2)
2612 nil)))
2613 (if (looking-at ",value=\\(\".*\"\\)}")
2614 (setcar (nthcdr 2 local) (read (match-string 1))))
2615 (push local locals-list)))
2616 (let ((buf (gdb-get-buffer 'gdb-locals-buffer)))
2617 (and buf (with-current-buffer buf
2618 (let* ((window (get-buffer-window buf 0))
2619 (start (window-start window))
2620 (p (window-point window))
2621 (buffer-read-only nil) (name) (value))
2622 (erase-buffer)
2623 (dolist (local locals-list)
2624 (setq name (car local))
2625 (setq value (nth 2 local))
2626 (if (or (not value)
2627 (string-match "\\0x" value))
2628 (add-text-properties 0 (length name)
2629 `(mouse-face highlight
2630 help-echo "mouse-2: create watch expression"
2631 local-map ,gdb-locals-watch-map)
2632 name)
2633 (add-text-properties 0 (length value)
2634 `(mouse-face highlight
2635 help-echo "mouse-2: edit value"
2636 local-map ,gdb-edit-locals-map-1)
2637 value))
2638 (insert
2639 (concat name "\t" (nth 1 local)
2640 "\t" (nth 2 local) "\n")))
2641 (set-window-start window start)
2642 (set-window-point window p)))))))
2643
2644 (defvar gdb-locals-header
2645 `(,(propertize "Locals"
2646 'help-echo "mouse-1: select"
2647 'mouse-face 'mode-line-highlight
2648 'face 'mode-line
2649 'local-map
2650 (gdb-make-header-line-mouse-map
2651 'mouse-1
2652 (lambda (event) (interactive "e")
2653 (save-selected-window
2654 (select-window (posn-window (event-start event)))
2655 (set-window-dedicated-p (selected-window) nil)
2656 (switch-to-buffer
2657 (gdb-get-buffer-create 'gdb-locals-buffer))
2658 (set-window-dedicated-p (selected-window) t)))))
2659 " "
2660 ,(propertize "Registers"
2661 'help-echo "mouse-1: select"
2662 'mouse-face 'mode-line-highlight
2663 'face 'mode-line
2664 'local-map
2665 (gdb-make-header-line-mouse-map
2666 'mouse-1
2667 (lambda (event) (interactive "e")
2668 (save-selected-window
2669 (select-window (posn-window (event-start event)))
2670 (set-window-dedicated-p (selected-window) nil)
2671 (switch-to-buffer
2672 (gdb-get-buffer-create 'gdb-registers-buffer))
2673 (set-window-dedicated-p (selected-window) t)))))))
2674
2675 (defvar gdb-locals-mode-map
2676 (let ((map (make-sparse-keymap)))
2677 (suppress-keymap map)
2678 (define-key map "q" 'kill-this-buffer)
2679 map))
2680
2681 (defun gdb-locals-mode ()
2682 "Major mode for gdb locals.
2683
2684 \\{gdb-locals-mode-map}"
2685 (kill-all-local-variables)
2686 (setq major-mode 'gdb-locals-mode)
2687 (setq mode-name (concat "Locals:" gdb-selected-frame))
2688 (setq buffer-read-only t)
2689 (buffer-disable-undo)
2690 (setq header-line-format gdb-locals-header)
2691 (use-local-map gdb-locals-mode-map)
2692 (set (make-local-variable 'font-lock-defaults)
2693 '(gdb-locals-font-lock-keywords))
2694 (run-mode-hooks 'gdb-locals-mode-hook)
2695 'gdb-invalidate-locals)
2696
2697 (defun gdb-locals-buffer-name ()
2698 (with-current-buffer gud-comint-buffer
2699 (concat "*locals of " (gdb-get-target-string) "*")))
2700
2701 (def-gdb-display-buffer
2702 gdb-display-locals-buffer
2703 'gdb-locals-buffer
2704 "Display local variables of current stack and their values.")
2705
2706 (def-gdb-frame-for-buffer
2707 gdb-frame-locals-buffer
2708 'gdb-locals-buffer
2709 "Display local variables of current stack and their values in a new frame.")
2710
2711 \f
2712 ;; Registers buffer.
2713 ;;
2714 (gdb-set-buffer-rules 'gdb-registers-buffer
2715 'gdb-registers-buffer-name
2716 'gdb-registers-mode)
2717
2718 (def-gdb-auto-update-trigger gdb-invalidate-registers
2719 (gdb-get-buffer 'gdb-registers-buffer)
2720 "-data-list-register-values x\n"
2721 gdb-data-list-register-values-handler)
2722
2723 (defconst gdb-data-list-register-values-regexp
2724 "number=\"\\(.*?\\)\",value=\"\\(.*?\\)\"")
2725
2726 (defun gdb-data-list-register-values-handler ()
2727 (setq gdb-pending-triggers (delq 'gdb-invalidate-registers
2728 gdb-pending-triggers))
2729 (goto-char (point-min))
2730 (if (re-search-forward gdb-error-regexp nil t)
2731 (progn
2732 (let ((match nil))
2733 (setq match (match-string 1))
2734 (with-current-buffer (gdb-get-buffer 'gdb-registers-buffer)
2735 (let ((buffer-read-only nil))
2736 (erase-buffer)
2737 (insert match)
2738 (goto-char (point-min))))))
2739 (let ((register-list (reverse gdb-register-names))
2740 (register nil) (register-string nil) (register-values nil))
2741 (goto-char (point-min))
2742 (while (re-search-forward gdb-data-list-register-values-regexp nil t)
2743 (setq register (pop register-list))
2744 (setq register-string (concat register "\t" (match-string 2) "\n"))
2745 (if (member (match-string 1) gdb-changed-registers)
2746 (put-text-property 0 (length register-string)
2747 'face 'font-lock-warning-face
2748 register-string))
2749 (setq register-values
2750 (concat register-values register-string)))
2751 (let ((buf (gdb-get-buffer 'gdb-registers-buffer)))
2752 (with-current-buffer buf
2753 (let ((p (window-point (get-buffer-window buf 0)))
2754 (buffer-read-only nil))
2755 (erase-buffer)
2756 (insert register-values)
2757 (set-window-point (get-buffer-window buf 0) p))))))
2758 (gdb-data-list-register-values-custom))
2759
2760 (defun gdb-data-list-register-values-custom ()
2761 (with-current-buffer (gdb-get-buffer 'gdb-registers-buffer)
2762 (save-excursion
2763 (let ((buffer-read-only nil)
2764 bl)
2765 (goto-char (point-min))
2766 (while (< (point) (point-max))
2767 (setq bl (line-beginning-position))
2768 (when (looking-at "^[^\t]+")
2769 (put-text-property bl (match-end 0)
2770 'face font-lock-variable-name-face))
2771 (forward-line 1))))))
2772
2773 (defvar gdb-registers-mode-map
2774 (let ((map (make-sparse-keymap)))
2775 (suppress-keymap map)
2776 (define-key map "q" 'kill-this-buffer)
2777 map))
2778
2779 (defun gdb-registers-mode ()
2780 "Major mode for gdb registers.
2781
2782 \\{gdb-registers-mode-map}"
2783 (kill-all-local-variables)
2784 (setq major-mode 'gdb-registers-mode)
2785 (setq mode-name "Registers")
2786 (setq header-line-format gdb-locals-header)
2787 (setq buffer-read-only t)
2788 (buffer-disable-undo)
2789 (use-local-map gdb-registers-mode-map)
2790 (run-mode-hooks 'gdb-registers-mode-hook)
2791 'gdb-invalidate-registers)
2792
2793 (defun gdb-registers-buffer-name ()
2794 (with-current-buffer gud-comint-buffer
2795 (concat "*registers of " (gdb-get-target-string) "*")))
2796
2797 (def-gdb-display-buffer
2798 gdb-display-registers-buffer
2799 'gdb-registers-buffer
2800 "Display integer register contents.")
2801
2802 (def-gdb-frame-for-buffer
2803 gdb-frame-registers-buffer
2804 'gdb-registers-buffer
2805 "Display integer register contents in a new frame.")
2806
2807 ;; Needs GDB 6.4 onwards (used to fail with no stack).
2808 (defun gdb-get-changed-registers ()
2809 (if (and (gdb-get-buffer 'gdb-registers-buffer)
2810 (not (member 'gdb-get-changed-registers gdb-pending-triggers)))
2811 (progn
2812 (gdb-input
2813 (list
2814 "-data-list-changed-registers\n"
2815 'gdb-get-changed-registers-handler))
2816 (push 'gdb-get-changed-registers gdb-pending-triggers))))
2817
2818 (defconst gdb-data-list-register-names-regexp "\"\\(.*?\\)\"")
2819
2820 (defun gdb-get-changed-registers-handler ()
2821 (setq gdb-pending-triggers
2822 (delq 'gdb-get-changed-registers gdb-pending-triggers))
2823 (setq gdb-changed-registers nil)
2824 (goto-char (point-min))
2825 (while (re-search-forward gdb-data-list-register-names-regexp nil t)
2826 (push (match-string 1) gdb-changed-registers)))
2827
2828 (defun gdb-get-register-names ()
2829 "Create a list of register names."
2830 (goto-char (point-min))
2831 (setq gdb-register-names nil)
2832 (while (re-search-forward gdb-data-list-register-names-regexp nil t)
2833 (push (match-string 1) gdb-register-names)))
2834 \f
2835
2836 (defun gdb-get-source-file-list ()
2837 "Create list of source files for current GDB session.
2838 If buffers already exist for any of these files, gud-minor-mode
2839 is set in them."
2840 (goto-char (point-min))
2841 (while (re-search-forward gdb-source-file-regexp nil t)
2842 (push (match-string 1) gdb-source-file-list))
2843 (dolist (buffer (buffer-list))
2844 (with-current-buffer buffer
2845 (when (member buffer-file-name gdb-source-file-list)
2846 (gdb-init-buffer))))
2847 (gdb-force-mode-line-update
2848 (propertize "ready" 'face font-lock-variable-name-face)))
2849
2850 (defun gdb-get-selected-frame ()
2851 (if (not (member 'gdb-get-selected-frame gdb-pending-triggers))
2852 (progn
2853 (gdb-input
2854 (list "-stack-info-frame\n" 'gdb-frame-handler))
2855 (push 'gdb-get-selected-frame
2856 gdb-pending-triggers))))
2857
2858 (defun gdb-frame-handler ()
2859 (setq gdb-pending-triggers
2860 (delq 'gdb-get-selected-frame gdb-pending-triggers))
2861 (let ((frame (gdb-get-field (json-partial-output) 'frame)))
2862 (when frame
2863 (setq gdb-frame-number (gdb-get-field frame 'level))
2864 (setq gdb-pc-address (gdb-get-field frame addr))
2865 (setq gdb-selected-frame (gdb-get-field frame 'func))
2866 (setq gdb-selected-file (gdb-get-field frame 'fullname))
2867 (let ((line (gdb-get-field frame 'line)))
2868 (setq gdb-selected-line (or (and line (string-to-number line))
2869 nil)) ; don't fail if line is nil
2870 (when line ; obey the current file only if we have line info
2871 (setq gud-last-frame (cons gdb-selected-file gdb-selected-line))
2872 (gud-display-frame)))
2873 (if (gdb-get-buffer 'gdb-locals-buffer)
2874 (with-current-buffer (gdb-get-buffer 'gdb-locals-buffer)
2875 (setq mode-name (concat "Locals:" gdb-selected-frame))))
2876 (if (gdb-get-buffer 'gdb-disassembly-buffer)
2877 (with-current-buffer (gdb-get-buffer 'gdb-disassembly-buffer)
2878 (setq mode-name (concat "Machine:" gdb-selected-frame))))
2879 (if gud-overlay-arrow-position
2880 (let ((buffer (marker-buffer gud-overlay-arrow-position))
2881 (position (marker-position gud-overlay-arrow-position)))
2882 (when buffer
2883 (with-current-buffer buffer
2884 (setq fringe-indicator-alist
2885 (if (string-equal gdb-frame-number "0")
2886 nil
2887 '((overlay-arrow . hollow-right-triangle))))
2888 (setq gud-overlay-arrow-position (make-marker))
2889 (set-marker gud-overlay-arrow-position position)))))
2890 (when gdb-selected-line
2891 (gdb-invalidate-disassembly)))))
2892
2893 (defvar gdb-prompt-name-regexp "value=\"\\(.*?\\)\"")
2894
2895 (defun gdb-get-prompt ()
2896 "Find prompt for GDB session."
2897 (goto-char (point-min))
2898 (setq gdb-prompt-name nil)
2899 (re-search-forward gdb-prompt-name-regexp nil t)
2900 (setq gdb-prompt-name (match-string 1))
2901 ;; Insert first prompt.
2902 (setq gdb-filter-output (concat gdb-filter-output gdb-prompt-name)))
2903
2904 ;;;; Window management
2905 (defun gdb-display-buffer (buf dedicated &optional frame)
2906 (let ((answer (get-buffer-window buf (or frame 0))))
2907 (if answer
2908 (display-buffer buf nil (or frame 0)) ;Deiconify the frame if necessary.
2909 (let ((window (get-lru-window)))
2910 (if (eq (buffer-local-value 'gud-minor-mode (window-buffer window))
2911 'gdbmi)
2912 (let* ((largest (get-largest-window))
2913 (cur-size (window-height largest)))
2914 (setq answer (split-window largest))
2915 (set-window-buffer answer buf)
2916 (set-window-dedicated-p answer dedicated)
2917 answer)
2918 (set-window-buffer window buf)
2919 window)))))
2920
2921 \f
2922 ;;; Shared keymap initialization:
2923
2924 (let ((menu (make-sparse-keymap "GDB-Windows")))
2925 (define-key gud-menu-map [displays]
2926 `(menu-item "GDB-Windows" ,menu
2927 :visible (eq gud-minor-mode 'gdbmi)))
2928 (define-key menu [gdb] '("Gdb" . gdb-display-gdb-buffer))
2929 (define-key menu [threads] '("Threads" . gdb-display-threads-buffer))
2930 ; (define-key menu [memory] '("Memory" . gdb-display-memory-buffer))
2931 (define-key menu [memory] '("Memory" . gdb-todo-memory))
2932 (define-key menu [disassembly]
2933 '("Disassembly" . gdb-display-disassembly-buffer))
2934 (define-key menu [registers] '("Registers" . gdb-display-registers-buffer))
2935 (define-key menu [inferior]
2936 '(menu-item "Separate IO" gdb-display-separate-io-buffer
2937 :enable gdb-use-separate-io-buffer))
2938 (define-key menu [locals] '("Locals" . gdb-display-locals-buffer))
2939 (define-key menu [frames] '("Stack" . gdb-display-stack-buffer))
2940 (define-key menu [breakpoints]
2941 '("Breakpoints" . gdb-display-breakpoints-buffer)))
2942
2943 (let ((menu (make-sparse-keymap "GDB-Frames")))
2944 (define-key gud-menu-map [frames]
2945 `(menu-item "GDB-Frames" ,menu
2946 :visible (eq gud-minor-mode 'gdbmi)))
2947 (define-key menu [gdb] '("Gdb" . gdb-frame-gdb-buffer))
2948 (define-key menu [threads] '("Threads" . gdb-frame-threads-buffer))
2949 ; (define-key menu [memory] '("Memory" . gdb-frame-memory-buffer))
2950 (define-key menu [memory] '("Memory" . gdb-todo-memory))
2951 (define-key menu [disassembly] '("Disassembly" . gdb-frame-disassembly-buffer))
2952 (define-key menu [registers] '("Registers" . gdb-frame-registers-buffer))
2953 (define-key menu [inferior]
2954 '(menu-item "Separate IO" gdb-frame-separate-io-buffer
2955 :enable gdb-use-separate-io-buffer))
2956 (define-key menu [locals] '("Locals" . gdb-frame-locals-buffer))
2957 (define-key menu [frames] '("Stack" . gdb-frame-stack-buffer))
2958 (define-key menu [breakpoints]
2959 '("Breakpoints" . gdb-frame-breakpoints-buffer)))
2960
2961 (let ((menu (make-sparse-keymap "GDB-MI")))
2962 (define-key gud-menu-map [mi]
2963 `(menu-item "GDB-MI" ,menu :visible (eq gud-minor-mode 'gdbmi)))
2964 (define-key menu [gdb-customize]
2965 '(menu-item "Customize" (lambda () (interactive) (customize-group 'gdb))
2966 :help "Customize Gdb Graphical Mode options."))
2967 (define-key menu [gdb-use-separate-io]
2968 '(menu-item "Separate IO" gdb-use-separate-io-buffer
2969 :help "Toggle separate IO for debugged program."
2970 :button (:toggle . gdb-use-separate-io-buffer)))
2971 (define-key menu [gdb-many-windows]
2972 '(menu-item "Display Other Windows" gdb-many-windows
2973 :help "Toggle display of locals, stack and breakpoint information"
2974 :button (:toggle . gdb-many-windows)))
2975 (define-key menu [gdb-restore-windows]
2976 '(menu-item "Restore Window Layout" gdb-restore-windows
2977 :help "Restore standard layout for debug session.")))
2978
2979 (defun gdb-frame-gdb-buffer ()
2980 "Display GUD buffer in a new frame."
2981 (interactive)
2982 (let ((special-display-regexps (append special-display-regexps '(".*")))
2983 (special-display-frame-alist
2984 (remove '(menu-bar-lines) (remove '(tool-bar-lines)
2985 gdb-frame-parameters)))
2986 (same-window-regexps nil))
2987 (display-buffer gud-comint-buffer)))
2988
2989 (defun gdb-display-gdb-buffer ()
2990 "Display GUD buffer."
2991 (interactive)
2992 (let ((same-window-regexps nil))
2993 (select-window (display-buffer gud-comint-buffer nil 0))))
2994
2995 (defun gdb-set-window-buffer (name)
2996 (set-window-buffer (selected-window) (get-buffer name))
2997 (set-window-dedicated-p (selected-window) t))
2998
2999 (defun gdb-setup-windows ()
3000 "Layout the window pattern for `gdb-many-windows'."
3001 (gdb-display-locals-buffer)
3002 (gdb-display-stack-buffer)
3003 (delete-other-windows)
3004 (gdb-display-breakpoints-buffer)
3005 (delete-other-windows)
3006 ; Don't dedicate.
3007 (pop-to-buffer gud-comint-buffer)
3008 (split-window nil ( / ( * (window-height) 3) 4))
3009 (split-window nil ( / (window-height) 3))
3010 (split-window-horizontally)
3011 (other-window 1)
3012 (gdb-set-window-buffer (gdb-locals-buffer-name))
3013 (other-window 1)
3014 (switch-to-buffer
3015 (if gud-last-last-frame
3016 (gud-find-file (car gud-last-last-frame))
3017 (if gdb-main-file
3018 (gud-find-file gdb-main-file)
3019 ;; Put buffer list in window if we
3020 ;; can't find a source file.
3021 (list-buffers-noselect))))
3022 (setq gdb-source-window (selected-window))
3023 (when gdb-use-separate-io-buffer
3024 (split-window-horizontally)
3025 (other-window 1)
3026 (gdb-set-window-buffer
3027 (gdb-get-buffer-create 'gdb-inferior-io)))
3028 (other-window 1)
3029 (gdb-set-window-buffer (gdb-stack-buffer-name))
3030 (split-window-horizontally)
3031 (other-window 1)
3032 (gdb-set-window-buffer (gdb-breakpoints-buffer-name))
3033 (other-window 1))
3034
3035 (defcustom gdb-many-windows nil
3036 "If nil just pop up the GUD buffer unless `gdb-show-main' is t.
3037 In this case it starts with two windows: one displaying the GUD
3038 buffer and the other with the source file with the main routine
3039 of the debugged program. Non-nil means display the layout shown for
3040 `gdb'."
3041 :type 'boolean
3042 :group 'gdb
3043 :version "22.1")
3044
3045 (defun gdb-many-windows (arg)
3046 "Toggle the number of windows in the basic arrangement.
3047 With arg, display additional buffers iff arg is positive."
3048 (interactive "P")
3049 (setq gdb-many-windows
3050 (if (null arg)
3051 (not gdb-many-windows)
3052 (> (prefix-numeric-value arg) 0)))
3053 (message (format "Display of other windows %sabled"
3054 (if gdb-many-windows "en" "dis")))
3055 (if (and gud-comint-buffer
3056 (buffer-name gud-comint-buffer))
3057 (condition-case nil
3058 (gdb-restore-windows)
3059 (error nil))))
3060
3061 (defun gdb-restore-windows ()
3062 "Restore the basic arrangement of windows used by gdb.
3063 This arrangement depends on the value of `gdb-many-windows'."
3064 (interactive)
3065 (pop-to-buffer gud-comint-buffer) ;Select the right window and frame.
3066 (delete-other-windows)
3067 (if gdb-many-windows
3068 (gdb-setup-windows)
3069 (when (or gud-last-last-frame gdb-show-main)
3070 (split-window)
3071 (other-window 1)
3072 (switch-to-buffer
3073 (if gud-last-last-frame
3074 (gud-find-file (car gud-last-last-frame))
3075 (gud-find-file gdb-main-file)))
3076 (setq gdb-source-window (selected-window))
3077 (other-window 1))))
3078
3079 (defun gdb-reset ()
3080 "Exit a debugging session cleanly.
3081 Kills the gdb buffers, and resets variables and the source buffers."
3082 (dolist (buffer (buffer-list))
3083 (unless (eq buffer gud-comint-buffer)
3084 (with-current-buffer buffer
3085 (if (eq gud-minor-mode 'gdbmi)
3086 (if (string-match "\\` ?\\*.+\\*\\'" (buffer-name))
3087 (kill-buffer nil)
3088 (gdb-remove-breakpoint-icons (point-min) (point-max) t)
3089 (setq gud-minor-mode nil)
3090 (kill-local-variable 'tool-bar-map)
3091 (kill-local-variable 'gdb-define-alist))))))
3092 (setq gdb-overlay-arrow-position nil)
3093 (setq overlay-arrow-variable-list
3094 (delq 'gdb-overlay-arrow-position overlay-arrow-variable-list))
3095 (setq fringe-indicator-alist '((overlay-arrow . right-triangle)))
3096 (setq gdb-stack-position nil)
3097 (setq overlay-arrow-variable-list
3098 (delq 'gdb-stack-position overlay-arrow-variable-list))
3099 (if (boundp 'speedbar-frame) (speedbar-timer-fn))
3100 (setq gud-running nil)
3101 (setq gdb-active-process nil)
3102 (remove-hook 'after-save-hook 'gdb-create-define-alist t))
3103
3104 (defun gdb-get-source-file ()
3105 "Find the source file where the program starts and display it with related
3106 buffers, if required."
3107 (goto-char (point-min))
3108 (if (re-search-forward gdb-source-file-regexp nil t)
3109 (setq gdb-main-file (match-string 1)))
3110 (if gdb-many-windows
3111 (gdb-setup-windows)
3112 (gdb-get-buffer-create 'gdb-breakpoints-buffer)
3113 (if gdb-show-main
3114 (let ((pop-up-windows t))
3115 (display-buffer (gud-find-file gdb-main-file))))))
3116
3117 ;;from put-image
3118 (defun gdb-put-string (putstring pos &optional dprop &rest sprops)
3119 "Put string PUTSTRING in front of POS in the current buffer.
3120 PUTSTRING is displayed by putting an overlay into the current buffer with a
3121 `before-string' string that has a `display' property whose value is
3122 PUTSTRING."
3123 (let ((string (make-string 1 ?x))
3124 (buffer (current-buffer)))
3125 (setq putstring (copy-sequence putstring))
3126 (let ((overlay (make-overlay pos pos buffer))
3127 (prop (or dprop
3128 (list (list 'margin 'left-margin) putstring))))
3129 (put-text-property 0 1 'display prop string)
3130 (if sprops
3131 (add-text-properties 0 1 sprops string))
3132 (overlay-put overlay 'put-break t)
3133 (overlay-put overlay 'before-string string))))
3134
3135 ;;from remove-images
3136 (defun gdb-remove-strings (start end &optional buffer)
3137 "Remove strings between START and END in BUFFER.
3138 Remove only strings that were put in BUFFER with calls to `gdb-put-string'.
3139 BUFFER nil or omitted means use the current buffer."
3140 (unless buffer
3141 (setq buffer (current-buffer)))
3142 (dolist (overlay (overlays-in start end))
3143 (when (overlay-get overlay 'put-break)
3144 (delete-overlay overlay))))
3145
3146 (defun gdb-put-breakpoint-icon (enabled bptno)
3147 (let ((start (- (line-beginning-position) 1))
3148 (end (+ (line-end-position) 1))
3149 (putstring (if enabled "B" "b"))
3150 (source-window (get-buffer-window (current-buffer) 0)))
3151 (add-text-properties
3152 0 1 '(help-echo "mouse-1: clear bkpt, mouse-3: enable/disable bkpt")
3153 putstring)
3154 (if enabled
3155 (add-text-properties
3156 0 1 `(gdb-bptno ,bptno gdb-enabled t) putstring)
3157 (add-text-properties
3158 0 1 `(gdb-bptno ,bptno gdb-enabled nil) putstring))
3159 (gdb-remove-breakpoint-icons start end)
3160 (if (display-images-p)
3161 (if (>= (or left-fringe-width
3162 (if source-window (car (window-fringes source-window)))
3163 gdb-buffer-fringe-width) 8)
3164 (gdb-put-string
3165 nil (1+ start)
3166 `(left-fringe breakpoint
3167 ,(if enabled
3168 'breakpoint-enabled
3169 'breakpoint-disabled))
3170 'gdb-bptno bptno
3171 'gdb-enabled enabled)
3172 (when (< left-margin-width 2)
3173 (save-current-buffer
3174 (setq left-margin-width 2)
3175 (if source-window
3176 (set-window-margins
3177 source-window
3178 left-margin-width right-margin-width))))
3179 (put-image
3180 (if enabled
3181 (or breakpoint-enabled-icon
3182 (setq breakpoint-enabled-icon
3183 (find-image `((:type xpm :data
3184 ,breakpoint-xpm-data
3185 :ascent 100 :pointer hand)
3186 (:type pbm :data
3187 ,breakpoint-enabled-pbm-data
3188 :ascent 100 :pointer hand)))))
3189 (or breakpoint-disabled-icon
3190 (setq breakpoint-disabled-icon
3191 (find-image `((:type xpm :data
3192 ,breakpoint-xpm-data
3193 :conversion disabled
3194 :ascent 100 :pointer hand)
3195 (:type pbm :data
3196 ,breakpoint-disabled-pbm-data
3197 :ascent 100 :pointer hand))))))
3198 (+ start 1)
3199 putstring
3200 'left-margin))
3201 (when (< left-margin-width 2)
3202 (save-current-buffer
3203 (setq left-margin-width 2)
3204 (let ((window (get-buffer-window (current-buffer) 0)))
3205 (if window
3206 (set-window-margins
3207 window left-margin-width right-margin-width)))))
3208 (gdb-put-string
3209 (propertize putstring
3210 'face (if enabled 'breakpoint-enabled 'breakpoint-disabled))
3211 (1+ start)))))
3212
3213 (defun gdb-remove-breakpoint-icons (start end &optional remove-margin)
3214 (gdb-remove-strings start end)
3215 (if (display-images-p)
3216 (remove-images start end))
3217 (when remove-margin
3218 (setq left-margin-width 0)
3219 (let ((window (get-buffer-window (current-buffer) 0)))
3220 (if window
3221 (set-window-margins
3222 window left-margin-width right-margin-width)))))
3223
3224 (provide 'gdb-mi)
3225
3226 ;; arch-tag: 1b41ea2b-f364-4cec-8f35-e02e4fe01912
3227 ;;; gdb-mi.el ends here