[t][cage] Remove PGE-dependence from t/op/inf_nan.t since it is part of 'make coretest'
[parrot.git] / src / exceptions.c
blob2e712ea1fe4cd36c9aa984c3dedd2c0679665eb5
1 /*
2 Copyright (C) 2001-2009, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/exceptions.c - Exceptions
9 =head1 DESCRIPTION
11 Define the the core subsystem for exceptions.
13 =head2 Exception Functions
15 =over 4
17 =cut
21 #include "parrot/parrot.h"
22 #include "parrot/call.h"
23 #include "parrot/exceptions.h"
24 #include "exceptions.str"
25 #include "pmc/pmc_continuation.h"
26 #include "pmc/pmc_context.h"
28 /* HEADERIZER HFILE: include/parrot/exceptions.h */
30 /* HEADERIZER BEGIN: static */
31 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
33 PARROT_CANNOT_RETURN_NULL
34 static PMC * build_exception_from_args(PARROT_INTERP,
35 int ex_type,
36 ARGIN(const char *format),
37 va_list arglist)
38 __attribute__nonnull__(1)
39 __attribute__nonnull__(3);
41 PARROT_CAN_RETURN_NULL
42 static void setup_exception_args(PARROT_INTERP, ARGIN(const char *sig), ...)
43 __attribute__nonnull__(1)
44 __attribute__nonnull__(2);
46 #define ASSERT_ARGS_build_exception_from_args __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
47 PARROT_ASSERT_ARG(interp) \
48 , PARROT_ASSERT_ARG(format))
49 #define ASSERT_ARGS_setup_exception_args __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
50 PARROT_ASSERT_ARG(interp) \
51 , PARROT_ASSERT_ARG(sig))
52 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
53 /* HEADERIZER END: static */
55 #include <stdarg.h>
59 =item C<PMC * Parrot_ex_build_exception(PARROT_INTERP, INTVAL severity, long
60 error, STRING *msg)>
62 Constructs a new exception object from the passed in arguments.
64 =cut
67 PARROT_EXPORT
68 PARROT_CAN_RETURN_NULL
69 PMC *
70 Parrot_ex_build_exception(PARROT_INTERP, INTVAL severity,
71 long error, ARGIN_NULLOK(STRING *msg))
73 ASSERT_ARGS(Parrot_ex_build_exception)
74 PMC *exception = pmc_new(interp, enum_class_Exception);
76 VTABLE_set_integer_keyed_str(interp, exception, CONST_STRING(interp, "severity"), severity);
77 VTABLE_set_integer_keyed_str(interp, exception, CONST_STRING(interp, "type"), error);
78 if (msg)
79 VTABLE_set_string_native(interp, exception, msg);
81 return exception;
86 =item C<void die_from_exception(PARROT_INTERP, PMC *exception)>
88 Print a stack trace for C<exception>, a message if there is one, and then exit.
90 =cut
94 PARROT_DOES_NOT_RETURN
95 void
96 die_from_exception(PARROT_INTERP, ARGIN(PMC *exception))
98 ASSERT_ARGS(die_from_exception)
99 STRING * const message = VTABLE_get_string(interp, exception);
100 INTVAL exit_status = 1;
101 const INTVAL severity = VTABLE_get_integer_keyed_str(interp, exception, CONST_STRING(interp, "severity"));
103 /* In some cases we have a fatal exception before the IO system
104 * is completely initialized. Do some attempt to output the
105 * message to stderr, to help diagnosing. */
106 int use_perr = !PMC_IS_NULL(Parrot_io_STDERR(interp));
108 /* flush interpreter output to get things printed in order */
109 if (!PMC_IS_NULL(Parrot_io_STDOUT(interp)))
110 Parrot_io_flush(interp, Parrot_io_STDOUT(interp));
111 if (use_perr)
112 Parrot_io_flush(interp, Parrot_io_STDERR(interp));
114 if (interp->pdb) {
115 Interp * interpdeb = interp->pdb->debugger;
116 if (interpdeb) {
117 Parrot_io_flush(interpdeb, Parrot_io_STDOUT(interpdeb));
118 Parrot_io_flush(interpdeb, Parrot_io_STDERR(interpdeb));
122 if (Parrot_str_not_equal(interp, message, CONST_STRING(interp, ""))) {
123 if (use_perr)
124 Parrot_io_eprintf(interp, "%S\n", message);
125 else {
126 char * const msg = Parrot_str_to_cstring(interp, message);
127 fflush(stderr);
128 fprintf(stderr, "\n%s\n", msg);
129 Parrot_str_free_cstring(msg);
132 /* caution against output swap (with PDB_backtrace) */
133 fflush(stderr);
134 PDB_backtrace(interp);
136 else if (severity == EXCEPT_exit) {
137 /* TODO: get exit status based on type */
138 exit_status = VTABLE_get_integer_keyed_str(interp, exception, CONST_STRING(interp, "exit_code"));
140 else {
141 Parrot_io_eprintf(interp, "No exception handler and no message\n");
142 /* caution against output swap (with PDB_backtrace) */
143 fflush(stderr);
144 PDB_backtrace(interp);
148 * returning NULL from here returns resume address NULL to the
149 * runloop, which will terminate the thread function finally
151 * TT #1287 this check should better be in Parrot_exit
154 /* no exception handler, but this is not the main thread */
155 if (interp->thread_data && interp->thread_data->tid)
156 pt_thread_detach(interp->thread_data->tid);
159 * only main should run the destroy functions - exit handler chain
160 * is freed during Parrot_exit
162 Parrot_exit(interp, exit_status);
167 =item C<void Parrot_ex_add_c_handler(PARROT_INTERP, Parrot_runloop *jp)>
169 Adds a new exception handler (defined in C) to the concurrency scheduler. Since
170 the exception handler is C code, it stores a runloop jump point to the start of
171 the handler code.
173 =cut
177 PARROT_EXPORT
178 void
179 Parrot_ex_add_c_handler(PARROT_INTERP, ARGIN(Parrot_runloop *jp))
181 ASSERT_ARGS(Parrot_ex_add_c_handler)
182 PMC * const handler = pmc_new(interp, enum_class_ExceptionHandler);
183 /* Flag to mark a C exception handler */
184 PObj_get_FLAGS(handler) |= SUB_FLAG_C_HANDLER;
185 VTABLE_set_pointer(interp, handler, jp);
186 Parrot_cx_add_handler_local(interp, handler);
191 =item C<opcode_t * Parrot_ex_throw_from_op(PARROT_INTERP, PMC *exception, void
192 *dest)>
194 Throw an exception from inside an op. Looks for an exception handler in the
195 current concurrency scheduler. If a suitable handler is found, invoke it and
196 return the address where execution should continue. If no handler is found,
197 the exception message is printed along with the current line number
198 annotation and a backtrace before exiting Parrot.
200 =cut
204 PARROT_EXPORT
205 PARROT_CAN_RETURN_NULL
206 opcode_t *
207 Parrot_ex_throw_from_op(PARROT_INTERP, ARGIN(PMC *exception), ARGIN_NULLOK(void *dest))
209 ASSERT_ARGS(Parrot_ex_throw_from_op)
210 opcode_t *address;
211 PMC * const handler = Parrot_cx_find_handler_local(interp, exception);
212 if (PMC_IS_NULL(handler)) {
213 STRING * const message = VTABLE_get_string(interp, exception);
214 const INTVAL severity = VTABLE_get_integer_keyed_str(interp, exception, CONST_STRING(interp, "severity"));
215 if (severity < EXCEPT_error) {
216 PMC * const resume = VTABLE_get_attr_str(interp, exception, CONST_STRING(interp, "resume"));
217 if (Parrot_str_not_equal(interp, message, CONST_STRING(interp, ""))) {
218 Parrot_io_eprintf(interp, "%S\n", message);
220 else {
221 Parrot_io_eprintf(interp, "%S\n", CONST_STRING(interp, "Warning"));
224 /* caution against output swap (with PDB_backtrace) */
225 fflush(stderr);
226 /* PDB_backtrace(interp); */
228 if (!PMC_IS_NULL(resume)) {
229 return VTABLE_invoke(interp, resume, NULL);
232 die_from_exception(interp, exception);
235 address = VTABLE_invoke(interp, handler, dest);
236 setup_exception_args(interp, "P", exception);
238 if (PObj_get_FLAGS(handler) & SUB_FLAG_C_HANDLER) {
239 /* it's a C exception handler */
240 Parrot_runloop * const jump_point = (Parrot_runloop *)address;
241 longjmp(jump_point->resume, 1);
244 /* return the address of the handler */
245 return address;
250 =item C<static void setup_exception_args(PARROT_INTERP, const char *sig, ...)>
252 Sets up arguments to the exception handler invocation.
254 =cut
258 PARROT_CAN_RETURN_NULL
259 static void
260 setup_exception_args(PARROT_INTERP, ARGIN(const char *sig), ...)
262 ASSERT_ARGS(setup_exception_args)
263 va_list args;
264 PMC *sig_obj;
266 va_start(args, sig);
267 sig_obj = Parrot_pcc_build_sig_object_from_varargs(interp, PMCNULL, sig, args);
268 va_end(args);
270 CALLSIGNATURE_is_exception_SET(sig_obj);
272 Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), sig_obj);
277 =item C<static PMC * build_exception_from_args(PARROT_INTERP, int ex_type, const
278 char *format, va_list arglist)>
280 Builds an exception PMC with the given integer type C<ex_type>, and the string
281 message given as a format/arglist combo, like is used by the Parrot_vsprintf*
282 family of functions.
284 =cut
288 PARROT_CANNOT_RETURN_NULL
289 static PMC *
290 build_exception_from_args(PARROT_INTERP, int ex_type,
291 ARGIN(const char *format), va_list arglist)
293 ASSERT_ARGS(build_exception_from_args)
294 /* Make and set exception message. */
295 STRING * const msg =
296 strchr(format, '%')
297 ? Parrot_vsprintf_c(interp, format, arglist)
298 : string_make(interp, format, strlen(format), NULL, 0);
300 return Parrot_ex_build_exception(interp, EXCEPT_error, ex_type, msg);
305 =item C<void Parrot_ex_throw_from_c(PARROT_INTERP, PMC *exception)>
307 Throws an exception object from any location in C code. A suitable handler
308 is retrieved from the concurrency scheduler. If the handler is found, control
309 flow is passed to it. Handlers can be either C-level or PIR-level routines. If
310 no suitable handler is found, Parrot exits with the stored exception error
311 message.
313 See also C<exit_fatal()>, which signals fatal errors, and
314 C<Parrot_ex_throw_from_op> which throws an exception from within an op.
316 The 'invoke' vtable function doesn't actually execute a
317 sub/continuation/handler, it only sets up the environment for invocation and
318 returns the address of the start of the sub's code. That address then becomes
319 the next op in the runloop.
321 Exceptions thrown from C and caught by a continuation-based handler are
322 resumable at the level of a C instruction. When handled, they return the
323 exception object. Any values returned from the handler to the C code that threw
324 the exception can be stored in the exception's payload.
326 =cut
330 PARROT_EXPORT
331 PARROT_DOES_NOT_RETURN
332 void
333 Parrot_ex_throw_from_c(PARROT_INTERP, ARGIN(PMC *exception))
335 ASSERT_ARGS(Parrot_ex_throw_from_c)
337 Parrot_runloop *return_point = interp->current_runloop;
338 opcode_t *address;
339 PMC * const handler =
340 Parrot_cx_find_handler_local(interp, exception);
342 if (PMC_IS_NULL(handler))
343 die_from_exception(interp, exception);
345 if (Interp_debug_TEST(interp, PARROT_BACKTRACE_DEBUG_FLAG)) {
346 STRING * const exit_code = CONST_STRING(interp, "exit_code");
347 STRING * const msg = VTABLE_get_string(interp, exception);
348 int exitcode = VTABLE_get_integer_keyed_str(interp,
349 exception, exit_code);
351 Parrot_io_eprintf(interp,
352 "Parrot_ex_throw_from_c (severity:%d error:%d): %Ss\n",
353 EXCEPT_error, exitcode, msg);
354 PDB_backtrace(interp);
357 /* Note the thrower.
358 * XXX TT #596 - pass in current context instead when we have context PMCs. */
359 /* Don't split line. It will break CONST_STRING handling */
360 VTABLE_set_attr_str(interp, exception, CONST_STRING(interp, "thrower"), Parrot_pcc_get_continuation(interp, CURRENT_CONTEXT(interp)));
363 /* it's a C exception handler */
364 if (PObj_get_FLAGS(handler) & SUB_FLAG_C_HANDLER) {
365 Parrot_runloop * const jump_point =
366 (Parrot_runloop * const)VTABLE_get_pointer(interp, handler);
367 longjmp(jump_point->resume, 1);
370 /* Run the handler. */
371 address = VTABLE_invoke(interp, handler, NULL);
372 setup_exception_args(interp, "P", exception);
373 PARROT_ASSERT(return_point->handler_start == NULL);
374 return_point->handler_start = address;
375 longjmp(return_point->resume, 2);
380 =item C<opcode_t * Parrot_ex_throw_from_op_args(PARROT_INTERP, void *dest, int
381 ex_type, const char *format, ...)>
383 Throws an exception from an opcode, with an error message constructed
384 from a format string and arguments. Constructs an Exception PMC, and passes it
385 to C<Parrot_ex_throw_from_op>.
387 See also C<Parrot_ex_throw_from_c> and C<exit_fatal()>.
389 =cut
393 PARROT_EXPORT
394 PARROT_CAN_RETURN_NULL
395 opcode_t *
396 Parrot_ex_throw_from_op_args(PARROT_INTERP, ARGIN_NULLOK(void *dest),
397 int ex_type, ARGIN(const char *format), ...)
399 ASSERT_ARGS(Parrot_ex_throw_from_op_args)
400 PMC *exception;
402 va_list arglist;
403 va_start(arglist, format);
404 exception = build_exception_from_args(interp, ex_type, format, arglist);
405 va_end(arglist);
407 return Parrot_ex_throw_from_op(interp, exception, dest);
412 =item C<void Parrot_ex_throw_from_c_args(PARROT_INTERP, void *ret_addr, int
413 exitcode, const char *format, ...)>
415 Throws an exception, with an error message constructed from a format string and
416 arguments. C<ret_addr> is the address from which to resume, if some handler
417 decides that is appropriate, or zero to make the error non-resumable.
418 C<exitcode> is a C<exception_type_enum> value. Constructs an Exception PMC
419 and passes it to C<Parrot_ex_throw_from_c>.
421 See also C<Parrot_ex_throw_from_op> and C<exit_fatal()>.
423 =cut
427 PARROT_EXPORT
428 PARROT_DOES_NOT_RETURN
429 void
430 Parrot_ex_throw_from_c_args(PARROT_INTERP, SHIM(void *ret_addr),
431 int exitcode, ARGIN(const char *format), ...)
433 ASSERT_ARGS(Parrot_ex_throw_from_c_args)
434 PMC *exception;
436 va_list arglist;
437 va_start(arglist, format);
438 exception = build_exception_from_args(interp, exitcode, format, arglist);
439 va_end(arglist);
441 Parrot_ex_throw_from_c(interp, exception);
446 =item C<opcode_t * Parrot_ex_rethrow_from_op(PARROT_INTERP, PMC *exception)>
448 Rethrow the given exception from an op, if it has previously been thrown and
449 not handled by the provided handler. Marks the exception object as being
450 unhandled and throws it again.
452 =cut
456 PARROT_EXPORT
457 PARROT_WARN_UNUSED_RESULT
458 PARROT_CAN_RETURN_NULL
459 opcode_t *
460 Parrot_ex_rethrow_from_op(PARROT_INTERP, ARGIN(PMC *exception))
462 ASSERT_ARGS(Parrot_ex_rethrow_from_op)
464 Parrot_ex_mark_unhandled(interp, exception);
466 return Parrot_ex_throw_from_op(interp, exception, NULL);
471 =item C<void Parrot_ex_rethrow_from_c(PARROT_INTERP, PMC *exception)>
473 Rethrow the exception from C code. Marks the Exception PMC as being unhandled
474 and throws it again.
476 =cut
480 PARROT_EXPORT
481 PARROT_DOES_NOT_RETURN
482 void
483 Parrot_ex_rethrow_from_c(PARROT_INTERP, ARGIN(PMC *exception))
485 ASSERT_ARGS(Parrot_ex_rethrow_from_c)
486 Parrot_ex_mark_unhandled(interp, exception);
488 Parrot_ex_throw_from_c(interp, exception);
493 =item C<void Parrot_ex_mark_unhandled(PARROT_INTERP, PMC *exception)>
495 Mark an exception as unhandled, as part of rethrowing it.
497 =cut
501 PARROT_EXPORT
502 void
503 Parrot_ex_mark_unhandled(PARROT_INTERP, ARGIN(PMC *exception))
505 ASSERT_ARGS(Parrot_ex_mark_unhandled)
506 VTABLE_set_integer_keyed_str(interp, exception, CONST_STRING(interp, "handled"), -1);
511 =item C<size_t Parrot_ex_calc_handler_offset(PARROT_INTERP)>
513 Retrieve an exception from the concurrency scheduler, prepare a call to the
514 handler, and return the offset to the handler so it can become the next op in
515 the runloop.
517 TT #546: This function appears to be unused.
519 =cut
523 PARROT_EXPORT
524 size_t
525 Parrot_ex_calc_handler_offset(PARROT_INTERP)
527 ASSERT_ARGS(Parrot_ex_calc_handler_offset)
528 PMC * const exception = VTABLE_pop_pmc(interp, interp->scheduler);
530 /* now fill rest of exception, locate handler and get
531 * destination of handler */
532 opcode_t * const handler_address = Parrot_ex_throw_from_op(interp, exception, NULL);
534 if (handler_address == NULL)
535 PANIC(interp, "Unable to calculate opcode address for exception handler");
537 /* return the *offset* of the handler */
538 return handler_address - interp->code->base.data;
543 =back
545 =head2 Error Functions
547 =over 4
549 =item C<PARROT_DOES_NOT_RETURN_WHEN_FALSE void Parrot_assert(INTVAL condition,
550 const char *condition_string, const char *file, unsigned int line)>
552 A better version of assert() that gives a backtrace.
554 =cut
558 PARROT_EXPORT
559 PARROT_DOES_NOT_RETURN_WHEN_FALSE
560 void
561 Parrot_assert(INTVAL condition, ARGIN(const char *condition_string),
562 ARGIN(const char *file), unsigned int line)
564 ASSERT_ARGS(Parrot_assert)
565 if (!condition)
566 Parrot_confess(condition_string, file, line);
571 =item C<void Parrot_confess(const char *cond, const char *file, unsigned int
572 line)>
574 Prints a backtrace and message for a failed assertion.
576 =cut
580 PARROT_EXPORT
581 PARROT_DOES_NOT_RETURN
582 void
583 Parrot_confess(ARGIN(const char *cond), ARGIN(const char *file), unsigned int line)
585 ASSERT_ARGS(Parrot_confess)
586 fprintf(stderr, "%s:%u: failed assertion '%s'\n", file, line, cond);
587 Parrot_print_backtrace();
588 abort();
593 =item C<void Parrot_print_backtrace(void)>
595 Displays the primrose path to disaster, (the stack frames leading up to the
596 abort). Used by C<Parrot_confess>.
598 =cut
602 void
603 Parrot_print_backtrace(void)
605 ASSERT_ARGS(Parrot_print_backtrace)
606 #ifdef PARROT_HAS_BACKTRACE
607 # define BACKTRACE_DEPTH 32
608 /*# define BACKTRACE_VERBOSE */
609 # ifndef PARROT_HAS_DLINFO
610 # define BACKTRACE_VERBOSE
611 # endif
612 /* stolen from http://www.delorie.com/gnu/docs/glibc/libc_665.html */
613 void *array[BACKTRACE_DEPTH];
614 int i;
616 const int size = backtrace(array, BACKTRACE_DEPTH);
618 fprintf(stderr,
619 "Backtrace - Obtained %d stack frames (max trace depth is %d).\n",
620 size, BACKTRACE_DEPTH);
621 # ifndef BACKTRACE_VERBOSE
622 for (i = 0; i < size; i++) {
623 Dl_info frameInfo;
624 const int found = dladdr(array[i], &frameInfo);
626 /* always indent */
627 const int indent = 2 + (2 * i);
629 fprintf(stderr, "%*s", indent, "");
631 if (found && frameInfo.dli_sname)
632 fprintf(stderr, "%s\n", frameInfo.dli_sname);
633 else
634 fprintf(stderr, "(unknown)\n");
637 # else
638 { /* Scope for strings */
639 char ** strings = backtrace_symbols(array, size);
640 if (strings) {
641 for (i = 0; i < size; i++)
642 fprintf(stderr, "%s\n", strings[i]);
643 /* backtrace_symbols gets memory using malloc */
644 free(strings);
646 else
647 fputs("Not enough memory for backtrace_symbols\n", stderr);
649 # endif
651 # undef BACKTRACE_DEPTH
652 #endif /* ifdef PARROT_HAS_BACKTRACE */
657 =item C<void exit_fatal(int exitcode, const char *format, ...)>
659 Signal a fatal error condition. This should only be used with dire errors that
660 cannot throw an exception (because no interpreter is available, or the nature
661 of the error would interfere with the exception system).
663 This involves printing an error message to stderr, and calling C<exit> to exit
664 the process with the given exitcode. It is not possible for Parrot bytecode to
665 intercept a fatal error (for that, use C<Parrot_ex_throw_from_c_args>).
666 C<exit_fatal> does not call C<Parrot_exit> to invoke exit handlers (that would
667 require an interpreter).
669 =cut
673 PARROT_EXPORT
674 PARROT_DOES_NOT_RETURN
675 void
676 exit_fatal(int exitcode, ARGIN(const char *format), ...)
678 ASSERT_ARGS(exit_fatal)
679 va_list arglist;
680 va_start(arglist, format);
681 vfprintf(stderr, format, arglist);
682 fprintf(stderr, "\n");
683 /* caution against output swap (with PDB_backtrace) */
684 fflush(stderr);
685 va_end(arglist);
686 exit(exitcode);
689 /* The DUMPCORE macro is defined for most platforms, but defined here if not
690 * found elsewhere, so we're sure it's safe to call. */
692 #ifndef DUMPCORE
693 # define DUMPCORE() \
694 fprintf(stderr, "Sorry, coredump is not yet implemented " \
695 "for this platform.\n\n"); \
696 exit(EXIT_FAILURE);
697 #endif
701 =item C<void do_panic(NULLOK_INTERP, const char *message, const char *file,
702 unsigned int line)>
704 Panic handler. Things have gone very wrong in an unexpected way. Print out an
705 error message and instructions for the user to report the error to the
706 developers
708 =cut
712 PARROT_DOES_NOT_RETURN
713 void
714 do_panic(NULLOK_INTERP, ARGIN_NULLOK(const char *message),
715 ARGIN_NULLOK(const char *file), unsigned int line)
717 ASSERT_ARGS(do_panic)
718 /* Note: we can't format any floats in here--Parrot_sprintf
719 ** may panic because of floats.
720 ** and we don't use Parrot_sprintf or such, because we are
721 ** already in panic --leo
723 fprintf(stderr, "Parrot VM: PANIC: %s!\n",
724 message ? message : "(no message available)");
726 fprintf(stderr, "C file %s, line %u\n",
727 file ? file : "(not available)", line);
729 fprintf(stderr, "Parrot file (not available), ");
730 fprintf(stderr, "line (not available)\n");
732 fprintf(stderr, "\n\
733 We highly suggest you notify the Parrot team if you have not been working on\n\
734 Parrot. Use parrotbug (located in parrot's root directory) or send an\n\
735 e-mail to parrot-dev@lists.parrot.org.\n\
736 Include the entire text of this error message and the text of the script that\n\
737 generated the error. If you've made any modifications to Parrot, please\n\
738 describe them as well.\n\n");
740 fprintf(stderr, "Version : %s\n", PARROT_VERSION);
741 fprintf(stderr, "Configured : %s\n", PARROT_CONFIG_DATE);
742 fprintf(stderr, "Architecture: %s\n", PARROT_ARCHNAME);
743 fprintf(stderr, "JIT Capable : %s\n", JIT_CAPABLE ? "Yes" : "No");
744 if (interp)
745 fprintf(stderr, "Interp Flags: %#x\n", (unsigned int)interp->flags);
746 else
747 fprintf(stderr, "Interp Flags: (no interpreter)\n");
748 fprintf(stderr, "Exceptions : %s\n", "(missing from core)");
749 fprintf(stderr, "\nDumping Core...\n");
751 DUMPCORE();
757 =back
759 =head1 SEE ALSO
761 F<include/parrot/exceptions.h>.
763 =cut
769 * Local variables:
770 * c-file-style: "parrot"
771 * End:
772 * vim: expandtab shiftwidth=4: