Spill registers before scanning the stack.

From the change:

    // xtensa has more registers than an instruction can address. The 16 that
    // can be addressed are called the "window". When a function is called or
    // returns the window rotates. This allows for more efficient function calls
    // because ram doesn't need to be used. It's only used if the window wraps
    // around onto itself. At that point values are "spilled" to empty spots in
    // the stack that were set aside. When the window rotates back around (on
    // function return), the values are restored into the register from ram.

    // So, in order to read the values in the stack scan we must make sure all
    // of the register values we care about have been spilled to RAM. Luckily,
    // there is a HAL call to do it. There is a bit of a race condition here
    // because the register value could change after it's been restored but that
    // is unlikely to happen with a heap pointer while we do a GC.

Fixes #2907
This commit is contained in:
Scott Shawcroft 2020-05-28 18:29:11 -07:00
parent d98151a434
commit 2fb4fa3289
No known key found for this signature in database
GPG Key ID: 9349BC7E64B1921E
2 changed files with 42 additions and 1 deletions

View File

@ -37,6 +37,24 @@ void mp_hal_delay_us(mp_uint_t delay) {
mp_hal_delay_ms(delay / 1000); mp_hal_delay_ms(delay / 1000);
} }
mp_uint_t cpu_get_regs_and_sp(mp_uint_t *regs) { // This is provided by the esp-idf/components/xtensa/esp32s2/libhal.a binary
// blob.
extern void xthal_window_spill(void);
mp_uint_t cpu_get_regs_and_sp(mp_uint_t *regs, uint8_t reg_count) {
// xtensa has more registers than an instruction can address. The 16 that
// can be addressed are called the "window". When a function is called or
// returns the window rotates. This allows for more efficient function calls
// because ram doesn't need to be used. It's only used if the window wraps
// around onto itself. At that point values are "spilled" to empty spots in
// the stack that were set aside. When the window rotates back around (on
// function return), the values are restored into the register from ram.
// So, in order to read the values in the stack scan we must make sure all
// of the register values we care about have been spilled to RAM. Luckily,
// there is a HAL call to do it. There is a bit of a race condition here
// because the register value could change after it's been restored but that
// is unlikely to happen with a heap pointer while we do a GC.
xthal_window_spill();
return (mp_uint_t) __builtin_frame_address(0); return (mp_uint_t) __builtin_frame_address(0);
} }

View File

@ -0,0 +1,23 @@
"""Simple script that translates "Backtrace:" lines from the ESP output to files
and line numbers.
Run with: python3 tools/decode_backtrace.py <board>
Enter the backtrace line at the "? " prompt. CTRL-C to exit the script.
"""
import subprocess
import sys
board = sys.argv[1]
print(board)
while True:
addresses = input("? ")
if addresses.startswith("Backtrace:"):
addresses = addresses[len("Backtrace:"):]
addresses = addresses.strip().split()
addresses = [address.split(":")[0] for address in addresses]
print('got', addresses)
subprocess.run(["xtensa-esp32s2-elf-addr2line",
"-e", "build-{}/firmware.elf".format(board)] + addresses)