mirror of
				https://github.com/esp8266/Arduino.git
				synced 2025-10-31 15:50:55 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			384 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			384 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
| 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
 | |
| <//sourceware.org/gdb/download/onlinedocs/gdb/index.html>`__.
 | |
| 
 | |
| 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:
 | |
| 
 | |
| .. code:: cpp
 | |
| 
 | |
|     #include <GDBStub.h>
 | |
| 
 | |
| And in the ``void setup()`` function ensure the serial port is initialized
 | |
| and call ``gdbstub_init()``:
 | |
| 
 | |
| .. code:: cpp
 | |
| 
 | |
|     Serial.begin(115200);
 | |
|     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:
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     find /tmp -name "*.elf" -print
 | |
| 
 | |
| 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:
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     dir %userprofile%\appdata\*.elf /s/b
 | |
| 
 | |
| 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
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     ~/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/2.5.0-4-b40a506/bin/xtensa-lx106-elf-gdb
 | |
| 
 | |
| Windows (Using Board Manager version)
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     %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)
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     %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:
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     set remote hardware-breakpoint-limit 1
 | |
|     set remote hardware-watchpoint-limit 1
 | |
|     set remote interrupt-on-connect on
 | |
|     set remote kill-packet off
 | |
|     set remote symbol-lookup-packet off
 | |
|     set remote verbose-resume-packet off
 | |
|     mem 0x20000000 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
 | |
|     set serial baud 115200
 | |
| 
 | |
| Now tell GDB where your compiled ELF file is located:
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     file /tmp/arduino_build_257110/sketch_dec26a.ino.elf
 | |
| 
 | |
| 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):
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     target remote /dev/ttyUSB0
 | |
| 
 | |
| or
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     target remote \\.\COM9
 | |
| 
 | |
| 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:
 | |
| 
 | |
| .. code:: cpp
 | |
| 
 | |
|     #include <GDBStub.h>
 | |
|     
 | |
|     void setup() {
 | |
|       Serial.begin(115200);
 | |
|       gdbstub_init();
 | |
|       Serial.printf("Starting...\n");
 | |
|     }
 | |
|     
 | |
|     void loop() {
 | |
|       static uint32_t cnt = 0;
 | |
|       Serial.printf("%d\n", cnt++);
 | |
|       delay(100);
 | |
|     }
 | |
| 
 | |
| Save it and then build and upload to your ESP8266.  On the Serial monitor you
 | |
| should see something like
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     1
 | |
|     2
 | |
|     3
 | |
|     ....
 | |
| 
 | |
| 
 | |
| Now close the Serial Monitor.
 | |
| 
 | |
| Open a command prompt and find the ELF file:
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     earle@server:~$ find /tmp -name "*.elf" -print
 | |
|     /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
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     earle@server:~$ ~/.arduino15/packages/esp8266/hardware/xtensa-lx106-elf/bin/xtensa-lx106-elf-gdb
 | |
|     GNU gdb (GDB) 8.2.50.20180723-git
 | |
|     Copyright (C) 2018 Free Software Foundation, Inc.
 | |
|     License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
 | |
|     This is free software: you are free to change and redistribute it.
 | |
|     There is NO WARRANTY, to the extent permitted by law.
 | |
|     Type "show copying" and "show warranty" for details.
 | |
|     This GDB was configured as "--host=x86_64-linux-gnu --target=xtensa-lx106-elf".
 | |
|     Type "show configuration" for configuration details.
 | |
|     For bug reporting instructions, please see:
 | |
|         <https://www.gnu.org/software/gdb/bugs/>.
 | |
|     Find the GDB manual and other documentation resources online at:
 | |
|         <https://www.gnu.org/software/gdb/documentation/>.
 | |
| 
 | |
|     For help, type "help".
 | |
|     Type "apropos word" to search for commands related to "word".
 | |
|     (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:
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     (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:
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     (gdb) file /tmp/arduino_build_257110/testgdb.ino.elf
 | |
|     Reading symbols from /tmp/arduino_build_257110/testgdb.ino.elf...done.
 | |
| 
 | |
| Now, connect to the running ESP8266:
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     (gdb)     target remote /dev/ttyUSB0
 | |
|     Remote debugging using /dev/ttyUSB0
 | |
|     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:
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     (gdb) cont
 | |
|     Continuing.
 | |
|     74
 | |
|     75
 | |
|     76
 | |
|     77
 | |
|     ...
 | |
| 
 | |
| The app is back running and we can stop it at any time using ``Ctrl-C``:
 | |
| 
 | |
| .. code:: bash 
 | |
| 
 | |
|     113
 | |
|     ^C
 | |
|     Program received signal SIGINT, Interrupt.
 | |
|     0x40000f68 in ?? ()
 | |
|     (gdb) 
 | |
| 
 | |
| At this point we can set a breakpoint on the main ``loop()`` and restart
 | |
| to get into our own code:
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     (gdb) break loop
 | |
|     Breakpoint 1 at 0x40202e33: file /home/earle/Arduino/sketch_dec26a/sketch_dec26a.ino, line 10.
 | |
|     (gdb) cont
 | |
|     Continuing.
 | |
|     Note: automatically using hardware breakpoints for read-only addresses.
 | |
|     bcn_timout,ap_probe_send_start
 | |
|     
 | |
|     Breakpoint 1, loop () at /home/earle/Arduino/sketch_dec26a/sketch_dec26a.ino:10
 | |
|     10	void loop()
 | |
|     (gdb) 
 | |
| 
 | |
| Let's examine the local variable:
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     (gdb) next
 | |
|     loop () at /home/earle/Arduino/sketch_dec26a/sketch_dec26a.ino:13
 | |
|     13      Serial.printf("%d\n", cnt++);
 | |
|     (gdb) print cnt
 | |
|     $1 = 114
 | |
|     (gdb) 
 | |
| 
 | |
| And change it:
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     $2 = 114
 | |
|     (gdb) set cnt = 2000
 | |
|     (gdb) print cnt
 | |
|     $3 = 2000
 | |
|     (gdb) 
 | |
| 
 | |
| And restart the app and see our changes take effect:
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     (gdb) cont
 | |
|     Continuing.
 | |
|     2000
 | |
|     Breakpoint 1, loop () at /home/earle/Arduino/sketch_dec26a/sketch_dec26a.ino:10
 | |
|     10	void loop() {
 | |
|     (gdb) cont
 | |
|     Continuing.
 | |
|     2001
 | |
|     Breakpoint 1, loop () at /home/earle/Arduino/sketch_dec26a/sketch_dec26a.ino:10
 | |
|     10	void loop() {
 | |
|     (gdb) 
 | |
| 
 | |
| Looks like we left the breakpoint on loop(), let's get rid of it and try again:
 | |
| 
 | |
| .. code:: bash
 | |
| 
 | |
|     (gdb) delete
 | |
|     Delete all breakpoints? (y or n) y
 | |
|     (gdb) cont
 | |
|     Continuing.
 | |
|     2002
 | |
|     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.
 | |
| 
 | |
| 
 |