Esp8266 GDBSTUB for Sming
Background
This is a rewrite of gdbstub based on the esp8266 Arduino project.
To use the GNU Debugger (GDB) with Sming requires your application to
include some code (gdbstub
) which communicates via the serial port.
On the ESP8266 only UART0 may be used for this as UART1 is transmit-only.
The gdbstub code will only be built if you specify ENABLE_GDB=1
when compiling your application. At startup, before your init()
function is called, it will claim UART0 so your application will be
unable to use it directly. Therefore, the default port for Serial
is changed to UART2
.
UART2 is a ‘virtual’ serial port to enable serial communications to work correctly when GDB-enabled. Read/write calls and serial callbacks are handled via gdbstub. Baud rate changes affect UART0 directly.
Note that target
refers to the application being debugged, and
host
the development system running the GDB program.
Refer to the official GDB documentation for further details.
Usage
Configure gdbstub by editing
gdbstub-cfg.h
as required. You can also configure the options by setting :USER_CFLAGS
in your project’scomponent.mk
file. e.gUSER_CFLAGS=-DGDBSTUB_BREAK_ON_INIT=0
.Optional: Add
gdb_do_break()
statements to your application.Run
make clean
, thenmake ENABLE_GDB=1 flash
to build and flash the application with debugging enabledRun gdb, depending on your configuration immediately after resetting the board or after it has run into an exception. The easiest way to do it is to use the provided script:
make gdb
.
To run manually, see the following variables which you can inspect using make list-config
.
- GDB_CMDLINE
Command line used to run GDB.
- GDBSTUB_DIR
Location of the GDB stub component, and the
gdbcmds
file.
- COM_SPEED_GDB
Same as
COM_SPEED_SERIAL
, which is the value compiled into the gdbstub code.
- GDB_UART_SWAP
If you need to use alternate serial pins, enable this option
GDB_UART_SWAP=1
- GDB
Path to the GDB executable being used. This is the application which runs on your development system and talks to
gdbstub
. It is provided in the standard toolchain.
Useful GDB commands
c
Continue execution
q
Quit and detach
where
Display current stopped location
bt
Show stack backtrace
disass
Disassemble, disass/m
to mix with source code
print expr
Display a variable or other value
print func()
Call a function, display result, or call func()
to
discard result
tui enable
Provides a windowed interface within the console (only
seems to work in Linux)
x/32xw $sp
Display contents of stack
info reg
Display register values
info break
Display details of currently set breakpoints
delete
Delete all breakpoints
br
Set a breakpoint at the given address or function name
hbr
Set a hardware breakpoint
watch
Set a hardware watchpoint to detect when the value of a
variable changes
These commands require GDBSTUB_ENABLE_HOSTIO
to be enabled:
remote get targetfile hostfile
Read a file from SPIFFS (on the
target)
remote put hostfile targetfile
Write a file to SPIFFS
remote delete targetfile
Delete a file from SPIFFS
Eclipse
Windows:
Ensure
Use external console for inferior
is checked.In connection settings, specify COM port like with leading /, e.g.
/COM4
Problems connecting?
Switch to the debug perspective before connecting
Ensure serial baud rate matches your application
Remove or disable all breakpoints before attaching. Eclipse will attempt to set these on connection, and if any are invalid it will hang and timeout.
Check connectivity using command-line GDB
GDB System Calls
Applications may interact with GDB directly using system calls, for example reading input from the GDB command prompt. See the Live Debug sample for a demonstration.
Note that system calls are disabled in the default configuration, so set
GDBSTUB_ENABLE_SYSCALL=1
to use this feature with your
application.
Known Issues and Limitations
- Unable to set requested break/watch points
Cause: Due to hardware limitations, only one hardware breakpount and one hardware watchpoint are available
Solution: None (hardware limitation)
- System crashes if debugger is paused for too long
Cause: The WiFi hardware is designed to be serviced by software periodically. It has some buffers so it will behave OK when some data comes in while the processor is busy, but these buffers are not infinite. If the WiFi hardware receives lots of data while the debugger has stopped the CPU, it is bound to crash. This will happen mostly when working with UDP and/or ICMP; TCP-connections in general will not send much more data when the other side doesn’t send any ACKs.
Solution: In such situations avoid pausing the debugger for extended periods
- Software breakpoints/watchpoints (‘break’ and ‘watch’) don’t work on flash code
Cause: GDB handles these by replacing code with a debugging instruction, therefore the code must be in RAM.
Solution: Use hardware breakpoint (‘hbreak’) or use
GDB_IRAM_ATTR
for code which requires testing
- If hardware breakpoint is set, single-stepping won’t work unless code is in RAM.
Cause: GDB reverts to software breakpoints if no hardware breakpoints are available
Solution: Delete hardware breakpoint before single-stepping
- Crash occurs when setting breakpoint in HardwareTimer callback routine
Cause: By default, HardwareTimer uses Non-maskable Interrupts (NMI) which keep running when the debugger is paused
Solution: Use the timer in non-maskable mode, or enable
GDBSTUB_PAUSE_HARDWARE_TIMER
option
- If gdbstub isn’t initialised then UART2 won’t work, though initialisation will succeed
Cause: By design, uart callbacks can be registered for UART2 at any time, before or after initialisation
Solution: Not really an issue, just something to be aware of
- Error reported, “packet reply is too long”
Cause: Mismatch between GDB version and stub code
Solution: Set
GDBSTUB_GDB_PATCHED=1
or use an unpatched version of GDB
- Whilst GDB is attached, input cannot be passed to application
Cause: GDB buffers keystrokes and replays them only when the target is interrupted (e.g. via ctrl+C), rather than passing them via serial connection.
Solution: Application may use gdb_syscall interface to communicate with debugger. See
$(SMING_HOME)/system/gdb_syscall.h
, and Live Debug sample.
- No apparent way to have second ‘console’ (windows terminology) separate from GDB interface
Cause: Unknown
Solution: Is this possible with remote targets?
- GDB (in Windows) doesn’t respond at all to Ctrl+C
Cause: Unknown
Solution: Press Ctrl+Break to ‘hard kill’ GDB. You’ll probably need to do the next step as well to get it back
- When GDB is running under windows, appears to hang when target reset or restarted
Cause: Unknown, may not happen on all devboards but presents with NodeMCU
- Solution
quit GDB
quit
Start terminal
make terminal
reset board
quit terminal
run GDB again
make gdb
- Debug messages don’t appear in Eclipse
Cause: Unknown
Solution: Use command-line GDB, or a better visual debugger
Configuration
Defines
-
ENABLE_EXCEPTION_DUMP
When enabled, an exception or crash dumps a stack trace to debug output Default is ON for debug builds, OFF for release builds
Note: Not dependent upon ENABLE_GDB
-
ENABLE_CRASH_DUMP
When enabled, an unexpected reset (i.e. system crash) dumps a stack trace to debug output Default is ON for debug builds, OFF for release builds
Note: Not dependent upon ENABLE_GDB
-
GDBSTUB_ENABLE_DEBUG
When defined, GDB communications are echoed to UART1 for testing GDB stub operation.
0: No debug output 1: Show decoded commands and responses 2: Show packet content 3: Show debug output for internal routines
-
GDBSTUB_GDB_PATCHED
Espressif provide a patched version of GDB which emits only those registered present in the lx106. Set to 0 if an unpatched version of GDB is used.
-
GDBSTUB_USE_OWN_STACK
Enable this to make the exception and debugging handlers switch to a private stack. This will use up 1K of RAM, but may be useful if you’re debugging stack or stack pointer corruption problems. It’s normally disabled because not many situations need it. If for some reason the GDB communication stops when you run into an error in your code, try enabling this.
-
GDBSTUB_STACK_SIZE
-
GDBSTUB_BREAK_ON_EXCEPTION
Enable this to cause the program to pause and wait for gdb to be connected when an exception is encountered.
-
GDBSTUB_BREAK_ON_RESTART
Enable this to cause the program to pause and wait for gdb to be connected when an unexpected system restart occurs.
-
GDBSTUB_CTRLC_BREAK
If this is defined, gdbstub will break the program when you press Ctrl-C in gdb. It does this by monitoring for the ‘x03’ character in the serial receive routine. Any preceding characters are passed through to the application via UART2. If your application uses the serial port for terminal (text) communications you should be OK, but binary transfers are likely to cause problems and this option should probably be disabled. Instead, use GDBSTUB_BREAK_ON_INIT, or call gdb_do_break() in your application.
Specify: 0 to disable Ctrl+C break checking completely 1 to allow Ctrl+C break only when debugger is attached 2 to allow Ctrl+C break at any time. Ensure you have set remote interrupt-on-connect on in GDB command file, so it will send a Ctrl+C sequence when attempting to connect
-
GDBSTUB_ENABLE_UART2
The GDB stub has exclusive access to UART0, so applications cannot use it directly and attempts to open it will fail.
If this option is enabled, the default serial port will be changed to UART2 to allow debug output (from m_printf, debug_*, os_printf, etc.) to show up in your GDB session.
Outside of GDB terminal applications should work as normal, with the following caveats:
See GDB remote serial protocol for further details.If GDBSTUB_BREAK_ON_INIT is defined, then at startup your application will display `$T05#b9` and stop. A similar thing will happen if GDBSTUB_CTRLC_BREAK=2 and you type Ctrl+C. Continue by typing `$D#44` (without the quotes), or exit the terminal and start GDB.
Disabling this option releases some IRAM. You may be instead able to use UART1 for debug output, adding
Serial.setPort(UART_ID_1);
in your application’sinit()
function.
-
GDBSTUB_ENABLE_SYSCALL
Enable gdb_syscall_* functions for use by application. If undefined, calls will do nothing and return -1.
-
GDBSTUB_ENABLE_HOSTIO
Enable Host I/O capability, where files may be accessed via GDB command prompt using
remote get
,remote put
andremote delete
commands.
-
GDBSTUB_BREAK_ON_INIT
Enable this if you want the GDB stub to wait for you to attach GDB before running. It does this by breaking in the init routine; use the gdb ‘c’ command (continue) to start the program.
-
GDBSTUB_CMDENABLE_P
Some commands are not required by GDB, so if necessary can be disabled to save memory.
-
GDBSTUB_CMDENABLE_X
-
GDBSTUB_UART_READ_TIMEOUT
Specify a timeout (in milliseconds) when stub is reading from serial port. Set to 0 to wait indefinitely.
-
GDBSTUB_FORCE_IRAM
Wherever possible gdbstub code is placed in flash memory. This is fine for most cases, but if debugging whilst flash is disabled or busy (eg during SPI operations or flash write/erase) then you will need to enable this option to move stub code into IRAM.
References
Used by
Sming (Esp32) Component
Sming (Esp8266) Component
Sming (Host) Component
Sming (Rp2040) Component
Environment Variables
SoC support
esp8266