]>
git.saurik.com Git - apple/xnu.git/blob - tools/lldbmacros/core/kernelcore.py
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.
7 from lazytarget
import *
8 from configuration
import *
12 def IterateTAILQ_HEAD(headval
, element_name
):
13 """ iterate over a TAILQ_HEAD in kernel. refer to bsd/sys/queue.h
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.
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
21 list_head = kern.GetGlobalVariable('mountlist')
22 for entryobj in IterateTAILQ_HEAD(list_head, 'mnt_list'):
23 print GetEntrySummary(entryobj)
25 iter_val
= headval
.tqh_first
26 while unsigned(iter_val
) != 0 :
28 iter_val
= iter_val
.__getattr
__(element_name
).tqe_next
31 def 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>; }
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
39 first_zone = kern.GetGlobalVariable('first_zone')
40 for zone in IterateLinkedList(first_zone, 'next_zone'):
41 print GetZoneSummary(zone)
44 while unsigned(elt
) != 0:
46 elt
= elt
.__getattr
__(field_name
)
49 def IterateListEntry(element
, element_type
, field_name
):
50 """ iterate over a list as defined with LIST_HEAD in bsd/sys/queue.h
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
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
59 headp = kern.globals.initproc.p_children
60 for pp in IterateListEntry(headp, 'struct proc *', 'p_sibling'):
63 elt
= element
.lh_first
64 if type(element_type
) == str:
65 element_type
= gettype(element_type
)
66 while unsigned(elt
) != 0:
68 next_el
= elt
.__getattr
__(field_name
).le_next
69 elt
= cast(next_el
, element_type
)
71 def 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
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.
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
82 if type(element_ptr_type
) == str :
83 element_ptr_type
= gettype(element_ptr_type
)
85 queue_head
= queue_head
.GetSBValue()
87 if queue_head
.TypeIsPointerType():
88 queue_head_addr
= queue_head
.GetValueAsUnsigned()
90 queue_head_addr
= queue_head
.GetAddress().GetLoadAddress(LazyTarget
.GetTarget())
91 cur_elt
= queue_head
.GetChildMemberWithName('next')
94 if not cur_elt
.IsValid() or cur_elt
.GetValueAsUnsigned() == 0 or cur_elt
.GetValueAsUnsigned() == queue_head_addr
:
96 elt
= cur_elt
.Cast(element_ptr_type
)
98 cur_elt
= elt
.GetChildMemberWithName(element_field_name
).GetChildMemberWithName('next')
102 class 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.
107 def __init__(self
, debugger
):
108 """ Initialize the kernel debugging environment.
109 Target properties like architecture and connectedness are lazy-evaluted.
111 self
._debugger
= debugger
# This holds an lldb.SBDebugger object for debugger state
112 self
._threads
_list
= []
113 self
._tasks
_list
= []
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.
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
_12obscure
12 = kern
126 def __getattr__(self
, name
):
127 v
= self
._xnu
_kernobj
_12obscure
12.GetGlobalVariable(name
)
128 if not v
.GetSBValue().IsValid():
129 raise ValueError('no such global variable by name: %s '%str
(name
))
131 self
.globals = _GlobalVariableFind(self
)
132 LazyTarget
.Initialize(debugger
)
134 def _GetSymbolicator(self
):
135 """ Internal function: To initialize the symbolication from lldb.utils
137 if not self
.symbolicator
is None:
138 return self
.symbolicator
140 from lldb
.utils
import symbolication
141 symbolicator
= symbolication
.Symbolicator()
142 symbolicator
.target
= LazyTarget
.GetTarget()
143 self
.symbolicator
= symbolicator
144 return self
.symbolicator
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'
149 addr - int : typically hex value like 0xffffff80002c0df0
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()
155 syms
= self
.SymbolicateFromAddress(addr
)
157 ret_str
+=syms
[0].GetName()
160 def SymbolicateFromAddress(self
, addr
):
161 """ symbolicates any given address based on modules loaded in the target.
163 addr - int : typically hex value like 0xffffff80002c0df0
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.
168 syms = kern.Symbolicate(0xffffff80002c0df0)
170 if s.GetType() == lldb.eSymbolTypeCode:
171 print "Function", s.GetName()
172 if s.GetType() == lldb.eSymbolTypeData:
173 print "Variable", s.GetName()
175 if type(int(1)) != type(addr
):
176 if str(addr
).strip().find("0x") == 0 :
181 symbolicator
= self
._GetSymbolicator
()
182 syms
= symbolicator
.symbolicate(addr
)
186 ret_array
.append(s
.get_symbol_context().symbol
)
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
194 def GetGlobalVariable(self
, name
):
195 """ Get the value object representation for a kernel global variable
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.
201 return value(LazyTarget
.GetTarget().FindGlobalVariables(name
, 0).GetValueAtIndex(0))
203 def GetLoadAddressForSymbol(self
, name
):
204 """ Get the load address of a symbol in the kernel.
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.
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()
216 return int(symbol
.GetStartAddress().GetLoadAddress(target
))
218 raise LookupError("Symbol not found: " + name
)
220 def GetValueFromAddress(self
, addr
, type_str
= 'void *'):
221 """ convert a address to value
223 addr - int : typically hex value like 0xffffff80008dc390
224 type_str - str: type to cast to. Default type will be void *
226 value : a value object which has address as addr and type is type_str
228 obj
= value(self
.globals.version
.GetSBValue().CreateValueFromExpression(None,'(void *)'+str(addr
)))
229 obj
= cast(obj
, type_str
)
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.
237 NameError - If 'v' cannot be found
238 TypeError - If 'v' is of the wrong type
241 return self
.GetValueFromAddress(v
, t
)
243 var
= LazyTarget
.GetTarget().FindGlobalVariables(v
, 1)[0]
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()))
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.
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.
257 iterable : typically used in conjunction with "for varname in iterable:"
259 head_element
= self
.GetGlobalVariable(iter_head_name
)
260 return head_element
.GetSBValue().linked_list_iter(next_element_name
)
262 def TruncPage(self
, addr
):
263 return (addr
& ~
(unsigned(self
.GetGlobalVariable("page_size")) - 1))
265 def RoundPage(self
, addr
):
266 return trunc_page(addr
+ unsigned(self
.GetGlobalVariable("page_size")) - 1)
268 def StraddlesPage(self
, addr
, size
):
269 if size
> unsigned(self
.GetGlobalVariable("page_size")):
271 return (((addr
+ size
) & (unsigned(self
.GetGlobalVariable("page_size"))-1)) < size
)
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")))
279 raise ValueError("PhysToVirt does not support {0}".format(arch
))
281 def __getattribute__(self
, name
):
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
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
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
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
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 *')
330 self
._allproc
.append(proc_val
)
331 proc_val
= cast(proc_val
.p_list
.le_next
, 'proc *')
332 caching
.SaveDynamicCacheData("kern._allproc", self
._allproc
)
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 *')
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
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
)
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'):
361 caching
.SaveStaticCacheData("kern.arch", self
._arch
)
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'):
372 caching
.SaveStaticCacheData("kern.ptrsize", self
._ptrsize
)
375 return object.__getattribute
__(self
, name
)