TeensyLC debug with GDB stub

Hi all

I am looking for a way to debug my TeensyLC board. Unfortunately printf debugging is no sufficient in my case. I need to step through the code (source level or assembly) and have some kind of callstack info. Inspection of variables is nice-to-have.

I got GitHub - ftrias/TeensyDebug: GDB proxy and debugging support to Teensy 3/4 to compile with PlatformIO for the Teensy4.0 and from this video Teensy 4.1 GDB Stub Debugging - YouTube I assume it does actually work. However, so far I didn’t manage to port it for the TeensyLC.

While this compile command works for Teensy4.0:

arm-none-eabi-g++ -o .pio/build/teensy40/src/TeensyDebug.cpp.o -c -fno-exceptions -felide-constructors -fno-rtti -std=gnu++14 -Wno-error=narrowing -fpermissive -fno-threadsafe-statics -Wall -ffunction-sections -fdata-sections -mthumb -mcpu=cortex-m7 -nostdlib -fsingle-precision-constant -mfloat-abi=hard -mfpu=fpv5-d16 -Og -g2 -ggdb2 -DPLATFORMIO=50205 -D__IMXRT1062__ -DARDUINO_TEENSY40 -DUSB_DUAL_SERIAL -DARDUINO=10805 -DTEENSYDUINO=156 -DCORE_TEENSY -DF_CPU=600000000 -DLAYOUT_US_ENGLISH -D__PLATFORMIO_BUILD_DEBUG__ -Isrc -I/home/ez/.platformio/packages/framework-arduinoteensy/cores/teensy4 src/TeensyDebug.cpp

This is what PlatformIO generates for TeensyLC and it fails:

