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