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