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.
|