.. Tutorial to start using the GDB debugger for embedded development
.. Author: Thomas Van Hoof

.. STATUS: production

###########################################
Debugging tutorial for embedded development
###########################################

Tutorial to start using the :abbr:`GDB (GNU Debugger)` debugger for embedded development.

.. note:: You need `the toolchain for embedded developers <toolchain.rst>`_ installed before following this tutorial.


.. rubric:: Quick Navigation
.. contents::
   :local:
   :depth: 2

************
Introduction
************

.. hint:: A successfully compiled project does by no means indicate the code is bug free.

Before debugging the target first needs to be flashed on the microcontroller [1]_.

:abbr:`OpenOCD (open on-chip-debugger)` is used to link the hardware debugger to the software debugger (:abbr:`GDB (GNU Debugger)`). A schematic of this setup is shown below:

.. image:: images/Debug_Schematic.svg
   :align: left
   :scale: 100%

*******
OpenOCD
*******

To start debugging, the hardware debugger needs to be connected to your computer **before** you launch the debugging software. To start debugging execute the following command:

.. hint:: Your version of OpenOCD will most likely differ from this tutorial. Use bash autocompletion to get the correct path to ``jlink.cfg`` and ``nrf52.cfg``:

::

  $ openocd -f /Applications/GNU\ ARM\ Eclipse/OpenOCD/0.10.0-201701241841/scripts/interface/jlink.cfg  -c "transport select swd" -f /Applications/GNU\ ARM\ Eclipse/OpenOCD/0.10.0-201701241841/scripts/target/nrf52.cfg
  Open On-Chip Debugger 0.10.0+dev-g0ecee83 (2017-02-10-15:11)
  Licensed under GNU GPL v2
  For bug reports, read
  	http://openocd.org/doc/doxygen/bugs.html
  swd
  adapter speed: 10000 kHz
  cortex_m reset_config sysresetreq
  Info : No device selected, using first device.
  Info : J-Link OB-SAM3U128-V2-NordicSemi compiled Nov 14 2016 16:58:29
  Info : Hardware version: 1.00
  Info : VTarget = 3.300 V
  Info : Reduced speed from 10000 kHz to 1000 kHz (maximum).
  Info : Reduced speed from 10000 kHz to 1000 kHz (maximum).
  Info : clock speed 10000 kHz
  Info : SWD DPIDR 0x2ba01477
  Info : nrf52.cpu: hardware has 6 breakpoints, 4 watchpoints
  Info : accepting 'gdb' connection on tcp/3333
  undefined debug reason 7 - target needs reset
  requesting target halt and executing a soft reset
  Warn : soft_reset_halt is deprecated, please use 'reset halt' instead.
  target halted due to breakpoint, current mode: Thread
  xPSR: 0x01000000 pc: 0x000008e4 msp: 0x20000400
  invalid command name "reset_halt"
  target halted due to debug-request, current mode: Thread
  xPSR: 0x01000000 pc: 0x000008e4 msp: 0x20000400
  Info : dropped 'gdb' connection
  ^CThomass-MacBook-Pro:armgcc thomas$ ~/debug_DK
  Open On-Chip Debugger 0.10.0+dev-g0ecee83 (2017-02-10-15:11)
  Licensed under GNU GPL v2
  For bug reports, read
  	http://openocd.org/doc/doxygen/bugs.html
  swd
  adapter speed: 10000 kHz
  cortex_m reset_config sysresetreq
  Info : No device selected, using first device.
  Info : J-Link OB-SAM3U128-V2-NordicSemi compiled Nov 14 2016 16:58:29
  Info : Hardware version: 1.00
  Info : VTarget = 3.300 V
  Info : Reduced speed from 10000 kHz to 1000 kHz (maximum).
  Info : Reduced speed from 10000 kHz to 1000 kHz (maximum).
  Info : clock speed 10000 kHz
  Info : SWD DPIDR 0x2ba01477
  Info : nrf52.cpu: hardware has 6 breakpoints, 4 watchpoints

.. hint:: You might want to create an alias for this long command by adding the following line to ``~/.bash_profile``: ``alias debugger='long command'``.

************
GNU Debugger
************

Since OpenOCD provides a link to the hardware debugger, it needs to keep running. You will need another terminal window or tab to continue. Go to the directory where the project was built and type: ::

  $ arm-none_eabi-gdb --tui *.out

This will open something similar to

.. image:: images/initial_GDB.png
   :align: left
   :scale: 100%

Both OpenOCD and GDB are running, but there is no connection between them. To establish this connection, type: ::

  (gdb) target remote localhost:3333

It is possible that the window with the sourcecode went empty. To solve this, press the arrow up or down. If you want to give commands to OpenOCD from within GDB, you will need to type: ::

  (gdb) monitor OpenOCD_command

The most used OpenOCD commands are

  +-------------------+----------------------------------------------------------------------------------------------+
  | command           | Description                                                                                  |
  +===================+==============================================================================================+
  | halt              | Stop the execution of the program                                                            |
  +-------------------+----------------------------------------------------------------------------------------------+
  | reset             | Performs a hard reset                                                                        |
  +-------------------+----------------------------------------------------------------------------------------------+
  | reset run         | Performs a hard reset, and will continue by running the device                               |
  +-------------------+----------------------------------------------------------------------------------------------+
  | reset halt        | Performs a hard reset, and immediately halts the device                                      |
  +-------------------+----------------------------------------------------------------------------------------------+
  | reset init        | Performs a hard reset, immediately halts the target, and will execute the reset-init script  |
  +-------------------+----------------------------------------------------------------------------------------------+
  | soft_reset_halt   | Requests a target halt, and executes a soft reset.                                           |
  +-------------------+----------------------------------------------------------------------------------------------+
  | resume            | Resume the execution. Optionally you can give an `address`-parameter, where to resume from   |
  +-------------------+----------------------------------------------------------------------------------------------+
  | reg               | prints out information and the values of the registers                                       |
  +-------------------+----------------------------------------------------------------------------------------------+

