Skip to content

Crash Engine

include/console/crash.h View source View on GitHub
struct crash_regs {
    union {
        struct {
            uint64_t  rip;
            uint64_t  rax;
            uint64_t  r8;
            uint64_t  rsp;
        };
        uint64_t  regs[CRASH_REG_COUNT];
    };
};
struct crash_payload {
    enum crash_code  code;
    void             *data;
    uintptr_t        params[4];
};
struct crash_facility {
    uint16_t    prefix;
    const char  *name;
    const char  *desc;
    uint16_t    hookable_threshold;
    const char  *(*const to_str)(uint16_t delta);
    void        (*const dump)(uint16_t delta, struct crash_payload pl);
    void        (*const emit_ndjson)(uint16_t delta, struct crash_payload pl);
};
struct crash_unwind_node_data {
    uintptr_t  arg;
    union {
        void       *ptr;
        size_t     rcu_lock_times;
        enum irql  irql;
        uintptr_t  raw;
    };
};
struct crash_unwind_node {
    enum crash_unwind_type         type;
    struct list_head               list;
    struct crash_unwind_node_data  data;
};
struct crash_unwind_perthread {
    struct list_head          free_list;
    struct list_head          in_use;
    struct crash_unwind_node  nodes[CRASH_UNWIND_NODES];
};
struct crash_perthread {
    struct crash_unwind_perthread  unwind;
    struct list_head               crash_hooks;
    bool                           unwinding;
    bool                           in_hook;
    jmp_buf                        env;
};
struct crash_hook {
    char               *name;
    struct list_head   list;
    enum crash_code    code;
    enum crash_source  source_mask;
};
struct crash_context {
    struct crash_payload     payload;
    enum crash_source        source;
    enum crash_format_flags  formats;
    const char               *file;
    int                      line;
    const char               *func;
    const char               *msg;
    const struct crash_regs  *regs;
    void                     *source_data;
};
enum qemu_exit_codes {
    QEMU_EXIT_OK = 0,
    QEMU_EXIT_FAIL = 1,
    QEMU_EXIT_PANIC = 2,
};
enum crash_code {
    CRASH_CODE_GENERIC,
};
enum crash_source {
    CRASH_SOURCE_PANIC = 0,
    CRASH_SOURCE_ASSERT,
    CRASH_SOURCE_KASAN,
    CRASH_SOURCE_UBSAN,
    CRASH_SOURCE_NMI_WATCHDOG,
    CRASH_SOURCE_CPU_EXCEPTION,
    CRASH_SOURCE_NIGHTMARE,
    CRASH_SOURCE_LOCK_CHK,
};
enum crash_format_flags {
    CRASH_FMT_RAW_SERIAL = 1 << 0,
    CRASH_FMT_VISUAL_PANES = 1 << 1,
    CRASH_FMT_NDJSON = 1 << 2,
    CRASH_FMT_DUMP_LOGS = 1 << 3,
    CRASH_FMT_PEER_CPUS = 1 << 4,
    CRASH_FMT_DEFAULT = CRASH_FMT_RAW_SERIAL | CRASH_FMT_VISUAL_PANES | CRASH_FMT_NDJSON | CRASH_FMT_DUMP_LOGS | CRASH_FMT_PEER_CPUS,
    CRASH_FMT_MINIMAL = CRASH_FMT_RAW_SERIAL | CRASH_FMT_NDJSON,
};
enum crash_hook_flags {
    CRASH_HOOK_DEFAULT = 0,
    CRASH_HOOK_FACILITY = 1 << 0,
    CRASH_HOOK_NO_UNWIND = 1 << 1,
};
enum crash_unwind_type {
    CRASH_UNWIND_NONE,
    CRASH_UNWIND_RCU,
    CRASH_UNWIND_MUTEX,
    CRASH_UNWIND_RWLOCK,
    CRASH_UNWIND_SPINLOCK,
    CRASH_UNWIND_QSPINLOCK,
    CRASH_UNWIND_MAX,
};
__noreturn void assert_impl_default(struct crash_payload payload, const char *file, int line, const char *func, const char *fmt);
__noreturn void assert_impl_assertion(struct crash_payload payload, const char *file, int line, const char *func, const char *prefix, const char *assertion, const char *fmt);
__noreturn void crash_full(const struct crash_context *ctx);
bool crash_cpu_is_owner(uint64_t id);
void crash_broadcast_nmi(void);
void crash_facilities_init(void);
const char * crash_code_from_facility_to_str(enum crash_code code);
__noreturn void crash_nmi_handoff(void *p, struct irq_context *ctx);
void debug_print_stack(void);
void crash_facility_printf(const char *fmt);
void crash_perthread_init(struct thread *t);
void crash_unwind(void);
void crash_unwind_enter_rcu(void);
void crash_unwind_exit_rcu(void);
void crash_unwind_enter_mutex(struct mutex *m);
void crash_unwind_exit_mutex(struct mutex *m);
void crash_unwind_enter_rwlock(struct rwlock *r);
void crash_unwind_exit_rwlock(struct rwlock *r);
void crash_unwind_enter_spinlock(struct spinlock *s, enum irql old);
void crash_unwind_exit_spinlock(struct spinlock *s);
void crash_unwind_enter_qspinlock(struct qspinlock *q, enum irql old);
void crash_unwind_exit_qspinlock(struct qspinlock *q);
void qemu_exit(int code);
char crash_code_to_str(enum crash_code code);
#define CRASH_REG_COUNT 20
#define CRASH_UNWIND_NODES 128
#define CRASH_WAIT_US MS_TO_US(500) /* Quiesce timeout per peer CPU */
#define CRASH_SPIN_ONE_US 5
#define CRASH_MAX_DEPTH 2 /* Max recursive fault depth */
#define CRASH_MSG_MAX 256
#define CRASH_PAYLOAD(c, d) ((struct crash_payload) {.code = c, .data = d})
#define CRASH_PARAMS(c, p0, p1, p2, p3) \
    ((struct crash_payload) {.code = (c), \
                             .params = {(uintptr_t) (p0), (uintptr_t) (p1), \
                                        (uintptr_t) (p2), (uintptr_t) (p3)}})
#define CRASH_CODE_TO_PAYLOAD(c) ((struct crash_payload) {.code = c})
#define CRASH_CODE_CREATE(pre, del) \
    ({ ((((int) (pre)) << 16) | (((int) (del)) & 0xFFFF)); })
#define CRASH_CODE_GET_FACILITY(c) ({ (((c)) >> 16) & 0xFFFF; })
#define CRASH_CODE_GET_DELTA(c) ({ (((c)) & 0xFFFF); })
#define CRASH_CODE_PREFIX(n) ((__crash_facility_##n).prefix)
#define CRASH_CODE_DELTA_START (1)
#define CRASH_CODE(n, d) CRASH_CODE_CREATE(CRASH_CODE_PREFIX(n), d)
#define CRASH_FACILITY(n) __crash_facility_##n
#define CRASH_FACILITY_EXTERN(n) \
    extern struct crash_facility __crash_facility_##n
#define CRASH_FACILITY_DECLARE(n, ...) \
    LINKER_SECTION_OBJECT(struct crash_facility, crash_facilities) \
    __crash_facility_##n = {.name = #n, __VA_ARGS__}