libguile-3.0-gdb.scm 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. ;;; GDB debugging support for Guile.
  2. ;;;
  3. ;;; Copyright 2014, 2015, 2017, 2020 Free Software Foundation, Inc.
  4. ;;;
  5. ;;; This program is free software; you can redistribute it and/or modify it
  6. ;;; under the terms of the GNU General Public License as published by
  7. ;;; the Free Software Foundation; either version 3 of the License, or (at
  8. ;;; your option) any later version.
  9. ;;;
  10. ;;; This program is distributed in the hope that it will be useful, but
  11. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;;; GNU General Public License for more details.
  14. ;;;
  15. ;;; You should have received a copy of the GNU General Public License
  16. ;;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. (define-module (guile-gdb)
  18. #:use-module (system base types)
  19. ;; Note: (system vm debug) is 2.2-specific, but GDB might be built
  20. ;; with Guile 2.0.
  21. #:autoload (system vm debug) (debug-context-from-image
  22. debug-context-base
  23. find-program-debug-info)
  24. #:use-module ((gdb) #:hide (symbol? frame?))
  25. #:use-module ((gdb) #:select ((symbol? . gdb:symbol?) (frame? . gdb:frame?)))
  26. #:use-module (gdb printing)
  27. #:use-module (srfi srfi-9)
  28. #:use-module (srfi srfi-11)
  29. #:use-module (srfi srfi-41)
  30. #:use-module (ice-9 match)
  31. #:use-module (ice-9 binary-ports)
  32. #:export (%gdb-memory-backend
  33. display-vm-frames))
  34. ;;; Commentary:
  35. ;;;
  36. ;;; This file defines GDB extensions to pretty-print 'SCM' objects, and
  37. ;;; to walk Guile's virtual machine stack.
  38. ;;;
  39. ;;; This file is installed under a name that follows the convention that
  40. ;;; allows GDB to auto-load it anytime the user is debugging libguile
  41. ;;; (info "(gdb) objfile-gdbdotext file").
  42. ;;;
  43. ;;; Code:
  44. ;; At run time, make sure we load (system base types) from the Guile
  45. ;; being debugged rather than from the Guile GDB is linked against.
  46. (set! %load-path
  47. (cons "@pkgdatadir@/@GUILE_EFFECTIVE_VERSION@" %load-path))
  48. (set! %load-compiled-path
  49. (cons "@pkglibdir@/@GUILE_EFFECTIVE_VERSION@/site-ccache" %load-compiled-path))
  50. (reload-module (resolve-module '(system base types)))
  51. (define (type-name-from-descriptor descriptor-array type-number)
  52. "Return the name of the type TYPE-NUMBER as seen in DESCRIPTOR-ARRAY, or #f
  53. if the information is not available."
  54. (let ((descriptors (lookup-global-symbol descriptor-array)))
  55. (and descriptors
  56. (let ((code (type-code (symbol-type descriptors))))
  57. (or (= TYPE_CODE_ARRAY code)
  58. (= TYPE_CODE_PTR code)))
  59. (let* ((type-descr (value-subscript (symbol-value descriptors)
  60. type-number))
  61. (name (value-field type-descr "name")))
  62. (value->string name)))))
  63. (define %gdb-memory-backend
  64. ;; The GDB back-end to access the inferior's memory.
  65. ;; When run through 'rr replay', even the 'void' type is initially
  66. ;; unavailable. Thus, delay lookup until it's actually needed.
  67. (let ((void* (delay (type-pointer (lookup-type "void")))))
  68. (define (dereference-word address)
  69. ;; Return the word at ADDRESS.
  70. (value->integer
  71. (value-dereference (value-cast (make-value address)
  72. (type-pointer (force void*))))))
  73. (define (open address size)
  74. ;; Return a port to the SIZE bytes starting at ADDRESS.
  75. (if size
  76. (open-memory #:start address #:size size)
  77. (open-memory #:start address)))
  78. (define (type-name kind number)
  79. ;; Return the type name of KIND type NUMBER.
  80. (type-name-from-descriptor (case kind
  81. ((smob) "scm_smobs")
  82. ((port) "scm_ptobs"))
  83. number))
  84. (memory-backend dereference-word open type-name)))
  85. ;;;
  86. ;;; GDB pretty-printer registration.
  87. ;;;
  88. (define scm-value->string
  89. (lambda* (value #:optional (backend %gdb-memory-backend))
  90. "Return a representation of value VALUE as a string."
  91. (object->string (scm->object (value->integer value) backend))))
  92. (define (make-scm-pretty-printer-worker obj)
  93. (define (list->iterator list)
  94. (make-iterator list list
  95. (let ((n 0))
  96. (lambda (iter)
  97. (match (iterator-progress iter)
  98. (() (end-of-iteration))
  99. ((elt . list)
  100. (set-iterator-progress! iter list)
  101. (let ((name (format #f "[~a]" n)))
  102. (set! n (1+ n))
  103. (cons name (object->string elt)))))))))
  104. (cond
  105. ((string? obj)
  106. (make-pretty-printer-worker
  107. "string" ; display hint
  108. (lambda (printer) obj)
  109. #f))
  110. ((and (array? obj)
  111. (match (array-shape obj)
  112. (((0 _)) #t)
  113. (_ #f)))
  114. (make-pretty-printer-worker
  115. "array" ; display hint
  116. (lambda (printer)
  117. (let ((tag (array-type obj)))
  118. (case tag
  119. ((#t) "#<vector>")
  120. ((b) "#<bitvector>")
  121. (else (format #f "#<~avector>" tag)))))
  122. (lambda (printer)
  123. (list->iterator (array->list obj)))))
  124. ((inferior-struct? obj)
  125. (make-pretty-printer-worker
  126. "array" ; display hint
  127. (lambda (printer)
  128. (format #f "#<struct ~a>" (inferior-struct-name obj)))
  129. (lambda (printer)
  130. (list->iterator (inferior-struct-fields obj)))))
  131. (else
  132. (make-pretty-printer-worker
  133. #f ; display hint
  134. (lambda (printer)
  135. (object->string obj))
  136. #f))))
  137. (define %scm-pretty-printer
  138. (make-pretty-printer
  139. "SCM"
  140. (lambda (pp value)
  141. (let ((name (type-name (value-type value))))
  142. (and (and name (string=? name "SCM"))
  143. (make-scm-pretty-printer-worker
  144. (scm->object (value->integer value) %gdb-memory-backend)))))))
  145. (define* (register-pretty-printer #:optional objfile)
  146. (prepend-pretty-printer! objfile %scm-pretty-printer))
  147. (register-pretty-printer)
  148. ;;;
  149. ;;; VM stack walking.
  150. ;;;
  151. (define-record-type <vm-frame>
  152. (make-vm-frame ip sp fp saved-ip saved-fp)
  153. vm-frame?
  154. (ip vm-frame-ip)
  155. (sp vm-frame-sp)
  156. (fp vm-frame-fp)
  157. (saved-ip vm-frame-saved-ip)
  158. (saved-fp vm-frame-saved-fp))
  159. ;; See libguile/frames.h.
  160. (define* (vm-frame ip sp fp #:optional (backend %gdb-memory-backend))
  161. "Return the components of the stack frame at FP."
  162. (define ip-type (type-pointer (lookup-type "uint32_t")))
  163. (define uint-type (type-pointer (lookup-type "uintptr_t")))
  164. (make-vm-frame ip
  165. sp
  166. fp
  167. ;; fp[0] is the return address.
  168. (value-dereference (value-cast fp (type-pointer ip-type)))
  169. ;; fp[1] is the offset to the previous frame pointer.
  170. (value-add fp
  171. (value->integer
  172. (value-dereference
  173. (value-cast (value-add fp 1)
  174. (type-pointer uint-type)))))))
  175. (define (vm-engine-frame? frame)
  176. (let ((sym (frame-function frame)))
  177. (and sym
  178. (member (symbol-name sym)
  179. '("vm_debug_engine" "vm_regular_engine")))))
  180. (define (find-vp)
  181. "Find the scm_vm pointer for the current thread."
  182. (match (lookup-symbol "scm_i_current_thread")
  183. ((#f _)
  184. #f)
  185. ((symbol _)
  186. (let ((thread (symbol-value symbol)))
  187. (value-field thread "vm")))))
  188. (define (newest-vm-frame)
  189. "Return the newest VM frame or #f."
  190. (let ((vp (find-vp)))
  191. (and vp
  192. (vm-frame (value-field vp "ip")
  193. (value-field vp "sp")
  194. (value-field vp "fp")))))
  195. (define* (vm-frame-older frame #:optional (backend %gdb-memory-backend))
  196. (let ((ip (vm-frame-saved-ip frame))
  197. (sp (value-sub (vm-frame-fp frame) 3))
  198. (fp (vm-frame-saved-fp frame)))
  199. (and (not (zero? (value->integer ip)))
  200. (vm-frame ip sp fp backend))))
  201. (define (vm-frames)
  202. "Return a SRFI-41 stream of the current VM frame stack."
  203. (stream-unfold identity
  204. vm-frame?
  205. vm-frame-older
  206. (newest-vm-frame)))
  207. (define (vm-frame-locals frame)
  208. (let ((fp (vm-frame-fp frame))
  209. (sp (vm-frame-sp frame)))
  210. (let lp ((slot 0) (ptr fp))
  211. (if (value<=? ptr sp)
  212. (acons (string-append "v" (number->string slot))
  213. (value-dereference ptr)
  214. (lp (1+ slot) (value-add ptr 1)))
  215. '()))))
  216. (define (lookup-symbol-or-false name)
  217. (match (lookup-symbol name)
  218. (#f #f)
  219. ((sym _) sym)))
  220. (define (find-mapped-elf-image addr)
  221. (let ((array (lookup-symbol-or-false "mapped_elf_images"))
  222. (count (lookup-symbol-or-false "mapped_elf_images_count")))
  223. (and array count
  224. (let ((array (symbol-value array))
  225. (count (value->integer (symbol-value count))))
  226. (let lp ((start 0) (end count))
  227. (if (< start end)
  228. (let ((n (+ start (ash (- end start) -1))))
  229. (if (value<? addr (value-field (value-add array n) "end"))
  230. (lp start n)
  231. (lp (1+ n) end)))
  232. (let ((mei (value-add array start)))
  233. (and (value<=? (value-field mei "start") addr)
  234. mei))))))))
  235. (define (vm-frame-program-debug-info frame)
  236. (let ((addr (vm-frame-ip frame)))
  237. (and=> (find-mapped-elf-image addr)
  238. (lambda (mei)
  239. (let* ((start (value->integer (value-field mei "start")))
  240. (size (- (value->integer (value-field mei "end"))
  241. start))
  242. (mem-port (open-memory #:start start #:size size))
  243. (bv (get-bytevector-all mem-port))
  244. (ctx (debug-context-from-image bv)))
  245. ;; The image is in this process at "bv", but in the
  246. ;; inferior at mei.start. Therefore we relocate addr
  247. ;; before we look for the PDI.
  248. (let ((addr (+ (value->integer addr)
  249. (- (debug-context-base ctx) start))))
  250. (find-program-debug-info addr ctx)))))))
  251. (define (vm-frame-function-name frame)
  252. (define (default-name)
  253. "[unknown]")
  254. (cond
  255. ((false-if-exception (vm-frame-program-debug-info frame))
  256. => (lambda (pdi)
  257. (or (and=> (program-debug-info-name pdi) symbol->string)
  258. "[anonymous]")))
  259. (else
  260. (let ((ip (vm-frame-ip frame)))
  261. (define (ip-in-symbol? name)
  262. (let ((sym (lookup-symbol-or-false name)))
  263. (and sym
  264. (not (value-optimized-out? (symbol-value sym)))
  265. (let* ((val (symbol-value sym))
  266. (size (type-sizeof (value-type val)))
  267. (char* (type-pointer (arch-char-type (current-arch))))
  268. (val-as-char* (value-cast val char*)))
  269. (and (value<=? val-as-char* ip)
  270. (value<? ip (value-add val-as-char* size)))))))
  271. (cond
  272. ((ip-in-symbol? "vm_boot_continuation_code") "[boot continuation]")
  273. ;; FIXME: For subrs, read the name from slot 0 in the frame.
  274. ((ip-in-symbol? "subr_stub_code") "[subr call]")
  275. ((ip-in-symbol? "vm_builtin_apply_code") "apply")
  276. ((ip-in-symbol? "vm_builtin_values_code") "values")
  277. ((ip-in-symbol? "vm_builtin_abort_to_prompt_code") "abort-to-prompt")
  278. ((ip-in-symbol? "vm_builtin_call_with_values_code") "call-with-values")
  279. ((ip-in-symbol? "vm_builtin_call_with_current_continuation_code")
  280. "call-with-current-continuation")
  281. ((ip-in-symbol? "continuation_stub_code") "[continuation]")
  282. ((ip-in-symbol? "compose_continuation_code") "[delimited continuation]")
  283. ((ip-in-symbol? "foreign_stub_code") "[ffi call]")
  284. (else (default-name)))))))
  285. (define (vm-frame-source frame)
  286. (let* ((ip (value->integer (vm-frame-ip frame)))
  287. (pdi (vm-frame-program-debug-info frame)))
  288. (and pdi
  289. (find-source-for-addr (program-debug-info-addr pdi)
  290. (program-debug-info-context pdi)))))
  291. (define* (dump-vm-frame frame #:optional (port (current-output-port)))
  292. (format port " name: ~a~%" (vm-frame-function-name frame))
  293. (format port " ip: 0x~x~%" (value->integer (vm-frame-ip frame)))
  294. (format port " fp: 0x~x~%" (value->integer (vm-frame-fp frame)))
  295. (for-each (match-lambda
  296. ((name . val)
  297. (let ((obj (scm->object (value->integer val) %gdb-memory-backend)))
  298. (format port " ~a: ~a~%" name obj))))
  299. (vm-frame-locals frame)))
  300. (define* (display-vm-frames #:optional (port (current-output-port)))
  301. "Display the VM frames on PORT."
  302. (stream-for-each (lambda (frame)
  303. (dump-vm-frame frame port))
  304. (vm-frames)))
  305. (register-command!
  306. (make-command "guile-backtrace"
  307. #:command-class COMMAND_STACK
  308. #:doc "Display a backtrace of Guile's VM stack for the \
  309. current thread"
  310. #:invoke (lambda (self args from-tty)
  311. (display-vm-frames))))
  312. ;;;
  313. ;;; Frame filters.
  314. ;;;
  315. (define-syntax compile-time-cond
  316. (lambda (x)
  317. (syntax-case x ()
  318. ((_ (test body ...) clause ...)
  319. (if (eval (syntax->datum #'test) (current-module))
  320. #'(begin body ...)
  321. #'(compile-time-cond clause ...)))
  322. ((_)
  323. #'(begin)))))
  324. (compile-time-cond
  325. ;; What follows depends on (gdb frame-filters), which unfortunately has
  326. ;; not yet been merged in GDB:
  327. ;; <https://sourceware.org/ml/gdb-patches/2015-02/msg00362.html>.
  328. ((false-if-exception (resolve-interface '(gdb frame-filters)))
  329. (use-modules (gdb frame-filters))
  330. (define (snarfy-frame-decorator dec)
  331. (let* ((frame (decorated-frame-frame dec))
  332. (sym (frame-function frame)))
  333. (or
  334. (and sym
  335. (gdb:symbol? sym)
  336. (let ((c-name (symbol-name sym)))
  337. (match (lookup-symbol (string-append "s_" c-name))
  338. (#f #f)
  339. ((scheme-name-sym _)
  340. (and (string-prefix?
  341. "const char ["
  342. (type-print-name (symbol-type scheme-name-sym)))
  343. (let* ((scheme-name-value (symbol-value scheme-name-sym))
  344. (scheme-name (value->string scheme-name-value))
  345. (name (format #f "~a [~a]" scheme-name c-name)))
  346. (redecorate-frame dec #:function-name name)))))))
  347. dec)))
  348. (define* (vm-frame-filter gdb-frames #:optional (vm-frames (vm-frames)))
  349. (define (synthesize-frame gdb-frame vm-frame)
  350. (let* ((ip (value->integer (vm-frame-ip vm-frame)))
  351. (source (vm-frame-source vm-frame)))
  352. (redecorate-frame gdb-frame
  353. #:function-name (vm-frame-function-name vm-frame)
  354. #:address ip
  355. #:filename (and=> source source-file)
  356. #:line (and=> source source-line-for-user)
  357. #:arguments '()
  358. #:locals (vm-frame-locals vm-frame)
  359. #:children '())))
  360. (define (recur gdb-frame gdb-frames vm-frames)
  361. (stream-cons gdb-frame
  362. (vm-frame-filter gdb-frames vm-frames)))
  363. (cond
  364. ((or (stream-null? gdb-frames)
  365. (not (lookup-symbol "vm_boot_continuation_code")))
  366. gdb-frames)
  367. (else
  368. (let ((gdb-frame (stream-car gdb-frames))
  369. (gdb-frames (stream-cdr gdb-frames)))
  370. (match (lookup-symbol "vm_boot_continuation_code")
  371. ((boot-sym _)
  372. (let ((boot-ptr (symbol-value boot-sym)))
  373. (cond
  374. ((vm-engine-frame? (decorated-frame-frame gdb-frame))
  375. (let lp ((children (reverse
  376. (decorated-frame-children gdb-frame)))
  377. (vm-frames vm-frames))
  378. (define (finish reversed-children vm-frames)
  379. (let ((children (reverse reversed-children)))
  380. (recur (redecorate-frame gdb-frame #:children children)
  381. gdb-frames
  382. vm-frames)))
  383. (cond
  384. ((stream-null? vm-frames)
  385. (finish children vm-frames))
  386. (else
  387. (let* ((vm-frame (stream-car vm-frames))
  388. (vm-frames (stream-cdr vm-frames)))
  389. (if (value=? (vm-frame-ip vm-frame) boot-ptr)
  390. ;; Drop the boot frame and finish.
  391. (finish children vm-frames)
  392. (lp (cons (synthesize-frame gdb-frame vm-frame)
  393. children)
  394. vm-frames)))))))
  395. (else
  396. (recur gdb-frame gdb-frames vm-frames))))))))))
  397. (add-frame-filter!
  398. (make-decorating-frame-filter "guile-snarf-decorator"
  399. snarfy-frame-decorator
  400. #:objfile (current-objfile)))
  401. (add-frame-filter!
  402. (make-frame-filter "guile-vm-frame-filter"
  403. vm-frame-filter
  404. #:objfile (current-objfile))))
  405. (#t #f))
  406. ;;; libguile-2.2-gdb.scm ends here