gdbstub: doc: Update documentation with example
Update the Zephyr `gdbstub` documentation with its 'how to use' example to align with former sample application replaced by the test. Fixes: zephyrproject-rtos#70966 Signed-off-by: Dmitrii Golovanov <dmitrii.golovanov@intel.com>
This commit is contained in:
parent
e13d1b47c6
commit
3614d4cb88
1 changed files with 101 additions and 98 deletions
|
@ -17,7 +17,7 @@ using GDB.
|
||||||
The protocol supports different connection types: serial, UDP/IP and
|
The protocol supports different connection types: serial, UDP/IP and
|
||||||
TCP/IP. Zephyr currently supports only serial device communication.
|
TCP/IP. Zephyr currently supports only serial device communication.
|
||||||
|
|
||||||
The GDB program acts as the client while Zephyr acts as the
|
The GDB program acts as a client while the Zephyr gdbstub acts as a
|
||||||
server. When this feature is enabled, Zephyr stops its execution after
|
server. When this feature is enabled, Zephyr stops its execution after
|
||||||
:c:func:`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
|
connection. Once a connection is established it is possible to
|
||||||
|
@ -87,20 +87,39 @@ Using Serial Backend
|
||||||
Example
|
Example
|
||||||
*******
|
*******
|
||||||
|
|
||||||
This is an example to demonstrate how GDB stub works.
|
There is a test application :zephyr_file:`tests/subsys/debug/gdbstub` with one of its
|
||||||
You can also refer to ``tests/subsys/debug/gdbstub``
|
test cases ``debug.gdbstub.breakpoints`` demonstrating how the Zephyr GDB stub can be used.
|
||||||
for its implementation as a Twister test.
|
The test also has a case to connect to the QEMU's GDB stub implementation (at a custom
|
||||||
|
port ``tcp:1235``) as a reference to validate the test script itself.
|
||||||
|
|
||||||
|
Run the test with the following command from your :envvar:`ZEPHYR_BASE` directory:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
./scripts/twister -p qemu_x86 -T tests/subsys/debug/gdbstub
|
||||||
|
|
||||||
|
The test should run successfully, and now let's do something similar step-by-step
|
||||||
|
to demonstrate how the Zephyr GDB stub works from the GDB user's perspective.
|
||||||
|
|
||||||
|
In the snippets below use and expect your appropriate directories instead of
|
||||||
|
``<SDK install directory>``, ``<build_directory>``, ``<ZEPHYR_BASE>``.
|
||||||
|
|
||||||
|
|
||||||
#. Open two terminal windows.
|
#. Open two terminal windows.
|
||||||
|
|
||||||
#. On the first terminal, build and run the sample:
|
#. On the first terminal, build and run the test application:
|
||||||
|
|
||||||
.. zephyr-app-commands::
|
.. zephyr-app-commands::
|
||||||
:zephyr-app: samples/subsys/debug/gdbstub
|
:zephyr-app: tests/subsys/debug/gdbstub
|
||||||
:host-os: unix
|
:host-os: unix
|
||||||
:board: qemu_x86
|
:board: qemu_x86
|
||||||
|
:gen-args: '-DCONFIG_QEMU_EXTRA_FLAGS="-serial tcp:localhost:5678,server"'
|
||||||
:goals: build run
|
:goals: build run
|
||||||
|
|
||||||
|
Note how we set :kconfig:option:`CONFIG_QEMU_EXTRA_FLAGS` to direct QEMU serial
|
||||||
|
console port to the ``localhost`` TCP port ``5678`` to wait for a connection
|
||||||
|
from the GDB ``remote`` command we are going to do on the next steps.
|
||||||
|
|
||||||
#. On the second terminal, start GDB:
|
#. On the second terminal, start GDB:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
@ -111,7 +130,7 @@ for its implementation as a Twister test.
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
(gdb) file <build directory>/zephyr/zephyr.elf
|
(gdb) symbol-file <build directory>/zephyr/zephyr.elf
|
||||||
|
|
||||||
Response from GDB:
|
Response from GDB:
|
||||||
|
|
||||||
|
@ -119,38 +138,38 @@ for its implementation as a Twister test.
|
||||||
|
|
||||||
Reading symbols from <build directory>/zephyr/zephyr.elf...
|
Reading symbols from <build directory>/zephyr/zephyr.elf...
|
||||||
|
|
||||||
#. Tell GDB to connect to the server:
|
#. Tell GDB to connect to the Zephyr gdbstub serial backend which is exposed
|
||||||
|
earlier as a server through the TCP port ``-serial`` redirection at QEMU.
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
(gdb) target remote localhost:5678
|
(gdb) target remote localhost:5678
|
||||||
|
|
||||||
Note that QEMU is setup to redirect the serial used for GDB stub in
|
|
||||||
the Zephyr image to a networking port. Hence the connection to
|
|
||||||
localhost, port 5678.
|
|
||||||
|
|
||||||
Response from GDB:
|
Response from GDB:
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
Remote debugging using :5678
|
Remote debugging using localhost:5678
|
||||||
arch_gdb_init () at <ZEPHYR_BASE>/arch/x86/core/ia32/gdbstub.c:232
|
arch_gdb_init () at <ZEPHYR_BASE>/arch/x86/core/ia32/gdbstub.c:252
|
||||||
232 }
|
252 }
|
||||||
|
|
||||||
GDB also shows where the code execution is stopped. In this case,
|
GDB also shows where the code execution is stopped. In this case,
|
||||||
it is at :file:`arch/x86/core/ia32/gdbstub.c`, line 232.
|
it is at :zephyr_file:`arch/x86/core/ia32/gdbstub.c`, line 252.
|
||||||
|
|
||||||
#. Use command ``bt`` or ``backtrace`` to show the backtrace of stack frames.
|
#. Use command ``bt`` or ``backtrace`` to show the backtrace of stack frames.
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
(gdb) bt
|
(gdb) bt
|
||||||
#0 arch_gdb_init () at <ZEPHYR_BASE>/arch/x86/core/ia32/gdbstub.c:232
|
#0 arch_gdb_init () at <ZEPHYR_BASE>/arch/x86/core/ia32/gdbstub.c:252
|
||||||
#1 0x00105068 in gdb_init (arg=0x0) at <ZEPHYR_BASE>/subsys/debug/gdbstub.c:833
|
#1 0x00104140 in gdb_init () at <ZEPHYR_BASE>/zephyr/subsys/debug/gdbstub.c:852
|
||||||
#2 0x00109d6f in z_sys_init_run_level (level=0x1) at <ZEPHYR_BASE>/kernel/device.c:72
|
#2 0x00109c13 in z_sys_init_run_level (level=INIT_LEVEL_PRE_KERNEL_2) at <ZEPHYR_BASE>/kernel/init.c:360
|
||||||
#3 0x0010a40b in z_cstart () at <ZEPHYR_BASE>/kernel/init.c:423
|
#3 0x00109e73 in z_cstart () at <ZEPHYR_BASE>/kernel/init.c:630
|
||||||
#4 0x00105383 in z_prep_c (arg=0x9500) at <ZEPHYR_BASE>/arch/x86/core/prep_c.c:58
|
#4 0x00104422 in z_prep_c (arg=0x1245bc <x86_cpu_boot_arg>) at <ZEPHYR_BASE>/arch/x86/core/prep_c.c:80
|
||||||
#5 0x001000a9 in __csSet () at <ZEPHYR_BASE>/arch/x86/core/ia32/crt0.S:273
|
#5 0x001000c9 in __csSet () at <ZEPHYR_BASE>/arch/x86/core/ia32/crt0.S:290
|
||||||
|
#6 0x001245bc in uart_dev ()
|
||||||
|
#7 0x00134988 in z_interrupt_stacks ()
|
||||||
|
#8 0x00000000 in ?? ()
|
||||||
|
|
||||||
#. Use command ``list`` to show the source code and surroundings where
|
#. Use command ``list`` to show the source code and surroundings where
|
||||||
code execution is stopped.
|
code execution is stopped.
|
||||||
|
@ -158,16 +177,16 @@ for its implementation as a Twister test.
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
(gdb) list
|
(gdb) list
|
||||||
227 }
|
247 __asm__ volatile ("int3");
|
||||||
228
|
248
|
||||||
229 void arch_gdb_init(void)
|
249 #ifdef CONFIG_GDBSTUB_TRACE
|
||||||
230 {
|
250 printk("gdbstub:%s GDB is connected\n", __func__);
|
||||||
231 __asm__ volatile ("int3");
|
251 #endif
|
||||||
232 }
|
252 }
|
||||||
233
|
253
|
||||||
234 /* Hook current IDT. */
|
254 /* Hook current IDT. */
|
||||||
235 _EXCEPTION_CONNECT_NOCODE(z_gdb_debug_isr, IV_DEBUG, 3);
|
255 _EXCEPTION_CONNECT_NOCODE(z_gdb_debug_isr, IV_DEBUG, 3);
|
||||||
236 _EXCEPTION_CONNECT_NOCODE(z_gdb_break_isr, IV_BREAKPOINT, 3);
|
256 _EXCEPTION_CONNECT_NOCODE(z_gdb_break_isr, IV_BREAKPOINT, 3);
|
||||||
|
|
||||||
#. Use command ``s`` or ``step`` to step through program until it reaches
|
#. Use command ``s`` or ``step`` to step through program until it reaches
|
||||||
a different source line. Now that it finished executing :c:func:`arch_gdb_init`
|
a different source line. Now that it finished executing :c:func:`arch_gdb_init`
|
||||||
|
@ -176,31 +195,34 @@ for its implementation as a Twister test.
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
(gdb) s
|
(gdb) s
|
||||||
gdb_init (arg=0x0) at /home/dleung5/zephyr/rtos/zephyr/subsys/debug/gdbstub.c:834
|
gdb_init () at <ZEPHYR_BASE>/subsys/debug/gdbstub.c:857
|
||||||
834 return 0;
|
857 return 0;
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
(gdb) list
|
(gdb) list
|
||||||
829 LOG_ERR("Could not initialize gdbstub backend.");
|
852 arch_gdb_init();
|
||||||
830 return -1;
|
853
|
||||||
831 }
|
854 #ifdef CONFIG_GDBSTUB_TRACE
|
||||||
832
|
855 printk("gdbstub:%s exit\n", __func__);
|
||||||
833 arch_gdb_init();
|
856 #endif
|
||||||
834 return 0;
|
857 return 0;
|
||||||
835 }
|
858 }
|
||||||
836
|
859
|
||||||
837 #ifdef CONFIG_XTENSA
|
860 #ifdef CONFIG_XTENSA
|
||||||
838 /*
|
861 /*
|
||||||
|
|
||||||
#. Use command ``br`` or ``break`` to setup a breakpoint. This example
|
#. Use command ``br`` or ``break`` to setup a breakpoint. For this example
|
||||||
sets up a breakpoint at :c:func:`main`, and let code execution continue
|
set up a breakpoint at :c:func:`main`, and let code execution continue
|
||||||
without any intervention using command ``c`` (or ``continue``).
|
without any intervention using command ``c`` (or ``continue``).
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
(gdb) break main
|
(gdb) break main
|
||||||
Breakpoint 1 at 0x1005a9: file <ZEPHYR_BASE>/samples/subsys/debug/gdbstub/src/main.c, line 32.
|
Breakpoint 1 at 0x10064d: file <ZEPHYR_BASE>/tests/subsys/debug/gdbstub/src/main.c, line 27.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
(gdb) continue
|
(gdb) continue
|
||||||
Continuing.
|
Continuing.
|
||||||
|
|
||||||
|
@ -209,24 +231,24 @@ for its implementation as a Twister test.
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
Breakpoint 1, main () at <ZEPHYR_BASE>/samples/subsys/debug/gdbstub/src/main.c:32
|
Breakpoint 1, main () at <ZEPHYR_BASE>/tests/subsys/debug/gdbstub/src/main.c:27
|
||||||
32 ret = test();
|
27 printk("%s():enter\n", __func__);
|
||||||
|
|
||||||
Now GDB is waiting at the beginning of :c:func:`main`:
|
Now GDB is waiting at the beginning of :c:func:`main`:
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
(gdb) list
|
(gdb) list
|
||||||
27
|
22
|
||||||
28 int main(void)
|
23 int main(void)
|
||||||
29 {
|
24 {
|
||||||
30 int ret;
|
25 int ret;
|
||||||
31
|
26
|
||||||
32 ret = test();
|
27 printk("%s():enter\n", __func__);
|
||||||
33 printk("%d\n", ret);
|
28 ret = test();
|
||||||
34 }
|
29 printk("ret=%d\n", ret);
|
||||||
35
|
30 return 0;
|
||||||
36 K_THREAD_DEFINE(thread, STACKSIZE, thread_entry, NULL, NULL, NULL,
|
31 }
|
||||||
|
|
||||||
#. To examine the value of ``ret``, the command ``p`` or ``print``
|
#. To examine the value of ``ret``, the command ``p`` or ``print``
|
||||||
can be used.
|
can be used.
|
||||||
|
@ -234,48 +256,26 @@ for its implementation as a Twister test.
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
(gdb) p ret
|
(gdb) p ret
|
||||||
$1 = 0x11318c
|
$1 = 1273788
|
||||||
|
|
||||||
Since ``ret`` has not been assigned a value yet, what it contains is
|
Since ``ret`` has not been initialized, it contains some random value.
|
||||||
simply a random value.
|
|
||||||
|
|
||||||
#. If step (``s`` or ``step``) is used here, it will continue execution
|
#. If step (``s`` or ``step``) is used here, it will continue execution
|
||||||
until :c:func:`printk` is reached, thus skipping the interior of
|
skipping the interior of :c:func:`test`.
|
||||||
:c:func:`test`. To examine code execution inside :c:func:`test`,
|
To examine code execution inside :c:func:`test`,
|
||||||
a breakpoint can be set for :c:func:`test`, or simply using
|
a breakpoint can be set for :c:func:`test`, or simply using
|
||||||
``si`` (or ``stepi``) to execute one machine instruction, where it has
|
``si`` (or ``stepi``) to execute one machine instruction, where it has
|
||||||
the side effect of going into the function.
|
the side effect of going into the function. The GDB command ``finish``
|
||||||
|
can be used to continue execution without intervention until the function
|
||||||
.. code-block:: text
|
returns.
|
||||||
|
|
||||||
(gdb) si
|
|
||||||
test () at <ZEPHYR_BASE>/samples/subsys/debug/gdbstub/src/main.c:13
|
|
||||||
13 {
|
|
||||||
(gdb) list
|
|
||||||
8 #include <zephyr/sys/printk.h>
|
|
||||||
9
|
|
||||||
10 #define STACKSIZE 512
|
|
||||||
11
|
|
||||||
12 static int test(void)
|
|
||||||
13 {
|
|
||||||
14 int a;
|
|
||||||
15 int b;
|
|
||||||
16
|
|
||||||
17 a = 10;
|
|
||||||
|
|
||||||
#. Here, ``step`` can be used to go through all code inside :c:func:`test`
|
|
||||||
until it returns. Or the command ``finish`` can be used to continue
|
|
||||||
execution without intervention until the function returns.
|
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
(gdb) finish
|
(gdb) finish
|
||||||
Run till exit from #0 test () at <ZEPHYR_BASE>/samples/subsys/debug/gdbstub/src/main.c:13
|
Run till exit from #0 test () at <ZEPHYR_BASE>/tests/subsys/debug/gdbstub/src/main.c:17
|
||||||
0x001005ae in main () at <ZEPHYR_BASE>/samples/subsys/debug/gdbstub/src/main.c:32
|
0x00100667 in main () at <ZEPHYR_BASE>/tests/subsys/debug/gdbstub/src/main.c:28
|
||||||
32 ret = test();
|
28 ret = test();
|
||||||
Value returned is $2 = 0x1e
|
Value returned is $2 = 30
|
||||||
|
|
||||||
And now, execution is back to :c:func:`main`.
|
|
||||||
|
|
||||||
#. Examine ``ret`` again which should have the return value from
|
#. Examine ``ret`` again which should have the return value from
|
||||||
:c:func:`test`. Sometimes, the assignment is not done until another
|
:c:func:`test`. Sometimes, the assignment is not done until another
|
||||||
|
@ -287,13 +287,16 @@ for its implementation as a Twister test.
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
(gdb) p ret
|
(gdb) p ret
|
||||||
$3 = 0x11318c
|
$3 = 1273788
|
||||||
(gdb) s
|
(gdb) step
|
||||||
33 printk("%d\n", ret);
|
29 printk("ret=%d\n", ret);
|
||||||
(gdb) p ret
|
(gdb) p ret
|
||||||
$4 = 0x1e
|
$4 = 30
|
||||||
|
|
||||||
#. If ``continue`` is issued here, code execution will continue indefinitely
|
#. If ``continue`` is issued here, code execution will continue indefinitely
|
||||||
as there are no breakpoints to further stop execution. Breaking execution
|
as there are no breakpoints to further stop execution. Breaking execution
|
||||||
in GDB via Ctrl-C does not currently work as the GDB stub does not
|
in GDB via :kbd:`Ctrl-C` does not currently work as the Zephyr gdbstub does
|
||||||
support this functionality (yet).
|
not support this functionality yet. Switch to the first console with QEMU
|
||||||
|
running the Zephyr image and stop it manually with :kbd:`Ctrl+a x`.
|
||||||
|
When the same test is executed by Twister, it automatically takes care of
|
||||||
|
stopping the QEMU instance.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue