You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
229 lines
7.4 KiB
229 lines
7.4 KiB
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()
|
|
|