aboutsummaryrefslogtreecommitdiff
path: root/docs/system/gdb.rst
blob: 144d083df315ae54e6616aa1703fbb2ede86c1f9 (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
.. _GDB usage:

GDB usage
---------

QEMU supports working with gdb via gdb's remote-connection facility
(the "gdbstub"). This allows you to debug guest code in the same
way that you might with a low-level debug facility like JTAG
on real hardware. You can stop and start the virtual machine,
examine state like registers and memory, and set breakpoints and
watchpoints.

In order to use gdb, launch QEMU with the ``-s`` and ``-S`` options.
The ``-s`` option will make QEMU listen for an incoming connection
from gdb on TCP port 1234, and ``-S`` will make QEMU not start the
guest until you tell it to from gdb. (If you want to specify which
TCP port to use or to use something other than TCP for the gdbstub
connection, use the ``-gdb dev`` option instead of ``-s``.)

.. parsed-literal::

   |qemu_system| -s -S -kernel bzImage -hda rootdisk.img -append "root=/dev/hda"

QEMU will launch but will silently wait for gdb to connect.

Then launch gdb on the 'vmlinux' executable::

   > gdb vmlinux

In gdb, connect to QEMU::

   (gdb) target remote localhost:1234

Then you can use gdb normally. For example, type 'c' to launch the
kernel::

   (gdb) c

Here are some useful tips in order to use gdb on system code:

1. Use ``info reg`` to display all the CPU registers.

2. Use ``x/10i $eip`` to display the code at the PC position.

3. Use ``set architecture i8086`` to dump 16 bit code. Then use
   ``x/10i $cs*16+$eip`` to dump the code at the PC position.

Debugging multicore machines
============================

GDB's abstraction for debugging targets with multiple possible
parallel flows of execution is a two layer one: it supports multiple
"inferiors", each of which can have multiple "threads". When the QEMU
machine has more than one CPU, QEMU exposes each CPU cluster as a
separate "inferior", where each CPU within the cluster is a separate
"thread". Most QEMU machine types have identical CPUs, so there is a
single cluster which has all the CPUs in it.  A few machine types are
heterogenous and have multiple clusters: for example the ``sifive_u``
machine has a cluster with one E51 core and a second cluster with four
U54 cores. Here the E51 is the only thread in the first inferior, and
the U54 cores are all threads in the second inferior.

When you connect gdb to the gdbstub, it will automatically
connect to the first inferior; you can display the CPUs in this
cluster using the gdb ``info thread`` command, and switch between
them using gdb's usual thread-management commands.

For multi-cluster machines, unfortunately gdb does not by default
handle multiple inferiors, and so you have to explicitly connect
to them. First, you must connect with the ``extended-remote``
protocol, not ``remote``::

    (gdb) target extended-remote localhost:1234

Once connected, gdb will have a single inferior, for the
first cluster. You need to create inferiors for the other
clusters and attach to them, like this::

  (gdb) add-inferior
  Added inferior 2
  (gdb) inferior 2
  [Switching to inferior 2 [<null>] (<noexec>)]
  (gdb) attach 2
  Attaching to process 2
  warning: No executable has been specified and target does not support
  determining executable automatically.  Try using the "file" command.
  0x00000000 in ?? ()

Once you've done this, ``info threads`` will show CPUs in
all the clusters you have attached to::

  (gdb) info threads
    Id   Target Id         Frame
    1.1  Thread 1.1 (cortex-m33-arm-cpu cpu [running]) 0x00000000 in ?? ()
  * 2.1  Thread 2.2 (cortex-m33-arm-cpu cpu [halted ]) 0x00000000 in ?? ()

You probably also want to set gdb to ``schedule-multiple`` mode,
so that when you tell gdb to ``continue`` it resumes all CPUs,
not just those in the cluster you are currently working on::

  (gdb) set schedule-multiple on

Advanced debugging options
==========================

Changing single-stepping behaviour
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The default single stepping behavior is step with the IRQs and timer
service routines off. It is set this way because when gdb executes a
single step it expects to advance beyond the current instruction. With
the IRQs and timer service routines on, a single step might jump into
the one of the interrupt or exception vectors instead of executing the
current instruction. This means you may hit the same breakpoint a number
of times before executing the instruction gdb wants to have executed.
Because there are rare circumstances where you want to single step into
an interrupt vector the behavior can be controlled from GDB. There are
three commands you can query and set the single step behavior:

``maintenance packet qqemu.sstepbits``
   This will display the MASK bits used to control the single stepping
   IE:

   ::

      (gdb) maintenance packet qqemu.sstepbits
      sending: "qqemu.sstepbits"
      received: "ENABLE=1,NOIRQ=2,NOTIMER=4"

``maintenance packet qqemu.sstep``
   This will display the current value of the mask used when single
   stepping IE:

   ::

      (gdb) maintenance packet qqemu.sstep
      sending: "qqemu.sstep"
      received: "0x7"

``maintenance packet Qqemu.sstep=HEX_VALUE``
   This will change the single step mask, so if wanted to enable IRQs on
   the single step, but not timers, you would use:

   ::

      (gdb) maintenance packet Qqemu.sstep=0x5
      sending: "qemu.sstep=0x5"
      received: "OK"

Examining physical memory
^^^^^^^^^^^^^^^^^^^^^^^^^

Another feature that QEMU gdbstub provides is to toggle the memory GDB
works with, by default GDB will show the current process memory respecting
the virtual address translation.

If you want to examine/change the physical memory you can set the gdbstub
to work with the physical memory rather with the virtual one.

The memory mode can be checked by sending the following command:

``maintenance packet qqemu.PhyMemMode``
    This will return either 0 or 1, 1 indicates you are currently in the
    physical memory mode.

``maintenance packet Qqemu.PhyMemMode:1``
    This will change the memory mode to physical memory.

``maintenance packet Qqemu.PhyMemMode:0``
    This will change it back to normal memory mode.