mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-16 00:30:21 +02:00
narrowing stacks to prompts; backtrace shows frames from start-stack
* libguile/stacks.c (scm_sys_stacks): New global variable, moved here from boot-9.scm. (scm_init_stacks): Define scm_sys_stacks to %stacks. (stack_depth): Remove narrowing by frame pointer. (find_prompt): New helper. (narrow_stack): Clean up a bit, and allow narrowing by prompt tag. (scm_make_stack): Update docs, and use scm_stack_id to get the stack id. (scm_stack_id): The current stack id may be fetched as the cdar of %stacks. (stack_id_with_fp): Remove helper. * module/ice-9/boot-9.scm (%start-stack): Fix indentation. (%stacks): Remove definition, it's in stacks.c now. (default-pre-unwind-handler): Narrow by another frame. (save-stack): Remove special handling for certain stack ids, as it is often possible that the function isn't on the stack -- in the interpreter, or after a tail call. Better to narrow by prompt ids. * module/system/vm/debug.scm (print-frames): Change to operate on a vector of frames. (run-debugger): Change to receive a vector of frames. The debugger also has the full stack, so it can re-narrow (or widen) to get the whole stack, if the user wants. (stack->vector): New helper. (debug-pre-unwind-handler): Narrow by more frames, and to the most recent start-stack invocation. Adapt to run-debugger change.
This commit is contained in:
parent
01c0082fae
commit
06dcb9dfb6
3 changed files with 227 additions and 173 deletions
|
@ -1030,7 +1030,7 @@ If there is no handler at all, Guile prints an error and then exits."
|
|||
;;; {The interpreter stack}
|
||||
;;;
|
||||
|
||||
(define %stacks (make-fluid))
|
||||
;; %stacks defined in stacks.c
|
||||
(define (%start-stack tag thunk)
|
||||
(let ((prompt-tag (make-prompt-tag "start-stack")))
|
||||
(call-with-prompt
|
||||
|
@ -2742,7 +2742,8 @@ module '(ice-9 q) '(make-q q-length))}."
|
|||
(define (set-repl-prompt! v) (set! scm-repl-prompt v))
|
||||
|
||||
(define (default-pre-unwind-handler key . args)
|
||||
(save-stack 1)
|
||||
;; Narrow by two more frames: this one, and the throw handler.
|
||||
(save-stack 2)
|
||||
(apply throw key args))
|
||||
|
||||
(begin-deprecated
|
||||
|
@ -2839,28 +2840,25 @@ module '(ice-9 q) '(make-q q-length))}."
|
|||
|
||||
;;(define the-last-stack (make-fluid)) Defined by scm_init_backtrace ()
|
||||
(define before-signal-stack (make-fluid))
|
||||
;; FIXME: stack-saved? is broken in the presence of threads.
|
||||
(define stack-saved? #f)
|
||||
|
||||
(define (save-stack . narrowing)
|
||||
(or stack-saved?
|
||||
(cond ((not (memq 'debug (debug-options-interface)))
|
||||
(fluid-set! the-last-stack #f)
|
||||
(set! stack-saved? #t))
|
||||
(else
|
||||
(fluid-set!
|
||||
the-last-stack
|
||||
(case (stack-id #t)
|
||||
((repl-stack)
|
||||
(apply make-stack #t save-stack primitive-eval #t 0 narrowing))
|
||||
((load-stack)
|
||||
(apply make-stack #t save-stack 0 #t 0 narrowing))
|
||||
((#t)
|
||||
(apply make-stack #t save-stack 0 1 narrowing))
|
||||
(else
|
||||
(let ((id (stack-id #t)))
|
||||
(and (procedure? id)
|
||||
(apply make-stack #t save-stack id #t 0 narrowing))))))
|
||||
(set! stack-saved? #t)))))
|
||||
(if (not stack-saved?)
|
||||
(begin
|
||||
(let ((stacks (fluid-ref %stacks)))
|
||||
(fluid-set! the-last-stack
|
||||
;; (make-stack obj inner outer inner outer ...)
|
||||
;;
|
||||
;; In this case, cut away the make-stack frame, the
|
||||
;; save-stack frame, and then narrow as specified by the
|
||||
;; user, delimited by the nearest start-stack invocation,
|
||||
;; if any.
|
||||
(apply make-stack #t
|
||||
2
|
||||
(if (pair? stacks) (cdar stacks) 0)
|
||||
narrowing)))
|
||||
(set! stack-saved? #t))))
|
||||
|
||||
(define before-error-hook (make-hook))
|
||||
(define after-error-hook (make-hook))
|
||||
|
|
|
@ -96,40 +96,34 @@
|
|||
x))))
|
||||
(frame-bindings frame))))))
|
||||
|
||||
(define* (collect-frames frame #:key count)
|
||||
(cond
|
||||
((not count)
|
||||
(let lp ((frame frame) (out '()))
|
||||
(if (not frame)
|
||||
out
|
||||
(lp (frame-previous frame) (cons frame out)))))
|
||||
;; should also have a from-end option, either via negative count or
|
||||
;; another kwarg
|
||||
((>= count 0)
|
||||
(let lp ((frame frame) (out '()) (count count))
|
||||
(if (or (not frame) (zero? count))
|
||||
out
|
||||
(lp (frame-previous frame) (cons frame out) (1- count)))))))
|
||||
|
||||
(define* (print-frames frames #:optional (port (current-output-port))
|
||||
#:key (start-index (1- (length frames))) (width 72)
|
||||
(full? #f))
|
||||
(let lp ((frames frames) (i start-index) (last-file ""))
|
||||
(if (pair? frames)
|
||||
(let* ((frame (car frames))
|
||||
(source (frame-source frame))
|
||||
(file (and source
|
||||
(or (source:file source)
|
||||
"current input")))
|
||||
(line (and=> source source:line)))
|
||||
(if (and file (not (equal? file last-file)))
|
||||
(format port "~&In ~a:~&" file))
|
||||
(format port "~:[~*~6_~;~5d:~]~3d ~v:@y~%" line line
|
||||
i width (frame-call-representation frame))
|
||||
(if full?
|
||||
(print-locals frame #:width width
|
||||
#:per-line-prefix " "))
|
||||
(lp (cdr frames) (1- i) (or file last-file))))))
|
||||
(define* (print-frames frames
|
||||
#:optional (port (current-output-port))
|
||||
#:key (width 72) (full? #f) (forward? #f) count)
|
||||
(let* ((len (vector-length frames))
|
||||
(lower-idx (if (or (not count) (positive? count))
|
||||
0
|
||||
(max 0 (+ len count))))
|
||||
(upper-idx (if (and count (negative? count))
|
||||
(1- len)
|
||||
(1- (if count (min count len) len))))
|
||||
(inc (if forward? 1 -1)))
|
||||
(let lp ((i (if forward? lower-idx upper-idx))
|
||||
(last-file ""))
|
||||
(if (<= lower-idx i upper-idx)
|
||||
(let* ((frame (vector-ref frames i))
|
||||
(source (frame-source frame))
|
||||
(file (and source
|
||||
(or (source:file source)
|
||||
"current input")))
|
||||
(line (and=> source source:line)))
|
||||
(if (and file (not (equal? file last-file)))
|
||||
(format port "~&In ~a:~&" file))
|
||||
(format port "~:[~*~6_~;~5d:~]~3d ~v:@y~%" line line
|
||||
i width (frame-call-representation frame))
|
||||
(if full?
|
||||
(print-locals frame #:width width
|
||||
#:per-line-prefix " "))
|
||||
(lp (+ i inc) (or file last-file)))))))
|
||||
|
||||
|
||||
;;;
|
||||
|
@ -150,31 +144,22 @@
|
|||
(set! (prop vm) debugger)
|
||||
debugger)))))
|
||||
|
||||
(define* (run-debugger frame #:optional (vm (the-vm)))
|
||||
(define* (run-debugger stack frames i #:optional (vm (the-vm)))
|
||||
(let* ((db (vm-debugger vm))
|
||||
(level (debugger-level db)))
|
||||
(dynamic-wind
|
||||
(lambda () (set! (debugger-level db) (1+ level)))
|
||||
(lambda () (debugger-repl db frame))
|
||||
(lambda () (debugger-repl db stack frames i))
|
||||
(lambda () (set! (debugger-level db) level)))))
|
||||
|
||||
(define (debugger-repl db frame)
|
||||
(let ((top frame)
|
||||
(cur frame)
|
||||
(index 0)
|
||||
(define (debugger-repl db stack frames index)
|
||||
(let ((top (vector-ref frames 0))
|
||||
(cur (vector-ref frames index))
|
||||
(level (debugger-level db))
|
||||
(last #f))
|
||||
(define (frame-index frame)
|
||||
(let lp ((idx 0) (walk top))
|
||||
(if (= (frame-return-address frame) (frame-return-address walk))
|
||||
idx
|
||||
(lp (1+ idx) (frame-previous walk)))))
|
||||
(define (frame-at-index idx)
|
||||
(let lp ((idx idx) (walk top))
|
||||
(cond
|
||||
((not walk) #f)
|
||||
((zero? idx) walk)
|
||||
(else (lp (1- idx) (frame-previous walk))))))
|
||||
(and (< idx (vector-length frames))
|
||||
(vector-ref frames idx)))
|
||||
(define (show-frame)
|
||||
;; #2 0x009600e0 in do_std_select (args=0xbfffd9e0) at threads.c:1668
|
||||
;; 1668 select (select_args->nfds,
|
||||
|
@ -214,44 +199,51 @@
|
|||
|
||||
(define-command ((commands backtrace bt) #:optional count
|
||||
#:key (width 72) full?)
|
||||
"Print a backtrace of all stack frames, or innermost COUNT frames."
|
||||
(print-frames (collect-frames top #:count count)
|
||||
"Print a backtrace of all stack frames, or innermost COUNT frames.
|
||||
If COUNT is negative, the last COUNT frames will be shown."
|
||||
(print-frames frames
|
||||
#:count count
|
||||
#:width width
|
||||
#:full? full?))
|
||||
|
||||
(define-command ((commands up) #:optional (count 1))
|
||||
"Select and print stack frames that called this one.
|
||||
An argument says how many frames up to go"
|
||||
(if (or (not (integer? count)) (<= count 0))
|
||||
(format #t "Invalid argument to `up': expected a positive integer for COUNT.~%")
|
||||
(let lp ((n count))
|
||||
(cond
|
||||
((zero? n) (show-frame))
|
||||
((frame-previous cur)
|
||||
=> (lambda (new)
|
||||
(set! cur new)
|
||||
(set! index (1+ index))
|
||||
(lp (1- n))))
|
||||
((= n count)
|
||||
(format #t "Already at outermost frame.\n"))
|
||||
(else
|
||||
(format #t "Reached outermost frame after walking ~a frames.\n"
|
||||
(- count n))
|
||||
(show-frame))))))
|
||||
|
||||
(cond
|
||||
((or (not (integer? count)) (<= count 0))
|
||||
(format #t "Invalid argument to `up': expected a positive integer for COUNT.~%"))
|
||||
((>= (+ count index) (vector-length frames))
|
||||
(cond
|
||||
((= index (1- (vector-length frames)))
|
||||
(format #t "Already at outermost frame.\n"))
|
||||
(else
|
||||
(set! index (1- (vector-length frames)))
|
||||
(set! cur (vector-ref frames index))
|
||||
(show-frame))))
|
||||
(else
|
||||
(set! index (+ count index))
|
||||
(set! cur (vector-ref frames index))
|
||||
(show-frame))))
|
||||
|
||||
(define-command ((commands down) #:optional (count 1))
|
||||
"Select and print stack frames called by this one.
|
||||
An argument says how many frames down to go"
|
||||
(cond
|
||||
((or (not (integer? count)) (<= count 0))
|
||||
(format #t "Invalid argument to `down': expected a positive integer for COUNT.~%"))
|
||||
((= index 0)
|
||||
(format #t "Already at innermost frame.~%"))
|
||||
((< (- index count) 0)
|
||||
(cond
|
||||
((zero? index)
|
||||
(format #t "Already at innermost frame.\n"))
|
||||
(else
|
||||
(set! index 0)
|
||||
(set! cur (vector-ref frames index))
|
||||
(show-frame))))
|
||||
(else
|
||||
(set! index (max (- index count) 0))
|
||||
(set! cur (frame-at-index index))
|
||||
(set! index (- index count))
|
||||
(set! cur (vector-ref frames index))
|
||||
(show-frame))))
|
||||
|
||||
|
||||
(define-command ((commands frame f) #:optional idx)
|
||||
"Show the selected frame.
|
||||
With an argument, select a frame by index, then show it."
|
||||
|
@ -377,15 +369,36 @@ With an argument, select a frame by index, then show it."
|
|||
;; hm, trace via reassigning global vars. tricksy.
|
||||
;; (state associated with vm ?)
|
||||
|
||||
(define (stack->vector stack)
|
||||
(let* ((len (stack-length stack))
|
||||
(v (make-vector len)))
|
||||
(if (positive? len)
|
||||
(let lp ((i 0) (frame (stack-ref stack 0)))
|
||||
(if (< i len)
|
||||
(begin
|
||||
(vector-set! v i frame)
|
||||
(lp (1+ i) (frame-previous frame))))))
|
||||
v))
|
||||
|
||||
(define (debug-pre-unwind-handler key . args)
|
||||
(let ((stack (make-stack #t 2)))
|
||||
(pmatch args
|
||||
((,subr ,msg ,args . ,rest)
|
||||
(format #t "Throw to key `~a':\n" key)
|
||||
(display-error stack (current-output-port) subr msg args rest))
|
||||
(else
|
||||
(format #t "Throw to key `~a' with args `~s'." key args)))
|
||||
(format #t "Entering the debugger. Type `bt' for a backtrace or `c' to continue.\n")
|
||||
(run-debugger (stack-ref stack 0)))
|
||||
;; Narrow the stack by three frames: make-stack, this one, and the throw
|
||||
;; handler.
|
||||
(cond
|
||||
((make-stack #t 3) =>
|
||||
(lambda (stack)
|
||||
(pmatch args
|
||||
((,subr ,msg ,args . ,rest)
|
||||
(format #t "Throw to key `~a':\n" key)
|
||||
(display-error stack (current-output-port) subr msg args rest))
|
||||
(else
|
||||
(format #t "Throw to key `~a' with args `~s'." key args)))
|
||||
(format #t "Entering the debugger. Type `bt' for a backtrace or `c' to continue.\n")
|
||||
(run-debugger stack
|
||||
(stack->vector
|
||||
;; by default, narrow to the most recent start-stack
|
||||
(make-stack (stack-ref stack 0) 0
|
||||
(and (pair? (fluid-ref %stacks))
|
||||
(cdar (fluid-ref %stacks)))))
|
||||
0))))
|
||||
(save-stack debug-pre-unwind-handler)
|
||||
(apply throw key args))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue