From 1ae271f31a6d998f62f02a988293387872021743 Mon Sep 17 00:00:00 2001
From: me-no-dev <hristo@espressif.com>
Date: Thu, 5 Oct 2023 15:14:23 +0300
Subject: [PATCH 1/2] Add support for custom panic handler

---
 cores/esp32/esp32-hal-misc.c | 90 ++++++++++++++++++++++++++++++++++++
 cores/esp32/esp32-hal.h      | 16 +++++++
 platform.txt                 |  2 +-
 3 files changed, 107 insertions(+), 1 deletion(-)

diff --git a/cores/esp32/esp32-hal-misc.c b/cores/esp32/esp32-hal-misc.c
index 6a7931117ad..08c69e12416 100644
--- a/cores/esp32/esp32-hal-misc.c
+++ b/cores/esp32/esp32-hal-misc.c
@@ -322,3 +322,93 @@ const char * ARDUINO_ISR_ATTR pathToFileName(const char * path)
     return path+pos;
 }
 
+#include "esp_rom_sys.h"
+#include "esp_debug_helpers.h"
+#if CONFIG_IDF_TARGET_ARCH_XTENSA
+#include "esp_cpu_utils.h"
+#else
+#include "riscv/rvruntime-frames.h"
+#endif
+#include "esp_memory_utils.h"
+#include "esp_private/panic_internal.h"
+
+static arduino_panic_handler_t _panic_handler = NULL;
+static void * _panic_handler_arg = NULL;
+
+void set_arduino_panic_handler(arduino_panic_handler_t handler, void * arg){
+    _panic_handler = handler;
+    _panic_handler_arg = arg;
+}
+
+arduino_panic_handler_t * get_arduino_panic_handler(void){
+    return _panic_handler;
+}
+
+void * get_arduino_panic_handler_arg(void){
+    return _panic_handler_arg;
+}
+
+static void handle_custom_backtrace(panic_info_t* info){
+    arduino_panic_info_t p_info;
+    p_info.reason = info->reason;
+    p_info.core = info->core;
+    p_info.pc = info->addr;
+    p_info.backtrace_len = 0;
+    p_info.backtrace_corrupt = false;
+    p_info.backtrace_continues = false;
+
+#if CONFIG_IDF_TARGET_ARCH_XTENSA
+    XtExcFrame *xt_frame = (XtExcFrame *) info->frame;
+    esp_backtrace_frame_t stk_frame = {.pc = xt_frame->pc, .sp = xt_frame->a1, .next_pc = xt_frame->a0, .exc_frame = xt_frame};
+    uint32_t i = 100, pc_ptr = esp_cpu_process_stack_pc(stk_frame.pc);
+    p_info.backtrace[p_info.backtrace_len++] = pc_ptr;
+
+    bool corrupted = !(esp_stack_ptr_is_sane(stk_frame.sp) &&
+                      (esp_ptr_executable((void *)esp_cpu_process_stack_pc(stk_frame.pc)) ||
+                      /* Ignore the first corrupted PC in case of InstrFetchProhibited */
+                      (stk_frame.exc_frame && ((XtExcFrame *)stk_frame.exc_frame)->exccause == EXCCAUSE_INSTR_PROHIBITED)));
+
+    while (i-- > 0 && stk_frame.next_pc != 0 && !corrupted) {
+        if (!esp_backtrace_get_next_frame(&stk_frame)) {
+            corrupted = true;
+        }
+        pc_ptr = esp_cpu_process_stack_pc(stk_frame.pc);
+        if(esp_ptr_executable((void *)pc_ptr)){
+            p_info.backtrace[p_info.backtrace_len++] = pc_ptr;
+            if(p_info.backtrace_len == 60){
+                break;
+            }
+        }
+    }
+
+    if (corrupted) {
+        p_info.backtrace_corrupt = true;
+    } else if (stk_frame.next_pc != 0) {
+        p_info.backtrace_continues = true;
+    }
+#elif CONFIG_IDF_TARGET_ARCH_RISCV
+    uint32_t sp = (uint32_t)((RvExcFrame *)info->frame)->sp;
+    p_info.backtrace[p_info.backtrace_len++] = sp;
+    uint32_t *spptr = (uint32_t *)(sp);
+    for (int i = 0; i < 256; i++){
+        if(esp_ptr_executable((void *)spptr[i])){
+            p_info.backtrace[p_info.backtrace_len++] = spptr[i];
+            if(p_info.backtrace_len == 60){
+                if(i < 255){
+                    p_info.backtrace_continues = true;
+                }
+                break;
+            }
+        }
+    }
+#endif
+    _panic_handler(&p_info, _panic_handler_arg);
+}
+
+void __real_esp_panic_handler(panic_info_t*);
+void __wrap_esp_panic_handler(panic_info_t* info) {
+    if(_panic_handler != NULL){
+        handle_custom_backtrace(info);
+    }
+    __real_esp_panic_handler(info);
+}
diff --git a/cores/esp32/esp32-hal.h b/cores/esp32/esp32-hal.h
index f71788e9399..3cc6444265b 100644
--- a/cores/esp32/esp32-hal.h
+++ b/cores/esp32/esp32-hal.h
@@ -137,6 +137,22 @@ void arduino_phy_init();
 void initArduino();
 #endif
 
