1 /* GDB/Scheme exception support.
3 Copyright (C) 2014 Free Software Foundation, Inc.
5 This file is part of GDB.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 /* See README file in this directory for implementation notes, coding
21 conventions, et.al. */
25 IWBN to support SRFI 34/35. At the moment we follow Guile's own
28 The non-static functions in this file have prefix gdbscm_ and
29 not exscm_ on purpose. */
33 #include "gdb_assert.h"
34 #include "guile-internal.h"
36 /* The <gdb:exception> smob.
37 This is used to record and handle Scheme exceptions.
38 One important invariant is that <gdb:exception> smobs are never a valid
39 result of a function, other than to signify an exception occurred. */
43 /* This always appears first. */
46 /* The key and args parameters to "throw". */
51 static const char exception_smob_name[] = "gdb:exception";
53 /* The tag Guile knows the exception smob by. */
54 static scm_t_bits exception_smob_tag;
56 /* A generic error in struct gdb_exception.
57 I.e., not RETURN_QUIT and not MEMORY_ERROR. */
58 static SCM error_symbol;
60 /* An error occurred accessing inferior memory.
61 This is not a Scheme programming error. */
62 static SCM memory_error_symbol;
64 /* User interrupt, e.g., RETURN_QUIT in struct gdb_exception. */
65 static SCM signal_symbol;
67 /* Printing the stack is done by first capturing the stack and recording it in
68 a <gdb:exception> object with this key and with the ARGS field set to
69 (cons real-key (cons stack real-args)).
70 See gdbscm_make_exception_with_stack. */
71 static SCM with_stack_error_symbol;
73 /* The key to use for an invalid object exception. An invalid object is one
74 where the underlying object has been removed from GDB. */
75 SCM gdbscm_invalid_object_error_symbol;
77 /* Values for "guile print-stack" as symbols. */
78 static SCM none_symbol;
79 static SCM message_symbol;
80 static SCM full_symbol;
82 static const char percent_print_exception_message_name[] =
83 "%print-exception-message";
85 /* Variable containing %print-exception-message.
86 It is not defined until late in initialization, after our init routine
87 has run. Cope by looking it up lazily. */
88 static SCM percent_print_exception_message_var = SCM_BOOL_F;
90 static const char percent_print_exception_with_stack_name[] =
91 "%print-exception-with-stack";
93 /* Variable containing %print-exception-with-stack.
94 It is not defined until late in initialization, after our init routine
95 has run. Cope by looking it up lazily. */
96 static SCM percent_print_exception_with_stack_var = SCM_BOOL_F;
98 /* Counter to keep track of the number of times we create a <gdb:exception>
99 object, for performance monitoring purposes. */
100 static unsigned long gdbscm_exception_count = 0;
102 /* Administrivia for exception smobs. */
104 /* The smob "print" function for <gdb:exception>. */
107 exscm_print_exception_smob (SCM self, SCM port, scm_print_state *pstate)
109 exception_smob *e_smob = (exception_smob *) SCM_SMOB_DATA (self);
111 gdbscm_printf (port, "#<%s ", exception_smob_name);
112 scm_write (e_smob->key, port);
113 scm_puts (" ", port);
114 scm_write (e_smob->args, port);
115 scm_puts (">", port);
117 scm_remember_upto_here_1 (self);
119 /* Non-zero means success. */
123 /* (make-exception key args) -> <gdb:exception> */
126 gdbscm_make_exception (SCM key, SCM args)
128 exception_smob *e_smob = (exception_smob *)
129 scm_gc_malloc (sizeof (exception_smob), exception_smob_name);
134 smob = scm_new_smob (exception_smob_tag, (scm_t_bits) e_smob);
135 gdbscm_init_gsmob (&e_smob->base);
137 ++gdbscm_exception_count;
142 /* Return non-zero if SCM is a <gdb:exception> object. */
145 gdbscm_is_exception (SCM scm)
147 return SCM_SMOB_PREDICATE (exception_smob_tag, scm);
150 /* (exception? scm) -> boolean */
153 gdbscm_exception_p (SCM scm)
155 return scm_from_bool (gdbscm_is_exception (scm));
158 /* (exception-key <gdb:exception>) -> key */
161 gdbscm_exception_key (SCM self)
163 exception_smob *e_smob;
165 SCM_ASSERT_TYPE (gdbscm_is_exception (self), self, SCM_ARG1, FUNC_NAME,
168 e_smob = (exception_smob *) SCM_SMOB_DATA (self);
172 /* (exception-args <gdb:exception>) -> arg-list */
175 gdbscm_exception_args (SCM self)
177 exception_smob *e_smob;
179 SCM_ASSERT_TYPE (gdbscm_is_exception (self), self, SCM_ARG1, FUNC_NAME,
182 e_smob = (exception_smob *) SCM_SMOB_DATA (self);
186 /* Wrap an exception in a <gdb:exception> object that includes STACK.
187 gdbscm_print_exception_with_stack knows how to unwrap it. */
190 gdbscm_make_exception_with_stack (SCM key, SCM args, SCM stack)
192 return gdbscm_make_exception (with_stack_error_symbol,
193 scm_cons (key, scm_cons (stack, args)));
196 /* Version of scm_error_scm that creates a gdb:exception object that can later
197 be passed to gdbscm_throw.
198 KEY is a symbol denoting the kind of error.
199 SUBR is either #f or a string marking the function in which the error
201 MESSAGE is either #f or the error message string. It may contain ~a and ~s
202 modifiers, provided by ARGS.
203 ARGS is a list of args to MESSAGE.
204 DATA is an arbitrary object, its value depends on KEY. The value to pass
205 here is a bit underspecified by Guile. */
208 gdbscm_make_error_scm (SCM key, SCM subr, SCM message, SCM args, SCM data)
210 return gdbscm_make_exception (key, scm_list_4 (subr, message, args, data));
213 /* Version of scm_error that creates a gdb:exception object that can later
214 be passed to gdbscm_throw.
215 See gdbscm_make_error_scm for a description of the arguments. */
218 gdbscm_make_error (SCM key, const char *subr, const char *message,
221 return gdbscm_make_error_scm
223 subr == NULL ? SCM_BOOL_F : scm_from_latin1_string (subr),
224 message == NULL ? SCM_BOOL_F : scm_from_latin1_string (message),
228 /* Version of SCM_ASSERT_TYPE/scm_wrong_type_arg_msg that creates a
229 gdb:exception object that can later be passed to gdbscm_throw. */
232 gdbscm_make_type_error (const char *subr, int arg_pos, SCM bad_value,
233 const char *expected_type)
240 if (expected_type != NULL)
242 msg = xstrprintf (_("Wrong type argument in position %d"
243 " (expecting %s): ~S"),
244 arg_pos, expected_type);
248 msg = xstrprintf (_("Wrong type argument in position %d: ~S"),
254 if (expected_type != NULL)
256 msg = xstrprintf (_("Wrong type argument (expecting %s): ~S"),
260 msg = xstrprintf (_("Wrong type argument: ~S"));
263 result = gdbscm_make_error (scm_arg_type_key, subr, msg,
264 scm_list_1 (bad_value), scm_list_1 (bad_value));
269 /* A variant of gdbscm_make_type_error for non-type argument errors.
270 ERROR_PREFIX and ERROR are combined to build the error message.
271 Care needs to be taken so that the i18n composed form is still
272 reasonable, but no one is going to translate these anyway so we don't
274 ERROR_PREFIX may be NULL, ERROR may not be NULL. */
277 gdbscm_make_arg_error (SCM key, const char *subr, int arg_pos, SCM bad_value,
278 const char *error_prefix, const char *error)
283 if (error_prefix != NULL)
287 msg = xstrprintf (_("%s %s in position %d: ~S"),
288 error_prefix, error, arg_pos);
291 msg = xstrprintf (_("%s %s: ~S"), error_prefix, error);
296 msg = xstrprintf (_("%s in position %d: ~S"), error, arg_pos);
298 msg = xstrprintf (_("%s: ~S"), error);
301 result = gdbscm_make_error (key, subr, msg,
302 scm_list_1 (bad_value), scm_list_1 (bad_value));
307 /* Make an invalid-object error <gdb:exception> object.
308 OBJECT is the name of the kind of object that is invalid. */
311 gdbscm_make_invalid_object_error (const char *subr, int arg_pos, SCM bad_value,
314 return gdbscm_make_arg_error (gdbscm_invalid_object_error_symbol,
315 subr, arg_pos, bad_value,
316 _("Invalid object:"), object);
319 /* Throw an invalid-object error.
320 OBJECT is the name of the kind of object that is invalid. */
323 gdbscm_invalid_object_error (const char *subr, int arg_pos, SCM bad_value,
327 = gdbscm_make_invalid_object_error (subr, arg_pos, bad_value, object);
329 gdbscm_throw (exception);
332 /* Make an out-of-range error <gdb:exception> object. */
335 gdbscm_make_out_of_range_error (const char *subr, int arg_pos, SCM bad_value,
338 return gdbscm_make_arg_error (scm_out_of_range_key,
339 subr, arg_pos, bad_value,
340 _("Out of range:"), error);
343 /* Throw an out-of-range error.
344 This is the standard Guile out-of-range exception. */
347 gdbscm_out_of_range_error (const char *subr, int arg_pos, SCM bad_value,
351 = gdbscm_make_out_of_range_error (subr, arg_pos, bad_value, error);
353 gdbscm_throw (exception);
356 /* Make a misc-error <gdb:exception> object. */
359 gdbscm_make_misc_error (const char *subr, int arg_pos, SCM bad_value,
362 return gdbscm_make_arg_error (scm_misc_error_key,
363 subr, arg_pos, bad_value, NULL, error);
366 /* Return a <gdb:exception> object for gdb:memory-error. */
369 gdbscm_make_memory_error (const char *subr, const char *msg, SCM args)
371 return gdbscm_make_error (memory_error_symbol, subr, msg, args,
375 /* Throw a gdb:memory-error exception. */
378 gdbscm_memory_error (const char *subr, const char *msg, SCM args)
380 SCM exception = gdbscm_make_memory_error (subr, msg, args);
382 gdbscm_throw (exception);
385 /* Return non-zero if KEY is gdb:memory-error.
386 Note: This is an excp_matcher_func function. */
389 gdbscm_memory_error_p (SCM key)
391 return scm_is_eq (key, memory_error_symbol);
394 /* Wrapper around scm_throw to throw a gdb:exception.
395 This function does not return.
396 This function cannot be called from inside TRY_CATCH. */
399 gdbscm_throw (SCM exception)
401 scm_throw (gdbscm_exception_key (exception),
402 gdbscm_exception_args (exception));
403 gdb_assert_not_reached ("scm_throw returned");
406 /* Convert a GDB exception to a <gdb:exception> object. */
409 gdbscm_scm_from_gdb_exception (struct gdb_exception exception)
413 if (exception.reason == RETURN_QUIT)
415 /* Handle this specially to be consistent with top-repl.scm. */
416 return gdbscm_make_error (signal_symbol, NULL, _("User interrupt"),
417 SCM_EOL, scm_list_1 (scm_from_int (SIGINT)));
420 if (exception.error == MEMORY_ERROR)
421 key = memory_error_symbol;
425 return gdbscm_make_error (key, NULL, "~A",
426 scm_list_1 (gdbscm_scm_from_c_string
427 (exception.message)),
431 /* Convert a GDB exception to the appropriate Scheme exception and throw it.
432 This function does not return. */
435 gdbscm_throw_gdb_exception (struct gdb_exception exception)
437 gdbscm_throw (gdbscm_scm_from_gdb_exception (exception));
440 /* Print the error message portion of an exception.
441 If PORT is #f, use the standard error port.
442 KEY cannot be gdb:with-stack.
444 Basically this function is just a wrapper around calling
445 %print-exception-message. */
448 gdbscm_print_exception_message (SCM port, SCM frame, SCM key, SCM args)
452 if (gdbscm_is_false (port))
453 port = scm_current_error_port ();
455 gdb_assert (!scm_is_eq (key, with_stack_error_symbol));
457 /* This does not use scm_print_exception because we tweak the output a bit.
458 Compare Guile's print-exception with our %print-exception-message for
460 if (gdbscm_is_false (percent_print_exception_message_var))
462 percent_print_exception_message_var
463 = scm_c_private_variable (gdbscm_init_module_name,
464 percent_print_exception_message_name);
465 /* If we can't find %print-exception-message, there's a problem on the
466 Scheme side. Don't kill GDB, just flag an error and leave it at
468 if (gdbscm_is_false (percent_print_exception_message_var))
470 gdbscm_printf (port, _("Error in Scheme exception printing,"
471 " can't find %s.\n"),
472 percent_print_exception_message_name);
476 printer = scm_variable_ref (percent_print_exception_message_var);
478 status = gdbscm_safe_call_4 (printer, port, frame, key, args, NULL);
480 /* If that failed still tell the user something.
481 But don't use the exception printing machinery! */
482 if (gdbscm_is_exception (status))
484 gdbscm_printf (port, _("Error in Scheme exception printing:\n"));
485 scm_display (status, port);
490 /* Print the description of exception KEY, ARGS to PORT, according to the
491 setting of "set guile print-stack".
492 If PORT is #f, use the standard error port.
493 If STACK is #f, never print the stack, regardless of whether printing it
494 is enabled. If STACK is #t, then print it if it is contained in ARGS
495 (i.e., KEY is gdb:with-stack). Otherwise STACK is the result of calling
496 scm_make_stack (which will be ignored in favor of the stack in ARGS if
497 KEY is gdb:with-stack).
498 KEY, ARGS are the standard arguments to scm_throw, et.al.
500 Basically this function is just a wrapper around calling
501 %print-exception-with-args. */
504 gdbscm_print_exception_with_stack (SCM port, SCM stack, SCM key, SCM args)
508 if (gdbscm_is_false (port))
509 port = scm_current_error_port ();
511 if (gdbscm_is_false (percent_print_exception_with_stack_var))
513 percent_print_exception_with_stack_var
514 = scm_c_private_variable (gdbscm_init_module_name,
515 percent_print_exception_with_stack_name);
516 /* If we can't find %print-exception-with-args, there's a problem on the
517 Scheme side. Don't kill GDB, just flag an error and leave it at
519 if (gdbscm_is_false (percent_print_exception_with_stack_var))
521 gdbscm_printf (port, _("Error in Scheme exception printing,"
522 " can't find %s.\n"),
523 percent_print_exception_with_stack_name);
527 printer = scm_variable_ref (percent_print_exception_with_stack_var);
529 status = gdbscm_safe_call_4 (printer, port, stack, key, args, NULL);
531 /* If that failed still tell the user something.
532 But don't use the exception printing machinery! */
533 if (gdbscm_is_exception (status))
535 gdbscm_printf (port, _("Error in Scheme exception printing:\n"));
536 scm_display (status, port);
541 /* Print EXCEPTION, a <gdb:exception> object, to PORT.
542 If PORT is #f, use the standard error port. */
545 gdbscm_print_gdb_exception (SCM port, SCM exception)
547 gdb_assert (gdbscm_is_exception (exception));
549 gdbscm_print_exception_with_stack (port, SCM_BOOL_T,
550 gdbscm_exception_key (exception),
551 gdbscm_exception_args (exception));
554 /* Return a string description of <gdb:exception> EXCEPTION.
555 If EXCEPTION is a gdb:with-stack exception, unwrap it, a backtrace
556 is never returned as part of the result.
558 Space for the result is malloc'd, the caller must free. */
561 gdbscm_exception_message_to_string (SCM exception)
563 SCM port = scm_open_output_string ();
567 gdb_assert (gdbscm_is_exception (exception));
569 key = gdbscm_exception_key (exception);
570 args = gdbscm_exception_args (exception);
572 if (scm_is_eq (key, with_stack_error_symbol)
573 /* Don't crash on a badly generated gdb:with-stack exception. */
574 && scm_is_pair (args)
575 && scm_is_pair (scm_cdr (args)))
577 key = scm_car (args);
578 args = scm_cddr (args);
581 gdbscm_print_exception_message (port, SCM_BOOL_F, key, args);
582 result = gdbscm_scm_to_c_string (scm_get_output_string (port));
583 scm_close_port (port);
588 /* Return the value of the "guile print-stack" option as one of:
589 'none, 'message, 'full. */
592 gdbscm_percent_exception_print_style (void)
594 if (gdbscm_print_excp == gdbscm_print_excp_none)
596 if (gdbscm_print_excp == gdbscm_print_excp_message)
597 return message_symbol;
598 if (gdbscm_print_excp == gdbscm_print_excp_full)
600 gdb_assert_not_reached ("bad value for \"guile print-stack\"");
603 /* Return the current <gdb:exception> counter.
604 This is for debugging purposes. */
607 gdbscm_percent_exception_count (void)
609 return scm_from_ulong (gdbscm_exception_count);
612 /* Initialize the Scheme exception support. */
614 static const scheme_function exception_functions[] =
616 { "make-exception", 2, 0, 0, gdbscm_make_exception,
618 Create a <gdb:exception> object.\n\
620 Arguments: key args\n\
621 These are the standard key,args arguments of \"throw\"." },
623 { "exception?", 1, 0, 0, gdbscm_exception_p,
625 Return #t if the object is a <gdb:exception> object." },
627 { "exception-key", 1, 0, 0, gdbscm_exception_key,
629 Return the exception's key." },
631 { "exception-args", 1, 0, 0, gdbscm_exception_args,
633 Return the exception's arg list." },
638 static const scheme_function private_exception_functions[] =
640 { "%exception-print-style", 0, 0, 0, gdbscm_percent_exception_print_style,
642 Return the value of the \"guile print-stack\" option." },
644 { "%exception-count", 0, 0, 0, gdbscm_percent_exception_count,
646 Return a count of the number of <gdb:exception> objects created.\n\
647 This is for debugging purposes." },
653 gdbscm_initialize_exceptions (void)
655 exception_smob_tag = gdbscm_make_smob_type (exception_smob_name,
656 sizeof (exception_smob));
657 scm_set_smob_print (exception_smob_tag, exscm_print_exception_smob);
659 gdbscm_define_functions (exception_functions, 1);
660 gdbscm_define_functions (private_exception_functions, 0);
662 error_symbol = scm_from_latin1_symbol ("gdb:error");
664 memory_error_symbol = scm_from_latin1_symbol ("gdb:memory-error");
666 gdbscm_invalid_object_error_symbol
667 = scm_from_latin1_symbol ("gdb:invalid-object-error");
669 with_stack_error_symbol = scm_from_latin1_symbol ("gdb:with-stack");
671 /* The text of this symbol is taken from Guile's top-repl.scm. */
672 signal_symbol = scm_from_latin1_symbol ("signal");
674 none_symbol = scm_from_latin1_symbol ("none");
675 message_symbol = scm_from_latin1_symbol ("message");
676 full_symbol = scm_from_latin1_symbol ("full");