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