doc: debug: expand documentation on gdbstub

This expands the documentation on GDB stub, and adding
hints on porting to new architectures.

Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
Daniel Leung 2021-11-02 10:10:30 -07:00 committed by Anas Nashif
parent 5d19da4507
commit bdc812c15a
3 changed files with 193 additions and 4 deletions

View file

@ -1,4 +1,4 @@
.. _gdbgstub:
.. _gdbstub:
GDB stub
########
@ -15,13 +15,11 @@ TCP/IP. Zephyr currently supports only serial device communication.
The GDB program acts as the client while Zephyr acts as the
server. When this feature is enabled, Zephyr stops its execution after
``gdb_init()`` starts gdbstub service and waits for a GDB
:c:func:`gdb_init` starts gdbstub service and waits for a GDB
connection. Once a connection is established it is possible to
synchronously interact with Zephyr. Note that currently it is not
possible to asynchronously send commands to the target.
Enable this feature with the :kconfig:`CONFIG_GDBSTUB` option.
Features
********
@ -32,3 +30,53 @@ The following features are supported:
* Print backtrace
* Read or write general registers
* Read or write the memory
Enabling GDB Stub
*****************
GDB stub can be enabled with the :kconfig:`CONFIG_GDBSTUB` option.
Using Serial Backend
====================
The serial backend for GDB stub can be enabled with
the :kconfig:`CONFIG_GDBSTUB_SERIAL_BACKEND` option.
Since serial backend utilizes UART devices to send and receive GDB commands,
* If there are spare UART devices on the board, set
:kconfig:`CONFIG_GDBSTUB_SERIAL_BACKEND_NAME` to the spare UART device
so that :c:func:`printk` and log messages are not being printed to
the same UART device used for GDB.
* For boards with only one UART device, :c:func:`printk` and logging
must be disabled if they are also using the same UART device for output.
GDB related messages may interleave with log messages which may have
unintended consequences. Usually this can be done by disabling
:kconfig:`CONFIG_PRINTK` and :kconfig:`CONFIG_LOG`.
Debugging
*********
Using Serial Backend
====================
#. Build with GDB stub and serial backend enabled.
#. Flash built image onto board and reset the board.
* Execution should now be paused at :c:func:`gdb_init`.
#. Execute GDB on development machine and connect to the GDB stub.
.. code-block:: bash
target remote <serial device>
For example,
.. code-block:: bash
target remote /dev/ttyUSB1
#. GDB commands can be used to start debugging.

View file

