xref: /linux/scripts/gdb/linux/utils.py (revision 7d4e49a77d9930c69751b9192448fda6ff9100f1)
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"))
274