12#define REPORT_SIZE 3072
14#define STACK_SCAN_BYTES 16384
16#define UNCACHED(p) ((uintptr_t)(p) | 0x20000000u)
29extern void __crash_vector(
void);
33typedef void (*terminate_fn)(void);
34extern terminate_fn std_set_terminate(terminate_fn) __asm__(
"_ZSt13set_terminatePFvvE")
__attribute__((weak));
35extern
void *__cxa_current_primary_exception(
void)
__attribute__((weak));
36extern const
void *__cxa_current_exception_type(
void)
__attribute__((weak));
38extern
int _Unwind_Backtrace(
int (*)(
void *,
void *),
void *)
__attribute__((weak));
41static const
char *const exception_names[16] = {
42 "Interrupt",
"TLB modification",
"TLB miss on load or fetch",
"TLB miss on store",
43 "Address error on load or fetch (AdEL)",
"Address error on store (AdES)",
44 "Bus error on fetch (IBE)",
"Bus error on data (DBE)",
"Syscall",
"Breakpoint (BREAK)",
45 "Reserved instruction (RI)",
"Coprocessor unusable (CpU)",
"Arithmetic overflow (Ov)",
"Trap",
49static const char *
const gpr_names[32] = {
50 "zr",
"at",
"v0",
"v1",
"a0",
"a1",
"a2",
"a3",
"t0",
"t1",
"t2",
"t3",
"t4",
"t5",
"t6",
"t7",
51 "s0",
"s1",
"s2",
"s3",
"s4",
"s5",
"s6",
"s7",
"t8",
"t9",
"k0",
"k1",
"gp",
"sp",
"fp",
"ra"
54static const int hooked_causes[] = {1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13};
56static void *old_handlers[16];
58static terminate_fn old_terminate;
61static int chain_previous;
63extern void __crash_chain(
const struct crash_frame *f);
65static char report[REPORT_SIZE];
67static uint32_t bt[BT_MAX];
70static uint32_t pkt[(6 + FB_WIDTH) * 4]
__attribute__((aligned(16)));
74 if (report_len < REPORT_SIZE - 1)
75 report[report_len++] = c;
78static void rs(
const char *s)
84static void rhex(uint32_t v)
86 for (
int i = 28; i >= 0; i -= 4)
87 rc(
"0123456789ABCDEF"[(v >> i) & 15]);
90static int addr_in_ram(uint32_t a)
92 return a >= 0x00100000u && a < 0x02000000u;
95static int in_text(uint32_t a)
97 return a >= (uint32_t)_ftext && a < (uint32_t)_etext;
100static void bt_add(uint32_t a)
102 if (bt_count < BT_MAX)
106static int looks_like_return(uint32_t a)
108 if (!in_text(a) || (a & 3) || !in_text(a - 8))
110 uint32_t insn = *(
const uint32_t *)(a - 8);
111 return (insn >> 26) == 3 || (insn & 0xFC00003Fu) == 0x00000009u;
114static void scan_stack(uint32_t sp)
116 if (!addr_in_ram(sp))
118 uint32_t end = sp + STACK_SCAN_BYTES;
119 if (end > 0x02000000u)
121 for (uint32_t p = sp & ~3u; p < end && bt_count < BT_MAX; p += 4) {
122 uint32_t v = *(
const uint32_t *)p;
123 if (looks_like_return(v))
128static int unwind_cb(
void *ctx,
void *arg)
131 bt_add((uint32_t)_Unwind_GetIP(ctx));
135static void emit_report(
const char *reason,
const char *detail,
const struct crash_frame *f, uint32_t sp)
138 rs(
"PROGRAM CRASHED\n");
142 if (detail && *detail) {
161 for (
int i = 1; i < 32; i++) {
165 rc((i % 6) == 0 || i == 31 ?
'\n' :
' ');
172 rs(
"\nBacktrace (return addresses):\n");
173 for (
int i = 0; i < bt_count; i++) {
175 rc((i % 8) == 7 || i == bt_count - 1 ?
'\n' :
' ');
179 rs(
"Resolve with: ps2symbolize <elf> <address...>\n");
180 report[report_len] = 0;
183static void send_console(
void)
188 for (
int i = 0; i <= report_len; i++) {
190 if (c ==
'\n' || c == 0 || n >= COLS) {
195 if (c !=
'\n' && c != 0)
203static void send_stdout(
void)
206 __asm__
volatile(
"mfc0 %0, $12" :
"=r"(st));
207 __asm__
volatile(
"mtc0 %0, $12\n\tsync.p" ::
"r"(st | 1u | (1u << 16)));
208 write(1, report, report_len);
210 __asm__
volatile(
"mtc0 %0, $12\n\tsync.p" ::
"r"(st));
213static void gs_setup(
int pal)
215 volatile uint64_t *gs = (
volatile uint64_t *)0x12000000;
216 volatile uint32_t *dma = (
volatile uint32_t *)0x1000A000;
217 int height = pal ? 256 : 224;
220 *(
volatile uint32_t *)0x1000E000 = 1;
221 *(
volatile uint32_t *)0x10003000 = 1;
222 *(
volatile uint32_t *)0x10003000 = 0;
223 *(
volatile uint64_t *)0x12001000 = 0x200;
224 __asm__
volatile(
"sync.p");
225 *(
volatile uint64_t *)0x12001000 = 0;
227 SetGsCrt(0, pal ? 3 : 2, 0);
229 gs[0x00 / 8] = 0x8046;
230 uint64_t dispfb = (uint64_t)(FB_WIDTH / 64) << 9 | (uint64_t)2 << 15;
231 uint64_t display = (uint64_t)(pal ? 656 : 636) | (uint64_t)(pal ? 36 : 25) << 12 | (uint64_t)3 << 23 |
232 (uint64_t)2559 << 32 | (uint64_t)(height - 1) << 44;
233 gs[0x70 / 8] = dispfb;
234 gs[0x80 / 8] = display;
235 gs[0x90 / 8] = dispfb;
236 gs[0xA0 / 8] = display;
240static void gs_send_row(
int y,
const char *text,
int len,
int color_red)
242 volatile uint32_t *q = (
volatile uint32_t *)UNCACHED(pkt);
243 volatile uint16_t *px = (
volatile uint16_t *)UNCACHED(&pkt[6 * 4]);
244 volatile uint32_t *dma = (
volatile uint32_t *)0x1000A000;
246 q[0] = 4 | (1 << 15);
251 q[5] = (10u << 16) | (2u << 24);
255 q[9] = (uint32_t)y << 16;
266 q[20] = FB_WIDTH | (1 << 15);
271 for (
int i = 0; i < FB_WIDTH * 8; i++)
273 uint16_t color = color_red ? 0x801F : 0xFFFF;
274 for (
int k = 0; k < len; k++) {
275 unsigned char c = (
unsigned char)text[k];
276 if (c < 32 || c > 126)
278 const unsigned char *g = crash_font[c - 32];
280 for (
int row = 0; row < 8; row++)
281 for (
int b = 0; b < 8; b++)
282 if ((g[row] >> b) & 1)
283 px[row * FB_WIDTH + x0 + b] = color;
286 __asm__
volatile(
"sync.l" :::
"memory");
287 dma[0x20 / 4] = 6 + FB_WIDTH;
288 dma[0x10 / 4] = (uint32_t)((uintptr_t)pkt & 0x0FFFFFFF);
290 for (
int t = 0; t < 20000000 && (dma[0] & 0x100); t++)
294static void draw_report(
int pal)
296 int height = pal ? 256 : 224;
297 int pixel_rows = height / 8;
298 int text_rows = pixel_rows - 2;
302 uint32_t d_ctrl = *(
volatile uint32_t *)0x1000E000;
305 for (
int r = 0; r < pixel_rows; r++) {
308 if (r >= 1 && r <= text_rows) {
309 while (pos < report_len && report[pos] !=
'\n' && len < COLS)
310 line[len++] = report[pos++];
311 if (pos < report_len && report[pos] ==
'\n')
314 gs_send_row(r * 8, line, len, red);
316 *(
volatile uint32_t *)0x1000E010 = 1u << 2;
317 *(
volatile uint32_t *)0x1000E000 = d_ctrl;
320static int console_is_pal(
void)
322 return *(
volatile char *)0xBFC7FF52 ==
'E';
325static void quiesce(
void)
328 __asm__
volatile(
"mfc0 %0, $12" :
"=r"(st));
329 st &= ~((1u << 0) | (1u << 1) | (3u << 3) | (1u << 16));
330 __asm__
volatile(
"mtc0 %0, $12\n\tsync.p" ::
"r"(st));
333void __crash_sleep(
void)
339extern void __crash_leave(
void (*fn)(
void));
341static void idle(
void)
343 __crash_leave(__crash_sleep);
346static void finish(
const char *reason,
const char *detail,
const struct crash_frame *f, uint32_t sp)
353 emit_report(reason, detail, f, sp);
354 draw_report(console_is_pal());
359 if (chain_previous && f) {
360 int c = (f->cause >> 2) & 15;
361 if (old_handlers[c]) {
363 SetVTLBRefillHandler(c, old_handlers[c]);
365 SetVCommonHandler(c, old_handlers[c]);
376 int code = (f->cause >> 2) & 31;
378 if (looks_like_return(f->gpr[31]))
380 scan_stack(f->gpr[29]);
381 finish(exception_names[code & 15], NULL, f, f->gpr[29]);
384static const char *exception_what(
char *name_out,
size_t name_size)
387 if (!__cxa_current_primary_exception || !__cxa_current_exception_type)
389 const void *type = __cxa_current_exception_type();
390 void *obj = __cxa_current_primary_exception();
393 const char *tn = *(
const char *
const *)((
const char *)type + 4);
394 if (addr_in_ram((uint32_t)tn)) {
396 for (; tn[i] && i + 1 < name_size; i++)
400 if (!obj || !_ZTISt9exception || !addr_in_ram((uint32_t)obj))
402 const uint32_t *t = (
const uint32_t *)type;
403 for (
int depth = 0; t != (
const uint32_t *)_ZTISt9exception; depth++) {
404 if (depth == 8 || !addr_in_ram(t[2]) || !addr_in_ram(((
const uint32_t *)t[2])[1]))
406 t = (
const uint32_t *)t[2];
408 void **svptr = *(
void ***)obj;
409 if (!addr_in_ram((uint32_t)svptr))
411 const char *(*what)(
void *) = (
const char *(*)(
void *))svptr[2];
415static void terminate_handler(
void)
421 __asm__
volatile(
"move %0, $29" :
"=r"(sp));
423 const char *what = exception_what(name,
sizeof(name));
424 const char *prefix = name[0] ?
"Type: " :
"";
425 for (
const char *s = prefix; *s && n < (int)
sizeof(detail) - 1; s++)
427 for (
const char *s = name; *s && n < (int)
sizeof(detail) - 1; s++)
430 const char *sep = name[0] ?
" what(): " :
"what(): ";
431 for (
const char *s = sep; *s && n < (int)
sizeof(detail) - 1; s++)
433 for (
int i = 0; what[i] && i < 120 && n < (int)
sizeof(detail) - 1; i++)
434 detail[n++] = what[i];
439 if (_Unwind_Backtrace && _Unwind_GetIP) {
440 _Unwind_Backtrace(unwind_cb, NULL);
442 for (
int i = 1; i < bt_count; i++)
449 finish(
"std::terminate (uncaught exception)", detail, NULL, sp);
455 __asm__
volatile(
"move %0, $29" :
"=r"(sp));
458 finish(reason ? reason :
"crashscreen_abort", NULL, NULL, sp);
465 chain_previous = enable;
477 for (
unsigned i = 0; i <
sizeof(hooked_causes) /
sizeof(hooked_causes[0]); i++) {
478 int c = hooked_causes[i];
481 SetVTLBRefillHandler(c, __crash_vector);
483 SetVCommonHandler(c, __crash_vector);
485 if (std_set_terminate)
486 old_terminate = std_set_terminate(terminate_handler);
496 for (
unsigned i = 0; i <
sizeof(hooked_causes) /
sizeof(hooked_causes[0]); i++) {
497 int c = hooked_causes[i];
498 if (!old_handlers[c])
501 SetVTLBRefillHandler(c, old_handlers[c]);
503 SetVCommonHandler(c, old_handlers[c]);
504 old_handlers[c] = NULL;
506 if (std_set_terminate)
507 std_set_terminate(old_terminate);
void crashscreen_set_chain(int enable)
void crashscreen_abort(const char *reason) __attribute__((noreturn))
void crashscreen_set_hook(crashscreen_hook_t hook)
void crashscreen_remove(void)
void crashscreen_install(void)
void(*) crashscreen_hook_t(const char *report)
void * GetExceptionHandler(int except_no)