summaryrefslogtreecommitdiff
path: root/ports
diff options
context:
space:
mode:
authorScott Shawcroft <scott@tannewt.org>2020-05-28 18:29:11 -0700
committerScott Shawcroft <scott@tannewt.org>2020-05-28 18:34:14 -0700
commit2fb4fa328946b07d90bd951d4a134ea8d31be7e8 (patch)
tree46ffafe7fdae0aebfef8d2f956219d18208a1cd0 /ports
parentd98151a434106f54dc267b387e19f7ee6c512332 (diff)
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
Diffstat (limited to 'ports')
-rw-r--r--ports/esp32s2/mphalport.c20
-rw-r--r--ports/esp32s2/tools/decode_backtrace.py23
2 files changed, 42 insertions, 1 deletions
diff --git a/ports/esp32s2/mphalport.c b/ports/esp32s2/mphalport.c
index 772b61c9e..da5258b0e 100644
--- a/ports/esp32s2/mphalport.c
+++ b/ports/esp32s2/mphalport.c
@@ -37,6 +37,24 @@ void mp_hal_delay_us(mp_uint_t delay) {
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);
}
diff --git a/ports/esp32s2/tools/decode_backtrace.py b/ports/esp32s2/tools/decode_backtrace.py
new file mode 100644
index 000000000..3f078895a
--- /dev/null
+++ b/ports/esp32s2/tools/decode_backtrace.py
@@ -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)