+typedef struct {
+    int core;                   // core which triggered panic
+    const char* reason;         // exception string
+    const void* pc;             // instruction address that triggered the exception
+    bool backtrace_corrupt;     // if backtrace is corrupt
+    bool backtrace_continues;   // if backtrace continues, but did not fit
+    unsigned int backtrace_len; // number of backtrace addresses
+    unsigned int backtrace[60]; // backtrace addresses array
+} arduino_panic_info_t;
+
+typedef void (*arduino_panic_handler_t)(arduino_panic_info_t * info, void * arg);
+
+void set_arduino_panic_handler(arduino_panic_handler_t handler, void * arg);
+arduino_panic_handler_t * get_arduino_panic_handler(void);
+void * get_arduino_panic_handler_arg(void);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/platform.txt b/platform.txt
index c345b941017..cf87e2ea7b2 100644
--- a/platform.txt
+++ b/platform.txt
@@ -70,7 +70,7 @@ compiler.size.cmd={compiler.prefix}size
 compiler.c.extra_flags=-MMD -c
 compiler.cpp.extra_flags=-MMD -c
 compiler.S.extra_flags=-MMD -c -x assembler-with-cpp
-compiler.c.elf.extra_flags="-Wl,--Map={build.path}/{build.project_name}.map" "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" "-L{compiler.sdk.path}/{build.memory_type}"
+compiler.c.elf.extra_flags="-Wl,--Map={build.path}/{build.project_name}.map" "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" "-L{compiler.sdk.path}/{build.memory_type}" "-Wl,--wrap=esp_panic_handler"
 compiler.ar.extra_flags=
 compiler.objcopy.eep.extra_flags=
 compiler.elf2hex.extra_flags=

From f74b3122c069f3cf957a2b1d2332301d0a256e59 Mon Sep 17 00:00:00 2001
From: Me No Dev <me-no-dev@users.noreply.github.com>
Date: Thu, 5 Oct 2023 18:30:46 +0300
Subject: [PATCH 2/2] Resolve comments

---
 cores/esp32/esp32-hal-misc.c | 2 +-
 cores/esp32/esp32-hal.h      | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/cores/esp32/esp32-hal-misc.c b/cores/esp32/esp32-hal-misc.c
index 08c69e12416..ae1083c9a7a 100644
--- a/cores/esp32/esp32-hal-misc.c
+++ b/cores/esp32/esp32-hal-misc.c
@@ -340,7 +340,7 @@ void set_arduino_panic_handler(arduino_panic_handler_t handler, void * arg){
     _panic_handler_arg = arg;
 }
 
-arduino_panic_handler_t * get_arduino_panic_handler(void){
+arduino_panic_handler_t get_arduino_panic_handler(void){
     return _panic_handler;
 }
 
diff --git a/cores/esp32/esp32-hal.h b/cores/esp32/esp32-hal.h
index 3cc6444265b..2f53bb2ff66 100644
--- a/cores/esp32/esp32-hal.h
+++ b/cores/esp32/esp32-hal.h
@@ -150,7 +150,7 @@ typedef struct {
 typedef void (*arduino_panic_handler_t)(arduino_panic_info_t * info, void * arg);
 
 void set_arduino_panic_handler(arduino_panic_handler_t handler, void * arg);
-arduino_panic_handler_t * get_arduino_panic_handler(void);
+arduino_panic_handler_t get_arduino_panic_handler(void);
 void * get_arduino_panic_handler_arg(void);
 
 #ifdef __cplusplus