mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 03:40:34 +02:00
172 lines
6 KiB
Scheme
172 lines
6 KiB
Scheme
|
|
(define-module (ice-9 debugging ice-9-debugger-extensions)
|
|
#:use-module (ice-9 debugger))
|
|
|
|
;;; Upgrade the debugger state object so that it can carry a flag
|
|
;;; indicating whether the debugging session is continuable.
|
|
|
|
(cond ((string>=? (version) "1.7")
|
|
(use-modules (ice-9 debugger state))
|
|
(define-module (ice-9 debugger state)))
|
|
(else
|
|
(define-module (ice-9 debugger))))
|
|
|
|
(set! state-rtd (make-record-type "debugger-state" '(stack index flags)))
|
|
(set! state? (record-predicate state-rtd))
|
|
(set! make-state
|
|
(let ((make-state-internal (record-constructor state-rtd
|
|
'(stack index flags))))
|
|
(lambda (stack index . flags)
|
|
(make-state-internal stack index flags))))
|
|
(set! state-stack (record-accessor state-rtd 'stack))
|
|
(set! state-index (record-accessor state-rtd 'index))
|
|
|
|
(define state-flags (record-accessor state-rtd 'flags))
|
|
|
|
;;; Add commands that (ice-9 debugger) doesn't currently have, for
|
|
;;; continuing or single stepping program execution.
|
|
|
|
(cond ((string>=? (version) "1.7")
|
|
(use-modules (ice-9 debugger command-loop))
|
|
(define-module (ice-9 debugger command-loop)
|
|
#:use-module (ice-9 debugger)
|
|
#:use-module (ice-9 debugger state)
|
|
#:use-module (ice-9 debugging traps))
|
|
(define new-define-command define-command)
|
|
(set! define-command
|
|
(lambda (name argument-template documentation procedure)
|
|
(new-define-command name argument-template procedure))))
|
|
(else
|
|
(define-module (ice-9 debugger))))
|
|
|
|
(use-modules (ice-9 debugging steps))
|
|
|
|
(define (assert-continuable state)
|
|
;; Check that debugger is in a state where `continuing' makes sense.
|
|
;; If not, signal an error.
|
|
(or (memq #:continuable (state-flags state))
|
|
(user-error "This debug session is not continuable.")))
|
|
|
|
(define (debugger:continue state)
|
|
"Tell the program being debugged to continue running. (In fact this is
|
|
the same as the @code{quit} command, because it exits the debugger
|
|
command loop and so allows whatever code it was that invoked the
|
|
debugger to continue.)"
|
|
(assert-continuable state)
|
|
(throw 'exit-debugger))
|
|
|
|
(define (debugger:finish state)
|
|
"Continue until evaluation of the current frame is complete, and
|
|
print the result obtained."
|
|
(assert-continuable state)
|
|
(at-exit (- (stack-length (state-stack state))
|
|
(state-index state))
|
|
(list trace-trap debug-trap))
|
|
(debugger:continue state))
|
|
|
|
(define (debugger:step state n)
|
|
"Tell the debugged program to do @var{n} more steps from its current
|
|
position. One @dfn{step} means executing until the next frame entry
|
|
or exit of any kind. @var{n} defaults to 1."
|
|
(assert-continuable state)
|
|
(at-step debug-trap (or n 1))
|
|
(debugger:continue state))
|
|
|
|
(define (debugger:next state n)
|
|
"Tell the debugged program to do @var{n} more steps from its current
|
|
position, but only counting frame entries and exits where the
|
|
corresponding source code comes from the same file as the current
|
|
stack frame. (See @ref{Step Traps} for the details of how this
|
|
works.) If the current stack frame has no source code, the effect of
|
|
this command is the same as of @code{step}. @var{n} defaults to 1."
|
|
(assert-continuable state)
|
|
(at-step debug-trap
|
|
(or n 1)
|
|
(frame-file-name (stack-ref (state-stack state)
|
|
(state-index state)))
|
|
(if (memq #:return (state-flags state))
|
|
#f
|
|
(- (stack-length (state-stack state)) (state-index state))))
|
|
(debugger:continue state))
|
|
|
|
(define-command "continue" '()
|
|
"Continue program execution."
|
|
debugger:continue)
|
|
|
|
(define-command "finish" '()
|
|
"Continue until evaluation of the current frame is complete, and
|
|
print the result obtained."
|
|
debugger:finish)
|
|
|
|
(define-command "step" '('optional exact-integer)
|
|
"Continue until entry to @var{n}th next frame."
|
|
debugger:step)
|
|
|
|
(define-command "next" '('optional exact-integer)
|
|
"Continue until entry to @var{n}th next frame in same file."
|
|
debugger:next)
|
|
|
|
;;; Export a couple of procedures for use by (ice-9 debugging trace).
|
|
|
|
(cond ((string>=? (version) "1.7"))
|
|
(else
|
|
(define-module (ice-9 debugger))
|
|
(export write-frame-short/expression
|
|
write-frame-short/application)))
|
|
|
|
;;; Provide a `debug-trap' entry point in (ice-9 debugger). This is
|
|
;;; designed so that it can be called to explore the stack at a
|
|
;;; breakpoint, and to single step from the breakpoint.
|
|
|
|
(define-module (ice-9 debugger))
|
|
|
|
(use-modules (ice-9 debugging traps))
|
|
|
|
(define *not-yet-introduced* #t)
|
|
|
|
(cond ((string>=? (version) "1.7"))
|
|
(else
|
|
(define (debugger-command-loop state)
|
|
(read-and-dispatch-commands state (current-input-port)))))
|
|
|
|
(define-public (debug-trap trap-context)
|
|
"Invoke the Guile debugger to explore the stack at the specified @var{trap}."
|
|
(start-stack 'debugger
|
|
(let* ((stack (tc:stack trap-context))
|
|
(flags1 (let ((trap-type (tc:type trap-context)))
|
|
(case trap-type
|
|
((#:return #:error)
|
|
(list trap-type
|
|
(tc:return-value trap-context)))
|
|
(else
|
|
(list trap-type)))))
|
|
(flags (if (tc:continuation trap-context)
|
|
(cons #:continuable flags1)
|
|
flags1))
|
|
(state (apply make-state stack 0 flags)))
|
|
(if *not-yet-introduced*
|
|
(let ((ssize (stack-length stack)))
|
|
(display "This is the Guile debugger -- for help, type `help'.\n")
|
|
(set! *not-yet-introduced* #f)
|
|
(if (= ssize 1)
|
|
(display "There is 1 frame on the stack.\n\n")
|
|
(format #t "There are ~A frames on the stack.\n\n" ssize))))
|
|
(write-state-short-with-source-location state)
|
|
(debugger-command-loop state))))
|
|
|
|
(define write-state-short-with-source-location
|
|
(cond ((string>=? (version) "1.7")
|
|
write-state-short)
|
|
(else
|
|
(lambda (state)
|
|
(let* ((frame (stack-ref (state-stack state) (state-index state)))
|
|
(source (frame-source frame))
|
|
(position (and source (source-position source))))
|
|
(format #t "Frame ~A at " (frame-number frame))
|
|
(if position
|
|
(display-position position)
|
|
(display "unknown source location"))
|
|
(newline)
|
|
(write-char #\tab)
|
|
(write-frame-short frame)
|
|
(newline))))))
|