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