Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1#
2# gdb helper commands and functions for Linux kernel debugging
3#
4# common utilities
5#
6# Copyright (c) Siemens AG, 2011-2013
7#
8# Authors:
9# Jan Kiszka <jan.kiszka@siemens.com>
10#
11# This work is licensed under the terms of the GNU GPL version 2.
12#
13
14import contextlib
15import dataclasses
16import re
17import typing
18
19import gdb
20
21
22class CachedType:
23 def __init__(self, name):
24 self._type = None
25 self._name = name
26
27 def _new_objfile_handler(self, event):
28 self._type = None
29 gdb.events.new_objfile.disconnect(self._new_objfile_handler)
30
31 def get_type(self):
32 if self._type is None:
33 self._type = gdb.lookup_type(self._name)
34 if self._type is None:
35 raise gdb.GdbError(
36 "cannot resolve type '{0}'".format(self._name))
37 if hasattr(gdb, 'events') and hasattr(gdb.events, 'new_objfile'):
38 gdb.events.new_objfile.connect(self._new_objfile_handler)
39 return self._type
40
41
42long_type = CachedType("long")
43ulong_type = CachedType("unsigned long")
44uint_type = CachedType("unsigned int")
45atomic_long_type = CachedType("atomic_long_t")
46size_t_type = CachedType("size_t")
47struct_page_type = CachedType("struct page")
48
49def get_uint_type():
50 global uint_type
51 return uint_type.get_type()
52
53def get_page_type():
54 global struct_page_type
55 return struct_page_type.get_type()
56
57def get_long_type():
58 global long_type
59 return long_type.get_type()
60
61def get_ulong_type():
62 global ulong_type
63 return ulong_type.get_type()
64
65def get_size_t_type():
66 global size_t_type
67 return size_t_type.get_type()
68
69def offset_of(typeobj, field):
70 element = gdb.Value(0).cast(typeobj)
71 return int(str(element[field].address).split()[0], 16)
72
73
74def container_of(ptr, typeobj, member):
75 return (ptr.cast(get_long_type()) -
76 offset_of(typeobj, member)).cast(typeobj)
77
78
79class ContainerOf(gdb.Function):
80 """Return pointer to containing data structure.
81
82$container_of(PTR, "TYPE", "ELEMENT"): Given PTR, return a pointer to the
83data structure of the type TYPE in which PTR is the address of ELEMENT.
84Note that TYPE and ELEMENT have to be quoted as strings."""
85
86 def __init__(self):
87 super(ContainerOf, self).__init__("container_of")
88
89 def invoke(self, ptr, typename, elementname):
90 return container_of(ptr, gdb.lookup_type(typename.string()).pointer(),
91 elementname.string())
92
93
94ContainerOf()
95
96
97BIG_ENDIAN = 0
98LITTLE_ENDIAN = 1
99target_endianness = None
100
101
102def get_target_endianness():
103 global target_endianness
104 if target_endianness is None:
105 endian = gdb.execute("show endian", to_string=True)
106 if "little endian" in endian:
107 target_endianness = LITTLE_ENDIAN
108 elif "big endian" in endian:
109 target_endianness = BIG_ENDIAN
110 else:
111 raise gdb.GdbError("unknown endianness '{0}'".format(str(endian)))
112 return target_endianness
113
114
115def read_memoryview(inf, start, length):
116 m = inf.read_memory(start, length)
117 if type(m) is memoryview:
118 return m
119 return memoryview(m)
120
121
122def read_u16(buffer, offset):
123 buffer_val = buffer[offset:offset + 2]
124 value = [0, 0]
125
126 if type(buffer_val[0]) is str:
127 value[0] = ord(buffer_val[0])
128 value[1] = ord(buffer_val[1])
129 else:
130 value[0] = buffer_val[0]
131 value[1] = buffer_val[1]
132
133 if get_target_endianness() == LITTLE_ENDIAN:
134 return value[0] + (value[1] << 8)
135 else:
136 return value[1] + (value[0] << 8)
137
138
139def read_u32(buffer, offset):
140 if get_target_endianness() == LITTLE_ENDIAN:
141 return read_u16(buffer, offset) + (read_u16(buffer, offset + 2) << 16)
142 else:
143 return read_u16(buffer, offset + 2) + (read_u16(buffer, offset) << 16)
144
145
146def read_u64(buffer, offset):
147 if get_target_endianness() == LITTLE_ENDIAN:
148 return read_u32(buffer, offset) + (read_u32(buffer, offset + 4) << 32)
149 else:
150 return read_u32(buffer, offset + 4) + (read_u32(buffer, offset) << 32)
151
152
153def read_ulong(buffer, offset):
154 if get_long_type().sizeof == 8:
155 return read_u64(buffer, offset)
156 else:
157 return read_u32(buffer, offset)
158
159atomic_long_counter_offset = atomic_long_type.get_type()['counter'].bitpos
160atomic_long_counter_sizeof = atomic_long_type.get_type()['counter'].type.sizeof
161
162def read_atomic_long(buffer, offset):
163 global atomic_long_counter_offset
164 global atomic_long_counter_sizeof
165
166 if atomic_long_counter_sizeof == 8:
167 return read_u64(buffer, offset + atomic_long_counter_offset)
168 else:
169 return read_u32(buffer, offset + atomic_long_counter_offset)
170
171target_arch = None
172
173
174def is_target_arch(arch):
175 if hasattr(gdb.Frame, 'architecture'):
176 return arch in gdb.newest_frame().architecture().name()
177 else:
178 global target_arch
179 if target_arch is None:
180 target_arch = gdb.execute("show architecture", to_string=True)
181 return arch in target_arch
182
183
184GDBSERVER_QEMU = 0
185GDBSERVER_KGDB = 1
186gdbserver_type = None
187
188
189def get_gdbserver_type():
190 def exit_handler(event):
191 global gdbserver_type
192 gdbserver_type = None
193 gdb.events.exited.disconnect(exit_handler)
194
195 def probe_qemu():
196 try:
197 return gdb.execute("monitor info version", to_string=True) != ""
198 except gdb.error:
199 return False
200
201 def probe_kgdb():
202 try:
203 thread_info = gdb.execute("info thread 1", to_string=True)
204 return "shadowCPU" in thread_info
205 except gdb.error:
206 return False
207
208 global gdbserver_type
209 if gdbserver_type is None:
210 if probe_qemu():
211 gdbserver_type = GDBSERVER_QEMU
212 elif probe_kgdb():
213 gdbserver_type = GDBSERVER_KGDB
214 if gdbserver_type is not None and hasattr(gdb, 'events'):
215 gdb.events.exited.connect(exit_handler)
216 return gdbserver_type
217
218
219def gdb_eval_or_none(expresssion):
220 try:
221 return gdb.parse_and_eval(expresssion)
222 except gdb.error:
223 return None
224
225
226@contextlib.contextmanager
227def qemu_phy_mem_mode():
228 connection = gdb.selected_inferior().connection
229 orig = connection.send_packet("qqemu.PhyMemMode")
230 if orig not in b"01":
231 raise gdb.error("Unexpected qemu.PhyMemMode")
232 orig = orig.decode()
233 if connection.send_packet("Qqemu.PhyMemMode:1") != b"OK":
234 raise gdb.error("Failed to set qemu.PhyMemMode")
235 try:
236 yield
237 finally:
238 if connection.send_packet("Qqemu.PhyMemMode:" + orig) != b"OK":
239 raise gdb.error("Failed to restore qemu.PhyMemMode")
240
241
242@dataclasses.dataclass
243class VmCore:
244 kerneloffset: typing.Optional[int]
245
246
247def parse_vmcore(s):
248 match = re.search(r"KERNELOFFSET=([0-9a-f]+)", s)
249 if match is None:
250 kerneloffset = None
251 else:
252 kerneloffset = int(match.group(1), 16)
253 return VmCore(kerneloffset=kerneloffset)
254
255
256def get_vmlinux():
257 vmlinux = 'vmlinux'
258 for obj in gdb.objfiles():
259 if (obj.filename.endswith('vmlinux') or
260 obj.filename.endswith('vmlinux.debug')):
261 vmlinux = obj.filename
262 return vmlinux
263
264
265@contextlib.contextmanager
266def pagination_off():
267 show_pagination = gdb.execute("show pagination", to_string=True)
268 pagination = show_pagination.endswith("on.\n")
269 gdb.execute("set pagination off")
270 try:
271 yield
272 finally:
273 gdb.execute("set pagination %s" % ("on" if pagination else "off"))