]>
Commit | Line | Data |
---|---|---|
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 | ||
6 | from cvalue import * | |
7 | from lazytarget import * | |
8 | from configuration import * | |
d9a64523 | 9 | from utils import * |
39236c6e A |
10 | import caching |
11 | import lldb | |
12 | ||
13 | def IterateTAILQ_HEAD(headval, element_name): | |
14 | """ iterate over a TAILQ_HEAD in kernel. refer to bsd/sys/queue.h | |
15 | params: | |
16 | headval - value : value object representing the head of the list | |
17 | element_name- str : string name of the field which holds the list links. | |
18 | returns: | |
19 | A generator does not return. It is used for iterating. | |
20 | value : an object that is of type as headval->tqh_first. Always a pointer object | |
21 | example usage: | |
22 | list_head = kern.GetGlobalVariable('mountlist') | |
23 | for entryobj in IterateTAILQ_HEAD(list_head, 'mnt_list'): | |
24 | print GetEntrySummary(entryobj) | |
25 | """ | |
26 | iter_val = headval.tqh_first | |
27 | while unsigned(iter_val) != 0 : | |
28 | yield iter_val | |
29 | iter_val = iter_val.__getattr__(element_name).tqe_next | |
30 | #end of yield loop | |
31 | ||
32 | def IterateLinkedList(element, field_name): | |
33 | """ iterate over a linked list. | |
34 | This is equivalent to elt = element; while(elt) { do_work(elt); elt = elt-><field_name>; } | |
35 | params: | |
36 | element - value : value object representing element in the list. | |
37 | field_name - str : name of field that holds pointer to next element | |
38 | returns: Nothing. This is used as iterable | |
39 | example usage: | |
40 | first_zone = kern.GetGlobalVariable('first_zone') | |
41 | for zone in IterateLinkedList(first_zone, 'next_zone'): | |
42 | print GetZoneSummary(zone) | |
43 | """ | |
44 | elt = element | |
45 | while unsigned(elt) != 0: | |
46 | yield elt | |
47 | elt = elt.__getattr__(field_name) | |
48 | #end of while loop | |
49 | ||
5ba3f43e | 50 | def IterateListEntry(element, element_type, field_name, list_prefix=''): |
39236c6e A |
51 | """ iterate over a list as defined with LIST_HEAD in bsd/sys/queue.h |
52 | params: | |
53 | element - value : Value object for lh_first | |
54 | element_type - str : Type of the next element | |
55 | field_name - str : Name of the field in next element's structure | |
cc8bc92a | 56 | list_prefix - str : use 's' here to iterate SLIST_HEAD instead |
39236c6e A |
57 | returns: |
58 | A generator does not return. It is used for iterating | |
59 | value : an object thats of type (element_type) head->le_next. Always a pointer object | |
60 | example usage: | |
61 | headp = kern.globals.initproc.p_children | |
62 | for pp in IterateListEntry(headp, 'struct proc *', 'p_sibling'): | |
63 | print GetProcInfo(pp) | |
64 | """ | |
5ba3f43e | 65 | elt = element.__getattr__(list_prefix + 'lh_first') |
39236c6e A |
66 | if type(element_type) == str: |
67 | element_type = gettype(element_type) | |
68 | while unsigned(elt) != 0: | |
69 | yield elt | |
5ba3f43e | 70 | next_el = elt.__getattr__(field_name).__getattr__(list_prefix + 'le_next') |
39236c6e A |
71 | elt = cast(next_el, element_type) |
72 | ||
3e170ce0 A |
73 | def IterateLinkageChain(queue_head, element_type, field_name, field_ofst=0): |
74 | """ Iterate over a Linkage Chain queue in kernel of type queue_head_t. (osfmk/kern/queue.h method 1) | |
75 | This is equivalent to the qe_foreach_element() macro | |
76 | params: | |
77 | queue_head - value : Value object for queue_head. | |
78 | element_type - lldb.SBType : pointer type of the element which contains the queue_chain_t. Typically its structs like thread, task etc.. | |
79 | - str : OR a string describing the type. ex. 'task *' | |
80 | field_name - str : Name of the field (in element) which holds a queue_chain_t | |
81 | field_ofst - int : offset from the 'field_name' (in element) which holds a queue_chain_t | |
82 | This is mostly useful if a particular element contains an array of queue_chain_t | |
83 | returns: | |
84 | A generator does not return. It is used for iterating. | |
85 | value : An object thats of type (element_type). Always a pointer object | |
86 | example usage: | |
87 | coalq = kern.GetGlobalVariable('coalitions_q') | |
88 | for coal in IterateLinkageChain(coalq, 'struct coalition *', 'coalitions'): | |
89 | print GetCoalitionInfo(coal) | |
90 | """ | |
91 | global kern | |
92 | if type(element_type) == str: | |
93 | element_type = gettype(element_type) | |
94 | ||
95 | if unsigned(queue_head) == 0: | |
96 | return | |
97 | ||
98 | if element_type.IsPointerType(): | |
99 | elem_ofst = getfieldoffset(element_type.GetPointeeType(), field_name) + field_ofst | |
100 | else: | |
101 | elem_ofst = getfieldoffset(element_type, field_name) + field_ofst | |
102 | ||
103 | link = queue_head.next | |
104 | while (unsigned(link) != unsigned(queue_head)): | |
105 | addr = unsigned(link) - elem_ofst; | |
106 | # I can't use the GetValueFromAddress function of the kernel class | |
107 | # because I have no instance of that class! | |
108 | obj = value(link.GetSBValue().CreateValueFromExpression(None,'(void *)'+str(addr))) | |
109 | obj = cast(obj, element_type) | |
110 | yield obj | |
111 | link = link.next | |
112 | ||
ea3f0419 A |
113 | def IterateCircleQueue(queue_head, element_ptr_type, element_field_name): |
114 | """ iterate over a circle queue in kernel of type circle_queue_head_t. refer to osfmk/kern/circle_queue.h | |
115 | params: | |
116 | queue_head - lldb.SBValue : Value object for queue_head. | |
117 | element_type - lldb.SBType : a pointer type of the element 'next' points to. Typically its structs like thread, task etc.. | |
118 | element_field_name - str : name of the field in target struct. | |
119 | returns: | |
120 | A generator does not return. It is used for iterating. | |
121 | SBValue : an object thats of type (element_type) queue_head->next. Always a pointer object | |
122 | """ | |
123 | head = queue_head.head.GetSBValue() | |
124 | queue_head_addr = 0x0 | |
125 | if head.TypeIsPointerType(): | |
126 | queue_head_addr = head.GetValueAsUnsigned() | |
127 | else: | |
128 | queue_head_addr = head.GetAddress().GetLoadAddress(osplugin_target_obj) | |
129 | cur_elt = head | |
130 | while True: | |
131 | if not cur_elt.IsValid() or cur_elt.GetValueAsUnsigned() == 0: | |
132 | break | |
133 | yield containerof(value(cur_elt), element_ptr_type, element_field_name) | |
134 | cur_elt = cur_elt.GetChildMemberWithName('next') | |
135 | if cur_elt.GetValueAsUnsigned() == queue_head_addr: | |
136 | break | |
3e170ce0 | 137 | |
39037602 | 138 | def IterateQueue(queue_head, element_ptr_type, element_field_name, backwards=False, unpack_ptr_fn=None): |
3e170ce0 | 139 | """ Iterate over an Element Chain queue in kernel of type queue_head_t. (osfmk/kern/queue.h method 2) |
39236c6e A |
140 | params: |
141 | queue_head - value : Value object for queue_head. | |
3e170ce0 | 142 | element_ptr_type - lldb.SBType : a pointer type of the element 'next' points to. Typically its structs like thread, task etc.. |
39236c6e A |
143 | - str : OR a string describing the type. ex. 'task *' |
144 | element_field_name - str : name of the field in target struct. | |
3e170ce0 | 145 | backwards - backwards : traverse the queue backwards |
39037602 | 146 | unpack_ptr_fn - function : a function ptr of signature def unpack_ptr(long v) which returns long. |
39236c6e A |
147 | returns: |
148 | A generator does not return. It is used for iterating. | |
149 | value : an object thats of type (element_type) queue_head->next. Always a pointer object | |
fe8ab488 A |
150 | example usage: |
151 | for page_meta in IterateQueue(kern.globals.first_zone.pages.all_free, 'struct zone_page_metadata *', 'pages'): | |
152 | print page_meta | |
39236c6e A |
153 | """ |
154 | if type(element_ptr_type) == str : | |
155 | element_ptr_type = gettype(element_ptr_type) | |
156 | ||
157 | queue_head = queue_head.GetSBValue() | |
158 | queue_head_addr = 0x0 | |
159 | if queue_head.TypeIsPointerType(): | |
160 | queue_head_addr = queue_head.GetValueAsUnsigned() | |
161 | else: | |
162 | queue_head_addr = queue_head.GetAddress().GetLoadAddress(LazyTarget.GetTarget()) | |
39037602 A |
163 | |
164 | def unpack_ptr_and_recast(v): | |
165 | if unpack_ptr_fn is None: | |
166 | return v | |
167 | v_unpacked = unpack_ptr_fn(v.GetValueAsUnsigned()) | |
168 | obj = v.CreateValueFromExpression(None,'(void *)'+str(v_unpacked)) | |
169 | obj.Cast(element_ptr_type) | |
170 | return obj | |
171 | ||
3e170ce0 | 172 | if backwards: |
39037602 | 173 | cur_elt = unpack_ptr_and_recast(queue_head.GetChildMemberWithName('prev')) |
3e170ce0 | 174 | else: |
39037602 | 175 | cur_elt = unpack_ptr_and_recast(queue_head.GetChildMemberWithName('next')) |
3e170ce0 | 176 | |
39236c6e A |
177 | while True: |
178 | ||
179 | if not cur_elt.IsValid() or cur_elt.GetValueAsUnsigned() == 0 or cur_elt.GetValueAsUnsigned() == queue_head_addr: | |
180 | break | |
181 | elt = cur_elt.Cast(element_ptr_type) | |
182 | yield value(elt) | |
3e170ce0 | 183 | if backwards: |
39037602 | 184 | cur_elt = unpack_ptr_and_recast(elt.GetChildMemberWithName(element_field_name).GetChildMemberWithName('prev')) |
3e170ce0 | 185 | else: |
39037602 A |
186 | cur_elt = unpack_ptr_and_recast(elt.GetChildMemberWithName(element_field_name).GetChildMemberWithName('next')) |
187 | ||
39236c6e | 188 | |
cc8bc92a A |
189 | def IterateRBTreeEntry(element, element_type, field_name): |
190 | """ iterate over a rbtree as defined with RB_HEAD in libkern/tree.h | |
191 | element - value : Value object for rbh_root | |
192 | element_type - str : Type of the link element | |
193 | field_name - str : Name of the field in link element's structure | |
194 | returns: | |
195 | A generator does not return. It is used for iterating | |
196 | value : an object thats of type (element_type) head->sle_next. Always a pointer object | |
197 | """ | |
198 | elt = element.__getattr__('rbh_root') | |
199 | if type(element_type) == str: | |
200 | element_type = gettype(element_type) | |
201 | ||
202 | # Walk to find min | |
203 | parent = elt | |
204 | while unsigned(elt) != 0: | |
205 | parent = elt | |
206 | elt = cast(elt.__getattr__(field_name).__getattr__('rbe_left'), element_type) | |
207 | elt = parent | |
208 | ||
209 | # Now elt is min | |
210 | while unsigned(elt) != 0: | |
211 | yield elt | |
212 | # implementation cribbed from RB_NEXT in libkern/tree.h | |
213 | right = cast(elt.__getattr__(field_name).__getattr__('rbe_right'), element_type) | |
214 | if unsigned(right) != 0: | |
215 | elt = right | |
216 | left = cast(elt.__getattr__(field_name).__getattr__('rbe_left'), element_type) | |
217 | while unsigned(left) != 0: | |
218 | elt = left | |
219 | left = cast(elt.__getattr__(field_name).__getattr__('rbe_left'), element_type) | |
220 | else: | |
221 | ||
222 | # avoid using GetValueFromAddress | |
223 | addr = elt.__getattr__(field_name).__getattr__('rbe_parent')&~1 | |
224 | parent = value(elt.GetSBValue().CreateValueFromExpression(None,'(void *)'+str(addr))) | |
225 | parent = cast(parent, element_type) | |
226 | ||
227 | if unsigned(parent) != 0: | |
228 | left = cast(parent.__getattr__(field_name).__getattr__('rbe_left'), element_type) | |
229 | if (unsigned(parent) != 0) and (unsigned(elt) == unsigned(left)): | |
230 | elt = parent | |
231 | else: | |
232 | if unsigned(parent) != 0: | |
233 | right = cast(parent.__getattr__(field_name).__getattr__('rbe_right'), element_type) | |
234 | while unsigned(parent) != 0 and (unsigned(elt) == unsigned(right)): | |
235 | elt = parent | |
236 | ||
237 | # avoid using GetValueFromAddress | |
238 | addr = elt.__getattr__(field_name).__getattr__('rbe_parent')&~1 | |
239 | parent = value(elt.GetSBValue().CreateValueFromExpression(None,'(void *)'+str(addr))) | |
240 | parent = cast(parent, element_type) | |
241 | ||
242 | right = cast(parent.__getattr__(field_name).__getattr__('rbe_right'), element_type) | |
243 | ||
244 | # avoid using GetValueFromAddress | |
245 | addr = elt.__getattr__(field_name).__getattr__('rbe_parent')&~1 | |
246 | elt = value(elt.GetSBValue().CreateValueFromExpression(None,'(void *)'+str(addr))) | |
247 | elt = cast(elt, element_type) | |
248 | ||
249 | ||
f427ee49 | 250 | def IterateSchedPriorityQueue(root, element_type, field_name): |
d9a64523 A |
251 | """ iterate over a priority queue as defined with struct priority_queue from osfmk/kern/priority_queue.h |
252 | root - value : Value object for the priority queue | |
253 | element_type - str : Type of the link element | |
254 | field_name - str : Name of the field in link element's structure | |
255 | returns: | |
256 | A generator does not return. It is used for iterating | |
257 | value : an object thats of type (element_type). Always a pointer object | |
258 | """ | |
259 | def _make_pqe(addr): | |
f427ee49 | 260 | return value(root.GetSBValue().CreateValueFromExpression(None,'(struct priority_queue_entry_sched *)'+str(addr))) |
d9a64523 | 261 | |
f427ee49 | 262 | queue = [unsigned(root.pq_root)] |
d9a64523 A |
263 | |
264 | while len(queue): | |
265 | elt = _make_pqe(queue.pop()) | |
266 | ||
267 | while elt: | |
268 | yield containerof(elt, element_type, field_name) | |
269 | addr = unsigned(elt.child) | |
270 | if addr: queue.append(addr) | |
271 | elt = elt.next | |
272 | ||
f427ee49 A |
273 | def SchedPriorityStableQueueRootPri(root, element_type, field_name): |
274 | """ Return the root level priority of a priority queue as defined with struct priority_queue from osfmk/kern/priority_queue.h | |
275 | root - value : Value object for the priority queue | |
276 | element_type - str : Type of the link element | |
277 | field_name - str : Name of the field in link element's structure | |
278 | returns: | |
279 | The sched pri of the root element. | |
280 | """ | |
281 | def _make_pqe(addr): | |
282 | return value(root.GetSBValue().CreateValueFromExpression(None,'(struct priority_queue_entry_stable *)'+str(addr))) | |
283 | ||
284 | elt = _make_pqe(unsigned(root.pq_root)) | |
285 | return (elt.key >> 8); | |
286 | ||
cb323159 A |
287 | def IterateMPSCQueue(root, element_type, field_name): |
288 | """ iterate over an MPSC queue as defined with struct mpsc_queue_head from osfmk/kern/mpsc_queue.h | |
289 | root - value : Value object for the mpsc queue | |
290 | element_type - str : Type of the link element | |
291 | field_name - str : Name of the field in link element's structure | |
292 | returns: | |
293 | A generator does not return. It is used for iterating | |
294 | value : an object thats of type (element_type). Always a pointer object | |
295 | """ | |
296 | elt = root.mpqh_head.mpqc_next | |
297 | while unsigned(elt): | |
298 | yield containerof(elt, element_type, field_name) | |
299 | elt = elt.mpqc_next | |
d9a64523 | 300 | |
39236c6e A |
301 | class KernelTarget(object): |
302 | """ A common kernel object that provides access to kernel objects and information. | |
303 | The class holds global lists for task, terminated_tasks, procs, zones, zombroc etc. | |
304 | It also provides a way to symbolicate an address or create a value from an address. | |
305 | """ | |
306 | def __init__(self, debugger): | |
307 | """ Initialize the kernel debugging environment. | |
308 | Target properties like architecture and connectedness are lazy-evaluted. | |
309 | """ | |
310 | self._debugger = debugger # This holds an lldb.SBDebugger object for debugger state | |
311 | self._threads_list = [] | |
312 | self._tasks_list = [] | |
fe8ab488 | 313 | self._coalitions_list = [] |
5ba3f43e | 314 | self._thread_groups = [] |
39236c6e A |
315 | self._allproc = [] |
316 | self._terminated_tasks_list = [] | |
c3c9b80d | 317 | self._terminated_threads_list = [] |
39236c6e A |
318 | self._zones_list = [] |
319 | self._zombproc_list = [] | |
320 | self._kernel_types_cache = {} #this will cache the Type objects as and when requested. | |
321 | self._version = None | |
322 | self._arch = None | |
323 | self._ptrsize = None # pointer size of kernel, not userspace | |
324 | self.symbolicator = None | |
325 | class _GlobalVariableFind(object): | |
326 | def __init__(self, kern): | |
327 | self._xnu_kernobj_12obscure12 = kern | |
328 | def __getattr__(self, name): | |
329 | v = self._xnu_kernobj_12obscure12.GetGlobalVariable(name) | |
330 | if not v.GetSBValue().IsValid(): | |
3e170ce0 | 331 | raise ValueError('No such global variable by name: %s '%str(name)) |
39236c6e A |
332 | return v |
333 | self.globals = _GlobalVariableFind(self) | |
334 | LazyTarget.Initialize(debugger) | |
335 | ||
336 | def _GetSymbolicator(self): | |
337 | """ Internal function: To initialize the symbolication from lldb.utils | |
338 | """ | |
339 | if not self.symbolicator is None: | |
340 | return self.symbolicator | |
341 | ||
342 | from lldb.utils import symbolication | |
343 | symbolicator = symbolication.Symbolicator() | |
344 | symbolicator.target = LazyTarget.GetTarget() | |
345 | self.symbolicator = symbolicator | |
346 | return self.symbolicator | |
347 | ||
348 | def Symbolicate(self, addr): | |
349 | """ simple method to get name of function/variable from an address. this is equivalent of gdb 'output /a 0xaddress' | |
350 | params: | |
351 | addr - int : typically hex value like 0xffffff80002c0df0 | |
352 | returns: | |
353 | str - '' if no symbol found else the symbol name. | |
354 | Note: this function only finds the first symbol. If you expect multiple symbol conflict please use SymbolicateFromAddress() | |
355 | """ | |
356 | ret_str = '' | |
357 | syms = self.SymbolicateFromAddress(addr) | |
358 | if len(syms) > 0: | |
359 | ret_str +=syms[0].GetName() | |
360 | return ret_str | |
361 | ||
362 | def SymbolicateFromAddress(self, addr): | |
363 | """ symbolicates any given address based on modules loaded in the target. | |
364 | params: | |
365 | addr - int : typically hex value like 0xffffff80002c0df0 | |
366 | returns: | |
367 | [] of SBSymbol: In case we don't find anything than empty array is returned. | |
368 | Note: a type of symbol can be figured out by gettype() function of SBSymbol. | |
369 | example usage: | |
370 | syms = kern.Symbolicate(0xffffff80002c0df0) | |
371 | for s in syms: | |
372 | if s.GetType() == lldb.eSymbolTypeCode: | |
373 | print "Function", s.GetName() | |
374 | if s.GetType() == lldb.eSymbolTypeData: | |
375 | print "Variable", s.GetName() | |
376 | """ | |
377 | if type(int(1)) != type(addr): | |
378 | if str(addr).strip().find("0x") == 0 : | |
379 | addr = int(addr, 16) | |
380 | else: | |
381 | addr = int(addr) | |
cb323159 | 382 | addr = self.StripKernelPAC(addr) |
39236c6e A |
383 | ret_array = [] |
384 | symbolicator = self._GetSymbolicator() | |
385 | syms = symbolicator.symbolicate(addr) | |
386 | if not syms: | |
387 | return ret_array | |
388 | for s in syms: | |
389 | ret_array.append(s.get_symbol_context().symbol) | |
390 | return ret_array | |
391 | ||
392 | def IsDebuggerConnected(self): | |
393 | proc_state = LazyTarget.GetProcess().state | |
394 | if proc_state == lldb.eStateInvalid : return False | |
395 | if proc_state in [lldb.eStateStopped, lldb.eStateSuspended] : return True | |
396 | ||
397 | def GetGlobalVariable(self, name): | |
398 | """ Get the value object representation for a kernel global variable | |
399 | params: | |
400 | name : str - name of the variable. ex. version | |
401 | returns: value - python object representing global variable. | |
402 | raises : Exception in case the variable is not found. | |
403 | """ | |
3e170ce0 A |
404 | self._globals_cache_dict = caching.GetDynamicCacheData("kern._globals_cache_dict", {}) |
405 | if name not in self._globals_cache_dict: | |
406 | self._globals_cache_dict[name] = value(LazyTarget.GetTarget().FindGlobalVariables(name, 1).GetValueAtIndex(0)) | |
407 | return self._globals_cache_dict[name] | |
39236c6e A |
408 | |
409 | def GetLoadAddressForSymbol(self, name): | |
410 | """ Get the load address of a symbol in the kernel. | |
411 | params: | |
412 | name : str - name of the symbol to lookup | |
413 | returns: int - the load address as an integer. Use GetValueFromAddress to cast to a value. | |
414 | raises : LookupError - if the symbol is not found. | |
415 | """ | |
416 | name = str(name) | |
417 | target = LazyTarget.GetTarget() | |
418 | syms_arr = target.FindSymbols(name) | |
419 | if syms_arr.IsValid() and len(syms_arr) > 0: | |
420 | symbol = syms_arr[0].GetSymbol() | |
421 | if symbol.IsValid(): | |
422 | return int(symbol.GetStartAddress().GetLoadAddress(target)) | |
423 | ||
424 | raise LookupError("Symbol not found: " + name) | |
425 | ||
426 | def GetValueFromAddress(self, addr, type_str = 'void *'): | |
427 | """ convert a address to value | |
428 | params: | |
429 | addr - int : typically hex value like 0xffffff80008dc390 | |
430 | type_str - str: type to cast to. Default type will be void * | |
431 | returns: | |
432 | value : a value object which has address as addr and type is type_str | |
433 | """ | |
434 | obj = value(self.globals.version.GetSBValue().CreateValueFromExpression(None,'(void *)'+str(addr))) | |
435 | obj = cast(obj, type_str) | |
436 | return obj | |
437 | ||
438 | def GetValueAsType(self, v, t): | |
439 | """ Retrieves a global variable 'v' of type 't' wrapped in a vue object. | |
440 | If 'v' is an address, creates a vue object of the appropriate type. | |
441 | If 'v' is a name, looks for the global variable and asserts its type. | |
442 | Throws: | |
443 | NameError - If 'v' cannot be found | |
444 | TypeError - If 'v' is of the wrong type | |
445 | """ | |
446 | if islong(v): | |
447 | return self.GetValueFromAddress(v, t) | |
448 | else: | |
449 | var = LazyTarget.GetTarget().FindGlobalVariables(v, 1)[0] | |
450 | if not var: | |
451 | raise NameError("Failed to find global variable '{0}'".format(v)) | |
452 | if var.GetTypeName() != t: | |
453 | raise TypeError("{0} must be of type '{1}', not '{2}'".format(v, t, var.GetTypeName())) | |
454 | return value(var) | |
455 | ||
456 | def _GetIterator(self, iter_head_name, next_element_name='next', iter_head_type=None): | |
457 | """ returns an iterator for a collection in kernel memory. | |
458 | params: | |
459 | iter_head_name - str : name of queue_head or list head variable. | |
460 | next_element_name - str : name of the element that leads to next element. | |
461 | for ex. in struct zone list 'next_zone' is the linking element. | |
462 | returns: | |
463 | iterable : typically used in conjunction with "for varname in iterable:" | |
464 | """ | |
465 | head_element = self.GetGlobalVariable(iter_head_name) | |
466 | return head_element.GetSBValue().linked_list_iter(next_element_name) | |
467 | ||
468 | def TruncPage(self, addr): | |
469 | return (addr & ~(unsigned(self.GetGlobalVariable("page_size")) - 1)) | |
470 | ||
471 | def RoundPage(self, addr): | |
472 | return trunc_page(addr + unsigned(self.GetGlobalVariable("page_size")) - 1) | |
473 | ||
474 | def StraddlesPage(self, addr, size): | |
475 | if size > unsigned(self.GetGlobalVariable("page_size")): | |
476 | return True | |
fe8ab488 A |
477 | val = ((addr + size) & (unsigned(self.GetGlobalVariable("page_size"))-1)) |
478 | return (val < size and val > 0) | |
39236c6e | 479 | |
cb323159 A |
480 | def StripUserPAC(self, addr): |
481 | if self.arch != 'arm64e': | |
482 | return addr | |
483 | T0Sz = self.GetGlobalVariable('gT0Sz') | |
484 | return StripPAC(addr, T0Sz) | |
485 | ||
486 | def StripKernelPAC(self, addr): | |
487 | if self.arch != 'arm64e': | |
488 | return addr | |
489 | T1Sz = self.GetGlobalVariable('gT1Sz') | |
490 | return StripPAC(addr, T1Sz) | |
d9a64523 A |
491 | |
492 | def PhysToKVARM64(self, addr): | |
493 | ptov_table = self.GetGlobalVariable('ptov_table') | |
494 | for i in range(0, self.GetGlobalVariable('ptov_index')): | |
495 | if (addr >= long(unsigned(ptov_table[i].pa))) and (addr < (long(unsigned(ptov_table[i].pa)) + long(unsigned(ptov_table[i].len)))): | |
496 | return (addr - long(unsigned(ptov_table[i].pa)) + long(unsigned(ptov_table[i].va))) | |
497 | return (addr - unsigned(self.GetGlobalVariable("gPhysBase")) + unsigned(self.GetGlobalVariable("gVirtBase"))) | |
498 | ||
39236c6e A |
499 | def PhysToKernelVirt(self, addr): |
500 | if self.arch == 'x86_64': | |
501 | return (addr + unsigned(self.GetGlobalVariable('physmap_base'))) | |
d9a64523 A |
502 | elif self.arch.startswith('arm64'): |
503 | return self.PhysToKVARM64(addr) | |
5ba3f43e | 504 | elif self.arch.startswith('arm'): |
39236c6e A |
505 | return (addr - unsigned(self.GetGlobalVariable("gPhysBase")) + unsigned(self.GetGlobalVariable("gVirtBase"))) |
506 | else: | |
5ba3f43e | 507 | raise ValueError("PhysToVirt does not support {0}".format(self.arch)) |
39236c6e | 508 | |
3e170ce0 A |
509 | def GetNanotimeFromAbstime(self, abstime): |
510 | """ convert absolute time (which is in MATUs) to nano seconds. | |
511 | Since based on architecture the conversion may differ. | |
512 | params: | |
513 | abstime - int absolute time as shown by mach_absolute_time | |
514 | returns: | |
515 | int - nanosecs of time | |
516 | """ | |
517 | usec_divisor = caching.GetStaticCacheData("kern.rtc_usec_divisor", None) | |
518 | if not usec_divisor: | |
519 | if self.arch == 'x86_64': | |
520 | usec_divisor = 1000 | |
521 | else: | |
522 | rtclockdata_addr = self.GetLoadAddressForSymbol('RTClockData') | |
523 | rtc = self.GetValueFromAddress(rtclockdata_addr, 'struct _rtclock_data_ *') | |
524 | usec_divisor = unsigned(rtc.rtc_usec_divisor) | |
525 | usec_divisor = int(usec_divisor) | |
526 | caching.SaveStaticCacheData('kern.rtc_usec_divisor', usec_divisor) | |
527 | nsecs = (abstime * 1000)/usec_divisor | |
528 | return nsecs | |
529 | ||
39236c6e A |
530 | def __getattribute__(self, name): |
531 | if name == 'zones' : | |
532 | self._zones_list = caching.GetDynamicCacheData("kern._zones_list", []) | |
533 | if len(self._zones_list) > 0: return self._zones_list | |
39037602 A |
534 | zone_array = self.GetGlobalVariable('zone_array') |
535 | for i in range(0, self.GetGlobalVariable('num_zones')): | |
536 | self._zones_list.append(addressof(zone_array[i])) | |
39236c6e A |
537 | caching.SaveDynamicCacheData("kern._zones_list", self._zones_list) |
538 | return self._zones_list | |
539 | ||
540 | if name == 'threads' : | |
541 | self._threads_list = caching.GetDynamicCacheData("kern._threads_list", []) | |
542 | if len(self._threads_list) > 0 : return self._threads_list | |
543 | thread_queue_head = self.GetGlobalVariable('threads') | |
544 | thread_type = LazyTarget.GetTarget().FindFirstType('thread') | |
545 | thread_ptr_type = thread_type.GetPointerType() | |
546 | for th in IterateQueue(thread_queue_head, thread_ptr_type, 'threads'): | |
547 | self._threads_list.append(th) | |
548 | caching.SaveDynamicCacheData("kern._threads_list", self._threads_list) | |
549 | return self._threads_list | |
550 | ||
551 | if name == 'tasks' : | |
552 | self._tasks_list = caching.GetDynamicCacheData("kern._tasks_list", []) | |
553 | if len(self._tasks_list) > 0 : return self._tasks_list | |
554 | task_queue_head = self.GetGlobalVariable('tasks') | |
555 | task_type = LazyTarget.GetTarget().FindFirstType('task') | |
556 | task_ptr_type = task_type.GetPointerType() | |
557 | for tsk in IterateQueue(task_queue_head, task_ptr_type, 'tasks'): | |
558 | self._tasks_list.append(tsk) | |
559 | caching.SaveDynamicCacheData("kern._tasks_list", self._tasks_list) | |
560 | return self._tasks_list | |
561 | ||
fe8ab488 A |
562 | if name == 'coalitions' : |
563 | self._coalitions_list = caching.GetDynamicCacheData("kern._coalitions_list", []) | |
564 | if len(self._coalitions_list) > 0 : return self._coalitions_list | |
3e170ce0 | 565 | coalition_queue_head = self.GetGlobalVariable('coalitions_q') |
fe8ab488 A |
566 | coalition_type = LazyTarget.GetTarget().FindFirstType('coalition') |
567 | coalition_ptr_type = coalition_type.GetPointerType() | |
3e170ce0 A |
568 | for coal in IterateLinkageChain(addressof(coalition_queue_head), coalition_ptr_type, 'coalitions'): |
569 | self._coalitions_list.append(coal) | |
fe8ab488 A |
570 | caching.SaveDynamicCacheData("kern._coalitions_list", self._coalitions_list) |
571 | return self._coalitions_list | |
572 | ||
5ba3f43e A |
573 | if name == 'thread_groups' : |
574 | self._thread_groups_list = caching.GetDynamicCacheData("kern._thread_groups_list", []) | |
575 | if len(self._thread_groups_list) > 0 : return self._thread_groups_list | |
576 | thread_groups_queue_head = self.GetGlobalVariable('tg_queue') | |
577 | thread_group_type = LazyTarget.GetTarget().FindFirstType('thread_group') | |
578 | thread_groups_ptr_type = thread_group_type.GetPointerType() | |
579 | for coal in IterateLinkageChain(addressof(thread_groups_queue_head), thread_groups_ptr_type, 'tg_queue_chain'): | |
580 | self._thread_groups_list.append(coal) | |
581 | caching.SaveDynamicCacheData("kern._thread_groups_list", self._thread_groups_list) | |
582 | return self._thread_groups_list | |
583 | ||
39236c6e A |
584 | if name == 'terminated_tasks' : |
585 | self._terminated_tasks_list = caching.GetDynamicCacheData("kern._terminated_tasks_list", []) | |
586 | if len(self._terminated_tasks_list) > 0 : return self._terminated_tasks_list | |
587 | task_queue_head = self.GetGlobalVariable('terminated_tasks') | |
588 | task_type = LazyTarget.GetTarget().FindFirstType('task') | |
589 | task_ptr_type = task_type.GetPointerType() | |
590 | for tsk in IterateQueue(task_queue_head, task_ptr_type, 'tasks'): | |
591 | self._terminated_tasks_list.append(tsk) | |
592 | caching.SaveDynamicCacheData("kern._terminated_tasks_list", self._terminated_tasks_list) | |
593 | return self._terminated_tasks_list | |
594 | ||
c3c9b80d A |
595 | if name == 'terminated_threads' : |
596 | self._terminated_threads_list = caching.GetDynamicCacheData("kern._terminated_threads_list", []) | |
597 | if len(self._terminated_threads_list) > 0 : return self._terminated_threads_list | |
598 | thread_queue_head = self.GetGlobalVariable('terminated_threads') | |
599 | thread_type = LazyTarget.GetTarget().FindFirstType('thread') | |
600 | thread_ptr_type = thread_type.GetPointerType() | |
601 | for trd in IterateQueue(thread_queue_head, thread_ptr_type, 'threads'): | |
602 | self._terminated_threads_list.append(trd) | |
603 | caching.SaveDynamicCacheData("kern._terminated_threads_list", self._terminated_threads_list) | |
604 | return self._terminated_threads_list | |
605 | ||
39236c6e A |
606 | if name == 'procs' : |
607 | self._allproc = caching.GetDynamicCacheData("kern._allproc", []) | |
608 | if len(self._allproc) > 0 : return self._allproc | |
609 | all_proc_head = self.GetGlobalVariable('allproc') | |
610 | proc_val = cast(all_proc_head.lh_first, 'proc *') | |
611 | while proc_val != 0: | |
612 | self._allproc.append(proc_val) | |
613 | proc_val = cast(proc_val.p_list.le_next, 'proc *') | |
614 | caching.SaveDynamicCacheData("kern._allproc", self._allproc) | |
615 | return self._allproc | |
616 | ||
fe8ab488 A |
617 | if name == 'interrupt_stats' : |
618 | self._interrupt_stats_list = caching.GetDynamicCacheData("kern._interrupt_stats_list", []) | |
619 | if len(self._interrupt_stats_list) > 0 : return self._interrupt_stats_list | |
620 | interrupt_stats_head = self.GetGlobalVariable('gInterruptAccountingDataList') | |
621 | interrupt_stats_type = LazyTarget.GetTarget().FindFirstType('IOInterruptAccountingData') | |
622 | interrupt_stats_ptr_type = interrupt_stats_type.GetPointerType() | |
623 | for interrupt_stats_obj in IterateQueue(interrupt_stats_head, interrupt_stats_ptr_type, 'chain'): | |
624 | self._interrupt_stats_list.append(interrupt_stats_obj) | |
625 | caching.SaveDynamicCacheData("kern._interrupt_stats", self._interrupt_stats_list) | |
626 | return self._interrupt_stats_list | |
627 | ||
39236c6e A |
628 | if name == 'zombprocs' : |
629 | self._zombproc_list = caching.GetDynamicCacheData("kern._zombproc_list", []) | |
630 | if len(self._zombproc_list) > 0 : return self._zombproc_list | |
631 | zproc_head = self.GetGlobalVariable('zombproc') | |
632 | proc_val = cast(zproc_head.lh_first, 'proc *') | |
633 | while proc_val != 0: | |
634 | self._zombproc_list.append(proc_val) | |
635 | proc_val = cast(proc_val.p_list.le_next, 'proc *') | |
636 | caching.SaveDynamicCacheData("kern._zombproc_list", self._zombproc_list) | |
637 | return self._zombproc_list | |
638 | ||
639 | if name == 'version' : | |
640 | self._version = caching.GetStaticCacheData("kern.version", None) | |
641 | if self._version != None : return self._version | |
642 | self._version = str(self.GetGlobalVariable('version')) | |
643 | caching.SaveStaticCacheData("kern.version", self._version) | |
644 | return self._version | |
645 | ||
646 | if name == 'arch' : | |
647 | self._arch = caching.GetStaticCacheData("kern.arch", None) | |
648 | if self._arch != None : return self._arch | |
649 | arch = LazyTarget.GetTarget().triple.split('-')[0] | |
fe8ab488 | 650 | if arch in ('armv7', 'armv7s', 'armv7k'): |
39236c6e A |
651 | self._arch = 'arm' |
652 | else: | |
653 | self._arch = arch | |
654 | caching.SaveStaticCacheData("kern.arch", self._arch) | |
655 | return self._arch | |
656 | ||
657 | if name == 'ptrsize' : | |
658 | self._ptrsize = caching.GetStaticCacheData("kern.ptrsize", None) | |
659 | if self._ptrsize != None : return self._ptrsize | |
660 | arch = LazyTarget.GetTarget().triple.split('-')[0] | |
d9a64523 | 661 | if arch == 'x86_64' or arch.startswith('arm64'): |
39236c6e A |
662 | self._ptrsize = 8 |
663 | else: | |
664 | self._ptrsize = 4 | |
665 | caching.SaveStaticCacheData("kern.ptrsize", self._ptrsize) | |
666 | return self._ptrsize | |
667 | ||
5ba3f43e A |
668 | if name == 'VM_MIN_KERNEL_ADDRESS': |
669 | if self.arch == 'x86_64': | |
670 | return unsigned(0xFFFFFF8000000000) | |
d9a64523 | 671 | elif self.arch.startswith('arm64'): |
5ba3f43e A |
672 | return unsigned(0xffffffe000000000) |
673 | else: | |
674 | return unsigned(0x80000000) | |
675 | ||
676 | if name == 'VM_MIN_KERNEL_AND_KEXT_ADDRESS': | |
677 | if self.arch == 'x86_64': | |
678 | return self.VM_MIN_KERNEL_ADDRESS - 0x80000000 | |
679 | else: | |
680 | return self.VM_MIN_KERNEL_ADDRESS | |
681 | ||
39236c6e | 682 | return object.__getattribute__(self, name) |