]> git.saurik.com Git - apple/xnu.git/blame - tools/lldbmacros/core/kernelcore.py
xnu-2422.1.72.tar.gz
[apple/xnu.git] / tools / lldbmacros / core / kernelcore.py
CommitLineData
39236c6e
A
1
2""" Please make sure you read the README COMPLETELY BEFORE reading anything below.
3 It is very critical that you read coding guidelines in Section E in README file.
4"""
5
6from cvalue import *
7from lazytarget import *
8from configuration import *
9import caching
10import lldb
11
12def IterateTAILQ_HEAD(headval, element_name):
13 """ iterate over a TAILQ_HEAD in kernel. refer to bsd/sys/queue.h
14 params:
15 headval - value : value object representing the head of the list
16 element_name- str : string name of the field which holds the list links.
17 returns:
18 A generator does not return. It is used for iterating.
19 value : an object that is of type as headval->tqh_first. Always a pointer object
20 example usage:
21 list_head = kern.GetGlobalVariable('mountlist')
22 for entryobj in IterateTAILQ_HEAD(list_head, 'mnt_list'):
23 print GetEntrySummary(entryobj)
24 """
25 iter_val = headval.tqh_first
26 while unsigned(iter_val) != 0 :
27 yield iter_val
28 iter_val = iter_val.__getattr__(element_name).tqe_next
29 #end of yield loop
30
31def IterateLinkedList(element, field_name):
32 """ iterate over a linked list.
33 This is equivalent to elt = element; while(elt) { do_work(elt); elt = elt-><field_name>; }
34 params:
35 element - value : value object representing element in the list.
36 field_name - str : name of field that holds pointer to next element
37 returns: Nothing. This is used as iterable
38 example usage:
39 first_zone = kern.GetGlobalVariable('first_zone')
40 for zone in IterateLinkedList(first_zone, 'next_zone'):
41 print GetZoneSummary(zone)
42 """
43 elt = element
44 while unsigned(elt) != 0:
45 yield elt
46 elt = elt.__getattr__(field_name)
47 #end of while loop
48
49def IterateListEntry(element, element_type, field_name):
50 """ iterate over a list as defined with LIST_HEAD in bsd/sys/queue.h
51 params:
52 element - value : Value object for lh_first
53 element_type - str : Type of the next element
54 field_name - str : Name of the field in next element's structure
55 returns:
56 A generator does not return. It is used for iterating
57 value : an object thats of type (element_type) head->le_next. Always a pointer object
58 example usage:
59 headp = kern.globals.initproc.p_children
60 for pp in IterateListEntry(headp, 'struct proc *', 'p_sibling'):
61 print GetProcInfo(pp)
62 """
63 elt = element.lh_first
64 if type(element_type) == str:
65 element_type = gettype(element_type)
66 while unsigned(elt) != 0:
67 yield elt
68 next_el = elt.__getattr__(field_name).le_next
69 elt = cast(next_el, element_type)
70
71def IterateQueue(queue_head, element_ptr_type, element_field_name):
72 """ iterate over a queue in kernel of type queue_head_t. refer to osfmk/kern/queue.h
73 params:
74 queue_head - value : Value object for queue_head.
75 element_ptr_type - lldb.SBType : a pointer type of the element 'next' points to. Typically its structs like thread, task etc..
76 - str : OR a string describing the type. ex. 'task *'
77 element_field_name - str : name of the field in target struct.
78 returns:
79 A generator does not return. It is used for iterating.
80 value : an object thats of type (element_type) queue_head->next. Always a pointer object
81 """
82 if type(element_ptr_type) == str :
83 element_ptr_type = gettype(element_ptr_type)
84
85 queue_head = queue_head.GetSBValue()
86 queue_head_addr = 0x0
87 if queue_head.TypeIsPointerType():
88 queue_head_addr = queue_head.GetValueAsUnsigned()
89 else:
90 queue_head_addr = queue_head.GetAddress().GetLoadAddress(LazyTarget.GetTarget())
91 cur_elt = queue_head.GetChildMemberWithName('next')
92 while True:
93
94 if not cur_elt.IsValid() or cur_elt.GetValueAsUnsigned() == 0 or cur_elt.GetValueAsUnsigned() == queue_head_addr:
95 break
96 elt = cur_elt.Cast(element_ptr_type)
97 yield value(elt)
98 cur_elt = elt.GetChildMemberWithName(element_field_name).GetChildMemberWithName('next')
99
100
101
102class KernelTarget(object):
103 """ A common kernel object that provides access to kernel objects and information.
104 The class holds global lists for task, terminated_tasks, procs, zones, zombroc etc.
105 It also provides a way to symbolicate an address or create a value from an address.
106 """
107 def __init__(self, debugger):
108 """ Initialize the kernel debugging environment.
109 Target properties like architecture and connectedness are lazy-evaluted.
110 """
111 self._debugger = debugger # This holds an lldb.SBDebugger object for debugger state
112 self._threads_list = []
113 self._tasks_list = []
114 self._allproc = []
115 self._terminated_tasks_list = []
116 self._zones_list = []
117 self._zombproc_list = []
118 self._kernel_types_cache = {} #this will cache the Type objects as and when requested.
119 self._version = None
120 self._arch = None
121 self._ptrsize = None # pointer size of kernel, not userspace
122 self.symbolicator = None
123 class _GlobalVariableFind(object):
124 def __init__(self, kern):
125 self._xnu_kernobj_12obscure12 = kern
126 def __getattr__(self, name):
127 v = self._xnu_kernobj_12obscure12.GetGlobalVariable(name)
128 if not v.GetSBValue().IsValid():
129 raise ValueError('no such global variable by name: %s '%str(name))
130 return v
131 self.globals = _GlobalVariableFind(self)
132 LazyTarget.Initialize(debugger)
133
134 def _GetSymbolicator(self):
135 """ Internal function: To initialize the symbolication from lldb.utils
136 """
137 if not self.symbolicator is None:
138 return self.symbolicator
139
140 from lldb.utils import symbolication
141 symbolicator = symbolication.Symbolicator()
142 symbolicator.target = LazyTarget.GetTarget()
143 self.symbolicator = symbolicator
144 return self.symbolicator
145
146 def Symbolicate(self, addr):
147 """ simple method to get name of function/variable from an address. this is equivalent of gdb 'output /a 0xaddress'
148 params:
149 addr - int : typically hex value like 0xffffff80002c0df0
150 returns:
151 str - '' if no symbol found else the symbol name.
152 Note: this function only finds the first symbol. If you expect multiple symbol conflict please use SymbolicateFromAddress()
153 """
154 ret_str = ''
155 syms = self.SymbolicateFromAddress(addr)
156 if len(syms) > 0:
157 ret_str +=syms[0].GetName()
158 return ret_str
159
160 def SymbolicateFromAddress(self, addr):
161 """ symbolicates any given address based on modules loaded in the target.
162 params:
163 addr - int : typically hex value like 0xffffff80002c0df0
164 returns:
165 [] of SBSymbol: In case we don't find anything than empty array is returned.
166 Note: a type of symbol can be figured out by gettype() function of SBSymbol.
167 example usage:
168 syms = kern.Symbolicate(0xffffff80002c0df0)
169 for s in syms:
170 if s.GetType() == lldb.eSymbolTypeCode:
171 print "Function", s.GetName()
172 if s.GetType() == lldb.eSymbolTypeData:
173 print "Variable", s.GetName()
174 """
175 if type(int(1)) != type(addr):
176 if str(addr).strip().find("0x") == 0 :
177 addr = int(addr, 16)
178 else:
179 addr = int(addr)
180 ret_array = []
181 symbolicator = self._GetSymbolicator()
182 syms = symbolicator.symbolicate(addr)
183 if not syms:
184 return ret_array
185 for s in syms:
186 ret_array.append(s.get_symbol_context().symbol)
187 return ret_array
188
189 def IsDebuggerConnected(self):
190 proc_state = LazyTarget.GetProcess().state
191 if proc_state == lldb.eStateInvalid : return False
192 if proc_state in [lldb.eStateStopped, lldb.eStateSuspended] : return True
193
194 def GetGlobalVariable(self, name):
195 """ Get the value object representation for a kernel global variable
196 params:
197 name : str - name of the variable. ex. version
198 returns: value - python object representing global variable.
199 raises : Exception in case the variable is not found.
200 """
201 return value(LazyTarget.GetTarget().FindGlobalVariables(name, 0).GetValueAtIndex(0))
202
203 def GetLoadAddressForSymbol(self, name):
204 """ Get the load address of a symbol in the kernel.
205 params:
206 name : str - name of the symbol to lookup
207 returns: int - the load address as an integer. Use GetValueFromAddress to cast to a value.
208 raises : LookupError - if the symbol is not found.
209 """
210 name = str(name)
211 target = LazyTarget.GetTarget()
212 syms_arr = target.FindSymbols(name)
213 if syms_arr.IsValid() and len(syms_arr) > 0:
214 symbol = syms_arr[0].GetSymbol()
215 if symbol.IsValid():
216 return int(symbol.GetStartAddress().GetLoadAddress(target))
217
218 raise LookupError("Symbol not found: " + name)
219
220 def GetValueFromAddress(self, addr, type_str = 'void *'):
221 """ convert a address to value
222 params:
223 addr - int : typically hex value like 0xffffff80008dc390
224 type_str - str: type to cast to. Default type will be void *
225 returns:
226 value : a value object which has address as addr and type is type_str
227 """
228 obj = value(self.globals.version.GetSBValue().CreateValueFromExpression(None,'(void *)'+str(addr)))
229 obj = cast(obj, type_str)
230 return obj
231
232 def GetValueAsType(self, v, t):
233 """ Retrieves a global variable 'v' of type 't' wrapped in a vue object.
234 If 'v' is an address, creates a vue object of the appropriate type.
235 If 'v' is a name, looks for the global variable and asserts its type.
236 Throws:
237 NameError - If 'v' cannot be found
238 TypeError - If 'v' is of the wrong type
239 """
240 if islong(v):
241 return self.GetValueFromAddress(v, t)
242 else:
243 var = LazyTarget.GetTarget().FindGlobalVariables(v, 1)[0]
244 if not var:
245 raise NameError("Failed to find global variable '{0}'".format(v))
246 if var.GetTypeName() != t:
247 raise TypeError("{0} must be of type '{1}', not '{2}'".format(v, t, var.GetTypeName()))
248 return value(var)
249
250 def _GetIterator(self, iter_head_name, next_element_name='next', iter_head_type=None):
251 """ returns an iterator for a collection in kernel memory.
252 params:
253 iter_head_name - str : name of queue_head or list head variable.
254 next_element_name - str : name of the element that leads to next element.
255 for ex. in struct zone list 'next_zone' is the linking element.
256 returns:
257 iterable : typically used in conjunction with "for varname in iterable:"
258 """
259 head_element = self.GetGlobalVariable(iter_head_name)
260 return head_element.GetSBValue().linked_list_iter(next_element_name)
261
262 def TruncPage(self, addr):
263 return (addr & ~(unsigned(self.GetGlobalVariable("page_size")) - 1))
264
265 def RoundPage(self, addr):
266 return trunc_page(addr + unsigned(self.GetGlobalVariable("page_size")) - 1)
267
268 def StraddlesPage(self, addr, size):
269 if size > unsigned(self.GetGlobalVariable("page_size")):
270 return True
271 return (((addr + size) & (unsigned(self.GetGlobalVariable("page_size"))-1)) < size)
272
273 def PhysToKernelVirt(self, addr):
274 if self.arch == 'x86_64':
275 return (addr + unsigned(self.GetGlobalVariable('physmap_base')))
276 elif self.arch == 'arm':
277 return (addr - unsigned(self.GetGlobalVariable("gPhysBase")) + unsigned(self.GetGlobalVariable("gVirtBase")))
278 else:
279 raise ValueError("PhysToVirt does not support {0}".format(arch))
280
281 def __getattribute__(self, name):
282 if name == 'zones' :
283 self._zones_list = caching.GetDynamicCacheData("kern._zones_list", [])
284 if len(self._zones_list) > 0: return self._zones_list
285 first_zone = self.GetGlobalVariable('first_zone')
286 for z in IterateLinkedList(first_zone, 'next_zone'):
287 self._zones_list.append(z)
288 caching.SaveDynamicCacheData("kern._zones_list", self._zones_list)
289 return self._zones_list
290
291 if name == 'threads' :
292 self._threads_list = caching.GetDynamicCacheData("kern._threads_list", [])
293 if len(self._threads_list) > 0 : return self._threads_list
294 thread_queue_head = self.GetGlobalVariable('threads')
295 thread_type = LazyTarget.GetTarget().FindFirstType('thread')
296 thread_ptr_type = thread_type.GetPointerType()
297 for th in IterateQueue(thread_queue_head, thread_ptr_type, 'threads'):
298 self._threads_list.append(th)
299 caching.SaveDynamicCacheData("kern._threads_list", self._threads_list)
300 return self._threads_list
301
302 if name == 'tasks' :
303 self._tasks_list = caching.GetDynamicCacheData("kern._tasks_list", [])
304 if len(self._tasks_list) > 0 : return self._tasks_list
305 task_queue_head = self.GetGlobalVariable('tasks')
306 task_type = LazyTarget.GetTarget().FindFirstType('task')
307 task_ptr_type = task_type.GetPointerType()
308 for tsk in IterateQueue(task_queue_head, task_ptr_type, 'tasks'):
309 self._tasks_list.append(tsk)
310 caching.SaveDynamicCacheData("kern._tasks_list", self._tasks_list)
311 return self._tasks_list
312
313 if name == 'terminated_tasks' :
314 self._terminated_tasks_list = caching.GetDynamicCacheData("kern._terminated_tasks_list", [])
315 if len(self._terminated_tasks_list) > 0 : return self._terminated_tasks_list
316 task_queue_head = self.GetGlobalVariable('terminated_tasks')
317 task_type = LazyTarget.GetTarget().FindFirstType('task')
318 task_ptr_type = task_type.GetPointerType()
319 for tsk in IterateQueue(task_queue_head, task_ptr_type, 'tasks'):
320 self._terminated_tasks_list.append(tsk)
321 caching.SaveDynamicCacheData("kern._terminated_tasks_list", self._terminated_tasks_list)
322 return self._terminated_tasks_list
323
324 if name == 'procs' :
325 self._allproc = caching.GetDynamicCacheData("kern._allproc", [])
326 if len(self._allproc) > 0 : return self._allproc
327 all_proc_head = self.GetGlobalVariable('allproc')
328 proc_val = cast(all_proc_head.lh_first, 'proc *')
329 while proc_val != 0:
330 self._allproc.append(proc_val)
331 proc_val = cast(proc_val.p_list.le_next, 'proc *')
332 caching.SaveDynamicCacheData("kern._allproc", self._allproc)
333 return self._allproc
334
335 if name == 'zombprocs' :
336 self._zombproc_list = caching.GetDynamicCacheData("kern._zombproc_list", [])
337 if len(self._zombproc_list) > 0 : return self._zombproc_list
338 zproc_head = self.GetGlobalVariable('zombproc')
339 proc_val = cast(zproc_head.lh_first, 'proc *')
340 while proc_val != 0:
341 self._zombproc_list.append(proc_val)
342 proc_val = cast(proc_val.p_list.le_next, 'proc *')
343 caching.SaveDynamicCacheData("kern._zombproc_list", self._zombproc_list)
344 return self._zombproc_list
345
346 if name == 'version' :
347 self._version = caching.GetStaticCacheData("kern.version", None)
348 if self._version != None : return self._version
349 self._version = str(self.GetGlobalVariable('version'))
350 caching.SaveStaticCacheData("kern.version", self._version)
351 return self._version
352
353 if name == 'arch' :
354 self._arch = caching.GetStaticCacheData("kern.arch", None)
355 if self._arch != None : return self._arch
356 arch = LazyTarget.GetTarget().triple.split('-')[0]
357 if arch in ('armv7', 'armv7s'):
358 self._arch = 'arm'
359 else:
360 self._arch = arch
361 caching.SaveStaticCacheData("kern.arch", self._arch)
362 return self._arch
363
364 if name == 'ptrsize' :
365 self._ptrsize = caching.GetStaticCacheData("kern.ptrsize", None)
366 if self._ptrsize != None : return self._ptrsize
367 arch = LazyTarget.GetTarget().triple.split('-')[0]
368 if arch in ('x86_64'):
369 self._ptrsize = 8
370 else:
371 self._ptrsize = 4
372 caching.SaveStaticCacheData("kern.ptrsize", self._ptrsize)
373 return self._ptrsize
374
375 return object.__getattribute__(self, name)
376