aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGustaf Waldemarson2022-03-06 22:56:04 +0100
committerLars Ingebrigtsen2022-03-06 22:56:04 +0100
commitf70bf8a21dc1283a58367cbca31decef633c6dab (patch)
tree2411f3fd0f2d3413a1cad5cd120b8592a7a595cf
parent5b7ce98ea0fd368aa5a73d5f6e01cf8b0fd253c1 (diff)
downloademacs-f70bf8a21dc1283a58367cbca31decef633c6dab.tar.gz
emacs-f70bf8a21dc1283a58367cbca31decef633c6dab.zip
Display complex data types in gdb-mi
* lisp/progmodes/gdb-mi.el (bindat): Require. (gdb-invalidate-locals): Use `-stack-list-variables` instead of the deprecated `-stack-list-locals`. Additionally, this allow function arguments to be displayed in the locals buffer. (gdb-locals-values-buffer, gdb-locals-values-buffer-name) (gdb-locals-simple-values-only, gdb-locals-values-table): New variables. (gdb-locals-values-handler-custom): Create a new gdb buffer for extracting local variable values. To extract the values for 'complex' data-types, the command `-stack-list-locals` is used with the `--all-values` flag. The extracted values are then stored in a hash-table for later use in the `gdb-locals-handler-custom` that performs the actual update of the Local variable buffer. All variable values are filtered to fit it into a single line, being truncated as necessary by the user customizable option `gdb-locals-value-limit`. The old behavior of hiding complex values can be restored using the customizable `gdb-locals-simple-values-only` option. Patch amended by William Xu <william.xwl@gmail.com>.
-rw-r--r--lisp/progmodes/gdb-mi.el69
1 files changed, 64 insertions, 5 deletions
diff --git a/lisp/progmodes/gdb-mi.el b/lisp/progmodes/gdb-mi.el
index ddccbe80e7f..a35a7deb4b1 100644
--- a/lisp/progmodes/gdb-mi.el
+++ b/lisp/progmodes/gdb-mi.el
@@ -90,6 +90,7 @@
90(require 'gud) 90(require 'gud)
91(require 'cl-lib) 91(require 'cl-lib)
92(require 'cl-seq) 92(require 'cl-seq)
93(require 'bindat)
93(eval-when-compile (require 'pcase)) 94(eval-when-compile (require 'pcase))
94 95
95(declare-function speedbar-change-initial-expansion-list 96(declare-function speedbar-change-initial-expansion-list
@@ -4288,7 +4289,7 @@ member."
4288;; uses "-stack-list-locals --simple-values". Needs GDB 6.1 onwards. 4289;; uses "-stack-list-locals --simple-values". Needs GDB 6.1 onwards.
4289(def-gdb-trigger-and-handler 4290(def-gdb-trigger-and-handler
4290 gdb-invalidate-locals 4291 gdb-invalidate-locals
4291 (concat (gdb-current-context-command "-stack-list-locals") 4292 (concat (gdb-current-context-command "-stack-list-variables")
4292 " --simple-values") 4293 " --simple-values")
4293 gdb-locals-handler gdb-locals-handler-custom 4294 gdb-locals-handler gdb-locals-handler-custom
4294 '(start update)) 4295 '(start update))
@@ -4299,6 +4300,48 @@ member."
4299 'gdb-locals-mode 4300 'gdb-locals-mode
4300 'gdb-invalidate-locals) 4301 'gdb-invalidate-locals)
4301 4302
4303
4304;; Retrieve the values of all variables before invalidating locals.
4305(def-gdb-trigger-and-handler
4306 gdb-locals-values
4307 (concat (gdb-current-context-command "-stack-list-variables")
4308 " --all-values")
4309 gdb-locals-values-handler gdb-locals-values-handler-custom
4310 '(start update))
4311
4312(gdb-set-buffer-rules
4313 'gdb-locals-values-buffer
4314 'gdb-locals-values-buffer-name
4315 'gdb-locals-mode
4316 'gdb-locals-values)
4317
4318(defun gdb-locals-values-buffer-name ()
4319 (gdb-current-context-buffer-name
4320 (concat "local values of " (gdb-get-target-string))))
4321
4322(defcustom gdb-locals-simple-values-only nil
4323 "Only display simple values in the Locals buffer."
4324 :type 'boolean
4325 :group 'gud
4326 :version "29.1")
4327
4328(defcustom gdb-locals-value-limit 100
4329 "Maximum length the value of a local variable is allowed to be."
4330 :type 'integer
4331 :group 'gud
4332 :version "29.1")
4333
4334(defvar gdb-locals-values-table (make-hash-table :test #'equal)
4335 "Mapping of local variable names to a string with their value.")
4336
4337(defun gdb-locals-values-handler-custom ()
4338 "Store the values of local variables in `gdb-locals-value-map'."
4339 (let ((locals-list (bindat-get-field (gdb-mi--partial-output) 'variables)))
4340 (dolist (local locals-list)
4341 (let ((name (bindat-get-field local 'name))
4342 (value (bindat-get-field local 'value)))
4343 (puthash name value gdb-locals-values-table)))))
4344
4302(defvar gdb-locals-watch-map 4345(defvar gdb-locals-watch-map
4303 (let ((map (make-sparse-keymap))) 4346 (let ((map (make-sparse-keymap)))
4304 (suppress-keymap map) 4347 (suppress-keymap map)
@@ -4315,6 +4358,15 @@ member."
4315 map) 4358 map)
4316 "Keymap to edit value of a simple data type local variable.") 4359 "Keymap to edit value of a simple data type local variable.")
4317 4360
4361(defun gdb-locals-value-filter (value)
4362 "Filter function for the local variable VALUE."
4363 (let* ((no-nl (replace-regexp-in-string "\n" " " value))
4364 (str (replace-regexp-in-string "[[:space:]]+" " " no-nl))
4365 (limit gdb-locals-value-limit))
4366 (if (>= (length str) limit)
4367 (concat (substring str 0 limit) "...")
4368 str)))
4369
4318(defun gdb-edit-locals-value (&optional event) 4370(defun gdb-edit-locals-value (&optional event)
4319 "Assign a value to a variable displayed in the locals buffer." 4371 "Assign a value to a variable displayed in the locals buffer."
4320 (interactive (list last-input-event)) 4372 (interactive (list last-input-event))
@@ -4327,17 +4379,22 @@ member."
4327 (gud-basic-call 4379 (gud-basic-call
4328 (concat "-gdb-set variable " var " = " value))))) 4380 (concat "-gdb-set variable " var " = " value)))))
4329 4381
4330;; Don't display values of arrays or structures. 4382;; Complex data types are looked up in `gdb-locals-values-table'.
4331;; These can be expanded using gud-watch.
4332(defun gdb-locals-handler-custom () 4383(defun gdb-locals-handler-custom ()
4333 (let ((locals-list (gdb-mi--field (gdb-mi--partial-output) 'locals)) 4384 "Handler to rebuild the local variables table buffer."
4385 (let ((locals-list (bindat-get-field (gdb-mi--partial-output) 'variables))
4334 (table (make-gdb-table))) 4386 (table (make-gdb-table)))
4335 (dolist (local locals-list) 4387 (dolist (local locals-list)
4336 (let ((name (gdb-mi--field local 'name)) 4388 (let ((name (gdb-mi--field local 'name))
4337 (value (gdb-mi--field local 'value)) 4389 (value (gdb-mi--field local 'value))
4338 (type (gdb-mi--field local 'type))) 4390 (type (gdb-mi--field local 'type)))
4339 (when (not value) 4391 (when (not value)
4340 (setq value "<complex data type>")) 4392 (setq value
4393 (if gdb-locals-simple-values-only
4394 "<complex data type>"
4395 (gethash name gdb-locals-values-table "<unavailable>"))))
4396 (setq value (gdb-locals-value-filter value))
4397
4341 (if (or (not value) 4398 (if (or (not value)
4342 (string-match "0x" value)) 4399 (string-match "0x" value))
4343 (add-text-properties 0 (length name) 4400 (add-text-properties 0 (length name)
@@ -4860,6 +4917,8 @@ file\" where the GDB session starts (see `gdb-main-file')."
4860 (expand-file-name gdb-default-window-configuration-file 4917 (expand-file-name gdb-default-window-configuration-file
4861 gdb-window-configuration-directory))) 4918 gdb-window-configuration-directory)))
4862 ;; Create default layout as before. 4919 ;; Create default layout as before.
4920 ;; Make sure that local values are updated before locals.
4921 (gdb-get-buffer-create 'gdb-locals-values-buffer)
4863 (gdb-get-buffer-create 'gdb-locals-buffer) 4922 (gdb-get-buffer-create 'gdb-locals-buffer)
4864 (gdb-get-buffer-create 'gdb-stack-buffer) 4923 (gdb-get-buffer-create 'gdb-stack-buffer)
4865 (gdb-get-buffer-create 'gdb-breakpoints-buffer) 4924 (gdb-get-buffer-create 'gdb-breakpoints-buffer)