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