* Fix missed backquote to make monospaced text in gdb.rst * Fix line spacing on example walkthrough
10 KiB
Using GDB to Debug Applications
ESP applications can be debugged using GDB, the GNU debugger, which is included with the standard IDE installation. This note will only discuss the ESP specific steps, so please refer to the main GNU GDB documentation.
Note that as of 2.5.0, the toolchain moved from the ESPRESSIF patched, closed-source version of GDB to the main GNU version. The debugging formats are different, so please be sure to use only the latest Arduino toolchain GDB executable.
CLI and IDE Note
Because the Arduino IDE doesn't support interactive debugging, the following sections describe debugging using the command line. Other IDEs which use GDB in their debug backends should work identically, but you may need to edit their configuration files or options to enable the remote serial debugging required and to set the standard options. PRs are happily accepted for updates to this document with additional IDEs!
Preparing your application for GDB
Applications need to be changed to enable GDB debugging support. This change will add 2-3KB of flash and around 700 bytes of IRAM usage, but should not affect operation of the application.
In your main sketch.ino
file, add the following line to
the top of the application:
#include <GDBStub.h>
And in the void setup()
function ensure the serial port
is initialized and call gdbstub_init()
:
.begin(115200);
Serial(); gdbstub_init
Rebuild and reupload your application and it should run exactly as before.
Starting a Debug Session
Once your application is running, the process to attach a debugger is quite simple: . Close the Arduino Serial Monitor . Locate Application.ino.elf File . Open a Command Prompt and Start GDB . Apply the GDB configurations . Attach the Debugger . Debug Away!
Close the Arduino Serial Monitor
Because GDB needs full control of the serial port, you will need to close any Arduino Serial Monitor windows you may have open. Otherwise GDB will report an error while attempting to debug.
Locate Application.ino.elf File
In order for GDB to debug your application, you need to locate the compiled ELF format version of it (which includes needed debug symbols).
Under Linux these files are stored in
/tmp/arduino_build_*
and the following command will help
locate the right file for your app:
/tmp -name "*.elf" -print find
Under Windows these files are stored in
%userprofile%\AppData\Local\Temp\arduino_build_*
and the
following command will help locate the right file for your app:
%userprofile%\appdata\*.elf /s/b dir
Note the full path of ELF file that corresponds to your sketch name, it will be needed later once GDB is started.
Open a Command Prompt and Start GDB
Open a terminal or CMD
prompt and navigate to the proper
ESP8266 toolchain directory.
Linux
~/.arduino15/packages/esp8266/hardware/xtensa-lx106-elf/bin/xtensa-lx106-elf-gdb
Windows (Using Board Manager version)
%userprofile%\AppData\Local\Arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc\2.5.0-3-20ed2b9\bin\xtensa-lx106-elf-gdb.exe
Windows (Using Git version)
%userprofile%\Documents\Arduino\hardware\esp8266com\esp8266\tools\xtensa-lx106-elf\bin\xtensa-lx106-elf-gdb.exe
Please note the proper GDB name is "xtensa-lx106-elf-gdb". If you accidentally run "gdb" you may start your own operating system's GDB, which will not know how to talk to the ESP8266.
Apply the GDB Configurations
At the (gdb)
prompt, enter the following options to
configure GDB for the ESP8266 memory map and configuration:
-breakpoint-limit 1
set remote hardware-watchpoint-limit 1
set remote hardware-on-connect on
set remote interrupt-packet off
set remote kill-lookup-packet off
set remote symbol-resume-packet off
set remote verbose0x20000000 0x3fefffff ro cache
mem 0x3ff00000 0x3fffffff rw
mem 0x40000000 0x400fffff ro cache
mem 0x40100000 0x4013ffff rw cache
mem 0x40140000 0x5fffffff ro cache
mem 0x60000000 0x60001fff rw
mem 115200 set serial baud
Now tell GDB where your compiled ELF file is located:
/tmp/arduino_build_257110/sketch_dec26a.ino.elf file
Attach the Debugger
Once GDB has been configured properly and loaded your debugging symbols, connect it to the ESP with the command (replace the ttyUSB0 or COM9 with your ESP's serial port):
/dev/ttyUSB0 target remote
or
.\COM9 target remote \\
At this point GDB will send a stop the application on the ESP8266 and
you can begin setting a breakpoint (break loop
) or any
other debugging operation.
Example Debugging Session
Create a new sketch and paste the following code into it:
#include <GDBStub.h>
void setup() {
.begin(115200);
Serial();
gdbstub_init.printf("Starting...\n");
Serial}
void loop() {
static uint32_t cnt = 0;
.printf("%d\n", cnt++);
Serial(100);
delay}
Save it and then build and upload to your ESP8266. On the Serial monitor you should see something like
1
2
3
....
Now close the Serial Monitor.
Open a command prompt and find the ELF file:
@server:~$ find /tmp -name "*.elf" -print
earle/tmp/arduino_build_257110/testgdb.ino.elf
/tmp/arduino_build_531411/listfiles.ino.elf
/tmp/arduino_build_156712/SDWebServer.ino.elf
In this example there are multiple elf
files found, but
we only care about the one we just built,
testgdb.ino.elf
.
Open up the proper ESP8266-specific GDB
@server:~$ ~/.arduino15/packages/esp8266/hardware/xtensa-lx106-elf/bin/xtensa-lx106-elf-gdb
earle(GDB) 8.2.50.20180723-git
GNU gdb (C) 2018 Free Software Foundation, Inc.
Copyright +: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
License GPLv3: you are free to change and redistribute it.
This is free software, to the extent permitted by law.
There is NO WARRANTY"show copying" and "show warranty" for details.
Type "--host=x86_64-linux-gnu --target=xtensa-lx106-elf".
This GDB was configured as "show configuration" for configuration details.
Type , please see:
For bug reporting instructions<http://www.gnu.org/software/gdb/bugs/>.
and other documentation resources online at:
Find the GDB manual <http://www.gnu.org/software/gdb/documentation/>.
, type "help".
For help"apropos word" to search for commands related to "word".
Type (gdb)
We're now at the GDB prompt, but nothing has been set up for the ESP8266 and no debug information has been loaded. Cut-and-paste the setup options:
(gdb) set remote hardware-breakpoint-limit 1
(gdb) set remote hardware-watchpoint-limit 1
(gdb) set remote interrupt-on-connect on
(gdb) set remote kill-packet off
(gdb) set remote symbol-lookup-packet off
(gdb) set remote verbose-resume-packet off
(gdb) mem 0x20000000 0x3fefffff ro cache
(gdb) mem 0x3ff00000 0x3fffffff rw
(gdb) mem 0x40000000 0x400fffff ro cache
(gdb) mem 0x40100000 0x4013ffff rw cache
(gdb) mem 0x40140000 0x5fffffff ro cache
(gdb) mem 0x60000000 0x60001fff rw
(gdb) set serial baud 115200
(gdb)
And tell GDB where the debugging info ELF file is located:
(gdb) file /tmp/arduino_build_257110/testgdb.ino.elf
/tmp/arduino_build_257110/testgdb.ino.elf...done. Reading symbols from
Now, connect to the running ESP8266:
(gdb) target remote /dev/ttyUSB0
using /dev/ttyUSB0
Remote debugging 0x40000f68 in ?? ()
(gdb)
Don't worry that GDB doesn't know what is at our present address, we broke into the code at a random spot and we could be in an interrupt, in the ROM, or elsewhere. The important bit is that we're now connected and two things will now happen: we can debug, and the app's regular serial output will be displayed on the GDB console..
Continue the running app to see the serial output:
(gdb) cont
.
Continuing74
75
76
77
...
The app is back running and we can stop it at any time using
Ctrl-C
:
At this point we can set a breakpoint on the main loop()
and restart to get into our own code:
(gdb) break loop
1 at 0x40202e33: file /home/earle/Arduino/sketch_dec26a/sketch_dec26a.ino, line 10.
Breakpoint (gdb) cont
.
Continuing: automatically using hardware breakpoints for read-only addresses.
Note,ap_probe_send_start
bcn_timout
1, loop () at /home/earle/Arduino/sketch_dec26a/sketch_dec26a.ino:10
Breakpoint 10 void loop()
(gdb)
Let's examine the local variable:
And change it:
$2 = 114
(gdb) set cnt = 2000
(gdb) print cnt
$3 = 2000
(gdb)
And restart the app and see our changes take effect:
(gdb) cont
.
Continuing2000
1, loop () at /home/earle/Arduino/sketch_dec26a/sketch_dec26a.ino:10
Breakpoint 10 void loop() {
(gdb) cont
.
Continuing2001
1, loop () at /home/earle/Arduino/sketch_dec26a/sketch_dec26a.ino:10
Breakpoint 10 void loop() {
(gdb)
Looks like we left the breakpoint on loop(), let's get rid of it and try again:
(gdb) delete
? (y or n) y
Delete all breakpoints(gdb) cont
.
Continuing2002
2003
2004
2005
2006
....
At this point we can exit GDB with quit
or do further
debugging.
ESP8266 Hardware Debugging Limitations
The ESP8266 only supports a single hardware breakpoint and a single
hardware data watchpoint. This means only one breakpoint in user code is
allowed at any time. Consider using the thb
(temporary
hardware breakpoint) command in GDB while debugging instead of the more
common break
command, since thb
will remove
the breakpoint once it is reached automatically and save you some
trouble.