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 228function_counters = dict() 229 230class KernelTarget(object): 231 """ A common kernel object that provides access to kernel objects and information. 232 The class holds global lists for task, terminated_tasks, procs, zones, zombroc etc. 233 It also provides a way to symbolicate an address or create a value from an address. 234 """ 235 def __init__(self, debugger): 236 """ Initialize the kernel debugging environment. 237 Target properties like architecture and connectedness are lazy-evaluted. 238 """ 239 240 self.symbolicator = None 241 242 class _GlobalVariableFind(object): 243 def __init__(self, kern): 244 self._xnu_kernobj_12obscure12 = kern 245 246 @cache_statically 247 def __getattr__(self, name, target=None): 248 v = self._xnu_kernobj_12obscure12.GetGlobalVariable(name) 249 if not v.GetSBValue().IsValid(): 250 # Python 2 swallows all exceptions in hasattr(). That makes it work 251 # even when global variable is not found. Python 3 has fixed the behavior 252 # and we can raise only AttributeError here to keep original behavior. 253 raise AttributeError('No such global variable by name: %s '%str(name)) 254 return v 255 def __contains__(self, name): 256 try: 257 val = self.__getattr__(name) 258 return True 259 except AttributeError: 260 return False 261 self.globals = _GlobalVariableFind(self) 262 263 264 def _GetSymbolicator(self): 265 """ Internal function: To initialize the symbolication from lldb.utils 266 """ 267 if not self.symbolicator is None: 268 return self.symbolicator 269 270 from lldb.utils import symbolication 271 symbolicator = symbolication.Symbolicator() 272 symbolicator.target = LazyTarget.GetTarget() 273 self.symbolicator = symbolicator 274 return self.symbolicator 275 276 def Symbolicate(self, addr): 277 """ simple method to get name of function/variable from an address. this is equivalent of gdb 'output /a 0xaddress' 278 params: 279 addr - int : typically hex value like 0xffffff80002c0df0 280 returns: 281 str - '' if no symbol found else the symbol name. 282 Note: this function only finds the first symbol. If you expect multiple symbol conflict please use SymbolicateFromAddress() 283 """ 284 ret_str = '' 285 syms = self.SymbolicateFromAddress(addr) 286 if len(syms) > 0: 287 ret_str +=syms[0].GetName() 288 return ret_str 289 290 def SymbolicateFromAddress(self, addr, fullSymbol=False): 291 """ symbolicates any given address based on modules loaded in the target. 292 params: 293 addr - int : typically hex value like 0xffffff80002c0df0 294 returns: 295 [] of SBSymbol: In case we don't find anything than empty array is returned. 296 Note: a type of symbol can be figured out by gettype() function of SBSymbol. 297 example usage: 298 syms = kern.Symbolicate(0xffffff80002c0df0) 299 for s in syms: 300 if s.GetType() == lldb.eSymbolTypeCode: 301 print "Function", s.GetName() 302 if s.GetType() == lldb.eSymbolTypeData: 303 print "Variable", s.GetName() 304 """ 305 if type(int(1)) != type(addr): 306 if str(addr).strip().find("0x") == 0 : 307 addr = int(addr, 16) 308 else: 309 addr = int(addr) 310 addr = self.StripKernelPAC(addr) 311 ret_array = [] 312 symbolicator = self._GetSymbolicator() 313 syms = symbolicator.symbolicate(addr) 314 if not syms: 315 return ret_array 316 for s in syms: 317 if fullSymbol: 318 ret_array.append(s) 319 else: 320 ret_array.append(s.get_symbol_context().symbol) 321 return ret_array 322 323 def IsDebuggerConnected(self): 324 proc_state = LazyTarget.GetProcess().state 325 if proc_state == lldb.eStateInvalid : return False 326 if proc_state in [lldb.eStateStopped, lldb.eStateSuspended] : return True 327 328 @staticmethod 329 @cache_statically 330 def GetGlobalVariable(name, target=None): 331 """ Get the value object representation for a kernel global variable 332 params: 333 name : str - name of the variable. ex. version 334 returns: value - python object representing global variable. 335 raises : Exception in case the variable is not found. 336 """ 337 338 return value(target.FindGlobalVariables(name, 1).GetValueAtIndex(0)) 339 340 @cache_statically 341 def PERCPU_BASE(self, cpu, target=None): 342 """ Get the PERCPU base for the given cpu number 343 params: 344 cpu : int - the cpu# for this variable 345 returns: int - the base for PERCPU for this cpu index 346 """ 347 if self.arch == 'x86_64': 348 return unsigned(self.globals.cpu_data_ptr[cpu].cpu_pcpu_base) 349 elif self.arch.startswith('arm'): 350 data_entries = self.GetGlobalVariable('CpuDataEntries') 351 BootCpuData = addressof(self.GetGlobalVariable('percpu_slot_cpu_data')) 352 return unsigned(data_entries[cpu].cpu_data_vaddr) - unsigned(BootCpuData) 353 354 def PERCPU_GET(self, name, cpu): 355 """ Get the value object representation for a kernel percpu global variable 356 params: 357 name : str - name of the variable. ex. version 358 cpu : int - the cpu# for this variable 359 returns: value - python object representing global variable. 360 raises : Exception in case the variable is not found. 361 """ 362 var = addressof(self.GetGlobalVariable('percpu_slot_' + name)) 363 var_type = var.GetSBValue().GetType().name 364 addr = unsigned(var) + self.PERCPU_BASE(cpu) 365 return dereference(self.GetValueFromAddress(addr, var_type)) 366 367 @cache_statically 368 def GetLoadAddressForSymbol(self, name, target=None): 369 """ Get the load address of a symbol in the kernel. 370 params: 371 name : str - name of the symbol to lookup 372 returns: int - the load address as an integer. Use GetValueFromAddress to cast to a value. 373 raises : LookupError - if the symbol is not found. 374 """ 375 name = str(name) 376 syms_arr = target.FindSymbols(name) 377 if syms_arr.IsValid() and len(syms_arr) > 0: 378 symbol = syms_arr[0].GetSymbol() 379 if symbol.IsValid(): 380 return int(symbol.GetStartAddress().GetLoadAddress(target)) 381 382 raise LookupError("Symbol not found: " + name) 383 384 def GetValueFromAddress(self, addr: int, type_str: str = 'void *') -> value: 385 """ convert an address to a value 386 params: 387 addr - int : typically hex value like 0xffffff80008dc390 388 type_str - str: type to cast to. Default type will be void * 389 returns: 390 value : a value object which has address as addr and type is type_str 391 """ 392 sbv = self.globals.version.GetSBValue().CreateValueFromExpression(None,f"({type_str}){str(addr)}") 393 394 wanted_type = gettype(type_str) 395 if sbv.GetType() != wanted_type: 396 sbv = sbv.Cast(wanted_type) 397 398 return value(sbv) 399 400 def CreateValueFromAddress(self, addr: int, type_str: str = 'void *') -> value: 401 """ convert an address to a value, using `GetValueFromAddress()` 402 params: 403 addr - int : typically hex value like 0xffffff80008dc390 404 type_str - str: type to cast to. Default type will be void * 405 returns: 406 value : a value object which has address as addr and type is type_str 407 408 There are 2 LLDB APIs to create SBValues for data in memory - `CreateValueFromExpression()` and `CreateValueFromAddress()`. 409 The former will parse an expression (like those used in an LLDB print command - `p/x *(vm_map_t)0xFOO_ADDR`). 410 The latter allows telling LLDB "Give me an SBValue that interprets the data begginning at FOO address as BAR type". 411 412 `CreateValueFromAddress()` is more performant, but can be clunkier to work with. 413 However, for simple use cases it can be just as convenient as `CreateValueFromExpression()`. 414 Just take heed that you probably don't want "an SBValue for a pointer to BAR type who's data is at address FOO", 415 rather "an SBValue for BAR type who's data is at address FOO". 416 417 Where performance matters or there's no usability tradeoff, you're encouraged to use `CreateValueFromAddress()` over `GetValueFromAddress()`. 418 The poor, confusing naming is legacy :/ 419 420 """ 421 sbv = self.globals.version.GetSBValue().xCreateValueFromAddress(None, addr, gettype(type_str)) 422 return value(sbv) 423 424 def CreateTypedPointerFromAddress(self, addr, type_str = "char"): 425 """ convert a address to pointer value 426 427 Note: This is obsolete and here as a temporary solution 428 for people to migrate to using references instead. 429 430 params: 431 addr - int : typically hex value like 0xffffff80008dc390 432 type_str - str: type to cast to, must not be a pointer type. 433 returns: 434 value : a value object which has address as addr 435 and type is `type_str *` 436 """ 437 438 target = LazyTarget.GetTarget() 439 sbv = target.xCreateValueFromAddress(None, addr, gettype(type_str)) 440 return value(sbv.AddressOf()) 441 442 443 def GetValueAsType(self, v, t): 444 """ Retrieves a global variable 'v' of type 't' wrapped in a vue object. 445 If 'v' is an address, creates a vue object of the appropriate type. 446 If 'v' is a name, looks for the global variable and asserts its type. 447 Throws: 448 NameError - If 'v' cannot be found 449 TypeError - If 'v' is of the wrong type 450 """ 451 if islong(v): 452 return self.GetValueFromAddress(v, t) 453 else: 454 var = LazyTarget.GetTarget().FindGlobalVariables(v, 1)[0] 455 if not var: 456 raise NameError("Failed to find global variable '{0}'".format(v)) 457 if var.GetTypeName() != t: 458 raise TypeError("{0} must be of type '{1}', not '{2}'".format(v, t, var.GetTypeName())) 459 return value(var) 460 461 def _GetIterator(self, iter_head_name, next_element_name='next', iter_head_type=None): 462 """ returns an iterator for a collection in kernel memory. 463 params: 464 iter_head_name - str : name of queue_head or list head variable. 465 next_element_name - str : name of the element that leads to next element. 466 for ex. in struct zone list 'next_zone' is the linking element. 467 returns: 468 iterable : typically used in conjunction with "for varname in iterable:" 469 """ 470 head_element = self.GetGlobalVariable(iter_head_name) 471 return head_element.GetSBValue().linked_list_iter(next_element_name) 472 473 def TruncPage(self, addr): 474 return (addr & ~(unsigned(self.GetGlobalVariable("page_size")) - 1)) 475 476 def RoundPage(self, addr): 477 return trunc_page(addr + unsigned(self.GetGlobalVariable("page_size")) - 1) 478 479 def StraddlesPage(self, addr, size): 480 if size > unsigned(self.GetGlobalVariable("page_size")): 481 return True 482 val = ((addr + size) & (unsigned(self.GetGlobalVariable("page_size"))-1)) 483 return (val < size and val > 0) 484 485 def StripUserPAC(self, addr): 486 if self.arch != 'arm64e': 487 return addr 488 T0Sz = self.GetGlobalVariable('gT0Sz') 489 return StripPAC(addr, T0Sz) 490 491 def StripKernelPAC(self, addr): 492 if self.arch != 'arm64e': 493 return addr 494 T1Sz = self.GetGlobalVariable('gT1Sz') 495 return StripPAC(addr, T1Sz) 496 497 PAGE_PROTECTION_TYPE_NONE = 0 498 PAGE_PROTECTION_TYPE_PPL = 1 499 PAGE_PROTECTION_TYPE_SPTM = 2 500 501 def PhysToKVARM64(self, addr): 502 if self.globals.page_protection_type <= self.PAGE_PROTECTION_TYPE_PPL: 503 ptov_table = self.globals.ptov_table 504 for i in range(0, self.globals.ptov_index): 505 if (addr >= int(unsigned(ptov_table[i].pa))) and (addr < (int(unsigned(ptov_table[i].pa)) + int(unsigned(ptov_table[i].len)))): 506 return (addr - int(unsigned(ptov_table[i].pa)) + int(unsigned(ptov_table[i].va))) 507 else: 508 papt_table = self.globals.libsptm_papt_ranges 509 page_size = self.globals.page_size 510 for i in range(0, self.globals.libsptm_n_papt_ranges): 511 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))): 512 return (addr - int(unsigned(papt_table[i].paddr_start)) + int(unsigned(papt_table[i].papt_start))) 513 raise ValueError("PA {:#x} not found in physical region lookup table".format(addr)) 514 return (addr - unsigned(self.globals.gPhysBase) + unsigned(self.globals.gVirtBase)) 515 516 def PhysToKernelVirt(self, addr): 517 if self.arch == 'x86_64': 518 return (addr + unsigned(self.GetGlobalVariable('physmap_base'))) 519 elif self.arch.startswith('arm64'): 520 return self.PhysToKVARM64(addr) 521 elif self.arch.startswith('arm'): 522 return (addr - unsigned(self.GetGlobalVariable("gPhysBase")) + unsigned(self.GetGlobalVariable("gVirtBase"))) 523 else: 524 raise ValueError("PhysToVirt does not support {0}".format(self.arch)) 525 526 @cache_statically 527 def GetUsecDivisor(self, target=None): 528 if self.arch == 'x86_64': 529 return 1000 530 531 rtclockdata_addr = self.GetLoadAddressForSymbol('RTClockData') 532 rtc = self.GetValueFromAddress(rtclockdata_addr, 'struct _rtclock_data_ *') 533 return unsigned(rtc.rtc_usec_divisor) 534 535 def GetNanotimeFromAbstime(self, abstime): 536 """ convert absolute time (which is in MATUs) to nano seconds. 537 Since based on architecture the conversion may differ. 538 params: 539 abstime - int absolute time as shown by mach_absolute_time 540 returns: 541 int - nanosecs of time 542 """ 543 return (abstime * 1000) // self.GetUsecDivisor() 544 545 @property 546 @cache_statically 547 def zones(self, target=None): 548 za = target.chkFindFirstGlobalVariable('zone_array') 549 zs = target.chkFindFirstGlobalVariable('zone_security_array') 550 n = target.chkFindFirstGlobalVariable('num_zones').xGetValueAsInteger() 551 552 iter_za = za.chkGetChildAtIndex(0).xIterSiblings(0, n) 553 iter_zs = zs.chkGetChildAtIndex(0).xIterSiblings(0, n) 554 555 return [ 556 (value(next(iter_za).AddressOf()), value(next(iter_zs).AddressOf())) 557 for i in range(n) 558 ] 559 560 @property 561 def threads(self): 562 target = LazyTarget.GetTarget() 563 564 return (value(t.AddressOf()) for t in ccol.iter_queue( 565 target.chkFindFirstGlobalVariable('threads'), 566 gettype('thread'), 567 'threads', 568 )) 569 570 @dyn_cached_property 571 def tasks(self, target=None): 572 return [value(t.AddressOf()) for t in ccol.iter_queue( 573 target.chkFindFirstGlobalVariable('tasks'), 574 gettype('task'), 575 'tasks', 576 )] 577 578 @property 579 def coalitions(self): 580 target = LazyTarget.GetTarget() 581 582 return (value(coal.AddressOf()) for coal in ccol.SMRHash( 583 target.chkFindFirstGlobalVariable('coalition_hash'), 584 target.chkFindFirstGlobalVariable('coal_hash_traits'), 585 )) 586 587 @property 588 def thread_groups(self): 589 target = LazyTarget.GetTarget() 590 591 return (value(tg.AddressOf()) for tg in ccol.iter_queue_entries( 592 target.chkFindFirstGlobalVariable('tg_queue'), 593 gettype('thread_group'), 594 'tg_queue_chain', 595 )) 596 597 @property 598 def terminated_tasks(self): 599 target = LazyTarget.GetTarget() 600 601 return (value(t.AddressOf()) for t in ccol.iter_queue( 602 target.chkFindFirstGlobalVariable('terminated_tasks'), 603 gettype('task'), 604 'tasks', 605 )) 606 607 @property 608 def terminated_threads(self): 609 target = LazyTarget.GetTarget() 610 611 return (value(t.AddressOf()) for t in ccol.iter_queue( 612 target.chkFindFirstGlobalVariable('terminated_threads'), 613 gettype('thread'), 614 'threads', 615 )) 616 617 @property 618 def procs(self): 619 target = LazyTarget.GetTarget() 620 621 return (value(p.AddressOf()) for p in ccol.iter_LIST_HEAD( 622 target.chkFindFirstGlobalVariable('allproc'), 623 'p_list', 624 )) 625 626 @property 627 def interrupt_stats(self): 628 target = LazyTarget.GetTarget() 629 630 return (value(stat.AddressOf()) for stat in ccol.iter_queue( 631 target.chkFindFirstGlobalVariable('gInterruptAccountingDataList'), 632 gettype('IOInterruptAccountingData'), 633 'chain', 634 )) 635 636 @property 637 def zombprocs(self): 638 target = LazyTarget.GetTarget() 639 640 return (value(p.AddressOf()) for p in ccol.iter_LIST_HEAD( 641 target.chkFindFirstGlobalVariable('zombproc'), 642 'p_list', 643 )) 644 645 @property 646 def version(self): 647 return str(self.globals.version) 648 649 @property 650 def arch(self): 651 return LazyTarget.GetTarget().triple.split('-', 1)[0] 652 653 @property 654 def ptrsize(self): 655 return LazyTarget.GetTarget().GetAddressByteSize() 656 657 @property 658 def VM_MIN_KERNEL_ADDRESS(self): 659 if self.arch == 'x86_64': 660 return 0xffffff8000000000 661 else: 662 return 0xffffffe00000000 663 664 @property 665 def VM_MIN_KERNEL_AND_KEXT_ADDRESS(self): 666 if self.arch == 'x86_64': 667 return 0xffffff8000000000 - 0x80000000 668 else: 669 return 0xffffffe00000000 670