debug.scm 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. ;;; Guile VM debugging facilities
  2. ;;; Copyright (C) 2001, 2009, 2010, 2011 Free Software Foundation, Inc.
  3. ;;;
  4. ;;; This library is free software; you can redistribute it and/or
  5. ;;; modify it under the terms of the GNU Lesser General Public
  6. ;;; License as published by the Free Software Foundation; either
  7. ;;; version 3 of the License, or (at your option) any later version.
  8. ;;;
  9. ;;; This library is distributed in the hope that it will be useful,
  10. ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;;; Lesser General Public License for more details.
  13. ;;;
  14. ;;; You should have received a copy of the GNU Lesser General Public
  15. ;;; License along with this library; if not, write to the Free Software
  16. ;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. ;;; Code:
  18. (define-module (system repl debug)
  19. #:use-module (system base pmatch)
  20. #:use-module (system base syntax)
  21. #:use-module (system base language)
  22. #:use-module (system vm vm)
  23. #:use-module (system vm frame)
  24. #:use-module (ice-9 rdelim)
  25. #:use-module (ice-9 pretty-print)
  26. #:use-module (ice-9 format)
  27. #:use-module ((system vm inspect) #:select ((inspect . %inspect)))
  28. #:use-module (system vm program)
  29. #:export (<debug>
  30. make-debug debug?
  31. debug-frames debug-index debug-error-message debug-for-trap?
  32. terminal-width
  33. print-registers print-locals print-frame print-frames frame->module
  34. stack->vector narrow-stack->vector
  35. frame->stack-vector))
  36. ;; TODO:
  37. ;;
  38. ;; eval expression in context of frame
  39. ;; set local variable in frame
  40. ;; step until greater source line
  41. ;; watch expression
  42. ;; set printing width
  43. ;; disassemble the current function
  44. ;; inspect any object
  45. ;;;
  46. ;;; Debugger
  47. ;;;
  48. ;;; The actual interaction loop of the debugger is run by the repl. This module
  49. ;;; simply exports a data structure to hold the debugger state, along with its
  50. ;;; accessors, and provides some helper functions.
  51. ;;;
  52. (define-record <debug> frames index error-message for-trap?)
  53. ;; A fluid, because terminals are usually implicitly associated with
  54. ;; threads.
  55. ;;
  56. (define terminal-width
  57. (let ((set-width (make-fluid)))
  58. (case-lambda
  59. (()
  60. (or (fluid-ref set-width)
  61. (let ((w (false-if-exception (string->number (getenv "COLUMNS")))))
  62. (and (integer? w) (exact? w) (> w 0) w))
  63. 72))
  64. ((w)
  65. (if (or (not w) (and (integer? w) (exact? w) (> w 0)))
  66. (fluid-set! set-width w)
  67. (error "Expected a column number (a positive integer)" w))))))
  68. (define (reverse-hashq h)
  69. (let ((ret (make-hash-table)))
  70. (hash-for-each
  71. (lambda (k v)
  72. (hashq-set! ret v (cons k (hashq-ref ret v '()))))
  73. h)
  74. ret))
  75. (define* (print-registers frame #:optional (port (current-output-port))
  76. #:key (per-line-prefix " "))
  77. (define (print fmt val)
  78. (display per-line-prefix port)
  79. (run-hook before-print-hook val)
  80. (format port fmt val))
  81. (format port "~aRegisters:~%" per-line-prefix)
  82. (print "ip = ~d\n" (frame-instruction-pointer frame))
  83. (print "sp = #x~x\n" (frame-stack-pointer frame))
  84. (print "fp = #x~x\n" (frame-address frame)))
  85. (define* (print-locals frame #:optional (port (current-output-port))
  86. #:key (width (terminal-width)) (per-line-prefix " "))
  87. (let ((bindings (frame-bindings frame)))
  88. (cond
  89. ((null? bindings)
  90. (format port "~aNo local variables.~%" per-line-prefix))
  91. (else
  92. (format port "~aLocal variables:~%" per-line-prefix)
  93. (for-each
  94. (lambda (binding)
  95. (let ((v (let ((x (frame-local-ref frame (binding:index binding))))
  96. (if (binding:boxed? binding)
  97. (variable-ref x)
  98. x))))
  99. (display per-line-prefix port)
  100. (run-hook before-print-hook v)
  101. (format port "~a~:[~; (boxed)~] = ~v:@y\n"
  102. (binding:name binding) (binding:boxed? binding) width v)))
  103. (frame-bindings frame))))))
  104. (define* (print-frame frame #:optional (port (current-output-port))
  105. #:key index (width (terminal-width)) (full? #f)
  106. (last-source #f) next-source?)
  107. (define (source:pretty-file source)
  108. (if source
  109. (or (source:file source) "current input")
  110. "unknown file"))
  111. (let* ((source ((if next-source? frame-next-source frame-source) frame))
  112. (file (source:pretty-file source))
  113. (line (and=> source source:line-for-user))
  114. (col (and=> source source:column)))
  115. (if (and file (not (equal? file (source:pretty-file last-source))))
  116. (format port "~&In ~a:~&" file))
  117. (format port "~9@a~:[~*~3_~;~3d~] ~v:@y~%"
  118. (if line (format #f "~a:~a" line col) "")
  119. index index width (frame-call-representation frame))
  120. (if full?
  121. (print-locals frame #:width width
  122. #:per-line-prefix " "))))
  123. (define* (print-frames frames
  124. #:optional (port (current-output-port))
  125. #:key (width (terminal-width)) (full? #f)
  126. (forward? #f) count for-trap?)
  127. (let* ((len (vector-length frames))
  128. (lower-idx (if (or (not count) (positive? count))
  129. 0
  130. (max 0 (+ len count))))
  131. (upper-idx (if (and count (negative? count))
  132. (1- len)
  133. (1- (if count (min count len) len))))
  134. (inc (if forward? 1 -1)))
  135. (let lp ((i (if forward? lower-idx upper-idx))
  136. (last-source #f))
  137. (if (<= lower-idx i upper-idx)
  138. (let* ((frame (vector-ref frames i)))
  139. (print-frame frame port #:index i #:width width #:full? full?
  140. #:last-source last-source
  141. #:next-source? (and (zero? i) for-trap?))
  142. (lp (+ i inc)
  143. (if (and (zero? i) for-trap?)
  144. (frame-next-source frame)
  145. (frame-source frame))))))))
  146. ;; Ideally here we would have something much more syntactic, in that a set! to a
  147. ;; local var that is not settable would raise an error, and export etc forms
  148. ;; would modify the module in question: but alack, this is what we have now.
  149. ;; Patches welcome!
  150. (define (frame->module frame)
  151. (let ((proc (frame-procedure frame)))
  152. (if (program? proc)
  153. (let* ((mod (or (program-module proc) (current-module)))
  154. (mod* (make-module)))
  155. (module-use! mod* mod)
  156. (for-each
  157. (lambda (binding)
  158. (let* ((x (frame-local-ref frame (binding:index binding)))
  159. (var (if (binding:boxed? binding) x (make-variable x))))
  160. (format #t
  161. "~:[Read-only~;Mutable~] local variable ~a = ~70:@y\n"
  162. (binding:boxed? binding)
  163. (binding:name binding)
  164. (if (variable-bound? var) (variable-ref var) var))
  165. (module-add! mod* (binding:name binding) var)))
  166. (frame-bindings frame))
  167. mod*)
  168. (current-module))))
  169. (define (stack->vector stack)
  170. (let* ((len (stack-length stack))
  171. (v (make-vector len)))
  172. (if (positive? len)
  173. (let lp ((i 0) (frame (stack-ref stack 0)))
  174. (if (< i len)
  175. (begin
  176. (vector-set! v i frame)
  177. (lp (1+ i) (frame-previous frame))))))
  178. v))
  179. (define (narrow-stack->vector stack . args)
  180. (let ((narrowed (apply make-stack (stack-ref stack 0) args)))
  181. (if narrowed
  182. (stack->vector narrowed)
  183. #()))) ; ? Can be the case for a tail-call to `throw' tho
  184. (define (frame->stack-vector frame)
  185. (let ((tag (and (pair? (fluid-ref %stacks))
  186. (cdar (fluid-ref %stacks)))))
  187. (narrow-stack->vector
  188. (make-stack frame)
  189. ;; Take the stack from the given frame, cutting 0
  190. ;; frames.
  191. 0
  192. ;; Narrow the end of the stack to the most recent
  193. ;; start-stack.
  194. tag
  195. ;; And one more frame, because %start-stack
  196. ;; invoking the start-stack thunk has its own frame
  197. ;; too.
  198. 0 (and tag 1))))
  199. ;; (define (debug)
  200. ;; (run-debugger
  201. ;; (narrow-stack->vector
  202. ;; (make-stack #t)
  203. ;; ;; Narrow the `make-stack' frame and the `debug' frame
  204. ;; 2
  205. ;; ;; Narrow the end of the stack to the most recent start-stack.
  206. ;; (and (pair? (fluid-ref %stacks))
  207. ;; (cdar (fluid-ref %stacks))))))