Crash Engine
include/console/crash.h View source View on GitHubStructs
Section titled “Structs”crash_regs
Section titled “crash_regs” struct crash_regs (1 field) source
crash_code
Section titled “crash_code” struct crash_code (3 fields) source
NULL crashes are the generic, code-less crash
const char *name const char *desc const struct crash_facility *facility crash_payload
Section titled “crash_payload” struct crash_payload (3 fields) source
crash_facility
Section titled “crash_facility” struct crash_facility (5 fields) source
const char *name const char *desc const struct crash_code *const *codes list order
size_t nr_codes void (*const dump)(struct crash_payload pl) crash_unwind_node_data
Section titled “crash_unwind_node_data” struct crash_unwind_node_data (2 fields) source
crash_unwind_node
Section titled “crash_unwind_node” struct crash_unwind_node (3 fields) source
crash_unwind_thread_data
Section titled “crash_unwind_thread_data” struct crash_unwind_thread_data (3 fields) source
struct crash_unwind_node nodes[CRASH_UNWIND_NODES] crash_thread_data
Section titled “crash_thread_data” struct crash_thread_data (5 fields) source
crash_hook
Section titled “crash_hook” struct crash_hook (4 fields) source
The idea of crash hooks:
A hook can hook into a specific code, which is checked against a facility to verify if it is hookable.
They are hooked PER-THREAD, so as to not introduce strange non-determinism bugs and the chance that the crash hook registration path itself can crash (would be problematic) due to synchronization violations.
The generic (NULL) code is not hookable
char *name const struct crash_code *code enum crash_source source_mask crash_context
Section titled “crash_context” struct crash_context (10 fields) source
struct crash_payload payload enum crash_source source enum crash_format_flags formats const char *stmt const char *file int line const char *func const char *msg const struct crash_regs *regs NULL = capture caller’s frame via asm
void *source_data qemu_exit_codes
Section titled “qemu_exit_codes” enum qemu_exit_codes (3 variants) source
crash_source
Section titled “crash_source” enum crash_source (8 variants) source
CRASH_SOURCE_KASAN ASAN check failure
CRASH_SOURCE_UBSAN UBSAN failure
CRASH_SOURCE_NMI_WATCHDOG Watchdog / Liveness monitor hard stall
CRASH_SOURCE_CPU_EXCEPTION Hardware CPU fault
CRASH_SOURCE_NIGHTMARE Nightmare test harness failure
CRASH_SOURCE_LOCK_CHK Lock validator order / dependency violation
crash_format_flags
Section titled “crash_format_flags” enum crash_format_flags (7 variants) source
CRASH_FMT_RAW_SERIAL = 1 << 0 Minimal serial printf
CRASH_FMT_VISUAL_PANES = 1 << 1 Dual pane ANSI console report
CRASH_FMT_NDJSON = 1 << 2 NDJSON stream
CRASH_FMT_DUMP_LOGS = 1 << 3 circular log buffer dump
CRASH_FMT_PEER_CPUS = 1 << 4 Quiesce and render peer CPU frames
CRASH_FMT_DEFAULT = CRASH_FMT_RAW_SERIAL | CRASH_FMT_VISUAL_PANES | CRASH_FMT_NDJSON | CRASH_FMT_DUMP_LOGS | CRASH_FMT_PEER_CPUS Default formatting
CRASH_FMT_MINIMAL = CRASH_FMT_RAW_SERIAL | CRASH_FMT_NDJSON Minimal formatting for early boot or nested crashes
crash_hook_flags
Section titled “crash_hook_flags” enum crash_hook_flags (3 variants) source
CRASH_HOOK_DEFAULT = 0 CRASH_HOOK_FACILITY = 1 << 0 Facility granularity: match any code whose ->facility is the code’s facility
CRASH_HOOK_NO_UNWIND = 1 << 1 By default, the crash handler will make a best-effort attempt to unwind: it’ll try to safely drop locks, exit RCU read-side critical sections, although memory may still leak (this is dependent on the facility implementation).
NO_UNWIND allows this behavior to be skipped. This is because in certain cases, the unwinding cannot happen (e.g. lock checking is disabled), and also because the stale state not unwinding leaves can be used as a postmortem for state verification.
crash_unwind_type
Section titled “crash_unwind_type” enum crash_unwind_type (7 variants) source
Functions
Section titled “Functions”enforce_impl_code_only
Section titled “enforce_impl_code_only”void enforce_impl_precond_msg(const char *file, int line, const char *func, const char *prefix, const char *expr, const char *fmt, ...) cc_printf_like(6, 7); cc_noreturn void enforce_impl_code(const char *file, int line, const char *func, const char *prefix, const char *expr, const struct crash_code *code, const char *fmt, ...) cc_printf_like(7, 8); cc_noreturn void enforce_impl_code_only(
const char *file,
int line,
const char *func,
const char *prefix,
const char *expr,
const struct crash_code *code
) source enforce_impl_msg() with INVALID_ARGUMENT for enforce_precond()crash_full
Section titled “crash_full”cc_noreturn void crash_full(const struct crash_context *ctx) source crash_cpu_is_owner
Section titled “crash_cpu_is_owner”bool crash_cpu_is_owner(uint64_t id) source crash_broadcast_nmi
Section titled “crash_broadcast_nmi”void crash_broadcast_nmi(void) source crash_code_name
Section titled “crash_code_name”size_t crash_code_name(
const struct crash_code *code,
char *buf,
size_t len
) source crash_nmi_handoff
Section titled “crash_nmi_handoff”void crash_nmi_handoff(void *p, struct irq_registers *irqc) source debug_print_stack
Section titled “debug_print_stack”void debug_print_stack(void) source crash_code_in_facility
Section titled “crash_code_in_facility”bool crash_code_in_facility(
const struct crash_code *code,
const struct crash_facility *f
) source crash_thread_init
Section titled “crash_thread_init”crash_unwind
Section titled “crash_unwind”void crash_unwind(void) source Enter/exit pairs
crash_unwind_enter_rcu
Section titled “crash_unwind_enter_rcu”void crash_unwind_enter_rcu(void) source crash_unwind_exit_rcu
Section titled “crash_unwind_exit_rcu”void crash_unwind_exit_rcu(void) source crash_unwind_enter_mutex
Section titled “crash_unwind_enter_mutex”crash_unwind_exit_mutex
Section titled “crash_unwind_exit_mutex”crash_unwind_enter_rwlock
Section titled “crash_unwind_enter_rwlock”crash_unwind_exit_rwlock
Section titled “crash_unwind_exit_rwlock”crash_unwind_enter_spinlock
Section titled “crash_unwind_enter_spinlock”crash_unwind_exit_spinlock
Section titled “crash_unwind_exit_spinlock”crash_unwind_enter_qspinlock
Section titled “crash_unwind_enter_qspinlock”crash_unwind_exit_qspinlock
Section titled “crash_unwind_exit_qspinlock”crash_thread_init
Section titled “crash_thread_init”crash_unwind
Section titled “crash_unwind”void crash_unwind(void) source crash_unwind_enter_rcu
Section titled “crash_unwind_enter_rcu”void crash_unwind_enter_rcu(void) source crash_unwind_exit_rcu
Section titled “crash_unwind_exit_rcu”void crash_unwind_exit_rcu(void) source crash_unwind_enter_mutex
Section titled “crash_unwind_enter_mutex”crash_unwind_exit_mutex
Section titled “crash_unwind_exit_mutex”crash_unwind_enter_rwlock
Section titled “crash_unwind_enter_rwlock”crash_unwind_exit_rwlock
Section titled “crash_unwind_exit_rwlock”crash_unwind_enter_spinlock
Section titled “crash_unwind_enter_spinlock”crash_unwind_exit_spinlock
Section titled “crash_unwind_exit_spinlock”crash_unwind_enter_qspinlock
Section titled “crash_unwind_enter_qspinlock”crash_unwind_exit_qspinlock
Section titled “crash_unwind_exit_qspinlock”qemu_exit
Section titled “qemu_exit”void qemu_exit(int code) source Variables
Section titled “Variables”cc_noreturn
Section titled “cc_noreturn”cc_noreturn void enforce_impl_msg(const char *file, int line, const char *func, const char *prefix, const char *expr, const char *fmt, ...) cc_printf_like(6, 7); /* enforce_impl_msg() with INVALID_ARGUMENT for enforce_precond() */ cc_noreturn source Macros
Section titled “Macros”CRASH_REG_COUNT
Section titled “CRASH_REG_COUNT”#define CRASH_REG_COUNT 20 source CRASH_CODES_global
Section titled “CRASH_CODES_global”#define CRASH_CODES_global source Codes that don’t have a facility, like enforce(p, INVALID_ARGUMENT)
Expansion
#define CRASH_CODES_global \
(INVALID_ARGUMENT, "Argument was NULL or out of range"), \
(INVALID_STATE, "Object was in a state this operation forbids"), \
(INVALID_CONTEXT, \
"Operation ran at a forbidden IRQL, IRQ or boot stage"), \
(OUT_OF_MEMORY, "Allocation that must not fail did fail"), \
(UNSUPPORTED, "Hardware or firmware lacks a required feature"), \
(CORRUPTION, "Data structure or allocator invariant was broken"), \
(CAPACITY_EXCEEDED, "A fixed-size limit was exceeded"), \
(UNREACHABLE, "Control reached a path that must not execute"), \
(DUPLICATE, "Object was registered, inserted, or defined twice"), \
(OVERFLOW, "Counter or arithmetic result exceeded its range"), \
(UNDERFLOW, "Counter was decremented below zero"), \
(STALE_REFERENCE, "Reference to an object that is dying or dead"), \
(BAD_FREE, "Freed memory was already free or never allocated"), \
(UNINITIALIZED, "Object was used before initialization"), \
(INIT_FAILED, "A required initialization step failed"), \
(NOT_FOUND, "Lookup that must succeed found nothing") CRASH_UNWIND_NODES
Section titled “CRASH_UNWIND_NODES”#define CRASH_UNWIND_NODES 128 source CRASH_WAIT_US
Section titled “CRASH_WAIT_US”CRASH_SPIN_ONE_US
Section titled “CRASH_SPIN_ONE_US”#define CRASH_SPIN_ONE_US 5 source CRASH_MAX_DEPTH
Section titled “CRASH_MAX_DEPTH”#define CRASH_MAX_DEPTH 2 source Max recursive fault depth
CRASH_MSG_MAX
Section titled “CRASH_MSG_MAX”#define CRASH_MSG_MAX 256 source CRASH_PAYLOAD
Section titled “CRASH_PAYLOAD”#define CRASH_PAYLOAD(c, d) source Expansion
#define CRASH_PAYLOAD(c, d) ((struct crash_payload) {.code = c, .data = d}) CRASH_PARAMS
Section titled “CRASH_PARAMS”#define CRASH_PARAMS(c, p0, p1, p2, p3) source Expansion
#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)}}) CRASH_CODE_TO_PAYLOAD
Section titled “CRASH_CODE_TO_PAYLOAD”#define CRASH_CODE_TO_PAYLOAD(c) source Expansion
#define CRASH_CODE_TO_PAYLOAD(c) ((struct crash_payload) {.code = c}) CRASH_FACILITY
Section titled “CRASH_FACILITY”#define CRASH_FACILITY(f) source Use like this:
#define CRASH_CODES_asan
(USE_AFTER_FREE, “Use after free”),
(PARTIAL_GRANULE)
CRASH_CODE(asan, USE_AFTER_FREE)Expansion
#define CRASH_FACILITY(f) __crash_facility_##f CRASH_CODE
Section titled “CRASH_CODE”#define CRASH_CODE(f, n) source Expansion
#define CRASH_CODE(f, n) _crash_code_sym(f, n) CRASH_CODE_NTH
Section titled “CRASH_CODE_NTH”#define CRASH_CODE_NTH(f, i) source Expansion
#define CRASH_CODE_NTH(f, i) __crash_codes_##f[(i)] CRASH_CODES_ENUM
Section titled “CRASH_CODES_ENUM”#define CRASH_CODES_ENUM(f, prefix) source Expansion
#define CRASH_CODES_ENUM(f, prefix) \
PP_FOREACH_CTX(_crash_code_enumerator, prefix, CRASH_CODES_##f) crash_code_in
Section titled “crash_code_in”#define crash_code_in(c, f) source Expansion
#define crash_code_in(c, f) crash_code_in_facility((c), &CRASH_FACILITY(f)) CRASH_CODES_DECLARE
Section titled “CRASH_CODES_DECLARE”#define CRASH_CODES_DECLARE(f) source Expansion
#define CRASH_CODES_DECLARE(f) \
extern const struct crash_facility CRASH_FACILITY(f); \
extern const struct crash_code *const __crash_codes_##f[]; \
PP_FOREACH_CTX(_crash_code_extern, f, CRASH_CODES_##f) CRASH_FACILITY_DEFINE
Section titled “CRASH_FACILITY_DEFINE”#define CRASH_FACILITY_DEFINE(f, d, ...) source Expansion
#define CRASH_FACILITY_DEFINE(f, d, ...) \
CRASH_CODES_DECLARE(f); \
PP_FOREACH_CTX(_crash_code_def, f, CRASH_CODES_##f) \
const struct crash_code *const __crash_codes_##f[] = { \
PP_FOREACH_CTX(_crash_code_ptr, f, CRASH_CODES_##f)}; \
const struct crash_facility CRASH_FACILITY(f) = { \
.name = #f, \
.desc = d, \
.codes = __crash_codes_##f, \
.nr_codes = ct_array_size(__crash_codes_##f), \
__VA_ARGS__} _crash_code_sym
Section titled “_crash_code_sym”#define _crash_code_sym(f, n) source Expansion
#define _crash_code_sym(f, n) __crash_code_##f##_##n _crash_code_name
Section titled “_crash_code_name”#define _crash_code_name(t) source Expansion
#define _crash_code_name(t) PP_GET_1 t _crash_code_desc
Section titled “_crash_code_desc”#define _crash_code_desc(t) source Expansion
#define _crash_code_desc(t) _crash_code_desc_(PP_UNPAREN(t), NULL, ~) crash_code_desc
Section titled “crash_code_desc”#define _crash_code_desc_(...) source Expansion
#define _crash_code_desc_(...) _crash_code_desc_pick(__VA_ARGS__) _crash_code_desc_pick
Section titled “_crash_code_desc_pick”#define _crash_code_desc_pick(n, d, ...) source Expansion
#define _crash_code_desc_pick(n, d, ...) d _crash_code_extern
Section titled “_crash_code_extern”#define _crash_code_extern(f, t) source Expansion
#define _crash_code_extern(f, t) _crash_code_extern_(f, _crash_code_name(t)) crash_code_extern
Section titled “crash_code_extern”#define _crash_code_extern_(f, n) source Expansion
#define _crash_code_extern_(f, n) \
extern const struct crash_code _crash_code_sym(f, n)[1]; _crash_code_def
Section titled “_crash_code_def”#define _crash_code_def(f, t) source Expansion
#define _crash_code_def(f, t) \
_crash_code_def_(f, _crash_code_name(t), _crash_code_desc(t)) crash_code_def
Section titled “crash_code_def”#define _crash_code_def_(f, n, d) source Expansion
#define _crash_code_def_(f, n, d) \
const struct crash_code _crash_code_sym(f, n)[1] = { \
{PP_STRINGIZE(n), d, &CRASH_FACILITY(f)}}; _crash_code_ptr
Section titled “_crash_code_ptr”#define _crash_code_ptr(f, t) source Expansion
#define _crash_code_ptr(f, t) _crash_code_ptr_(f, _crash_code_name(t)) crash_code_ptr
Section titled “crash_code_ptr”#define _crash_code_ptr_(f, n) source Expansion
#define _crash_code_ptr_(f, n) _crash_code_sym(f, n), _crash_code_enumerator
Section titled “_crash_code_enumerator”#define _crash_code_enumerator(p, t) source Expansion
#define _crash_code_enumerator(p, t) PP_CONCAT(p, _crash_code_name(t)), CRASH_CODE_ARG
Section titled “CRASH_CODE_ARG”#define CRASH_CODE_ARG(a) source Expansion
#define CRASH_CODE_ARG(a) PP_IIF(PP_IS_PAREN(a))(_crash_tuple_code(a), a) _crash_tuple_code
Section titled “_crash_tuple_code”#define _crash_tuple_code(t) source Expansion
#define _crash_tuple_code(t) \
PP_CONCAT(_crash_tuple_code_, _crash_narg(PP_UNPAREN(t))) t _crash_narg
Section titled “_crash_narg”#define _crash_narg(...) source Expansion
#define _crash_narg(...) PP_NARG(__VA_ARGS__) _crash_tuple_code_1
Section titled “_crash_tuple_code_1”#define _crash_tuple_code_1(n) source Expansion
#define _crash_tuple_code_1(n) CRASH_CODE(global, n) _crash_tuple_code_2
Section titled “_crash_tuple_code_2”#define _crash_tuple_code_2(f, n) source Expansion
#define _crash_tuple_code_2(f, n) CRASH_CODE(f, n) CRASH_CODE_SCOPED
Section titled “CRASH_CODE_SCOPED”#define CRASH_CODE_SCOPED(a, ...) source Wraps stmt in the bare-name scope unless code was a tuple
Expansion
#define CRASH_CODE_SCOPED(a, ...) \
PP_CONCAT(_crash_code_scoped_, PP_IS_PAREN(a))(__VA_ARGS__) _crash_code_scoped_1
Section titled “_crash_code_scoped_1”#define _crash_code_scoped_1(...) source Expansion
#define _crash_code_scoped_1(...) __VA_ARGS__ _crash_code_scoped_0
Section titled “_crash_code_scoped_0”#define _crash_code_scoped_0(...) source Expansion
#define _crash_code_scoped_0(...) \
({ \
_CRASH_CODE_SCOPE \
__VA_ARGS__; \
}) _crash_code_alias
Section titled “_crash_code_alias”#define _crash_code_alias(f, t) source Expansion
#define _crash_code_alias(f, t) _crash_code_alias_(f, _crash_code_name(t)) crash_code_alias
Section titled “crash_code_alias”#define _crash_code_alias_(f, n) source Expansion
#define _crash_code_alias_(f, n) \
cc_unused extern const struct crash_code n[1] asm(PP_STRINGIZE(__USER_LABEL_PREFIX__) PP_STRINGIZE(_crash_code_sym(f, n))); _CRASH_CODE_SCOPE
Section titled “_CRASH_CODE_SCOPE”#define _CRASH_CODE_SCOPE source Expansion
#define _CRASH_CODE_SCOPE \
PP_FOREACH_CTX(_crash_code_alias, global, CRASH_CODES_global)