138 lines
3.6 KiB
C++
138 lines
3.6 KiB
C++
|
|
#include "HalSystem.h"
|
||
|
|
|
||
|
|
#include <string>
|
||
|
|
|
||
|
|
#include "Arduino.h"
|
||
|
|
#include "HalStorage.h"
|
||
|
|
#include "Logging.h"
|
||
|
|
#include "esp_debug_helpers.h"
|
||
|
|
#include "esp_private/esp_cpu_internal.h"
|
||
|
|
#include "esp_private/esp_system_attr.h"
|
||
|
|
#include "esp_private/panic_internal.h"
|
||
|
|
|
||
|
|
#define MAX_PANIC_STACK_DEPTH 32
|
||
|
|
|
||
|
|
RTC_NOINIT_ATTR char panicMessage[256];
|
||
|
|
RTC_NOINIT_ATTR HalSystem::StackFrame panicStack[MAX_PANIC_STACK_DEPTH];
|
||
|
|
|
||
|
|
extern "C" {
|
||
|
|
|
||
|
|
static DRAM_ATTR const char PANIC_REASON_UNKNOWN[] = "(unknown panic reason)";
|
||
|
|
void IRAM_ATTR __wrap_panic_abort(const char* message) {
|
||
|
|
if (!message) message = PANIC_REASON_UNKNOWN;
|
||
|
|
// IRAM-safe bounded copy (strncpy is not IRAM-safe in panic context)
|
||
|
|
int i = 0;
|
||
|
|
for (; i < (int)sizeof(panicMessage) - 1 && message[i]; i++) {
|
||
|
|
panicMessage[i] = message[i];
|
||
|
|
}
|
||
|
|
panicMessage[i] = '\0';
|
||
|
|
|
||
|
|
__real_panic_abort(message);
|
||
|
|
}
|
||
|
|
|
||
|
|
void IRAM_ATTR __wrap_panic_print_backtrace(const void* frame, int core) {
|
||
|
|
if (!frame) {
|
||
|
|
__real_panic_print_backtrace(frame, core);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
for (size_t i = 0; i < MAX_PANIC_STACK_DEPTH; i++) {
|
||
|
|
panicStack[i].sp = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Copied from components/esp_system/port/arch/riscv/panic_arch.c
|
||
|
|
uint32_t sp = (uint32_t)((RvExcFrame*)frame)->sp;
|
||
|
|
const int per_line = 8;
|
||
|
|
int depth = 0;
|
||
|
|
for (int x = 0; x < 1024; x += per_line * sizeof(uint32_t)) {
|
||
|
|
uint32_t* spp = (uint32_t*)(sp + x);
|
||
|
|
// panic_print_hex(sp + x);
|
||
|
|
// panic_print_str(": ");
|
||
|
|
panicStack[depth].sp = sp + x;
|
||
|
|
for (int y = 0; y < per_line; y++) {
|
||
|
|
// panic_print_str("0x");
|
||
|
|
// panic_print_hex(spp[y]);
|
||
|
|
// panic_print_str(y == per_line - 1 ? "\r\n" : " ");
|
||
|
|
panicStack[depth].spp[y] = spp[y];
|
||
|
|
}
|
||
|
|
|
||
|
|
depth++;
|
||
|
|
if (depth >= MAX_PANIC_STACK_DEPTH) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
__real_panic_print_backtrace(frame, core);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
namespace HalSystem {
|
||
|
|
|
||
|
|
void begin() {
|
||
|
|
// This is mostly for the first boot, we need to initialize the panic info and logs to empty state
|
||
|
|
// If we reboot from a panic state, we want to keep the panic info until we successfully dump it to the SD card, use
|
||
|
|
// `clearPanic()` to clear it after dumping
|
||
|
|
if (!isRebootFromPanic()) {
|
||
|
|
clearPanic();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void checkPanic() {
|
||
|
|
if (isRebootFromPanic()) {
|
||
|
|
auto panicInfo = getPanicInfo(true);
|
||
|
|
auto file = Storage.open("/crash_report.txt", O_WRITE | O_CREAT | O_TRUNC);
|
||
|
|
if (file) {
|
||
|
|
file.write(panicInfo.c_str(), panicInfo.size());
|
||
|
|
file.close();
|
||
|
|
LOG_INF("SYS", "Dumped panic info to SD card");
|
||
|
|
} else {
|
||
|
|
LOG_ERR("SYS", "Failed to open crash_report.txt for writing");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void clearPanic() {
|
||
|
|
panicMessage[0] = '\0';
|
||
|
|
for (size_t i = 0; i < MAX_PANIC_STACK_DEPTH; i++) {
|
||
|
|
panicStack[i].sp = 0;
|
||
|
|
}
|
||
|
|
clearLastLogs();
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string getPanicInfo(bool full) {
|
||
|
|
if (!full) {
|
||
|
|
return panicMessage;
|
||
|
|
} else {
|
||
|
|
std::string info;
|
||
|
|
|
||
|
|
info += "CrossPoint version: " CROSSPOINT_VERSION;
|
||
|
|
info += "\n\nPanic reason: " + std::string(panicMessage);
|
||
|
|
info += "\n\nLast logs:\n" + getLastLogs();
|
||
|
|
info += "\n\nStack memory:\n";
|
||
|
|
|
||
|
|
auto toHex = [](uint32_t value) {
|
||
|
|
char buffer[9];
|
||
|
|
snprintf(buffer, sizeof(buffer), "%08X", value);
|
||
|
|
return std::string(buffer);
|
||
|
|
};
|
||
|
|
for (size_t i = 0; i < MAX_PANIC_STACK_DEPTH; i++) {
|
||
|
|
if (panicStack[i].sp == 0) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
info += "0x" + toHex(panicStack[i].sp) + ": ";
|
||
|
|
for (size_t j = 0; j < 8; j++) {
|
||
|
|
info += "0x" + toHex(panicStack[i].spp[j]) + " ";
|
||
|
|
}
|
||
|
|
info += "\n";
|
||
|
|
}
|
||
|
|
|
||
|
|
return info;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool isRebootFromPanic() {
|
||
|
|
const auto resetReason = esp_reset_reason();
|
||
|
|
return resetReason == ESP_RST_PANIC || resetReason == ESP_RST_CPU_LOCKUP;
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace HalSystem
|