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