xref: /xnu-11215.1.10/tools/lldbmacros/core/kernelcore.py (revision 8d741a5de7ff4191bf97d57b9f54c2f6d4a15585)
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        addr = unsigned(var) + self.PERCPU_BASE(cpu)
353        return dereference(self.GetValueFromAddress(addr, var))
354
355    def GetLoadAddressForSymbol(self, name):
356        """ Get the load address of a symbol in the kernel.
357            params:
358              name : str - name of the symbol to lookup
359            returns: int - the load address as an integer. Use GetValueFromAddress to cast to a value.
360            raises : LookupError - if the symbol is not found.
361        """
362        name = str(name)
363        target = LazyTarget.GetTarget()
364        syms_arr = target.FindSymbols(name)
365        if syms_arr.IsValid() and len(syms_arr) > 0:
366            symbol = syms_arr[0].GetSymbol()
367            if symbol.IsValid():
368                return int(symbol.GetStartAddress().GetLoadAddress(target))
369
370        raise LookupError("Symbol not found: " + name)
371
372    def GetValueFromAddress(self, addr: int, type_str: str = 'void *') -> value:
373        """ convert an address to a value
374            params:
375                addr - int : typically hex value like 0xffffff80008dc390
376                type_str - str: type to cast to. Default type will be void *
377            returns:
378                value : a value object which has address as addr and type is type_str
379        """
380        sbv = self.globals.version.GetSBValue().CreateValueFromExpression(None,f"({type_str}){str(addr)}")
381
382        wanted_type = gettype(type_str)
383        if sbv.GetType() != wanted_type:
384            sbv = sbv.Cast(wanted_type)
385
386        return value(sbv)
387
388    def CreateValueFromAddress(self, addr: int, type_str: str = 'void *') -> value:
389        """ convert an address to a value, using `GetValueFromAddress()`
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            There are 2 LLDB APIs to create SBValues for data in memory - `CreateValueFromExpression()` and `CreateValueFromAddress()`.
397            The former will parse an expression (like those used in an LLDB print command - `p/x *(vm_map_t)0xFOO_ADDR`).
398            The latter allows telling LLDB "Give me an SBValue that interprets the data begginning at FOO address as BAR type".
399
400            `CreateValueFromAddress()` is more performant, but can be clunkier to work with.
401            However, for simple use cases it can be just as convenient as `CreateValueFromExpression()`.
402            Just take heed that you probably don't want "an SBValue for a pointer to BAR type who's data is at address FOO",
403            rather "an SBValue for BAR type who's data is at address FOO".
404
405            Where performance matters or there's no usability tradeoff, you're encouraged to use `CreateValueFromAddress()` over `GetValueFromAddress()`.
406            The poor, confusing naming is legacy :/
407
408        """
409        sbv = self.globals.version.GetSBValue().xCreateValueFromAddress(None, addr, gettype(type_str))
410        return value(sbv)
411
412    def CreateTypedPointerFromAddress(self, addr, type_str = "char"):
413        """ convert a address to pointer value
414
415            Note: This is obsolete and here as a temporary solution
416                  for people to migrate to using references instead.
417
418            params:
419                addr - int : typically hex value like 0xffffff80008dc390
420                type_str - str: type to cast to, must not be a pointer type.
421            returns:
422                value : a value object which has address as addr
423                        and type is `type_str *`
424        """
425
426        target = LazyTarget.GetTarget()
427        sbv    = target.xCreateValueFromAddress(None, addr, gettype(type_str))
428        return value(sbv.AddressOf())
429
430
431    def GetValueAsType(self, v, t):
432        """ Retrieves a global variable 'v' of type 't' wrapped in a vue object.
433            If 'v' is an address, creates a vue object of the appropriate type.
434            If 'v' is a name, looks for the global variable and asserts its type.
435            Throws:
436                NameError - If 'v' cannot be found
437                TypeError - If 'v' is of the wrong type
438        """
439        if islong(v):
440            return self.GetValueFromAddress(v, t)
441        else:
442            var = LazyTarget.GetTarget().FindGlobalVariables(v, 1)[0]
443            if not var:
444                raise NameError("Failed to find global variable '{0}'".format(v))
445            if var.GetTypeName() != t:
446                raise TypeError("{0} must be of type '{1}', not '{2}'".format(v, t, var.GetTypeName()))
447            return value(var)
448
449    def _GetIterator(self, iter_head_name, next_element_name='next', iter_head_type=None):
450        """ returns an iterator for a collection in kernel memory.
451            params:
452                iter_head_name - str : name of queue_head or list head variable.
453                next_element_name - str : name of the element that leads to next element.
454                                          for ex. in struct zone list 'next_zone' is the linking element.
455            returns:
456                iterable : typically used in conjunction with "for varname in iterable:"
457        """
458        head_element = self.GetGlobalVariable(iter_head_name)
459        return head_element.GetSBValue().linked_list_iter(next_element_name)
460
461    def TruncPage(self, addr):
462        return (addr & ~(unsigned(self.GetGlobalVariable("page_size")) - 1))
463
464    def RoundPage(self, addr):
465        return trunc_page(addr + unsigned(self.GetGlobalVariable("page_size")) - 1)
466
467    def StraddlesPage(self, addr, size):
468        if size > unsigned(self.GetGlobalVariable("page_size")):
469            return True
470        val = ((addr + size) & (unsigned(self.GetGlobalVariable("page_size"))-1))
471        return (val < size and val > 0)
472
473    def StripUserPAC(self, addr):
474        if self.arch != 'arm64e':
475            return addr
476        T0Sz = self.GetGlobalVariable('gT0Sz')
477        return StripPAC(addr, T0Sz)
478
479    def StripKernelPAC(self, addr):
480        if self.arch != 'arm64e':
481            return addr
482        T1Sz = self.GetGlobalVariable('gT1Sz')
483        return StripPAC(addr, T1Sz)
484
485    PAGE_PROTECTION_TYPE_NONE = 0
486    PAGE_PROTECTION_TYPE_PPL = 1
487    PAGE_PROTECTION_TYPE_SPTM = 2
488
489    def PhysToKVARM64(self, addr):
490        if self.globals.page_protection_type <= self.PAGE_PROTECTION_TYPE_PPL:
491            ptov_table = self.globals.ptov_table
492            for i in range(0, self.globals.ptov_index):
493                if (addr >= int(unsigned(ptov_table[i].pa))) and (addr < (int(unsigned(ptov_table[i].pa)) + int(unsigned(ptov_table[i].len)))):
494                    return (addr - int(unsigned(ptov_table[i].pa)) + int(unsigned(ptov_table[i].va)))
495        else:
496            papt_table = self.globals.libsptm_papt_ranges
497            page_size = self.globals.page_size
498            for i in range(0, self.globals.libsptm_n_papt_ranges):
499                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))):
500                    return (addr - int(unsigned(papt_table[i].paddr_start)) + int(unsigned(papt_table[i].papt_start)))
501            raise ValueError("PA {:#x} not found in physical region lookup table".format(addr))
502        return (addr - unsigned(self.globals.gPhysBase) + unsigned(self.globals.gVirtBase))
503
504    def PhysToKernelVirt(self, addr):
505        if self.arch == 'x86_64':
506            return (addr + unsigned(self.GetGlobalVariable('physmap_base')))
507        elif self.arch.startswith('arm64'):
508            return self.PhysToKVARM64(addr)
509        elif self.arch.startswith('arm'):
510            return (addr - unsigned(self.GetGlobalVariable("gPhysBase")) + unsigned(self.GetGlobalVariable("gVirtBase")))
511        else:
512            raise ValueError("PhysToVirt does not support {0}".format(self.arch))
513
514    @cache_statically
515    def GetUsecDivisor(self, target=None):
516        if self.arch == 'x86_64':
517            return 1000
518
519        rtclockdata_addr = self.GetLoadAddressForSymbol('RTClockData')
520        rtc = self.GetValueFromAddress(rtclockdata_addr, 'struct _rtclock_data_ *')
521        return unsigned(rtc.rtc_usec_divisor)
522
523    def GetNanotimeFromAbstime(self, abstime):
524        """ convert absolute time (which is in MATUs) to nano seconds.
525            Since based on architecture the conversion may differ.
526            params:
527                abstime - int absolute time as shown by mach_absolute_time
528            returns:
529                int - nanosecs of time
530        """
531        return (abstime * 1000) // self.GetUsecDivisor()
532
533    @property
534    @cache_statically
535    def zones(self, target=None):
536        za = target.chkFindFirstGlobalVariable('zone_array')
537        zs = target.chkFindFirstGlobalVariable('zone_security_array')
538        n  = target.chkFindFirstGlobalVariable('num_zones').xGetValueAsInteger()
539
540        iter_za = za.chkGetChildAtIndex(0).xIterSiblings(0, n)
541        iter_zs = zs.chkGetChildAtIndex(0).xIterSiblings(0, n)
542
543        return [
544            (value(next(iter_za).AddressOf()), value(next(iter_zs).AddressOf()))
545            for i in range(n)
546        ]
547
548    @property
549    def threads(self):
550        target = LazyTarget.GetTarget()
551
552        return (value(t.AddressOf()) for t in ccol.iter_queue(
553            target.chkFindFirstGlobalVariable('threads'),
554            gettype('thread'),
555            'threads',
556        ))
557
558    @dyn_cached_property
559    def tasks(self, target=None):
560        return [value(t.AddressOf()) for t in ccol.iter_queue(
561            target.chkFindFirstGlobalVariable('tasks'),
562            gettype('task'),
563            'tasks',
564        )]
565
566    @property
567    def coalitions(self):
568        target = LazyTarget.GetTarget()
569
570        return (value(coal.AddressOf()) for coal in ccol.SMRHash(
571            target.chkFindFirstGlobalVariable('coalition_hash'),
572            target.chkFindFirstGlobalVariable('coal_hash_traits'),
573        ))
574
575    @property
576    def thread_groups(self):
577        target = LazyTarget.GetTarget()
578
579        return (value(tg.AddressOf()) for tg in ccol.iter_queue_entries(
580            target.chkFindFirstGlobalVariable('tg_queue'),
581            gettype('thread_group'),
582            'tg_queue_chain',
583        ))
584
585    @property
586    def terminated_tasks(self):
587        target = LazyTarget.GetTarget()
588
589        return (value(t.AddressOf()) for t in ccol.iter_queue(
590            target.chkFindFirstGlobalVariable('terminated_tasks'),
591            gettype('task'),
592            'tasks',
593        ))
594
595    @property
596    def terminated_threads(self):
597        target = LazyTarget.GetTarget()
598
599        return (value(t.AddressOf()) for t in ccol.iter_queue(
600            target.chkFindFirstGlobalVariable('terminated_threads'),
601            gettype('thread'),
602            'threads',
603        ))
604
605    @property
606    def procs(self):
607        target = LazyTarget.GetTarget()
608
609        return (value(p.AddressOf()) for p in ccol.iter_LIST_HEAD(
610            target.chkFindFirstGlobalVariable('allproc'),
611            'p_list',
612        ))
613
614    @property
615    def interrupt_stats(self):
616        target = LazyTarget.GetTarget()
617
618        return (value(stat.AddressOf()) for stat in ccol.iter_queue(
619            target.chkFindFirstGlobalVariable('gInterruptAccountingDataList'),
620            gettype('IOInterruptAccountingData'),
621            'chain',
622        ))
623
624    @property
625    def zombprocs(self):
626        target = LazyTarget.GetTarget()
627
628        return (value(p.AddressOf()) for p in ccol.iter_LIST_HEAD(
629            target.chkFindFirstGlobalVariable('zombproc'),
630            'p_list',
631        ))
632
633    @property
634    def version(self):
635        return str(self.globals.version)
636
637    @property
638    def arch(self):
639        return LazyTarget.GetTarget().triple.split('-', 1)[0]
640
641    @property
642    def ptrsize(self):
643        return LazyTarget.GetTarget().GetAddressByteSize()
644
645    @property
646    def VM_MIN_KERNEL_ADDRESS(self):
647        if self.arch == 'x86_64':
648            return 0xffffff8000000000
649        else:
650            return 0xffffffe00000000
651
652    @property
653    def VM_MIN_KERNEL_AND_KEXT_ADDRESS(self):
654        if self.arch == 'x86_64':
655            return 0xffffff8000000000 - 0x80000000
656        else:
657            return 0xffffffe00000000
658