comparison lisp/progmodes/gdb-mi.el @ 104153:957779ca8cea

* progmodes/gdb-mi.el (gdb-get-buffer, gdb-get-buffer-create): Argument `key' renamed to `buffer-type'. (gdb-current-context-buffer-name): Do not add thread info to buffer name when no thread is selected. (gdbmi-record-list, gdb-shell): Try to handle GDB `shell' command (bug 3794). (gdb-thread-selected): Handle `=thread-selected' notification. (gdb-wait-for-pending): New macro to deal with congestion problems. (gdb-breakpoints-list-handler-custom): Don't fail on pending breakpoints. (gdb-invalidate-disassembly): Use 'fullname instead of 'file. This fixes problem similar to one described in bug 3947. (gud-menu-map): More menu items. (gdb-init-1): Reset `gdb-thread-number' to nil.
author Dmitry Dzhus <dima@sphinx.net.ru>
date Tue, 04 Aug 2009 15:51:58 +0000
parents 22070e4cdf2a
children 87373993f3bd
comparison
equal deleted inserted replaced
104152:0727b216c5bf 104153:957779ca8cea
231 `(member ,item gdb-pending-triggers)) 231 `(member ,item gdb-pending-triggers))
232 (defmacro gdb-delete-pending (item) 232 (defmacro gdb-delete-pending (item)
233 `(setq gdb-pending-triggers 233 `(setq gdb-pending-triggers
234 (delete ,item gdb-pending-triggers))) 234 (delete ,item gdb-pending-triggers)))
235 235
236 (defvar gdb-wait-for-pending-timeout 0.5)
237
238 (defmacro gdb-wait-for-pending (&rest body)
239 "Wait until `gdb-pending-triggers' is empty and execute BODY.
240
241 This function checks `gdb-pending-triggers' value every
242 `gdb-wait-for-pending' seconds."
243 (run-with-timer
244 gdb-wait-for-pending-timeout nil
245 `(lambda ()
246 (if (not gdb-pending-triggers)
247 (progn
248 ,@body)
249 (gdb-wait-for-pending ,@body)))))
250
236 (defcustom gdb-debug-log-max 128 251 (defcustom gdb-debug-log-max 128
237 "Maximum size of `gdb-debug-log'. If nil, size is unlimited." 252 "Maximum size of `gdb-debug-log'. If nil, size is unlimited."
238 :group 'gdb 253 :group 'gdb
239 :type '(choice (integer :tag "Number of elements") 254 :type '(choice (integer :tag "Number of elements")
240 (const :tag "Unlimited" nil)) 255 (const :tag "Unlimited" nil))
617 632
618 (defun gdb-init-1 () 633 (defun gdb-init-1 ()
619 ;; (re-)initialise 634 ;; (re-)initialise
620 (setq gdb-selected-frame nil 635 (setq gdb-selected-frame nil
621 gdb-frame-number nil 636 gdb-frame-number nil
637 gdb-thread-number nil
622 gdb-var-list nil 638 gdb-var-list nil
623 gdb-pending-triggers nil 639 gdb-pending-triggers nil
624 gdb-output-sink 'user 640 gdb-output-sink 'user
625 gdb-location-alist nil 641 gdb-location-alist nil
626 gdb-source-file-list nil 642 gdb-source-file-list nil
1086 1102
1087 (defun gdb-current-buffer-frame () 1103 (defun gdb-current-buffer-frame ()
1088 "Get current stack frame object for thread of current buffer." 1104 "Get current stack frame object for thread of current buffer."
1089 (gdb-get-field (gdb-current-buffer-thread) 'frame)) 1105 (gdb-get-field (gdb-current-buffer-thread) 'frame))
1090 1106
1091 (defun gdb-get-buffer (key &optional thread) 1107 (defun gdb-get-buffer (buffer-type &optional thread)
1092 "Get a specific GDB buffer. 1108 "Get a specific GDB buffer.
1093 1109
1094 In that buffer, `gdb-buffer-type' must be equal to KEY and 1110 In that buffer, `gdb-buffer-type' must be equal to BUFFER-TYPE
1095 `gdb-thread-number' (if provided) must be equal to THREAD." 1111 and `gdb-thread-number' (if provided) must be equal to THREAD."
1096 (catch 'found 1112 (catch 'found
1097 (dolist (buffer (buffer-list) nil) 1113 (dolist (buffer (buffer-list) nil)
1098 (with-current-buffer buffer 1114 (with-current-buffer buffer
1099 (when (and (eq gdb-buffer-type key) 1115 (when (and (eq gdb-buffer-type buffer-type)
1100 (or (not thread) 1116 (or (not thread)
1101 (equal gdb-thread-number thread))) 1117 (equal gdb-thread-number thread)))
1102 (throw 'found buffer)))))) 1118 (throw 'found buffer))))))
1103 1119
1104 (defun gdb-get-buffer-create (key &optional thread) 1120 (defun gdb-get-buffer-create (buffer-type &optional thread)
1105 "Create a new GDB buffer of the type specified by KEY. 1121 "Create a new GDB buffer of the type specified by BUFFER-TYPE.
1106 The key should be one of the cars in `gdb-buffer-rules'. 1122 The buffer-type should be one of the cars in `gdb-buffer-rules'.
1107 1123
1108 If THREAD is non-nil, it is assigned to `gdb-thread-number' 1124 If THREAD is non-nil, it is assigned to `gdb-thread-number'
1109 buffer-local variable of the new buffer. 1125 buffer-local variable of the new buffer.
1110 1126
1111 If buffer's mode returns a symbol, it's used to register " 1127 If buffer's mode returns a symbol, it's used to register "
1112 (or (gdb-get-buffer key thread) 1128 (or (gdb-get-buffer buffer-type thread)
1113 (let ((rules (assoc key gdb-buffer-rules)) 1129 (let ((rules (assoc buffer-type gdb-buffer-rules))
1114 (new (generate-new-buffer "limbo"))) 1130 (new (generate-new-buffer "limbo")))
1115 (with-current-buffer new 1131 (with-current-buffer new
1116 (let ((mode (gdb-rules-buffer-mode rules)) 1132 (let ((mode (gdb-rules-buffer-mode rules))
1117 (trigger (gdb-rules-update-trigger rules))) 1133 (trigger (gdb-rules-update-trigger rules)))
1118 (when mode (funcall mode)) 1134 (when mode (funcall mode))
1119 (setq gdb-buffer-type key) 1135 (setq gdb-buffer-type buffer-type)
1120 (when thread 1136 (when thread
1121 (set (make-local-variable 'gdb-thread-number) thread)) 1137 (set (make-local-variable 'gdb-thread-number) thread))
1122 (set (make-local-variable 'gud-minor-mode) 1138 (set (make-local-variable 'gud-minor-mode)
1123 (buffer-local-value 'gud-minor-mode gud-comint-buffer)) 1139 (buffer-local-value 'gud-minor-mode gud-comint-buffer))
1124 (set (make-local-variable 'tool-bar-map) gud-tool-bar-map) 1140 (set (make-local-variable 'tool-bar-map) gud-tool-bar-map)
1428 (if gdb-thread-number 1444 (if gdb-thread-number
1429 (concat command " --thread " gdb-thread-number " ") 1445 (concat command " --thread " gdb-thread-number " ")
1430 command)) 1446 command))
1431 1447
1432 (defun gdb-current-context-buffer-name (name) 1448 (defun gdb-current-context-buffer-name (name)
1433 "Add thread information and asterisks to string NAME." 1449 "Add thread information and asterisks to string NAME.
1450
1451 If `gdb-thread-number' is nil, just wrap NAME in asterisks."
1434 (concat "*" name 1452 (concat "*" name
1435 (if (local-variable-p 'gdb-thread-number) 1453 (format
1436 " (bound to thread " 1454 (cond ((local-variable-p 'gdb-thread-number) " (bound to thread %s)")
1437 " (current thread ") 1455 (gdb-thread-number " (current thread %s)")
1438 gdb-thread-number ")*")) 1456 (t ""))
1457 gdb-thread-number)
1458 "*"))
1439 1459
1440 1460
1441 (defcustom gud-gdb-command-name "gdb -i=mi" 1461 (defcustom gud-gdb-command-name "gdb -i=mi"
1442 "Default command to execute an executable under the GDB debugger." 1462 "Default command to execute an executable under the GDB debugger."
1443 :type 'string 1463 :type 'string
1515 cannot be reliably used to determine whether or not execution 1535 cannot be reliably used to determine whether or not execution
1516 control buttons should be shown in menu or toolbar. Use 1536 control buttons should be shown in menu or toolbar. Use
1517 `gdb-running-threads-count' and `gdb-stopped-threads-count' 1537 `gdb-running-threads-count' and `gdb-stopped-threads-count'
1518 instead. 1538 instead.
1519 1539
1520 For all-stop mode, thread information is unavailable while target is running" 1540 For all-stop mode, thread information is unavailable while target
1541 is running."
1521 (setq gud-running 1542 (setq gud-running
1522 (string= (gdb-get-field (gdb-current-buffer-thread) 'state) 1543 (string= (gdb-get-field (gdb-current-buffer-thread) 'state)
1523 "running"))) 1544 "running")))
1524 1545
1525 ;; GUD displays the selected GDB frame. This might might not be the current 1546 ;; GUD displays the selected GDB frame. This might might not be the current
1549 (gdb-console . "~\\(\".*?\"\\)\n") 1570 (gdb-console . "~\\(\".*?\"\\)\n")
1550 (gdb-internals . "&\\(\".*?\"\\)\n") 1571 (gdb-internals . "&\\(\".*?\"\\)\n")
1551 (gdb-stopped . "\\*stopped,?\\(.*?\\)\n") 1572 (gdb-stopped . "\\*stopped,?\\(.*?\\)\n")
1552 (gdb-running . "\\*running,\\(.*?\n\\)") 1573 (gdb-running . "\\*running,\\(.*?\n\\)")
1553 (gdb-thread-created . "=thread-created,\\(.*?\n\\)") 1574 (gdb-thread-created . "=thread-created,\\(.*?\n\\)")
1554 (gdb-thread-exited . "=thread-exited,\\(.*?\n\\)"))) 1575 (gdb-thread-selected . "=thread-selected,\\(.*?\\)\n")
1576 (gdb-thread-exited . "=thread-exited,\\(.*?\n\\)")
1577 (gdb-ignored-notification . "=[-[:alpha:]]+,?\\(.*?\\)\n")
1578 (gdb-shell . "\\(\\(?:^.+\n\\)+\\)")))
1555 1579
1556 (defun gud-gdbmi-marker-filter (string) 1580 (defun gud-gdbmi-marker-filter (string)
1557 "Filter GDB/MI output." 1581 "Filter GDB/MI output."
1558 1582
1559 ;; Record transactions if logging is enabled. 1583 ;; Record transactions if logging is enabled.
1608 1632
1609 gdb-filter-output)) 1633 gdb-filter-output))
1610 1634
1611 (defun gdb-gdb (output-field)) 1635 (defun gdb-gdb (output-field))
1612 1636
1637 (defun gdb-shell (output-field)
1638 (let ((gdb-output-sink gdb-output-sink))
1639 (setq gdb-filter-output
1640 (concat output-field gdb-filter-output))))
1641
1642 (defun gdb-ignored-notification (output-field))
1643
1613 ;; gdb-invalidate-threads is defined to accept 'update-threads signal 1644 ;; gdb-invalidate-threads is defined to accept 'update-threads signal
1614 (defun gdb-thread-created (output-field)) 1645 (defun gdb-thread-created (output-field))
1615 (defun gdb-thread-exited (output-field) 1646 (defun gdb-thread-exited (output-field)
1616 (gdb-emit-signal gdb-buf-publisher 'update-threads)) 1647 (gdb-emit-signal gdb-buf-publisher 'update-threads))
1648
1649 (defun gdb-thread-selected (output-field)
1650 "Handler for =thread-selected MI output record.
1651
1652 Sets `gdb-thread-number' to new id."
1653 (let* ((result (gdb-json-string output-field))
1654 (thread-id (gdb-get-field result 'id)))
1655 (gdb-setq-thread-number thread-id)
1656 (gdb-wait-for-pending
1657 (gdb-update))))
1617 1658
1618 (defun gdb-running (output-field) 1659 (defun gdb-running (output-field)
1619 (setq gdb-inferior-status "running") 1660 (setq gdb-inferior-status "running")
1620 (gdb-force-mode-line-update 1661 (gdb-force-mode-line-update
1621 (propertize gdb-inferior-status 'face font-lock-type-face)) 1662 (propertize gdb-inferior-status 'face font-lock-type-face))
1953 (if (string-equal flag "y") 1994 (if (string-equal flag "y")
1954 (propertize "y" 'face font-lock-warning-face) 1995 (propertize "y" 'face font-lock-warning-face)
1955 (propertize "n" 'face font-lock-comment-face))) "\t" 1996 (propertize "n" 'face font-lock-comment-face))) "\t"
1956 (gdb-get-field breakpoint 'times) "\t" 1997 (gdb-get-field breakpoint 'times) "\t"
1957 (gdb-get-field breakpoint 'addr))) 1998 (gdb-get-field breakpoint 'addr)))
1958 (let ((at (gdb-get-field breakpoint 'at))) 1999 (let ((at (gdb-get-field breakpoint 'at))
1959 (cond ((not at) 2000 (pending (gdb-get-field breakpoint 'pending)))
2001 (cond (pending (insert " " pending))
2002 (at (insert " " at))
2003 (t
1960 (progn 2004 (progn
1961 (insert 2005 (insert
1962 (concat " in " 2006 (concat " in "
1963 (propertize (gdb-get-field breakpoint 'func) 2007 (propertize (gdb-get-field breakpoint 'func)
1964 'face font-lock-function-name-face))) 2008 'face font-lock-function-name-face)))
1965 (gdb-insert-frame-location breakpoint) 2009 (gdb-insert-frame-location breakpoint)
1966 (add-text-properties (line-beginning-position) 2010 (add-text-properties (line-beginning-position)
1967 (line-end-position) 2011 (line-end-position)
1968 '(mouse-face highlight 2012 '(mouse-face highlight
1969 help-echo "mouse-2, RET: visit breakpoint")))) 2013 help-echo "mouse-2, RET: visit breakpoint")))))
1970 (at (insert (concat " " at)))
1971 (t (insert (gdb-get-field breakpoint 'original-location)))))
1972 (add-text-properties (line-beginning-position) 2014 (add-text-properties (line-beginning-position)
1973 (line-end-position) 2015 (line-end-position)
1974 `(gdb-breakpoint ,breakpoint)) 2016 `(gdb-breakpoint ,breakpoint))
1975 (newline)) 2017 (newline))
1976 (gdb-place-breakpoints))) 2018 (gdb-place-breakpoints))))
1977 2019
1978 ;; Put breakpoint icons in relevant margins (even those set in the GUD buffer). 2020 ;; Put breakpoint icons in relevant margins (even those set in the GUD buffer).
1979 (defun gdb-place-breakpoints () 2021 (defun gdb-place-breakpoints ()
1980 (let ((flag) (bptno)) 2022 (let ((flag) (bptno))
1981 ;; Remove all breakpoint-icons in source buffers but not assembler buffer. 2023 ;; Remove all breakpoint-icons in source buffers but not assembler buffer.
2158 (let ((map (make-sparse-keymap))) 2200 (let ((map (make-sparse-keymap)))
2159 (define-key map (vector 'header-line mouse) function) 2201 (define-key map (vector 'header-line mouse) function)
2160 (define-key map (vector 'header-line 'down-mouse-1) 'ignore) 2202 (define-key map (vector 'header-line 'down-mouse-1) 'ignore)
2161 map)) 2203 map))
2162 2204
2205
2206 ;; uses "-thread-info". Needs GDB 7.0 onwards.
2207 ;;; Threads view
2208
2209 (defun gdb-jump-to (file line)
2210 (find-file-other-window file)
2211 (goto-line line))
2212
2213 (define-button-type 'gdb-file-button
2214 'help-echo "Push to jump to source code"
2215 ; 'face 'bold
2216 'action
2217 (lambda (b)
2218 (gdb-jump-to (button-get b 'file)
2219 (button-get b 'line))))
2220
2221 (defun gdb-insert-file-location-button (file line)
2222 "Insert text button which allows jumping to FILE:LINE.
2223
2224 FILE is a full path."
2225 (insert-text-button
2226 (format "%s:%d" (file-name-nondirectory file) line)
2227 :type 'gdb-file-button
2228 'file file
2229 'line line))
2230
2231 (defun gdb-threads-buffer-name ()
2232 (concat "*threads of " (gdb-get-target-string) "*"))
2233
2234 (def-gdb-display-buffer
2235 gdb-display-threads-buffer
2236 'gdb-threads-buffer
2237 "Display GDB threads.")
2238
2239 (def-gdb-frame-for-buffer
2240 gdb-frame-threads-buffer
2241 'gdb-threads-buffer
2242 "Display GDB threads in a new frame.")
2243
2244 (def-gdb-trigger-and-handler
2245 gdb-invalidate-threads "-thread-info"
2246 gdb-thread-list-handler gdb-thread-list-handler-custom
2247 '(update update-threads))
2248
2249 (gdb-set-buffer-rules
2250 'gdb-threads-buffer
2251 'gdb-threads-buffer-name
2252 'gdb-threads-mode
2253 'gdb-invalidate-threads)
2254
2255 (defvar gdb-threads-font-lock-keywords
2256 '(("in \\([^ ]+\\) (" (1 font-lock-function-name-face))
2257 (" \\(stopped\\) in " (1 font-lock-warning-face))
2258 (" \\(running\\)" (1 font-lock-string-face))
2259 ("\\(\\(\\sw\\|[_.]\\)+\\)=" (1 font-lock-variable-name-face)))
2260 "Font lock keywords used in `gdb-threads-mode'.")
2261
2262 (defvar gdb-threads-mode-map
2263 (let ((map (make-sparse-keymap)))
2264 (define-key map "\r" 'gdb-select-thread)
2265 (define-key map "f" 'gdb-display-stack-for-thread)
2266 (define-key map "F" 'gdb-frame-stack-for-thread)
2267 (define-key map "l" 'gdb-display-locals-for-thread)
2268 (define-key map "L" 'gdb-frame-locals-for-thread)
2269 (define-key map "r" 'gdb-display-registers-for-thread)
2270 (define-key map "R" 'gdb-frame-registers-for-thread)
2271 (define-key map "d" 'gdb-display-disassembly-for-thread)
2272 (define-key map "D" 'gdb-frame-disassembly-for-thread)
2273 (define-key map "i" 'gdb-interrupt-thread)
2274 (define-key map "c" 'gdb-continue-thread)
2275 (define-key map "s" 'gdb-step-thread)
2276 map))
2277
2163 (defmacro gdb-propertize-header (name buffer help-echo mouse-face face) 2278 (defmacro gdb-propertize-header (name buffer help-echo mouse-face face)
2164 `(propertize ,name 2279 `(propertize ,name
2165 'help-echo ,help-echo 2280 'help-echo ,help-echo
2166 'mouse-face ',mouse-face 2281 'mouse-face ',mouse-face
2167 'face ',face 2282 'face ',face
2174 (set-window-dedicated-p (selected-window) nil) 2289 (set-window-dedicated-p (selected-window) nil)
2175 (switch-to-buffer 2290 (switch-to-buffer
2176 (gdb-get-buffer-create ',buffer)) 2291 (gdb-get-buffer-create ',buffer))
2177 (setq header-line-format(gdb-set-header ',buffer)) 2292 (setq header-line-format(gdb-set-header ',buffer))
2178 (set-window-dedicated-p (selected-window) t)))))) 2293 (set-window-dedicated-p (selected-window) t))))))
2294
2295 (defvar gdb-breakpoints-header
2296 (list
2297 (gdb-propertize-header "Breakpoints" gdb-breakpoints-buffer
2298 nil nil mode-line)
2299 " "
2300 (gdb-propertize-header "Threads" gdb-threads-buffer
2301 "mouse-1: select" mode-line-highlight mode-line-inactive)))
2302 (define-derived-mode gdb-threads-mode gdb-parent-mode "Threads"
2303 "Major mode for GDB threads.
2304
2305 \\{gdb-threads-mode-map}"
2306 (setq gdb-thread-position (make-marker))
2307 (add-to-list 'overlay-arrow-variable-list 'gdb-thread-position)
2308 (setq header-line-format gdb-breakpoints-header)
2309 (set (make-local-variable 'font-lock-defaults)
2310 '(gdb-threads-font-lock-keywords))
2311 (run-mode-hooks 'gdb-threads-mode-hook)
2312 'gdb-invalidate-threads)
2313
2314 (defun gdb-thread-list-handler-custom ()
2315 (let* ((res (gdb-json-partial-output))
2316 (threads-list (gdb-get-field res 'threads)))
2317 (setq gdb-threads-list nil)
2318 (setq gdb-running-threads-count 0)
2319 (setq gdb-stopped-threads-count 0)
2320 (set-marker gdb-thread-position nil)
2321
2322 (dolist (thread (reverse threads-list))
2323 (let ((running (string-equal (gdb-get-field thread 'state) "running")))
2324 (add-to-list 'gdb-threads-list
2325 (cons (gdb-get-field thread 'id)
2326 thread))
2327 (if running
2328 (incf gdb-running-threads-count)
2329 (incf gdb-stopped-threads-count))
2330
2331 (insert (apply 'format `("%s (%s) %s"
2332 ,@(gdb-get-many-fields thread 'id 'target-id 'state))))
2333 ;; Include frame information for stopped threads
2334 (when (not running)
2335 (insert (concat " in " (gdb-get-field thread 'frame 'func)))
2336 (insert " (")
2337 (let ((args (gdb-get-field thread 'frame 'args)))
2338 (dolist (arg args)
2339 (insert (apply 'format `("%s=%s," ,@(gdb-get-many-fields arg 'name 'value)))))
2340 (when args (kill-backward-chars 1)))
2341 (insert ")")
2342 (gdb-insert-frame-location (gdb-get-field thread 'frame))
2343 (insert (format " at %s" (gdb-get-field thread 'frame 'addr))))
2344 (add-text-properties (line-beginning-position)
2345 (line-end-position)
2346 `(gdb-thread ,thread))
2347 ;; We assume that gdb-thread-number is non-nil by this time
2348 (when (string-equal gdb-thread-number
2349 (gdb-get-field thread 'id))
2350 (set-marker gdb-thread-position (line-beginning-position))))
2351 (newline))
2352 ;; We update gud-running here because we need to make sure that
2353 ;; gdb-threads-list is up-to-date
2354 (gdb-update-gud-running)))
2355
2356 (defmacro def-gdb-thread-buffer-command (name custom-defun &optional doc)
2357 "Define a NAME command which will act upon thread on the current line.
2358
2359 CUSTOM-DEFUN may use locally bound `thread' variable, which will
2360 be the value of 'gdb-thread property of the current line. If
2361 'gdb-thread is nil, error is signaled."
2362 `(defun ,name ()
2363 ,(when doc doc)
2364 (interactive)
2365 (save-excursion
2366 (beginning-of-line)
2367 (let ((thread (get-text-property (point) 'gdb-thread)))
2368 (if thread
2369 ,custom-defun
2370 (error "Not recognized as thread line"))))))
2371
2372 (defmacro def-gdb-thread-buffer-simple-command (name buffer-command &optional doc)
2373 "Define a NAME which will call BUFFER-COMMAND with id of thread
2374 on the current line."
2375 `(def-gdb-thread-buffer-command ,name
2376 (,buffer-command (gdb-get-field thread 'id))
2377 ,doc))
2378
2379 (def-gdb-thread-buffer-command gdb-select-thread
2380 (let ((new-id (gdb-get-field thread 'id)))
2381 (gdb-setq-thread-number new-id)
2382 (gdb-input (list (concat "-thread-select " new-id) 'ignore))
2383 (gdb-update))
2384 "Select the thread at current line of threads buffer.")
2385
2386 (def-gdb-thread-simple-buffer-command
2387 gdb-display-stack-for-thread
2388 gdb-display-stack-buffer
2389 "Display stack buffer for the thread at current line.")
2390
2391 (def-gdb-thread-simple-buffer-command
2392 gdb-display-locals-for-thread
2393 gdb-display-locals-buffer
2394 "Display locals buffer for the thread at current line.")
2395
2396 (def-gdb-thread-simple-buffer-command
2397 gdb-display-registers-for-thread
2398 gdb-display-registers-buffer
2399 "Display registers buffer for the thread at current line.")
2400
2401 (def-gdb-thread-buffer-simple-command
2402 gdb-display-disassembly-for-thread
2403 gdb-display-disassembly-buffer
2404 "Display disassembly buffer for the thread at current line.")
2405
2406 (def-gdb-thread-simple-buffer-command
2407 gdb-frame-stack-for-thread
2408 gdb-frame-stack-buffer
2409 "Display a new frame with stack buffer for the thread at
2410 current line.")
2411
2412 (def-gdb-thread-simple-buffer-command
2413 gdb-frame-locals-for-thread
2414 gdb-frame-locals-buffer
2415 "Display a new frame with locals buffer for the thread at
2416 current line.")
2417
2418 (def-gdb-thread-simple-buffer-command
2419 gdb-frame-registers-for-thread
2420 gdb-frame-registers-buffer
2421 "Display a new frame with registers buffer for the thread at
2422 current line.")
2423
2424 (def-gdb-thread-buffer-simple-command
2425 gdb-frame-disassembly-for-thread
2426 gdb-frame-disassembly-buffer
2427 "Display a new frame with disassembly buffer for the thread at
2428 current line.")
2429
2430 (defmacro def-gdb-thread-buffer-gdb-command (name gdb-command &optional doc)
2431 "Define a NAME which will execute send GDB-COMMAND with
2432 `gdb-thread-number' locally bound to id of thread on the current
2433 line."
2434 `(def-gdb-thread-buffer-command ,name
2435 (if gdb-non-stop
2436 (let ((gdb-thread-number (gdb-get-field thread 'id)))
2437 (gdb-input (list (gdb-current-context-command ,gdb-command)
2438 'ignore)))
2439 (error "Available in non-stop mode only, customize gdb-non-stop."))
2440 ,doc))
2441
2442 ;; Does this make sense in all-stop mode?
2443 (def-gdb-thread-buffer-gdb-command
2444 gdb-interrupt-thread
2445 "-exec-interrupt"
2446 "Interrupt thread at current line.")
2447
2448 (def-gdb-thread-buffer-gdb-command
2449 gdb-continue-thread
2450 "-exec-continue"
2451 "Continue thread at current line.")
2452
2453 (def-gdb-thread-buffer-gdb-command
2454 gdb-step-thread
2455 "-exec-step"
2456 "Step thread at current line.")
2179 2457
2180 (defun gdb-set-header (buffer) 2458 (defun gdb-set-header (buffer)
2181 (cond ((eq buffer 'gdb-locals-buffer) 2459 (cond ((eq buffer 'gdb-locals-buffer)
2182 (list 2460 (list
2183 (gdb-propertize-header "Locals" gdb-locals-buffer 2461 (gdb-propertize-header "Locals" gdb-locals-buffer
2204 (gdb-propertize-header "Breakpoints" gdb-breakpoints-buffer 2482 (gdb-propertize-header "Breakpoints" gdb-breakpoints-buffer
2205 "mouse-1: select" mode-line-highlight mode-line-inactive) 2483 "mouse-1: select" mode-line-highlight mode-line-inactive)
2206 " " 2484 " "
2207 (gdb-propertize-header "Threads" gdb-threads-buffer 2485 (gdb-propertize-header "Threads" gdb-threads-buffer
2208 nil nil mode-line))))) 2486 nil nil mode-line)))))
2209
2210
2211 ;; uses "-thread-info". Needs GDB 7.0 onwards.
2212 ;;; Threads view
2213
2214 (defun gdb-jump-to (file line)
2215 (find-file-other-window file)
2216 (goto-line line))
2217
2218 (define-button-type 'gdb-file-button
2219 'help-echo "Push to jump to source code"
2220 ; 'face 'bold
2221 'action
2222 (lambda (b)
2223 (gdb-jump-to (button-get b 'file)
2224 (button-get b 'line))))
2225
2226 (defun gdb-insert-file-location-button (file line)
2227 "Insert text button which allows jumping to FILE:LINE.
2228
2229 FILE is a full path."
2230 (insert-text-button
2231 (format "%s:%d" (file-name-nondirectory file) line)
2232 :type 'gdb-file-button
2233 'file file
2234 'line line))
2235
2236 (defun gdb-threads-buffer-name ()
2237 (concat "*threads of " (gdb-get-target-string) "*"))
2238
2239 (def-gdb-display-buffer
2240 gdb-display-threads-buffer
2241 'gdb-threads-buffer
2242 "Display GDB threads.")
2243
2244 (def-gdb-frame-for-buffer
2245 gdb-frame-threads-buffer
2246 'gdb-threads-buffer
2247 "Display GDB threads in a new frame.")
2248
2249 (def-gdb-trigger-and-handler
2250 gdb-invalidate-threads "-thread-info"
2251 gdb-thread-list-handler gdb-thread-list-handler-custom
2252 '(update update-threads))
2253
2254 (gdb-set-buffer-rules
2255 'gdb-threads-buffer
2256 'gdb-threads-buffer-name
2257 'gdb-threads-mode
2258 'gdb-invalidate-threads)
2259
2260 (defvar gdb-threads-font-lock-keywords
2261 '(("in \\([^ ]+\\) (" (1 font-lock-function-name-face))
2262 (" \\(stopped\\) in " (1 font-lock-warning-face))
2263 (" \\(running\\)" (1 font-lock-string-face))
2264 ("\\(\\(\\sw\\|[_.]\\)+\\)=" (1 font-lock-variable-name-face)))
2265 "Font lock keywords used in `gdb-threads-mode'.")
2266
2267 (defvar gdb-threads-mode-map
2268 (let ((map (make-sparse-keymap)))
2269 (define-key map "\r" 'gdb-select-thread)
2270 (define-key map "f" 'gdb-display-stack-for-thread)
2271 (define-key map "F" 'gdb-frame-stack-for-thread)
2272 (define-key map "l" 'gdb-display-locals-for-thread)
2273 (define-key map "L" 'gdb-frame-locals-for-thread)
2274 (define-key map "r" 'gdb-display-registers-for-thread)
2275 (define-key map "R" 'gdb-frame-registers-for-thread)
2276 (define-key map "d" 'gdb-display-disassembly-for-thread)
2277 (define-key map "D" 'gdb-frame-disassembly-for-thread)
2278 (define-key map "i" 'gdb-interrupt-thread)
2279 (define-key map "c" 'gdb-continue-thread)
2280 (define-key map "s" 'gdb-step-thread)
2281 map))
2282
2283 (defvar gdb-breakpoints-header
2284 (list
2285 (gdb-propertize-header "Breakpoints" gdb-breakpoints-buffer
2286 nil nil mode-line)
2287 " "
2288 (gdb-propertize-header "Threads" gdb-threads-buffer
2289 "mouse-1: select" mode-line-highlight mode-line-inactive)))
2290 (define-derived-mode gdb-threads-mode gdb-parent-mode "Threads"
2291 "Major mode for GDB threads.
2292
2293 \\{gdb-threads-mode-map}"
2294 (setq gdb-thread-position (make-marker))
2295 (add-to-list 'overlay-arrow-variable-list 'gdb-thread-position)
2296 (setq header-line-format gdb-breakpoints-header)
2297 (set (make-local-variable 'font-lock-defaults)
2298 '(gdb-threads-font-lock-keywords))
2299 (run-mode-hooks 'gdb-threads-mode-hook)
2300 'gdb-invalidate-threads)
2301
2302 (defun gdb-thread-list-handler-custom ()
2303 (let* ((res (gdb-json-partial-output))
2304 (threads-list (gdb-get-field res 'threads)))
2305 (setq gdb-threads-list nil)
2306 (setq gdb-running-threads-count 0)
2307 (setq gdb-stopped-threads-count 0)
2308 (set-marker gdb-thread-position nil)
2309
2310 (dolist (thread (reverse threads-list))
2311 (let ((running (string-equal (gdb-get-field thread 'state) "running")))
2312 (add-to-list 'gdb-threads-list
2313 (cons (gdb-get-field thread 'id)
2314 thread))
2315 (if running
2316 (incf gdb-running-threads-count)
2317 (incf gdb-stopped-threads-count))
2318
2319 (insert (apply 'format `("%s (%s) %s"
2320 ,@(gdb-get-many-fields thread 'id 'target-id 'state))))
2321 ;; Include frame information for stopped threads
2322 (when (not running)
2323 (insert (concat " in " (gdb-get-field thread 'frame 'func)))
2324 (insert " (")
2325 (let ((args (gdb-get-field thread 'frame 'args)))
2326 (dolist (arg args)
2327 (insert (apply 'format `("%s=%s," ,@(gdb-get-many-fields arg 'name 'value)))))
2328 (when args (kill-backward-chars 1)))
2329 (insert ")")
2330 (gdb-insert-frame-location (gdb-get-field thread 'frame))
2331 (insert (format " at %s" (gdb-get-field thread 'frame 'addr))))
2332 (add-text-properties (line-beginning-position)
2333 (line-end-position)
2334 `(gdb-thread ,thread))
2335 ;; We assume that gdb-thread-number is non-nil by this time
2336 (when (string-equal gdb-thread-number
2337 (gdb-get-field thread 'id))
2338 (set-marker gdb-thread-position (line-beginning-position))))
2339 (newline))
2340 ;; We update gud-running here because we need to make sure that
2341 ;; gdb-threads-list is up-to-date
2342 (gdb-update-gud-running)))
2343
2344 (defmacro def-gdb-thread-buffer-command (name custom-defun &optional doc)
2345 "Define a NAME command which will act upon thread on the current line.
2346
2347 CUSTOM-DEFUN may use locally bound `thread' variable, which will
2348 be the value of 'gdb-thread property of the current line. If
2349 'gdb-thread is nil, error is signaled."
2350 `(defun ,name ()
2351 ,(when doc doc)
2352 (interactive)
2353 (save-excursion
2354 (beginning-of-line)
2355 (let ((thread (get-text-property (point) 'gdb-thread)))
2356 (if thread
2357 ,custom-defun
2358 (error "Not recognized as thread line"))))))
2359
2360 (defmacro def-gdb-thread-buffer-simple-command (name buffer-command &optional doc)
2361 "Define a NAME which will call BUFFER-COMMAND with id of thread
2362 on the current line."
2363 `(def-gdb-thread-buffer-command ,name
2364 (,buffer-command (gdb-get-field thread 'id))
2365 ,doc))
2366
2367 (def-gdb-thread-buffer-command gdb-select-thread
2368 (let ((new-id (gdb-get-field thread 'id)))
2369 (gdb-setq-thread-number new-id)
2370 (gdb-input (list (concat "-thread-select " new-id) 'ignore))
2371 (gdb-update))
2372 "Select the thread at current line of threads buffer.")
2373
2374 (def-gdb-thread-simple-buffer-command
2375 gdb-display-stack-for-thread
2376 gdb-display-stack-buffer
2377 "Display stack buffer for the thread at current line.")
2378
2379 (def-gdb-thread-simple-buffer-command
2380 gdb-display-locals-for-thread
2381 gdb-display-locals-buffer
2382 "Display locals buffer for the thread at current line.")
2383
2384 (def-gdb-thread-simple-buffer-command
2385 gdb-display-registers-for-thread
2386 gdb-display-registers-buffer
2387 "Display registers buffer for the thread at current line.")
2388
2389 (def-gdb-thread-buffer-simple-command
2390 gdb-display-disassembly-for-thread
2391 gdb-display-disassembly-buffer
2392 "Display disassembly buffer for the thread at current line.")
2393
2394 (def-gdb-thread-simple-buffer-command
2395 gdb-frame-stack-for-thread
2396 gdb-frame-stack-buffer
2397 "Display a new frame with stack buffer for the thread at
2398 current line.")
2399
2400 (def-gdb-thread-simple-buffer-command
2401 gdb-frame-locals-for-thread
2402 gdb-frame-locals-buffer
2403 "Display a new frame with locals buffer for the thread at
2404 current line.")
2405
2406 (def-gdb-thread-simple-buffer-command
2407 gdb-frame-registers-for-thread
2408 gdb-frame-registers-buffer
2409 "Display a new frame with registers buffer for the thread at
2410 current line.")
2411
2412 (def-gdb-thread-buffer-simple-command
2413 gdb-frame-disassembly-for-thread
2414 gdb-frame-disassembly-buffer
2415 "Display a new frame with disassembly buffer for the thread at
2416 current line.")
2417
2418 (defmacro def-gdb-thread-buffer-gdb-command (name gdb-command &optional doc)
2419 "Define a NAME which will execute send GDB-COMMAND with
2420 `gdb-thread-number' locally bound to id of thread on the current
2421 line."
2422 `(def-gdb-thread-buffer-command ,name
2423 (if gdb-non-stop
2424 (let ((gdb-thread-number (gdb-get-field thread 'id)))
2425 (gdb-input (list (gdb-current-context-command ,gdb-command)
2426 'ignore)))
2427 (error "Available in non-stop mode only, customize gdb-non-stop."))
2428 ,doc))
2429
2430 ;; Does this make sense in all-stop mode?
2431 (def-gdb-thread-buffer-gdb-command
2432 gdb-interrupt-thread
2433 "-exec-interrupt"
2434 "Interrupt thread at current line.")
2435
2436 (def-gdb-thread-buffer-gdb-command
2437 gdb-continue-thread
2438 "-exec-continue"
2439 "Continue thread at current line.")
2440
2441 (def-gdb-thread-buffer-gdb-command
2442 gdb-step-thread
2443 "-exec-step"
2444 "Step thread at current line.")
2445 2487
2446 2488
2447 ;;; Memory view 2489 ;;; Memory view
2448 2490
2449 (defcustom gdb-memory-rows 8 2491 (defcustom gdb-memory-rows 8
2849 'gdb-disassembly-buffer 2891 'gdb-disassembly-buffer
2850 "Display disassembly in a new frame.") 2892 "Display disassembly in a new frame.")
2851 2893
2852 (def-gdb-auto-update-trigger gdb-invalidate-disassembly 2894 (def-gdb-auto-update-trigger gdb-invalidate-disassembly
2853 (let* ((frame (gdb-current-buffer-frame)) 2895 (let* ((frame (gdb-current-buffer-frame))
2854 (file (gdb-get-field frame 'file)) 2896 (file (gdb-get-field frame 'fullname))
2855 (line (gdb-get-field frame 'line))) 2897 (line (gdb-get-field frame 'line)))
2856 (when file 2898 (when file
2857 (format "-data-disassemble -f %s -l %s -n -1 -- 0" file line))) 2899 (format "-data-disassemble -f %s -l %s -n -1 -- 0" file line)))
2858 gdb-disassembly-handler) 2900 gdb-disassembly-handler)
2859 2901
3373 ;; Insert first prompt. 3415 ;; Insert first prompt.
3374 (setq gdb-filter-output (concat gdb-filter-output gdb-prompt-name))) 3416 (setq gdb-filter-output (concat gdb-filter-output gdb-prompt-name)))
3375 3417
3376 ;;;; Window management 3418 ;;;; Window management
3377 (defun gdb-display-buffer (buf dedicated &optional frame) 3419 (defun gdb-display-buffer (buf dedicated &optional frame)
3420 "Show buffer BUF.
3421
3422 If BUF is already displayed in some window, show it, deiconifying
3423 the frame if necessary. Otherwise, find least recently used
3424 window and show BUF there, if the window is not used for GDB
3425 already, in which case that window is splitted first."
3378 (let ((answer (get-buffer-window buf (or frame 0)))) 3426 (let ((answer (get-buffer-window buf (or frame 0))))
3379 (if answer 3427 (if answer
3380 (display-buffer buf nil (or frame 0)) ;Deiconify the frame if necessary. 3428 (display-buffer buf nil (or frame 0)) ;Deiconify the frame if necessary.
3381 (let ((window (get-lru-window))) 3429 (let ((window (get-lru-window)))
3382 (if (eq (buffer-local-value 'gud-minor-mode (window-buffer window)) 3430 (if (eq (buffer-local-value 'gud-minor-mode (window-buffer window))
3424 (define-key menu [locals] '("Locals" . gdb-frame-locals-buffer)) 3472 (define-key menu [locals] '("Locals" . gdb-frame-locals-buffer))
3425 (define-key menu [frames] '("Stack" . gdb-frame-stack-buffer)) 3473 (define-key menu [frames] '("Stack" . gdb-frame-stack-buffer))
3426 (define-key menu [breakpoints] 3474 (define-key menu [breakpoints]
3427 '("Breakpoints" . gdb-frame-breakpoints-buffer))) 3475 '("Breakpoints" . gdb-frame-breakpoints-buffer)))
3428 3476
3429 (let ((menu (make-sparse-keymap "GDB-MI")) 3477 (let ((menu (make-sparse-keymap "GDB-MI")))
3430 (submenu (make-sparse-keymap "GUD thread control mode")))
3431 (define-key menu [gdb-customize] 3478 (define-key menu [gdb-customize]
3432 '(menu-item "Customize" (lambda () (interactive) (customize-group 'gdb)) 3479 '(menu-item "Customize" (lambda () (interactive) (customize-group 'gdb))
3433 :help "Customize Gdb Graphical Mode options.")) 3480 :help "Customize Gdb Graphical Mode options."))
3434 (define-key menu [gdb-many-windows] 3481 (define-key menu [gdb-many-windows]
3435 '(menu-item "Display Other Windows" gdb-many-windows 3482 '(menu-item "Display Other Windows" gdb-many-windows
3438 (define-key menu [gdb-restore-windows] 3485 (define-key menu [gdb-restore-windows]
3439 '(menu-item "Restore Window Layout" gdb-restore-windows 3486 '(menu-item "Restore Window Layout" gdb-restore-windows
3440 :help "Restore standard layout for debug session.")) 3487 :help "Restore standard layout for debug session."))
3441 (define-key menu [sep1] 3488 (define-key menu [sep1]
3442 '(menu-item "--")) 3489 '(menu-item "--"))
3443 (define-key submenu [all-threads] 3490 (define-key menu [all-threads]
3444 '(menu-item "All threads" 3491 '(menu-item "GUD controls all threads"
3445 (lambda () 3492 (lambda ()
3446 (interactive) 3493 (interactive)
3447 (setq gdb-gud-control-all-threads t)) 3494 (setq gdb-gud-control-all-threads t))
3448 :help "GUD start/stop commands apply to all threads" 3495 :help "GUD start/stop commands apply to all threads"
3449 :button (:radio . gdb-gud-control-all-threads))) 3496 :button (:radio . gdb-gud-control-all-threads)))
3450 (define-key submenu [current-thread] 3497 (define-key menu [current-thread]
3451 '(menu-item "Current thread" 3498 '(menu-item "GUD controls current thread"
3452 (lambda () 3499 (lambda ()
3453 (interactive) 3500 (interactive)
3454 (setq gdb-gud-control-all-threads nil)) 3501 (setq gdb-gud-control-all-threads nil))
3455 :help "GUD start/stop commands apply to current thread only" 3502 :help "GUD start/stop commands apply to current thread only"
3456 :button (:radio . (not gdb-gud-control-all-threads)))) 3503 :button (:radio . (not gdb-gud-control-all-threads))))
3457 (define-key menu [thread-control] 3504 (define-key menu [sep2]
3458 `("GUD thread control mode" . ,submenu)) 3505 '(menu-item "--"))
3459 (define-key gud-menu-map [mi] 3506 (define-key menu [gdb-customize-reasons]
3460 `(menu-item "GDB-MI" ,menu :visible (eq gud-minor-mode 'gdbmi))) 3507 '(menu-item "Customize switching..."
3508 (lambda ()
3509 (interactive)
3510 (customize-option 'gdb-switch-reasons))))
3461 (define-key menu [gdb-switch-when-another-stopped] 3511 (define-key menu [gdb-switch-when-another-stopped]
3462 (menu-bar-make-toggle gdb-toggle-switch-when-another-stopped gdb-switch-when-another-stopped 3512 (menu-bar-make-toggle gdb-toggle-switch-when-another-stopped gdb-switch-when-another-stopped
3463 "Automatically switch to stopped thread" 3513 "Automatically switch to stopped thread"
3464 "GDB thread switching %s" 3514 "GDB thread switching %s"
3465 "Switch to stopped thread")) 3515 "Switch to stopped thread"))
3466 (define-key menu [gdb-non-stop] 3516 (define-key gud-menu-map [mi]
3467 (menu-bar-make-toggle gdb-toggle-non-stop gdb-non-stop 3517 `(menu-item "GDB-MI" ,menu :visible (eq gud-minor-mode 'gdbmi))))
3468 "Non-stop mode"
3469 "GDB non-stop mode %s"
3470 "Allow examining stopped threads while others continue to execute")))
3471 3518
3472 (defun gdb-frame-gdb-buffer () 3519 (defun gdb-frame-gdb-buffer ()
3473 "Display GUD buffer in a new frame." 3520 "Display GUD buffer in a new frame."
3474 (interactive) 3521 (interactive)
3475 (let ((special-display-regexps (append special-display-regexps '(".*"))) 3522 (let ((special-display-regexps (append special-display-regexps '(".*")))