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