from gdb.printing import PrettyPrinter, register_pretty_printer import gdb class KthreadPrettyPrinter(object): def __init__(self, val): self.val = val def to_string(self): result = "" name = self.val["name"] state = self.val["state"] # Should get PC on stack for non-current thread otherwise will only get address in cpu_context_switch cpuState = self.val["cpuState"] cmdline = "info line *%s"%int(cpuState["eip"].cast(gdb.lookup_type("long").pointer())) line = gdb.execute(cmdline, to_string=True) #line = gdb.find_pc_line(int(cpuState["eip"].cast(gdb.lookup_type("long").pointer()).referenced_value())) currentThread = gdb.parse_and_eval("currentThread") if self.val.address == currentThread: result += "->" else: result += " " result += "Addr: 0x%x, name: %s, state: %s, PC: %s" % (self.val.address, name, state, line) return result class CustomPrettyPrinterLocator(PrettyPrinter): """Given a gdb.Value, search for a custom pretty printer""" def __init__(self): super(CustomPrettyPrinterLocator, self).__init__( "matos_pretty_printers", [] ) def __call__(self, val): """Return the custom formatter if the type can be handled""" typename = gdb.types.get_basic_type(val.type).tag if typename is None: typename = val.type.name if typename == "thread": return KthreadPrettyPrinter(val) class threadListDumpCmd(gdb.Command): """Prints the thread list""" def __init__(self): super(threadListDumpCmd, self).__init__( "thread_list_dump", gdb.COMMAND_USER ) def _thread_list_to_str(self, val): """Walk through the Kthread list. We will simply follow the 'next' pointers until we encounter the HEAD again """ idx = 0 head = val thread_ptr = val result = "" while thread_ptr != 0 and (idx == 0 or thread_ptr != head): result += "\n%d: %s" % (idx, KthreadPrettyPrinter(thread_ptr).to_string()) thread_ptr = thread_ptr["next"] idx += 1 result = ("Found a Linked List with %d thread:" % idx) + result return result def complete(self, text, word): # We expect the argument passed to be a symbol so fallback to the # internal tab-completion handler for symbols return gdb.COMPLETE_SYMBOL def invoke(self, args, from_tty): # We can pass args here and use Python CLI utilities like argparse # to do argument parsing print("Args Passed: %s" % args) if args: thread_ptr_val = gdb.parse_and_eval(args) else: thread_ptr_val = gdb.parse_and_eval("currentThread") if str(thread_ptr_val.type) != "struct thread *": print("Expected pointer argument of type (struct thread *)") return print(self._thread_list_to_str(thread_ptr_val)) class PhyMemDescListDumpCmd(gdb.Command): """Prints the memDesc list""" def __init__(self): super(PhyMemDescListDumpCmd, self).__init__( "phyMem_list_dump", gdb.COMMAND_USER) def _phy_memDesc_lit_to_str(self, val): result = "" idx = 0 head = val memDesc_ptr = val prevAddr = None printBegin = True memAddrs = [] while memDesc_ptr != 0 and (idx == 0 or memDesc_ptr != head): memAddrs.append(int(memDesc_ptr["phy_addr"])) memDesc_ptr = memDesc_ptr["next"] idx += 1 memAddrs.sort() for currAddr in memAddrs: if printBegin: prevAddr = currAddr result += "[0x%x" % prevAddr printBegin = False if currAddr > prevAddr + 4096: result += "->0x%x[\n[0x%x" % ((prevAddr+4096), currAddr) prevAddr = currAddr if prevAddr: result += "->0x%x[\n" % (prevAddr+4096) result = ("Found a List with %d memDesc:\n" % idx) + result return result def complete(self, text, word): return gdb.COMPLETE_SYMBOL def invoke(self, args, from_tty): if args: desc = gdb.parse_and_eval(args) else: desc = gdb.parse_and_eval("phyFreePage") if str(desc.type) != "struct memDesc *": print("Expected pointer argument of type (struct memDesc *)") return print(self._phy_memDesc_lit_to_str(desc)) class PrintStructC99Cmd(gdb.Command): def __init__(self): super(PrintStructC99Cmd, self).__init__( "print_struct_c99", gdb.COMMAND_USER, ) def complete(self, text, word): return gdb.COMPLETE_SYMBOL def get_count_heading(self, string): for i, s in enumerate(string): if s != ' ': break return i def extract_typename(self, string): first_line = string.split('\n')[0] return first_line.split('=')[1][:-1].strip() def invoke(self, arg, from_tty): gdb.execute("set print pretty") gdb.execute('set pagination off') gdb.execute('set print repeats 0') gdb.execute('set print elements unlimited') ret_ptype = gdb.execute('ptype {}'.format(arg), to_string=True) tname = self.extract_typename(ret_ptype) print('{} {} = {{'.format(tname, arg)) r = gdb.execute('p {}'.format(arg), to_string=True) r = r.split('\n') for rr in r[1:]: if '=' not in rr: print(rr) continue hs = self.get_count_heading(rr) rr_s = rr.strip().split('=', 1) rr_rval = rr_s[1].strip() print(' ' * hs + '.' + rr_s[0] + '= ' + rr_rval) class ListDumpCmd(gdb.Command): """Prints a linked list""" def __init__(self): super(ListDumpCmd, self).__init__( "list_dump", gdb.COMMAND_USER ) def _print_list(self, val): """Walk through the linked list. We will simply follow the 'next' pointers until we encounter the HEAD again """ idx = 0 head = val thread_ptr = val result = "" while thread_ptr != 0 and (idx == 0 or thread_ptr != head): result += gdb.execute('p *({}){}'.format(str(thread_ptr.type),thread_ptr), to_string=True) thread_ptr = thread_ptr["next"] idx += 1 result = ("Found a Linked List with %d items:" % idx) + "\n" + result return result def complete(self, text, word): # We expect the argument passed to be a symbol so fallback to the # internal tab-completion handler for symbols return gdb.COMPLETE_SYMBOL def invoke(self, args, from_tty): # We can pass args here and use Python CLI utilities like argparse # to do argument parsing print("Args Passed: %s" % args) if args: ptr_val = gdb.parse_and_eval(args) else: ptr_val = gdb.parse_and_eval("currentThread") try: ptr_val["next"] except: print("Expected pointer argument with a next field") return print(self._print_list(ptr_val)) register_pretty_printer(None, CustomPrettyPrinterLocator(), replace=True) threadListDumpCmd() PhyMemDescListDumpCmd() PrintStructC99Cmd() ListDumpCmd()