1import lldb
2import re
3import getopt
4
5# Note: This module will eventually contain loads of macros. So please bear with the Macro/EndMacro comments
6
7
8# Global functions
9def findGlobal(variable):
10    return lldb.target.FindGlobalVariables(variable, 0).GetValueAtIndex(0)
11
12def findGlobalValue(variable):
13    return findGlobal(variable).GetValue()
14
15def readMemberUnsigned(variable,member):
16    return variable.GetChildMemberWithName(member).GetValueAsUnsigned(0)
17
18def readMemberSigned(variable,member):
19    return variable.GetChildMemberWithName(member).GetValueAsSigned()
20
21def readMemberString(variable,member):
22    return str(variable.GetChildMemberWithName(member).GetSummary()).strip('"')
23
24
25
26class Output :
27    """
28    An output handler for all command. Use Output.print to direct all output of macro via the handler.
29    Currently this provide capabilities
30    -o path/to/filename
31       The output of this command execution will be saved to file. Parser information or errors will
32       not be sent to file though. eg /tmp/output.txt
33    -s filter_string
34       the "filter_string" param is parsed to python regex expression and each line of output
35       will be printed/saved only if it matches the expression.
36       The command header will not be filtered in any case.
37    """
38    STDOUT  =1
39    FILEOUT =2
40    FILTER  =False
41
42    def __init__(self):
43        self.out = Output.STDOUT
44	self.fname=None
45	self.fhandle=None
46	self.FILTER=False
47
48    def printString(self, s):
49        """ Handler for all commands output. By default just print to stdout """
50        if self.FILTER and not self.reg.search(s): return
51        if self.out == Output.STDOUT: print s
52	elif self.out == Output.FILEOUT : self.fhandle.write(s+"\n")
53
54    def printHeader(self,s):
55        if self.out == Output.STDOUT: print s
56	elif self.out == Output.FILEOUT: self.fhandle.write(s+"\n")
57
58    def done(self):
59        """ closes any open files. report on any errors """
60        if self.fhandle != None :
61		self.fhandle.close()
62
63    def setOptions(self,args):
64        """ parse the arguments passed to the command
65	    param : args => [] of <str> (typically args.split())
66	"""
67        opts=()
68        try:
69	  opts,args = getopt.getopt(args,'o:s:',[])
70	except getopt.GetoptError,err:
71	  print str(err)
72	#continue with processing
73	for o,a in opts :
74	  if o == "-o" and len(a) > 0:
75            self.fname=a.strip()
76	    self.fhandle=open(self.fname,"w")
77	    self.out = Output.FILEOUT
78	    print "saving results in file ",str(a)
79	  elif o == "-s" and len(a) > 0:
80	    self.reg = re.compile(a.strip(),re.MULTILINE|re.DOTALL)
81	    self.FILTER=True
82	    print "showing results for regex:",a.strip()
83	  else :
84	    print "Error: unknown option ",o,a
85
86
87# Inteface function for showallkexts command
88def showallkexts_command(debugger, args, result, lldb_dict):
89    kext_summary_header = findGlobal("gLoadedKextSummaries")
90    result.Printf(_summarizeallkexts(kext_summary_header))
91    return None
92
93# Interface function for loaded kext summary formatter
94def showallkexts_summary(kext_summary_header, lldb_dict):
95    return "\n" + _summarizeallkexts(kext_summary_header)
96
97# Internal function for walking kext summaries
98def _summarizeallkexts(kext_summary_header):
99    summary = "ID  Address            Size              Version    Name\n"
100    summaries = kext_summary_header.GetChildMemberWithName("summaries")
101    count = int(kext_summary_header.GetChildMemberWithName("numSummaries").GetValue())
102    for i in range(0, count):
103        summary += summaries.GetChildAtIndex(i, lldb.eNoDynamicValues, True).GetSummary() + "\n"
104    return summary
105
106# Macro: memstats
107def memstats_command(debugger,args,result,lldb_dict):
108    stream = Output()
109    stream.setOptions(args.split())
110    memstats(stream)
111    stream.done()
112
113def memstats(ostream):
114    ostream.printString ( "kern_memorystatus_level: {0}".format(findGlobalValue("kern_memorystatus_level")) )
115    ostream.printString ( "vm_page_throttled_count: {0}".format(findGlobalValue("vm_page_throttled_count")) )
116    ostream.printString ( "vm_page_active_count:    {0}".format(findGlobalValue("vm_page_active_count")) )
117    ostream.printString ( "vm_page_inactive_count:  {0}".format(findGlobalValue("vm_page_inactive_count")) )
118    ostream.printString ( "vm_page_wire_count:      {0}".format(findGlobalValue("vm_page_wire_count")) )
119    ostream.printString ( "vm_page_free_count:      {0}".format(findGlobalValue("vm_page_free_count")) )
120    ostream.printString ( "vm_page_purgeable_count: {0}".format(findGlobalValue("vm_page_purgeable_count")) )
121    ostream.printString ( "vm_page_inactive_target: {0}".format(findGlobalValue("vm_page_inactive_target")) )
122    ostream.printString ( "vm_page_free_target:     {0}".format(findGlobalValue("vm_page_free_target")) )
123    ostream.printString ( "insue_ptepages_count:    {0}".format(findGlobalValue("inuse_ptepages_count")) )
124    ostream.printString ( "vm_page_free_reserved:   {0}".format(findGlobalValue("vm_page_free_reserved")) )
125# EndMacro: memstats
126
127
128# Macro: zprint
129def zprint_command(debugger,args,result,lldb_dict):
130    stream = Output()
131    stream.setOptions(args.split())
132    _zprint(stream)
133    stream.done()
134
135def _zprint(ostream):
136    """Display info about memory zones"""
137    ostream.printHeader ( "{0: ^20s} {1: >5s} {2: >12s} {3: >12s} {4: >7s} {5: >8s} {6: >9s} {7: >8s} {8: <20s} {9} ".format('ZONE', 'COUNT', 'TOT_SZ', 'MAX_SZ', 'ELT_SZ', 'ALLOC_SZ', 'TOT_ALLOC', 'TOT_FREE', 'NAME','') )
138    format_string = '{0: >#020x} {1: >5d} {2: >12d} {3: >12d} {4: >7d} {5: >8d} {6: >9d} {7: >8d} {8: <20s} {9}'
139    zone_ptr = findGlobal("first_zone");
140
141    while zone_ptr.GetValueAsUnsigned() != 0 :
142        addr = zone_ptr.GetValueAsUnsigned()
143	count = readMemberUnsigned(zone_ptr, "count")
144	cur_size = readMemberUnsigned(zone_ptr, "cur_size")
145	max_size = readMemberUnsigned(zone_ptr, "max_size")
146	elem_size = readMemberUnsigned(zone_ptr, "elem_size")
147	alloc_size = readMemberUnsigned(zone_ptr, "alloc_size")
148	num_allocs = readMemberUnsigned(zone_ptr, "num_allocs")
149	num_frees = readMemberUnsigned(zone_ptr, "num_frees")
150	name = str(readMemberString(zone_ptr, "zone_name"))
151	markings=""
152	if str(zone_ptr.GetChildMemberWithName("exhaustible").GetValue()) == '1' : markings+="H"
153	if str(zone_ptr.GetChildMemberWithName("collectable").GetValue()) == '1' : markings+="C"
154	if str(zone_ptr.GetChildMemberWithName("expandable").GetValue()) == '1' : markings+="X"
155	if str(zone_ptr.GetChildMemberWithName("noencrypt").GetValue()) == '1' : markings+="$"
156
157	ostream.printString(format_string.format(addr, count, cur_size, max_size, elem_size, alloc_size, num_allocs, num_frees, name, markings))
158
159	zone_ptr = zone_ptr.GetChildMemberWithName("next_zone")
160    return None
161# EndMacro: zprint
162
163
164# Macro: showioalloc
165def showioalloc_command(debugger,args,result,lldb_dict):
166    stream = Output()
167    stream.setOptions(args.split())
168    _showioalloc(stream)
169    stream.done()
170
171def _showioalloc(ostream):
172    ivars_size = findGlobal("debug_ivars_size").GetValueAsUnsigned()
173    container_malloc_size = findGlobal("debug_container_malloc_size").GetValueAsUnsigned()
174    iomalloc_size = findGlobal("debug_iomalloc_size").GetValueAsUnsigned()
175    iomallocpageable_size = findGlobal("debug_iomallocpageable_size").GetValueAsUnsigned()
176
177    ostream.printString("Instance allocation  = {0:#0x} = {1:d} K".format(ivars_size, (int)(ivars_size/1024)))
178    ostream.printString("Container allocation = {0:#0x} = {1:d} K".format(container_malloc_size,(int)(container_malloc_size/1024)))
179    ostream.printString("IOMalloc allocation  = {0:#0x} = {1:d} K".format(iomalloc_size,(int)(iomalloc_size/1024)))
180    ostream.printString("Pageable allocation  = {0:#0x} = {1:d} K".format(iomallocpageable_size,(int)(iomallocpageable_size/1024)))
181    return None
182# EndMacro: showioalloc
183
184
185