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
|
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 $@ $^
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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'
|
#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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue