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