arm-none-eabi-g++ -o .pio/build/teensylc/src/TeensyDebug.cpp.o -c -fno-exceptions -felide-constructors -fno-rtti -std=gnu++14 -Wno-error=narrowing -fpermissive -Wall -ffunction-sections -fdata-sections -mthumb -mcpu=cortex-m0plus -nostdlib --specs=nano.specs -mno-unaligned-access -fsingle-precision-constant -Og -g2 -ggdb2 -DPLATFORMIO=50205 -D__MKL26Z64__ -DARDUINO_TEENSYLC -DUSB_DUAL_SERIAL -DARDUINO=10805 -DTEENSYDUINO=156 -DCORE_TEENSY -DF_CPU=48000000L -DLAYOUT_US_ENGLISH -D__PLATFORMIO_BUILD_DEBUG__ -Isrc -I/home/ez/.platformio/packages/framework-arduinoteensy/cores/teensy3 src/TeensyDebug.cpp
/tmp/ccWtiFK5.s: Assembler messages:
/tmp/ccWtiFK5.s:2367: Error: lo register required -- `str sp,[r0]'
/tmp/ccWtiFK5.s:2395: Error: lo register required -- `str r8,[r0,#48]'
/tmp/ccWtiFK5.s:2396: Error: lo register required -- `str r9,[r0,#52]'
/tmp/ccWtiFK5.s:2397: Error: lo register required -- `str r10,[r0,#56]'
/tmp/ccWtiFK5.s:2398: Error: lo register required -- `str r11,[r0,#60]'
/tmp/ccWtiFK5.s:2430: Error: invalid register list to push/pop instruction -- `pop {lr}'
/tmp/ccWtiFK5.s:2467: Error: invalid register list to push/pop instruction -- `pop {r12}'
/tmp/ccWtiFK5.s:2498: Error: lo register required -- `ldr r8,[r0,#48]'
/tmp/ccWtiFK5.s:2499: Error: lo register required -- `ldr r9,[r0,#52]'
/tmp/ccWtiFK5.s:2500: Error: lo register required -- `ldr r10,[r0,#56]'
/tmp/ccWtiFK5.s:2501: Error: lo register required -- `ldr r11,[r0,#60]'
/tmp/ccWtiFK5.s:2692: Error: invalid register list to push/pop instruction -- `pop {lr}'
/tmp/ccWtiFK5.s:3643: Error: lo register required -- `str sp,[r0]'
/tmp/ccWtiFK5.s:3670: Error: lo register required -- `str r8,[r0,#48]'
/tmp/ccWtiFK5.s:3671: Error: lo register required -- `str r9,[r0,#52]'
/tmp/ccWtiFK5.s:3672: Error: lo register required -- `str r10,[r0,#56]'
/tmp/ccWtiFK5.s:3673: Error: lo register required -- `str r11,[r0,#60]'
/tmp/ccWtiFK5.s:3722: Error: lo register required -- `str sp,[r0]'
/tmp/ccWtiFK5.s:3749: Error: lo register required -- `str r8,[r0,#48]'
/tmp/ccWtiFK5.s:3750: Error: lo register required -- `str r9,[r0,#52]'
/tmp/ccWtiFK5.s:3751: Error: lo register required -- `str r10,[r0,#56]'
/tmp/ccWtiFK5.s:3752: Error: lo register required -- `str r11,[r0,#60]'
/tmp/ccWtiFK5.s:3801: Error: lo register required -- `str sp,[r0]'
/tmp/ccWtiFK5.s:3828: Error: lo register required -- `str r8,[r0,#48]'
/tmp/ccWtiFK5.s:3829: Error: lo register required -- `str r9,[r0,#52]'
/tmp/ccWtiFK5.s:3830: Error: lo register required -- `str r10,[r0,#56]'
/tmp/ccWtiFK5.s:3831: Error: lo register required -- `str r11,[r0,#60]'
/tmp/ccWtiFK5.s:3880: Error: lo register required -- `str sp,[r0]'
/tmp/ccWtiFK5.s:3907: Error: lo register required -- `str r8,[r0,#48]'
/tmp/ccWtiFK5.s:3908: Error: lo register required -- `str r9,[r0,#52]'
/tmp/ccWtiFK5.s:3909: Error: lo register required -- `str r10,[r0,#56]'
/tmp/ccWtiFK5.s:3910: Error: lo register required -- `str r11,[r0,#60]'
/tmp/ccWtiFK5.s:3959: Error: lo register required -- `str sp,[r0]'
/tmp/ccWtiFK5.s:3986: Error: lo register required -- `str r8,[r0,#48]'
/tmp/ccWtiFK5.s:3987: Error: lo register required -- `str r9,[r0,#52]'
/tmp/ccWtiFK5.s:3988: Error: lo register required -- `str r10,[r0,#56]'
/tmp/ccWtiFK5.s:3989: Error: lo register required -- `str r11,[r0,#60]'

I don’t think it’s the fault of PlatformIO. Rather the inline assembly is likely not suited for the TeensyLC hardware. I don’t know the hardware good enough to fix this right away. As I didn’t find this specific question raised anywhere, I though I’d write it down here and see if someone maybe ported this project or found a better way to debug the TeensyLC.

All feedback welcome! I will post updates here, when I make progress with my approach.
Cheers, Stefan

The code was written for Cortex-M4/M7 (Teensy 3.0 is a mk20dx128vlh5 Cortex-M4, Teensy 4.0 is a iMX.RT1062 Cortex-M7), but the Teensy LC is a Cortex-M0+.

There is a architectural problem here because the Cortex-M0+ does not allow the target or source (base address) register to be >R7, as Documentation – Arm Developer says.

Rt, Rn, and Rm must only specify R0-R7.

So all str rn, .. fail here if rn > R7. (SP is an alias for R13, LR is R14).

So while the Cortex-M0+ has these registers (Documentation – Arm Developer), somehow they can’t be used in a store word instruction, which seems weird to me. Maybe the code has to be modified to first load R0-R7 directly and save them on the stack, then move (mov) a higher register into a lower register, and save that again to the originally intended target address (r0 plus some offset). mov has no such register restrictions (Documentation – Arm Developer).

Possibly more adaptions are needed in the library for other things that don’t work on a Cortex-M0+.

1 Like

Maybe the code has to be modified to first load R0-R7 directly and save them on the stack, then move (mov) a higher register into a lower register

Yes, that sounds reasonable. Spill a low register to the stack and use it as a scratch register.

So while the Cortex-M0+ has these registers, somehow they can’t be used in a store word instruction, which seems weird to me.

Looks like it’s due to the dense encoding in the Thumb-2 Instruction Set! There is just no more free bits to encode more registers :slight_smile: Some more details here

I am deferring my work on the TeensyLC (there are a few more reasons) and hope to find the time to pick this issue up later this year. I think the information here is quite helpful already, but there is no real solution right now (assuming we ignore “It’s not possible” as a solution). Hope it’s fine to leave the ticket open for so long?