367 lines
12 KiB
ReStructuredText
367 lines
12 KiB
ReStructuredText
.. _develop_debug:
|
|
|
|
Debugging
|
|
#########
|
|
|
|
.. _application_debugging:
|
|
|
|
Application Debugging
|
|
*********************
|
|
|
|
This section is a quick hands-on reference to start debugging your
|
|
application with QEMU. Most content in this section is already covered in
|
|
`QEMU`_ and `GNU_Debugger`_ reference manuals.
|
|
|
|
.. _QEMU: http://wiki.qemu.org/Main_Page
|
|
|
|
.. _GNU_Debugger: http://www.gnu.org/software/gdb
|
|
|
|
In this quick reference, you'll find shortcuts, specific environmental
|
|
variables, and parameters that can help you to quickly set up your debugging
|
|
environment.
|
|
|
|
The simplest way to debug an application running in QEMU is using the GNU
|
|
Debugger and setting a local GDB server in your development system through QEMU.
|
|
|
|
You will need an :abbr:`ELF (Executable and Linkable Format)` binary image for
|
|
debugging purposes. The build system generates the image in the build
|
|
directory. By default, the kernel binary name is :file:`zephyr.elf`. The name
|
|
can be changed using :kconfig:option:`CONFIG_KERNEL_BIN_NAME`.
|
|
|
|
GDB server
|
|
==========
|
|
|
|
We will use the standard 1234 TCP port to open a :abbr:`GDB (GNU Debugger)`
|
|
server instance. This port number can be changed for a port that best suits the
|
|
development environment. There are multiple ways to do this. Each way starts a
|
|
QEMU instance with the processor halted at startup and with a GDB server
|
|
instance listening for a connection.
|
|
|
|
Running QEMU directly
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
You can run QEMU to listen for a "gdb connection" before it starts executing any
|
|
code to debug it.
|
|
|
|
.. code-block:: bash
|
|
|
|
qemu -s -S <image>
|
|
|
|
will setup Qemu to listen on port 1234 and wait for a GDB connection to it.
|
|
|
|
The options used above have the following meaning:
|
|
|
|
* ``-S`` Do not start CPU at startup; rather, you must type 'c' in the
|
|
monitor.
|
|
* ``-s`` Shorthand for :literal:`-gdb tcp::1234`: open a GDB server on
|
|
TCP port 1234.
|
|
|
|
|
|
Running QEMU via :command:`ninja`
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Run the following inside the build directory of an application:
|
|
|
|
.. code-block:: console
|
|
|
|
ninja debugserver
|
|
|
|
QEMU will write the console output to the path specified in
|
|
:makevar:`${QEMU_PIPE}` via CMake, typically :file:`qemu-fifo` within the build
|
|
directory. You may monitor this file during the run with :command:`tail -f
|
|
qemu-fifo`.
|
|
|
|
Running QEMU via :command:`west`
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Run the following from your project root:
|
|
|
|
.. code-block:: console
|
|
|
|
west build -t debugserver_qemu
|
|
|
|
QEMU will write the console output to the terminal from which you invoked
|
|
:command:`west`.
|
|
|
|
Configuring the :command:`gdbserver` listening device
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
The Kconfig option :kconfig:option:`CONFIG_QEMU_GDBSERVER_LISTEN_DEV` controls
|
|
the listening device, which can be a TCP port number or a path to a character
|
|
device. GDB releases 9.0 and newer also support Unix domain sockets.
|
|
|
|
If the option is unset, then the QEMU invocation will lack a ``-s`` or a
|
|
``-gdb`` parameter. You can then use the :envvar:`QEMU_EXTRA_FLAGS` shell
|
|
environment variable to pass in your own listen device configuration.
|
|
|
|
GDB client
|
|
==========
|
|
|
|
Connect to the server by running :command:`gdb` and giving these commands:
|
|
|
|
.. code-block:: bash
|
|
|
|
$ path/to/gdb path/to/zephyr.elf
|
|
(gdb) target remote localhost:1234
|
|
(gdb) dir ZEPHYR_BASE
|
|
|
|
.. note::
|
|
|
|
Substitute the correct :ref:`ZEPHYR_BASE <important-build-vars>` for your
|
|
system.
|
|
|
|
You can use a local GDB configuration :file:`.gdbinit` to initialize your GDB
|
|
instance on every run. Your home directory is a typical location for
|
|
:file:`.gdbinit`, but you can configure GDB to load from other locations,
|
|
including the directory from which you invoked :command:`gdb`. This example
|
|
file performs the same configuration as above:
|
|
|
|
.. code-block:: none
|
|
|
|
target remote localhost:1234
|
|
dir ZEPHYR_BASE
|
|
|
|
Alternate interfaces
|
|
~~~~~~~~~~~~~~~~~~~~
|
|
|
|
GDB provides a curses-based interface that runs in the terminal. Pass the ``--tui``
|
|
option when invoking :command:`gdb` or give the ``tui enable`` command within
|
|
:command:`gdb`.
|
|
|
|
.. note::
|
|
|
|
The GDB version on your development system might not support the ``--tui``
|
|
option. Please make sure you use the GDB binary from the SDK which
|
|
corresponds to the toolchain that has been used to build the binary.
|
|
|
|
Finally, the command below connects to the GDB server using the :abbr:`DDD
|
|
(Data Display Debugger)`, a graphical frontend for GDB. The following command
|
|
loads the symbol table from the ELF binary file, in this instance,
|
|
:file:`zephyr.elf`.
|
|
|
|
.. code-block:: bash
|
|
|
|
ddd --gdb --debugger "gdb zephyr.elf"
|
|
|
|
Both commands execute :command:`gdb`. The command name might
|
|
change depending on the toolchain you are using and your cross-development
|
|
tools.
|
|
|
|
:command:`ddd` may not be installed in your
|
|
development system by default. Follow your system instructions to install
|
|
it. For example, use :command:`sudo apt-get install ddd` on an Ubuntu system.
|
|
|
|
Debugging
|
|
=========
|
|
|
|
As configured above, when you connect the GDB client, the application will be
|
|
stopped at system startup. You may set breakpoints, step through code, etc. as
|
|
when running the application directly within :command:`gdb`.
|
|
|
|
.. note::
|
|
|
|
:command:`gdb` will not print the system console output as the application runs,
|
|
unlike when you run a native application in GDB directly. If you just
|
|
:command:`continue` after connecting the client, the application will run,
|
|
but nothing will appear to happen. Check the console output as described
|
|
above.
|
|
|
|
Debug with Eclipse
|
|
******************
|
|
|
|
Overview
|
|
========
|
|
|
|
CMake supports generating a project description file that can be imported into
|
|
the Eclipse Integrated Development Environment (IDE) and used for graphical
|
|
debugging.
|
|
|
|
The `GNU MCU Eclipse plug-ins`_ provide a mechanism to debug ARM projects in
|
|
Eclipse with pyOCD, Segger J-Link, and OpenOCD debugging tools.
|
|
|
|
The following tutorial demonstrates how to debug a Zephyr application in
|
|
Eclipse with pyOCD in Windows. It assumes you have already installed the GCC
|
|
ARM Embedded toolchain and pyOCD.
|
|
|
|
Set Up the Eclipse Development Environment
|
|
==========================================
|
|
|
|
#. Download and install `Eclipse IDE for C/C++ Developers`_.
|
|
|
|
#. In Eclipse, install the `GNU MCU Eclipse plug-ins`_ by opening the menu
|
|
``Window->Eclipse Marketplace...``, searching for ``GNU MCU Eclipse``, and
|
|
clicking ``Install`` on the matching result.
|
|
|
|
#. Configure the path to the pyOCD GDB server by opening the menu
|
|
``Window->Preferences``, navigating to ``MCU``, and setting the ``Global
|
|
pyOCD Path``.
|
|
|
|
Generate and Import an Eclipse Project
|
|
======================================
|
|
|
|
#. Set up a GNU Arm Embedded toolchain as described in
|
|
:ref:`toolchain_gnuarmemb`.
|
|
|
|
#. Navigate to a folder outside of the Zephyr tree to build your application.
|
|
|
|
.. code-block:: console
|
|
|
|
# On Windows
|
|
cd %userprofile%
|
|
|
|
.. note::
|
|
If the build directory is a subdirectory of the source directory, as is
|
|
usually done in Zephyr, CMake will warn:
|
|
|
|
"The build directory is a subdirectory of the source directory.
|
|
|
|
This is not supported well by Eclipse. It is strongly recommended to use
|
|
a build directory which is a sibling of the source directory."
|
|
|
|
#. Configure your application with CMake and build it with ninja. Note the
|
|
different CMake generator specified by the ``-G"Eclipse CDT4 - Ninja"``
|
|
argument. This will generate an Eclipse project description file,
|
|
:file:`.project`, in addition to the usual ninja build files.
|
|
|
|
.. zephyr-app-commands::
|
|
:tool: all
|
|
:zephyr-app: samples/synchronization
|
|
:host-os: win
|
|
:board: frdm_k64f
|
|
:gen-args: -G"Eclipse CDT4 - Ninja"
|
|
:goals: build
|
|
:compact:
|
|
|
|
#. In Eclipse, import your generated project by opening the menu
|
|
``File->Import...`` and selecting the option ``Existing Projects into
|
|
Workspace``. Browse to your application build directory in the choice,
|
|
``Select root directory:``. Check the box for your project in the list of
|
|
projects found and click the ``Finish`` button.
|
|
|
|
Create a Debugger Configuration
|
|
===============================
|
|
|
|
#. Open the menu ``Run->Debug Configurations...``.
|
|
|
|
#. Select ``GDB PyOCD Debugging``, click the ``New`` button, and configure the
|
|
following options:
|
|
|
|
- In the Main tab:
|
|
|
|
- Project: ``my_zephyr_app@build``
|
|
- C/C++ Application: :file:`zephyr/zephyr.elf`
|
|
|
|
- In the Debugger tab:
|
|
|
|
- pyOCD Setup
|
|
|
|
- Executable path: :file:`${pyocd_path}\\${pyocd_executable}`
|
|
- Uncheck "Allocate console for semihosting"
|
|
|
|
- Board Setup
|
|
|
|
- Bus speed: 8000000 Hz
|
|
- Uncheck "Enable semihosting"
|
|
|
|
- GDB Client Setup
|
|
|
|
- Executable path example (use your ``GNUARMEMB_TOOLCHAIN_PATH``):
|
|
:file:`C:\\gcc-arm-none-eabi-6_2017-q2-update\\bin\\arm-none-eabi-gdb.exe`
|
|
|
|
- In the SVD Path tab:
|
|
|
|
- File path: :file:`<workspace
|
|
top>\\modules\\hal\\nxp\\mcux\\devices\\MK64F12\\MK64F12.xml`
|
|
|
|
.. note::
|
|
This is optional. It provides the SoC's memory-mapped register
|
|
addresses and bitfields to the debugger.
|
|
|
|
#. Click the ``Debug`` button to start debugging.
|
|
|
|
RTOS Awareness
|
|
==============
|
|
|
|
Support for Zephyr RTOS awareness is implemented in `pyOCD v0.11.0`_ and later.
|
|
It is compatible with GDB PyOCD Debugging in Eclipse, but you must enable
|
|
CONFIG_DEBUG_THREAD_INFO=y in your application.
|
|
|
|
Debugging I2C communication
|
|
***************************
|
|
|
|
There is a possibility to log all or some of the I2C transactions done by the application.
|
|
This feature is enabled by the Kconfig option :kconfig:option:`CONFIG_I2C_DUMP_MESSAGES`, but it
|
|
uses the :c:macro:`LOG_DBG` function to print the contents so the
|
|
:kconfig:option:`CONFIG_I2C_LOG_LEVEL_DBG` option must also be enabled.
|
|
|
|
The sample output of the dump looks like this::
|
|
|
|
D: I2C msg: io_i2c_ctrl7_port0, addr=50
|
|
D: W len=01: 00
|
|
D: R Sr P len=08:
|
|
D: contents:
|
|
D: 43 42 41 00 00 00 00 00 |CBA.....
|
|
|
|
The first line indicates the I2C controller and the target address of the transaction.
|
|
In above example, the I2C controller is named ``io_i2c_ctrl7_port0`` and the target device address
|
|
is ``0x50``
|
|
|
|
.. note::
|
|
|
|
the address, length and contents values are in hexadecimal, but lack the ``0x`` prefix
|
|
|
|
Next lines contain messages, both sent and received. The contents of write messages is
|
|
always shown, while the content of read messages is controlled by a parameter to the
|
|
function ``i2c_dump_msgs_rw``. This function is available for use by user, but is also
|
|
called internally by ``i2c_transfer`` API function with read content dump enabled.
|
|
Before the length parameter, the header of the message is printed using abbreviations:
|
|
|
|
- W - write message
|
|
- R - read message
|
|
- Sr - restart bit
|
|
- P - stop bit
|
|
|
|
The above example shows one write message with byte ``0x00`` representing the address of register to
|
|
read from the I2C target. After that the log shows the length of received message and following
|
|
that, the bytes read from the target ``43 42 41 00 00 00 00 00``.
|
|
The content dump consist of both the hex and ASCII representation.
|
|
|
|
Filtering the I2C communication dump
|
|
====================================
|
|
|
|
By default, all I2C communication is logged between all I2C controllers and I2C targets.
|
|
It may litter the log with unrelated devices and make it difficult to effectively debug the
|
|
communication with a device of interest.
|
|
|
|
Enable the Kconfig option :kconfig:option:`CONFIG_I2C_DUMP_MESSAGES_ALLOWLIST` to create an
|
|
allowlist of I2C targets to log.
|
|
The allowlist of devices is configured using the devicetree, for example::
|
|
|
|
/ {
|
|
i2c {
|
|
display0: some-display@a {
|
|
...
|
|
};
|
|
sensor3: some-sensor@b {
|
|
...
|
|
};
|
|
};
|
|
|
|
i2c-dump-allowlist {
|
|
compatible = "zephyr,i2c-dump-allowlist";
|
|
devices = < &display0 >, < &sensor3 >;
|
|
};
|
|
};
|
|
|
|
The filters nodes are identified by the compatible string with ``zephyr,i2c-dump-allowlist`` value.
|
|
The devices are selected using the ``devices`` property with phandles to the devices on the I2C bus.
|
|
|
|
In the above example, the communication with device ``display0`` and ``sensor3`` will be displayed
|
|
in the log.
|
|
|
|
|
|
|
|
.. _Eclipse IDE for C/C++ Developers: https://www.eclipse.org/downloads/packages/eclipse-ide-cc-developers/oxygen2
|
|
.. _GNU MCU Eclipse plug-ins: https://gnu-mcu-eclipse.github.io/plugins/install/
|
|
.. _pyOCD v0.11.0: https://github.com/mbedmicro/pyOCD/releases/tag/v0.11.0
|