Skip to content

Commit

Permalink
On uncaught exception, execute finally clauses and collect backtrace.
Browse files Browse the repository at this point in the history
whitequark committed Jul 27, 2015
1 parent 2939d4f commit edffb40
Showing 5 changed files with 77 additions and 5 deletions.
2 changes: 1 addition & 1 deletion lit-test/libartiq_personality/Makefile
Original file line number Diff line number Diff line change
@@ -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 $@ $^
17 changes: 16 additions & 1 deletion lit-test/libartiq_personality/artiq_terminate.c
Original file line number Diff line number Diff line change
@@ -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 changes: 12 additions & 0 deletions lit-test/test/exceptions/finally_uncaught.py
Original file line number Diff line number Diff line change
@@ -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()
42 changes: 40 additions & 2 deletions soc/runtime/artiq_personality.c
Original file line number Diff line number Diff line change
@@ -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) {
9 changes: 8 additions & 1 deletion soc/runtime/artiq_personality.h
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit edffb40

Please sign in to comment.