diff options
| author | Jean-Philippe Gravel | 2013-03-11 13:13:39 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2013-03-11 13:13:39 -0400 |
| commit | 6ff2c8f1febc01a8c59accc340b91b51c41677cf (patch) | |
| tree | 8808067592c1ebb722cae8d2fa1eca9b5dc64184 | |
| parent | b388e7ad07438a3e3434b63798e3a691982e3bc4 (diff) | |
| download | emacs-6ff2c8f1febc01a8c59accc340b91b51c41677cf.tar.gz emacs-6ff2c8f1febc01a8c59accc340b91b51c41677cf.zip | |
* lisp/progmodes/gdb-mi.el: Speed up initialization. Use lexical-binding.
Fix up docstring according to conventions.
(gdbmi-debug-mode): New var.
(gdbmi-start-with, gdbmi-same-start, gdbmi-is-number, gdbmi-bnf-init)
(gdbmi-bnf-output, gdbmi-bnf-skip-unrecognized, gdbmi-bnf-gdb-prompt)
(gdbmi-bnf-result-record, gdbmi-bnf-out-of-band-record)
(gdbmi-bnf-async-record, gdbmi-bnf-stream-record)
(gdbmi-bnf-console-stream-output, gdbmi-bnf-target-stream-output)
(gdbmi-bnf-log-stream-output, gdbmi-bnf-result-and-async-record-impl)
(gdbmi-bnf-incomplete-record-result): New functions.
(gdb-car<): Remove function.
(gdbmi-record-list): Remove variable.
(gdbmi-bnf-state, gdbmi-bnf-offset): New vars.
(gdbmi-bnf-result-state-configs): New const.
(gud-gdbmi-marker-filter): Rewrite.
(gdb-ignored-notification, gdb-thread-created, gdb-thread-exited)
(gdb-thread-selected, gdb-running, gdb-starting, gdb-stopped):
Add `token' argument.
(gdb-done, gdb-error): New functions.
(gdb-done-or-error): Add `is-complete' argument. Change arg order.
Fixes: debbugs:10580
| -rw-r--r-- | lisp/ChangeLog | 23 | ||||
| -rw-r--r-- | lisp/progmodes/gdb-mi.el | 632 |
2 files changed, 488 insertions, 167 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 1f136ca398a..483957033bd 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,26 @@ | |||
| 1 | 2013-03-11 Jean-Philippe Gravel <jpgravel@gmail.com> | ||
| 2 | |||
| 3 | * progmodes/gdb-mi.el: Speed up initialization (bug#10580). | ||
| 4 | Use lexical-binding. Fix up docstring according to conventions. | ||
| 5 | (gdbmi-debug-mode): New var. | ||
| 6 | (gdbmi-start-with, gdbmi-same-start, gdbmi-is-number, gdbmi-bnf-init) | ||
| 7 | (gdbmi-bnf-output, gdbmi-bnf-skip-unrecognized, gdbmi-bnf-gdb-prompt) | ||
| 8 | (gdbmi-bnf-result-record, gdbmi-bnf-out-of-band-record) | ||
| 9 | (gdbmi-bnf-async-record, gdbmi-bnf-stream-record) | ||
| 10 | (gdbmi-bnf-console-stream-output, gdbmi-bnf-target-stream-output) | ||
| 11 | (gdbmi-bnf-log-stream-output, gdbmi-bnf-result-and-async-record-impl) | ||
| 12 | (gdbmi-bnf-incomplete-record-result): New functions. | ||
| 13 | (gdb-car<): Remove function. | ||
| 14 | (gdbmi-record-list): Remove variable. | ||
| 15 | (gdbmi-bnf-state, gdbmi-bnf-offset): New vars. | ||
| 16 | (gdbmi-bnf-result-state-configs): New const. | ||
| 17 | (gud-gdbmi-marker-filter): Rewrite. | ||
| 18 | (gdb-ignored-notification, gdb-thread-created, gdb-thread-exited) | ||
| 19 | (gdb-thread-selected, gdb-running, gdb-starting, gdb-stopped): | ||
| 20 | Add `token' argument. | ||
| 21 | (gdb-done, gdb-error): New functions. | ||
| 22 | (gdb-done-or-error): Add `is-complete' argument. Change arg order. | ||
| 23 | |||
| 1 | 2013-03-11 Stefan Monnier <monnier@iro.umontreal.ca> | 24 | 2013-03-11 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 25 | ||
| 3 | * term/xterm.el (xterm--report-background-handler): Don't burp | 26 | * term/xterm.el (xterm--report-background-handler): Don't burp |
diff --git a/lisp/progmodes/gdb-mi.el b/lisp/progmodes/gdb-mi.el index 90c7cfc5008..8ba2822c3a3 100644 --- a/lisp/progmodes/gdb-mi.el +++ b/lisp/progmodes/gdb-mi.el | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | ;;; gdb-mi.el --- User Interface for running GDB | 1 | ;;; gdb-mi.el --- User Interface for running GDB -*- lexical-binding: t -*- |
| 2 | 2 | ||
| 3 | ;; Copyright (C) 2007-2013 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 2007-2013 Free Software Foundation, Inc. |
| 4 | 4 | ||
| @@ -192,8 +192,8 @@ address for root variables.") | |||
| 192 | (defvar gdb-disassembly-position nil) | 192 | (defvar gdb-disassembly-position nil) |
| 193 | 193 | ||
| 194 | (defvar gdb-location-alist nil | 194 | (defvar gdb-location-alist nil |
| 195 | "Alist of breakpoint numbers and full filenames. Only used for files that | 195 | "Alist of breakpoint numbers and full filenames. |
| 196 | Emacs can't find.") | 196 | Only used for files that Emacs can't find.") |
| 197 | (defvar gdb-active-process nil | 197 | (defvar gdb-active-process nil |
| 198 | "GUD tooltips display variable values when t, and macro definitions otherwise.") | 198 | "GUD tooltips display variable values when t, and macro definitions otherwise.") |
| 199 | (defvar gdb-error "Non-nil when GDB is reporting an error.") | 199 | (defvar gdb-error "Non-nil when GDB is reporting an error.") |
| @@ -227,9 +227,8 @@ This variable is updated in `gdb-done-or-error' and returned by | |||
| 227 | It is initialized to `gdb-non-stop-setting' at the beginning of | 227 | It is initialized to `gdb-non-stop-setting' at the beginning of |
| 228 | every GDB session.") | 228 | every GDB session.") |
| 229 | 229 | ||
| 230 | (defvar gdb-buffer-type nil | 230 | (defvar-local gdb-buffer-type nil |
| 231 | "One of the symbols bound in `gdb-buffer-rules'.") | 231 | "One of the symbols bound in `gdb-buffer-rules'.") |
| 232 | (make-variable-buffer-local 'gdb-buffer-type) | ||
| 233 | 232 | ||
| 234 | (defvar gdb-output-sink 'nil | 233 | (defvar gdb-output-sink 'nil |
| 235 | "The disposition of the output of the current gdb command. | 234 | "The disposition of the output of the current gdb command. |
| @@ -294,9 +293,7 @@ argument (see `gdb-emit-signal')." | |||
| 294 | (funcall (cdr subscriber) signal))) | 293 | (funcall (cdr subscriber) signal))) |
| 295 | 294 | ||
| 296 | (defvar gdb-buf-publisher '() | 295 | (defvar gdb-buf-publisher '() |
| 297 | "Used to invalidate GDB buffers by emitting a signal in | 296 | "Used to invalidate GDB buffers by emitting a signal in `gdb-update'. |
| 298 | `gdb-update'. | ||
| 299 | |||
| 300 | Must be a list of pairs with cars being buffers and cdr's being | 297 | Must be a list of pairs with cars being buffers and cdr's being |
| 301 | valid signal handlers.") | 298 | valid signal handlers.") |
| 302 | 299 | ||
| @@ -327,8 +324,7 @@ valid signal handlers.") | |||
| 327 | "When in non-stop mode, stopped threads can be examined while | 324 | "When in non-stop mode, stopped threads can be examined while |
| 328 | other threads continue to execute. | 325 | other threads continue to execute. |
| 329 | 326 | ||
| 330 | GDB session needs to be restarted for this setting to take | 327 | GDB session needs to be restarted for this setting to take effect." |
| 331 | effect." | ||
| 332 | :type 'boolean | 328 | :type 'boolean |
| 333 | :group 'gdb-non-stop | 329 | :group 'gdb-non-stop |
| 334 | :version "23.2") | 330 | :version "23.2") |
| @@ -336,19 +332,18 @@ effect." | |||
| 336 | ;; TODO Some commands can't be called with --all (give a notice about | 332 | ;; TODO Some commands can't be called with --all (give a notice about |
| 337 | ;; it in setting doc) | 333 | ;; it in setting doc) |
| 338 | (defcustom gdb-gud-control-all-threads t | 334 | (defcustom gdb-gud-control-all-threads t |
| 339 | "When enabled, GUD execution commands affect all threads when | 335 | "When non-nil, GUD execution commands affect all threads when |
| 340 | in non-stop mode. Otherwise, only current thread is affected." | 336 | in non-stop mode. Otherwise, only current thread is affected." |
| 341 | :type 'boolean | 337 | :type 'boolean |
| 342 | :group 'gdb-non-stop | 338 | :group 'gdb-non-stop |
| 343 | :version "23.2") | 339 | :version "23.2") |
| 344 | 340 | ||
| 345 | (defcustom gdb-switch-reasons t | 341 | (defcustom gdb-switch-reasons t |
| 346 | "List of stop reasons which cause Emacs to switch to the thread | 342 | "List of stop reasons for which Emacs should switch thread. |
| 347 | which caused the stop. When t, switch to stopped thread no matter | 343 | When t, switch to stopped thread no matter what the reason was. |
| 348 | what the reason was. When nil, never switch to stopped thread | 344 | When nil, never switch to stopped thread automatically. |
| 349 | automatically. | ||
| 350 | 345 | ||
| 351 | This setting is used in non-stop mode only. In all-stop mode, | 346 | This setting is used in non-stop mode only. In all-stop mode, |
| 352 | Emacs always switches to the thread which caused the stop." | 347 | Emacs always switches to the thread which caused the stop." |
| 353 | ;; exited, exited-normally and exited-signaled are not | 348 | ;; exited, exited-normally and exited-signaled are not |
| 354 | ;; thread-specific stop reasons and therefore are not included in | 349 | ;; thread-specific stop reasons and therefore are not included in |
| @@ -404,7 +399,7 @@ and GDB buffers were updated in `gdb-stopped'." | |||
| 404 | :link '(info-link "(gdb)GDB/MI Async Records")) | 399 | :link '(info-link "(gdb)GDB/MI Async Records")) |
| 405 | 400 | ||
| 406 | (defcustom gdb-switch-when-another-stopped t | 401 | (defcustom gdb-switch-when-another-stopped t |
| 407 | "When nil, Emacs won't switch to stopped thread if some other | 402 | "When nil, don't switch to stopped thread if some other |
| 408 | stopped thread is already selected." | 403 | stopped thread is already selected." |
| 409 | :type 'boolean | 404 | :type 'boolean |
| 410 | :group 'gdb-non-stop | 405 | :group 'gdb-non-stop |
| @@ -447,8 +442,7 @@ stopped thread is already selected." | |||
| 447 | :version "23.2") | 442 | :version "23.2") |
| 448 | 443 | ||
| 449 | (defcustom gdb-show-threads-by-default nil | 444 | (defcustom gdb-show-threads-by-default nil |
| 450 | "Show threads list buffer instead of breakpoints list by | 445 | "Show threads list buffer instead of breakpoints list by default." |
| 451 | default." | ||
| 452 | :type 'boolean | 446 | :type 'boolean |
| 453 | :group 'gdb-buffers | 447 | :group 'gdb-buffers |
| 454 | :version "23.2") | 448 | :version "23.2") |
| @@ -490,12 +484,12 @@ predefined macros." | |||
| 490 | 484 | ||
| 491 | (defcustom gdb-create-source-file-list t | 485 | (defcustom gdb-create-source-file-list t |
| 492 | "Non-nil means create a list of files from which the executable was built. | 486 | "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 | 487 | 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 | 488 | line for a long time when starting, possibly because your executable was |
| 495 | built from a large number of files. This allows quicker initialization | 489 | built from a large number of files. This allows quicker initialization |
| 496 | but means that these files are not automatically enabled for debugging, | 490 | 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 | 491 | e.g., you won't be able to click in the fringe to set a breakpoint until |
| 498 | execution has already stopped there." | 492 | execution has already stopped there." |
| 499 | :type 'boolean | 493 | :type 'boolean |
| 500 | :group 'gdb | 494 | :group 'gdb |
| 501 | :version "23.1") | 495 | :version "23.1") |
| @@ -507,6 +501,9 @@ Also display the main routine in the disassembly buffer if present." | |||
| 507 | :group 'gdb | 501 | :group 'gdb |
| 508 | :version "22.1") | 502 | :version "22.1") |
| 509 | 503 | ||
| 504 | (defvar gdbmi-debug-mode nil | ||
| 505 | "When non-nil, print the messages sent/received from GDB/MI in *Messages*.") | ||
| 506 | |||
| 510 | (defun gdb-force-mode-line-update (status) | 507 | (defun gdb-force-mode-line-update (status) |
| 511 | (let ((buffer gud-comint-buffer)) | 508 | (let ((buffer gud-comint-buffer)) |
| 512 | (if (and buffer (buffer-name buffer)) | 509 | (if (and buffer (buffer-name buffer)) |
| @@ -570,7 +567,7 @@ When `gdb-non-stop' is nil, return COMMAND unchanged." | |||
| 570 | 567 | ||
| 571 | (defmacro gdb-gud-context-call (cmd1 &optional cmd2 noall noarg) | 568 | (defmacro gdb-gud-context-call (cmd1 &optional cmd2 noall noarg) |
| 572 | "`gud-call' wrapper which adds --thread/--all options between | 569 | "`gud-call' wrapper which adds --thread/--all options between |
| 573 | CMD1 and CMD2. NOALL is the same as in `gdb-gud-context-command'. | 570 | CMD1 and CMD2. NOALL is the same as in `gdb-gud-context-command'. |
| 574 | 571 | ||
| 575 | NOARG must be t when this macro is used outside `gud-def'" | 572 | NOARG must be t when this macro is used outside `gud-def'" |
| 576 | `(gud-call | 573 | `(gud-call |
| @@ -603,7 +600,7 @@ and source-file directory for your debugger. | |||
| 603 | 600 | ||
| 604 | COMMAND-LINE is the shell command for starting the gdb session. | 601 | COMMAND-LINE is the shell command for starting the gdb session. |
| 605 | It should be a string consisting of the name of the gdb | 602 | It should be a string consisting of the name of the gdb |
| 606 | executable followed by command-line options. The command-line | 603 | executable followed by command line options. The command line |
| 607 | options should include \"-i=mi\" to use gdb's MI text interface. | 604 | options should include \"-i=mi\" to use gdb's MI text interface. |
| 608 | Note that the old \"--annotate\" option is no longer supported. | 605 | Note that the old \"--annotate\" option is no longer supported. |
| 609 | 606 | ||
| @@ -846,6 +843,8 @@ detailed description of this mode. | |||
| 846 | gdb-register-names '() | 843 | gdb-register-names '() |
| 847 | gdb-non-stop gdb-non-stop-setting) | 844 | gdb-non-stop gdb-non-stop-setting) |
| 848 | ;; | 845 | ;; |
| 846 | (gdbmi-bnf-init) | ||
| 847 | ;; | ||
| 849 | (setq gdb-buffer-type 'gdbmi) | 848 | (setq gdb-buffer-type 'gdbmi) |
| 850 | ;; | 849 | ;; |
| 851 | (gdb-force-mode-line-update | 850 | (gdb-force-mode-line-update |
| @@ -1254,7 +1253,7 @@ With arg, enter name of variable to be watched in the minibuffer." | |||
| 1254 | (cond | 1253 | (cond |
| 1255 | ((> new previous) | 1254 | ((> new previous) |
| 1256 | ;; Add new children to list. | 1255 | ;; Add new children to list. |
| 1257 | (dotimes (dummy previous) | 1256 | (dotimes (_ previous) |
| 1258 | (push (pop temp-var-list) var-list)) | 1257 | (push (pop temp-var-list) var-list)) |
| 1259 | (dolist (child children) | 1258 | (dolist (child children) |
| 1260 | (let ((varchild | 1259 | (let ((varchild |
| @@ -1268,9 +1267,9 @@ With arg, enter name of variable to be watched in the minibuffer." | |||
| 1268 | (push varchild var-list)))) | 1267 | (push varchild var-list)))) |
| 1269 | ;; Remove deleted children from list. | 1268 | ;; Remove deleted children from list. |
| 1270 | ((< new previous) | 1269 | ((< new previous) |
| 1271 | (dotimes (dummy new) | 1270 | (dotimes (_ new) |
| 1272 | (push (pop temp-var-list) var-list)) | 1271 | (push (pop temp-var-list) var-list)) |
| 1273 | (dotimes (dummy (- previous new)) | 1272 | (dotimes (_ (- previous new)) |
| 1274 | (pop temp-var-list))))) | 1273 | (pop temp-var-list))))) |
| 1275 | (push var1 var-list)) | 1274 | (push var1 var-list)) |
| 1276 | (setq var1 (pop temp-var-list))) | 1275 | (setq var1 (pop temp-var-list))) |
| @@ -1502,7 +1501,7 @@ this trigger is subscribed to `gdb-buf-publisher' and called with | |||
| 1502 | (gdb-input | 1501 | (gdb-input |
| 1503 | (concat "-inferior-tty-set " tty) 'ignore)))) | 1502 | (concat "-inferior-tty-set " tty) 'ignore)))) |
| 1504 | 1503 | ||
| 1505 | (defun gdb-inferior-io-sentinel (proc str) | 1504 | (defun gdb-inferior-io-sentinel (proc _str) |
| 1506 | (when (eq (process-status proc) 'failed) | 1505 | (when (eq (process-status proc) 'failed) |
| 1507 | ;; When the debugged process exits, Emacs gets an EIO error on | 1506 | ;; When the debugged process exits, Emacs gets an EIO error on |
| 1508 | ;; read from the pty, and stops listening to it. If the gdb | 1507 | ;; read from the pty, and stops listening to it. If the gdb |
| @@ -1739,6 +1738,7 @@ complete." | |||
| 1739 | (setq gdb-token-number (1+ gdb-token-number)) | 1738 | (setq gdb-token-number (1+ gdb-token-number)) |
| 1740 | (setq command (concat (number-to-string gdb-token-number) command)) | 1739 | (setq command (concat (number-to-string gdb-token-number) command)) |
| 1741 | (push (cons gdb-token-number handler-function) gdb-handler-alist) | 1740 | (push (cons gdb-token-number handler-function) gdb-handler-alist) |
| 1741 | (if gdbmi-debug-mode (message "gdb-input: %s" command)) | ||
| 1742 | (process-send-string (get-buffer-process gud-comint-buffer) | 1742 | (process-send-string (get-buffer-process gud-comint-buffer) |
| 1743 | (concat command "\n"))) | 1743 | (concat command "\n"))) |
| 1744 | 1744 | ||
| @@ -1761,8 +1761,7 @@ If `gdb-thread-number' is nil, just wrap NAME in asterisks." | |||
| 1761 | "*")) | 1761 | "*")) |
| 1762 | 1762 | ||
| 1763 | (defun gdb-current-context-mode-name (mode) | 1763 | (defun gdb-current-context-mode-name (mode) |
| 1764 | "Add thread information to MODE which is to be used as | 1764 | "Add thread information to MODE which is to be used as `mode-name'." |
| 1765 | `mode-name'." | ||
| 1766 | (concat mode | 1765 | (concat mode |
| 1767 | (if gdb-thread-number | 1766 | (if gdb-thread-number |
| 1768 | (format " [thread %s]" gdb-thread-number) | 1767 | (format " [thread %s]" gdb-thread-number) |
| @@ -1809,7 +1808,8 @@ If NO-PROC is non-nil, do not try to contact the GDB process." | |||
| 1809 | ;; because we may need to update current gud-running value without | 1808 | ;; because we may need to update current gud-running value without |
| 1810 | ;; changing current thread (see gdb-running) | 1809 | ;; changing current thread (see gdb-running) |
| 1811 | (defun gdb-setq-thread-number (number) | 1810 | (defun gdb-setq-thread-number (number) |
| 1812 | "Only this function must be used to change `gdb-thread-number' | 1811 | "Set `gdb-thread-number' to NUMBER. |
| 1812 | Only this function must be used to change `gdb-thread-number' | ||
| 1813 | value to NUMBER, because `gud-running' and `gdb-frame-number' | 1813 | value to NUMBER, because `gud-running' and `gdb-frame-number' |
| 1814 | need to be updated appropriately when current thread changes." | 1814 | need to be updated appropriately when current thread changes." |
| 1815 | ;; GDB 6.8 and earlier always output thread-id="0" when stopping. | 1815 | ;; GDB 6.8 and earlier always output thread-id="0" when stopping. |
| @@ -1824,7 +1824,7 @@ need to be updated appropriately when current thread changes." | |||
| 1824 | 1824 | ||
| 1825 | Note that when `gdb-gud-control-all-threads' is t, `gud-running' | 1825 | Note that when `gdb-gud-control-all-threads' is t, `gud-running' |
| 1826 | cannot be reliably used to determine whether or not execution | 1826 | cannot be reliably used to determine whether or not execution |
| 1827 | control buttons should be shown in menu or toolbar. Use | 1827 | control buttons should be shown in menu or toolbar. Use |
| 1828 | `gdb-running-threads-count' and `gdb-stopped-threads-count' | 1828 | `gdb-running-threads-count' and `gdb-stopped-threads-count' |
| 1829 | instead. | 1829 | instead. |
| 1830 | 1830 | ||
| @@ -1874,23 +1874,337 @@ is running." | |||
| 1874 | (set-window-buffer source-window buffer)) | 1874 | (set-window-buffer source-window buffer)) |
| 1875 | source-window)) | 1875 | source-window)) |
| 1876 | 1876 | ||
| 1877 | (defun gdb-car< (a b) | 1877 | |
| 1878 | (< (car a) (car b))) | 1878 | (defun gdbmi-start-with (str offset match) |
| 1879 | 1879 | "Return non-nil if string STR starts with MATCH, else returns nil. | |
| 1880 | (defvar gdbmi-record-list | 1880 | OFFSET is the position in STR at which the comparison takes place." |
| 1881 | '((gdb-gdb . "(gdb) \n") | 1881 | (let ((match-length (length match)) |
| 1882 | (gdb-done . "\\([0-9]*\\)\\^done,?\\(.*?\\)\n") | 1882 | (str-length (- (length str) offset))) |
| 1883 | (gdb-starting . "\\([0-9]*\\)\\^running\n") | 1883 | (when (>= str-length match-length) |
| 1884 | (gdb-error . "\\([0-9]*\\)\\^error,\\(.*?\\)\n") | 1884 | (string-equal match (substring str offset (+ offset match-length)))))) |
| 1885 | (gdb-console . "~\\(\".*?\"\\)\n") | 1885 | |
| 1886 | (gdb-internals . "&\\(\".*?\"\\)\n") | 1886 | (defun gdbmi-same-start (str offset match) |
| 1887 | (gdb-stopped . "\\*stopped,?\\(.*?\\)\n") | 1887 | "Return non-nil iff STR and MATCH are equal up to the end of either strings. |
| 1888 | (gdb-running . "\\*running,\\(.*?\n\\)") | 1888 | OFFSET is the position in STR at which the comparison takes place." |
| 1889 | (gdb-thread-created . "=thread-created,\\(.*?\n\\)") | 1889 | (let* ((str-length (- (length str) offset)) |
| 1890 | (gdb-thread-selected . "=thread-selected,\\(.*?\\)\n") | 1890 | (match-length (length match)) |
| 1891 | (gdb-thread-exited . "=thread-exited,\\(.*?\n\\)") | 1891 | (compare-length (min str-length match-length))) |
| 1892 | (gdb-ignored-notification . "=[-[:alpha:]]+,?\\(.*?\\)\n") | 1892 | (when (> compare-length 0) |
| 1893 | (gdb-shell . "\\(\\(?:^.+\n\\)+\\)"))) | 1893 | (string-equal (substring str offset (+ offset compare-length)) |
| 1894 | (substring match 0 compare-length))))) | ||
| 1895 | |||
| 1896 | (defun gdbmi-is-number (character) | ||
| 1897 | "Return non-nil iff CHARACTER is a numerical character between 0 and 9." | ||
| 1898 | (and (>= character ?0) | ||
| 1899 | (<= character ?9))) | ||
| 1900 | |||
| 1901 | |||
| 1902 | (defvar-local gdbmi-bnf-state 'gdbmi-bnf-output | ||
| 1903 | "Current GDB/MI output parser state. | ||
| 1904 | The parser is placed in a different state when an incomplete data steam is | ||
| 1905 | received from GDB. | ||
| 1906 | This variable will preserve the state required to resume the parsing | ||
| 1907 | when more data arrives.") | ||
| 1908 | |||
| 1909 | (defvar-local gdbmi-bnf-offset 0 | ||
| 1910 | "Offset in `gud-marker-acc' at which the parser is reading. | ||
| 1911 | This offset is used to be able to parse the GDB/MI message | ||
| 1912 | in-place, without the need of copying the string in a temporary buffer | ||
| 1913 | or discarding parsed tokens by substringing the message.") | ||
| 1914 | |||
| 1915 | (defun gdbmi-bnf-init () | ||
| 1916 | "Initialize the GDB/MI message parser." | ||
| 1917 | (setq gdbmi-bnf-state 'gdbmi-bnf-output) | ||
| 1918 | (setq gdbmi-bnf-offset 0) | ||
| 1919 | (setq gud-marker-acc "")) | ||
| 1920 | |||
| 1921 | |||
| 1922 | (defun gdbmi-bnf-output () | ||
| 1923 | "Implementation of the following GDB/MI output grammar rule: | ||
| 1924 | |||
| 1925 | output ==> | ||
| 1926 | ( out-of-band-record )* [ result-record ] gdb-prompt" | ||
| 1927 | |||
| 1928 | (gdbmi-bnf-skip-unrecognized) | ||
| 1929 | (while (gdbmi-bnf-out-of-band-record)) | ||
| 1930 | (gdbmi-bnf-result-record) | ||
| 1931 | (gdbmi-bnf-gdb-prompt)) | ||
| 1932 | |||
| 1933 | |||
| 1934 | (defun gdbmi-bnf-skip-unrecognized () | ||
| 1935 | "Skip characters until is encounters the beginning of a valid record. | ||
| 1936 | Used as a protection mechanism in case something goes wrong when parsing | ||
| 1937 | a GDB/MI reply message." | ||
| 1938 | (let ((acc-length (length gud-marker-acc)) | ||
| 1939 | (prefix-offset gdbmi-bnf-offset) | ||
| 1940 | (prompt "(gdb) \n")) | ||
| 1941 | |||
| 1942 | (while (and (< prefix-offset acc-length) | ||
| 1943 | (gdbmi-is-number (aref gud-marker-acc prefix-offset))) | ||
| 1944 | (setq prefix-offset (1+ prefix-offset))) | ||
| 1945 | |||
| 1946 | (if (and (< prefix-offset acc-length) | ||
| 1947 | (not (memq (aref gud-marker-acc prefix-offset) | ||
| 1948 | '(?^ ?* ?+ ?= ?~ ?@ ?&))) | ||
| 1949 | (not (gdbmi-same-start gud-marker-acc gdbmi-bnf-offset prompt)) | ||
| 1950 | (string-match "\\([^^*+=~@&]+\\)" gud-marker-acc | ||
| 1951 | gdbmi-bnf-offset)) | ||
| 1952 | (let ((unrecognized-str (match-string 0 gud-marker-acc))) | ||
| 1953 | (setq gdbmi-bnf-offset (match-end 0)) | ||
| 1954 | (if gdbmi-debug-mode | ||
| 1955 | (message "gdbmi-bnf-skip-unrecognized: %s" unrecognized-str)) | ||
| 1956 | (gdb-shell unrecognized-str) | ||
| 1957 | t)))) | ||
| 1958 | |||
| 1959 | |||
| 1960 | (defun gdbmi-bnf-gdb-prompt () | ||
| 1961 | "Implementation of the following GDB/MI output grammar rule: | ||
| 1962 | gdb-prompt ==> | ||
| 1963 | '(gdb)' nl | ||
| 1964 | |||
| 1965 | nl ==> | ||
| 1966 | CR | CR-LF" | ||
| 1967 | |||
| 1968 | (let ((prompt "(gdb) \n")) | ||
| 1969 | (when (gdbmi-start-with gud-marker-acc gdbmi-bnf-offset prompt) | ||
| 1970 | (if gdbmi-debug-mode (message "gdbmi-bnf-gdb-prompt: %s" prompt)) | ||
| 1971 | (gdb-gdb prompt) | ||
| 1972 | (setq gdbmi-bnf-offset (+ gdbmi-bnf-offset (length prompt))) | ||
| 1973 | |||
| 1974 | ;; Returns non-nil to tell gud-gdbmi-marker-filter we've reached | ||
| 1975 | ;; the end of a GDB reply message. | ||
| 1976 | t))) | ||
| 1977 | |||
| 1978 | |||
| 1979 | (defun gdbmi-bnf-result-record () | ||
| 1980 | "Implementation of the following GDB/MI output grammar rule: | ||
| 1981 | |||
| 1982 | result-record ==> | ||
| 1983 | [ token ] '^' result-class ( ',' result )* nl | ||
| 1984 | |||
| 1985 | token ==> | ||
| 1986 | any sequence of digits." | ||
| 1987 | |||
| 1988 | (gdbmi-bnf-result-and-async-record-impl)) | ||
| 1989 | |||
| 1990 | |||
| 1991 | (defun gdbmi-bnf-out-of-band-record () | ||
| 1992 | "Implementation of the following GDB/MI output grammar rule: | ||
| 1993 | |||
| 1994 | out-of-band-record ==> | ||
| 1995 | async-record | stream-record" | ||
| 1996 | |||
| 1997 | (or (gdbmi-bnf-async-record) | ||
| 1998 | (gdbmi-bnf-stream-record))) | ||
| 1999 | |||
| 2000 | |||
| 2001 | (defun gdbmi-bnf-async-record () | ||
| 2002 | "Implementation of the following GDB/MI output grammar rules: | ||
| 2003 | |||
| 2004 | async-record ==> | ||
| 2005 | exec-async-output | status-async-output | notify-async-output | ||
| 2006 | |||
| 2007 | exec-async-output ==> | ||
| 2008 | [ token ] '*' async-output | ||
| 2009 | |||
| 2010 | status-async-output ==> | ||
| 2011 | [ token ] '+' async-output | ||
| 2012 | |||
| 2013 | notify-async-output ==> | ||
| 2014 | [ token ] '=' async-output | ||
| 2015 | |||
| 2016 | async-output ==> | ||
| 2017 | async-class ( ',' result )* nl" | ||
| 2018 | |||
| 2019 | (gdbmi-bnf-result-and-async-record-impl)) | ||
| 2020 | |||
| 2021 | |||
| 2022 | (defun gdbmi-bnf-stream-record () | ||
| 2023 | "Implement the following GDB/MI output grammar rule: | ||
| 2024 | stream-record ==> | ||
| 2025 | console-stream-output | target-stream-output | log-stream-output | ||
| 2026 | |||
| 2027 | console-stream-output ==> | ||
| 2028 | '~' c-string | ||
| 2029 | |||
| 2030 | target-stream-output ==> | ||
| 2031 | '@' c-string | ||
| 2032 | |||
| 2033 | log-stream-output ==> | ||
| 2034 | '&' c-string" | ||
| 2035 | (when (< gdbmi-bnf-offset (length gud-marker-acc)) | ||
| 2036 | (if (and (member (aref gud-marker-acc gdbmi-bnf-offset) '(?~ ?@ ?&)) | ||
| 2037 | (string-match "\\([~@&]\\)\\(\".*?\"\\)\n" gud-marker-acc | ||
| 2038 | gdbmi-bnf-offset)) | ||
| 2039 | (let ((prefix (match-string 1 gud-marker-acc)) | ||
| 2040 | (c-string (match-string 2 gud-marker-acc))) | ||
| 2041 | |||
| 2042 | (setq gdbmi-bnf-offset (match-end 0)) | ||
| 2043 | (if gdbmi-debug-mode (message "gdbmi-bnf-stream-record: %s" | ||
| 2044 | (match-string 0 gud-marker-acc))) | ||
| 2045 | |||
| 2046 | (cond ((string-equal prefix "~") | ||
| 2047 | (gdbmi-bnf-console-stream-output c-string)) | ||
| 2048 | ((string-equal prefix "@") | ||
| 2049 | (gdbmi-bnf-target-stream-output c-string)) | ||
| 2050 | ((string-equal prefix "&") | ||
| 2051 | (gdbmi-bnf-log-stream-output c-string))) | ||
| 2052 | t)))) | ||
| 2053 | |||
| 2054 | (defun gdbmi-bnf-console-stream-output (c-string) | ||
| 2055 | "Handler for the console-stream-output GDB/MI output grammar rule." | ||
| 2056 | (gdb-console c-string)) | ||
| 2057 | |||
| 2058 | (defun gdbmi-bnf-target-stream-output (_c-string) | ||
| 2059 | "Handler for the target-stream-output GDB/MI output grammar rule." | ||
| 2060 | ;; Not currently used. | ||
| 2061 | ) | ||
| 2062 | |||
| 2063 | (defun gdbmi-bnf-log-stream-output (c-string) | ||
| 2064 | "Handler for the log-stream-output GDB/MI output grammar rule." | ||
| 2065 | ;; Suppress "No registers." GDB 6.8 and earlier | ||
| 2066 | ;; duplicates MI error message on internal stream. | ||
| 2067 | ;; Don't print to GUD buffer. | ||
| 2068 | (if (not (string-equal (read c-string) "No registers.\n")) | ||
| 2069 | (gdb-internals c-string))) | ||
| 2070 | |||
| 2071 | |||
| 2072 | (defconst gdbmi-bnf-result-state-configs | ||
| 2073 | '(("^" . (("done" . (gdb-done . progressive)) | ||
| 2074 | ("error" . (gdb-error . progressive)) | ||
| 2075 | ("running" . (gdb-starting . atomic)))) | ||
| 2076 | ("*" . (("stopped" . (gdb-stopped . atomic)) | ||
| 2077 | ("running" . (gdb-running . atomic)))) | ||
| 2078 | ("+" . ()) | ||
| 2079 | ("=" . (("thread-created" . (gdb-thread-created . atomic)) | ||
| 2080 | ("thread-selected" . (gdb-thread-selected . atomic)) | ||
| 2081 | ("thread-existed" . (gdb-ignored-notification . atomic)) | ||
| 2082 | ('default . (gdb-ignored-notification . atomic))))) | ||
| 2083 | "Alist of alists, mapping the type and class of message to a handler function. | ||
| 2084 | Handler functions are all flagged as either `progressive' or `atomic'. | ||
| 2085 | `progressive' handlers are capable of parsing incomplete messages. | ||
| 2086 | They can be called several time with new data chunk as they arrive from GDB. | ||
| 2087 | `progressive' handlers must have an extra argument that is set to a non-nil | ||
| 2088 | value when the message is complete. | ||
| 2089 | |||
| 2090 | Implement the following GDB/MI output grammar rule: | ||
| 2091 | result-class ==> | ||
| 2092 | 'done' | 'running' | 'connected' | 'error' | 'exit' | ||
| 2093 | |||
| 2094 | async-class ==> | ||
| 2095 | 'stopped' | others (where others will be added depending on the needs | ||
| 2096 | --this is still in development).") | ||
| 2097 | |||
| 2098 | (defun gdbmi-bnf-result-and-async-record-impl () | ||
| 2099 | "Common implementation of the result-record and async-record rule. | ||
| 2100 | Both rules share the same syntax. Those records may be very large in size. | ||
| 2101 | For that reason, the \"result\" part of the record is parsed by | ||
| 2102 | `gdbmi-bnf-incomplete-record-result', which will keep | ||
| 2103 | receiving characters as they arrive from GDB until the record is complete." | ||
| 2104 | (let ((acc-length (length gud-marker-acc)) | ||
| 2105 | (prefix-offset gdbmi-bnf-offset)) | ||
| 2106 | |||
| 2107 | (while (and (< prefix-offset acc-length) | ||
| 2108 | (gdbmi-is-number (aref gud-marker-acc prefix-offset))) | ||
| 2109 | (setq prefix-offset (1+ prefix-offset))) | ||
| 2110 | |||
| 2111 | (if (and (< prefix-offset acc-length) | ||
| 2112 | (member (aref gud-marker-acc prefix-offset) '(?* ?+ ?= ?^)) | ||
| 2113 | (string-match "\\([0-9]*\\)\\([*+=^]\\)\\(.+?\\)\\([,\n]\\)" | ||
| 2114 | gud-marker-acc gdbmi-bnf-offset)) | ||
| 2115 | |||
| 2116 | (let ((token (match-string 1 gud-marker-acc)) | ||
| 2117 | (prefix (match-string 2 gud-marker-acc)) | ||
| 2118 | (class (match-string 3 gud-marker-acc)) | ||
| 2119 | (complete (string-equal (match-string 4 gud-marker-acc) "\n")) | ||
| 2120 | class-alist | ||
| 2121 | class-command) | ||
| 2122 | |||
| 2123 | (setq gdbmi-bnf-offset (match-end 0)) | ||
| 2124 | (if gdbmi-debug-mode (message "gdbmi-bnf-result-record: %s" | ||
| 2125 | (match-string 0 gud-marker-acc))) | ||
| 2126 | |||
| 2127 | (setq class-alist | ||
| 2128 | (cdr (assoc prefix gdbmi-bnf-result-state-configs))) | ||
| 2129 | (setq class-command (cdr (assoc class class-alist))) | ||
| 2130 | (if (null class-command) | ||
| 2131 | (setq class-command (cdr (assoc 'default class-alist)))) | ||
| 2132 | |||
| 2133 | (if complete | ||
| 2134 | (if class-command | ||
| 2135 | (if (equal (cdr class-command) 'progressive) | ||
| 2136 | (funcall (car class-command) token "" complete) | ||
| 2137 | (funcall (car class-command) token ""))) | ||
| 2138 | (setq gdbmi-bnf-state | ||
| 2139 | (lambda () | ||
| 2140 | (gdbmi-bnf-incomplete-record-result token class-command))) | ||
| 2141 | (funcall gdbmi-bnf-state)) | ||
| 2142 | t)))) | ||
| 2143 | |||
| 2144 | (defun gdbmi-bnf-incomplete-record-result (token class-command) | ||
| 2145 | "State of the parser used to progressively parse a result-record or async-record | ||
| 2146 | rule from an incomplete data stream. The parser will stay in this state until | ||
| 2147 | the end of the current result or async record is reached." | ||
| 2148 | (when (< gdbmi-bnf-offset (length gud-marker-acc)) | ||
| 2149 | ;; Search the data stream for the end of the current record: | ||
| 2150 | (let* ((newline-pos (string-match "\n" gud-marker-acc gdbmi-bnf-offset)) | ||
| 2151 | (is-progressive (equal (cdr class-command) 'progressive)) | ||
| 2152 | (is-complete (not (null newline-pos))) | ||
| 2153 | result-str) | ||
| 2154 | |||
| 2155 | ;; Update the gdbmi-bnf-offset only if the current chunk of data can | ||
| 2156 | ;; be processed by the class-command handler: | ||
| 2157 | (when (or is-complete is-progressive) | ||
| 2158 | (setq result-str | ||
| 2159 | (substring gud-marker-acc gdbmi-bnf-offset newline-pos)) | ||
| 2160 | (setq gdbmi-bnf-offset (+ 1 newline-pos))) | ||
| 2161 | |||
| 2162 | (if gdbmi-debug-mode | ||
| 2163 | (message "gdbmi-bnf-incomplete-record-result: %s" | ||
| 2164 | (substring gud-marker-acc gdbmi-bnf-offset newline-pos))) | ||
| 2165 | |||
| 2166 | ;; Update the parsing state before invoking the handler in class-command | ||
| 2167 | ;; to make sure it's not left in an invalid state if the handler was | ||
| 2168 | ;; to generate an error. | ||
| 2169 | (if is-complete | ||
| 2170 | (setq gdbmi-bnf-state 'gdbmi-bnf-output)) | ||
| 2171 | |||
| 2172 | (if class-command | ||
| 2173 | (if is-progressive | ||
| 2174 | (funcall (car class-command) token result-str is-complete) | ||
| 2175 | (if is-complete | ||
| 2176 | (funcall (car class-command) token result-str)))) | ||
| 2177 | |||
| 2178 | (unless is-complete | ||
| 2179 | ;; Incomplete gdb response: abort parsing until we receive more data. | ||
| 2180 | (if gdbmi-debug-mode (message "gdbmi-bnf-incomplete-record-result, aborting: incomplete stream")) | ||
| 2181 | (throw 'gdbmi-incomplete-stream nil)) | ||
| 2182 | |||
| 2183 | is-complete))) | ||
| 2184 | |||
| 2185 | |||
| 2186 | ; The following grammar rules are not yet implemented by this GDBMI-BNF parser. | ||
| 2187 | ; The handling of those rules is currently done by the handlers registered | ||
| 2188 | ; in gdbmi-bnf-result-state-configs | ||
| 2189 | ; | ||
| 2190 | ; result ==> | ||
| 2191 | ; variable "=" value | ||
| 2192 | ; | ||
| 2193 | ; variable ==> | ||
| 2194 | ; string | ||
| 2195 | ; | ||
| 2196 | ; value ==> | ||
| 2197 | ; const | tuple | list | ||
| 2198 | ; | ||
| 2199 | ; const ==> | ||
| 2200 | ; c-string | ||
| 2201 | ; | ||
| 2202 | ; tuple ==> | ||
| 2203 | ; "{}" | "{" result ( "," result )* "}" | ||
| 2204 | ; | ||
| 2205 | ; list ==> | ||
| 2206 | ; "[]" | "[" value ( "," value )* "]" | "[" result ( "," result )* "]" | ||
| 2207 | |||
| 1894 | 2208 | ||
| 1895 | (defun gud-gdbmi-marker-filter (string) | 2209 | (defun gud-gdbmi-marker-filter (string) |
| 1896 | "Filter GDB/MI output." | 2210 | "Filter GDB/MI output." |
| @@ -1907,46 +2221,20 @@ is running." | |||
| 1907 | 2221 | ||
| 1908 | ;; Start accumulating output for the GUD buffer. | 2222 | ;; Start accumulating output for the GUD buffer. |
| 1909 | (setq gdb-filter-output "") | 2223 | (setq gdb-filter-output "") |
| 1910 | (let (output-record-list) | ||
| 1911 | |||
| 1912 | ;; Process all the complete markers in this chunk. | ||
| 1913 | (dolist (gdbmi-record gdbmi-record-list) | ||
| 1914 | (while (string-match (cdr gdbmi-record) gud-marker-acc) | ||
| 1915 | (push (list (match-beginning 0) | ||
| 1916 | (car gdbmi-record) | ||
| 1917 | (match-string 1 gud-marker-acc) | ||
| 1918 | (match-string 2 gud-marker-acc) | ||
| 1919 | (match-end 0)) | ||
| 1920 | output-record-list) | ||
| 1921 | (setq gud-marker-acc | ||
| 1922 | (concat (substring gud-marker-acc 0 (match-beginning 0)) | ||
| 1923 | ;; Pad with spaces to preserve position. | ||
| 1924 | (make-string (length (match-string 0 gud-marker-acc)) 32) | ||
| 1925 | (substring gud-marker-acc (match-end 0)))))) | ||
| 1926 | |||
| 1927 | (setq output-record-list (sort output-record-list 'gdb-car<)) | ||
| 1928 | |||
| 1929 | (dolist (output-record output-record-list) | ||
| 1930 | (let ((record-type (cadr output-record)) | ||
| 1931 | (arg1 (nth 2 output-record)) | ||
| 1932 | (arg2 (nth 3 output-record))) | ||
| 1933 | (cond ((eq record-type 'gdb-error) | ||
| 1934 | (gdb-done-or-error arg2 arg1 'error)) | ||
| 1935 | ((eq record-type 'gdb-done) | ||
| 1936 | (gdb-done-or-error arg2 arg1 'done)) | ||
| 1937 | ;; Suppress "No registers." GDB 6.8 and earlier | ||
| 1938 | ;; duplicates MI error message on internal stream. | ||
| 1939 | ;; Don't print to GUD buffer. | ||
| 1940 | ((not (and (eq record-type 'gdb-internals) | ||
| 1941 | (string-equal (read arg1) "No registers.\n"))) | ||
| 1942 | (funcall record-type arg1))))) | ||
| 1943 | 2224 | ||
| 1944 | (setq gdb-output-sink 'user) | 2225 | (let ((acc-length (length gud-marker-acc))) |
| 1945 | ;; Remove padding. | 2226 | (catch 'gdbmi-incomplete-stream |
| 1946 | (string-match "^ *" gud-marker-acc) | 2227 | (while (and (< gdbmi-bnf-offset acc-length) |
| 1947 | (setq gud-marker-acc (substring gud-marker-acc (match-end 0))) | 2228 | (funcall gdbmi-bnf-state))))) |
| 2229 | |||
| 2230 | (when (/= gdbmi-bnf-offset 0) | ||
| 2231 | (setq gud-marker-acc (substring gud-marker-acc gdbmi-bnf-offset)) | ||
| 2232 | (setq gdbmi-bnf-offset 0)) | ||
| 2233 | |||
| 2234 | (when (and gdbmi-debug-mode (> (length gud-marker-acc) 0)) | ||
| 2235 | (message "gud-gdbmi-marker-filter, unparsed string: %s" gud-marker-acc)) | ||
| 1948 | 2236 | ||
| 1949 | gdb-filter-output)) | 2237 | gdb-filter-output) |
| 1950 | 2238 | ||
| 1951 | (defun gdb-gdb (_output-field)) | 2239 | (defun gdb-gdb (_output-field)) |
| 1952 | 2240 | ||
| @@ -1954,13 +2242,13 @@ is running." | |||
| 1954 | (setq gdb-filter-output | 2242 | (setq gdb-filter-output |
| 1955 | (concat output-field gdb-filter-output))) | 2243 | (concat output-field gdb-filter-output))) |
| 1956 | 2244 | ||
| 1957 | (defun gdb-ignored-notification (_output-field)) | 2245 | (defun gdb-ignored-notification (_token _output-field)) |
| 1958 | 2246 | ||
| 1959 | ;; gdb-invalidate-threads is defined to accept 'update-threads signal | 2247 | ;; gdb-invalidate-threads is defined to accept 'update-threads signal |
| 1960 | (defun gdb-thread-created (_output-field)) | 2248 | (defun gdb-thread-created (_token _output-field)) |
| 1961 | (defun gdb-thread-exited (output-field) | 2249 | (defun gdb-thread-exited (_token output-field) |
| 1962 | "Handle =thread-exited async record: unset `gdb-thread-number' | 2250 | "Handle =thread-exited async record. |
| 1963 | if current thread exited and update threads list." | 2251 | Unset `gdb-thread-number' if current thread exited and update threads list." |
| 1964 | (let* ((thread-id (bindat-get-field (gdb-json-string output-field) 'id))) | 2252 | (let* ((thread-id (bindat-get-field (gdb-json-string output-field) 'id))) |
| 1965 | (if (string= gdb-thread-number thread-id) | 2253 | (if (string= gdb-thread-number thread-id) |
| 1966 | (gdb-setq-thread-number nil)) | 2254 | (gdb-setq-thread-number nil)) |
| @@ -1971,7 +2259,7 @@ is running." | |||
| 1971 | (gdb-wait-for-pending | 2259 | (gdb-wait-for-pending |
| 1972 | (gdb-emit-signal gdb-buf-publisher 'update-threads)))) | 2260 | (gdb-emit-signal gdb-buf-publisher 'update-threads)))) |
| 1973 | 2261 | ||
| 1974 | (defun gdb-thread-selected (output-field) | 2262 | (defun gdb-thread-selected (_token output-field) |
| 1975 | "Handler for =thread-selected MI output record. | 2263 | "Handler for =thread-selected MI output record. |
| 1976 | 2264 | ||
| 1977 | Sets `gdb-thread-number' to new id." | 2265 | Sets `gdb-thread-number' to new id." |
| @@ -1988,7 +2276,7 @@ Sets `gdb-thread-number' to new id." | |||
| 1988 | (gdb-wait-for-pending | 2276 | (gdb-wait-for-pending |
| 1989 | (gdb-update)))) | 2277 | (gdb-update)))) |
| 1990 | 2278 | ||
| 1991 | (defun gdb-running (output-field) | 2279 | (defun gdb-running (_token output-field) |
| 1992 | (let* ((thread-id | 2280 | (let* ((thread-id |
| 1993 | (bindat-get-field (gdb-json-string output-field) 'thread-id))) | 2281 | (bindat-get-field (gdb-json-string output-field) 'thread-id))) |
| 1994 | ;; We reset gdb-frame-number to nil if current thread has gone | 2282 | ;; We reset gdb-frame-number to nil if current thread has gone |
| @@ -2006,7 +2294,7 @@ Sets `gdb-thread-number' to new id." | |||
| 2006 | (setq gdb-active-process t) | 2294 | (setq gdb-active-process t) |
| 2007 | (gdb-emit-signal gdb-buf-publisher 'update-threads)) | 2295 | (gdb-emit-signal gdb-buf-publisher 'update-threads)) |
| 2008 | 2296 | ||
| 2009 | (defun gdb-starting (_output-field) | 2297 | (defun gdb-starting (_output-field _result) |
| 2010 | ;; CLI commands don't emit ^running at the moment so use gdb-running too. | 2298 | ;; CLI commands don't emit ^running at the moment so use gdb-running too. |
| 2011 | (setq gdb-inferior-status "running") | 2299 | (setq gdb-inferior-status "running") |
| 2012 | (gdb-force-mode-line-update | 2300 | (gdb-force-mode-line-update |
| @@ -2020,7 +2308,7 @@ Sets `gdb-thread-number' to new id." | |||
| 2020 | 2308 | ||
| 2021 | ;; -break-insert -t didn't give a reason before gdb 6.9 | 2309 | ;; -break-insert -t didn't give a reason before gdb 6.9 |
| 2022 | 2310 | ||
| 2023 | (defun gdb-stopped (output-field) | 2311 | (defun gdb-stopped (_token output-field) |
| 2024 | "Given the contents of *stopped MI async record, select new | 2312 | "Given the contents of *stopped MI async record, select new |
| 2025 | current thread and update GDB buffers." | 2313 | current thread and update GDB buffers." |
| 2026 | ;; Reason is available with target-async only | 2314 | ;; Reason is available with target-async only |
| @@ -2106,7 +2394,13 @@ current thread and update GDB buffers." | |||
| 2106 | (setq gdb-filter-output | 2394 | (setq gdb-filter-output |
| 2107 | (gdb-concat-output gdb-filter-output (read output-field)))) | 2395 | (gdb-concat-output gdb-filter-output (read output-field)))) |
| 2108 | 2396 | ||
| 2109 | (defun gdb-done-or-error (output-field token-number type) | 2397 | (defun gdb-done (token-number output-field is-complete) |
| 2398 | (gdb-done-or-error token-number 'done output-field is-complete)) | ||
| 2399 | |||
| 2400 | (defun gdb-error (token-number output-field is-complete) | ||
| 2401 | (gdb-done-or-error token-number 'error output-field is-complete)) | ||
| 2402 | |||
| 2403 | (defun gdb-done-or-error (token-number type output-field is-complete) | ||
| 2110 | (if (string-equal token-number "") | 2404 | (if (string-equal token-number "") |
| 2111 | ;; Output from command entered by user | 2405 | ;; Output from command entered by user |
| 2112 | (progn | 2406 | (progn |
| @@ -2122,14 +2416,12 @@ current thread and update GDB buffers." | |||
| 2122 | ;; Output from command from frontend. | 2416 | ;; Output from command from frontend. |
| 2123 | (setq gdb-output-sink 'emacs)) | 2417 | (setq gdb-output-sink 'emacs)) |
| 2124 | 2418 | ||
| 2125 | (gdb-clear-partial-output) | ||
| 2126 | |||
| 2127 | ;; The process may already be dead (e.g. C-d at the gdb prompt). | 2419 | ;; The process may already be dead (e.g. C-d at the gdb prompt). |
| 2128 | (let* ((proc (get-buffer-process gud-comint-buffer)) | 2420 | (let* ((proc (get-buffer-process gud-comint-buffer)) |
| 2129 | (no-proc (or (null proc) | 2421 | (no-proc (or (null proc) |
| 2130 | (memq (process-status proc) '(exit signal))))) | 2422 | (memq (process-status proc) '(exit signal))))) |
| 2131 | 2423 | ||
| 2132 | (when gdb-first-done-or-error | 2424 | (when (and is-complete gdb-first-done-or-error) |
| 2133 | (unless (or token-number gud-running no-proc) | 2425 | (unless (or token-number gud-running no-proc) |
| 2134 | (setq gdb-filter-output (concat gdb-filter-output gdb-prompt-name))) | 2426 | (setq gdb-filter-output (concat gdb-filter-output gdb-prompt-name))) |
| 2135 | (gdb-update no-proc) | 2427 | (gdb-update no-proc) |
| @@ -2138,13 +2430,19 @@ current thread and update GDB buffers." | |||
| 2138 | (setq gdb-filter-output | 2430 | (setq gdb-filter-output |
| 2139 | (gdb-concat-output gdb-filter-output output-field)) | 2431 | (gdb-concat-output gdb-filter-output output-field)) |
| 2140 | 2432 | ||
| 2141 | (when token-number | 2433 | ;; We are done concatenating to the output sink. Restore it to user sink: |
| 2434 | (setq gdb-output-sink 'user) | ||
| 2435 | |||
| 2436 | (when (and token-number is-complete) | ||
| 2142 | (with-current-buffer | 2437 | (with-current-buffer |
| 2143 | (gdb-get-buffer-create 'gdb-partial-output-buffer) | 2438 | (gdb-get-buffer-create 'gdb-partial-output-buffer) |
| 2144 | (funcall | 2439 | (funcall |
| 2145 | (cdr (assoc (string-to-number token-number) gdb-handler-alist)))) | 2440 | (cdr (assoc (string-to-number token-number) gdb-handler-alist)))) |
| 2146 | (setq gdb-handler-alist | 2441 | (setq gdb-handler-alist |
| 2147 | (assq-delete-all token-number gdb-handler-alist))))) | 2442 | (assq-delete-all token-number gdb-handler-alist))) |
| 2443 | |||
| 2444 | (when is-complete | ||
| 2445 | (gdb-clear-partial-output)))) | ||
| 2148 | 2446 | ||
| 2149 | (defun gdb-concat-output (so-far new) | 2447 | (defun gdb-concat-output (so-far new) |
| 2150 | (cond | 2448 | (cond |
| @@ -2169,8 +2467,8 @@ Field names are wrapped in double quotes and equal signs are | |||
| 2169 | replaced with semicolons. | 2467 | replaced with semicolons. |
| 2170 | 2468 | ||
| 2171 | If FIX-KEY is non-nil, strip all \"FIX-KEY=\" occurrences from | 2469 | If FIX-KEY is non-nil, strip all \"FIX-KEY=\" occurrences from |
| 2172 | partial output. This is used to get rid of useless keys in lists | 2470 | partial output. This is used to get rid of useless keys in lists |
| 2173 | in MI messages, e.g.: [key=.., key=..]. -stack-list-frames and | 2471 | in MI messages, e.g.: [key=.., key=..]. -stack-list-frames and |
| 2174 | -break-info are examples of MI commands which issue such | 2472 | -break-info are examples of MI commands which issue such |
| 2175 | responses. | 2473 | responses. |
| 2176 | 2474 | ||
| @@ -2337,16 +2635,16 @@ calling `gdb-table-string'." | |||
| 2337 | handler-name | 2635 | handler-name |
| 2338 | &optional signal-list) | 2636 | &optional signal-list) |
| 2339 | "Define a trigger TRIGGER-NAME which sends GDB-COMMAND and sets | 2637 | "Define a trigger TRIGGER-NAME which sends GDB-COMMAND and sets |
| 2340 | HANDLER-NAME as its handler. HANDLER-NAME is bound to current | 2638 | HANDLER-NAME as its handler. HANDLER-NAME is bound to current |
| 2341 | buffer with `gdb-bind-function-to-buffer'. | 2639 | buffer with `gdb-bind-function-to-buffer'. |
| 2342 | 2640 | ||
| 2343 | If SIGNAL-LIST is non-nil, GDB-COMMAND is sent only when the | 2641 | If SIGNAL-LIST is non-nil, GDB-COMMAND is sent only when the |
| 2344 | defined trigger is called with an argument from SIGNAL-LIST. It's | 2642 | defined trigger is called with an argument from SIGNAL-LIST. It's |
| 2345 | not recommended to define triggers with empty SIGNAL-LIST. | 2643 | not recommended to define triggers with empty SIGNAL-LIST. |
| 2346 | Normally triggers should respond at least to 'update signal. | 2644 | Normally triggers should respond at least to 'update signal. |
| 2347 | 2645 | ||
| 2348 | Normally the trigger defined by this command must be called from | 2646 | Normally the trigger defined by this command must be called from |
| 2349 | the buffer where HANDLER-NAME must work. This should be done so | 2647 | the buffer where HANDLER-NAME must work. This should be done so |
| 2350 | that buffer-local thread number may be used in GDB-COMMAND (by | 2648 | that buffer-local thread number may be used in GDB-COMMAND (by |
| 2351 | calling `gdb-current-context-command'). | 2649 | calling `gdb-current-context-command'). |
| 2352 | `gdb-bind-function-to-buffer' is used to achieve this, see | 2650 | `gdb-bind-function-to-buffer' is used to achieve this, see |
| @@ -2375,32 +2673,33 @@ Handlers are normally called from the buffers they put output in. | |||
| 2375 | 2673 | ||
| 2376 | Delete ((current-buffer) . TRIGGER-NAME) from | 2674 | Delete ((current-buffer) . TRIGGER-NAME) from |
| 2377 | `gdb-pending-triggers', erase current buffer and evaluate | 2675 | `gdb-pending-triggers', erase current buffer and evaluate |
| 2378 | CUSTOM-DEFUN. Then `gdb-update-buffer-name' is called. | 2676 | CUSTOM-DEFUN. Then `gdb-update-buffer-name' is called. |
| 2379 | 2677 | ||
| 2380 | If NOPRESERVE is non-nil, window point is not restored after CUSTOM-DEFUN." | 2678 | If NOPRESERVE is non-nil, window point is not restored after CUSTOM-DEFUN." |
| 2381 | `(defun ,handler-name () | 2679 | `(defun ,handler-name () |
| 2382 | (gdb-delete-pending (cons (current-buffer) ',trigger-name)) | 2680 | (gdb-delete-pending (cons (current-buffer) ',trigger-name)) |
| 2383 | (let* ((buffer-read-only nil) | 2681 | (let* ((inhibit-read-only t) |
| 2384 | (window (get-buffer-window (current-buffer) 0)) | 2682 | ,@(unless nopreserve |
| 2385 | (start (window-start window)) | 2683 | '((window (get-buffer-window (current-buffer) 0)) |
| 2386 | (p (window-point window))) | 2684 | (start (window-start window)) |
| 2685 | (p (window-point window))))) | ||
| 2387 | (erase-buffer) | 2686 | (erase-buffer) |
| 2388 | (,custom-defun) | 2687 | (,custom-defun) |
| 2389 | (gdb-update-buffer-name) | 2688 | (gdb-update-buffer-name) |
| 2390 | ,(when (not nopreserve) | 2689 | ,@(when (not nopreserve) |
| 2391 | '(set-window-start window start) | 2690 | '((set-window-start window start) |
| 2392 | '(set-window-point window p))))) | 2691 | (set-window-point window p)))))) |
| 2393 | 2692 | ||
| 2394 | (defmacro def-gdb-trigger-and-handler (trigger-name gdb-command | 2693 | (defmacro def-gdb-trigger-and-handler (trigger-name gdb-command |
| 2395 | handler-name custom-defun | 2694 | handler-name custom-defun |
| 2396 | &optional signal-list) | 2695 | &optional signal-list) |
| 2397 | "Define trigger and handler. | 2696 | "Define trigger and handler. |
| 2398 | 2697 | ||
| 2399 | TRIGGER-NAME trigger is defined to send GDB-COMMAND. See | 2698 | TRIGGER-NAME trigger is defined to send GDB-COMMAND. |
| 2400 | `def-gdb-auto-update-trigger'. | 2699 | See `def-gdb-auto-update-trigger'. |
| 2401 | 2700 | ||
| 2402 | HANDLER-NAME handler uses customization of CUSTOM-DEFUN. See | 2701 | HANDLER-NAME handler uses customization of CUSTOM-DEFUN. |
| 2403 | `def-gdb-auto-update-handler'." | 2702 | See `def-gdb-auto-update-handler'." |
| 2404 | `(progn | 2703 | `(progn |
| 2405 | (def-gdb-auto-update-trigger ,trigger-name | 2704 | (def-gdb-auto-update-trigger ,trigger-name |
| 2406 | ,gdb-command | 2705 | ,gdb-command |
| @@ -2757,37 +3056,38 @@ corresponding to the mode line clicked." | |||
| 2757 | gdb-running-threads-count | 3056 | gdb-running-threads-count |
| 2758 | gdb-stopped-threads-count)) | 3057 | gdb-stopped-threads-count)) |
| 2759 | 3058 | ||
| 2760 | (gdb-table-add-row table | 3059 | (gdb-table-add-row |
| 2761 | (list | 3060 | table |
| 2762 | (bindat-get-field thread 'id) | 3061 | (list |
| 2763 | (concat | 3062 | (bindat-get-field thread 'id) |
| 2764 | (if gdb-thread-buffer-verbose-names | 3063 | (concat |
| 2765 | (concat (bindat-get-field thread 'target-id) " ") "") | 3064 | (if gdb-thread-buffer-verbose-names |
| 2766 | (bindat-get-field thread 'state) | 3065 | (concat (bindat-get-field thread 'target-id) " ") "") |
| 2767 | ;; Include frame information for stopped threads | 3066 | (bindat-get-field thread 'state) |
| 2768 | (if (not running) | 3067 | ;; Include frame information for stopped threads |
| 2769 | (concat | 3068 | (if (not running) |
| 2770 | " in " (bindat-get-field thread 'frame 'func) | 3069 | (concat |
| 2771 | (if gdb-thread-buffer-arguments | 3070 | " in " (bindat-get-field thread 'frame 'func) |
| 2772 | (concat | 3071 | (if gdb-thread-buffer-arguments |
| 2773 | " (" | 3072 | (concat |
| 2774 | (let ((args (bindat-get-field thread 'frame 'args))) | 3073 | " (" |
| 2775 | (mapconcat | 3074 | (let ((args (bindat-get-field thread 'frame 'args))) |
| 2776 | (lambda (arg) | 3075 | (mapconcat |
| 2777 | (apply #'format "%s=%s" | 3076 | (lambda (arg) |
| 2778 | (gdb-get-many-fields arg 'name 'value))) | 3077 | (apply #'format "%s=%s" |
| 2779 | args ",")) | 3078 | (gdb-get-many-fields arg 'name 'value))) |
| 2780 | ")") | 3079 | args ",")) |
| 2781 | "") | 3080 | ")") |
| 2782 | (if gdb-thread-buffer-locations | 3081 | "") |
| 2783 | (gdb-frame-location (bindat-get-field thread 'frame)) "") | 3082 | (if gdb-thread-buffer-locations |
| 2784 | (if gdb-thread-buffer-addresses | 3083 | (gdb-frame-location (bindat-get-field thread 'frame)) "") |
| 2785 | (concat " at " (bindat-get-field thread 'frame 'addr)) "")) | 3084 | (if gdb-thread-buffer-addresses |
| 2786 | ""))) | 3085 | (concat " at " (bindat-get-field thread 'frame 'addr)) "")) |
| 2787 | (list | 3086 | ""))) |
| 2788 | 'gdb-thread thread | 3087 | (list |
| 2789 | 'mouse-face 'highlight | 3088 | 'gdb-thread thread |
| 2790 | 'help-echo "mouse-2, RET: select thread"))) | 3089 | 'mouse-face 'highlight |
| 3090 | 'help-echo "mouse-2, RET: select thread"))) | ||
| 2791 | (when (string-equal gdb-thread-number | 3091 | (when (string-equal gdb-thread-number |
| 2792 | (bindat-get-field thread 'id)) | 3092 | (bindat-get-field thread 'id)) |
| 2793 | (setq marked-line (length gdb-threads-list)))) | 3093 | (setq marked-line (length gdb-threads-list)))) |
| @@ -2803,8 +3103,8 @@ corresponding to the mode line clicked." | |||
| 2803 | "Define a NAME command which will act upon thread on the current line. | 3103 | "Define a NAME command which will act upon thread on the current line. |
| 2804 | 3104 | ||
| 2805 | CUSTOM-DEFUN may use locally bound `thread' variable, which will | 3105 | CUSTOM-DEFUN may use locally bound `thread' variable, which will |
| 2806 | be the value of 'gdb-thread property of the current line. If | 3106 | be the value of 'gdb-thread property of the current line. |
| 2807 | 'gdb-thread is nil, error is signaled." | 3107 | If `gdb-thread' is nil, error is signaled." |
| 2808 | `(defun ,name (&optional event) | 3108 | `(defun ,name (&optional event) |
| 2809 | ,(when doc doc) | 3109 | ,(when doc doc) |
| 2810 | (interactive (list last-input-event)) | 3110 | (interactive (list last-input-event)) |
| @@ -2953,7 +3253,7 @@ line." | |||
| 2953 | (defun gdb-memory-column-width (size format) | 3253 | (defun gdb-memory-column-width (size format) |
| 2954 | "Return length of string with memory unit of SIZE in FORMAT. | 3254 | "Return length of string with memory unit of SIZE in FORMAT. |
| 2955 | 3255 | ||
| 2956 | SIZE is in bytes, as in `gdb-memory-unit'. FORMAT is a string as | 3256 | SIZE is in bytes, as in `gdb-memory-unit'. FORMAT is a string as |
| 2957 | in `gdb-memory-format'." | 3257 | in `gdb-memory-format'." |
| 2958 | (let ((format-base (cdr (assoc format | 3258 | (let ((format-base (cdr (assoc format |
| 2959 | '(("x" . 16) | 3259 | '(("x" . 16) |
| @@ -3455,8 +3755,7 @@ DOC is an optional documentation string." | |||
| 3455 | (error "Not recognized as break/watchpoint line"))))) | 3755 | (error "Not recognized as break/watchpoint line"))))) |
| 3456 | 3756 | ||
| 3457 | (defun gdb-goto-breakpoint (&optional event) | 3757 | (defun gdb-goto-breakpoint (&optional event) |
| 3458 | "Go to the location of breakpoint at current line of | 3758 | "Go to the location of breakpoint at current line of breakpoints buffer." |
| 3459 | breakpoints buffer." | ||
| 3460 | (interactive (list last-input-event)) | 3759 | (interactive (list last-input-event)) |
| 3461 | (if event (posn-set-point (event-end event))) | 3760 | (if event (posn-set-point (event-end event))) |
| 3462 | ;; Hack to stop gdb-goto-breakpoint displaying in GUD buffer. | 3761 | ;; Hack to stop gdb-goto-breakpoint displaying in GUD buffer. |
| @@ -3840,7 +4139,7 @@ member." | |||
| 3840 | 4139 | ||
| 3841 | (defun gdb-get-source-file-list () | 4140 | (defun gdb-get-source-file-list () |
| 3842 | "Create list of source files for current GDB session. | 4141 | "Create list of source files for current GDB session. |
| 3843 | If buffers already exist for any of these files, gud-minor-mode | 4142 | If buffers already exist for any of these files, `gud-minor-mode' |
| 3844 | is set in them." | 4143 | is set in them." |
| 3845 | (goto-char (point-min)) | 4144 | (goto-char (point-min)) |
| 3846 | (while (re-search-forward gdb-source-file-regexp nil t) | 4145 | (while (re-search-forward gdb-source-file-regexp nil t) |
| @@ -3851,8 +4150,8 @@ is set in them." | |||
| 3851 | (gdb-init-buffer))))) | 4150 | (gdb-init-buffer))))) |
| 3852 | 4151 | ||
| 3853 | (defun gdb-get-main-selected-frame () | 4152 | (defun gdb-get-main-selected-frame () |
| 3854 | "Trigger for `gdb-frame-handler' which uses main current | 4153 | "Trigger for `gdb-frame-handler' which uses main current thread. |
| 3855 | thread. Called from `gdb-update'." | 4154 | Called from `gdb-update'." |
| 3856 | (if (not (gdb-pending-p 'gdb-get-main-selected-frame)) | 4155 | (if (not (gdb-pending-p 'gdb-get-main-selected-frame)) |
| 3857 | (progn | 4156 | (progn |
| 3858 | (gdb-input (gdb-current-context-command "-stack-info-frame") | 4157 | (gdb-input (gdb-current-context-command "-stack-info-frame") |
| @@ -3860,7 +4159,7 @@ thread. Called from `gdb-update'." | |||
| 3860 | (gdb-add-pending 'gdb-get-main-selected-frame)))) | 4159 | (gdb-add-pending 'gdb-get-main-selected-frame)))) |
| 3861 | 4160 | ||
| 3862 | (defun gdb-frame-handler () | 4161 | (defun gdb-frame-handler () |
| 3863 | "Sets `gdb-selected-frame' and `gdb-selected-file' to show | 4162 | "Set `gdb-selected-frame' and `gdb-selected-file' to show |
| 3864 | overlay arrow in source buffer." | 4163 | overlay arrow in source buffer." |
| 3865 | (gdb-delete-pending 'gdb-get-main-selected-frame) | 4164 | (gdb-delete-pending 'gdb-get-main-selected-frame) |
| 3866 | (let ((frame (bindat-get-field (gdb-json-partial-output) 'frame))) | 4165 | (let ((frame (bindat-get-field (gdb-json-partial-output) 'frame))) |
| @@ -3921,8 +4220,8 @@ overlay arrow in source buffer." | |||
| 3921 | 4220 | ||
| 3922 | (defun gdb-preempt-existing-or-display-buffer (buf &optional split-horizontal) | 4221 | (defun gdb-preempt-existing-or-display-buffer (buf &optional split-horizontal) |
| 3923 | "Find window displaying a buffer with the same | 4222 | "Find window displaying a buffer with the same |
| 3924 | `gdb-buffer-type' as BUF and show BUF there. If no such window | 4223 | `gdb-buffer-type' as BUF and show BUF there. If no such window |
| 3925 | exists, just call `gdb-display-buffer' for BUF. If the window | 4224 | exists, just call `gdb-display-buffer' for BUF. If the window |
| 3926 | found is already dedicated, split window according to | 4225 | found is already dedicated, split window according to |
| 3927 | SPLIT-HORIZONTAL and show BUF in the new window." | 4226 | SPLIT-HORIZONTAL and show BUF in the new window." |
| 3928 | (if buf | 4227 | (if buf |
| @@ -4310,8 +4609,7 @@ CONTEXT is the text before COMMAND on the line." | |||
| 4310 | (gud-gdb-fetch-lines-break (length context)) | 4609 | (gud-gdb-fetch-lines-break (length context)) |
| 4311 | (gud-gdb-fetched-lines nil) | 4610 | (gud-gdb-fetched-lines nil) |
| 4312 | ;; This filter dumps output lines to `gud-gdb-fetched-lines'. | 4611 | ;; This filter dumps output lines to `gud-gdb-fetched-lines'. |
| 4313 | (gud-marker-filter #'gud-gdbmi-fetch-lines-filter) | 4612 | (gud-marker-filter #'gud-gdbmi-fetch-lines-filter)) |
| 4314 | complete-list) | ||
| 4315 | (with-current-buffer (gdb-get-buffer 'gdb-partial-output-buffer) | 4613 | (with-current-buffer (gdb-get-buffer 'gdb-partial-output-buffer) |
| 4316 | (gdb-input (concat "complete " context command) | 4614 | (gdb-input (concat "complete " context command) |
| 4317 | (lambda () (setq gud-gdb-fetch-lines-in-progress nil))) | 4615 | (lambda () (setq gud-gdb-fetch-lines-in-progress nil))) |