Basic commands for GDB
======================

.. hint:: most of the GDB commands can be abbreviated to the first (set of) character(s). All the commands shown in this tutorial can be abbreviated to their first character.

Use the ``break`` (or ``b``) command to set a breakpoint.


+------------------------------------+-------------------------------------------------------------------------------------------------------+
| Command                            | Description                                                                                           |
+====================================+=======================================================================================================+
| break `function_name`              | Set a breakpoint at a specific function or line number                                                |
+------------------------------------+                                                                                                       +
| break `line_number`                |                                                                                                       |
+------------------------------------+-------------------------------------------------------------------------------------------------------+
| break +`offset`                    | Set a breakpoint at a specified number lines of code forward or back from where the execution stopped |
+------------------------------------+                                                                                                       +
| break -`offset`                    |                                                                                                       |
+------------------------------------+-------------------------------------------------------------------------------------------------------+
| break `*address`                   | The program will halt when processing an instruction at address                                       |
+------------------------------------+-------------------------------------------------------------------------------------------------------+
| break `line_number` if `condition` | where condition is an expression. Suspend at line number when boolean expression is true              |
+------------------------------------+-------------------------------------------------------------------------------------------------------+
| watch `condition`                  | Suspend when condition is true                                                                        |
+------------------------------------+-------------------------------------------------------------------------------------------------------+
| clear `function_name`              | remove the breakpoint at a specific function or line number                                           |
+------------------------------------+                                                                                                       +
| clear `line_number`                |                                                                                                       |
+------------------------------------+-------------------------------------------------------------------------------------------------------+
| delete                             | delete all breakpoints                                                                                |
+------------------------------------+-------------------------------------------------------------------------------------------------------+

When you have stopped the execution of the program, you can also use line executions

+-----------------------------------+----------------------------------------------------------------------------+
| Command                           | Description                                                                |
+===================================+============================================================================+
| step                              | performs the specified amount of steps. This will enter function           |
+-----------------------------------+                                                                            +
| step `number_of_steps_to_perform` |                                                                            |
+-----------------------------------+----------------------------------------------------------------------------+
| next                              | performs the specified amount of steps. This will not enter function       |
+-----------------------------------+                                                                            +
| next `number`                     |                                                                            |
+-----------------------------------+----------------------------------------------------------------------------+
| until `line_number`               | will run until you reach a specified line number, function name or address |
+-----------------------------------+----------------------------------------------------------------------------+

You can check or change the values of variables

+---------------------------+----------------------------------------------------+
| command                   | Description                                        |
+===========================+====================================================+
| print `variable`          | print the value of `variable`                      |
+---------------------------+                                                    +
| p `variable`              |                                                    |
+---------------------------+----------------------------------------------------+
| p `*array-variable@length`| print first # values of array specified by length  |
+---------------------------+----------------------------------------------------+
| p/x `variable`            | prints an integer variable in hex                  |
+---------------------------+----------------------------------------------------+
| p/d `variable`            | prints variable as a signed int                    |
+---------------------------+----------------------------------------------------+
| p/u `variable`            | prints variable as an unsigned int                 |
+---------------------------+----------------------------------------------------+
| p/t `variable`            | prints an integer value in binary                  |
+---------------------------+                                                    +
| x/b `variable`            |                                                    |
+---------------------------+----------------------------------------------------+
| p/c `variable`            | prints integer as character                        |
+---------------------------+----------------------------------------------------+
| p/f `variable`            | prints variable as float                           |
+---------------------------+----------------------------------------------------+
| set variable=x            | change the value of variable to x                  |
+---------------------------+----------------------------------------------------+

Another important and very useful command is to load a new file into the debugger. This can be done with ::

  (gdb) file <file_name>

The debugger will ask you if you are sure you want to load the new binary.

.. hint:: All the breakpoints you have set, might be lost. Check them before continuing.

Basic commands for GDB TUI
==========================
At startup, there are 2 windows. You can get more information about the window with ::

  (gdb) info win
          SRC     (41 lines)  <has focus>
          CMD     (21 lines)

Now you can see that the src window has the focus. This can easily be changed to another window with the ``focus`` command, followed by the name of the window,  ``next`` or ``prev``. You can also change the layout, with the ``layout`` command, followed by a name [2]_, ``next`` or ``prev``. You can also split the top window with ::

  (gdb) layout split

*************
Usefull sites
*************

| `Using GDB with OpenOCD <http://openocd.org/doc/html/GDB-and-OpenOCD.html>`_
| `Flash programming with OpenOCD <http://openocd.org/doc/html/Flash-Programming.html>`_
| `General GDB TUI commands <https://sourceware.org/gdb/onlinedocs/gdb/TUI-Commands.html>`_
| `General GDB commands <https://www.tutorialspoint.com/gnu_debugger/gdb_commands.htm>`_
| `GDB commands <http://www.yolinux.com/TUTORIALS/GDB-Commands.html>`_
| `How to use the gdb gnu debugger and openocd for microcontroller debugging <http://stackoverflow.com/questions/38033130/how-to-use-the-gdb-gnu-debugger-and-openocd-for-microcontroller-debugging-fr>`_
| `More GDB Commands <http://www.yolinux.com/TUTORIALS/GDB-Commands.html>`_

.. [1] This is something that might change in the future when we have other HW debuggers. Then it might be possible to flash the target from within the debugger
.. [2] possible names are: src, asm, regs.
