* __scm.h, stackchk.h, stackchk.c: Guile now performs stack
[bpt/guile.git] / libguile / debug.c
CommitLineData
f0e9217a
MD
1/* Debugging extensions for Guile
2 Copyright (C) 1995, 1996 Mikael Djurfeldt
3
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 1, or (at your option)
7 any later version.
8
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.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 The author can be reached at djurfeldt@nada.kth.se
19 Mikael Djurfeldt, SANS/NADA KTH, 10044 STOCKHOLM, SWEDEN
20 */
21
22#include <stdio.h>
23#include "_scm.h"
24
25\f
26
27/* {Run time control of the debugging evaluator}
28 */
29
30SCM_PROC (s_debug_options, "debug-options", 0, 1, 0, scm_debug_options);
31#ifdef __STDC__
32SCM
33scm_debug_options (SCM new_values)
34#else
35SCM
36scm_debug_options (new_values)
37 SCM new_values;
38#endif
39{
40 SCM ans;
41 SCM_DEFER_INTS;
42 ans = scm_change_options (new_values,
43 scm_debug_opts,
44 N_DEBUG_OPTIONS,
45 s_debug_options);
46#ifndef SCM_RECKLESS
47 if (!(1 <= FRAMES && FRAMES <= MAXFRAMESIZE))
48 {
49 scm_change_options (ans, scm_debug_opts, N_DEBUG_OPTIONS, s_debug_options);
50 /* *fixme* Should SCM_ALLOW_INTS be called here? */
51 scm_wta (new_values, (char *) SCM_OUTOFRANGE, "frames");
52 }
53#endif
54 RESET_DEBUG_MODE;
55 scm_debug_eframe_size = 2 * FRAMES;
56 SCM_ALLOW_INTS
57 return ans;
58}
59
60SCM_PROC (s_evaluator_traps, "evaluator-traps", 0, 1, 0, scm_evaluator_traps);
61#ifdef __STDC__
62SCM
63scm_evaluator_traps (SCM new_values)
64#else
65SCM
66scm_evaluator_traps (new_values)
67 SCM new_values;
68#endif
69{
70 SCM ans;
71 SCM_DEFER_INTS;
72 ans = scm_change_options (new_values,
73 scm_evaluator_trap_table,
74 N_EVALUATOR_TRAPS,
75 s_evaluator_traps);
76 RESET_DEBUG_MODE;
77 SCM_ALLOW_INTS
78 return ans;
79}
80
81SCM_PROC (s_single_step, "single-step", 2, 0, 0, scm_single_step);
82#ifdef __STDC__
83SCM
84scm_single_step (SCM cont, SCM val)
85#else
86SCM
87scm_single_step (val)
88 SCM cont, SCM val;
89#endif
90{
91 SCM_DEFER_INTS;
92 ENTER_FRAME = EXIT_FRAME = 1;
93 RESET_DEBUG_MODE;
94 SCM_ALLOW_INTS;
95 scm_throw (cont, val);
96 return SCM_BOOL_F; /* never returns */
97}
98
99\f
100static SCM scm_i_source, scm_i_more;
101static SCM scm_i_proc, scm_i_args, scm_i_eval_args;
102static SCM scm_i_procname;
103
104/* {Memoized Source}
105 */
106
107long scm_tc16_memoized;
108
109#ifdef __STDC__
110static int
111prinmemoized (SCM obj, SCM port, int writing)
112#else
113static int
114prinmemoized (obj, port, writing)
115 SCM obj;
116 SCM port;
117 int writing;
118#endif
119{
120 scm_gen_puts (scm_regular_string, "#<memoized ", port);
121 scm_iprin1 (scm_unmemoize (obj), port, 1);
122 scm_gen_putc ('>', port);
123 return 1;
124}
125
126static scm_smobfuns memoizedsmob =
127{scm_markcdr, scm_free0, prinmemoized, 0};
128
129SCM_PROC (s_memoized_p, "memoized?", 1, 0, 0, scm_memoized_p);
130#ifdef __STDC__
131SCM
132scm_memoized_p (SCM obj)
133#else
134SCM
135scm_memoized_p (obj)
136 SCM obj;
137#endif
138{
139 return SCM_NIMP (obj) && SCM_MEMOIZEDP (obj) ? SCM_BOOL_T : SCM_BOOL_F;
140}
141
142#ifdef __STDC__
143SCM
144scm_make_memoized (SCM exp, SCM env)
145#else
146SCM
147scm_make_memoized (env)
148 SCM exp, SCM env;
149#endif
150{
151 register SCM z, ans;
152 SCM_DEFER_INTS;
153 SCM_NEWCELL (z);
154 SCM_CAR (z) = exp;
155 SCM_CDR (z) = env;
156 SCM_NEWCELL (ans);
157 SCM_CAR (ans) = scm_tc16_memoized;
158 SCM_CDR (ans) = z;
159 SCM_ALLOW_INTS;
160 return ans;
161}
162
163SCM_PROC (s_unmemoize, "unmemoize", 1, 0, 0, scm_unmemoize);
164#ifdef __STDC__
165SCM
166scm_unmemoize (SCM m)
167#else
168SCM
169scm_unmemoize (m)
170 SCM m;
171#endif
172{
173 SCM_ASSERT (SCM_MEMOIZEDP (m), m, SCM_ARG1, s_unmemoize);
174 return scm_unmemocopy (SCM_MEMOEXP (m), SCM_MEMOENV (m));
175}
176
177SCM_PROC (s_memoized_environment, "memoized-environment", 1, 0, 0, scm_memoized_environment);
178#ifdef __STDC__
179SCM
180scm_memoized_environment (SCM m)
181#else
182SCM
183scm_memoized_environment (m)
184 SCM m;
185#endif
186{
187 SCM_ASSERT (SCM_MEMOIZEDP (m), m, SCM_ARG1, s_unmemoize);
188 return SCM_MEMOENV (m);
189}
190
191SCM_PROC (s_procedure_name, "procedure-name", 1, 0, 0, scm_procedure_name);
192#ifdef __STDC__
193SCM
194scm_procedure_name (SCM proc)
195#else
196SCM
197scm_procedure_name (proc)
198 SCM proc;
199#endif
200{
201 SCM_ASSERT(scm_procedure_p (proc) == SCM_BOOL_T,
202 proc,
203 SCM_ARG1,
204 s_procedure_name);
205 switch (SCM_TYP7 (proc)) {
206 case scm_tcs_closures:
207 {
208 SCM name = scm_procedure_property (proc, scm_i_name);
209#if 0
210 /* Procedure property scm_i_procname not implemented yet... */
211 SCM name = scm_source_property (SCM_CAR (SCM_CDR (SCM_CODE (proc))), scm_i_procname);
212 if (SCM_FALSEP (name))
213 name = scm_procedure_property (proc, scm_i_name);
214#endif
215 return name;
216 }
217 case scm_tcs_subrs:
218 return SCM_SNAME (proc);
219 default:
220 return SCM_BOOL_F;
221 }
222}
223
224SCM_PROC (s_procedure_source, "procedure-source", 1, 0, 0, scm_procedure_source);
225#ifdef __STDC__
226SCM
227scm_procedure_source (SCM proc)
228#else
229SCM
230scm_procedure_source (proc)
231 SCM proc;
232#endif
233{
234 SCM_ASSERT(SCM_NIMP (proc), proc, SCM_ARG1, s_procedure_source);
235 switch (SCM_TYP7 (proc)) {
236 case scm_tcs_closures:
237 {
238 SCM src;
239 src = scm_source_property (SCM_CDR (SCM_CODE (proc)), scm_i_copy);
240 if (src != SCM_BOOL_F)
241 return scm_cons2 (scm_i_lambda, SCM_CAR (SCM_CODE (proc)), src);
242 src = SCM_CODE (proc);
243 return scm_cons (scm_i_lambda,
244 scm_unmemocopy (src,
245 SCM_EXTEND_SCM_ENV (SCM_CAR (src),
246 SCM_EOL,
247 SCM_ENV (proc))));
248 }
249 case scm_tc7_contin:
250 case scm_tcs_subrs:
251#ifdef CCLO
252 case scm_tc7_cclo:
253#endif
254 /* It would indeed be a nice thing if we supplied source even for
255 built in procedures! */
256 return scm_procedure_property (proc, scm_i_source);
257 default:
258 scm_wta (proc, (char *) SCM_ARG1, s_procedure_source);
259 return 0;
260 }
261}
262
263SCM_PROC (s_procedure_environment, "procedure-environment", 1, 0, 0, scm_procedure_environment);
264#ifdef __STDC__
265SCM
266scm_procedure_environment (SCM proc)
267#else
268SCM
269scm_procedure_environment (proc)
270 SCM proc;
271#endif
272{
273 SCM_ASSERT (SCM_NIMP (proc), proc, SCM_ARG1, s_procedure_environment);
274 switch (SCM_TYP7 (proc)) {
275 case scm_tcs_closures:
276 return SCM_ENV (proc);
277 case scm_tc7_contin:
278 case scm_tcs_subrs:
279#ifdef CCLO
280 case scm_tc7_cclo:
281#endif
282 return SCM_EOL;
283 default:
284 scm_wta (proc, (char *) SCM_ARG1, s_procedure_environment);
285 return 0;
286 }
287}
288
289
290/* Eval in a local environment. We would like to have the ability to
291 * evaluate in a specified local environment, but due to the memoization
292 * this isn't normally possible. We solve it by copying the code before
293 * evaluating. Probably the best solution would be to have eval.c generate
294 * yet another evaluator. They are not very big actually.
295 */
296SCM_PROC (s_local_eval, "local-eval", 2, 0, 0, scm_local_eval);
297#ifdef __STDC__
298SCM
299scm_local_eval (SCM exp, SCM env)
300#else
301SCM
302scm_local_eval (exp, env)
303 SCM exp;
304 SCM env;
305#endif
306{
307 return scm_eval_3 (exp, 1, env);
308}
309
310/* {Stack Frames}
311 *
312 * The stack is a list of stackframes, from root to current.
313 *
314 * A stackframe is a list of virtual stackframes, which occur due to
315 * the evaluators tail recursion. A virtual stackframe normally
316 * corresponds to an eval/apply pair, but macros and special forms
317 * (which are implemented as macros in scm...) only have eval
318 * information and apply calls leads to apply only frames.
319 *
320 * A virtual stackframe is either a property list or the symbol
321 * ... which marks the location of virtual stackframes which could not
322 * be stored with the current debug-depth.
323 *
324 * Property Type Description
325 *
326 * These three only present in eval frames:
327 *
328 * sexpr memoized Source code expression and environment.
329 * proc procedure The procedure being applied.
330 * (Not present if pre-apply state.)
331 * args list The arguments evaluated so far.
332 * eval-args boolean True if evaluation of arguments not finished.
333 */
334
335/* {Debug Objects}
336 *
337 * The debugging evaluator throws these on frame traps.
338 */
339
340long scm_tc16_debugobj;
341
342#define DEBUGOBJP(x) (scm_tc16_debugobj == SCM_TYP16 (x))
343#define DBGFRAME(x) SCM_CDR (x)
344
345#ifdef __STDC__
346static int
347prindebugobj (SCM obj, SCM port, int writing)
348#else
349static int
350prindebugobj (writing)
351 SCM obj, SCM port, int writing;
352#endif
353{
354 scm_gen_puts (scm_regular_string, "#<debug-object ", port);
355 scm_intprint (DBGFRAME (obj), 16, port);
356 scm_gen_putc ('>', port);
357 return 1;
358}
359
360static scm_smobfuns debugobjsmob =
361{scm_mark0, scm_free0, prindebugobj, 0};
362
363SCM_PROC (s_debug_object_p, "debug-object?", 1, 0, 0, scm_debug_object_p);
364#ifdef __STDC__
365SCM
366scm_debug_object_p (SCM obj)
367#else
368SCM
369scm_debug_object_p (obj)
370 SCM obj;
371#endif
372{
373 return SCM_NIMP (obj) && DEBUGOBJP (obj) ? SCM_BOOL_T : SCM_BOOL_F;
374}
375
376#ifdef __STDC__
377SCM
378scm_make_debugobj (scm_debug_frame *frame)
379#else
380SCM
381scm_make_debugobj (frame)
382 scm_debug_frame *frame;
383#endif
384{
385 register SCM z;
386 SCM_DEFER_INTS;
387 SCM_NEWCELL (z);
388 SCM_CAR (z) = scm_tc16_debugobj;
389 DBGFRAME (z) = (SCM) frame;
390 SCM_ALLOW_INTS;
391 return z;
392}
393
394#ifdef __STDC__
395static SCM
396_scm_stack_frame_to_plist (scm_debug_frame *frame, long offset)
397#else
398static SCM
399_scm_stack_frame_to_plist (frame, offset)
400 scm_debug_frame *frame;
401 long offset;
402#endif
403{
404 int size;
405 scm_debug_info *info;
406 if (EVALFRAMEP (*frame))
407 {
408 size = frame->status & MAXFRAMESIZE;
409 info = (scm_debug_info *) (*((SCM_STACKITEM **) &frame->vect[size]) + offset);
410 if ((info - frame->vect) & 1)
411 {
412 /* Debug.vect ends with apply info. */
413 SCM p;
414 --info;
415 if (info[1].a.proc == SCM_UNDEFINED)
416 p = SCM_EOL;
417 else
418 p = scm_acons (scm_i_proc,
419 info[1].a.proc,
420 scm_acons (scm_i_args,
421 info[1].a.args,
422 ARGSREADYP (*frame)
423 ? SCM_EOL
424 : scm_acons (scm_i_eval_args,
425 SCM_BOOL_T,
426 SCM_EOL)));
427 return scm_acons (scm_i_source,
428 scm_make_memoized (info[0].e.exp, info[0].e.env),
429 p);
430 }
431 else
432 /* Debug.vect ends with eval info. */
433 return scm_acons (scm_i_source,
434 scm_make_memoized (info[0].e.exp, info[0].e.env),
435 SCM_EOL);
436 }
437 else
438 return scm_acons (scm_i_proc,
439 frame->vect[0].a.proc,
440 scm_acons (scm_i_args, frame->vect[0].a.args, SCM_EOL));
441}
442
443SCM_PROC (s_last_stack_frame, "last-stack-frame", 1, 0, 0, scm_last_stack_frame);
444#ifdef __STDC__
445SCM
446scm_last_stack_frame (SCM obj)
447#else
448SCM
449scm_last_stack_frame (obj)
450 SCM obj;
451#endif
452{
453 scm_debug_frame *frame;
454 long offset = 0;
455 SCM_ASSERT (SCM_NIMP (obj), obj, SCM_ARG1, s_last_stack_frame);
456 if (scm_tc16_debugobj == SCM_TYP16 (obj))
457 frame = (scm_debug_frame *) DBGFRAME (obj);
458 else if (scm_tc7_contin == SCM_TYP7 (obj))
459 {
460 frame = SCM_DFRAME (obj);
461 offset = (SCM_STACKITEM *) (SCM_CHARS (obj) + sizeof (regs)) - SCM_BASE (obj);
462#ifndef STACK_GROWS_UP
463 offset += SCM_LENGTH (obj);
464#endif
465 }
466 else scm_wta (obj, (char *) SCM_ARG1, s_last_stack_frame);
467 if (!frame)
468 return SCM_BOOL_F;
469 return _scm_stack_frame_to_plist ((scm_debug_frame *) ((SCM_STACKITEM *) frame + offset), offset);
470}
471
472/* Make a scheme object of the current evaluation stack.
473 */
474
475SCM_PROC (s_expr_stack, "expr-stack", 0, 1, 0, scm_expr_stack);
476#ifdef __STDC__
477SCM
478scm_expr_stack (SCM obj)
479#else
480SCM
481scm_expr_stack (obj)
482 SCM obj;
483#endif
484{
485 SCM frs = SCM_EOL, vfrs, p;
486 int size;
487 int max_vfrs = BACKTRACE_DEPTH;
488 scm_debug_info *info;
489 scm_debug_frame *frame;
490 long offset = 0;
491 if (SCM_UNBNDP (obj))
492 frame = last_debug_info_frame;
493 else
494 {
495 SCM_ASSERT (SCM_NIMP (obj), obj, SCM_ARG1, s_expr_stack);
496 if (scm_tc16_debugobj == SCM_TYP16 (obj))
497 frame = (scm_debug_frame *) DBGFRAME (obj);
498 else if (scm_tc7_contin == SCM_TYP7 (obj))
499 {
500 frame = SCM_DFRAME (obj);
501 offset = (SCM_STACKITEM *) (SCM_CHARS (obj) + sizeof (regs)) - SCM_BASE (obj);
502#ifndef STACK_GROWS_UP
503 offset += SCM_LENGTH (obj);
504#endif
505 }
506 else scm_wta (obj, (char *) SCM_ARG1, s_expr_stack);
507 }
508 for (; frame && max_vfrs > 0; frame = frame->prev)
509 {
510 frame = (scm_debug_frame *) ((SCM_STACKITEM *) frame + offset);
511 p = _scm_stack_frame_to_plist (frame, offset);
512 if (EVALFRAMEP (*frame))
513 {
514 size = frame->status & MAXFRAMESIZE;
515 info = (scm_debug_info *) (*((SCM_STACKITEM **) &frame->vect[size]) + offset);
516 vfrs = SCM_EOL;
517 if ((info - frame->vect) & 1)
518 --info;
519 /* Data in the apply part of an eval info frame comes from
520 previous stack frame if the scm_debug_info vector is overflowed. */
521 else if (OVERFLOWP (*frame)
522 && !SCM_UNBNDP (info[1].a.proc))
523 {
524 vfrs = scm_cons (p, SCM_EOL);
525 --max_vfrs;
526 p = scm_acons (scm_i_proc,
527 info[1].a.proc,
528 scm_acons (scm_i_args, info[1].a.args, SCM_EOL));
529 }
530 info -= 2;
531 vfrs = scm_cons (p, vfrs);
532 --max_vfrs;
533 if (OVERFLOWP (*frame))
534 vfrs = scm_cons (scm_i_more, vfrs);
535 while (info >= frame->vect)
536 {
537 p = SCM_EOL;
538 if (!SCM_UNBNDP (info[1].a.proc))
539 p = scm_acons (scm_i_proc,
540 info[1].a.proc,
541 scm_acons (scm_i_args, info[1].a.args, SCM_EOL));
542 p = scm_acons (scm_i_source,
543 scm_make_memoized (info[0].e.exp, info[0].e.env),
544 p);
545 info -= 2;
546 vfrs = scm_cons (p, vfrs);
547 --max_vfrs;
548 }
549 }
550 else
551 {
552 vfrs = scm_cons (p, SCM_EOL);
553 --max_vfrs;
554 }
555 frs = scm_cons (vfrs, frs);
556 }
557 if (max_vfrs <= 0)
558 frs = scm_cons (scm_i_more, frs);
559 return frs;
560}
561
562/* {Support for debugging with gdb}
563 *
564 * Gdb's support for debugging with Guile is written by Per Bothner at
565 * Cygnus Support.
566 */
567
568/* debug_print is a handy function for calling from a debugger.
569 * Given an SCM object, o, it executes (write o) to stdout.
570 */
571
572void debug_print (SCM o)
573{
574 scm_write(o, scm_def_outp);
575 fflush(NULL);
576}
577
578SCM_PROC (s_eval_string, "eval-string", 1, 0, 0, scm_eval_string);
579#ifdef __STDC__
580SCM
581scm_eval_string (SCM str)
582#else
583SCM
584scm_eval_string (str)
585 SCM str;
586#endif
587{
588 str = scm_mkstrport (SCM_INUM0, str, SCM_OPN | SCM_RDNG, s_eval_string);
589 str = scm_read (str, SCM_UNDEFINED, SCM_UNDEFINED);
590 return XEVAL(str, (SCM) SCM_EOL);
591}
592
593#ifdef __STDC__
594SCM
595scm_evstr (char *str)
596#else
597SCM
598scm_evstr (str)
599 char *str;
600#endif
601{
602 SCM lsym;
603 SCM_NEWCELL(lsym);
604 SCM_SETLENGTH (lsym, strlen(str)+0L, scm_tc7_ssymbol);
605 SCM_SETCHARS (lsym, str);
606 return scm_eval_string (lsym);
607}
608
609#ifdef __STDC__
610SCM
611scm_lookup_cstr (char *str, int len, SCM env)
612#else
613SCM
614scm_lookup_cstr (str, len, env)
615 char *str;
616 int len;
617 SCM env;
618#endif
619{
620 SCM sym = scm_intern (str, len);
621 SCM cell = scm_cons (sym, SCM_UNDEFINED);
622 return (*scm_lookupcar (cell, env));
623}
624
625
626\f
627
628void
629scm_init_debug ()
630{
631 scm_init_opts (scm_debug_options, scm_debug_opts, N_DEBUG_OPTIONS);
632
633 scm_tc16_memoized = scm_newsmob (&memoizedsmob);
634 scm_tc16_debugobj = scm_newsmob (&debugobjsmob);
635
636 scm_i_procname = SCM_CAR (scm_sysintern ("procname", SCM_UNDEFINED));
637 scm_i_more = SCM_CAR (scm_sysintern ("...", SCM_UNDEFINED));
638 scm_i_source = SCM_CAR (scm_sysintern ("source", SCM_UNDEFINED));
639 scm_i_proc = SCM_CAR (scm_sysintern ("proc", SCM_UNDEFINED));
640 scm_i_args = SCM_CAR (scm_sysintern ("args", SCM_UNDEFINED));
641 scm_i_eval_args = SCM_CAR (scm_sysintern ("eval-args", SCM_UNDEFINED));
642
643 scm_add_feature ("debug-extensions");
644
645#include "debug.x"
646}