1 /*
2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <stdio.h>
8 #include <stdarg.h>
9 #include <sys/cdefs.h>
10 #include <unistd.h>
11 #include "pico.h"
12 
13 #if LIB_PICO_PRINTF_PICO
14 #include "pico/printf.h"
15 #else
16 #define weak_raw_printf printf
17 #define weak_raw_vprintf vprintf
18 #endif
19 
panic_unsupported(void)20 void __attribute__((noreturn)) panic_unsupported(void) {
21     panic("not supported");
22 }
23 
24 // PICO_CONFIG: PICO_PANIC_FUNCTION, Name of a function to use in place of the stock panic function or empty string to simply breakpoint on panic, group=pico_runtime
25 // note the default is not "panic" it is undefined
26 #ifdef PICO_PANIC_FUNCTION
27 #define PICO_PANIC_FUNCTION_EMPTY (__CONCAT(PICO_PANIC_FUNCTION, 1) == 1)
28 #if !PICO_PANIC_FUNCTION_EMPTY
29 extern void __attribute__((noreturn)) __printflike(1, 0) PICO_PANIC_FUNCTION(__unused const char *fmt, ...);
30 #endif
31 // Use a forwarding method here as it is a little simpler than renaming the symbol as it is used from assembler
panic(__unused const char * fmt,...)32 void __attribute__((naked, noreturn)) __printflike(1, 0) panic(__unused const char *fmt, ...) {
33     // if you get an undefined reference here, you didn't define your PICO_PANIC_FUNCTION!
34     pico_default_asm (
35 #ifdef __riscv
36 
37 #if !PICO_PANIC_FUNCTION_EMPTY
38             "jal " __XSTRING(PICO_PANIC_FUNCTION) "\n"
39 #endif
40             "1: ebreak\n"
41             "j 1b\n"
42 
43 #else
44 
45             "push {lr}\n"
46 #if !PICO_PANIC_FUNCTION_EMPTY
47             "bl " __XSTRING(PICO_PANIC_FUNCTION) "\n"
48 #endif
49             "1: bkpt #0\n"
50             "b 1b\n" // loop for ever as we are no return
51 
52 #endif
53         :
54         :
55         :
56     );
57 }
58 #else
59 // todo consider making this try harder to output if we panic early
60 //  right now, print mutex may be uninitialised (in which case it deadlocks - although after printing "PANIC")
61 //  more importantly there may be no stdout/UART initialized yet
62 // todo we may want to think about where we print panic messages to; writing to USB appears to work
63 //  though it doesn't seem like we can expect it to... fine for now
panic(const char * fmt,...)64 void __attribute__((noreturn)) __printflike(1, 0) panic(const char *fmt, ...) {
65     puts("\n*** PANIC ***\n");
66     if (fmt) {
67 #if LIB_PICO_PRINTF_NONE
68         puts(fmt);
69 #else
70         va_list args;
71         va_start(args, fmt);
72 #if PICO_PRINTF_ALWAYS_INCLUDED
73         vprintf(fmt, args);
74 #else
75         weak_raw_vprintf(fmt, args);
76 #endif
77         va_end(args);
78         puts("\n");
79 #endif
80     }
81 
82     _exit(1);
83 }
84 #endif
85