xref: /linux-6.15/scripts/gdb/linux/utils.py (revision 28939c3e)
12b514827SJan Kiszka#
22b514827SJan Kiszka# gdb helper commands and functions for Linux kernel debugging
32b514827SJan Kiszka#
42b514827SJan Kiszka#  common utilities
52b514827SJan Kiszka#
62b514827SJan Kiszka# Copyright (c) Siemens AG, 2011-2013
72b514827SJan Kiszka#
82b514827SJan Kiszka# Authors:
92b514827SJan Kiszka#  Jan Kiszka <[email protected]>
102b514827SJan Kiszka#
112b514827SJan Kiszka# This work is licensed under the terms of the GNU GPL version 2.
122b514827SJan Kiszka#
132b514827SJan Kiszka
14*28939c3eSIlya Leoshkevichimport contextlib
15*28939c3eSIlya Leoshkevichimport dataclasses
16*28939c3eSIlya Leoshkevichimport re
17*28939c3eSIlya Leoshkevichimport typing
18*28939c3eSIlya Leoshkevich
192b514827SJan Kiszkaimport gdb
202b514827SJan Kiszka
212b514827SJan Kiszka
222b514827SJan Kiszkaclass CachedType:
232b514827SJan Kiszka    def __init__(self, name):
242b514827SJan Kiszka        self._type = None
252b514827SJan Kiszka        self._name = name
262b514827SJan Kiszka
272b514827SJan Kiszka    def _new_objfile_handler(self, event):
282b514827SJan Kiszka        self._type = None
292b514827SJan Kiszka        gdb.events.new_objfile.disconnect(self._new_objfile_handler)
302b514827SJan Kiszka
312b514827SJan Kiszka    def get_type(self):
322b514827SJan Kiszka        if self._type is None:
332b514827SJan Kiszka            self._type = gdb.lookup_type(self._name)
342b514827SJan Kiszka            if self._type is None:
352b514827SJan Kiszka                raise gdb.GdbError(
362b514827SJan Kiszka                    "cannot resolve type '{0}'".format(self._name))
372b514827SJan Kiszka            if hasattr(gdb, 'events') and hasattr(gdb.events, 'new_objfile'):
382b514827SJan Kiszka                gdb.events.new_objfile.connect(self._new_objfile_handler)
392b514827SJan Kiszka        return self._type
40b0fecd8cSJan Kiszka
41b0fecd8cSJan Kiszka
42b0fecd8cSJan Kiszkalong_type = CachedType("long")
434d040cbcSKuan-Ying Leeulong_type = CachedType("unsigned long")
444d040cbcSKuan-Ying Leeuint_type = CachedType("unsigned int")
45e3c8d33eSAntonio Borneoatomic_long_type = CachedType("atomic_long_t")
464d040cbcSKuan-Ying Leesize_t_type = CachedType("size_t")
474d040cbcSKuan-Ying Leestruct_page_type = CachedType("struct page")
484d040cbcSKuan-Ying Lee
494d040cbcSKuan-Ying Leedef get_uint_type():
504d040cbcSKuan-Ying Lee    global uint_type
514d040cbcSKuan-Ying Lee    return uint_type.get_type()
524d040cbcSKuan-Ying Lee
534d040cbcSKuan-Ying Leedef get_page_type():
544d040cbcSKuan-Ying Lee    global struct_page_type
554d040cbcSKuan-Ying Lee    return struct_page_type.get_type()
56b0fecd8cSJan Kiszka
57b0fecd8cSJan Kiszkadef get_long_type():
58b0fecd8cSJan Kiszka    global long_type
59b0fecd8cSJan Kiszka    return long_type.get_type()
60b0fecd8cSJan Kiszka
614d040cbcSKuan-Ying Leedef get_ulong_type():
624d040cbcSKuan-Ying Lee    global ulong_type
634d040cbcSKuan-Ying Lee    return ulong_type.get_type()
644d040cbcSKuan-Ying Lee
654d040cbcSKuan-Ying Leedef get_size_t_type():
664d040cbcSKuan-Ying Lee    global size_t_type
674d040cbcSKuan-Ying Lee    return size_t_type.get_type()
684d040cbcSKuan-Ying Lee
69b0fecd8cSJan Kiszkadef offset_of(typeobj, field):
70b0fecd8cSJan Kiszka    element = gdb.Value(0).cast(typeobj)
71b0fecd8cSJan Kiszka    return int(str(element[field].address).split()[0], 16)
72b0fecd8cSJan Kiszka
73b0fecd8cSJan Kiszka
74b0fecd8cSJan Kiszkadef container_of(ptr, typeobj, member):
75b0fecd8cSJan Kiszka    return (ptr.cast(get_long_type()) -
76b0fecd8cSJan Kiszka            offset_of(typeobj, member)).cast(typeobj)
77b0fecd8cSJan Kiszka
78b0fecd8cSJan Kiszka
79b0fecd8cSJan Kiszkaclass ContainerOf(gdb.Function):
80b0fecd8cSJan Kiszka    """Return pointer to containing data structure.
81b0fecd8cSJan Kiszka
82b0fecd8cSJan Kiszka$container_of(PTR, "TYPE", "ELEMENT"): Given PTR, return a pointer to the
83b0fecd8cSJan Kiszkadata structure of the type TYPE in which PTR is the address of ELEMENT.
84b0fecd8cSJan KiszkaNote that TYPE and ELEMENT have to be quoted as strings."""
85b0fecd8cSJan Kiszka
86b0fecd8cSJan Kiszka    def __init__(self):
87b0fecd8cSJan Kiszka        super(ContainerOf, self).__init__("container_of")
88b0fecd8cSJan Kiszka
89b0fecd8cSJan Kiszka    def invoke(self, ptr, typename, elementname):
90b0fecd8cSJan Kiszka        return container_of(ptr, gdb.lookup_type(typename.string()).pointer(),
91b0fecd8cSJan Kiszka                            elementname.string())
92b0fecd8cSJan Kiszka
93494dbe02SStephen Boyd
94b0fecd8cSJan KiszkaContainerOf()
957f994963SJan Kiszka
967f994963SJan Kiszka
977f994963SJan KiszkaBIG_ENDIAN = 0
987f994963SJan KiszkaLITTLE_ENDIAN = 1
997f994963SJan Kiszkatarget_endianness = None
1007f994963SJan Kiszka
1017f994963SJan Kiszka
1027f994963SJan Kiszkadef get_target_endianness():
1037f994963SJan Kiszka    global target_endianness
1047f994963SJan Kiszka    if target_endianness is None:
1057f994963SJan Kiszka        endian = gdb.execute("show endian", to_string=True)
1067f994963SJan Kiszka        if "little endian" in endian:
1077f994963SJan Kiszka            target_endianness = LITTLE_ENDIAN
1087f994963SJan Kiszka        elif "big endian" in endian:
1097f994963SJan Kiszka            target_endianness = BIG_ENDIAN
1107f994963SJan Kiszka        else:
111a2e73c48SThiébaud Weksteen            raise gdb.GdbError("unknown endianness '{0}'".format(str(endian)))
1127f994963SJan Kiszka    return target_endianness
11378e87817SJan Kiszka
11478e87817SJan Kiszka
115321958d9SDom Cotedef read_memoryview(inf, start, length):
1167362042fSPeng Liu    m = inf.read_memory(start, length)
1177362042fSPeng Liu    if type(m) is memoryview:
1187362042fSPeng Liu        return m
1197362042fSPeng Liu    return memoryview(m)
120321958d9SDom Cote
121321958d9SDom Cote
122ca210ba3SJoel Colledgedef read_u16(buffer, offset):
123ca210ba3SJoel Colledge    buffer_val = buffer[offset:offset + 2]
124321958d9SDom Cote    value = [0, 0]
125321958d9SDom Cote
126ca210ba3SJoel Colledge    if type(buffer_val[0]) is str:
127ca210ba3SJoel Colledge        value[0] = ord(buffer_val[0])
128ca210ba3SJoel Colledge        value[1] = ord(buffer_val[1])
12978e87817SJan Kiszka    else:
130ca210ba3SJoel Colledge        value[0] = buffer_val[0]
131ca210ba3SJoel Colledge        value[1] = buffer_val[1]
132321958d9SDom Cote
133321958d9SDom Cote    if get_target_endianness() == LITTLE_ENDIAN:
134321958d9SDom Cote        return value[0] + (value[1] << 8)
135321958d9SDom Cote    else:
136321958d9SDom Cote        return value[1] + (value[0] << 8)
13778e87817SJan Kiszka
13878e87817SJan Kiszka
139ca210ba3SJoel Colledgedef read_u32(buffer, offset):
14078e87817SJan Kiszka    if get_target_endianness() == LITTLE_ENDIAN:
141ca210ba3SJoel Colledge        return read_u16(buffer, offset) + (read_u16(buffer, offset + 2) << 16)
14278e87817SJan Kiszka    else:
143ca210ba3SJoel Colledge        return read_u16(buffer, offset + 2) + (read_u16(buffer, offset) << 16)
14478e87817SJan Kiszka
14578e87817SJan Kiszka
146ca210ba3SJoel Colledgedef read_u64(buffer, offset):
14778e87817SJan Kiszka    if get_target_endianness() == LITTLE_ENDIAN:
148ca210ba3SJoel Colledge        return read_u32(buffer, offset) + (read_u32(buffer, offset + 4) << 32)
14978e87817SJan Kiszka    else:
150ca210ba3SJoel Colledge        return read_u32(buffer, offset + 4) + (read_u32(buffer, offset) << 32)
151b24e2d21SJan Kiszka
152b24e2d21SJan Kiszka
1533e0d075cSJohn Ognessdef read_ulong(buffer, offset):
1543e0d075cSJohn Ogness    if get_long_type().sizeof == 8:
1553e0d075cSJohn Ogness        return read_u64(buffer, offset)
1563e0d075cSJohn Ogness    else:
1573e0d075cSJohn Ogness        return read_u32(buffer, offset)
1583e0d075cSJohn Ogness
159e3c8d33eSAntonio Borneoatomic_long_counter_offset = atomic_long_type.get_type()['counter'].bitpos
160e3c8d33eSAntonio Borneoatomic_long_counter_sizeof = atomic_long_type.get_type()['counter'].type.sizeof
161e3c8d33eSAntonio Borneo
162e3c8d33eSAntonio Borneodef read_atomic_long(buffer, offset):
163e3c8d33eSAntonio Borneo    global atomic_long_counter_offset
164e3c8d33eSAntonio Borneo    global atomic_long_counter_sizeof
165e3c8d33eSAntonio Borneo
166e3c8d33eSAntonio Borneo    if atomic_long_counter_sizeof == 8:
167e3c8d33eSAntonio Borneo        return read_u64(buffer, offset + atomic_long_counter_offset)
168e3c8d33eSAntonio Borneo    else:
169e3c8d33eSAntonio Borneo        return read_u32(buffer, offset + atomic_long_counter_offset)
1703e0d075cSJohn Ogness
171b24e2d21SJan Kiszkatarget_arch = None
172b24e2d21SJan Kiszka
173b24e2d21SJan Kiszka
174b24e2d21SJan Kiszkadef is_target_arch(arch):
175b24e2d21SJan Kiszka    if hasattr(gdb.Frame, 'architecture'):
176b24e2d21SJan Kiszka        return arch in gdb.newest_frame().architecture().name()
177b24e2d21SJan Kiszka    else:
178b24e2d21SJan Kiszka        global target_arch
179b24e2d21SJan Kiszka        if target_arch is None:
180b24e2d21SJan Kiszka            target_arch = gdb.execute("show architecture", to_string=True)
181b24e2d21SJan Kiszka        return arch in target_arch
182a4d86792SJan Kiszka
183a4d86792SJan Kiszka
184a4d86792SJan KiszkaGDBSERVER_QEMU = 0
185a4d86792SJan KiszkaGDBSERVER_KGDB = 1
186a4d86792SJan Kiszkagdbserver_type = None
187a4d86792SJan Kiszka
188a4d86792SJan Kiszka
189a4d86792SJan Kiszkadef get_gdbserver_type():
190a4d86792SJan Kiszka    def exit_handler(event):
191a4d86792SJan Kiszka        global gdbserver_type
192a4d86792SJan Kiszka        gdbserver_type = None
193a4d86792SJan Kiszka        gdb.events.exited.disconnect(exit_handler)
194a4d86792SJan Kiszka
195a4d86792SJan Kiszka    def probe_qemu():
196a4d86792SJan Kiszka        try:
197a4d86792SJan Kiszka            return gdb.execute("monitor info version", to_string=True) != ""
198494dbe02SStephen Boyd        except gdb.error:
199a4d86792SJan Kiszka            return False
200a4d86792SJan Kiszka
201a4d86792SJan Kiszka    def probe_kgdb():
202a4d86792SJan Kiszka        try:
203a4d86792SJan Kiszka            thread_info = gdb.execute("info thread 2", to_string=True)
204ec0b6d17SFlorian Rommel            return "shadowCPU" in thread_info
205494dbe02SStephen Boyd        except gdb.error:
206a4d86792SJan Kiszka            return False
207a4d86792SJan Kiszka
208a4d86792SJan Kiszka    global gdbserver_type
209a4d86792SJan Kiszka    if gdbserver_type is None:
210a4d86792SJan Kiszka        if probe_qemu():
211a4d86792SJan Kiszka            gdbserver_type = GDBSERVER_QEMU
212a4d86792SJan Kiszka        elif probe_kgdb():
213a4d86792SJan Kiszka            gdbserver_type = GDBSERVER_KGDB
2146ad18b73SThiébaud Weksteen        if gdbserver_type is not None and hasattr(gdb, 'events'):
215a4d86792SJan Kiszka            gdb.events.exited.connect(exit_handler)
216a4d86792SJan Kiszka    return gdbserver_type
217e78f3d70SKieran Bingham
218e78f3d70SKieran Bingham
219e78f3d70SKieran Binghamdef gdb_eval_or_none(expresssion):
220e78f3d70SKieran Bingham    try:
221e78f3d70SKieran Bingham        return gdb.parse_and_eval(expresssion)
222494dbe02SStephen Boyd    except gdb.error:
223e78f3d70SKieran Bingham        return None
224*28939c3eSIlya Leoshkevich
225*28939c3eSIlya Leoshkevich
226*28939c3eSIlya Leoshkevich@contextlib.contextmanager
227*28939c3eSIlya Leoshkevichdef qemu_phy_mem_mode():
228*28939c3eSIlya Leoshkevich    connection = gdb.selected_inferior().connection
229*28939c3eSIlya Leoshkevich    orig = connection.send_packet("qqemu.PhyMemMode")
230*28939c3eSIlya Leoshkevich    if orig not in b"01":
231*28939c3eSIlya Leoshkevich        raise gdb.error("Unexpected qemu.PhyMemMode")
232*28939c3eSIlya Leoshkevich    orig = orig.decode()
233*28939c3eSIlya Leoshkevich    if connection.send_packet("Qqemu.PhyMemMode:1") != b"OK":
234*28939c3eSIlya Leoshkevich        raise gdb.error("Failed to set qemu.PhyMemMode")
235*28939c3eSIlya Leoshkevich    try:
236*28939c3eSIlya Leoshkevich        yield
237*28939c3eSIlya Leoshkevich    finally:
238*28939c3eSIlya Leoshkevich        if connection.send_packet("Qqemu.PhyMemMode:" + orig) != b"OK":
239*28939c3eSIlya Leoshkevich            raise gdb.error("Failed to restore qemu.PhyMemMode")
240*28939c3eSIlya Leoshkevich
241*28939c3eSIlya Leoshkevich
242*28939c3eSIlya Leoshkevich@dataclasses.dataclass
243*28939c3eSIlya Leoshkevichclass VmCore:
244*28939c3eSIlya Leoshkevich    kerneloffset: typing.Optional[int]
245*28939c3eSIlya Leoshkevich
246*28939c3eSIlya Leoshkevich
247*28939c3eSIlya Leoshkevichdef parse_vmcore(s):
248*28939c3eSIlya Leoshkevich    match = re.search(r"KERNELOFFSET=([0-9a-f]+)", s)
249*28939c3eSIlya Leoshkevich    if match is None:
250*28939c3eSIlya Leoshkevich        kerneloffset = None
251*28939c3eSIlya Leoshkevich    else:
252*28939c3eSIlya Leoshkevich        kerneloffset = int(match.group(1), 16)
253*28939c3eSIlya Leoshkevich    return VmCore(kerneloffset=kerneloffset)
254