Don't quote lambda expressions with `quote'.
[bpt/emacs.git] / lisp / progmodes / gdb-mi.el
CommitLineData
691cf4a0
NR
1;;; gdb-mi.el --- User Interface for running GDB
2
73b0cd50 3;; Copyright (C) 2007-2011 Free Software Foundation, Inc.
691cf4a0
NR
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
e02f48d7
JB
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
691cf4a0
NR
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
129Invalidation triggers use this variable to query GDB for
130information on the specified thread by wrapping GDB/MI commands
131in `gdb-current-context-command'.
132
133This variable may be updated implicitly by GDB via `gdb-stopped'
134or explicitly by `gdb-select-thread'.
135
136Only `gdb-setq-thread-number' should be used to change this
137value.")
138
139(defvar gdb-frame-number nil
140 "Selected frame level for main current thread.
141
142Updated according to the following rules:
143
144When a thread is selected or current thread stops, set to \"0\".
145
146When current thread goes running (and possibly exits eventually),
147set to nil.
148
149May 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
166Keys are thread numbers (in strings) and values are structures as
167returned 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
40b1a3a9 173If nil, no information is available.
691cf4a0
NR
174
175Updated in `gdb-thread-list-handler-custom'.")
176
177(defvar gdb-stopped-threads-count nil
178 "Number of currently stopped threads.
179
180See also `gdb-running-threads-count'.")
181
182(defvar gdb-breakpoints-list nil
183 "Associative list of breakpoints provided by \"-break-list\" MI command.
184
185Keys are breakpoint numbers (in string) and values are structures
186as 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.
193Each element has the form (VARNUM EXPRESSION NUMCHILD TYPE VALUE STATUS HAS_MORE FP)
194where STATUS is nil (`unchanged'), `changed' or `out-of-scope', FP the frame
195address 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
205Emacs 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
230This 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
236It is initialized to `gdb-non-stop-setting' at the beginning of
237every 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.
245Possible 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
261Elements 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
274This 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
288SUBSCRIBER must be a pair, where cdr is a function of one
289argument (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
309Must be a list of pairs with cars being buffers and cdr's being
310valid 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
337other threads continue to execute.
338
339GDB session needs to be restarted for this setting to take
340effect."
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
349in 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
356which caused the stop. When t, switch to stopped thread no matter
357what the reason was. When nil, never switch to stopped thread
358automatically.
359
360This setting is used in non-stop mode only. In all-stop mode,
361Emacs 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
384GDB stops.
385
386Each function takes one argument, a parsed MI response, which
387contains 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
400Note 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
404Each function is called after the new current thread was selected
405and 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
413stopped 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
456default."
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.
463Most 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.
475This list is used to display the #define directive associated
476with an identifier as a tooltip. It works in a debug session with
477GDB, when `gud-tooltip-mode' is t.
478
479Set `gdb-cpp-define-alist-flags' for any include paths or
480predefined 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.
505Also 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.
522The log is stored in `gdb-debug-log' as an alist with elements
523whose cons is send, send-item or recv and whose cdr is the string
524being transferred. This list may grow up to a size of
525`gdb-debug-log-max' after which the oldest element (at the end of
526the 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))
e02f48d7 554 (varnum (car var)) expr)
691cf4a0
NR
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.
574If NOALL is t, always add --thread option no matter what
575`gdb-gud-control-all-threads' value is.
576
577When `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
588CMD1 and CMD2. NOALL is the same as in `gdb-gud-context-command'.
589
590NOARG 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*.
598The directory containing FILE becomes the initial working directory
599and source-file directory for your debugger.
600
601If `gdb-many-windows' is nil (the default value) then gdb just
602pops up the GUD buffer unless `gdb-show-main' is t. In this case
603it starts with two windows: one displaying the GUD buffer and the
604other with the source file with the main routine of the inferior.
605
606If `gdb-many-windows' is t, regardless of the value of
607`gdb-show-main', the layout below will appear. Keybindings are
608shown in some of the buffers.
609
610Watch expressions appear in the speedbar/slowbar.
611
612The 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
617See Info node `(emacs)GDB Graphical Interface' for a more
618detailed 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)
ac8331a7 657 (when (ring-empty-p comint-input-ring) ; cf shell-mode
927c53e7 658 (let ((hfile (expand-file-name (or (getenv "GDBHISTFILE")
13522cb4
GM
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))))))))
1289e5d3 681 (and (stringp hsize)
791cd386 682 (integerp (setq hsize (string-to-number hsize)))
1289e5d3
GM
683 (> hsize 0)
684 (set (make-local-variable 'comint-input-ring-size) hsize))
13522cb4
GM
685 (if (stringp hfile)
686 (set (make-local-variable 'comint-input-ring-file-name) hfile))
687 (comint-read-input-ring t)))
691cf4a0
NR
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 "
683cc385
MA
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"))))
691cf4a0
NR
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.
936The destination source line can be selected either by clicking
937with mouse-3 on the fringe/margin or dragging the arrow
938with 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.
954The destination source line can be selected either by clicking with C-mouse-3
955on the fringe/margin or dragging the arrow with C-mouse-1 (default bindings).
956Unlike `gdb-mouse-until' the destination address can be before the current
957line, 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.
977Out of scope variables are suppressed with `shadow' face.
978Changed 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.
1010With prefix argument ARG, automatically raise speedbar if ARG is
1011positive, 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.
1027With 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))
175069ef 1041 (concat (if (derived-mode-p 'gdb-registers-mode) "$")
691cf4a0
NR
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
e02f48d7 1161(defun gdb-edit-value (_text _token _indent)
691cf4a0
NR
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.
1251TEXT is the text of the button we clicked on, a + or - item.
1252TOKEN is data related to this node.
1253INDENT 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
1299it 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
1311When current buffer is not bound to any thread, return main
1312thread."
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
1326is 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
1333In that buffer, `gdb-buffer-type' must be equal to BUFFER-TYPE
1334and `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.
1345The buffer-type should be one of the cars in `gdb-buffer-rules'.
1346
1347If THREAD is non-nil, it is assigned to `gdb-thread-number'
1348buffer-local variable of the new buffer.
1349
1350Buffer mode and name are selected according to buffer type.
1351
1352If buffer has trigger associated with it in `gdb-buffer-rules',
1353this 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
1387DOC 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
1398DOC 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"
175069ef 1508 "Major mode for gdb inferior-io."
691cf4a0 1509 :syntax-table nil :abbrev-table nil
175069ef 1510 (make-comint-in-buffer "gdb-inferior" (current-buffer) nil))
691cf4a0
NR
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 */
1549static 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
157010 10\",
15710 0 0 0 1 1 1 1 0 0 0 0
15720 0 0 1 1 1 1 1 1 0 0 0
15730 0 1 1 1 1 1 1 1 1 0 0
15740 1 1 1 1 1 1 1 1 1 1 0
15750 1 1 1 1 1 1 1 1 1 1 0
15760 1 1 1 1 1 1 1 1 1 1 0
15770 1 1 1 1 1 1 1 1 1 1 0
15780 0 1 1 1 1 1 1 1 1 0 0
15790 0 0 1 1 1 1 1 1 0 0 0
15800 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
158510 10\",
15860 0 1 0 1 0 1 0 0 0
15870 1 0 1 0 1 0 1 0 0
15881 0 1 0 1 0 1 0 1 0
15890 1 0 1 0 1 0 1 0 1
15901 0 1 0 1 0 1 0 1 0
15910 1 0 1 0 1 0 1 0 1
15921 0 1 0 1 0 1 0 1 0
15930 1 0 1 0 1 0 1 0 1
15940 0 1 0 1 0 1 0 1 0
15950 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
1679If `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'
1733value to NUMBER, because `gud-running' and `gdb-frame-number'
1734need 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
1745Note that when `gdb-gud-control-all-threads' is t, `gud-running'
1746cannot be reliably used to determine whether or not execution
1747control buttons should be shown in menu or toolbar. Use
1748`gdb-running-threads-count' and `gdb-stopped-threads-count'
1749instead.
1750
1751For all-stop mode, thread information is unavailable while target
1752is 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 "")
e02f48d7 1830 (let (output-record-list)
691cf4a0
NR
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
e02f48d7 1870(defun gdb-gdb (_output-field))
691cf4a0
NR
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
e02f48d7 1877(defun gdb-ignored-notification (_output-field))
691cf4a0
NR
1878
1879;; gdb-invalidate-threads is defined to accept 'update-threads signal
e02f48d7 1880(defun gdb-thread-created (_output-field))
691cf4a0
NR
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
1897Sets `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
e02f48d7 1928(defun gdb-starting (_output-field)
691cf4a0
NR
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
1944current 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
2083Field names are wrapped in double quotes and equal signs are
2084replaced with semicolons.
2085
40b1a3a9 2086If FIX-KEY is non-nil, strip all \"FIX-KEY=\" occurrences from
691cf4a0
NR
2087partial output. This is used to get rid of useless keys in lists
2088in MI messages, e.g.: [key=.., key=..]. -stack-list-frames and
2089-break-info are examples of MI commands which issue such
2090responses.
2091
2092If 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
2095incompatible 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
2128FIX-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
2138FIX-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
2146FIX-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
2160If current window has no fringes, inverse colors on LINE.
2161
2162Return 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.
2188If there are several SEQS, FUNCTION is called with that many
2189arugments, and mapping stops as sson as the shortest list runs
2190out."
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
2203When non-nil, PROPERTIES will be added to the whole row when
2204calling `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."
e02f48d7 2229 (let ((column-sizes (gdb-table-column-sizes table)))
691cf4a0
NR
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
2255HANDLER-NAME as its handler. HANDLER-NAME is bound to current
2256buffer with `gdb-bind-function-to-buffer'.
2257
2258If SIGNAL-LIST is non-nil, GDB-COMMAND is sent only when the
2259defined trigger is called with an argument from SIGNAL-LIST. It's
2260not recommended to define triggers with empty SIGNAL-LIST.
2261Normally triggers should respond at least to 'update signal.
2262
2263Normally the trigger defined by this command must be called from
2264the buffer where HANDLER-NAME must work. This should be done so
2265that buffer-local thread number may be used in GDB-COMMAND (by
2266calling `gdb-current-context-command').
2267`gdb-bind-function-to-buffer' is used to achieve this, see
2268`gdb-get-buffer-create'.
2269
2270Triggers defined by this command are meant to be used as a
2271trigger 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
2290Handlers are normally called from the buffers they put output in.
2291
2292Delete ((current-buffer) . TRIGGER-NAME) from
2293`gdb-pending-triggers', erase current buffer and evaluate
2294CUSTOM-DEFUN. Then `gdb-update-buffer-name' is called.
2295
2296If 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
2315TRIGGER-NAME trigger is defined to send GDB-COMMAND. See
2316`def-gdb-auto-update-trigger'.
2317
2318HANDLER-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 "
c1b4afac
SS
2371 (propertize (or func "unknown")
2372 'font-lock-face font-lock-function-name-face)
691cf4a0
NR
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 ()
e02f48d7
JB
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))))))))))
691cf4a0
NR
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.
2420Put 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.
2430Add 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
2441of 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.
2457If 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)
175069ef 2462 (if (or (buffer-file-name) (derived-mode-p 'gdb-disassembly-mode))
691cf4a0
NR
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)
4f91a816 2542 (define-key map "\t" (lambda ()
691cf4a0
NR
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) "\
2558Return a keymap with single entry for mouse key MOUSE on the header line.
2559MOUSE is defined to run function FUNCTION with no args in the buffer
2560corresponding 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)
4f91a816 2629 (define-key map "\t" (lambda ()
691cf4a0
NR
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"
175069ef 2646 "Major mode for GDB threads."
691cf4a0
NR
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))
691cf4a0
NR
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
2716CUSTOM-DEFUN may use locally bound `thread' variable, which will
2717be 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
2732on 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
2768current 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
2774current 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
2780current 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
2786current 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
2791line."
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
2870SIZE is in bytes, as in `gdb-memory-unit'. FORMAT is a string as
2871in `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
2974DOC 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
b016851c
SM
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)
691cf4a0
NR
3025 "Menu of display formats in the header line.")
3026
691cf4a0
NR
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
3043DOC 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
3064The defined function switches Memory buffer to show address
3065stored in ADDRESS-VAR variable.
3066
3067DOC 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
b016851c
SM
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)
691cf4a0
NR
3101 "Menu of units in the header line.")
3102
691cf4a0
NR
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"
175069ef 3180 "Major mode for examining memory."
691cf4a0
NR
3181 (setq header-line-format gdb-memory-header)
3182 (set (make-local-variable 'font-lock-defaults)
3183 '(gdb-memory-font-lock-keywords))
691cf4a0
NR
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"
175069ef 3272 "Major mode for GDB disassembly information."
691cf4a0
NR
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))
691cf4a0
NR
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))
691cf4a0
NR
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"
175069ef 3335 "Major mode for gdb breakpoints."
691cf4a0 3336 (setq header-line-format gdb-breakpoints-header)
691cf4a0
NR
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
3365breakpoints 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
3408FRAME must have either \"file\" and \"line\" members or \"from\"
3409member."
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"
175069ef 3475 "Major mode for gdb call stack."
691cf4a0
NR
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))
691cf4a0
NR
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)
4f91a816 3585 (define-key map "\t" (lambda ()
691cf4a0
NR
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"
175069ef 3594 "Major mode for gdb locals."
691cf4a0 3595 (setq header-line-format gdb-locals-header)
691cf4a0
NR
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)
4f91a816 3673 (define-key map "\t" (lambda ()
691cf4a0
NR
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"
175069ef 3690 "Major mode for gdb registers."
691cf4a0 3691 (setq header-line-format gdb-registers-header)
691cf4a0
NR
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.
3740If buffers already exist for any of these files, gud-minor-mode
3741is 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
3754thread. 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
3763overlay 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
3803If BUF is already displayed in some window, show it, deiconifying
3804the frame if necessary. Otherwise, find least recently used
3805window and show BUF there, if the window is not used for GDB
3806already, 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)
e02f48d7 3813 (let ((largest (get-largest-window)))
691cf4a0
NR
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
3824exists, just call `gdb-display-buffer' for BUF. If the window
3825found is already dedicated, split window according to
3826SPLIT-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
3966When IGNORE-DEDICATED is non-nil, buffer is set even if selected
3967window 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.
4012In this case it starts with two windows: one displaying the GUD
4013buffer and the other with the source file with the main routine
4014of 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.
4022With 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.
4038This 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.
4056Kills 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
4084buffers, 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.
4098PUTSTRING is displayed by putting an overlay into the current buffer with a
4099`before-string' string that has a `display' property whose value is
4100PUTSTRING."
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.
4116Remove only strings that were put in BUFFER with calls to `gdb-put-string'.
4117BUFFER 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
691cf4a0 4205;;; gdb-mi.el ends here