On uncaught exception, execute finally clauses and collect backtrace.

This commit is contained in:
whitequark 2015-07-27 13:48:42 +03:00
parent 2939d4f0f3
commit edffb40ef2
5 changed files with 77 additions and 5 deletions

View File

@ -1,4 +1,4 @@
CC ?= clang CC ?= clang
libartiq_personality.so: ../../soc/runtime/artiq_personality.c artiq_terminate.c libartiq_personality.so: ../../soc/runtime/artiq_personality.c artiq_terminate.c
$(CC) -Wall -Werror -I. -I../../soc/runtime -g -fPIC -shared -o $@ $^ $(CC) -std=c99 -Wall -Werror -I. -I../../soc/runtime -g -fPIC -shared -o $@ $^

View File

@ -4,11 +4,26 @@
#include <unwind.h> #include <unwind.h>
#include <artiq_personality.h> #include <artiq_personality.h>
void __artiq_terminate(struct artiq_exception *exn) { #define __USE_GNU
#include <dlfcn.h>
void __artiq_terminate(struct artiq_exception *exn,
struct artiq_backtrace_item *backtrace,
size_t backtrace_size) {
printf("Uncaught %s: %s (%"PRIi64", %"PRIi64", %"PRIi64")\n" printf("Uncaught %s: %s (%"PRIi64", %"PRIi64", %"PRIi64")\n"
"at %s:%"PRIi32":%"PRIi32"\n", "at %s:%"PRIi32":%"PRIi32"\n",
exn->name, exn->message, exn->name, exn->message,
exn->param[0], exn->param[1], exn->param[1], exn->param[0], exn->param[1], exn->param[1],
exn->file, exn->line, exn->column + 1); exn->file, exn->line, exn->column + 1);
for(size_t i = 0; i < backtrace_size; i++) {
Dl_info info;
if(dladdr((void*) backtrace[i].function, &info) && info.dli_sname) {
printf("at %s+%p\n", info.dli_sname, (void*)backtrace[i].offset);
} else {
printf("at %p+%p\n", (void*)backtrace[i].function, (void*)backtrace[i].offset);
}
}
exit(1); exit(1);
} }

View File

@ -0,0 +1,12 @@
# RUN: %not %python -m artiq.compiler.testbench.jit %s >%t
# RUN: OutputCheck %s --file-to-check=%t
# REQUIRES: exceptions
def f():
try:
1/0
finally:
print("f-fin")
# CHECK-L: f-fin
f()

View File

@ -200,11 +200,17 @@ static uintptr_t readEncodedPointer(const uint8_t **data, uint8_t encoding) {
#define ARTIQ_EXCEPTION_CLASS 0x4152545141525451LL // 'ARTQARTQ' #define ARTIQ_EXCEPTION_CLASS 0x4152545141525451LL // 'ARTQARTQ'
static void __artiq_cleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception *exc); static void __artiq_cleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception *exc);
static _Unwind_Reason_Code __artiq_uncaught_exception(
int version, _Unwind_Action actions, uint64_t exceptionClass,
struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context,
void *stop_parameter);
struct artiq_raised_exception { struct artiq_raised_exception {
struct _Unwind_Exception unwind; struct _Unwind_Exception unwind;
struct artiq_exception artiq; struct artiq_exception artiq;
int handled; int handled;
struct artiq_backtrace_item backtrace[1024];
size_t backtrace_size;
}; };
static struct artiq_raised_exception inflight; static struct artiq_raised_exception inflight;
@ -216,13 +222,17 @@ void __artiq_raise(struct artiq_exception *artiq_exn) {
inflight.unwind.exception_class = ARTIQ_EXCEPTION_CLASS; inflight.unwind.exception_class = ARTIQ_EXCEPTION_CLASS;
inflight.unwind.exception_cleanup = &__artiq_cleanup; inflight.unwind.exception_cleanup = &__artiq_cleanup;
inflight.handled = 0; inflight.handled = 0;
inflight.backtrace_size = 0;
_Unwind_Reason_Code result = _Unwind_RaiseException(&inflight.unwind); _Unwind_Reason_Code result = _Unwind_RaiseException(&inflight.unwind);
EH_ASSERT((result == _URC_END_OF_STACK) && EH_ASSERT((result == _URC_END_OF_STACK) &&
"Unexpected error during unwinding"); "Unexpected error during unwinding");
// If we're here, there are no handlers, only cleanups. // If we're here, there are no handlers, only cleanups.
__artiq_terminate(&inflight.artiq); // Force unwinding anyway; we shall stop at nothing except the end of stack.
result = _Unwind_ForcedUnwind(&inflight.unwind, &__artiq_uncaught_exception,
NULL);
EH_FAIL("_Unwind_ForcedUnwind should not return");
} }
void __artiq_reraise() { void __artiq_reraise() {
@ -238,7 +248,7 @@ void __artiq_reraise() {
} }
} }
/* Catching */ /* Unwinding */
// The code below does not refer to the `inflight` global. // The code below does not refer to the `inflight` global.
@ -250,6 +260,34 @@ static void __artiq_cleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception
memset(&inflight->artiq, 0, sizeof(struct artiq_exception)); memset(&inflight->artiq, 0, sizeof(struct artiq_exception));
} }
static _Unwind_Reason_Code __artiq_uncaught_exception(
int version, _Unwind_Action actions, uint64_t exceptionClass,
struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context,
void *stop_parameter) {
struct artiq_raised_exception *inflight =
(struct artiq_raised_exception*)exceptionObject;
EH_ASSERT(inflight->backtrace_size <
sizeof(inflight->backtrace) / sizeof(inflight->backtrace[0]) &&
"Out of space for backtrace");
uintptr_t pc = _Unwind_GetIP(context);
uintptr_t funcStart = _Unwind_GetRegionStart(context);
uintptr_t pcOffset = pc - funcStart;
EH_LOG("===> uncaught (pc=%p+%p)", (void*)funcStart, (void*)pcOffset);
inflight->backtrace[inflight->backtrace_size].function = funcStart;
inflight->backtrace[inflight->backtrace_size].offset = pcOffset;
++inflight->backtrace_size;
if(actions & _UA_END_OF_STACK) {
EH_LOG0("end of stack");
__artiq_terminate(&inflight->artiq, inflight->backtrace, inflight->backtrace_size);
} else {
EH_LOG0("continue");
return _URC_NO_REASON;
}
}
_Unwind_Reason_Code __artiq_personality( _Unwind_Reason_Code __artiq_personality(
int version, _Unwind_Action actions, uint64_t exceptionClass, int version, _Unwind_Action actions, uint64_t exceptionClass,
struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context) { struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context) {

View File

@ -15,6 +15,11 @@ struct artiq_exception {
int64_t param[3]; int64_t param[3];
}; };
struct artiq_backtrace_item {
intptr_t function;
intptr_t offset;
};
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -26,7 +31,9 @@ void __artiq_reraise()
__attribute__((noreturn)); __attribute__((noreturn));
/* Called by the runtime */ /* Called by the runtime */
void __artiq_terminate(struct artiq_exception *artiq_exn) void __artiq_terminate(struct artiq_exception *artiq_exn,
struct artiq_backtrace_item *backtrace,
size_t backtrace_size)
__attribute__((noreturn)); __attribute__((noreturn));
#ifdef __cplusplus #ifdef __cplusplus