forked from M-Labs/artiq
On uncaught exception, execute finally clauses and collect backtrace.
This commit is contained in:
parent
2939d4f0f3
commit
edffb40ef2
@ -1,4 +1,4 @@
|
||||
CC ?= clang
|
||||
|
||||
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 $@ $^
|
||||
|
@ -4,11 +4,26 @@
|
||||
#include <unwind.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"
|
||||
"at %s:%"PRIi32":%"PRIi32"\n",
|
||||
exn->name, exn->message,
|
||||
exn->param[0], exn->param[1], exn->param[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);
|
||||
}
|
||||
|
12
lit-test/test/exceptions/finally_uncaught.py
Normal file
12
lit-test/test/exceptions/finally_uncaught.py
Normal 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()
|
@ -200,11 +200,17 @@ static uintptr_t readEncodedPointer(const uint8_t **data, uint8_t encoding) {
|
||||
#define ARTIQ_EXCEPTION_CLASS 0x4152545141525451LL // 'ARTQARTQ'
|
||||
|
||||
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 _Unwind_Exception unwind;
|
||||
struct artiq_exception artiq;
|
||||
int handled;
|
||||
struct artiq_backtrace_item backtrace[1024];
|
||||
size_t backtrace_size;
|
||||
};
|
||||
|
||||
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_cleanup = &__artiq_cleanup;
|
||||
inflight.handled = 0;
|
||||
inflight.backtrace_size = 0;
|
||||
|
||||
_Unwind_Reason_Code result = _Unwind_RaiseException(&inflight.unwind);
|
||||
EH_ASSERT((result == _URC_END_OF_STACK) &&
|
||||
"Unexpected error during unwinding");
|
||||
|
||||
// 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() {
|
||||
@ -238,7 +248,7 @@ void __artiq_reraise() {
|
||||
}
|
||||
}
|
||||
|
||||
/* Catching */
|
||||
/* Unwinding */
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
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(
|
||||
int version, _Unwind_Action actions, uint64_t exceptionClass,
|
||||
struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context) {
|
||||
|
@ -15,6 +15,11 @@ struct artiq_exception {
|
||||
int64_t param[3];
|
||||
};
|
||||
|
||||
struct artiq_backtrace_item {
|
||||
intptr_t function;
|
||||
intptr_t offset;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -26,7 +31,9 @@ void __artiq_reraise()
|
||||
__attribute__((noreturn));
|
||||
|
||||
/* 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));
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
Loading…
Reference in New Issue
Block a user