import lldb
import shlex
DOF_ID_SIZE = 16
DOF_ID_MODEL = 4
DOF_ID_ENCODING = 5
DOF_ID_VERSION = 6
DOF_ID_DIFVERS = 7
DOF_ID_DIFIREG = 8
DOF_ID_DIFTREG = 9
dof_magic = [0x7f, ord('D'), ord('O'), ord('F')]
DOF_SECF_LOAD = 1
section_names = ["NONE", "COMMENTS", "SOURCE", "ECBDESC", "PROBEDESC",
"ACTDESC", "DIFOHDR", "DIF", "STRTAB", "VARTAB", "RELTAB", "TYPTAB",
"URELHDR", "KRELHDR", "OPTDESC", "PROVIDER", "PROBES", "PRARGS",
"PROFFS", "INTTAB", "UTSNAME", "XLTAB", "XLMEMBERS", "XLIMPORT",
"XLEXPORT", "PREXPORT", "PRENOFFS"]
def DIF_INSTR_OP(i):
return (((i) >> 24) & 0xff)
def DIF_INSTR_R1(i):
return (((i) >> 16) & 0xff)
def DIF_INSTR_R2(i):
return (((i) >> 8) & 0xff)
def DIF_INSTR_RD(i):
return ((i) & 0xff)
def DIF_INSTR_RS(i):
return ((i) & 0xff)
def DIF_INSTR_LABEL(i):
return ((i) & 0xffffff)
def DIF_INSTR_VAR(i):
return (((i) >> 8) & 0xffff)
def DIF_INSTR_INTEGER(i):
return (((i) >> 8) & 0xffff)
def DIF_INSTR_STRING(i):
return (((i) >> 8) & 0xffff)
def DIF_INSTR_SUBR(i):
return (((i) >> 8) & 0xffff)
def DIF_INSTR_TYPE(i):
return (((i) >> 16) & 0xff)
def DIF_INSTR_XLREF(i):
return (((i) >> 8) & 0xffff)
DIFV_SCOPE_GLOBAL = 0
DIFV_SCOPE_THREAD = 1
DIFV_SCOPE_LOCAL = 2
subroutine_strings = {
0: "rand",
1: "mutex_owned",
2: "mutex_owner",
3: "mutex_type_adaptive",
4: "mutex_type_spin",
5: "rw_read_held",
6: "rw_write_held",
7: "rw_iswriter",
8: "copyin",
9: "copyinstr",
10: "speculation",
11: "progenyof",
12: "strlen",
13: "copyout",
14: "copyoutstr",
15: "alloca",
16: "bcopy",
17: "copyinto",
18: "msgdsize",
19: "msgsize",
20: "getmajor",
21: "getminor",
22: "ddi_pathname",
23: "strjoin",
24: "lltostr",
25: "basename",
26: "dirname",
27: "cleanpath",
28: "strchr",
29: "strrchr",
30: "strstr",
31: "strtok",
32: "substr",
33: "index",
34: "rindex",
35: "htons",
36: "htonl",
37: "htonll",
38: "ntohs",
39: "ntohl",
40: "ntohll",
41: "inet_ntop",
42: "inet_nota",
43: "inet_nota6",
44: "toupper",
45: "tolower",
200: "vm_kernel_addrperm",
201: "kdebug_trace",
202: "kdebug_trace_string"
}
DTRACEACT_NONE = 0
DTRACEACT_DIFEXPR = 1
DTRACEACT_EXIT = 2
DTRACEACT_PRINTF = 3
DTRACEACT_PRINTA = 4
DTRACEACT_LIBACT = 5
DTRACEACT_TRACEMEM = 6
DTRACEACT_TRACEMEM_DYNSIZE = 7
DTRACEACT_PROC = 0x0100
DTRACEACT_USTACK = DTRACEACT_PROC + 1
DTRACEACT_JSTACK = DTRACEACT_PROC + 2
DTRACEACT_USYM = DTRACEACT_PROC + 3
DTRACEACT_UMOD = DTRACEACT_PROC + 3
DTRACEACT_UADDR = DTRACEACT_PROC + 3
DTRACEACT_PROC_DESTRUCTIVE = 0x0200
DTRACEACT_STOP = DTRACEACT_PROC_DESTRUCTIVE + 1
DTRACEACT_RAISE = DTRACEACT_PROC_DESTRUCTIVE + 2
DTRACEACT_SYSTEM = DTRACEACT_PROC_DESTRUCTIVE + 3
DTRACEACT_FREOPEN = DTRACEACT_PROC_DESTRUCTIVE + 4
DTRACEACT_KERNEL = 0x0400
DTRACEACT_STACK = DTRACEACT_KERNEL + 1
DTRACEACT_SYM = DTRACEACT_KERNEL + 2
DTRACEACT_MOD = DTRACEACT_KERNEL + 3
DTRACEACT_KERNEL_DESTRUCTIVE = 0x0500
DTRACEACT_BREAKPOINT = DTRACEACT_KERNEL_DESTRUCTIVE + 1
DTRACEACT_PANIC = DTRACEACT_KERNEL_DESTRUCTIVE + 2
DTRACEACT_CHILL = DTRACEACT_KERNEL_DESTRUCTIVE + 3
DTRACEACT_SPECULATIVE = 0x0600
DTRACEACT_SPECULATE = DTRACEACT_SPECULATIVE + 1
DTRACEACT_COMMIT = DTRACEACT_SPECULATIVE + 2
DTRACEACT_DISCARD = DTRACEACT_SPECULATIVE + 3
DTRACEACT_AGGREGATION = 0x0700
DTRACEAGG_COUNT = DTRACEACT_AGGREGATION + 1
DTRACEAGG_MIN = DTRACEACT_AGGREGATION + 2
DTRACEAGG_MAX = DTRACEACT_AGGREGATION + 3
DTRACEAGG_AVG = DTRACEACT_AGGREGATION + 4
DTRACEAGG_SUM = DTRACEACT_AGGREGATION + 5
DTRACEAGG_STDDEV = DTRACEACT_AGGREGATION + 6
DTRACEAGG_QUANTIZE = DTRACEACT_AGGREGATION + 7
DTRACEAGG_LQUANTIZE = DTRACEACT_AGGREGATION + 8
DTRACEAGG_LLQUANTIZE = DTRACEACT_AGGREGATION + 9
err = lldb.SBError()
action_strings = {
DTRACEACT_NONE: 'NONE',
DTRACEACT_DIFEXPR: 'DIFEXPR',
DTRACEACT_EXIT: 'EXIT',
DTRACEACT_PRINTF: 'PRINTF',
DTRACEACT_PRINTA: 'PRINTA',
DTRACEACT_LIBACT: 'LIBACT',
DTRACEACT_TRACEMEM: 'TRACEMEM',
DTRACEACT_TRACEMEM_DYNSIZE: 'TRACEMEM_DYNSIZE',
DTRACEACT_USTACK: 'USTACK',
DTRACEACT_JSTACK: 'JSTACK',
DTRACEACT_USYM: 'USYM',
DTRACEACT_UMOD: 'UMOD',
DTRACEACT_UADDR: 'UADDR',
DTRACEACT_STOP: 'STOP',
DTRACEACT_RAISE: 'RAISE',
DTRACEACT_SYSTEM: 'SYSTEM',
DTRACEACT_FREOPEN: 'FREOPEN',
DTRACEACT_STACK: 'STACK',
DTRACEACT_SYM: 'SYM',
DTRACEACT_MOD: 'MOD',
DTRACEACT_BREAKPOINT: 'BREAKPOINT',
DTRACEACT_PANIC: 'PANIC',
DTRACEACT_CHILL: 'CHILL',
DTRACEACT_COMMIT: 'COMMIT',
DTRACEACT_DISCARD: 'DISCARD',
DTRACEAGG_COUNT: 'COUNT',
DTRACEAGG_MIN: 'MIN',
DTRACEAGG_MAX: 'MAX',
DTRACEAGG_AVG: 'AVG',
DTRACEAGG_SUM: 'SUM',
DTRACEAGG_STDDEV: 'STDDEV',
DTRACEAGG_QUANTIZE: 'QUANTIZE',
DTRACEAGG_LQUANTIZE: 'LQUANTIZE',
DTRACEAGG_LLQUANTIZE: 'LLQUANTIZE'
}
def ActionString(kind):
if kind in action_strings:
return action_strings[kind]
return '??? ({})'.format(kind)
def DOFModelString(model):
if model == 0:
return 'NONE'
elif model == 1:
return 'ILP32'
elif model == 2:
return 'LP64'
def DOFEncodingString(encoding):
if encoding == 0:
return 'NONE'
elif encoding == 1:
return 'LSB'
elif encoding == 2:
return 'MSB'
def DOFFlagsString(flag):
if flag != DOF_SECF_LOAD:
return '(Non-Loadable)'
return ''
def DOFSecIdxString(val):
if val == -1:
return 'NONE'
return val
def GetChildAtIndexAsUnsigned(source, i):
return source.GetChildAtIndex(i).GetValueAsUnsigned()
def GetMemberAsSigned(source, field):
return source.GetChildMemberWithName(field, True).GetValueAsSigned()
def GetMemberAsUnsigned(source, field):
return source.GetChildMemberWithName(field, True).GetValueAsUnsigned()
class DIFODisassembler:
"""
Disassembler for DIFO given a DIF section, a strtab section, a inttab
section and a vartab section
"""
def __init__(self, dif, strtab, inttab, vartab):
self.dif = dif
self.strtab = strtab
self.inttab = inttab
self.vartab = vartab
self.ops = [
["(illegal opcode)", self.DisStr],
["or", self.DisLog], ["xor", self.DisLog], ["and", self.DisLog], ["sll", self.DisLog], ["srl", self.DisLog], ["sub", self.DisLog], ["add", self.DisLog], ["mul", self.DisLog], ["sdiv", self.DisLog], ["udiv", self.DisLog], ["srem", self.DisLog], ["urem", self.DisLog], ["not", self.DisR1Rd], ["mov", self.DisR1Rd], ["cmp", self.DisCmp], ["tst", self.DisTst], ["ba", self.DisBranch], ["be", self.DisBranch], ["bne", self.DisBranch], ["bg", self.DisBranch], ["bgu", self.DisBranch], ["bge", self.DisBranch], ["bgeu", self.DisBranch], ["bl", self.DisBranch], ["blu", self.DisBranch], ["ble", self.DisBranch], ["bleu", self.DisBranch], ["ldsb", self.DisLoad], ["ldsh", self.DisLoad], ["ldsw", self.DisLoad], ["ldub", self.DisLoad], ["lduh", self.DisLoad], ["lduw", self.DisLoad], ["ldx", self.DisLoad], ["ret", self.DisRet], ["nop", self.DisStr], ["setx", self.DisSetX], ["sets", self.DisSetS], ["scmp", self.DisCmp], ["ldga", self.DisLda], ["ldgs", self.DisLdv], ["stgs", self.DisStv], ["ldta", self.DisLda], ["ldts", self.DisLdv], ["stts", self.DisStv], ["sra", self.DisLog], ["call", self.DisCall], ["pushtr", self.DisPushTs], ["pushtv", self.DisPushTs], ["popts", self.DisStr], ["flushts", self.DisStr], ["ldgaa", self.DisLdv], ["ldtaa", self.DisLdv], ["stgaa", self.DisStv], ["sttaa", self.DisStv], ["ldls", self.DisLdv], ["stls", self.DisStv], ["allocs", self.DisR1Rd], ["copys", self.DisLog], ["stb", self.DisStore], ["sth", self.DisStore], ["stw", self.DisStore], ["stx", self.DisStore], ["uldsb", self.DisLoad], ["uldsh", self.DisLoad], ["uldsw", self.DisLoad], ["uldub", self.DisLoad], ["ulduh", self.DisLoad], ["ulduw", self.DisLoad], ["uldx", self.DisLoad], ["rldsb", self.DisLoad], ["rldsh", self.DisLoad], ["rldsw", self.DisLoad], ["rldub", self.DisLoad], ["rlduh", self.DisLoad], ["rlduw", self.DisLoad], ["rldx", self.DisLoad], ["xlate", self.DisXlate], ["xlarg", self.DisXlate], ]
def Disassemble(self):
dif = self.dif
print '\t%-3s %-8s %s' % ('OFF', 'OPCODE', 'INSTRUCTION')
for i in range(dif.dif_len):
instr = dif.GetInstr(i)
op = DIF_INSTR_OP(instr)
print '\t%02lu: %08x ' % (i, instr),
if op < len(self.ops):
self.ops[op][1](self.ops[op][0], instr)
else:
print ''
def DisStr(self, name, ins):
print name
def DisLog(self, name, ins):
print "%-4s %%r%u, %%r%u, %%r%u" % (name, DIF_INSTR_R1(ins),
DIF_INSTR_R2(ins), DIF_INSTR_RD(ins))
def DisR1Rd(self, name, ins):
print "%-4s %%r%u, %%r%u" % (name, DIF_INSTR_R1(ins), DIF_INSTR_RD(ins))
def DisCmp(self, name, ins):
print "%-4s %%r%u, %%r%u" % (name, DIF_INSTR_R1(ins), DIF_INSTR_R2(ins))
def DisTst(self, name, ins):
print "%-4s %%r%u" % (name, DIF_INSTR_R1(ins))
def DisBranch(self, name, ins):
print "%-4s %u" % (name, DIF_INSTR_LABEL(ins))
def DisLoad(self, name, ins):
print "%-4s [%%r%u], %%r%u" % (name, DIF_INSTR_R1(ins), DIF_INSTR_RD(ins))
def DisRet(self, name, ins):
print "%-4s %%r%u" % (name, DIF_INSTR_RD(ins))
def DisSetX(self, name, ins):
intptr = DIF_INSTR_INTEGER(ins)
print "%-4s DT_INTEGER[%u], %%r%u" % (name, intptr, DIF_INSTR_RD(ins)),
if intptr < self.inttab.int_len:
print "\t\t! 0x%dx" % (self.inttab.GetInt(intptr))
else:
print ''
def DisSetS(self, name, ins):
strptr = DIF_INSTR_STRING(ins)
print "%-4s DT_STRING[%u], %%r%u" % (name, strptr, DIF_INSTR_RD(ins)),
if strptr < self.strtab.data_size:
print "\t\t! \"%s\"" % self.strtab.GetString(strptr)
else:
print ''
def DisLda(self, name, ins):
var = DIF_INSTR_R1(ins)
print '%-4s DT_VAR(%u), %%r%u, %%r%u' % (name, var, DIF_INSTR_R2(ins),
DIF_INSTR_RD(ins)),
vname = self.VarName(var, self.Scope(name))
if vname is not(None):
print "\t\t! DT_VAR(%u) = \"%s\"" % (var, vname)
else:
print ''
def DisLdv(self, name, ins):
var = DIF_INSTR_VAR(ins)
print '%-4s DT_VAR(%u), %%r%u' % (name, var, DIF_INSTR_RD(ins)),
vname = self.VarName(var, self.Scope(name))
if vname is not(None):
print "\t\t! DT_VAR(%u) = \"%s\"" % (var, vname)
else:
print ''
def DisStv(self, name, ins):
var = DIF_INSTR_VAR(ins)
print '%-4s %%r%u, DT_VAR(%u)' % (name, DIF_INSTR_RS(ins), var),
vname = self.VarName(var, self.Scope(name))
if vname is not(None):
print "\t\t! DT_VAR(%u) = \"%s\"" % (var, vname)
else:
print ''
def DisLog(self, name, ins):
print "%-4s %%r%u, %%r%u, %%r%u" % (name, DIF_INSTR_R1(ins),
DIF_INSTR_R2(ins), DIF_INSTR_RD(ins))
def DisCall(self, name, ins):
subr = DIF_INSTR_SUBR(ins)
subr_string = subroutine_strings[subr] if subr in subroutine_strings else ''
print '%-4s DIF_SUBR(%u), %%r%u\t\t! %s' % (name, subr,
DIF_INSTR_RD(ins), subr_string)
def DisPushTs(self, name, ins):
tnames = ["D type", "string"]
itype = DIF_INSTR_TYPE(ins)
print "%-4s DT_TYPE(%u), %%r%u, %%r%u" % (name, itype, DIF_INSTR_R2(ins),
DIF_INSTR_RS(ins)),
if itype <= 1:
print "\t! DT_TYPE(%u) = %s" % (itype, tnames[itype])
else:
print ''
def DisStore(self, name, ins):
print '%-4s %%r%u, [%%r%u]' % (DIF_INSTR_R1(ins), DIF_INSTR_RD(ins))
def DisLoad(self, name, ins):
print '%-4s [%%r%u], %%r%u' % (name, DIF_INSTR_R1(ins), DIF_INSTR_RD(ins))
def DisXlate(self, name, ins):
xlr = DIF_INSTR_XLREF(ins);
print "%-4s DT_XLREF[%u], %%r%u" % (name, xlr, DIF_INSTR_RD(ins))
def VarName(self, vid, scope):
for i in range(self.vartab.var_len):
var = self.vartab.GetVar(i)
tested_vid = GetMemberAsSigned(var, "dtdv_id")
tested_scope = GetMemberAsSigned(var, "dtdv_scope")
if vid == tested_vid and scope == tested_scope:
name = GetMemberAsUnsigned(var, "dtdv_name")
return self.strtab.GetString(name)
return None
def Scope(self, name):
scope = name[2]
if scope == 'l':
return DIFV_SCOPE_LOCAL
elif scope == 't':
return DIFV_SCOPE_THREAD
elif scope == 'g':
return DIFV_SCOPE_GLOBAL
else:
return -1
class AddrData:
"""DOF data coming from a specific address"""
def __init__(self, target, addr):
self.target = target
self.addr = addr
def GetAddr(self):
return self.addr
def GetValue(self, name, offset, vtype):
address = lldb.SBAddress(self.addr + offset, self.target)
return self.target.CreateValueFromAddress(name, address, vtype)
class SectionData:
"""
DOF data coming from a section. We can't use addresses directly here
because lldb won't let us inspect DOF sections in libraries not loaded
in a specific process otherwise
"""
def __init__(self, target, section):
self.section = section
self.target = target
def GetAddr(self):
return self.section.GetLoadAddress(self.target)
def GetData(self, offset, size):
return self.section.GetSectionData(offset, size)
def GetValue(self, name, offset, vtype):
size = vtype.GetByteSize()
return self.target.CreateValueFromData(name, self.GetData(offset, size),
vtype)
class DOFHeader:
def __init__(self, dof, target, data):
self.dof = dof
dof_hdr_type = target.FindFirstType("dof_hdr_t")
if not(dof_hdr_type.IsValid()):
print 'could not find dof_hdr_t type'
return
header = data.GetValue("$dof_hdr", 0, dof_hdr_type)
self.secoff = GetMemberAsUnsigned(header, "dofh_secoff")
self.secsize = GetMemberAsUnsigned(header,"dofh_secsize")
self.nsecs = GetMemberAsUnsigned(header, "dofh_secnum")
dofh_ident = header.GetChildMemberWithName("dofh_ident", True)
for i in range(3):
mag = dofh_ident.GetChildAtIndex(i).GetValueAsUnsigned()
if mag != dof_magic[i]:
raise LookupError("Invalid magic number, is this a DOF ?")
self.model = DOFModelString(GetChildAtIndexAsUnsigned(dofh_ident, DOF_ID_MODEL))
self.encoding = DOFEncodingString(GetChildAtIndexAsUnsigned(dofh_ident, DOF_ID_ENCODING))
self.format_version = GetChildAtIndexAsUnsigned(dofh_ident, DOF_ID_VERSION)
self.difvers = GetChildAtIndexAsUnsigned(dofh_ident, DOF_ID_DIFVERS)
self.difireg = GetChildAtIndexAsUnsigned(dofh_ident, DOF_ID_DIFIREG)
self.diftreg = GetChildAtIndexAsUnsigned(dofh_ident, DOF_ID_DIFTREG)
def Show(self):
print 'DOF data model: {}'.format(self.model)
print 'DOF encoding: {}'.format(self.encoding)
print 'DOF format version: {}'.format(self.format_version)
print 'DOF instruction set version: {}'.format(self.difvers)
print 'DOF integer register count: {}'.format(self.difireg)
print 'DOF tuple register count: {}'.format(self.diftreg)
class DOFSection(object):
def __init__(self, dof, target, data, i):
self.hdr_offset = dof.header.secoff + dof.header.secsize * i
sec = data.GetValue("$sec", self.hdr_offset, dof.dof_sec_type)
self.i = i
self.dof = dof
self.stype = section_names[GetMemberAsUnsigned(sec, "dofs_type")]
self.flags = DOFFlagsString(GetMemberAsUnsigned(sec, "dofs_flags"))
self.ent_size = GetMemberAsUnsigned(sec, "dofs_entsize")
self.offset = GetMemberAsUnsigned(sec, "dofs_offset")
self.data_size = GetMemberAsUnsigned(sec, "dofs_size")
def Show(self):
print 'Section {} type {} data size {} ent size {} {} header {} data {}'.format(
self.i,
self.stype,
self.data_size, self.ent_size, self.flags,
hex(self.dof.addr + self.hdr_offset),
hex(self.dof.addr + self.offset))
class DOFDIFSection(DOFSection):
def __init__(self, dof, target, data, i):
super(DOFDIFSection, self).__init__(dof, target, data, i)
dif_instr_type = target.FindFirstType("dif_instr_t")
if not(dif_instr_type):
raise TypeError('Could not find dif_instr_t. Do you have a kernel binary loaded ?)')
self.dif_len = self.data_size / dif_instr_type.GetByteSize()
target.EvaluateExpression("dif_instr_t (*$pi{})[{}]".format(self.dif_len, self.dif_len))
dift_type = target.EvaluateExpression("$pi{}".format(self.dif_len)).GetType().GetPointeeType()
self.dif = data.GetValue("$dif_buf", self.offset, dift_type)
def GetInstr(self, i):
return GetChildAtIndexAsUnsigned(self.dif, i)
class DOFStrTabSection(DOFSection):
def __init__(self, dof, target, data, i):
super(DOFStrTabSection, self).__init__(dof, target, data, i)
target.EvaluateExpression("char (*$p{})[{}]".format(self.data_size,
self.data_size))
char_type = target.EvaluateExpression("$p{}".format(self.data_size)).GetType().GetPointeeType()
self.str_sec_data = data.GetValue("$strtab", self.offset, char_type)
def GetString(self, index):
return self.str_sec_data.GetData().GetString(err, index)
class DOFVarTabSection(DOFSection):
def __init__(self, dof, target, data, i):
super(DOFVarTabSection, self).__init__(dof, target, data, i)
dtrace_difv_type = target.FindFirstType("dtrace_difv_t")
if not(dtrace_difv_type):
raise TypeError('Could not find dtrace_difv_t. Do you have a kernel binary loaded ?)')
self.var_len = self.data_size / dtrace_difv_type.GetByteSize()
target.EvaluateExpression("dtrace_difv_t (*$difva{})[{}]".format(self.var_len, self.var_len))
difva_type = target.EvaluateExpression("$difva{}".format(self.var_len)).GetType().GetPointeeType()
self.vartab = data.GetValue("$vartab", self.offset, difva_type)
def GetVar(self, i):
return self.vartab.GetChildAtIndex(i)
class DOFIntTabSection(DOFSection):
def __init__(self, dof, target, data, i):
super(DOFIntTabSection, self).__init__(dof, target, data, i)
uint64_type = target.FindFirstType("uint64_t")
if not(uint64_type):
raise TypeError('Could not find uint64_t. Do you have a kernel binary loaded ?)')
self.int_len = self.data_size / uint64_type.GetByteSize()
target.EvaluateExpression("uint64_t (*$intat)[{}]".format(self.int_len))
inta_type = target.EvaluateExpression("$intat").GetType().GetPointeeType()
self.inttab = data.GetValue("$inttab", self.offset, inta_type)
def GetInt(self, i):
return GetChildAtIndexAsUnsigned(self.inttab, i)
class DOFProbe(object):
def __init__(self, func, name, nargv, xargv):
self.func = func
self.name = name
self.nargv = nargv
self.xargv = xargv
def Show(self):
if self.nargv != self.xargv:
print '\t{}::{}({} | {})'.format(self.func, self.name, self.nargv,
self.xargv)
else:
print '\t{}::{}({})'.format(self.func, self.name, self.nargv)
class DOFProviderSection(DOFSection):
"""
Helper (USDT) provider section, containing the definition of a provider
and a link to a probe section containing the definition of probes for
this provider. (usually) only contained in DOFs in files
"""
def __init__(self, dof, target, data, i):
super(DOFProviderSection, self).__init__(dof, target, data, i)
dof_provider_type = target.FindFirstType("dof_provider_t")
if not(dof_provider_type):
raise TypeError('Could not find dof_provider_t. Do you have a kernel binary loaded ?)')
dof_probe_type = target.FindFirstType("dof_probe_t")
if not(dof_probe_type):
raise TypeError('Could not find dof_probe_t. Do you have a kernel binary loaded ?)')
provider = data.GetValue("$provider", self.offset, dof_provider_type)
self.strtab_secid = GetMemberAsSigned(provider, "dofpv_strtab")
self.probes_secid = GetMemberAsSigned(provider, "dofpv_probes")
self.prargs_secid = GetMemberAsSigned(provider, "dofpv_prargs")
self.proffs_secid = GetMemberAsSigned(provider, "dofpv_proffs")
self.name_idx = GetMemberAsUnsigned(provider, "dofpv_name")
str_sec = dof.GetSection(self.strtab_secid)
self.provider_name = str_sec.GetString(self.name_idx)
prb_sec = dof.GetSection(self.probes_secid)
arg_sec = dof.GetSection(self.prargs_secid)
off_sec = dof.GetSection(self.proffs_secid)
self.nprobes = prb_sec.data_size / prb_sec.ent_size
self.probes = []
for i in range(self.nprobes):
probe = data.GetValue("$probe", prb_sec.offset + i *
prb_sec.ent_size, dof_probe_type)
probe_name_idx = GetMemberAsUnsigned(probe, "dofpr_name")
probe_name = str_sec.GetString(probe_name_idx)
probe_func_idx = GetMemberAsUnsigned(probe, "dofpr_func")
probe_func = str_sec.GetString(probe_func_idx)
probe_nargv_idx = GetMemberAsUnsigned(probe, "dofpr_nargv")
probe_nargv = str_sec.GetString(probe_nargv_idx) if probe_nargv_idx != probe_func_idx else "void"
probe_xargv_idx = GetMemberAsUnsigned(probe, "dofpr_xargv")
probe_xargv = str_sec.GetString(probe_xargv_idx) if probe_xargv_idx != probe_func_idx else "void"
self.probes.append(DOFProbe(probe_func, probe_name, probe_nargv,
probe_xargv))
def Show(self):
super(DOFProviderSection, self).Show()
print 'Provider name: {} ({} probes)'.format(self.provider_name,
self.nprobes)
for i in range(self.nprobes):
self.probes[i].Show()
class DOFEcbDescSection(DOFSection):
"""
ECB (Enabling control block) description section
"""
def __init__(self, dof, target, data, i):
super(DOFEcbDescSection, self).__init__(dof, target, data, i)
dof_ecbdesc_type = target.FindFirstType("dof_ecbdesc_t")
if not(dof_ecbdesc_type):
raise TypeError('Could not find dof_ecbdesc_t. Do you have a kernel binary loaded ?')
ecbdesc = data.GetValue("$ecbdesc", self.offset, dof_ecbdesc_type)
self.probes_secid = GetMemberAsSigned(ecbdesc, "dofe_probes")
self.pred_secid = GetMemberAsSigned(ecbdesc, "dofe_pred")
self.actions_secid = GetMemberAsSigned(ecbdesc, "dofe_actions")
def Show(self):
super(DOFEcbDescSection, self).Show()
print('\tprobe {} pred {} actions {}'.format(
DOFSecIdxString(self.probes_secid),
DOFSecIdxString(self.pred_secid),
DOFSecIdxString(self.actions_secid)
))
class DOFProbeDescSection(DOFSection):
"""
Probe description section
"""
def __init__(self, dof, target, data, i):
super(DOFProbeDescSection, self).__init__(dof, target, data, i)
dof_probedesc_type = target.FindFirstType("dof_probedesc_t")
if not(dof_probedesc_type):
raise TypeError('Could not find dof_probedesc_t. Do you have a kernel binary loaded ?')
probe = data.GetValue("$probe", self.offset, dof_probedesc_type)
str_sec_secid = GetMemberAsSigned(probe, "dofp_strtab")
str_sec = dof.GetSection(str_sec_secid)
provider_idx = GetMemberAsUnsigned(probe, "dofp_provider")
mod_idx = GetMemberAsUnsigned(probe, "dofp_mod")
func_idx = GetMemberAsUnsigned(probe, "dofp_func")
name_idx = GetMemberAsUnsigned(probe, "dofp_name")
self.provider = str_sec.GetString(provider_idx)
self.mod = str_sec.GetString(mod_idx)
self.func = str_sec.GetString(func_idx)
self.name = str_sec.GetString(name_idx)
def Show(self):
super(DOFProbeDescSection, self).Show()
print '\tProbe desc {}:{}:{}:{}'.format(self.provider,
self.mod, self.func, self.name)
class DOFAction:
def __init__(self, i, kind, difo, arg, arg_string):
self.i = i
self.kind = kind
self.difo = difo
self.arg = arg
self.arg_string = arg_string
class DOFActDescSection(DOFSection):
"""
Probe action description. The section contains multiple actions
"""
def __init__(self, dof, target, data, i):
super(DOFActDescSection, self).__init__(dof, target, data, i)
dof_actdesc_type = target.FindFirstType("dof_actdesc_t")
if not(dof_actdesc_type.IsValid()):
raise TypeError('Could not find dof_actdesc_t type. Do you have a kenrel binary loaded ?')
nactions = self.data_size / self.ent_size
self.actions = []
for i in range(nactions):
act = data.GetValue("$act", self.ent_size * i + self.offset, dof_actdesc_type)
kind = GetMemberAsUnsigned(act, "dofa_kind")
difo = GetMemberAsSigned(act, "dofa_difo")
strtab_secid = GetMemberAsSigned(act, "dofa_strtab")
arg = GetMemberAsUnsigned(act, "dofa_arg")
arg_string = None
if (kind in [DTRACEACT_PRINTF, DTRACEACT_PRINTA, DTRACEACT_SYSTEM,
DTRACEACT_FREOPEN]) and ((kind != DTRACEACT_PRINTA or strtab_secid != -1) or (kind == DTRACEACT_DIFEXPR and strtab_secid != -1)):
strtab = dof.GetSection(strtab_secid)
arg_string = strtab.GetString(arg)
self.actions.append(DOFAction(i, kind, difo, arg, arg_string))
def Show(self):
super(DOFActDescSection, self).Show()
for a in self.actions:
print '\tAction {} type {} difo in {}'.format(
a.i,
ActionString(a.kind),
a.difo,
),
if a.arg_string is not(None):
print 'arg "{}"'.format(a.arg_string)
else:
print 'arg {}'.format(a.arg)
class DOFDifoHdrSection(DOFSection):
"""
DIFO header section. Contains references to
DIF/INTTAB/STRTAB/VARTAB sections
"""
def __init__(self, dof, target, data, i):
super(DOFDifoHdrSection, self).__init__(dof, target, data, i)
dof_difohdr_type = target.FindFirstType("dof_difohdr_t")
if not(dof_difohdr_type.IsValid()):
raise TypeError('Could not find dof_difohdr_t type. Do you have a kernel binary loaded ?')
dof_secidx_type = target.FindFirstType("dof_secidx_t")
if not(dof_secidx_type.IsValid()):
raise TypeError('Could not find dof_secidx_t type. Do you have a kernel binary loaded ?')
self.nsections = (self.data_size - dof_difohdr_type.GetByteSize()) / dof_secidx_type.GetByteSize() + 1
self.secs = []
(self.dif_idx, self.dif) = (0, None)
(self.inttab_idx, self.inttab) = (0, None)
self.strtab_idx, self.strtab = (0, None)
(self.vartab_idx, self.vartab) = (0, None)
for i in range(self.nsections):
sec_idx = data.GetValue("$idx", self.offset + dof_difohdr_type.GetByteSize()
+ (i - 1) * dof_secidx_type.GetByteSize(),
dof_secidx_type).GetValueAsSigned()
sec = dof.GetSection(sec_idx)
if sec.stype == "DIF":
self.dif_idx = sec_idx
self.dif = sec
elif sec.stype == "STRTAB":
self.strtab_idx = sec_idx
self.strtab = sec
elif sec.stype == "INTTAB":
self.inttab_idx = sec_idx
self.inttab = sec
elif sec.stype == "VARTAB":
self.vartab_idx = sec_idx
self.vartab = sec
self.secs.append(sec_idx)
self.disassembler = DIFODisassembler(self.dif, self.strtab,
self.inttab, self.vartab)
def Show(self):
super(DOFDifoHdrSection, self).Show()
print 'DIF {} STRTAB {} INTTAB {} VARTAB {}'.format(
DOFSecIdxString(self.dif_idx),
DOFSecIdxString(self.strtab_idx),
DOFSecIdxString(self.inttab_idx),
DOFSecIdxString(self.vartab_idx)
)
self.disassembler.Disassemble()
section_classes = {
'ECBDESC': DOFEcbDescSection,
'PROBEDESC': DOFProbeDescSection,
'ACTDESC': DOFActDescSection,
'DIFOHDR': DOFDifoHdrSection,
'DIF': DOFDIFSection,
'STRTAB': DOFStrTabSection,
'VARTAB': DOFVarTabSection,
'PROVIDER': DOFProviderSection,
'INTTAB': DOFIntTabSection,
}
class DOF:
def __init__(self, target, data):
self.target = target
self.data = data
self.addr = data.GetAddr()
self.dof_sec_type = target.FindFirstType("dof_sec_t")
if not(self.dof_sec_type.IsValid()):
raise TypeError('Could not find dof_sec_t type. Do you have a kernel binary loaded ?')
return
self.header = DOFHeader(self, target, data)
self.sections = {}
for i in range(self.header.nsecs):
section = self.GetSection(i)
def GetSection(self, index):
"""Retrieves a section from the DOF, parsing it if it hasn't been
already"""
if index not in self.sections:
stype = self.GetSectionType(index)
if stype in section_classes:
SectionType = section_classes[stype]
else:
SectionType = DOFSection
self.sections[index] = SectionType(self, self.target, self.data, index)
return self.sections[index]
def Show(self):
self.header.Show()
print 'Sections:'
for i in range(len(self.sections)):
self.sections[i].Show()
def GetSectionType(self, i):
sec = self.data.GetValue("$sec", self.header.secoff +
self.header.secsize * i, self.dof_sec_type)
return section_names[GetMemberAsUnsigned(sec, "dofs_type")]
def __lldb_init_module(debugger, internal_dict):
debugger.HandleCommand('command script add -f dof.dof_command dof')
def show_dof_module(target, module):
print 'Printing DOFs for module {}'.format(module.GetFileSpec().GetFilename())
text_section = module.FindSection("__TEXT")
for i in range(text_section.GetNumSubSections()):
section = text_section.GetSubSectionAtIndex(i)
if section.GetName().find("dof_") != -1:
section_data = SectionData(target, section)
dof = DOF(target, section_data)
print 'Section {}'.format(section.GetName())
dof.Show()
def dof_command_section(debugger, args, result, internal_dict):
"""
Retrieves DOF data from DOF sections inside a specific module
"""
target = debugger.GetSelectedTarget()
if len(args) == 1:
return show_dof_module(target, target.GetModuleAtIndex(0))
subsubcommand = args[1]
if subsubcommand == 'index':
i = int(args[2])
return show_dof_module(target, target.GetModuleAtIndex(i))
elif subsubcommand == 'file':
filename = args[2]
filespec = lldb.SBFileSpec(filename)
return show_dof_module(target, target.FindModule(filespec))
elif subsubcommand == 'all':
for i in range(target.GetNumModules()):
show_dof_module(target, target.GetModuleAtIndex(i))
def dof_command_addr(debugger, args, result, internal_dict):
"""
Parses DOF from an address
"""
target = debugger.GetSelectedTarget()
dof_hdr_type = target.FindFirstType("dof_hdr_t")
if len(args) == 1:
return
addr = int(args[1], 0)
addr_data = AddrData(target, addr)
dof = DOF(target, addr_data)
dof.Show()
def dof_command(debugger, command, result, internal_dict):
args = shlex.split(command)
if len(args) == 0:
return
subcommand = args[0]
if subcommand == "section":
dof_command_section(debugger, args, result, internal_dict)
elif subcommand == "addr":
dof_command_addr(debugger, args, result, internal_dict)