1 /* Representation of stack frame debug information
2 * Copyright (C) 1996 Mikael Djurfeldt
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
9 * This program 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
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this software; see the file COPYING. If not, write to
16 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice.
42 * The author can be reached at djurfeldt@nada.kth.se
43 * Mikael Djurfeldt, SANS/NADA KTH, 10044 STOCKHOLM, SWEDEN
50 #include "continuations.h"
56 /* {Frames and stacks}
58 * The debugging evaluator creates debug frames on the stack. These
59 * are linked from the innermost frame and outwards. The last frame
60 * created can always be accessed as SCM_LAST_DEBUG_FRAME.
61 * Continuations contain a pointer to the innermost debug frame on the
64 * Each debug frame contains a set of flags and information about one
65 * or more stack frames. The case of multiple frames occurs due to
66 * tail recursion. The maximal number of stack frames which can be
67 * recorded in one debug frame can be set dynamically with the debug
70 * Stack frame information is of two types: eval information (the
71 * expression being evaluated and its environment) and apply
72 * information (the procedure being applied and its arguments). A
73 * stack frame normally corresponds to an eval/apply pair, but macros
74 * and special forms (which are implemented as macros in Guile) only
75 * have eval information and apply calls leads to apply only frames.
77 * Since we want to record the total stack information and later
78 * manipulate this data at the scheme level in the debugger, we need
79 * to transform it into a new representation. In the following code
80 * section you'll find the functions implementing this data type.
84 * The stack is represented as a struct with an id slot and a tail
85 * array of scm_info_frame structs.
87 * A frame is represented as a pair where the car contains a stack and
88 * the cdr an inum. The inum is an index to the first SCM value of
89 * the scm_info_frame struct.
113 * frame-evaluating-args?
118 /* Some auxiliary functions for reading debug frames off the stack.
121 /* Count number of debug info frames on a stack, beginning with
122 * DFRAME. OFFSET is used for relocation of pointers when the stack
123 * is read from a continuation.
125 static int stack_depth
SCM_P ((scm_debug_frame
*dframe
, long offset
, SCM
*id
, int *maxp
));
127 stack_depth (dframe
, offset
, id
, maxp
)
128 scm_debug_frame
*dframe
;
134 int max_depth
= SCM_BACKTRACE_MAXDEPTH
;
135 scm_debug_info
*info
;
137 dframe
&& !SCM_VOIDFRAMEP (*dframe
) && n
< max_depth
;
138 dframe
= (scm_debug_frame
*) ((SCM_STACKITEM
*) dframe
->prev
+ offset
))
140 if (SCM_EVALFRAMEP (*dframe
))
142 size
= dframe
->status
& SCM_MAX_FRAME_SIZE
;
143 info
= (scm_debug_info
*) (*((SCM_STACKITEM
**) &dframe
->vect
[size
])
145 n
+= (info
- dframe
->vect
) / 2 + 1;
146 /* Data in the apply part of an eval info frame comes from previous
147 stack frame if the scm_debug_info vector is overflowed. */
148 if ((((info
- dframe
->vect
) & 1) == 0)
149 && SCM_OVERFLOWP (*dframe
)
150 && !SCM_UNBNDP (info
[1].a
.proc
))
156 if (dframe
&& SCM_VOIDFRAMEP (*dframe
))
157 *id
= dframe
->vect
[0].id
;
163 /* Read debug info from DFRAME into IFRAME.
165 static void read_frame
SCM_P ((scm_debug_frame
*dframe
, long offset
, scm_info_frame
*iframe
));
167 read_frame (dframe
, offset
, iframe
)
168 scm_debug_frame
*dframe
;
170 scm_info_frame
*iframe
;
172 SCM flags
= SCM_INUM0
;
174 scm_debug_info
*info
;
175 if (SCM_EVALFRAMEP (*dframe
))
177 size
= dframe
->status
& SCM_MAX_FRAME_SIZE
;
178 info
= (scm_debug_info
*) (*((SCM_STACKITEM
**) &dframe
->vect
[size
])
180 if ((info
- dframe
->vect
) & 1)
182 /* Debug.vect ends with apply info. */
184 if (info
[1].a
.proc
!= SCM_UNDEFINED
)
186 flags
|= SCM_FRAMEF_PROC
;
187 iframe
->proc
= info
[1].a
.proc
;
188 iframe
->args
= info
[1].a
.args
;
189 if (!SCM_ARGS_READY_P (*dframe
))
190 flags
|= SCM_FRAMEF_EVAL_ARGS
;
193 iframe
->source
= scm_make_memoized (info
[0].e
.exp
, info
[0].e
.env
);
197 flags
|= SCM_FRAMEF_PROC
;
198 iframe
->proc
= dframe
->vect
[0].a
.proc
;
199 iframe
->args
= dframe
->vect
[0].a
.args
;
201 iframe
->flags
= flags
;
204 /* Fill the scm_info_frame vector IFRAME with data from N stack frames
205 * starting with the first stack frame represented by debug frame
209 #define NEXT_FRAME(iframe, n, quit) \
217 static void read_frames SCM_P ((scm_debug_frame *dframe, long offset, int nframes, scm_info_frame *iframes));
219 read_frames (dframe
, offset
, n
, iframes
)
220 scm_debug_frame
*dframe
;
223 scm_info_frame
*iframes
;
226 scm_info_frame
*iframe
= iframes
;
227 scm_debug_info
*info
;
230 dframe
&& !SCM_VOIDFRAMEP (*dframe
) && n
> 0;
231 dframe
= (scm_debug_frame
*) ((SCM_STACKITEM
*) dframe
->prev
+ offset
))
233 read_frame (dframe
, offset
, iframe
);
234 if (SCM_EVALFRAMEP (*dframe
))
236 size
= dframe
->status
& SCM_MAX_FRAME_SIZE
;
237 info
= (scm_debug_info
*) (*((SCM_STACKITEM
**) &dframe
->vect
[size
])
239 if ((info
- dframe
->vect
) & 1)
241 /* Data in the apply part of an eval info frame comes from
242 previous stack frame if the scm_debug_info vector is overflowed. */
243 else if (SCM_OVERFLOWP (*dframe
)
244 && !SCM_UNBNDP (info
[1].a
.proc
))
246 NEXT_FRAME (iframe
, n
, quit
);
247 iframe
->flags
= SCM_INUM0
| SCM_FRAMEF_PROC
;
248 iframe
->proc
= info
[1].a
.proc
;
249 iframe
->args
= info
[1].a
.args
;
251 if (SCM_OVERFLOWP (*dframe
))
252 iframe
->flags
|= SCM_FRAMEF_OVERFLOW
;
254 NEXT_FRAME (iframe
, n
, quit
);
255 while (info
>= dframe
->vect
)
257 if (!SCM_UNBNDP (info
[1].a
.proc
))
259 iframe
->flags
= SCM_INUM0
| SCM_FRAMEF_PROC
;
260 iframe
->proc
= info
[1].a
.proc
;
261 iframe
->args
= info
[1].a
.args
;
264 iframe
->flags
= SCM_INUM0
;
265 iframe
->source
= scm_make_memoized (info
[0].e
.exp
,
268 NEXT_FRAME (iframe
, n
, quit
);
273 NEXT_FRAME (iframe
, n
, quit
);
276 if (iframe
> iframes
)
277 (iframe
- 1) -> flags
|= SCM_FRAMEF_REAL
;
281 static void narrow_stack
SCM_P ((SCM stack
, int inner
, SCM inner_key
, int outer
, SCM outer_key
));
284 narrow_stack (stack
, inner
, inner_key
, outer
, outer_key
)
291 scm_stack
*s
= SCM_STACK (stack
);
295 /* Cut inner part. */
296 for (i
= 0; inner
; --inner
)
297 if (s
->frames
[i
++].proc
== inner_key
)
299 s
->frames
= &s
->frames
[i
];
302 /* Cut outer part. */
303 for (; n
&& outer
; --outer
)
304 if (s
->frames
[--n
].proc
== outer_key
)
317 SCM_PROC (s_stack_p
, "stack?", 1, 0, 0, scm_stack_p
);
322 return SCM_NIMP (obj
) && SCM_STACKP (obj
) ? SCM_BOOL_T
: SCM_BOOL_F
;
325 SCM_PROC (s_make_stack
, "make-stack", 0, 0, 1, scm_make_stack
);
327 scm_make_stack (args
)
331 scm_debug_frame
*dframe
;
332 scm_info_frame
*iframe
;
335 SCM obj
, inner_cut
, outer_cut
;
337 SCM_ASSERT (SCM_NIMP (args
) && SCM_CONSP (args
), SCM_WNA
, args
, s_make_stack
);
338 obj
= SCM_CAR (args
);
339 args
= SCM_CDR (args
);
341 /* Extract a pointer to the innermost frame of whatever object
342 scm_make_stack was given. */
343 if (obj
== SCM_BOOL_T
)
344 dframe
= scm_last_debug_frame
;
347 SCM_ASSERT (SCM_NIMP (obj
), obj
, SCM_ARG1
, s_make_stack
);
348 if (SCM_DEBUGOBJP (obj
))
349 dframe
= (scm_debug_frame
*) SCM_DEBUGOBJ_FRAME (obj
);
350 else if (scm_tc7_contin
== SCM_TYP7 (obj
))
352 offset
= ((SCM_STACKITEM
*) (SCM_CHARS (obj
) + sizeof (scm_contregs
))
354 #ifndef STACK_GROWS_UP
355 offset
+= SCM_LENGTH (obj
);
357 dframe
= (scm_debug_frame
*) ((SCM_STACKITEM
*) SCM_DFRAME (obj
)
362 scm_wta (obj
, (char *) SCM_ARG1
, s_make_stack
);
367 /* Count number of frames. Also get stack id tag and check whether
368 there are more stackframes than we want to record
369 (SCM_BACKTRACE_MAXDEPTH). */
372 n
= stack_depth (dframe
, offset
, &id
, &maxp
);
373 size
= n
* SCM_FRAME_N_SLOTS
;
375 /* Make the stack object. */
376 stack
= scm_make_struct (scm_stack_type
, SCM_MAKINUM (size
), SCM_EOL
);
377 SCM_STACK (stack
) -> id
= id
;
378 SCM_STACK (stack
) -> length
= n
;
379 iframe
= &SCM_STACK (stack
) -> tail
[0];
380 SCM_STACK (stack
) -> frames
= iframe
;
382 /* Translate the current chain of stack frames into debugging information. */
383 read_frames ((scm_debug_frame
*) ((SCM_STACKITEM
*) dframe
+ offset
),
386 /* Narrow the stack according to the arguments given to scm_make_stack. */
387 while (n
> 0 && SCM_NIMP (args
) && SCM_CONSP (args
))
389 inner_cut
= SCM_CAR (args
);
390 args
= SCM_CDR (args
);
391 if (SCM_NIMP (args
) && SCM_CONSP (args
))
393 outer_cut
= SCM_CAR (args
);
394 args
= SCM_CDR (args
);
397 outer_cut
= SCM_INUM0
;
400 SCM_INUMP (inner_cut
) ? SCM_INUM (inner_cut
) : n
,
401 SCM_INUMP (inner_cut
) ? 0 : inner_cut
,
402 SCM_INUMP (outer_cut
) ? SCM_INUM (outer_cut
) : n
,
403 SCM_INUMP (outer_cut
) ? 0 : outer_cut
);
405 n
= SCM_STACK (stack
) -> length
;
411 iframe
[n
- 1].flags
|= SCM_FRAMEF_OVERFLOW
;
418 SCM_PROC (s_stack_id
, "stack-id", 1, 0, 0, scm_stack_id
);
423 scm_debug_frame
*dframe
;
425 if (stack
== SCM_BOOL_T
)
426 dframe
= scm_last_debug_frame
;
429 SCM_ASSERT (SCM_NIMP (stack
), stack
, SCM_ARG1
, s_make_stack
);
430 if (SCM_DEBUGOBJP (stack
))
431 dframe
= (scm_debug_frame
*) SCM_DEBUGOBJ_FRAME (stack
);
432 else if (scm_tc7_contin
== SCM_TYP7 (stack
))
434 offset
= ((SCM_STACKITEM
*) (SCM_CHARS (stack
) + sizeof (scm_contregs
))
436 #ifndef STACK_GROWS_UP
437 offset
+= SCM_LENGTH (stack
);
439 dframe
= (scm_debug_frame
*) ((SCM_STACKITEM
*) SCM_DFRAME (stack
)
442 else if (SCM_STACKP (stack
))
443 return SCM_STACK (stack
) -> id
;
444 else scm_wrong_type_arg (s_stack_id
, SCM_ARG1
, stack
);
446 while (dframe
&& !SCM_VOIDFRAMEP (*dframe
))
447 dframe
= (scm_debug_frame
*) ((SCM_STACKITEM
*) dframe
->prev
+ offset
);
448 if (dframe
&& SCM_VOIDFRAMEP (*dframe
))
449 return dframe
->vect
[0].id
;
453 SCM_PROC (s_stack_ref
, "stack-ref", 2, 0, 0, scm_stack_ref
);
455 scm_stack_ref (stack
, i
)
459 SCM_ASSERT (SCM_NIMP (stack
)
460 && SCM_STACKP (stack
),
464 SCM_ASSERT (SCM_INUMP (i
), i
, SCM_ARG2
, s_stack_ref
);
465 SCM_ASSERT (SCM_INUM (i
) >= 0
466 && SCM_INUM (i
) < SCM_STACK_LENGTH (stack
),
470 return scm_cons (stack
, i
);
473 SCM_PROC(s_stack_length
, "stack-length", 1, 0, 0, scm_stack_length
);
475 scm_stack_length (stack
)
478 SCM_ASSERT (SCM_NIMP (stack
)
479 && SCM_STACKP (stack
),
483 return SCM_MAKINUM (SCM_STACK_LENGTH (stack
));
489 SCM_PROC (s_frame_p
, "frame?", 1, 0, 0, scm_frame_p
);
494 return SCM_NIMP (obj
) && SCM_FRAMEP (obj
);
497 SCM_PROC(s_last_stack_frame
, "last-stack-frame", 1, 0, 0, scm_last_stack_frame
);
499 scm_last_stack_frame (obj
)
502 scm_debug_frame
*dframe
;
506 SCM_ASSERT (SCM_NIMP (obj
), obj
, SCM_ARG1
, s_last_stack_frame
);
507 if (SCM_DEBUGOBJP (obj
))
508 dframe
= (scm_debug_frame
*) SCM_DEBUGOBJ_FRAME (obj
);
509 else if (scm_tc7_contin
== SCM_TYP7 (obj
))
511 offset
= ((SCM_STACKITEM
*) (SCM_CHARS (obj
) + sizeof (scm_contregs
))
513 #ifndef STACK_GROWS_UP
514 offset
+= SCM_LENGTH (obj
);
516 dframe
= (scm_debug_frame
*) ((SCM_STACKITEM
*) SCM_DFRAME (obj
) + offset
);
520 scm_wta (obj
, (char *) SCM_ARG1
, s_last_stack_frame
);
524 if (!dframe
|| SCM_VOIDFRAMEP (*dframe
))
527 stack
= scm_make_struct (scm_stack_type
, SCM_MAKINUM (SCM_FRAME_N_SLOTS
), SCM_EOL
);
528 SCM_STACK (stack
) -> length
= 1;
529 SCM_STACK (stack
) -> frames
= &SCM_STACK (stack
) -> tail
[0];
530 read_frame (dframe
, offset
, (scm_info_frame
*) &SCM_STACK (stack
) -> frames
[0]);
532 return scm_cons (stack
, SCM_INUM0
);;
535 SCM_PROC(s_frame_number
, "frame-number", 1, 0, 0, scm_frame_number
);
537 scm_frame_number (frame
)
540 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
544 return SCM_MAKINUM (SCM_FRAME_NUMBER (frame
));
547 SCM_PROC(s_frame_source
, "frame-source", 1, 0, 0, scm_frame_source
);
549 scm_frame_source (frame
)
552 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
556 return SCM_FRAME_SOURCE (frame
);
559 SCM_PROC(s_frame_procedure
, "frame-procedure", 1, 0, 0, scm_frame_procedure
);
561 scm_frame_procedure (frame
)
564 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
568 return (SCM_FRAME_PROC_P (frame
)
570 : SCM_FRAME_PROC (frame
));
573 SCM_PROC(s_frame_arguments
, "frame-arguments", 1, 0, 0, scm_frame_arguments
);
575 scm_frame_arguments (frame
)
578 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
582 return SCM_FRAME_ARGS (frame
);
585 SCM_PROC(s_frame_previous
, "frame-previous", 1, 0, 0, scm_frame_previous
);
587 scm_frame_previous (frame
)
591 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
595 n
= SCM_INUM (SCM_CDR (frame
)) + 1;
596 if (n
>= SCM_STACK_LENGTH (SCM_CAR (frame
)))
599 return scm_cons (SCM_CAR (frame
), SCM_MAKINUM (n
));
602 SCM_PROC(s_frame_next
, "frame-next", 1, 0, 0, scm_frame_next
);
604 scm_frame_next (frame
)
608 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
612 n
= SCM_INUM (SCM_CDR (frame
)) - 1;
616 return scm_cons (SCM_CAR (frame
), SCM_MAKINUM (n
));
619 SCM_PROC(s_frame_real_p
, "frame-real?", 1, 0, 0, scm_frame_real_p
);
621 scm_frame_real_p (frame
)
624 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
628 return SCM_FRAME_REAL_P (frame
) ? SCM_BOOL_T
: SCM_BOOL_F
;
631 SCM_PROC(s_frame_procedure_p
, "frame-procedure?", 1, 0, 0, scm_frame_procedure_p
);
633 scm_frame_procedure_p (frame
)
636 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
639 s_frame_procedure_p
);
640 return SCM_FRAME_PROC_P (frame
) ? SCM_BOOL_T
: SCM_BOOL_F
;
643 SCM_PROC(s_frame_evaluating_args_p
, "frame-evaluating-args?", 1, 0, 0, scm_frame_evaluating_args_p
);
645 scm_frame_evaluating_args_p (frame
)
648 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
651 s_frame_evaluating_args_p
);
652 return SCM_FRAME_EVAL_ARGS_P (frame
) ? SCM_BOOL_T
: SCM_BOOL_F
;
655 SCM_PROC(s_frame_overflow_p
, "frame-overflow?", 1, 0, 0, scm_frame_overflow_p
);
657 scm_frame_overflow_p (frame
)
660 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
664 return SCM_FRAME_OVERFLOW_P (frame
) ? SCM_BOOL_T
: SCM_BOOL_F
;
673 SCM vtable_layout
= scm_make_struct_layout (scm_nullstr
);
674 SCM stack_layout
= scm_make_struct_layout (scm_makfrom0str (SCM_STACK_LAYOUT
));
675 vtable
= scm_make_vtable_vtable (vtable_layout
, SCM_INUM0
, SCM_EOL
);
676 scm_stack_type
= scm_permanent_object (scm_make_struct (vtable
,
678 scm_cons (stack_layout
, SCM_EOL
)));