mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 03:40:34 +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
|
@ -24,6 +24,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "libguile/_scm.h"
|
#include "libguile/_scm.h"
|
||||||
|
#include "libguile/control.h"
|
||||||
#include "libguile/eval.h"
|
#include "libguile/eval.h"
|
||||||
#include "libguile/debug.h"
|
#include "libguile/debug.h"
|
||||||
#include "libguile/continuations.h"
|
#include "libguile/continuations.h"
|
||||||
|
@ -41,6 +42,8 @@
|
||||||
#include "libguile/private-options.h"
|
#include "libguile/private-options.h"
|
||||||
|
|
||||||
|
|
||||||
|
static SCM scm_sys_stacks;
|
||||||
|
|
||||||
|
|
||||||
/* {Stacks}
|
/* {Stacks}
|
||||||
*
|
*
|
||||||
|
@ -59,17 +62,14 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static SCM stack_id_with_fp (SCM frame, SCM **fp);
|
|
||||||
|
|
||||||
/* Count number of debug info frames on a stack, beginning with FRAME.
|
/* Count number of debug info frames on a stack, beginning with FRAME.
|
||||||
*/
|
*/
|
||||||
static long
|
static long
|
||||||
stack_depth (SCM frame, SCM *fp)
|
stack_depth (SCM frame)
|
||||||
{
|
{
|
||||||
long n = 0;
|
long n = 0;
|
||||||
/* count frames, skipping boot frames */
|
/* count frames, skipping boot frames */
|
||||||
for (; scm_is_true (frame) && SCM_VM_FRAME_FP (frame) > fp;
|
for (; scm_is_true (frame); frame = scm_frame_previous (frame))
|
||||||
frame = scm_frame_previous (frame))
|
|
||||||
++n;
|
++n;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,21 @@ stack_depth (SCM frame, SCM *fp)
|
||||||
* encountered.
|
* encountered.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static SCM
|
||||||
|
find_prompt (SCM key)
|
||||||
|
{
|
||||||
|
SCM winds;
|
||||||
|
for (winds = scm_i_dynwinds (); scm_is_pair (winds); winds = scm_cdr (winds))
|
||||||
|
{
|
||||||
|
SCM elt = scm_car (winds);
|
||||||
|
if (SCM_PROMPT_P (elt) && SCM_PROMPT_TAG (elt) == key)
|
||||||
|
return elt;
|
||||||
|
}
|
||||||
|
scm_misc_error ("make-stack", "Prompt tag not found while narrowing stack",
|
||||||
|
scm_list_1 (key));
|
||||||
|
return SCM_BOOL_F; /* not reached */
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
narrow_stack (SCM stack, long inner, SCM inner_key, long outer, SCM outer_key)
|
narrow_stack (SCM stack, long inner, SCM inner_key, long outer, SCM outer_key)
|
||||||
{
|
{
|
||||||
|
@ -105,16 +120,7 @@ narrow_stack (SCM stack, long inner, SCM inner_key, long outer, SCM outer_key)
|
||||||
frame = SCM_STACK_FRAME (stack);
|
frame = SCM_STACK_FRAME (stack);
|
||||||
|
|
||||||
/* Cut inner part. */
|
/* Cut inner part. */
|
||||||
if (scm_is_eq (inner_key, SCM_BOOL_T))
|
if (scm_is_true (scm_procedure_p (inner_key)))
|
||||||
{
|
|
||||||
/* Cut specified number of frames. */
|
|
||||||
for (; inner && len; --inner)
|
|
||||||
{
|
|
||||||
len--;
|
|
||||||
frame = scm_frame_previous (frame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
/* Cut until the given procedure is seen. */
|
/* Cut until the given procedure is seen. */
|
||||||
for (; inner && len ; --inner)
|
for (; inner && len ; --inner)
|
||||||
|
@ -126,11 +132,33 @@ narrow_stack (SCM stack, long inner, SCM inner_key, long outer, SCM outer_key)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (scm_is_symbol (inner_key))
|
||||||
|
{
|
||||||
|
/* Cut until the given prompt tag is seen. FIXME, assumes prompt tags are
|
||||||
|
symbols. */
|
||||||
|
SCM prompt = find_prompt (inner_key);
|
||||||
|
for (; len; len--, frame = scm_frame_previous (frame))
|
||||||
|
if (SCM_PROMPT_REGISTERS (prompt)->fp
|
||||||
|
== SCM_VM_FRAME_FP (frame) - SCM_VM_FRAME_OFFSET (frame))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Cut specified number of frames. */
|
||||||
|
for (; inner && len; --inner)
|
||||||
|
{
|
||||||
|
len--;
|
||||||
|
frame = scm_frame_previous (frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SCM_SET_STACK_LENGTH (stack, len);
|
SCM_SET_STACK_LENGTH (stack, len);
|
||||||
SCM_SET_STACK_FRAME (stack, frame);
|
SCM_SET_STACK_FRAME (stack, frame);
|
||||||
|
|
||||||
/* Cut outer part. */
|
/* Cut outer part. */
|
||||||
|
if (scm_is_true (scm_procedure_p (outer_key)))
|
||||||
|
{
|
||||||
|
/* Cut until the given procedure is seen. */
|
||||||
for (; outer && len ; --outer)
|
for (; outer && len ; --outer)
|
||||||
{
|
{
|
||||||
frame = scm_stack_ref (stack, scm_from_long (len - 1));
|
frame = scm_stack_ref (stack, scm_from_long (len - 1));
|
||||||
|
@ -138,6 +166,30 @@ narrow_stack (SCM stack, long inner, SCM inner_key, long outer, SCM outer_key)
|
||||||
if (scm_is_eq (scm_frame_procedure (frame), outer_key))
|
if (scm_is_eq (scm_frame_procedure (frame), outer_key))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if (scm_is_symbol (outer_key))
|
||||||
|
{
|
||||||
|
/* Cut until the given prompt tag is seen. FIXME, assumes prompt tags are
|
||||||
|
symbols. */
|
||||||
|
SCM prompt = find_prompt (outer_key);
|
||||||
|
while (len)
|
||||||
|
{
|
||||||
|
frame = scm_stack_ref (stack, scm_from_long (len - 1));
|
||||||
|
len--;
|
||||||
|
if (SCM_PROMPT_REGISTERS (prompt)->fp
|
||||||
|
== SCM_VM_FRAME_FP (frame) - SCM_VM_FRAME_OFFSET (frame))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Cut specified number of frames. */
|
||||||
|
for (; outer && len ; --outer)
|
||||||
|
{
|
||||||
|
frame = scm_stack_ref (stack, scm_from_long (len - 1));
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SCM_SET_STACK_LENGTH (stack, len);
|
SCM_SET_STACK_LENGTH (stack, len);
|
||||||
}
|
}
|
||||||
|
@ -163,24 +215,33 @@ SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1,
|
||||||
"Create a new stack. If @var{obj} is @code{#t}, the current\n"
|
"Create a new stack. If @var{obj} is @code{#t}, the current\n"
|
||||||
"evaluation stack is used for creating the stack frames,\n"
|
"evaluation stack is used for creating the stack frames,\n"
|
||||||
"otherwise the frames are taken from @var{obj} (which must be\n"
|
"otherwise the frames are taken from @var{obj} (which must be\n"
|
||||||
"either a debug object or a continuation).\n\n"
|
"a continuation or a frame object).\n"
|
||||||
|
"\n"
|
||||||
"@var{args} should be a list containing any combination of\n"
|
"@var{args} should be a list containing any combination of\n"
|
||||||
"integer, procedure and @code{#t} values.\n\n"
|
"integer, procedure, prompt tag and @code{#t} values.\n"
|
||||||
|
"\n"
|
||||||
"These values specify various ways of cutting away uninteresting\n"
|
"These values specify various ways of cutting away uninteresting\n"
|
||||||
"stack frames from the top and bottom of the stack that\n"
|
"stack frames from the top and bottom of the stack that\n"
|
||||||
"@code{make-stack} returns. They come in pairs like this:\n"
|
"@code{make-stack} returns. They come in pairs like this:\n"
|
||||||
"@code{(@var{inner_cut_1} @var{outer_cut_1} @var{inner_cut_2}\n"
|
"@code{(@var{inner_cut_1} @var{outer_cut_1} @var{inner_cut_2}\n"
|
||||||
"@var{outer_cut_2} @dots{})}.\n\n"
|
"@var{outer_cut_2} @dots{})}.\n"
|
||||||
"Each @var{inner_cut_N} can be @code{#t}, an integer, or a\n"
|
"\n"
|
||||||
"procedure. @code{#t} means to cut away all frames up to but\n"
|
"Each @var{inner_cut_N} can be @code{#t}, an integer, a prompt\n"
|
||||||
"excluding the first user module frame. An integer means to cut\n"
|
"tag, or a procedure. @code{#t} means to cut away all frames up\n"
|
||||||
"away exactly that number of frames. A procedure means to cut\n"
|
"to but excluding the first user module frame. An integer means\n"
|
||||||
"away all frames up to but excluding the application frame whose\n"
|
"to cut away exactly that number of frames. A prompt tag means\n"
|
||||||
"procedure matches the specified one.\n\n"
|
"to cut away all frames that are inside a prompt with the given\n"
|
||||||
"Each @var{outer_cut_N} can be an integer or a procedure. An\n"
|
"tag. A procedure means to cut away all frames up to but\n"
|
||||||
"integer means to cut away that number of frames. A procedure\n"
|
"excluding the application frame whose procedure matches the\n"
|
||||||
"means to cut away frames down to but excluding the application\n"
|
"specified one.\n"
|
||||||
"frame whose procedure matches the specified one.\n\n"
|
"\n"
|
||||||
|
"Each @var{outer_cut_N} can be an integer, a prompt tag, or a\n"
|
||||||
|
"procedure. An integer means to cut away that number of frames.\n"
|
||||||
|
"A prompt tag means to cut away all frames that are outside a\n"
|
||||||
|
"prompt with the given tag. A procedure means to cut away\n"
|
||||||
|
"frames down to but excluding the application frame whose\n"
|
||||||
|
"procedure matches the specified one.\n"
|
||||||
|
"\n"
|
||||||
"If the @var{outer_cut_N} of the last pair is missing, it is\n"
|
"If the @var{outer_cut_N} of the last pair is missing, it is\n"
|
||||||
"taken as 0.")
|
"taken as 0.")
|
||||||
#define FUNC_NAME s_scm_make_stack
|
#define FUNC_NAME s_scm_make_stack
|
||||||
|
@ -189,7 +250,6 @@ SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1,
|
||||||
int maxp;
|
int maxp;
|
||||||
SCM frame;
|
SCM frame;
|
||||||
SCM stack;
|
SCM stack;
|
||||||
SCM id, *id_fp;
|
|
||||||
SCM inner_cut, outer_cut;
|
SCM inner_cut, outer_cut;
|
||||||
|
|
||||||
/* Extract a pointer to the innermost frame of whatever object
|
/* Extract a pointer to the innermost frame of whatever object
|
||||||
|
@ -209,6 +269,8 @@ SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1,
|
||||||
else if (SCM_VM_FRAME_P (obj))
|
else if (SCM_VM_FRAME_P (obj))
|
||||||
frame = obj;
|
frame = obj;
|
||||||
else if (SCM_CONTINUATIONP (obj))
|
else if (SCM_CONTINUATIONP (obj))
|
||||||
|
/* FIXME: Narrowing to prompt tags should narrow with respect to the prompts
|
||||||
|
that were in place when the continuation was captured. */
|
||||||
frame = scm_i_continuation_to_frame (obj);
|
frame = scm_i_continuation_to_frame (obj);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -224,20 +286,16 @@ SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1,
|
||||||
if (scm_is_false (frame))
|
if (scm_is_false (frame))
|
||||||
return SCM_BOOL_F;
|
return SCM_BOOL_F;
|
||||||
|
|
||||||
/* Get ID of the stack corresponding to the given frame. */
|
|
||||||
id = stack_id_with_fp (frame, &id_fp);
|
|
||||||
|
|
||||||
/* Count number of frames. Also get stack id tag and check whether
|
/* Count number of frames. Also get stack id tag and check whether
|
||||||
there are more stackframes than we want to record
|
there are more stackframes than we want to record
|
||||||
(SCM_BACKTRACE_MAXDEPTH). */
|
(SCM_BACKTRACE_MAXDEPTH). */
|
||||||
id = SCM_BOOL_F;
|
|
||||||
maxp = 0;
|
maxp = 0;
|
||||||
n = stack_depth (frame, id_fp);
|
n = stack_depth (frame);
|
||||||
|
|
||||||
/* Make the stack object. */
|
/* Make the stack object. */
|
||||||
stack = scm_make_struct (scm_stack_type, SCM_INUM0, SCM_EOL);
|
stack = scm_make_struct (scm_stack_type, SCM_INUM0, SCM_EOL);
|
||||||
SCM_SET_STACK_LENGTH (stack, n);
|
SCM_SET_STACK_LENGTH (stack, n);
|
||||||
SCM_SET_STACK_ID (stack, id);
|
SCM_SET_STACK_ID (stack, scm_stack_id (obj));
|
||||||
SCM_SET_STACK_FRAME (stack, frame);
|
SCM_SET_STACK_FRAME (stack, frame);
|
||||||
|
|
||||||
/* Narrow the stack according to the arguments given to scm_make_stack. */
|
/* Narrow the stack according to the arguments given to scm_make_stack. */
|
||||||
|
@ -258,9 +316,9 @@ SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1,
|
||||||
|
|
||||||
narrow_stack (stack,
|
narrow_stack (stack,
|
||||||
scm_is_integer (inner_cut) ? scm_to_int (inner_cut) : n,
|
scm_is_integer (inner_cut) ? scm_to_int (inner_cut) : n,
|
||||||
scm_is_integer (inner_cut) ? 0 : inner_cut,
|
scm_is_integer (inner_cut) ? SCM_BOOL_T : inner_cut,
|
||||||
scm_is_integer (outer_cut) ? scm_to_int (outer_cut) : n,
|
scm_is_integer (outer_cut) ? scm_to_int (outer_cut) : n,
|
||||||
scm_is_integer (outer_cut) ? 0 : outer_cut);
|
scm_is_integer (outer_cut) ? SCM_BOOL_T : outer_cut);
|
||||||
|
|
||||||
n = SCM_STACK_LENGTH (stack);
|
n = SCM_STACK_LENGTH (stack);
|
||||||
}
|
}
|
||||||
|
@ -277,44 +335,26 @@ SCM_DEFINE (scm_stack_id, "stack-id", 1, 0, 0,
|
||||||
"Return the identifier given to @var{stack} by @code{start-stack}.")
|
"Return the identifier given to @var{stack} by @code{start-stack}.")
|
||||||
#define FUNC_NAME s_scm_stack_id
|
#define FUNC_NAME s_scm_stack_id
|
||||||
{
|
{
|
||||||
SCM frame, *id_fp;
|
if (scm_is_eq (stack, SCM_BOOL_T)
|
||||||
|
/* FIXME: frame case assumes frame still live on the stack, and no
|
||||||
if (scm_is_eq (stack, SCM_BOOL_T))
|
intervening start-stack. Hmm... */
|
||||||
|
|| SCM_VM_FRAME_P (stack))
|
||||||
{
|
{
|
||||||
struct scm_vm *vp = SCM_VM_DATA (scm_the_vm ());
|
/* Fetch most recent start-stack tag. */
|
||||||
frame = scm_c_make_frame (scm_the_vm (), vp->fp, vp->sp, vp->ip, 0);
|
SCM stacks = scm_fluid_ref (scm_sys_stacks);
|
||||||
|
return scm_is_pair (stacks) ? scm_caar (stacks) : SCM_BOOL_F;
|
||||||
}
|
}
|
||||||
else if (SCM_VM_FRAME_P (stack))
|
|
||||||
frame = stack;
|
|
||||||
else if (SCM_CONTINUATIONP (stack))
|
else if (SCM_CONTINUATIONP (stack))
|
||||||
frame = scm_i_continuation_to_frame (stack);
|
/* FIXME: implement me */
|
||||||
|
return SCM_BOOL_F;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SCM_WRONG_TYPE_ARG (SCM_ARG1, stack);
|
SCM_WRONG_TYPE_ARG (SCM_ARG1, stack);
|
||||||
/* not reached */
|
/* not reached */
|
||||||
}
|
}
|
||||||
|
|
||||||
return stack_id_with_fp (frame, &id_fp);
|
|
||||||
}
|
}
|
||||||
#undef FUNC_NAME
|
#undef FUNC_NAME
|
||||||
|
|
||||||
static SCM
|
|
||||||
stack_id_with_fp (SCM frame, SCM **fp)
|
|
||||||
{
|
|
||||||
SCM holder = SCM_VM_FRAME_STACK_HOLDER (frame);
|
|
||||||
|
|
||||||
if (SCM_VM_CONT_P (holder))
|
|
||||||
{
|
|
||||||
*fp = NULL;
|
|
||||||
return SCM_BOOL_F;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*fp = NULL;
|
|
||||||
return SCM_BOOL_F;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SCM_DEFINE (scm_stack_ref, "stack-ref", 2, 0, 0,
|
SCM_DEFINE (scm_stack_ref, "stack-ref", 2, 0, 0,
|
||||||
(SCM stack, SCM index),
|
(SCM stack, SCM index),
|
||||||
"Return the @var{index}'th frame from @var{stack}.")
|
"Return the @var{index}'th frame from @var{stack}.")
|
||||||
|
@ -347,6 +387,9 @@ SCM_DEFINE (scm_stack_length, "stack-length", 1, 0, 0,
|
||||||
void
|
void
|
||||||
scm_init_stacks ()
|
scm_init_stacks ()
|
||||||
{
|
{
|
||||||
|
scm_sys_stacks = scm_make_fluid ();
|
||||||
|
scm_c_define ("%stacks", scm_sys_stacks);
|
||||||
|
|
||||||
scm_stack_type = scm_make_vtable (scm_from_locale_string (SCM_STACK_LAYOUT),
|
scm_stack_type = scm_make_vtable (scm_from_locale_string (SCM_STACK_LAYOUT),
|
||||||
SCM_UNDEFINED);
|
SCM_UNDEFINED);
|
||||||
scm_set_struct_vtable_name_x (scm_stack_type,
|
scm_set_struct_vtable_name_x (scm_stack_type,
|
||||||
|
|
|
@ -1030,7 +1030,7 @@ If there is no handler at all, Guile prints an error and then exits."
|
||||||
;;; {The interpreter stack}
|
;;; {The interpreter stack}
|
||||||
;;;
|
;;;
|
||||||
|
|
||||||
(define %stacks (make-fluid))
|
;; %stacks defined in stacks.c
|
||||||
(define (%start-stack tag thunk)
|
(define (%start-stack tag thunk)
|
||||||
(let ((prompt-tag (make-prompt-tag "start-stack")))
|
(let ((prompt-tag (make-prompt-tag "start-stack")))
|
||||||
(call-with-prompt
|
(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 (set-repl-prompt! v) (set! scm-repl-prompt v))
|
||||||
|
|
||||||
(define (default-pre-unwind-handler key . args)
|
(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))
|
(apply throw key args))
|
||||||
|
|
||||||
(begin-deprecated
|
(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 the-last-stack (make-fluid)) Defined by scm_init_backtrace ()
|
||||||
(define before-signal-stack (make-fluid))
|
(define before-signal-stack (make-fluid))
|
||||||
|
;; FIXME: stack-saved? is broken in the presence of threads.
|
||||||
(define stack-saved? #f)
|
(define stack-saved? #f)
|
||||||
|
|
||||||
(define (save-stack . narrowing)
|
(define (save-stack . narrowing)
|
||||||
(or stack-saved?
|
(if (not stack-saved?)
|
||||||
(cond ((not (memq 'debug (debug-options-interface)))
|
(begin
|
||||||
(fluid-set! the-last-stack #f)
|
(let ((stacks (fluid-ref %stacks)))
|
||||||
(set! stack-saved? #t))
|
(fluid-set! the-last-stack
|
||||||
(else
|
;; (make-stack obj inner outer inner outer ...)
|
||||||
(fluid-set!
|
;;
|
||||||
the-last-stack
|
;; In this case, cut away the make-stack frame, the
|
||||||
(case (stack-id #t)
|
;; save-stack frame, and then narrow as specified by the
|
||||||
((repl-stack)
|
;; user, delimited by the nearest start-stack invocation,
|
||||||
(apply make-stack #t save-stack primitive-eval #t 0 narrowing))
|
;; if any.
|
||||||
((load-stack)
|
(apply make-stack #t
|
||||||
(apply make-stack #t save-stack 0 #t 0 narrowing))
|
2
|
||||||
((#t)
|
(if (pair? stacks) (cdar stacks) 0)
|
||||||
(apply make-stack #t save-stack 0 1 narrowing))
|
narrowing)))
|
||||||
(else
|
(set! stack-saved? #t))))
|
||||||
(let ((id (stack-id #t)))
|
|
||||||
(and (procedure? id)
|
|
||||||
(apply make-stack #t save-stack id #t 0 narrowing))))))
|
|
||||||
(set! stack-saved? #t)))))
|
|
||||||
|
|
||||||
(define before-error-hook (make-hook))
|
(define before-error-hook (make-hook))
|
||||||
(define after-error-hook (make-hook))
|
(define after-error-hook (make-hook))
|
||||||
|
|
|
@ -96,27 +96,21 @@
|
||||||
x))))
|
x))))
|
||||||
(frame-bindings frame))))))
|
(frame-bindings frame))))))
|
||||||
|
|
||||||
(define* (collect-frames frame #:key count)
|
(define* (print-frames frames
|
||||||
(cond
|
#:optional (port (current-output-port))
|
||||||
((not count)
|
#:key (width 72) (full? #f) (forward? #f) count)
|
||||||
(let lp ((frame frame) (out '()))
|
(let* ((len (vector-length frames))
|
||||||
(if (not frame)
|
(lower-idx (if (or (not count) (positive? count))
|
||||||
out
|
0
|
||||||
(lp (frame-previous frame) (cons frame out)))))
|
(max 0 (+ len count))))
|
||||||
;; should also have a from-end option, either via negative count or
|
(upper-idx (if (and count (negative? count))
|
||||||
;; another kwarg
|
(1- len)
|
||||||
((>= count 0)
|
(1- (if count (min count len) len))))
|
||||||
(let lp ((frame frame) (out '()) (count count))
|
(inc (if forward? 1 -1)))
|
||||||
(if (or (not frame) (zero? count))
|
(let lp ((i (if forward? lower-idx upper-idx))
|
||||||
out
|
(last-file ""))
|
||||||
(lp (frame-previous frame) (cons frame out) (1- count)))))))
|
(if (<= lower-idx i upper-idx)
|
||||||
|
(let* ((frame (vector-ref frames i))
|
||||||
(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))
|
(source (frame-source frame))
|
||||||
(file (and source
|
(file (and source
|
||||||
(or (source:file source)
|
(or (source:file source)
|
||||||
|
@ -129,7 +123,7 @@
|
||||||
(if full?
|
(if full?
|
||||||
(print-locals frame #:width width
|
(print-locals frame #:width width
|
||||||
#:per-line-prefix " "))
|
#:per-line-prefix " "))
|
||||||
(lp (cdr frames) (1- i) (or file last-file))))))
|
(lp (+ i inc) (or file last-file)))))))
|
||||||
|
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
|
@ -150,31 +144,22 @@
|
||||||
(set! (prop vm) debugger)
|
(set! (prop vm) debugger)
|
||||||
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))
|
(let* ((db (vm-debugger vm))
|
||||||
(level (debugger-level db)))
|
(level (debugger-level db)))
|
||||||
(dynamic-wind
|
(dynamic-wind
|
||||||
(lambda () (set! (debugger-level db) (1+ level)))
|
(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)))))
|
(lambda () (set! (debugger-level db) level)))))
|
||||||
|
|
||||||
(define (debugger-repl db frame)
|
(define (debugger-repl db stack frames index)
|
||||||
(let ((top frame)
|
(let ((top (vector-ref frames 0))
|
||||||
(cur frame)
|
(cur (vector-ref frames index))
|
||||||
(index 0)
|
|
||||||
(level (debugger-level db))
|
(level (debugger-level db))
|
||||||
(last #f))
|
(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)
|
(define (frame-at-index idx)
|
||||||
(let lp ((idx idx) (walk top))
|
(and (< idx (vector-length frames))
|
||||||
(cond
|
(vector-ref frames idx)))
|
||||||
((not walk) #f)
|
|
||||||
((zero? idx) walk)
|
|
||||||
(else (lp (1- idx) (frame-previous walk))))))
|
|
||||||
(define (show-frame)
|
(define (show-frame)
|
||||||
;; #2 0x009600e0 in do_std_select (args=0xbfffd9e0) at threads.c:1668
|
;; #2 0x009600e0 in do_std_select (args=0xbfffd9e0) at threads.c:1668
|
||||||
;; 1668 select (select_args->nfds,
|
;; 1668 select (select_args->nfds,
|
||||||
|
@ -214,30 +199,31 @@
|
||||||
|
|
||||||
(define-command ((commands backtrace bt) #:optional count
|
(define-command ((commands backtrace bt) #:optional count
|
||||||
#:key (width 72) full?)
|
#:key (width 72) full?)
|
||||||
"Print a backtrace of all stack frames, or innermost COUNT frames."
|
"Print a backtrace of all stack frames, or innermost COUNT frames.
|
||||||
(print-frames (collect-frames top #:count count)
|
If COUNT is negative, the last COUNT frames will be shown."
|
||||||
|
(print-frames frames
|
||||||
|
#:count count
|
||||||
#:width width
|
#:width width
|
||||||
#:full? full?))
|
#:full? full?))
|
||||||
|
|
||||||
(define-command ((commands up) #:optional (count 1))
|
(define-command ((commands up) #:optional (count 1))
|
||||||
"Select and print stack frames that called this one.
|
"Select and print stack frames that called this one.
|
||||||
An argument says how many frames up to go"
|
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
|
(cond
|
||||||
((zero? n) (show-frame))
|
((or (not (integer? count)) (<= count 0))
|
||||||
((frame-previous cur)
|
(format #t "Invalid argument to `up': expected a positive integer for COUNT.~%"))
|
||||||
=> (lambda (new)
|
((>= (+ count index) (vector-length frames))
|
||||||
(set! cur new)
|
(cond
|
||||||
(set! index (1+ index))
|
((= index (1- (vector-length frames)))
|
||||||
(lp (1- n))))
|
|
||||||
((= n count)
|
|
||||||
(format #t "Already at outermost frame.\n"))
|
(format #t "Already at outermost frame.\n"))
|
||||||
(else
|
(else
|
||||||
(format #t "Reached outermost frame after walking ~a frames.\n"
|
(set! index (1- (vector-length frames)))
|
||||||
(- count n))
|
(set! cur (vector-ref frames index))
|
||||||
(show-frame))))))
|
(show-frame))))
|
||||||
|
(else
|
||||||
|
(set! index (+ count index))
|
||||||
|
(set! cur (vector-ref frames index))
|
||||||
|
(show-frame))))
|
||||||
|
|
||||||
(define-command ((commands down) #:optional (count 1))
|
(define-command ((commands down) #:optional (count 1))
|
||||||
"Select and print stack frames called by this one.
|
"Select and print stack frames called by this one.
|
||||||
|
@ -245,11 +231,17 @@ An argument says how many frames down to go"
|
||||||
(cond
|
(cond
|
||||||
((or (not (integer? count)) (<= count 0))
|
((or (not (integer? count)) (<= count 0))
|
||||||
(format #t "Invalid argument to `down': expected a positive integer for COUNT.~%"))
|
(format #t "Invalid argument to `down': expected a positive integer for COUNT.~%"))
|
||||||
((= index 0)
|
((< (- index count) 0)
|
||||||
(format #t "Already at innermost frame.~%"))
|
(cond
|
||||||
|
((zero? index)
|
||||||
|
(format #t "Already at innermost frame.\n"))
|
||||||
(else
|
(else
|
||||||
(set! index (max (- index count) 0))
|
(set! index 0)
|
||||||
(set! cur (frame-at-index index))
|
(set! cur (vector-ref frames index))
|
||||||
|
(show-frame))))
|
||||||
|
(else
|
||||||
|
(set! index (- index count))
|
||||||
|
(set! cur (vector-ref frames index))
|
||||||
(show-frame))))
|
(show-frame))))
|
||||||
|
|
||||||
(define-command ((commands frame f) #:optional idx)
|
(define-command ((commands frame f) #:optional idx)
|
||||||
|
@ -377,8 +369,23 @@ With an argument, select a frame by index, then show it."
|
||||||
;; hm, trace via reassigning global vars. tricksy.
|
;; hm, trace via reassigning global vars. tricksy.
|
||||||
;; (state associated with vm ?)
|
;; (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)
|
(define (debug-pre-unwind-handler key . args)
|
||||||
(let ((stack (make-stack #t 2)))
|
;; Narrow the stack by three frames: make-stack, this one, and the throw
|
||||||
|
;; handler.
|
||||||
|
(cond
|
||||||
|
((make-stack #t 3) =>
|
||||||
|
(lambda (stack)
|
||||||
(pmatch args
|
(pmatch args
|
||||||
((,subr ,msg ,args . ,rest)
|
((,subr ,msg ,args . ,rest)
|
||||||
(format #t "Throw to key `~a':\n" key)
|
(format #t "Throw to key `~a':\n" key)
|
||||||
|
@ -386,6 +393,12 @@ With an argument, select a frame by index, then show it."
|
||||||
(else
|
(else
|
||||||
(format #t "Throw to key `~a' with args `~s'." key args)))
|
(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")
|
(format #t "Entering the debugger. Type `bt' for a backtrace or `c' to continue.\n")
|
||||||
(run-debugger (stack-ref stack 0)))
|
(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)
|
(save-stack debug-pre-unwind-handler)
|
||||||
(apply throw key args))
|
(apply throw key args))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue