Home | History | Annotate | Line # | Download | only in guile
      1 /* GDB/Scheme exception support.
      2 
      3    Copyright (C) 2014-2024 Free Software Foundation, Inc.
      4 
      5    This file is part of GDB.
      6 
      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.
     11 
     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.
     16 
     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/>.  */
     19 
     20 /* See README file in this directory for implementation notes, coding
     21    conventions, et.al.  */
     22 
     23 /* Notes:
     24 
     25    IWBN to support SRFI 34/35.  At the moment we follow Guile's own
     26    exception mechanism.
     27 
     28    The non-static functions in this file have prefix gdbscm_ and
     29    not exscm_ on purpose.  */
     30 
     31 #include <signal.h>
     32 #include "guile-internal.h"
     33 
     34 /* The <gdb:exception> smob.
     35    This is used to record and handle Scheme exceptions.
     36    One important invariant is that <gdb:exception> smobs are never a valid
     37    result of a function, other than to signify an exception occurred.  */
     38 
     39 struct exception_smob
     40 {
     41   /* This always appears first.  */
     42   gdb_smob base;
     43 
     44   /* The key and args parameters to "throw".  */
     45   SCM key;
     46   SCM args;
     47 };
     48 
     49 static const char exception_smob_name[] = "gdb:exception";
     50 
     51 /* The tag Guile knows the exception smob by.  */
     52 static scm_t_bits exception_smob_tag;
     53 
     54 /* A generic error in struct gdb_exception.
     55    I.e., not RETURN_QUIT and not MEMORY_ERROR.  */
     56 static SCM error_symbol;
     57 
     58 /* An error occurred accessing inferior memory.
     59    This is not a Scheme programming error.  */
     60 static SCM memory_error_symbol;
     61 
     62 /* User interrupt, e.g., RETURN_QUIT in struct gdb_exception.  */
     63 static SCM signal_symbol;
     64 
     65 /* A user error, e.g., bad arg to gdb command.  */
     66 static SCM user_error_symbol;
     67 
     68 /* Printing the stack is done by first capturing the stack and recording it in
     69    a <gdb:exception> object with this key and with the ARGS field set to
     70    (cons real-key (cons stack real-args)).
     71    See gdbscm_make_exception_with_stack.  */
     72 static SCM with_stack_error_symbol;
     73 
     74 /* The key to use for an invalid object exception.  An invalid object is one
     75    where the underlying object has been removed from GDB.  */
     76 SCM gdbscm_invalid_object_error_symbol;
     77 
     78 /* Values for "guile print-stack" as symbols.  */
     79 static SCM none_symbol;
     80 static SCM message_symbol;
     81 static SCM full_symbol;
     82 
     83 static const char percent_print_exception_message_name[] =
     84   "%print-exception-message";
     85 
     86 /* Variable containing %print-exception-message.
     87    It is not defined until late in initialization, after our init routine
     88    has run.  Cope by looking it up lazily.  */
     89 static SCM percent_print_exception_message_var = SCM_BOOL_F;
     90 
     91 static const char percent_print_exception_with_stack_name[] =
     92   "%print-exception-with-stack";
     93 
     94 /* Variable containing %print-exception-with-stack.
     95    It is not defined until late in initialization, after our init routine
     96    has run.  Cope by looking it up lazily.  */
     97 static SCM percent_print_exception_with_stack_var = SCM_BOOL_F;
     98 
     99 /* Counter to keep track of the number of times we create a <gdb:exception>
    100    object, for performance monitoring purposes.  */
    101 static unsigned long gdbscm_exception_count = 0;
    102 
    103 /* Administrivia for exception smobs.  */
    105 
    106 /* The smob "print" function for <gdb:exception>.  */
    107 
    108 static int
    109 exscm_print_exception_smob (SCM self, SCM port, scm_print_state *pstate)
    110 {
    111   exception_smob *e_smob = (exception_smob *) SCM_SMOB_DATA (self);
    112 
    113   gdbscm_printf (port, "#<%s ", exception_smob_name);
    114   scm_write (e_smob->key, port);
    115   scm_puts (" ", port);
    116   scm_write (e_smob->args, port);
    117   scm_puts (">", port);
    118 
    119   scm_remember_upto_here_1 (self);
    120 
    121   /* Non-zero means success.  */
    122   return 1;
    123 }
    124 
    125 /* (make-exception key args) -> <gdb:exception> */
    126 
    127 SCM
    128 gdbscm_make_exception (SCM key, SCM args)
    129 {
    130   exception_smob *e_smob = (exception_smob *)
    131     scm_gc_malloc (sizeof (exception_smob), exception_smob_name);
    132   SCM smob;
    133 
    134   e_smob->key = key;
    135   e_smob->args = args;
    136   smob = scm_new_smob (exception_smob_tag, (scm_t_bits) e_smob);
    137   gdbscm_init_gsmob (&e_smob->base);
    138 
    139   ++gdbscm_exception_count;
    140 
    141   return smob;
    142 }
    143 
    144 /* Return non-zero if SCM is a <gdb:exception> object.  */
    145 
    146 int
    147 gdbscm_is_exception (SCM scm)
    148 {
    149   return SCM_SMOB_PREDICATE (exception_smob_tag, scm);
    150 }
    151 
    152 /* (exception? scm) -> boolean */
    153 
    154 static SCM
    155 gdbscm_exception_p (SCM scm)
    156 {
    157   return scm_from_bool (gdbscm_is_exception (scm));
    158 }
    159 
    160 /* (exception-key <gdb:exception>) -> key */
    161 
    162 SCM
    163 gdbscm_exception_key (SCM self)
    164 {
    165   exception_smob *e_smob;
    166 
    167   SCM_ASSERT_TYPE (gdbscm_is_exception (self), self, SCM_ARG1, FUNC_NAME,
    168 		   "gdb:exception");
    169 
    170   e_smob = (exception_smob *) SCM_SMOB_DATA (self);
    171   return e_smob->key;
    172 }
    173 
    174 /* (exception-args <gdb:exception>) -> arg-list */
    175 
    176 SCM
    177 gdbscm_exception_args (SCM self)
    178 {
    179   exception_smob *e_smob;
    180 
    181   SCM_ASSERT_TYPE (gdbscm_is_exception (self), self, SCM_ARG1, FUNC_NAME,
    182 		   "gdb:exception");
    183 
    184   e_smob = (exception_smob *) SCM_SMOB_DATA (self);
    185   return e_smob->args;
    186 }
    187 
    188 /* Wrap an exception in a <gdb:exception> object that includes STACK.
    190    gdbscm_print_exception_with_stack knows how to unwrap it.  */
    191 
    192 SCM
    193 gdbscm_make_exception_with_stack (SCM key, SCM args, SCM stack)
    194 {
    195   return gdbscm_make_exception (with_stack_error_symbol,
    196 				scm_cons (key, scm_cons (stack, args)));
    197 }
    198 
    199 /* Version of scm_error_scm that creates a gdb:exception object that can later
    200    be passed to gdbscm_throw.
    201    KEY is a symbol denoting the kind of error.
    202    SUBR is either #f or a string marking the function in which the error
    203    occurred.
    204    MESSAGE is either #f or the error message string.  It may contain ~a and ~s
    205    modifiers, provided by ARGS.
    206    ARGS is a list of args to MESSAGE.
    207    DATA is an arbitrary object, its value depends on KEY.  The value to pass
    208    here is a bit underspecified by Guile.  */
    209 
    210 SCM
    211 gdbscm_make_error_scm (SCM key, SCM subr, SCM message, SCM args, SCM data)
    212 {
    213   return gdbscm_make_exception (key, scm_list_4 (subr, message, args, data));
    214 }
    215 
    216 /* Version of scm_error that creates a gdb:exception object that can later
    217    be passed to gdbscm_throw.
    218    See gdbscm_make_error_scm for a description of the arguments.  */
    219 
    220 SCM
    221 gdbscm_make_error (SCM key, const char *subr, const char *message,
    222 		   SCM args, SCM data)
    223 {
    224   return gdbscm_make_error_scm
    225     (key,
    226      subr == NULL ? SCM_BOOL_F : scm_from_latin1_string (subr),
    227      message == NULL ? SCM_BOOL_F : scm_from_latin1_string (message),
    228      args, data);
    229 }
    230 
    231 /* Version of SCM_ASSERT_TYPE/scm_wrong_type_arg_msg that creates a
    232    gdb:exception object that can later be passed to gdbscm_throw.  */
    233 
    234 SCM
    235 gdbscm_make_type_error (const char *subr, int arg_pos, SCM bad_value,
    236 			const char *expected_type)
    237 {
    238   gdb::unique_xmalloc_ptr<char> msg;
    239   SCM result;
    240 
    241   if (arg_pos > 0)
    242     {
    243       if (expected_type != NULL)
    244 	{
    245 	  msg = xstrprintf (_("Wrong type argument in position %d"
    246 			      " (expecting %s): ~S"),
    247 			    arg_pos, expected_type);
    248 	}
    249       else
    250 	{
    251 	  msg = xstrprintf (_("Wrong type argument in position %d: ~S"),
    252 			    arg_pos);
    253 	}
    254     }
    255   else
    256     {
    257       if (expected_type != NULL)
    258 	{
    259 	  msg = xstrprintf (_("Wrong type argument (expecting %s): ~S"),
    260 			    expected_type);
    261 	}
    262       else
    263 	msg = xstrprintf (_("Wrong type argument: ~S"));
    264     }
    265 
    266   result = gdbscm_make_error (scm_arg_type_key, subr, msg.get (),
    267 			      scm_list_1 (bad_value), scm_list_1 (bad_value));
    268   return result;
    269 }
    270 
    271 /* A variant of gdbscm_make_type_error for non-type argument errors.
    272    ERROR_PREFIX and ERROR are combined to build the error message.
    273    Care needs to be taken so that the i18n composed form is still
    274    reasonable, but no one is going to translate these anyway so we don't
    275    worry too much.
    276    ERROR_PREFIX may be NULL, ERROR may not be NULL.  */
    277 
    278 static SCM
    279 gdbscm_make_arg_error (SCM key, const char *subr, int arg_pos, SCM bad_value,
    280 		       const char *error_prefix, const char *error)
    281 {
    282   gdb::unique_xmalloc_ptr<char> msg;
    283   SCM result;
    284 
    285   if (error_prefix != NULL)
    286     {
    287       if (arg_pos > 0)
    288 	{
    289 	  msg = xstrprintf (_("%s %s in position %d: ~S"),
    290 			    error_prefix, error, arg_pos);
    291 	}
    292       else
    293 	msg = xstrprintf (_("%s %s: ~S"), error_prefix, error);
    294     }
    295   else
    296     {
    297       if (arg_pos > 0)
    298 	msg = xstrprintf (_("%s in position %d: ~S"), error, arg_pos);
    299       else
    300 	msg = xstrprintf (_("%s: ~S"), error);
    301     }
    302 
    303   result = gdbscm_make_error (key, subr, msg.get (), scm_list_1 (bad_value),
    304 			      scm_list_1 (bad_value));
    305   return result;
    306 }
    307 
    308 /* Make an invalid-object error <gdb:exception> object.
    309    OBJECT is the name of the kind of object that is invalid.  */
    310 
    311 SCM
    312 gdbscm_make_invalid_object_error (const char *subr, int arg_pos, SCM bad_value,
    313 				  const char *object)
    314 {
    315   return gdbscm_make_arg_error (gdbscm_invalid_object_error_symbol,
    316 				subr, arg_pos, bad_value,
    317 				_("Invalid object:"), object);
    318 }
    319 
    320 /* Throw an invalid-object error.
    321    OBJECT is the name of the kind of object that is invalid.  */
    322 
    323 void
    324 gdbscm_invalid_object_error (const char *subr, int arg_pos, SCM bad_value,
    325 			     const char *object)
    326 {
    327   SCM exception
    328     = gdbscm_make_invalid_object_error (subr, arg_pos, bad_value, object);
    329 
    330   gdbscm_throw (exception);
    331 }
    332 
    333 /* Make an out-of-range error <gdb:exception> object.  */
    334 
    335 SCM
    336 gdbscm_make_out_of_range_error (const char *subr, int arg_pos, SCM bad_value,
    337 				const char *error)
    338 {
    339   return gdbscm_make_arg_error (scm_out_of_range_key,
    340 				subr, arg_pos, bad_value,
    341 				_("Out of range:"), error);
    342 }
    343 
    344 /* Throw an out-of-range error.
    345    This is the standard Guile out-of-range exception.  */
    346 
    347 void
    348 gdbscm_out_of_range_error (const char *subr, int arg_pos, SCM bad_value,
    349 			   const char *error)
    350 {
    351   SCM exception
    352     = gdbscm_make_out_of_range_error (subr, arg_pos, bad_value, error);
    353 
    354   gdbscm_throw (exception);
    355 }
    356 
    357 /* Make a misc-error <gdb:exception> object.  */
    358 
    359 SCM
    360 gdbscm_make_misc_error (const char *subr, int arg_pos, SCM bad_value,
    361 			const char *error)
    362 {
    363   return gdbscm_make_arg_error (scm_misc_error_key,
    364 				subr, arg_pos, bad_value, NULL, error);
    365 }
    366 
    367 /* Throw a misc-error error.  */
    368 
    369 void
    370 gdbscm_misc_error (const char *subr, int arg_pos, SCM bad_value,
    371 		   const char *error)
    372 {
    373   SCM exception = gdbscm_make_misc_error (subr, arg_pos, bad_value, error);
    374 
    375   gdbscm_throw (exception);
    376 }
    377 
    378 /* Return a <gdb:exception> object for gdb:memory-error.  */
    379 
    380 SCM
    381 gdbscm_make_memory_error (const char *subr, const char *msg, SCM args)
    382 {
    383   return gdbscm_make_error (memory_error_symbol, subr, msg, args,
    384 			    SCM_EOL);
    385 }
    386 
    387 /* Throw a gdb:memory-error exception.  */
    388 
    389 void
    390 gdbscm_memory_error (const char *subr, const char *msg, SCM args)
    391 {
    392   SCM exception = gdbscm_make_memory_error (subr, msg, args);
    393 
    394   gdbscm_throw (exception);
    395 }
    396 
    397 /* Return non-zero if KEY is gdb:memory-error.
    398    Note: This is an excp_matcher_func function.  */
    399 
    400 int
    401 gdbscm_memory_error_p (SCM key)
    402 {
    403   return scm_is_eq (key, memory_error_symbol);
    404 }
    405 
    406 /* Return non-zero if KEY is gdb:user-error.
    407    Note: This is an excp_matcher_func function.  */
    408 
    409 int
    410 gdbscm_user_error_p (SCM key)
    411 {
    412   return scm_is_eq (key, user_error_symbol);
    413 }
    414 
    415 /* Wrapper around scm_throw to throw a gdb:exception.
    416    This function does not return.
    417    This function cannot be called from inside TRY_CATCH.  */
    418 
    419 void
    420 gdbscm_throw (SCM exception)
    421 {
    422   scm_throw (gdbscm_exception_key (exception),
    423 	     gdbscm_exception_args (exception));
    424   gdb_assert_not_reached ("scm_throw returned");
    425 }
    426 
    427 /* Convert a GDB exception to a <gdb:exception> object.  */
    428 
    429 SCM
    430 gdbscm_scm_from_gdb_exception (const gdbscm_gdb_exception &exception)
    431 {
    432   SCM key;
    433 
    434   if (exception.reason == RETURN_QUIT)
    435     {
    436       /* Handle this specially to be consistent with top-repl.scm.  */
    437       return gdbscm_make_error (signal_symbol, NULL, _("User interrupt"),
    438 				SCM_EOL, scm_list_1 (scm_from_int (SIGINT)));
    439     }
    440 
    441   if (exception.error == MEMORY_ERROR)
    442     key = memory_error_symbol;
    443   else
    444     key = error_symbol;
    445 
    446   return gdbscm_make_error (key, NULL, "~A",
    447 			    scm_list_1 (gdbscm_scm_from_c_string
    448 					(exception.message)),
    449 			    SCM_BOOL_F);
    450 }
    451 
    452 /* Convert a GDB exception to the appropriate Scheme exception and throw it.
    453    This function does not return.  */
    454 
    455 void
    456 gdbscm_throw_gdb_exception (gdbscm_gdb_exception exception)
    457 {
    458   SCM scm_exception = gdbscm_scm_from_gdb_exception (exception);
    459   xfree (exception.message);
    460   gdbscm_throw (scm_exception);
    461 }
    462 
    463 /* Print the error message portion of an exception.
    464    If PORT is #f, use the standard error port.
    465    KEY cannot be gdb:with-stack.
    466 
    467    Basically this function is just a wrapper around calling
    468    %print-exception-message.  */
    469 
    470 static void
    471 gdbscm_print_exception_message (SCM port, SCM frame, SCM key, SCM args)
    472 {
    473   SCM printer, status;
    474 
    475   if (gdbscm_is_false (port))
    476     port = scm_current_error_port ();
    477 
    478   gdb_assert (!scm_is_eq (key, with_stack_error_symbol));
    479 
    480   /* This does not use scm_print_exception because we tweak the output a bit.
    481      Compare Guile's print-exception with our %print-exception-message for
    482      details.  */
    483   if (gdbscm_is_false (percent_print_exception_message_var))
    484     {
    485       percent_print_exception_message_var
    486 	= scm_c_private_variable (gdbscm_init_module_name,
    487 				  percent_print_exception_message_name);
    488       /* If we can't find %print-exception-message, there's a problem on the
    489 	 Scheme side.  Don't kill GDB, just flag an error and leave it at
    490 	 that.  */
    491       if (gdbscm_is_false (percent_print_exception_message_var))
    492 	{
    493 	  gdbscm_printf (port, _("Error in Scheme exception printing,"
    494 				 " can't find %s.\n"),
    495 			 percent_print_exception_message_name);
    496 	  return;
    497 	}
    498     }
    499   printer = scm_variable_ref (percent_print_exception_message_var);
    500 
    501   status = gdbscm_safe_call_4 (printer, port, frame, key, args, NULL);
    502 
    503   /* If that failed still tell the user something.
    504      But don't use the exception printing machinery!  */
    505   if (gdbscm_is_exception (status))
    506     {
    507       gdbscm_printf (port, _("Error in Scheme exception printing:\n"));
    508       scm_display (status, port);
    509       scm_newline (port);
    510     }
    511 }
    512 
    513 /* Print the description of exception KEY, ARGS to PORT, according to the
    514    setting of "set guile print-stack".
    515    If PORT is #f, use the standard error port.
    516    If STACK is #f, never print the stack, regardless of whether printing it
    517    is enabled.  If STACK is #t, then print it if it is contained in ARGS
    518    (i.e., KEY is gdb:with-stack).  Otherwise STACK is the result of calling
    519    scm_make_stack (which will be ignored in favor of the stack in ARGS if
    520    KEY is gdb:with-stack).
    521    KEY, ARGS are the standard arguments to scm_throw, et.al.
    522 
    523    Basically this function is just a wrapper around calling
    524    %print-exception-with-stack.  */
    525 
    526 void
    527 gdbscm_print_exception_with_stack (SCM port, SCM stack, SCM key, SCM args)
    528 {
    529   SCM printer, status;
    530 
    531   if (gdbscm_is_false (port))
    532     port = scm_current_error_port ();
    533 
    534   if (gdbscm_is_false (percent_print_exception_with_stack_var))
    535     {
    536       percent_print_exception_with_stack_var
    537 	= scm_c_private_variable (gdbscm_init_module_name,
    538 				  percent_print_exception_with_stack_name);
    539       /* If we can't find %print-exception-with-stack, there's a problem on the
    540 	 Scheme side.  Don't kill GDB, just flag an error and leave it at
    541 	 that.  */
    542       if (gdbscm_is_false (percent_print_exception_with_stack_var))
    543 	{
    544 	  gdbscm_printf (port, _("Error in Scheme exception printing,"
    545 				 " can't find %s.\n"),
    546 			 percent_print_exception_with_stack_name);
    547 	  return;
    548 	}
    549     }
    550   printer = scm_variable_ref (percent_print_exception_with_stack_var);
    551 
    552   status = gdbscm_safe_call_4 (printer, port, stack, key, args, NULL);
    553 
    554   /* If that failed still tell the user something.
    555      But don't use the exception printing machinery!  */
    556   if (gdbscm_is_exception (status))
    557     {
    558       gdbscm_printf (port, _("Error in Scheme exception printing:\n"));
    559       scm_display (status, port);
    560       scm_newline (port);
    561     }
    562 }
    563 
    564 /* Print EXCEPTION, a <gdb:exception> object, to PORT.
    565    If PORT is #f, use the standard error port.  */
    566 
    567 void
    568 gdbscm_print_gdb_exception (SCM port, SCM exception)
    569 {
    570   gdb_assert (gdbscm_is_exception (exception));
    571 
    572   gdbscm_print_exception_with_stack (port, SCM_BOOL_T,
    573 				     gdbscm_exception_key (exception),
    574 				     gdbscm_exception_args (exception));
    575 }
    576 
    577 /* Return a string description of <gdb:exception> EXCEPTION.
    578    If EXCEPTION is a gdb:with-stack exception, unwrap it, a backtrace
    579    is never returned as part of the result.  */
    580 
    581 gdb::unique_xmalloc_ptr<char>
    582 gdbscm_exception_message_to_string (SCM exception)
    583 {
    584   SCM port = scm_open_output_string ();
    585   SCM key, args;
    586 
    587   gdb_assert (gdbscm_is_exception (exception));
    588 
    589   key = gdbscm_exception_key (exception);
    590   args = gdbscm_exception_args (exception);
    591 
    592   if (scm_is_eq (key, with_stack_error_symbol)
    593       /* Don't crash on a badly generated gdb:with-stack exception.  */
    594       && scm_is_pair (args)
    595       && scm_is_pair (scm_cdr (args)))
    596     {
    597       key = scm_car (args);
    598       args = scm_cddr (args);
    599     }
    600 
    601   gdbscm_print_exception_message (port, SCM_BOOL_F, key, args);
    602   gdb::unique_xmalloc_ptr<char> result
    603     = gdbscm_scm_to_c_string (scm_get_output_string (port));
    604   scm_close_port (port);
    605   return result;
    606 }
    607 
    608 /* Return the value of the "guile print-stack" option as one of:
    609    'none, 'message, 'full.  */
    610 
    611 static SCM
    612 gdbscm_percent_exception_print_style (void)
    613 {
    614   if (gdbscm_print_excp == gdbscm_print_excp_none)
    615     return none_symbol;
    616   if (gdbscm_print_excp == gdbscm_print_excp_message)
    617     return message_symbol;
    618   if (gdbscm_print_excp == gdbscm_print_excp_full)
    619     return full_symbol;
    620   gdb_assert_not_reached ("bad value for \"guile print-stack\"");
    621 }
    622 
    623 /* Return the current <gdb:exception> counter.
    624    This is for debugging purposes.  */
    625 
    626 static SCM
    627 gdbscm_percent_exception_count (void)
    628 {
    629   return scm_from_ulong (gdbscm_exception_count);
    630 }
    631 
    632 /* Initialize the Scheme exception support.  */
    634 
    635 static const scheme_function exception_functions[] =
    636 {
    637   { "make-exception", 2, 0, 0, as_a_scm_t_subr (gdbscm_make_exception),
    638     "\
    639 Create a <gdb:exception> object.\n\
    640 \n\
    641   Arguments: key args\n\
    642     These are the standard key,args arguments of \"throw\"." },
    643 
    644   { "exception?", 1, 0, 0, as_a_scm_t_subr (gdbscm_exception_p),
    645     "\
    646 Return #t if the object is a <gdb:exception> object." },
    647 
    648   { "exception-key", 1, 0, 0, as_a_scm_t_subr (gdbscm_exception_key),
    649     "\
    650 Return the exception's key." },
    651 
    652   { "exception-args", 1, 0, 0, as_a_scm_t_subr (gdbscm_exception_args),
    653     "\
    654 Return the exception's arg list." },
    655 
    656   END_FUNCTIONS
    657 };
    658 
    659 static const scheme_function private_exception_functions[] =
    660 {
    661   { "%exception-print-style", 0, 0, 0,
    662     as_a_scm_t_subr (gdbscm_percent_exception_print_style),
    663     "\
    664 Return the value of the \"guile print-stack\" option." },
    665 
    666   { "%exception-count", 0, 0, 0,
    667     as_a_scm_t_subr (gdbscm_percent_exception_count),
    668     "\
    669 Return a count of the number of <gdb:exception> objects created.\n\
    670 This is for debugging purposes." },
    671 
    672   END_FUNCTIONS
    673 };
    674 
    675 void
    676 gdbscm_initialize_exceptions (void)
    677 {
    678   exception_smob_tag = gdbscm_make_smob_type (exception_smob_name,
    679 					      sizeof (exception_smob));
    680   scm_set_smob_print (exception_smob_tag, exscm_print_exception_smob);
    681 
    682   gdbscm_define_functions (exception_functions, 1);
    683   gdbscm_define_functions (private_exception_functions, 0);
    684 
    685   error_symbol = scm_from_latin1_symbol ("gdb:error");
    686 
    687   memory_error_symbol = scm_from_latin1_symbol ("gdb:memory-error");
    688 
    689   user_error_symbol = scm_from_latin1_symbol ("gdb:user-error");
    690 
    691   gdbscm_invalid_object_error_symbol
    692     = scm_from_latin1_symbol ("gdb:invalid-object-error");
    693 
    694   with_stack_error_symbol = scm_from_latin1_symbol ("gdb:with-stack");
    695 
    696   /* The text of this symbol is taken from Guile's top-repl.scm.  */
    697   signal_symbol = scm_from_latin1_symbol ("signal");
    698 
    699   none_symbol = scm_from_latin1_symbol ("none");
    700   message_symbol = scm_from_latin1_symbol ("message");
    701   full_symbol = scm_from_latin1_symbol ("full");
    702 }
    703