1 /* Debugging extensions for Guile
2 * Copyright (C) 1995, 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
55 #include "continuations.h"
63 /* {Run time control of the debugging evaluator}
66 SCM_PROC (s_debug_options
, "debug-options-interface", 0, 1, 0, scm_debug_options
);
69 scm_debug_options (setting
)
74 ans
= scm_options (setting
,
79 if (!(1 <= SCM_N_FRAMES
&& SCM_N_FRAMES
<= SCM_MAX_FRAME_SIZE
))
81 scm_options (ans
, scm_debug_opts
, SCM_N_DEBUG_OPTIONS
, s_debug_options
);
82 scm_out_of_range (s_debug_options
, setting
);
86 scm_debug_eframe_size
= 2 * SCM_N_FRAMES
;
91 SCM_PROC (s_evaluator_traps
, "evaluator-traps-interface", 0, 1, 0, scm_evaluator_traps
);
94 scm_evaluator_traps (setting
)
99 ans
= scm_options (setting
,
100 scm_evaluator_trap_table
,
101 SCM_N_EVALUATOR_TRAPS
,
103 SCM_RESET_DEBUG_MODE
;
108 SCM_PROC (s_single_step
, "single-step", 2, 0, 0, scm_single_step
);
111 scm_single_step (cont
, val
)
116 SCM_ENTER_FRAME_P
= SCM_EXIT_FRAME_P
= 1;
117 SCM_RESET_DEBUG_MODE
;
119 scm_throw (cont
, val
);
120 return SCM_BOOL_F
; /* never returns */
124 static SCM scm_i_source
, scm_i_more
;
125 static SCM scm_i_proc
, scm_i_args
, scm_i_eval_args
;
126 static SCM scm_i_procname
;
131 long scm_tc16_memoized
;
134 static int prinmemoized
SCM_P ((SCM obj
, SCM port
, scm_print_state
*pstate
));
137 prinmemoized (obj
, port
, pstate
)
140 scm_print_state
*pstate
;
142 int writingp
= SCM_WRITINGP (pstate
);
143 scm_gen_puts (scm_regular_string
, "#<memoized ", port
);
144 SCM_SET_WRITINGP (pstate
, 1);
145 scm_iprin1 (scm_unmemoize (obj
), port
, pstate
);
146 SCM_SET_WRITINGP (pstate
, writingp
);
147 scm_gen_putc ('>', port
);
151 static scm_smobfuns memoizedsmob
=
152 {scm_markcdr
, scm_free0
, prinmemoized
, 0};
154 SCM_PROC (s_memoized_p
, "memoized?", 1, 0, 0, scm_memoized_p
);
160 return SCM_NIMP (obj
) && SCM_MEMOIZEDP (obj
) ? SCM_BOOL_T
: SCM_BOOL_F
;
165 scm_make_memoized (exp
, env
)
175 SCM_CAR (ans
) = scm_tc16_memoized
;
181 SCM_PROC (s_unmemoize
, "unmemoize", 1, 0, 0, scm_unmemoize
);
187 SCM_ASSERT (SCM_MEMOIZEDP (m
), m
, SCM_ARG1
, s_unmemoize
);
188 return scm_unmemocopy (SCM_MEMOEXP (m
), SCM_MEMOENV (m
));
191 SCM_PROC (s_memoized_environment
, "memoized-environment", 1, 0, 0, scm_memoized_environment
);
194 scm_memoized_environment (m
)
197 SCM_ASSERT (SCM_MEMOIZEDP (m
), m
, SCM_ARG1
, s_unmemoize
);
198 return SCM_MEMOENV (m
);
201 SCM_PROC (s_procedure_name
, "procedure-name", 1, 0, 0, scm_procedure_name
);
204 scm_procedure_name (proc
)
207 SCM_ASSERT(scm_procedure_p (proc
) == SCM_BOOL_T
,
211 switch (SCM_TYP7 (proc
)) {
212 case scm_tcs_closures
:
214 SCM name
= scm_procedure_property (proc
, scm_i_name
);
216 /* Procedure property scm_i_procname not implemented yet... */
217 SCM name
= scm_source_property (SCM_CAR (SCM_CDR (SCM_CODE (proc
))), scm_i_procname
);
218 if (SCM_FALSEP (name
))
219 name
= scm_procedure_property (proc
, scm_i_name
);
224 return SCM_SNAME (proc
);
230 SCM_PROC (s_procedure_source
, "procedure-source", 1, 0, 0, scm_procedure_source
);
233 scm_procedure_source (proc
)
236 SCM_ASSERT(SCM_NIMP (proc
), proc
, SCM_ARG1
, s_procedure_source
);
237 switch (SCM_TYP7 (proc
)) {
238 case scm_tcs_closures
:
241 src
= scm_source_property (SCM_CDR (SCM_CODE (proc
)), scm_i_copy
);
242 if (src
!= SCM_BOOL_F
)
243 return scm_cons2 (scm_i_lambda
, SCM_CAR (SCM_CODE (proc
)), src
);
244 src
= SCM_CODE (proc
);
245 return scm_cons (scm_i_lambda
,
247 SCM_EXTEND_ENV (SCM_CAR (src
),
256 /* It would indeed be a nice thing if we supplied source even for
257 built in procedures! */
258 return scm_procedure_property (proc
, scm_i_source
);
260 scm_wta (proc
, (char *) SCM_ARG1
, s_procedure_source
);
265 SCM_PROC (s_procedure_environment
, "procedure-environment", 1, 0, 0, scm_procedure_environment
);
268 scm_procedure_environment (proc
)
271 SCM_ASSERT (SCM_NIMP (proc
), proc
, SCM_ARG1
, s_procedure_environment
);
272 switch (SCM_TYP7 (proc
)) {
273 case scm_tcs_closures
:
274 return SCM_ENV (proc
);
282 scm_wta (proc
, (char *) SCM_ARG1
, s_procedure_environment
);
288 /* Eval in a local environment. We would like to have the ability to
289 * evaluate in a specified local environment, but due to the memoization
290 * this isn't normally possible. We solve it by copying the code before
291 * evaluating. Probably the best solution would be to have eval.c generate
292 * yet another evaluator. They are not very big actually.
294 SCM_PROC (s_local_eval
, "local-eval", 2, 0, 0, scm_local_eval
);
297 scm_local_eval (exp
, env
)
301 return scm_eval_3 (exp
, 1, env
);
306 * The stack is a list of stackframes, from root to current.
308 * A stackframe is a list of virtual stackframes, which occur due to
309 * the evaluators tail recursion. A virtual stackframe normally
310 * corresponds to an eval/apply pair, but macros and special forms
311 * (which are implemented as macros in scm...) only have eval
312 * information and apply calls leads to apply only frames.
314 * A virtual stackframe is either a property list or the symbol
315 * ... which marks the location of virtual stackframes which could not
316 * be stored with the current debug-depth.
318 * Property Type Description
320 * These three only present in eval frames:
322 * sexpr memoized Source code expression and environment.
323 * proc procedure The procedure being applied.
324 * (Not present if pre-apply state.)
325 * args list The arguments evaluated so far.
326 * eval-args boolean True if evaluation of arguments not finished.
331 * The debugging evaluator throws these on frame traps.
334 long scm_tc16_debugobj
;
336 #define DEBUGOBJP(x) (scm_tc16_debugobj == SCM_TYP16 (x))
337 #define DBGFRAME(x) SCM_CDR (x)
340 static int prindebugobj
SCM_P ((SCM obj
, SCM port
, scm_print_state
*pstate
));
343 prindebugobj (obj
, port
, pstate
)
346 scm_print_state
*pstate
;
348 scm_gen_puts (scm_regular_string
, "#<debug-object ", port
);
349 scm_intprint (DBGFRAME (obj
), 16, port
);
350 scm_gen_putc ('>', port
);
354 static scm_smobfuns debugobjsmob
=
355 {scm_mark0
, scm_free0
, prindebugobj
, 0};
357 SCM_PROC (s_debug_object_p
, "debug-object?", 1, 0, 0, scm_debug_object_p
);
360 scm_debug_object_p (obj
)
363 return SCM_NIMP (obj
) && DEBUGOBJP (obj
) ? SCM_BOOL_T
: SCM_BOOL_F
;
368 scm_make_debugobj (frame
)
369 scm_debug_frame
*frame
;
374 SCM_CAR (z
) = scm_tc16_debugobj
;
375 DBGFRAME (z
) = (SCM
) frame
;
381 static SCM _scm_stack_frame_to_plist
SCM_P ((scm_debug_frame
*frame
, long offset
));
384 _scm_stack_frame_to_plist (frame
, offset
)
385 scm_debug_frame
*frame
;
389 scm_debug_info
*info
;
390 if (SCM_EVALFRAMEP (*frame
))
392 size
= frame
->status
& SCM_MAX_FRAME_SIZE
;
393 info
= (scm_debug_info
*) (*((SCM_STACKITEM
**) &frame
->vect
[size
]) + offset
);
394 if ((info
- frame
->vect
) & 1)
396 /* Debug.vect ends with apply info. */
399 if (info
[1].a
.proc
== SCM_UNDEFINED
)
402 p
= scm_acons (scm_i_proc
,
404 scm_acons (scm_i_args
,
406 SCM_ARGS_READY_P (*frame
)
408 : scm_acons (scm_i_eval_args
,
411 return scm_acons (scm_i_source
,
412 scm_make_memoized (info
[0].e
.exp
, info
[0].e
.env
),
416 /* Debug.vect ends with eval info. */
417 return scm_acons (scm_i_source
,
418 scm_make_memoized (info
[0].e
.exp
, info
[0].e
.env
),
422 return scm_acons (scm_i_proc
,
423 frame
->vect
[0].a
.proc
,
424 scm_acons (scm_i_args
, frame
->vect
[0].a
.args
, SCM_EOL
));
427 SCM_PROC (s_last_stack_frame
, "last-stack-frame", 1, 0, 0, scm_last_stack_frame
);
430 scm_last_stack_frame (obj
)
433 scm_debug_frame
*frame
;
435 SCM_ASSERT (SCM_NIMP (obj
), obj
, SCM_ARG1
, s_last_stack_frame
);
436 if (scm_tc16_debugobj
== SCM_TYP16 (obj
))
437 frame
= (scm_debug_frame
*) DBGFRAME (obj
);
438 else if (scm_tc7_contin
== SCM_TYP7 (obj
))
440 frame
= SCM_DFRAME (obj
);
441 offset
= (SCM_STACKITEM
*) (SCM_CHARS (obj
) + sizeof (regs
)) - SCM_BASE (obj
);
442 #ifndef STACK_GROWS_UP
443 offset
+= SCM_LENGTH (obj
);
446 else scm_wta (obj
, (char *) SCM_ARG1
, s_last_stack_frame
);
449 return _scm_stack_frame_to_plist ((scm_debug_frame
*) ((SCM_STACKITEM
*) frame
+ offset
), offset
);
452 /* Make a scheme object of the current evaluation stack.
455 SCM_PROC (s_expr_stack
, "expr-stack", 0, 1, 0, scm_expr_stack
);
461 SCM frs
= SCM_EOL
, vfrs
, p
;
463 int max_vfrs
= SCM_BACKTRACE_DEPTH
;
464 scm_debug_info
*info
;
465 scm_debug_frame
*frame
;
467 if (SCM_UNBNDP (obj
))
468 frame
= scm_last_debug_frame
;
471 SCM_ASSERT (SCM_NIMP (obj
), obj
, SCM_ARG1
, s_expr_stack
);
472 if (scm_tc16_debugobj
== SCM_TYP16 (obj
))
473 frame
= (scm_debug_frame
*) DBGFRAME (obj
);
474 else if (scm_tc7_contin
== SCM_TYP7 (obj
))
476 frame
= SCM_DFRAME (obj
);
477 offset
= (SCM_STACKITEM
*) (SCM_CHARS (obj
) + sizeof (regs
)) - SCM_BASE (obj
);
478 #ifndef STACK_GROWS_UP
479 offset
+= SCM_LENGTH (obj
);
482 else scm_wta (obj
, (char *) SCM_ARG1
, s_expr_stack
);
484 for (; frame
&& max_vfrs
> 0; frame
= frame
->prev
)
486 frame
= (scm_debug_frame
*) ((SCM_STACKITEM
*) frame
+ offset
);
487 p
= _scm_stack_frame_to_plist (frame
, offset
);
488 if (SCM_EVALFRAMEP (*frame
))
490 size
= frame
->status
& SCM_MAX_FRAME_SIZE
;
491 info
= (scm_debug_info
*) (*((SCM_STACKITEM
**) &frame
->vect
[size
]) + offset
);
493 if ((info
- frame
->vect
) & 1)
495 /* Data in the apply part of an eval info frame comes from
496 previous stack frame if the scm_debug_info vector is overflowed. */
497 else if (SCM_OVERFLOWP (*frame
)
498 && !SCM_UNBNDP (info
[1].a
.proc
))
500 vfrs
= scm_cons (p
, SCM_EOL
);
502 p
= scm_acons (scm_i_proc
,
504 scm_acons (scm_i_args
, info
[1].a
.args
, SCM_EOL
));
507 vfrs
= scm_cons (p
, vfrs
);
509 if (SCM_OVERFLOWP (*frame
))
510 vfrs
= scm_cons (scm_i_more
, vfrs
);
511 while (info
>= frame
->vect
)
514 if (!SCM_UNBNDP (info
[1].a
.proc
))
515 p
= scm_acons (scm_i_proc
,
517 scm_acons (scm_i_args
, info
[1].a
.args
, SCM_EOL
));
518 p
= scm_acons (scm_i_source
,
519 scm_make_memoized (info
[0].e
.exp
, info
[0].e
.env
),
522 vfrs
= scm_cons (p
, vfrs
);
528 vfrs
= scm_cons (p
, SCM_EOL
);
531 frs
= scm_cons (vfrs
, frs
);
534 frs
= scm_cons (scm_i_more
, frs
);
544 scm_init_opts (scm_debug_options
, scm_debug_opts
, SCM_N_DEBUG_OPTIONS
);
545 scm_init_opts (scm_evaluator_traps
,
546 scm_evaluator_trap_table
,
547 SCM_N_EVALUATOR_TRAPS
);
549 scm_tc16_memoized
= scm_newsmob (&memoizedsmob
);
550 scm_tc16_debugobj
= scm_newsmob (&debugobjsmob
);
552 scm_i_procname
= SCM_CAR (scm_sysintern ("procname", SCM_UNDEFINED
));
553 scm_i_more
= SCM_CAR (scm_sysintern ("...", SCM_UNDEFINED
));
554 scm_i_source
= SCM_CAR (scm_sysintern ("source", SCM_UNDEFINED
));
555 scm_i_proc
= SCM_CAR (scm_sysintern ("proc", SCM_UNDEFINED
));
556 scm_i_args
= SCM_CAR (scm_sysintern ("args", SCM_UNDEFINED
));
557 scm_i_eval_args
= SCM_CAR (scm_sysintern ("eval-args", SCM_UNDEFINED
));
559 scm_add_feature ("debug-extensions");