iBoot/tools/lldb_os_iboot.py

200 lines
12 KiB
Python
Raw Normal View History

2023-07-08 13:03:17 -07:00
#!/usr/bin/python
import lldb
import struct
def __lldb_init_module(debugger, internal_dict):
debugger.HandleCommand("command script add -f lldb_os_iboot.iboot_tasks iboot_tasks")
def iboot_tasks(debugger, command, result, internal_dict):
"""Print the list of tasks maintained by the iBoot runtime"""
process = debugger.GetSelectedTarget().GetProcess()
if not process or not process.target:
print 'Not connected'
return
plugin = OperatingSystemPlugIn(process)
current_task = plugin.get_global('current_task')
assert current_task is not None
current_task_addr = current_task.GetValueAsUnsigned()
tasks = plugin.get_task_dict().itervalues()
print ' TID Task Name Address'
print ' ------ ---- ---------------- ------------------'
for t in tasks:
task_addr = t.AddressOf().GetValueAsUnsigned()
current = "*" if task_addr == current_task_addr else " "
tv = lldb.value(t)
task_id = int(tv.task_id)
tid = task_id + plugin.TID_OFFSET
name = plugin.value_to_str(tv.name.sbvalue)
print '{} {:#06x} {:<4} {:<16} {:#018x}'.format(current, tid, task_id, name, task_addr)
class OperatingSystemPlugIn(object):
"""Class that provides data for an instance of a LLDB 'OperatingSystemPython' plug-in class"""
TID_OFFSET = 0x1000
def __init__(self, process):
'''Initialization needs a valid.SBProcess object'''
self.process = None
self.registers = None
self.task_dict = None
self.arch = None
if type(process) is lldb.SBProcess and process.IsValid():
self.process = process
triple = process.target.triple
if triple:
self.arch = triple.split('-')[0]
def get_global(self, name):
return self.process.target.FindGlobalVariables(name, 1)[0]
def iboot_task_iter(self, head, skip_task=None):
task_type = self.process.target.FindFirstType('task')
task_members = { member.name : member for member in task_type.get_members_array() }
list_offset = task_members['task_list_node'].byte_offset
if not skip_task is None:
skip_addr = skip_task.GetValueAsUnsigned()
else:
skip_addr = 0
for node in head.AddressOf().linked_list_iter('next'):
task_addr = node.GetValueAsUnsigned() - list_offset
if task_addr == skip_addr:
continue
task = node.CreateValueFromAddress('task', task_addr, task_type)
tid = int(lldb.value(task).task_id)
yield tid, task
def summarize_iboot_task(self, task):
task_value = lldb.value(task)
return {
'name': self.value_to_str(task_value.name.sbvalue).ljust(15),
'tid': int(task_value.task_id) + self.TID_OFFSET,
'state': 'stopped',
'stop_reason': 'none'
}
def get_task_dict(self, skip_current=False):
if self.task_dict is None:
task_list = self.get_global('task_list')
assert task_list is not None
if skip_current:
skip_task = self.get_global('current_task')
else:
skip_task = None
task_tuples = list(self.iboot_task_iter(task_list, skip_task))
# The first entry in the list isn't a task, so remove it from the list
task_tuples = task_tuples[1:]
# If there aren't any tasks in the list, we must still be
# in the bootstrap task, which we can get through current_task
if len(task_tuples) == 0 and not skip_current:
current_task = self.get_global('current_task').Dereference()
current_tid = int(lldb.value(current_task).task_id)
task_tuples = [(current_tid, current_task)]
self.task_dict = {tid : thread for tid,thread in task_tuples}
return self.task_dict
@staticmethod
def value_to_str(value):
return "".join([chr(x) for x in value.GetData().uint8s if x != 0])
@staticmethod
def value_to_bytes(value):
return "".join([chr(x) for x in value.GetData().uint8s])
def get_thread_info(self):
task_iter = self.get_task_dict(skip_current=True).itervalues()
return map(lambda x: self.summarize_iboot_task(x), task_iter)
def get_register_data(self, tid):
assert tid >= self.TID_OFFSET
tasks = self.get_task_dict()
task = tasks[tid - self.TID_OFFSET]
task_arch_value = lldb.value(task).arch
if self.arch == 'arm64':
regs = task_arch_value.regs.sbvalue
fp = task_arch_value.fp.sbvalue
lr = task_arch_value.lr.sbvalue
sp = task_arch_value.sp.sbvalue
# We don't know the PC, so use the LR instead to keep LLDB happy
pc = task_arch_value.lr.sbvalue
registers = [regs, fp, lr, sp, pc]
else:
regs = task_arch_value.regs.sbvalue
# We don't know the PC, so use the LR instead to keep LLDB happy
pc = task_arch_value.regs[9].sbvalue
registers = [regs, pc]
result = "".join(map(self.value_to_bytes, registers))
return result
def get_register_info(self):
if self.registers == None:
self.registers = dict()
if self.arch == 'arm64':
self.registers['sets'] = ['GPR']
self.registers['registers'] = [
{ 'name':'x0' , 'bitsize' : 64, 'offset' : 0x00, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 0, 'dwarf' : 0},
{ 'name':'x1' , 'bitsize' : 64, 'offset' : 0x08, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 1, 'dwarf' : 1},
{ 'name':'x2' , 'bitsize' : 64, 'offset' : 0x10, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 2, 'dwarf' : 2},
{ 'name':'x3' , 'bitsize' : 64, 'offset' : 0x18, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 3, 'dwarf' : 3},
{ 'name':'x4' , 'bitsize' : 64, 'offset' : 0x20, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 4, 'dwarf' : 4},
{ 'name':'x5' , 'bitsize' : 64, 'offset' : 0x28, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 5, 'dwarf' : 5},
{ 'name':'x6' , 'bitsize' : 64, 'offset' : 0x30, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 6, 'dwarf' : 6},
{ 'name':'x7' , 'bitsize' : 64, 'offset' : 0x38, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 7, 'dwarf' : 7},
{ 'name':'x8' , 'bitsize' : 64, 'offset' : 0x40, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 8, 'dwarf' : 8},
{ 'name':'x9' , 'bitsize' : 64, 'offset' : 0x48, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 9, 'dwarf' : 9},
{ 'name':'x10' , 'bitsize' : 64, 'offset' : 0x50, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 10, 'dwarf' : 10},
{ 'name':'x11' , 'bitsize' : 64, 'offset' : 0x58, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 11, 'dwarf' : 11},
{ 'name':'x12' , 'bitsize' : 64, 'offset' : 0x60, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 12, 'dwarf' : 12},
{ 'name':'x13' , 'bitsize' : 64, 'offset' : 0x68, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 13, 'dwarf' : 13},
{ 'name':'x14' , 'bitsize' : 64, 'offset' : 0x70, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 14, 'dwarf' : 14},
{ 'name':'x15' , 'bitsize' : 64, 'offset' : 0x78, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 15, 'dwarf' : 15},
{ 'name':'x16' , 'bitsize' : 64, 'offset' : 0x80, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 16, 'dwarf' : 16},
{ 'name':'x17' , 'bitsize' : 64, 'offset' : 0x88, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 17, 'dwarf' : 17},
{ 'name':'x18' , 'bitsize' : 64, 'offset' : 0x90, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 18, 'dwarf' : 18},
{ 'name':'x19' , 'bitsize' : 64, 'offset' : 0x98, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 19, 'dwarf' : 19},
{ 'name':'x20' , 'bitsize' : 64, 'offset' : 0xa0, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 20, 'dwarf' : 20},
{ 'name':'x21' , 'bitsize' : 64, 'offset' : 0xa8, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 21, 'dwarf' : 21},
{ 'name':'x22' , 'bitsize' : 64, 'offset' : 0xb0, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 22, 'dwarf' : 22},
{ 'name':'x23' , 'bitsize' : 64, 'offset' : 0xb8, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 23, 'dwarf' : 23},
{ 'name':'x24' , 'bitsize' : 64, 'offset' : 0xc0, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 24, 'dwarf' : 24},
{ 'name':'x25' , 'bitsize' : 64, 'offset' : 0xc8, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 25, 'dwarf' : 25},
{ 'name':'x26' , 'bitsize' : 64, 'offset' : 0xd0, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 26, 'dwarf' : 26},
{ 'name':'x27' , 'bitsize' : 64, 'offset' : 0xd8, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 27, 'dwarf' : 27},
{ 'name':'x28' , 'bitsize' : 64, 'offset' : 0xe0, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 28, 'dwarf' : 28},
{ 'name':'fp' , 'bitsize' : 64, 'offset' : 0xe8, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 29, 'dwarf' : 29, 'generic':'fp'},
{ 'name':'lr' , 'bitsize' : 64, 'offset' : 0xf0, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 30, 'dwarf' : 30, 'generic':'lr'},
{ 'name':'sp' , 'bitsize' : 64, 'offset' : 0xf8, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 31, 'dwarf' : 31, 'generic':'sp'},
{ 'name':'pc' , 'bitsize' : 64, 'offset' : 0x100, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 32, 'dwarf' : 32, 'generic':'pc'},
]
else:
self.registers['sets'] = ['GPR']
self.registers['registers'] = [
{ 'name':'r4' , 'bitsize' : 32, 'offset' : 0x00, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 4, 'dwarf' : 4},
{ 'name':'r5' , 'bitsize' : 32, 'offset' : 0x04, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 5, 'dwarf' : 5},
{ 'name':'r6' , 'bitsize' : 32, 'offset' : 0x08, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 6, 'dwarf' : 6},
{ 'name':'r7' , 'bitsize' : 32, 'offset' : 0x0c, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 7, 'dwarf' : 7, 'generic':'fp'},
{ 'name':'r8' , 'bitsize' : 32, 'offset' : 0x10, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 8, 'dwarf' : 8},
{ 'name':'r9' , 'bitsize' : 32, 'offset' : 0x14, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 9, 'dwarf' : 9},
{ 'name':'r10' , 'bitsize' : 32, 'offset' : 0x18, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 10, 'dwarf' : 10},
{ 'name':'r11' , 'bitsize' : 32, 'offset' : 0x1c, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 11, 'dwarf' : 11},
{ 'name':'r13' , 'bitsize' : 32, 'offset' : 0x20, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 13, 'dwarf' : 13, 'generic':'sp'},
{ 'name':'r14' , 'bitsize' : 32, 'offset' : 0x24, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 14, 'dwarf' : 14, 'generic':'lr'},
{ 'name':'pc' , 'bitsize' : 32, 'offset' : 0x28, 'encoding':'uint' , 'format':'hex', 'set': 0, 'gcc' : 15, 'dwarf' : 15, 'generic':'pc'},
]
return self.registers