forked from espressif/esp-idf
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'feature/enable_fp_backtracing' into 'master'
feat(riscv): implement frame pointer option for backtracing See merge request espressif/esp-idf!32342
- Loading branch information
Showing
32 changed files
with
497 additions
and
167 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include "sdkconfig.h" | ||
#include <string.h> | ||
#include "esp_private/panic_internal.h" | ||
#include "esp_memory_utils.h" | ||
#include "riscv/libunwind-riscv.h" | ||
#include "esp_private/fp_unwind.h" | ||
|
||
#define FP_MAX_CALLERS 64 | ||
#define RA_INDEX_IN_FP -1 | ||
#define SP_INDEX_IN_FP -2 | ||
|
||
/** | ||
* @brief When one step of the backtrace is generated, output it to the serial. | ||
* This function can be overridden as it is defined as weak. | ||
* | ||
* @param pc Program counter of the backtrace step. | ||
* @param sp Stack pointer of the backtrace step. | ||
*/ | ||
void __attribute__((weak)) esp_fp_generated_step(uint32_t pc, uint32_t sp) | ||
{ | ||
panic_print_str(" 0x"); | ||
panic_print_hex(pc); | ||
panic_print_str(":0x"); | ||
panic_print_hex(sp); | ||
} | ||
|
||
/** | ||
* @brief Check if the given pointer is a data pointer that can be dereferenced | ||
* | ||
* @param ptr Data pointer to check | ||
*/ | ||
static inline bool esp_fp_ptr_is_data(void* ptr) | ||
{ | ||
return esp_ptr_in_dram(ptr) || esp_ptr_external_ram(ptr); | ||
} | ||
|
||
/** | ||
* @brief Generate a call stack starting at the given frame pointer. | ||
* | ||
* @note Since this function can be called from RAM (from heap trace), it shall also be put in RAM. | ||
* | ||
* @param frame[in] Frame pointer to start unrolling from. | ||
* @param callers[out] Array of callers where 0 will store the most recent caller. Can be NULL. | ||
* @param stacks[out] Array of callers' stacks where 0 will store the most recent caller's stack. Can be NULL. | ||
* @param depth[in] Number of maximum entries to fill in the callers array. | ||
* | ||
* @returns Number of entries filled in the array. | ||
*/ | ||
uint32_t IRAM_ATTR esp_fp_get_callers(uint32_t frame, void** callers, void** stacks, uint32_t depth) | ||
{ | ||
uint32_t written = 0; | ||
uint32_t pc = 0; | ||
uint32_t sp = 0; | ||
uint32_t* fp = (uint32_t*) frame; | ||
|
||
if (depth == 0 || (callers == NULL && stacks == NULL)) { | ||
return 0; | ||
} | ||
|
||
/** | ||
* We continue filling the callers array until we meet a function in ROM (not compiled | ||
* with frame pointer) or the pointer we retrieved is not in RAM (binary libraries | ||
* not compiled with frame pointer configuration, which means what is stored in the register is not a valid pointer) | ||
*/ | ||
while (depth > 0 && esp_fp_ptr_is_data(fp) && !esp_ptr_in_rom((void *) pc)) { | ||
/* Dereference the RA register from the frame pointer and store it in PC */ | ||
pc = fp[RA_INDEX_IN_FP]; | ||
sp = fp[SP_INDEX_IN_FP]; | ||
fp = (uint32_t*) sp; | ||
|
||
if (callers) { | ||
callers[written] = (void*) pc; | ||
} | ||
if (stacks) { | ||
stacks[written] = (void*) sp; | ||
} | ||
|
||
depth--; | ||
written++; | ||
} | ||
|
||
return written; | ||
} | ||
|
||
/** | ||
* @brief Print backtrace for the given execution frame. | ||
* | ||
* @param frame_or Snapshot of the CPU registers when the CPU stopped its normal execution. | ||
*/ | ||
void esp_fp_print_backtrace(const void *frame_or) | ||
{ | ||
assert(frame_or != NULL); | ||
ExecutionFrame frame = *((ExecutionFrame*) frame_or); | ||
|
||
const uint32_t sp = EXECUTION_FRAME_SP(frame); | ||
const uint32_t pc = EXECUTION_FRAME_PC(frame); | ||
const uint32_t fp = frame.s0; | ||
void* callers[FP_MAX_CALLERS]; | ||
void* stacks[FP_MAX_CALLERS]; | ||
|
||
panic_print_str("Backtrace:"); | ||
esp_fp_generated_step(pc, sp); | ||
|
||
uint32_t len = esp_fp_get_callers(fp, callers, stacks, FP_MAX_CALLERS); | ||
|
||
for (int i = 0; i < len; i++) { | ||
esp_fp_generated_step((uint32_t) callers[i], (uint32_t) stacks[i]); | ||
} | ||
|
||
panic_print_str("\r\n"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#ifndef FP_UNWIND_H | ||
#define FP_UNWIND_H | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
/** | ||
* @brief Print backtrace for the given execution frame thanks to the frame pointers. | ||
* | ||
* @param frame_or Snapshot of the CPU registers when the program stopped its | ||
* normal execution. This frame is usually generated on the | ||
* stack when an exception or an interrupt occurs. | ||
*/ | ||
void esp_fp_print_backtrace(const void *frame_or); | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif // FP_UNWIND_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.