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