summaryrefslogtreecommitdiff
path: root/doc/develop/gdb.rst
blob: 79510ee94d3ce130174d9b944df0a4e4d8a19da9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
.. SPDX-License-Identifier: GPL-2.0+
.. Copyright (c) 2024 Alexander Dahl

Debugging U-Boot with GDB
=========================

Using a JTAG adapter it is possible to debug a running U-Boot with GDB.
A common way is to connect a debug adapter to the JTAG connector of your
board, run a GDB server, connect GDB to the GDB server, and use GDB as usual.

Similarly, QEMU can provide a GDB server.

Preparing build
---------------

Building U-Boot with reduced optimization (-Og) and without link time
optimization is recommended for easier debugging::

    CONFIG_CC_OPTIMIZE_FOR_DEBUG=y
    CONFIG_LTO=n

Otherwise build, install, and run U-Boot as usual.

Using OpenOCD as GDB server
---------------------------

`OpenOCD <https://openocd.org/>`_ is an open-source tool supporting hardware
debug probes, and providing a GDB server. It is readily available in major Linux
distributions or you can build it from source.

Here is example of starting OpenOCD on Debian using a J-Link adapter and a
board with an AT91 SAMA5D2 SoC:

.. code-block:: console

    $ openocd -f interface/jlink.cfg -f target/at91sama5d2.cfg -c 'adapter speed 4000'
    Open On-Chip Debugger 0.12.0
    Licensed under GNU GPL v2
    For bug reports, read
            http://openocd.org/doc/doxygen/bugs.html
    Info : auto-selecting first available session transport "jtag". To override use 'transport select <transport>'.
    adapter speed: 4000 kHz

    Info : Listening on port 6666 for tcl connections
    Info : Listening on port 4444 for telnet connections
    Info : J-Link V10 compiled Jan 30 2023 11:28:07
    Info : Hardware version: 10.10
    Info : VTarget = 3.244 V
    Info : clock speed 4000 kHz
    Info : JTAG tap: at91sama5d2.cpu tap/device found: 0x5ba00477 (mfg: 0x23b (ARM Ltd), part: 0xba00, ver: 0x5)
    Info : at91sama5d2.cpu_a5.0: hardware has 3 breakpoints, 2 watchpoints
    Info : at91sama5d2.cpu_a5.0: MPIDR level2 0, cluster 0, core 0, mono core, no SMT
    Info : starting gdb server for at91sama5d2.cpu_a5.0 on 3333
    Info : Listening on port 3333 for gdb connections

Notice that OpenOCD is listening on port 3333 for GDB connections.

Using QEMU as GDB server
------------------------

When running U-Boot on QEMU you can used the '-gdb' parameter to provide a
GDB server:

     qemu-system-riscv64 -M virt -nographic -gdb tcp::3333 -kernel u-boot

Running a GDB session
----------------------

You need a GDB suited for your target. This can be the GDB coming with your
toolchain or *gdb-multiarch* available in your Linux distribution.

.. prompt:: bash $

    gdb-multiarch u-boot

In the above command-line *u-boot* is the U-boot binary in your build
directory. You may need to adjust the path when calling GDB.

Connect to the GDB server like this:

.. code-block:: console

    (gdb) target extended-remote :3333
    Remote debugging using :3333
    0x27fa9ac6 in ?? ()
    (gdb)

This is fine for debugging before U-Boot relocates itself.

For debugging U-Boot after relocation you need to indicate the relocation
address to GDB. You can retrieve the relocation address from the U-Boot shell
with the command *bdinfo*:

.. code-block:: console

    U-Boot> bdinfo
    boot_params = 0x20000100
    DRAM bank   = 0x00000000
    -> start    = 0x20000000
    -> size     = 0x08000000
    flashstart  = 0x00000000
    flashsize   = 0x00000000
    flashoffset = 0x00000000
    baudrate    = 115200 bps
    relocaddr   = 0x27f7a000
    reloc off   = 0x0607a000
    Build       = 32-bit
    current eth = ethernet@f8008000
    ethaddr     = 00:50:c2:31:58:d4
    IP addr     = <NULL>
    fdt_blob    = 0x27b36060
    new_fdt     = 0x27b36060
    fdt_size    = 0x00003e40
    lmb_dump_all:
     memory.cnt = 0x1 / max = 0x10
     memory[0]      [0x20000000-0x27ffffff], 0x08000000 bytes flags: 0
     reserved.cnt = 0x1 / max = 0x10
     reserved[0]    [0x27b31d00-0x27ffffff], 0x004ce300 bytes flags: 0
    devicetree  = separate
    arch_number = 0x00000000
    TLB addr    = 0x27ff0000
    irq_sp      = 0x27b36050
    sp start    = 0x27b36040
    Early malloc usage: cd8 / 2000

Look out for the line starting with *relocaddr* which has the address
you need, ``0x27f7a000`` in this case.

On most architectures (not sandbox, x86, Xtensa) the global data pointer is
stored in a fixed register:

============ ========
Architecture Register
============ ========
arc          r25
arm          r9
arm64        x18
m68k         d7
microblaze   r31
mips         k0
nios2        gp
powerpc      r2
riscv        gp
sh           r13
============ ========

On these architectures the relocation address can be determined by
dereferencing the global data pointer stored in register, *r9* in the example:

.. code-block:: console

     (gdb) p/x (*(struct global_data*)$r9)->relocaddr
     $1 = 0x27f7a000

In the GDB shell discard the previously loaded symbol file and add it once
again, with the relocation address like this:

.. code-block:: console

    (gdb) symbol-file
    Discard symbol table from `/home/adahl/build/u-boot/v2024.04.x/u-boot'? (y or n) y
    No symbol file now.
    (gdb) add-symbol-file u-boot 0x27f7a000
    add symbol table from file "u-boot" at
            .text_addr = 0x27f7a000
    (y or n) y
    Reading symbols from u-boot...
    (gdb)

You can now use GDB as usual, setting breakpoints, printing backtraces,
inspecting variables, stepping through the code, etc.