diff options
Diffstat (limited to 'lisp/progmodes/gdb-mi.el')
-rw-r--r-- | lisp/progmodes/gdb-mi.el | 82 |
1 files changed, 76 insertions, 6 deletions
diff --git a/lisp/progmodes/gdb-mi.el b/lisp/progmodes/gdb-mi.el index 66fc4b1a4ce..a35a7deb4b1 100644 --- a/lisp/progmodes/gdb-mi.el +++ b/lisp/progmodes/gdb-mi.el @@ -90,6 +90,7 @@ (require 'gud) (require 'cl-lib) (require 'cl-seq) +(require 'bindat) (eval-when-compile (require 'pcase)) (declare-function speedbar-change-initial-expansion-list @@ -1266,7 +1267,7 @@ Used by Speedbar." :version "22.1") (define-key gud-minor-mode-map "\C-c\C-w" 'gud-watch) -(define-key global-map (vconcat gud-key-prefix "\C-w") 'gud-watch) +(keymap-set gud-global-map "C-w" 'gud-watch) (declare-function tooltip-identifier-from-point "tooltip" (point)) @@ -1612,6 +1613,7 @@ this trigger is subscribed to `gdb-buf-publisher' and called with ;; Used to display windows with thread-bound buffers (defmacro def-gdb-preempt-display-buffer (name buffer &optional doc split-horizontal) + (declare (indent defun)) `(defun ,name (&optional thread) ,(when doc doc) (message "%s" thread) @@ -3012,6 +3014,7 @@ calling `gdb-current-context-command'). Triggers defined by this command are meant to be used as a trigger argument when describing buffer types with `gdb-set-buffer-rules'." + (declare (indent defun)) `(defun ,trigger-name (&optional signal) (when (or (not ,signal-list) @@ -3032,6 +3035,7 @@ Erase current buffer and evaluate CUSTOM-DEFUN. Then call `gdb-update-buffer-name'. If NOPRESERVE is non-nil, window point is not restored after CUSTOM-DEFUN." + (declare (indent defun)) `(defun ,handler-name () (let* ((inhibit-read-only t) ,@(unless nopreserve @@ -3055,6 +3059,7 @@ See `def-gdb-auto-update-trigger'. HANDLER-NAME handler uses customization of CUSTOM-DEFUN. See `def-gdb-auto-update-handler'." + (declare (indent defun)) `(progn (def-gdb-auto-update-trigger ,trigger-name ,gdb-command @@ -3473,6 +3478,7 @@ corresponding to the mode line clicked." CUSTOM-DEFUN may use locally bound `thread' variable, which will be the value of `gdb-thread' property of the current line. If `gdb-thread' is nil, error is signaled." + (declare (indent defun)) `(defun ,name (&optional event) ,(when doc doc) (interactive (list last-input-event)) @@ -3488,6 +3494,7 @@ If `gdb-thread' is nil, error is signaled." &optional doc) "Define a NAME which will call BUFFER-COMMAND with id of thread on the current line." + (declare (indent defun)) `(def-gdb-thread-buffer-command ,name (,buffer-command (gdb-mi--field thread 'id)) ,doc)) @@ -3543,6 +3550,7 @@ on the current line." "Define a NAME which will execute GUD-COMMAND with `gdb-thread-number' locally bound to id of thread on the current line." + (declare (indent defun)) `(def-gdb-thread-buffer-command ,name (if gdb-non-stop (let ((gdb-thread-number (gdb-mi--field thread 'id)) @@ -3711,6 +3719,7 @@ in `gdb-memory-format'." (defmacro def-gdb-set-positive-number (name variable echo-string &optional doc) "Define a function NAME which reads new VAR value from minibuffer." + (declare (indent defun)) `(defun ,name (event) ,(when doc doc) (interactive "e") @@ -3739,6 +3748,7 @@ in `gdb-memory-format'." "Define a function NAME to switch memory buffer to use FORMAT. DOC is an optional documentation string." + (declare (indent defun)) `(defun ,name () ,(when doc doc) (interactive) (customize-set-variable 'gdb-memory-format ,format) @@ -3808,6 +3818,7 @@ DOC is an optional documentation string." "Define a function NAME to switch memory unit size to UNIT-SIZE. DOC is an optional documentation string." + (declare (indent defun)) `(defun ,name () ,(when doc doc) (interactive) (customize-set-variable 'gdb-memory-unit ,unit-size) @@ -3832,6 +3843,7 @@ The defined function switches Memory buffer to show address stored in ADDRESS-VAR variable. DOC is an optional documentation string." + (declare (indent defun)) `(defun ,name ,(when doc doc) (interactive) @@ -4277,7 +4289,7 @@ member." ;; uses "-stack-list-locals --simple-values". Needs GDB 6.1 onwards. (def-gdb-trigger-and-handler gdb-invalidate-locals - (concat (gdb-current-context-command "-stack-list-locals") + (concat (gdb-current-context-command "-stack-list-variables") " --simple-values") gdb-locals-handler gdb-locals-handler-custom '(start update)) @@ -4288,6 +4300,48 @@ member." 'gdb-locals-mode 'gdb-invalidate-locals) + +;; Retrieve the values of all variables before invalidating locals. +(def-gdb-trigger-and-handler + gdb-locals-values + (concat (gdb-current-context-command "-stack-list-variables") + " --all-values") + gdb-locals-values-handler gdb-locals-values-handler-custom + '(start update)) + +(gdb-set-buffer-rules + 'gdb-locals-values-buffer + 'gdb-locals-values-buffer-name + 'gdb-locals-mode + 'gdb-locals-values) + +(defun gdb-locals-values-buffer-name () + (gdb-current-context-buffer-name + (concat "local values of " (gdb-get-target-string)))) + +(defcustom gdb-locals-simple-values-only nil + "Only display simple values in the Locals buffer." + :type 'boolean + :group 'gud + :version "29.1") + +(defcustom gdb-locals-value-limit 100 + "Maximum length the value of a local variable is allowed to be." + :type 'integer + :group 'gud + :version "29.1") + +(defvar gdb-locals-values-table (make-hash-table :test #'equal) + "Mapping of local variable names to a string with their value.") + +(defun gdb-locals-values-handler-custom () + "Store the values of local variables in `gdb-locals-value-map'." + (let ((locals-list (bindat-get-field (gdb-mi--partial-output) 'variables))) + (dolist (local locals-list) + (let ((name (bindat-get-field local 'name)) + (value (bindat-get-field local 'value))) + (puthash name value gdb-locals-values-table))))) + (defvar gdb-locals-watch-map (let ((map (make-sparse-keymap))) (suppress-keymap map) @@ -4304,6 +4358,15 @@ member." map) "Keymap to edit value of a simple data type local variable.") +(defun gdb-locals-value-filter (value) + "Filter function for the local variable VALUE." + (let* ((no-nl (replace-regexp-in-string "\n" " " value)) + (str (replace-regexp-in-string "[[:space:]]+" " " no-nl)) + (limit gdb-locals-value-limit)) + (if (>= (length str) limit) + (concat (substring str 0 limit) "...") + str))) + (defun gdb-edit-locals-value (&optional event) "Assign a value to a variable displayed in the locals buffer." (interactive (list last-input-event)) @@ -4316,17 +4379,22 @@ member." (gud-basic-call (concat "-gdb-set variable " var " = " value))))) -;; Don't display values of arrays or structures. -;; These can be expanded using gud-watch. +;; Complex data types are looked up in `gdb-locals-values-table'. (defun gdb-locals-handler-custom () - (let ((locals-list (gdb-mi--field (gdb-mi--partial-output) 'locals)) + "Handler to rebuild the local variables table buffer." + (let ((locals-list (bindat-get-field (gdb-mi--partial-output) 'variables)) (table (make-gdb-table))) (dolist (local locals-list) (let ((name (gdb-mi--field local 'name)) (value (gdb-mi--field local 'value)) (type (gdb-mi--field local 'type))) (when (not value) - (setq value "<complex data type>")) + (setq value + (if gdb-locals-simple-values-only + "<complex data type>" + (gethash name gdb-locals-values-table "<unavailable>")))) + (setq value (gdb-locals-value-filter value)) + (if (or (not value) (string-match "0x" value)) (add-text-properties 0 (length name) @@ -4849,6 +4917,8 @@ file\" where the GDB session starts (see `gdb-main-file')." (expand-file-name gdb-default-window-configuration-file gdb-window-configuration-directory))) ;; Create default layout as before. + ;; Make sure that local values are updated before locals. + (gdb-get-buffer-create 'gdb-locals-values-buffer) (gdb-get-buffer-create 'gdb-locals-buffer) (gdb-get-buffer-create 'gdb-stack-buffer) (gdb-get-buffer-create 'gdb-breakpoints-buffer) |