1 /* Printing of backtraces and error messages
2 * Copyright (C) 1996,1997,1998,1999,2000,2001, 2003, 2004 Free Software Foundation
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library 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 GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "libguile/_scm.h"
35 #include "libguile/stacks.h"
36 #include "libguile/srcprop.h"
37 #include "libguile/struct.h"
38 #include "libguile/strports.h"
39 #include "libguile/throw.h"
40 #include "libguile/fluids.h"
41 #include "libguile/ports.h"
42 #include "libguile/strings.h"
43 #include "libguile/dynwind.h"
45 #include "libguile/validate.h"
46 #include "libguile/lang.h"
47 #include "libguile/backtrace.h"
48 #include "libguile/filesys.h"
50 /* {Error reporting and backtraces}
52 * Note that these functions shouldn't generate errors themselves.
55 /* Print parameters for error messages. */
57 #define DISPLAY_ERROR_MESSAGE_MAX_LEVEL 7
58 #define DISPLAY_ERROR_MESSAGE_MAX_LENGTH 10
60 /* Print parameters for failing expressions in error messages.
61 * (See also `print_params' below for backtrace print parameters.)
64 #define DISPLAY_EXPRESSION_MAX_LEVEL 2
65 #define DISPLAY_EXPRESSION_MAX_LENGTH 3
68 #define SCM_ASSERT(_cond, _arg, _pos, _subr) \
72 SCM scm_the_last_stack_fluid_var
;
75 display_header (SCM source
, SCM port
)
77 if (SCM_MEMOIZEDP (source
))
79 SCM fname
= scm_source_property (source
, scm_sym_filename
);
80 SCM line
= scm_source_property (source
, scm_sym_line
);
81 SCM col
= scm_source_property (source
, scm_sym_column
);
83 /* Dirk:FIXME:: Maybe we should store the _port_ rather than the
84 * filename with the source properties? Then we could in case of
85 * non-file ports give at least some more details than just
86 * "<unnamed port>". */
87 if (SCM_STRINGP (fname
))
88 scm_prin1 (fname
, port
, 0);
90 scm_puts ("<unnamed port>", port
);
92 if (scm_is_true (line
) && scm_is_true (col
))
95 scm_intprint (SCM_INUM (line
) + 1, 10, port
);
97 scm_intprint (SCM_INUM (col
) + 1, 10, port
);
101 scm_puts ("ERROR", port
);
102 scm_puts (": ", port
);
106 struct display_error_message_data
{
110 scm_print_state
*pstate
;
117 display_error_message (struct display_error_message_data
*d
)
119 if (SCM_STRINGP (d
->message
) && scm_is_true (scm_list_p (d
->args
)))
120 scm_simple_format (d
->port
, d
->message
, d
->args
);
122 scm_display (d
->message
, d
->port
);
123 scm_newline (d
->port
);
124 return SCM_UNSPECIFIED
;
128 before_display_error_message (struct display_error_message_data
*d
)
130 scm_print_state
*pstate
= d
->pstate
;
131 d
->old_fancyp
= pstate
->fancyp
;
132 d
->old_level
= pstate
->level
;
133 d
->old_length
= pstate
->length
;
135 pstate
->level
= DISPLAY_ERROR_MESSAGE_MAX_LEVEL
;
136 pstate
->length
= DISPLAY_ERROR_MESSAGE_MAX_LENGTH
;
140 after_display_error_message (struct display_error_message_data
*d
)
142 scm_print_state
*pstate
= d
->pstate
;
143 pstate
->fancyp
= d
->old_fancyp
;
144 pstate
->level
= d
->old_level
;
145 pstate
->length
= d
->old_length
;
149 scm_display_error_message (SCM message
, SCM args
, SCM port
)
151 struct display_error_message_data d
;
153 scm_print_state
*pstate
;
155 port
= scm_i_port_with_print_state (port
, SCM_UNDEFINED
);
156 print_state
= SCM_PORT_WITH_PS_PS (port
);
157 pstate
= SCM_PRINT_STATE (print_state
);
163 scm_internal_dynamic_wind ((scm_t_guard
) before_display_error_message
,
164 (scm_t_inner
) display_error_message
,
165 (scm_t_guard
) after_display_error_message
,
171 display_expression (SCM frame
, SCM pname
, SCM source
, SCM port
)
173 SCM print_state
= scm_make_print_state ();
174 scm_print_state
*pstate
= SCM_PRINT_STATE (print_state
);
175 pstate
->writingp
= 0;
177 pstate
->level
= DISPLAY_EXPRESSION_MAX_LEVEL
;
178 pstate
->length
= DISPLAY_EXPRESSION_MAX_LENGTH
;
179 if (SCM_SYMBOLP (pname
) || SCM_STRINGP (pname
))
181 if (SCM_FRAMEP (frame
)
182 && SCM_FRAME_EVAL_ARGS_P (frame
))
183 scm_puts ("While evaluating arguments to ", port
);
185 scm_puts ("In procedure ", port
);
186 scm_iprin1 (pname
, port
, pstate
);
187 if (SCM_MEMOIZEDP (source
))
189 scm_puts (" in expression ", port
);
190 pstate
->writingp
= 1;
191 scm_iprin1 (scm_i_unmemoize_expr (source
), port
, pstate
);
194 else if (SCM_MEMOIZEDP (source
))
196 scm_puts ("In expression ", port
);
197 pstate
->writingp
= 1;
198 scm_iprin1 (scm_i_unmemoize_expr (source
), port
, pstate
);
200 scm_puts (":\n", port
);
201 scm_free_print_state (print_state
);
204 struct display_error_args
{
214 display_error_body (struct display_error_args
*a
)
216 SCM current_frame
= SCM_BOOL_F
;
217 SCM source
= SCM_BOOL_F
;
218 SCM prev_frame
= SCM_BOOL_F
;
222 && SCM_STACKP (a
->stack
)
223 && SCM_STACK_LENGTH (a
->stack
) > 0)
225 current_frame
= scm_stack_ref (a
->stack
, SCM_INUM0
);
226 source
= SCM_FRAME_SOURCE (current_frame
);
227 prev_frame
= SCM_FRAME_PREV (current_frame
);
228 if (!SCM_MEMOIZEDP (source
) && scm_is_true (prev_frame
))
229 source
= SCM_FRAME_SOURCE (prev_frame
);
230 if (!SCM_SYMBOLP (pname
) && !SCM_STRINGP (pname
) && SCM_FRAME_PROC_P (current_frame
)
231 && SCM_EQ_P (scm_procedure_p (SCM_FRAME_PROC (current_frame
)), SCM_BOOL_T
))
232 pname
= scm_procedure_name (SCM_FRAME_PROC (current_frame
));
234 if (SCM_SYMBOLP (pname
) || SCM_STRINGP (pname
) || SCM_MEMOIZEDP (source
))
236 display_header (source
, a
->port
);
237 display_expression (current_frame
, pname
, source
, a
->port
);
239 display_header (source
, a
->port
);
240 scm_display_error_message (a
->message
, a
->args
, a
->port
);
241 return SCM_UNSPECIFIED
;
244 struct display_error_handler_data
{
249 /* This is the exception handler for error reporting routines.
250 Note that it is very important that this handler *doesn't* try to
251 print more than the error tag, since the error very probably is
252 caused by an erroneous print call-back routine. If we would
253 try to print all objects, we would enter an infinite loop. */
255 display_error_handler (struct display_error_handler_data
*data
,
256 SCM tag
, SCM args SCM_UNUSED
)
258 SCM print_state
= scm_make_print_state ();
259 scm_puts ("\nException during displaying of ", data
->port
);
260 scm_puts (data
->mode
, data
->port
);
261 scm_puts (": ", data
->port
);
262 scm_iprin1 (tag
, data
->port
, SCM_PRINT_STATE (print_state
));
263 scm_putc ('\n', data
->port
);
264 return SCM_UNSPECIFIED
;
268 /* The function scm_i_display_error prints out a detailed error message. This
269 * function will be called directly within libguile to signal error messages.
270 * No parameter checks will be performed by scm_i_display_error. Thus, User
271 * code should rather use the function scm_display_error.
274 scm_i_display_error (SCM stack
, SCM port
, SCM subr
, SCM message
, SCM args
, SCM rest
)
276 struct display_error_args a
;
277 struct display_error_handler_data data
;
286 scm_internal_catch (SCM_BOOL_T
,
287 (scm_t_catch_body
) display_error_body
, &a
,
288 (scm_t_catch_handler
) display_error_handler
, &data
);
292 SCM_DEFINE (scm_display_error
, "display-error", 6, 0, 0,
293 (SCM stack
, SCM port
, SCM subr
, SCM message
, SCM args
, SCM rest
),
294 "Display an error message to the output port @var{port}.\n"
295 "@var{stack} is the saved stack for the error, @var{subr} is\n"
296 "the name of the procedure in which the error occurred and\n"
297 "@var{message} is the actual error message, which may contain\n"
298 "formatting instructions. These will format the arguments in\n"
299 "the list @var{args} accordingly. @var{rest} is currently\n"
301 #define FUNC_NAME s_scm_display_error
303 SCM_VALIDATE_OUTPUT_PORT (2, port
);
305 scm_i_display_error (stack
, port
, subr
, message
, args
, rest
);
307 return SCM_UNSPECIFIED
;
317 static int n_print_params
= 9;
318 static print_params_t default_print_params
[] = {
322 { 1, 4 }, { 1, 3 }, { 1, 2 }
324 static print_params_t
*print_params
= default_print_params
;
327 SCM_DEFINE (scm_set_print_params_x
, "set-print-params!", 1, 0, 0,
329 "Set the print parameters to the values from @var{params}.\n"
330 "@var{params} must be a list of two-element lists which must\n"
331 "hold two integer values.")
332 #define FUNC_NAME s_scm_set_print_params_x
337 print_params_t
*new_params
;
339 SCM_VALIDATE_NONEMPTYLIST_COPYLEN (2, params
, n
);
340 for (ls
= params
; !SCM_NULL_OR_NIL_P (ls
); ls
= SCM_CDR (ls
))
341 SCM_ASSERT (scm_ilength (SCM_CAR (params
)) == 2
342 && SCM_INUMP (SCM_CAAR (ls
))
343 && SCM_INUM (SCM_CAAR (ls
)) >= 0
344 && SCM_INUMP (SCM_CADAR (ls
))
345 && SCM_INUM (SCM_CADAR (ls
)) >= 0,
348 s_scm_set_print_params_x
);
349 new_params
= scm_malloc (n
* sizeof (print_params_t
));
350 if (print_params
!= default_print_params
)
352 print_params
= new_params
;
353 for (i
= 0; i
< n
; ++i
)
355 print_params
[i
].level
= SCM_INUM (SCM_CAAR (params
));
356 print_params
[i
].length
= SCM_INUM (SCM_CADAR (params
));
357 params
= SCM_CDR (params
);
360 return SCM_UNSPECIFIED
;
366 indent (int n
, SCM port
)
369 for (i
= 0; i
< n
; ++i
)
370 scm_putc (' ', port
);
374 display_frame_expr (char *hdr
, SCM exp
, char *tlr
, int indentation
, SCM sport
, SCM port
, scm_print_state
*pstate
)
378 scm_t_ptob_descriptor
*ptob
= scm_ptobs
+ SCM_PTOBNUM (sport
);
381 pstate
->length
= print_params
[i
].length
;
382 ptob
->seek (sport
, 0, SEEK_SET
);
385 pstate
->level
= print_params
[i
].level
- 1;
386 scm_iprlist (hdr
, exp
, tlr
[0], sport
, pstate
);
387 scm_puts (&tlr
[1], sport
);
391 pstate
->level
= print_params
[i
].level
;
392 scm_iprin1 (exp
, sport
, pstate
);
395 n
= ptob
->seek (sport
, 0, SEEK_CUR
);
398 while (indentation
+ n
> SCM_BACKTRACE_WIDTH
&& i
< n_print_params
);
399 ptob
->truncate (sport
, n
);
400 string
= scm_strport_to_string (sport
);
401 /* Remove control characters */
402 for (i
= 0; i
< n
; ++i
)
403 if (iscntrl ((int) (unsigned char) SCM_STRING_CHARS (string
)[i
]))
404 SCM_STRING_CHARS (string
)[i
] = ' ';
406 if (indentation
+ n
> SCM_BACKTRACE_WIDTH
)
408 n
= SCM_BACKTRACE_WIDTH
- indentation
;
409 SCM_STRING_CHARS (string
)[n
- 1] = '$';
412 scm_lfwrite (SCM_STRING_CHARS (string
), n
, port
);
416 display_application (SCM frame
, int indentation
, SCM sport
, SCM port
, scm_print_state
*pstate
)
418 SCM proc
= SCM_FRAME_PROC (frame
);
419 SCM name
= (scm_is_true (scm_procedure_p (proc
))
420 ? scm_procedure_name (proc
)
422 display_frame_expr ("[",
423 scm_cons (scm_is_true (name
) ? name
: proc
,
424 SCM_FRAME_ARGS (frame
)),
425 SCM_FRAME_EVAL_ARGS_P (frame
) ? " ..." : "]",
432 SCM_DEFINE (scm_display_application
, "display-application", 1, 2, 0,
433 (SCM frame
, SCM port
, SCM indent
),
434 "Display a procedure application @var{frame} to the output port\n"
435 "@var{port}. @var{indent} specifies the indentation of the\n"
437 #define FUNC_NAME s_scm_display_application
439 SCM_VALIDATE_FRAME (1, frame
);
440 if (SCM_UNBNDP (port
))
443 SCM_VALIDATE_OPOUTPORT (2, port
);
444 if (SCM_UNBNDP (indent
))
447 SCM_VALIDATE_INUM (3, indent
);
449 if (SCM_FRAME_PROC_P (frame
))
450 /* Display an application. */
452 SCM sport
, print_state
;
453 scm_print_state
*pstate
;
455 /* Create a string port used for adaptation of printing parameters. */
456 sport
= scm_mkstrport (SCM_INUM0
,
457 scm_make_string (scm_from_int (240),
462 /* Create a print state for printing of frames. */
463 print_state
= scm_make_print_state ();
464 pstate
= SCM_PRINT_STATE (print_state
);
465 pstate
->writingp
= 1;
468 display_application (frame
, SCM_INUM (indent
), sport
, port
, pstate
);
476 SCM_SYMBOL (sym_base
, "base");
479 display_backtrace_get_file_line (SCM frame
, SCM
*file
, SCM
*line
)
481 SCM source
= SCM_FRAME_SOURCE (frame
);
482 *file
= SCM_MEMOIZEDP (source
) ? scm_source_property (source
, scm_sym_filename
) : SCM_BOOL_F
;
483 *line
= (SCM_MEMOIZEDP (source
)) ? scm_source_property (source
, scm_sym_line
) : SCM_BOOL_F
;
487 display_backtrace_file (frame
, last_file
, port
, pstate
)
491 scm_print_state
*pstate
;
495 display_backtrace_get_file_line (frame
, &file
, &line
);
497 if (SCM_EQ_P (file
, *last_file
))
502 scm_puts ("In ", port
);
503 if (scm_is_false (file
))
504 if (scm_is_false (line
))
505 scm_puts ("unknown file", port
);
507 scm_puts ("current input", port
);
510 pstate
->writingp
= 0;
511 scm_iprin1 (file
, port
, pstate
);
512 pstate
->writingp
= 1;
514 scm_puts (":\n", port
);
518 display_backtrace_file_and_line (SCM frame
, SCM port
, scm_print_state
*pstate
)
522 display_backtrace_get_file_line (frame
, &file
, &line
);
524 if (SCM_EQ_P (SCM_PACK (SCM_SHOW_FILE_NAME
), sym_base
))
526 if (scm_is_false (file
))
528 if (scm_is_false (line
))
529 scm_putc ('?', port
);
531 scm_puts ("<stdin>", port
);
535 pstate
-> writingp
= 0;
537 scm_iprin1 (SCM_STRINGP (file
) ? scm_basename (file
, SCM_UNDEFINED
) : file
,
540 scm_iprin1 (file
, port
, pstate
);
542 pstate
-> writingp
= 1;
545 scm_putc (':', port
);
547 else if (scm_is_true (line
))
550 for (i
= SCM_INUM (line
)+1; i
> 0; i
= i
/10, j
++)
555 if (scm_is_false (line
))
556 scm_puts (" ?", port
);
558 scm_intprint (SCM_INUM (line
) + 1, 10, port
);
559 scm_puts (": ", port
);
563 display_frame (SCM frame
, int nfield
, int indentation
, SCM sport
, SCM port
, scm_print_state
*pstate
)
567 /* Announce missing frames? */
568 if (!SCM_BACKWARDS_P
&& SCM_FRAME_OVERFLOW_P (frame
))
570 indent (nfield
+ 1 + indentation
, port
);
571 scm_puts ("...\n", port
);
574 /* display file name and line number */
575 if (scm_is_true (SCM_PACK (SCM_SHOW_FILE_NAME
)))
576 display_backtrace_file_and_line (frame
, port
, pstate
);
578 /* Check size of frame number. */
579 n
= SCM_FRAME_NUMBER (frame
);
580 for (i
= 0, j
= n
; j
> 0; ++i
) j
/= 10;
582 /* Number indentation. */
583 indent (nfield
- (i
? i
: 1), port
);
586 scm_iprin1 (scm_from_int (n
), port
, pstate
);
588 /* Real frame marker */
589 scm_putc (SCM_FRAME_REAL_P (frame
) ? '*' : ' ', port
);
592 indent (indentation
, port
);
594 if (SCM_FRAME_PROC_P (frame
))
595 /* Display an application. */
596 display_application (frame
, nfield
+ 1 + indentation
, sport
, port
, pstate
);
598 /* Display a special form. */
600 SCM source
= SCM_FRAME_SOURCE (frame
);
601 SCM copy
= (SCM_CONSP (source
)
602 ? scm_source_property (source
, scm_sym_copy
)
604 SCM umcopy
= (SCM_MEMOIZEDP (source
)
605 ? scm_i_unmemoize_expr (source
)
607 display_frame_expr ("(",
608 SCM_CONSP (copy
) ? copy
: umcopy
,
610 nfield
+ 1 + indentation
,
615 scm_putc ('\n', port
);
617 /* Announce missing frames? */
618 if (SCM_BACKWARDS_P
&& SCM_FRAME_OVERFLOW_P (frame
))
620 indent (nfield
+ 1 + indentation
, port
);
621 scm_puts ("...\n", port
);
625 struct display_backtrace_args
{
633 display_backtrace_body (struct display_backtrace_args
*a
)
634 #define FUNC_NAME "display_backtrace_body"
636 int n_frames
, beg
, end
, n
, i
, j
;
637 int nfield
, indent_p
, indentation
;
638 SCM frame
, sport
, print_state
;
640 scm_print_state
*pstate
;
642 a
->port
= SCM_COERCE_OUTPORT (a
->port
);
644 /* Argument checking and extraction. */
645 SCM_VALIDATE_STACK (1, a
->stack
);
646 SCM_VALIDATE_OPOUTPORT (2, a
->port
);
647 n_frames
= SCM_INUM (scm_stack_length (a
->stack
));
648 n
= SCM_INUMP (a
->depth
) ? SCM_INUM (a
->depth
) : SCM_BACKTRACE_DEPTH
;
651 beg
= SCM_INUMP (a
->first
) ? SCM_INUM (a
->first
) : 0;
659 if (SCM_INUMP (a
->first
))
661 beg
= SCM_INUM (a
->first
);
675 SCM_ASSERT (beg
>= 0 && beg
< n_frames
, a
->first
, SCM_ARG3
, s_display_backtrace
);
676 SCM_ASSERT (n
> 0, a
->depth
, SCM_ARG4
, s_display_backtrace
);
678 /* Create a string port used for adaptation of printing parameters. */
679 sport
= scm_mkstrport (SCM_INUM0
,
680 scm_make_string (scm_from_int (240), SCM_UNDEFINED
),
684 /* Create a print state for printing of frames. */
685 print_state
= scm_make_print_state ();
686 pstate
= SCM_PRINT_STATE (print_state
);
687 pstate
->writingp
= 1;
690 /* First find out if it's reasonable to do indentation. */
698 frame
= scm_stack_ref (a
->stack
, scm_from_int (beg
));
699 for (i
= 0, j
= 0; i
< n
; ++i
)
701 if (SCM_FRAME_REAL_P (frame
))
703 if (j
> SCM_BACKTRACE_INDENT
)
708 frame
= (SCM_BACKWARDS_P
709 ? SCM_FRAME_PREV (frame
)
710 : SCM_FRAME_NEXT (frame
));
714 /* Determine size of frame number field. */
715 j
= SCM_FRAME_NUMBER (scm_stack_ref (a
->stack
, scm_from_int (end
)));
716 for (i
= 0; j
> 0; ++i
) j
/= 10;
720 frame
= scm_stack_ref (a
->stack
, scm_from_int (beg
));
722 last_file
= SCM_UNDEFINED
;
723 for (i
= 0; i
< n
; ++i
)
725 if (!SCM_EQ_P (SCM_PACK (SCM_SHOW_FILE_NAME
), sym_base
))
726 display_backtrace_file (frame
, &last_file
, a
->port
, pstate
);
728 display_frame (frame
, nfield
, indentation
, sport
, a
->port
, pstate
);
729 if (indent_p
&& SCM_FRAME_EVAL_ARGS_P (frame
))
731 frame
= (SCM_BACKWARDS_P
?
732 SCM_FRAME_PREV (frame
) : SCM_FRAME_NEXT (frame
));
735 scm_remember_upto_here_1 (print_state
);
737 return SCM_UNSPECIFIED
;
741 SCM_DEFINE (scm_display_backtrace
, "display-backtrace", 2, 2, 0,
742 (SCM stack
, SCM port
, SCM first
, SCM depth
),
743 "Display a backtrace to the output port @var{port}. @var{stack}\n"
744 "is the stack to take the backtrace from, @var{first} specifies\n"
745 "where in the stack to start and @var{depth} how much frames\n"
746 "to display. Both @var{first} and @var{depth} can be @code{#f},\n"
747 "which means that default values will be used.")
748 #define FUNC_NAME s_scm_display_backtrace
750 struct display_backtrace_args a
;
751 struct display_error_handler_data data
;
756 data
.mode
= "backtrace";
758 scm_internal_catch (SCM_BOOL_T
,
759 (scm_t_catch_body
) display_backtrace_body
, &a
,
760 (scm_t_catch_handler
) display_error_handler
, &data
);
761 return SCM_UNSPECIFIED
;
765 SCM_VARIABLE (scm_has_shown_backtrace_hint_p_var
, "has-shown-backtrace-hint?");
767 SCM_DEFINE (scm_backtrace
, "backtrace", 0, 0, 0,
769 "Display a backtrace of the stack saved by the last error\n"
770 "to the current output port.")
771 #define FUNC_NAME s_scm_backtrace
774 scm_fluid_ref (SCM_VARIABLE_REF (scm_the_last_stack_fluid_var
));
775 if (scm_is_true (the_last_stack
))
777 scm_newline (scm_cur_outp
);
778 scm_puts ("Backtrace:\n", scm_cur_outp
);
779 scm_display_backtrace (the_last_stack
,
783 scm_newline (scm_cur_outp
);
784 if (scm_is_false (SCM_VARIABLE_REF (scm_has_shown_backtrace_hint_p_var
))
787 scm_puts ("Type \"(debug-enable 'backtrace)\" if you would like "
789 "automatically if an error occurs in the future.\n",
791 SCM_VARIABLE_SET (scm_has_shown_backtrace_hint_p_var
, SCM_BOOL_T
);
796 scm_puts ("No backtrace available.\n", scm_cur_outp
);
798 return SCM_UNSPECIFIED
;
805 scm_init_backtrace ()
807 SCM f
= scm_make_fluid ();
808 scm_the_last_stack_fluid_var
= scm_c_define ("the-last-stack", f
);
810 #include "libguile/backtrace.x"