doc: gdbstub: add a simple example
Adds a simple example to demonstrate how to use GDB stub. Fixes #39415 Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
parent
183328a4fb
commit
38c42f69d2
1 changed files with 217 additions and 0 deletions
|
@ -3,6 +3,10 @@
|
||||||
GDB stub
|
GDB stub
|
||||||
########
|
########
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:local:
|
||||||
|
:depth: 2
|
||||||
|
|
||||||
Overview
|
Overview
|
||||||
********
|
********
|
||||||
|
|
||||||
|
@ -80,3 +84,216 @@ Using Serial Backend
|
||||||
target remote /dev/ttyUSB1
|
target remote /dev/ttyUSB1
|
||||||
|
|
||||||
#. GDB commands can be used to start debugging.
|
#. GDB commands can be used to start debugging.
|
||||||
|
|
||||||
|
Example
|
||||||
|
*******
|
||||||
|
|
||||||
|
This is an example using ``samples/subsys/debug/gdbstub`` to demonstrate
|
||||||
|
how GDB stub works.
|
||||||
|
|
||||||
|
#. Open two terminal windows.
|
||||||
|
|
||||||
|
#. On the first terminal, build and run the sample:
|
||||||
|
|
||||||
|
.. zephyr-app-commands::
|
||||||
|
:zephyr-app: samples/subsys/debug/gdbstub
|
||||||
|
:host-os: unix
|
||||||
|
:board: qemu_x86
|
||||||
|
:goals: build run
|
||||||
|
|
||||||
|
#. On the second terminal, start GDB:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
<SDK install directory>/x86_64-zephyr-elf/bin/x86_64-zephyr-elf-gdb
|
||||||
|
|
||||||
|
#. Tell GDB where to look for the built ELF file:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
(gdb) file <build directory>/zephyr/zephyr.elf
|
||||||
|
|
||||||
|
Response from GDB:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
Reading symbols from <build directory>/zephyr/zephyr.elf...
|
||||||
|
|
||||||
|
#. Tell GDB to connect to the server:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
(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:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
Remote debugging using :5678
|
||||||
|
arch_gdb_init () at <ZEPHYR_BASE>/arch/x86/core/ia32/gdbstub.c:232
|
||||||
|
232 }
|
||||||
|
|
||||||
|
GDB also shows where the code execution is stopped. In this case,
|
||||||
|
it is at :file:`arch/x86/core/ia32/gdbstub.c`, line 232.
|
||||||
|
|
||||||
|
#. Use command ``bt`` or ``backtrace`` to show the backtrace of stack frames.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
(gdb) bt
|
||||||
|
#0 arch_gdb_init () at <ZEPHYR_BASE>/arch/x86/core/ia32/gdbstub.c:232
|
||||||
|
#1 0x00105068 in gdb_init (arg=0x0) at <ZEPHYR_BASE>/subsys/debug/gdbstub.c:833
|
||||||
|
#2 0x00109d6f in z_sys_init_run_level (level=0x1) at <ZEPHYR_BASE>/kernel/device.c:72
|
||||||
|
#3 0x0010a40b in z_cstart () at <ZEPHYR_BASE>/kernel/init.c:423
|
||||||
|
#4 0x00105383 in z_x86_prep_c (arg=0x9500) at <ZEPHYR_BASE>/arch/x86/core/prep_c.c:58
|
||||||
|
#5 0x001000a9 in __csSet () at <ZEPHYR_BASE>/arch/x86/core/ia32/crt0.S:273
|
||||||
|
|
||||||
|
#. Use command ``list`` to show the source code and surroundings where
|
||||||
|
code execution is stopped.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
(gdb) list
|
||||||
|
227 }
|
||||||
|
228
|
||||||
|
229 void arch_gdb_init(void)
|
||||||
|
230 {
|
||||||
|
231 __asm__ volatile ("int3");
|
||||||
|
232 }
|
||||||
|
233
|
||||||
|
234 /* Hook current IDT. */
|
||||||
|
235 _EXCEPTION_CONNECT_NOCODE(z_gdb_debug_isr, IV_DEBUG, 3);
|
||||||
|
236 _EXCEPTION_CONNECT_NOCODE(z_gdb_break_isr, IV_BREAKPOINT, 3);
|
||||||
|
|
||||||
|
#. 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`
|
||||||
|
and is continuing in :c:func:`gdb_init`.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
(gdb) s
|
||||||
|
gdb_init (arg=0x0) at /home/dleung5/zephyr/rtos/zephyr/subsys/debug/gdbstub.c:834
|
||||||
|
834 return 0;
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
(gdb) list
|
||||||
|
829 LOG_ERR("Could not initialize gdbstub backend.");
|
||||||
|
830 return -1;
|
||||||
|
831 }
|
||||||
|
832
|
||||||
|
833 arch_gdb_init();
|
||||||
|
834 return 0;
|
||||||
|
835 }
|
||||||
|
836
|
||||||
|
837 #ifdef CONFIG_XTENSA
|
||||||
|
838 /*
|
||||||
|
|
||||||
|
#. Use command ``br`` or ``break`` to setup a breakpoint. This example
|
||||||
|
sets up a breakpoint at :c:func:`main`, and let code execution continue
|
||||||
|
without any intervention using command ``c`` (or ``continue``).
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
(gdb) break main
|
||||||
|
Breakpoint 1 at 0x1005a9: file <ZEPHYR_BASE>/samples/subsys/debug/gdbstub/src/main.c, line 32.
|
||||||
|
(gdb) continue
|
||||||
|
Continuing.
|
||||||
|
|
||||||
|
Once code execution reaches :c:func:`main`, execution will be stopped
|
||||||
|
and GDB prompt returns.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
Breakpoint 1, main () at <ZEPHYR_BASE>/samples/subsys/debug/gdbstub/src/main.c:32
|
||||||
|
32 ret = test();
|
||||||
|
|
||||||
|
Now GDB is waiting at the beginning of :c:func:`main`:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
(gdb) list
|
||||||
|
27
|
||||||
|
28 void main(void)
|
||||||
|
29 {
|
||||||
|
30 int ret;
|
||||||
|
31
|
||||||
|
32 ret = test();
|
||||||
|
33 printk("%d\n", ret);
|
||||||
|
34 }
|
||||||
|
35
|
||||||
|
36 K_THREAD_DEFINE(thread, STACKSIZE, thread_entry, NULL, NULL, NULL,
|
||||||
|
|
||||||
|
#. To examine the value of ``ret``, the command ``p`` or ``print``
|
||||||
|
can be used.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
(gdb) p ret
|
||||||
|
$1 = 0x11318c
|
||||||
|
|
||||||
|
Since ``ret`` has not been assigned a value yet, what it contains is
|
||||||
|
simply a random value.
|
||||||
|
|
||||||
|
#. If step (``s`` or ``step``) is used here, it will continue execution
|
||||||
|
until :c:func:`printk` is reached, thus skipping the interior of
|
||||||
|
:c:func:`test`. To examine code execution inside :c:func:`test`,
|
||||||
|
a breakpoint can be set for :c:func:`test`, or simply using
|
||||||
|
``si`` (or ``stepi``) to execute one machine instruction, where it has
|
||||||
|
the side effect of going into the function.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
(gdb) si
|
||||||
|
test () at <ZEPHYR_BASE>/samples/subsys/debug/gdbstub/src/main.c:13
|
||||||
|
13 {
|
||||||
|
(gdb) list
|
||||||
|
8 #include <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
|
||||||
|
|
||||||
|
(gdb) finish
|
||||||
|
Run till exit from #0 test () at <ZEPHYR_BASE>/samples/subsys/debug/gdbstub/src/main.c:13
|
||||||
|
0x001005ae in main () at <ZEPHYR_BASE>/samples/subsys/debug/gdbstub/src/main.c:32
|
||||||
|
32 ret = test();
|
||||||
|
Value returned is $2 = 0x1e
|
||||||
|
|
||||||
|
And now, execution is back to :c:func:`main`.
|
||||||
|
|
||||||
|
#. Examine ``ret`` again which should have the return value from
|
||||||
|
:c:func:`test`. Sometimes, the assignment is not done until another
|
||||||
|
``step`` is issued, as in this case. This is due to the assginment
|
||||||
|
code is done after retruning from function. The assignment code is
|
||||||
|
generated by the toolchain as machine instructions which are not
|
||||||
|
visible when viewing the corresponding C source file.
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
(gdb) p ret
|
||||||
|
$3 = 0x11318c
|
||||||
|
(gdb) s
|
||||||
|
33 printk("%d\n", ret);
|
||||||
|
(gdb) p ret
|
||||||
|
$4 = 0x1e
|
||||||
|
|
||||||
|
#. If ``continue`` is issued here, code execution will continue indefinitely
|
||||||
|
as there are no breakpoints to further stop exection. Breaking execution
|
||||||
|
in GDB via Ctrl-C does not currently work as the GDB stub does not
|
||||||
|
support this functionality (yet).
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue