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