#include <windows.h>
#include <string.h>
#if !defined(_WIN64)
#error "seh.c decodes the 64-bit C++ exception layout only; no 32-bit Windows target is built"
#endif
#define MB_SEH_CPP_EXCEPTION 0xE06D7363ul
#define MB_SEH_GCC_THROW 0x20474343ul
#define MB_SEH_IS_ERROR(code) ((((code) & 0xC0000000ul)) == 0xC0000000ul)
#define MB_SEH_STACK_OVERFLOW 0xC00000FDul
#define MB_EH_MAGIC_1 0x19930520ul
#define MB_EH_MAGIC_2 0x19930521ul
#define MB_EH_MAGIC_3 0x19930522ul
static const char MB_RUST_PANIC[] = "rust_panic";
typedef struct _MB_TypeDescriptor {
const void *pVFTable;
void *spare;
char name[1];
} MB_TypeDescriptor;
typedef struct _MB_CatchableType {
unsigned int properties;
unsigned int pType;
} MB_CatchableType;
typedef struct _MB_CatchableTypeArray {
int nCatchableTypes;
unsigned int arrayOfCatchableTypes[1];
} MB_CatchableTypeArray;
typedef struct _MB_ThrowInfo {
unsigned int attributes;
unsigned int pmfnUnwind;
unsigned int pForwardCompat;
unsigned int pCatchableTypeArray;
} MB_ThrowInfo;
static const unsigned long long MB_FOREIGN_CLASSES[] = {
0x474E5543432B2B00ull,
0x474E5543432B2B01ull,
0x434C4E47432B2B00ull,
0x434C4E47432B2B01ull,
};
static int
mb_is_foreign_cpp(const EXCEPTION_RECORD *rec)
{
if (rec->ExceptionCode == MB_SEH_CPP_EXCEPTION && rec->NumberParameters == 4) {
const MB_ThrowInfo *info;
const MB_CatchableTypeArray *types;
const MB_CatchableType *catchable;
const MB_TypeDescriptor *type;
ULONG_PTR magic = rec->ExceptionInformation[0];
ULONG_PTR base = rec->ExceptionInformation[3];
if (magic != MB_EH_MAGIC_1 && magic != MB_EH_MAGIC_2 && magic != MB_EH_MAGIC_3) {
return 0;
}
info = (const MB_ThrowInfo *)rec->ExceptionInformation[2];
if (info == 0 || base == 0) {
return 0;
}
types = (const MB_CatchableTypeArray *)(base + info->pCatchableTypeArray);
if (types->nCatchableTypes < 1) {
return 0;
}
catchable = (const MB_CatchableType *)(base + types->arrayOfCatchableTypes[0]);
type = (const MB_TypeDescriptor *)(base + catchable->pType);
return strncmp(type->name, MB_RUST_PANIC, sizeof MB_RUST_PANIC) != 0;
}
if (rec->ExceptionCode == MB_SEH_GCC_THROW && rec->NumberParameters >= 1) {
const unsigned long long *class =
(const unsigned long long *)rec->ExceptionInformation[0];
size_t i;
if (class == 0) {
return 0;
}
for (i = 0; i < sizeof MB_FOREIGN_CLASSES / sizeof MB_FOREIGN_CLASSES[0]; i++) {
if (*class == MB_FOREIGN_CLASSES[i]) {
return 1;
}
}
return 0;
}
return 0;
}
static int
mb_seh_filter(EXCEPTION_POINTERS *info)
{
EXCEPTION_RECORD *rec = info->ExceptionRecord;
switch (rec->ExceptionCode) {
case MB_SEH_CPP_EXCEPTION:
case MB_SEH_GCC_THROW:
return mb_is_foreign_cpp(rec) ? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH;
case MB_SEH_STACK_OVERFLOW:
return EXCEPTION_CONTINUE_SEARCH;
default:
return MB_SEH_IS_ERROR(rec->ExceptionCode) ? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH;
}
}
typedef void (*mb_seh_body)(void *ctx);
int
mb_seh_guard(mb_seh_body body, void *ctx, unsigned long *code)
{
__try {
body(ctx);
}
__except (mb_seh_filter(GetExceptionInformation())) {
*code = GetExceptionCode();
return 1;
}
return 0;
}