* Add full gdb support with uart/Serial integration * Fix GDB merge errors * Update to unpatched GDB protocol specification It appears that Espressif patched the open source xtensa GDB port in order to build their old GDB executable and their old gdbstub (basically removing any register in a generic xtensa and only leaving those present in the chip they synthesized). Their GDBStub also assumed this behavior. Unpatched upstream GNU GDB now expects all the registers in xtensa-config.c to be sent/read on a 'g' command. Change the GDB stub to send "xxxxxxxx"s (legal per the spec) for unimplemented registers. This makes the 'g' response much longer, but it's results are cached and in an interactive debugger it isn't noticeable. * Fix .iram.literal to come before .iram.text for GDB * Move functions to flash, call using wrappers All functions which are not interrupt or exception called are now in flash. A small IRAM wrapper enables flash when processing main GDB ops by calling Cache_Read_Enable_New() and then jumping to the main flash code. This seems to work for catching exceptions, data and code breaks, and Ctrl-C. The UART ISR handler and exception handler register-saving bits of code in ASM are still in IRAM. GDB IRAM usage is now about 670 bytes. * Remove LWIP2 builder commit * Add documentation and gdbstub_init header Add some simple GDB documentation to the main tree showing a worked example. Adds the definition of `void gdbstub_init()` to <GDBStub.h> * Clean up GDB include and library dir Replace GDBstub.h with the version in the internal/ directory, and adjust stub code accordingly. This way, only one copy of a file called "GDBstub.h" will exist. Update the gdbcommands and replace the obsolete ESPRESSIF readme with @kylefleming's version since we're mainly doing serial, not TCP, connected debugging. Bump the library rev. number since this is a pretty big functionality change. Minor documentation tweak. * Undo much of UART refactoring, set fifo IRQ to 16 Remove the refactoring of pin control and other little things not directly related to GDB processing. Should greatly reduce the diff size in uart.c. Should also remove any register value changes (intended or otherwise) introduced in the original PR from @kylefleming. Set the FIFO interrupt to 16 chars when in GDB mode, matching the latest UART configuration for highest speed. * Add architecture comments, cleanup uart.c code Comments added to UART.c trying to explain (as best as I understand it) the changes done to support GDB and how they interact with standard operation. Fix the uart_uninit to stop the ISR and then free appropriately. Fix uart_isr_handle_data (GDB's shim for sending chars to the 8266 app) to do the exact same thing as the standard UART handler including set the overflow properly and either discard or overwrite in that case. Fix serial reception when GDB enabled by enabling the user recv ISR. Remove commented attributes from gdbstub, leftover from the move to flash. General logic cleanup per comments in the PR. * Also set the UART flags for HW error in GDB Ensure we also check the UART flags and set the uart status appropriately when in GDB mode.
GDBSTUB
Intro
While the ESP8266 supports the standard Gnu set of C programming utilities, for now the choice of debuggers has been limited: there is an attempt at OpenOCD support, but at the time of writing, it doesn't support hardware watchpoints and breakpoints yet, and it needs a separate JTAG adapter connecting to the ESP8266s JTAG pins. As an alternative, Cesanta has implemented a barebonesGDB stub in their Smart.js solution - unfortunately, this only supports exception catching and needs some work before you can use it outside of the Smart.js platform. Moreover, it also does not work with FreeRTOS.
For internal use, we at Espressif desired a GDB stub that works with FreeRTOS and is a bit more capable, so we designed our own implementation of it. This stub works both under FreeRTOS as well as the OS-less SDK and is able to catch exceptions and do backtraces on them, read and write memory, forward [os_]printf statements to gdb, single-step instructions and set hardware break- and watchpoints. It connects to the host machine (which runs gdb) using the standard serial connection that's also used for programming.
In order to be useful the gdbstub has to be used in conjunction with an xtensa-lx106-elf-gdb, for example as generated by the esp-open-sdk project.
Usage
- Grab the gdbstub project and put the files in a directory called 'gdbstub' in your project. You can do this either by checking out the Git repo, or adding the Git repo as a submodule to your project if it's already in Git.
- Modify your Makefile. You'll need to include the gdbstub sources: if your Makefile is structured like the
ones in the Espressif examples, you can add
gdbstub
to theSUBDIRS
define andgdbstub/libgdbstub.a
to theCOMPONENTS_eagle.app.v6
define. Also, you probably want to add-ggdb
to your compiler flags (TARGET_LDFLAGS
) and, if you are debugging, change any optimation flags (-Os, -O2 etc) into-Og
. Finally, make sure your Makefile also compiles .S files. - Configure gdbstub by editting
gdbstub-cfg.h
. There are a bunch of options you can tweak: FreeRTOS or bare SDK, private exception/breakpoint stack, console redirection to GDB, wait till debugger attachment etc. You can also configure the options by including the proper -Dwhatever gcc flags in your Makefiles. - In your user_main.c, add an
#include <../gdbstub/gdbstub.h>
and callgdbstub_init();
somewhere in user_main. - Compile and flash your board.
- Run 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: xtensa-lx106-elf-gdb -x gdbcmds -b 38400 Change the '38400' into the baud rate your code uses. You may need to change the gdbcmds script to fit the configuration of your hardware and build environment.
Notes
- Using software breakpoints ('br') only works on code that's in RAM. Code in flash can only have a hardware breakpoint ('hbr').
- Due to hardware limitations, only one hardware breakpount and one hardware watchpoint are available.
- Pressing control-C to interrupt the running program depends on gdbstub hooking the UART interrupt. If some code re-hooks this afterwards, gdbstub won't be able to receive characters. If gdbstub handles the interrupt, the user code will not receive any characters.
- Continuing from an exception is not (yet) supported in FreeRTOS mode.
- 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.
License
This gdbstub is licensed under the Espressif MIT license, as described in the License file.
Thanks
- Cesanta, for their initial ESP8266 exception handling only gdbstub,
- jcmvbkbc, for providing an incompatible but interesting gdbstub for other Xtensa CPUs,
- Sysprogs (makers of VisualGDB), for their suggestions and bugreports.