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