@ -835,6 +835,141 @@ In addition to implementing these APIs, there are some other tasks as well:
:c:enum:`K_SYSCALL_BAD` handler. Upon completion of the system call, care
must be taken not to leak any register state back to user mode.
GDB Stub
********
To enable GDB stub for remote debugging on a new architecture:
#. Create a new ``gdbstub.h`` header file under appropriate architecture
include directory (``include/arch/<arch>/gdbstub.h``).
* Create a new struct ``struct gdb_ctx`` as the GDB context.
* Must define a member named ``exception`` of type ``unsigned int`` to
store the GDB exception reason. This value needs to be set before
entering :c:func:`z_gdb_main_loop`.
* Architecture can define as many members as needed for GDB stub to
function.
* Pointer to this struct needs to be passed to :c:func:`z_gdb_main_loop`,
where this pointer will be passed to other GDB stub functions.
#. Functions for entering and exiting GDB stub main loop.
* If the architecture relies on interrupts to service breakpoints,
interrupt service routines (ISR) need to be implemented, which
will serve as the entry point to GDB stub main loop.
* These functions need to save and restore context so code execution
can continue as if no breakpoints have been encountered.
* These functions need to call :c:func:`z_gdb_main_loop` after saving
execution context to go into the GDB stub main loop to receive commands
from GDB.
* Before calling :c:func:`z_gdb_main_loop`, :c:member:`gdb_ctx.exception`
must be set to specify the exception reason.
#. Implementat necessary functions to support GDB stub functionality:
* :c:func:`arch_gdb_init`
* This needs to initialize necessary bits to support GDB stub functionality,
for example, setting up the GDB context and connecting debug interrupts.
* This must stop code execution via architecture specific method (e.g.
raising debug interrupts). This allows GDB to connect during boot.
* :c:func:`arch_gdb_continue`
* This function is called when GDB sends a ``c`` or ``continue`` command
to continue code execution.
* :c:func:`arch_gdb_step`
* This function is called when GDB sends a ``si`` or ``stepi`` command
to execute one machine instruction, before returning to GDB prompt.
* Hardware register read/write functions:
* Since the GDB stub is running on the target, manipulation of hardware
registers need to cached to avoid affecting the execution of GDB stub.
Think of it as context switching, where the execution context is
changed to the GDB stub. So that the register values of the running
thread before context switch need to be stored. Manipulation of
register values must only be done to this cached copy. The updated
values will then be written to hardware registers before switching
back to the previous running thread.
* :c:func:`arch_gdb_reg_readall`
* This collects all hardware register values that would appear in
a ``g``/``G`` packets which will be sent back to GDB. The format of
the G-packet is architecture specific. Consult GDB on what is
expected.
* Note that, for most architectures, a valid G-packet must be returned
and sent to GDB. If a packet without incorrect length is sent to
GDB, GDB will abort the debugging session.
* :c:func:`arch_gdb_reg_writeall`
* This takes a G-packet sent by GDB and populates the hardware
registers with values from the G-packet.
* :c:func:`arch_gdb_reg_readone`
* This reads the value of one hardware register and sends
the result to GDB.
* :c:func:`arch_gdb_reg_writeone`
* This writes the value of one hardware register received from GDB.
* Breakpoints:
* :c:func:`arch_gdb_add_breakpoint` and
:c:func:`arch_gdb_remove_breakpoint`
* GDB may decide to use software breakpoints which modifies
the memory at the breakpoint locations to replace the instruction
with software breakpoint or trap instructions. GDB will then
restore the memory content once execution reaches the breakpoints.
GDB supports this by default and there is usually no need to
handle software breakpoints in the architecture code (where
breakpoint type is ``0``).
* Hardware breakpoints (type ``1``) are required if the code is
in ROM or flash that cannot be modified at runtime. Consult
the architecture datasheet on how to enable hardware breakpoints.
* If hardware breakpoints are not supported by the architecture,
there is no need to implement these in architecture code.
GDB will then rely on software breakpoints.
#. For architecture where certain memory regions are not accessible,
an array named :c:var:`gdb_mem_region_array` of type
:c:struct:`gdb_mem_region` needs to be defined to specify regions
that are accessible. For each array item:
* :c:member:`gdb_mem_region.start` specifies the start of a memory
region.
* :c:member:`gdb_mem_region.end` specifies the end of a memory
region.
* :c:member:`gdb_mem_region.attribites` specifies the permission
of a memory region.
* :c:macro:`GDB_MEM_REGION_RO`: region is read-only.
* :c:macro:`GDB_MEM_REGION_RW`: region is read-write.
* :c:member:`gdb_mem_region.alignment` specifies read/write alignment
of a memory region. Use ``0`` if there is no alignment requirement
and read/write can be done byte-by-byte.
API Reference
*************
@ -879,3 +1014,8 @@ Miscellaneous Architecture APIs
===============================
.. doxygengroup:: arch-misc
GDB Stub APIs
=============
.. doxygengroup:: arch-gdbstub

View file

@ -2268,6 +2268,7 @@ PREDEFINED = __DOXYGEN__ \
CONFIG_FLASH_PAGE_LAYOUT \
CONFIG_FPU \
CONFIG_FPU_SHARING \
CONFIG_GDBSTUB \
CONFIG_HEAP_MEM_POOL_SIZE \
CONFIG_MMU \
CONFIG_NET_L2_ETHERNET_MGMT \