1from xnu import *
2from utils import *
3import sys
4
5######################################
6# Globals
7######################################
8plane = None
9
10######################################
11# Type Summaries
12######################################
13@lldb_type_summary(['OSObject *'])
14@header("")
15def GetObjectSummary(obj):
16    """ Show info about an OSObject - its vtable ptr and retain count, & more info for simple container classes.
17    """
18    if obj is None:
19        return
20
21    vt = dereference(Cast(obj, 'uintptr_t *')) - 2 * sizeof('uintptr_t')
22    vtype = kern.SymbolicateFromAddress(vt)
23    if hasattr(obj, 'retainCount'):
24        retCount = (obj.retainCount & 0xffff)
25        cntnrRetCount = (retCount >> 16)
26        out_string = "`object 0x{0: <16x}, vt 0x{1: <16x} <{2:s}>, retain count {3:d}, container retain {4:d}` ".format(obj, vt, vtype[0].GetName(), retCount, cntnrRetCount)
27    else:
28        if len(vtype):
29            out_string = "`object 0x{0: <16x}, vt 0x{1: <16x} <{2:s}>` ".format(obj, vt, vtype[0].GetName())
30        else:
31            out_string = "`object 0x{0: <16x}, vt 0x{1: <16x}` ".format(obj, vt)
32
33    ztvAddr = kern.GetLoadAddressForSymbol('_ZTV8OSString')
34    if vt == ztvAddr:
35        out_string += GetString(obj)
36        return out_string
37
38    ztvAddr = kern.GetLoadAddressForSymbol('_ZTV8OSSymbol')
39    if vt == ztvAddr:
40        out_string += GetString(obj)
41        return out_string
42
43    ztvAddr = kern.GetLoadAddressForSymbol('_ZTV8OSNumber')
44    if vt == ztvAddr:
45        out_string += GetNumber(obj)
46        return out_string
47
48    ztvAddr = kern.GetLoadAddressForSymbol('_ZTV9OSBoolean')
49    if vt == ztvAddr:
50        out_string += GetBoolean(obj)
51        return out_string
52
53    ztvAddr = kern.GetLoadAddressForSymbol('_ZTV7OSArray')
54    if vt == ztvAddr:
55        out_string += "(" + GetArray(Cast(obj, 'OSArray *')) + ")"
56        return out_string
57
58    ztvAddr = kern.GetLoadAddressForSymbol('_ZTV5OSSet')
59    if vt == ztvAddr:
60        out_string += GetSet(Cast(obj, 'OSSet *'))
61        return out_string
62
63    ztvAddr = kern.GetLoadAddressForSymbol('_ZTV12OSDictionary')
64    if vt == ztvAddr:
65        out_string += GetDictionary(Cast(obj, 'OSDictionary *'))
66        return out_string
67
68    return out_string
69
70@lldb_type_summary(['IORegistryEntry *'])
71@header("")
72def GetRegistryEntrySummary(entry):
73    """ returns a string containing summary information about an IORegistry
74        object including it's registry id , vtable ptr and retain count
75    """
76    name = None
77    out_string = ""
78    registryTable = entry.fRegistryTable
79    propertyTable = entry.fPropertyTable
80
81    name = LookupKeyInOSDict(registryTable, kern.globals.gIOServicePlane.nameKey)
82    if name is None:
83        name = LookupKeyInOSDict(registryTable, kern.globals.gIONameKey)
84    if name is None:
85        name = LookupKeyInOSDict(propertyTable, kern.globals.gIOClassKey)
86
87    if name is not None:
88        out_string += "+-o {0:s}  ".format(GetString(Cast(name, 'OSString *')))
89    elif Cast(entry, 'IOService *').pwrMgt and Cast(entry, 'IOService *').pwrMgt.Name:
90        out_string += "+-o {0:s}  ".format(Cast(entry, 'IOService *').pwrMgt.Name)
91    else:
92        out_string += "+-o ??  "
93
94    # I'm using uintptr_t for now to work around <rdar://problem/12749733> FindFirstType & Co. should allow you to make pointer types directly
95    vtableAddr = dereference(Cast(entry, 'uintptr_t *')) - 2 * sizeof('uintptr_t *')
96    vtype = kern.SymbolicateFromAddress(vtableAddr)
97    if vtype is None or len(vtype) < 1:
98        out_string += "<object 0x{0: <16x}, id 0x{1:x}, vtable 0x{2: <16x}".format(entry, entry.reserved.fRegistryEntryID, vtableAddr)
99    else:
100        out_string += "<object 0x{0: <16x}, id 0x{1:x}, vtable 0x{2: <16x} <{3:s}>".format(entry, entry.reserved.fRegistryEntryID, vtableAddr, vtype[0].GetName())
101
102    ztvAddr = kern.GetLoadAddressForSymbol('_ZTV15IORegistryEntry')
103    if vtableAddr != ztvAddr:
104        out_string += ", "
105        state = Cast(entry, 'IOService *').__state[0]
106        # kIOServiceRegisteredState
107        if 0 == state & 2:
108            out_string += "!"
109        out_string += "registered, "
110        # kIOServiceMatchedState
111        if 0 == state & 4:
112            out_string += "!"
113        out_string += "matched, "
114        #kIOServiceInactiveState
115        if 0 != state & 1:
116            out_string += "in"
117        busyCount = (Cast(entry, 'IOService *').__state[1] & 0xff)
118        retCount = (Cast(entry, 'IOService *').retainCount & 0xffff)
119        out_string += "active, busy {0}, retain count {1}>".format(busyCount, retCount)
120    #else:
121    #    out_string += "\n"
122    return out_string
123
124######################################
125# Commands
126######################################
127@lldb_command('showallclasses')
128def ShowAllClasses(cmd_args=None):
129    """ Show the instance counts and ivar size of all OSObject subclasses.
130        See ioclasscount man page for details
131    """
132    idx = 0
133    count = unsigned(kern.globals.sAllClassesDict.count)
134
135    while idx < count:
136        meta = Cast(kern.globals.sAllClassesDict.dictionary[idx].value, 'OSMetaClass *')
137        idx += 1
138        print GetMetaClass(meta)
139
140@lldb_command('showobject')
141def ShowObject(cmd_args=None):
142    """ Show info about an OSObject - its vtable ptr and retain count, & more info for simple container classes.
143    """
144    if not cmd_args:
145        print "Please specify the address of the OSObject whose info you want to view. Type help showobject for help"
146        return
147
148    obj = kern.GetValueFromAddress(cmd_args[0], 'OSObject *')
149    print GetObjectSummary(obj)
150
151@lldb_command('setregistryplane')
152def SetRegistryPlane(cmd_args=None):
153    """ Set the plane to be used for the IOKit registry macros
154        syntax: (lldb) setregistryplane 0  - will display all known planes
155        syntax: (lldb) setregistryplane 0xaddr      - will set the registry plane to 0xaddr
156        syntax: (lldb) setregistryplane gIODTPlane  - will set the registry plane to gIODTPlane
157    """
158    if not cmd_args:
159        print "Please specify the name of the plane you want to use with the IOKit registry macros."
160        print SetRegistryPlane.__doc__
161
162    if cmd_args[0] == "0":
163        print GetObjectSummary(kern.globals.gIORegistryPlanes)
164    else:
165        global plane
166        plane = kern.GetValueFromAddress(cmd_args[0], 'IORegistryPlane *')
167    return
168
169@lldb_command('showregistryentry')
170def ShowRegistryEntry(cmd_args=None):
171    """ Show info about a registry entry; its properties and descendants in the current plane
172        syntax: (lldb) showregistryentry 0xaddr
173        syntax: (lldb) showregistryentry gIOPMRootDomain
174    """
175    if not cmd_args:
176        print "Please specify the address of the registry entry whose info you want to view."
177        print ShowRegistryEntry.__doc__
178        return
179
180    entry = kern.GetValueFromAddress(cmd_args[0], 'IORegistryEntry *')
181    ShowRegistryEntryRecurse(entry, "", True)
182
183@lldb_command('showregistry')
184def ShowRegistry(cmd_args=None):
185    """ Show info about all registry entries in the current plane
186        If prior to invoking this command no registry plane is specified
187        using 'setregistryplane', the command defaults to the IOService plane
188    """
189    ShowRegistryEntryRecurse(kern.globals.gRegistryRoot, "", False)
190
191@lldb_command('showregistryprops')
192def ShowRegistryProps(cmd_args=None):
193    """ Show info about all registry entries in the current plane, and their properties
194        If prior to invoking this command no registry plane is specified
195        using 'setregistryplane', the command defaults to the IOService plane
196    """
197    ShowRegistryEntryRecurse(kern.globals.gRegistryRoot, "", True)
198
199@lldb_command('findregistryentry')
200def FindRegistryEntry(cmd_args=None):
201    """ Search for registry entry that matches the given string
202        If prior to invoking this command no registry plane is specified
203        using 'setregistryplane', the command defaults to searching entries from the IOService plane
204        syntax: (lldb) findregistryentries AppleACPICPU - will find the first registry entry that matches AppleACPICPU
205    """
206    if not cmd_args:
207        print "Please specify the name of the registry entry you want to find"
208        print FindRegistryEntry.__doc__
209        return
210
211    FindRegistryEntryRecurse(kern.globals.gRegistryRoot, cmd_args[0], True)
212
213@lldb_command('findregistryentries')
214def FindRegistryEntries(cmd_args=None):
215    """ Search for all registry entries that match the given string
216        If prior to invoking this command no registry plane is specified
217        using 'setregistryplane', the command defaults to searching entries from the IOService plane
218        syntax: (lldb) findregistryentries AppleACPICPU - will find all registry entries that match AppleACPICPU
219    """
220    if not cmd_args:
221        print "Please specify the name of the registry entry/entries you want to find"
222        print FindRegistryEntries.__doc__
223        return
224
225    FindRegistryEntryRecurse(kern.globals.gRegistryRoot, cmd_args[0], False)
226
227@lldb_command('findregistryprop')
228def FindRegistryProp(cmd_args=None):
229    """ Given a registry entry, print out the contents for the property that matches
230        a specific string
231        syntax: (lldb) findregistryprop 0xaddr IOSleepSupported
232        syntax: (lldb) findregistryprop gIOPMRootDomain IOSleepSupported
233        syntax: (lldb) findregistryprop gIOPMRootDomain "Supported Features"
234    """
235    if not cmd_args or len(cmd_args) < 2:
236        print "Please specify the address of a IORegistry entry and the property you're looking for"
237        print FindRegistryProp.__doc__
238        return
239
240    entry = kern.GetValueFromAddress(cmd_args[0], 'IOService *')
241    propertyTable = entry.fPropertyTable
242    print GetObjectSummary(LookupKeyInPropTable(propertyTable, cmd_args[1]))
243
244@lldb_command('readioport8')
245def ReadIOPort8(cmd_args=None):
246    """ Read value stored in the specified IO port. The CPU can be optionally
247        specified as well.
248        Prints 0xBAD10AD in case of a bad read
249        Syntax: (lldb) readioport8 <port> [lcpu (kernel's numbering convention)]
250    """
251    if not cmd_args:
252        print "Please specify a port to read out of"
253        print ReadIOPort8.__doc__
254        return
255
256    portAddr = ArgumentStringToInt(cmd_args[0])
257    if len(cmd_args) >= 2:
258        lcpu = ArgumentStringToInt(cmd_args[1])
259    else:
260        lcpu = xnudefines.lcpu_self
261
262    ReadIOPortInt(portAddr, 1, lcpu)
263
264@lldb_command('readioport16')
265def ReadIOPort8(cmd_args=None):
266    """ Read value stored in the specified IO port. The CPU can be optionally
267        specified as well.
268        Prints 0xBAD10AD in case of a bad read
269        Syntax: (lldb) readioport16 <port> [lcpu (kernel's numbering convention)]
270    """
271    if not cmd_args:
272        print "Please specify a port to read out of"
273        print ReadIOPort16.__doc__
274        return
275
276    portAddr = ArgumentStringToInt(cmd_args[0])
277    if len(cmd_args) >= 2:
278        lcpu = ArgumentStringToInt(cmd_args[1])
279    else:
280        lcpu = xnudefines.lcpu_self
281
282    ReadIOPortInt(portAddr, 2, lcpu)
283
284@lldb_command('readioport32')
285def ReadIOPort8(cmd_args=None):
286    """ Read value stored in the specified IO port. The CPU can be optionally
287        specified as well.
288        Prints 0xBAD10AD in case of a bad read
289        Syntax: (lldb) readioport32 <port> [lcpu (kernel's numbering convention)]
290    """
291    if not cmd_args:
292        print "Please specify a port to read out of"
293        print ReadIOPort32.__doc__
294        return
295
296    portAddr = ArgumentStringToInt(cmd_args[0])
297    if len(cmd_args) >= 2:
298        lcpu = ArgumentStringToInt(cmd_args[1])
299    else:
300        lcpu = xnudefines.lcpu_self
301
302    ReadIOPortInt(portAddr, 4, lcpu)
303
304@lldb_command('writeioport8')
305def WriteIOPort8(cmd_args=None):
306    """ Write the value to the specified IO port. The size of the value is
307        determined by the name of the command. The CPU used can be optionally
308        specified as well.
309        Syntax: (lldb) writeioport8 <port> <value> [lcpu (kernel's numbering convention)]
310    """
311    if not cmd_args or len(cmd_args) < 2:
312        print "Please specify a port to write to, followed by the value you want to write"
313        print WriteIOPort8.__doc__
314        return
315
316    portAddr = ArgumentStringToInt(cmd_args[0])
317    value = ArgumentStringToInt(cmd_args[1])
318
319    if len(cmd_args) >= 3:
320        lcpu = ArgumentStringToInt(cmd_args[2])
321    else:
322        lcpu = xnudefines.lcpu_self
323
324    WriteIOPortInt(portAddr, 1, value, lcpu)
325
326@lldb_command('writeioport16')
327def WriteIOPort8(cmd_args=None):
328    """ Write the value to the specified IO port. The size of the value is
329        determined by the name of the command. The CPU used can be optionally
330        specified as well.
331        Syntax: (lldb) writeioport16 <port> <value> [lcpu (kernel's numbering convention)]
332    """
333    if not cmd_args or len(cmd_args) < 2:
334        print "Please specify a port to write to, followed by the value you want to write"
335        print WriteIOPort16.__doc__
336        return
337
338    portAddr = ArgumentStringToInt(cmd_args[0])
339    value = ArgumentStringToInt(cmd_args[1])
340
341    if len(cmd_args) >= 3:
342        lcpu = ArgumentStringToInt(cmd_args[2])
343    else:
344        lcpu = xnudefines.lcpu_self
345
346    WriteIOPortInt(portAddr, 2, value, lcpu)
347
348@lldb_command('writeioport32')
349def WriteIOPort8(cmd_args=None):
350    """ Write the value to the specified IO port. The size of the value is
351        determined by the name of the command. The CPU used can be optionally
352        specified as well.
353        Syntax: (lldb) writeioport32 <port> <value> [lcpu (kernel's numbering convention)]
354    """
355    if not cmd_args or len(cmd_args) < 2:
356        print "Please specify a port to write to, followed by the value you want to write"
357        print WriteIOPort32.__doc__
358        return
359
360    portAddr = ArgumentStringToInt(cmd_args[0])
361    value = ArgumentStringToInt(cmd_args[1])
362
363    if len(cmd_args) >= 3:
364        lcpu = ArgumentStringToInt(cmd_args[2])
365    else:
366        lcpu = xnudefines.lcpu_self
367
368    WriteIOPortInt(portAddr, 4, value, lcpu)
369
370@lldb_command('showioservicepm')
371def ShowIOServicePM(cmd_args=None):
372    """ Routine to dump the IOServicePM object
373        Syntax: (lldb) showioservicepm <IOServicePM pointer>
374    """
375    if not cmd_args:
376        print "Please enter the pointer to the IOServicePM object you'd like to introspect"
377        print ShowIOServicePM.__doc__
378        return
379
380    iopmpriv = kern.GetValueFromAddress(cmd_args[0], 'IOServicePM *')
381    out_string = "MachineState {0: <6d} (".format(iopmpriv.MachineState)
382
383    # Power state map
384    pstate_map = {
385            0:  'kIOPM_Finished',
386            1:  'kIOPM_OurChangeTellClientsPowerDown',
387            2:  'kIOPM_OurChangeTellClientsPowerDown',
388            3:  'kIOPM_OurChangeNotifyInterestedDriversWillChange',
389            4:  'kIOPM_OurChangeSetPowerState',
390            5:  'kIOPM_OurChangeWaitForPowerSettle',
391            6:  'kIOPM_OurChangeNotifyInterestedDriversDidChange',
392            7:  'kIOPM_OurChangeTellCapabilityDidChange',
393            8:  'kIOPM_OurChangeFinish',
394            9:  'Unused_MachineState_9',
395            10: 'kIOPM_ParentChangeTellPriorityClientsPowerDown',
396            11: 'kIOPM_ParentChangeNotifyInterestedDriversWillChange',
397            12: 'kIOPM_ParentChangeSetPowerState',
398            13: 'kIOPM_ParentChangeWaitForPowerSettle',
399            14: 'kIOPM_ParentChangeNotifyInterestedDriversDidChange',
400            15: 'kIOPM_ParentChangeTellCapabilityDidChange',
401            16: 'kIOPM_ParentChangeAcknowledgePowerChange',
402            17: 'kIOPM_NotifyChildrenStart',
403            18: 'kIOPM_NotifyChildrenOrdered',
404            19: 'kIOPM_NotifyChildrenDelayed',
405            20: 'kIOPM_SyncTellClientsPowerDown',
406            21: 'kIOPM_SyncTellPriorityClientsPowerDown',
407            22: 'kIOPM_SyncNotifyWillChange',
408            23: 'kIOPM_SyncNotifyDidChange',
409            24: 'kIOPM_SyncTellCapabilityDidChange',
410            25: 'kIOPM_SyncFinish',
411            26: 'kIOPM_TellCapabilityChangeDone',
412            27: 'kIOPM_DriverThreadCallDone'
413        }
414    powerstate = unsigned(iopmpriv.MachineState)
415    if powerstate in pstate_map:
416        out_string += "{0:s}".format(pstate_map[powerstate])
417    else:
418        out_string += "Unknown_MachineState"
419    out_string += "), "
420
421    if iopmpriv.MachineState != 20:
422        out_string += "DriverTimer = {0: <6d}, SettleTime = {1: < 6d}, HeadNoteFlags = {2: #12x}, HeadNotePendingAcks = {3: #012x}, ".format(
423                unsigned(iopmpriv.DriverTimer),
424                unsigned(iopmpriv.SettleTimeUS),
425                unsigned(iopmpriv.HeadNoteChangeFlags),
426                unsigned(iopmpriv.HeadNotePendingAcks))
427
428    if iopmpriv.DeviceOverrideEnabled != 0:
429        out_string += "DeviceOverrides, "
430
431    out_string += "DeviceDesire = {0: <6d}, DesiredPowerState = {1: <6d}, PreviousRequest = {2: <6d}\n".format(
432            unsigned(iopmpriv.DeviceDesire),
433            unsigned(iopmpriv.DesiredPowerState),
434            unsigned(iopmpriv.PreviousRequestPowerFlags))
435
436    print out_string
437
438######################################
439#  Helper routines
440######################################
441def ShowRegistryEntryRecurse(entry, prefix, printProps):
442    """ prints registry entry summary and recurses through all its children.
443    """
444    # Setup
445    global plane
446    out_string = ""
447    plen = (len(prefix)//2)
448    registryTable = entry.fRegistryTable
449    propertyTable = entry.fPropertyTable
450
451    # Print entry details
452    print "{0:s}{1:s}".format(prefix, GetRegistryEntrySummary(entry))
453    # Printing large property tables make it look like lldb is 'stuck'
454    if printProps:
455        print GetRegDictionary(propertyTable, prefix + "  | ")
456
457    # Recurse
458    if plane is None:
459        childKey = kern.globals.gIOServicePlane.keys[1]
460    else:
461        childKey = plane.keys[1]
462    childArray = LookupKeyInOSDict(registryTable, childKey)
463    if childArray is not None:
464        idx = 0
465        ca = Cast(childArray, 'OSArray *')
466        count = unsigned(ca.count)
467        while idx < count:
468            if plen != 0 and plen != 1 and (plen & (plen - 1)) == 0:
469                ShowRegistryEntryRecurse(Cast(ca.array[idx], 'IORegistryEntry *'), prefix + "| ", printProps)
470            else:
471                ShowRegistryEntryRecurse(Cast(ca.array[idx], 'IORegistryEntry *'), prefix + "  ", printProps)
472            idx += 1
473
474def FindRegistryEntryRecurse(entry, search_name, stopAfterFirst):
475    """ Checks if given registry entry's name matches the search_name we're looking for
476        If yes, it prints the entry's summary and then recurses through its children
477        If no, it does nothing and recurses through its children
478    """
479    # Setup
480    global plane
481    registryTable = entry.fRegistryTable
482    propertyTable = entry.fPropertyTable
483
484    # Compare
485    name = None
486    name = LookupKeyInOSDict(registryTable, kern.globals.gIOServicePlane.nameKey)
487    if name is None:
488        name = LookupKeyInOSDict(registryTable, kern.globals.gIONameKey)
489    if name is None:
490        name = LookupKeyInOSDict(propertyTable, kern.globals.gIOClassKey)
491
492    if name is not None:
493        if str(Cast(name, 'OSString *').string) == search_name:
494            print GetRegistryEntrySummary(entry)
495            if stopAfterFirst is True:
496                return True
497    elif Cast(entry, 'IOService *').pwrMgt and Cast(entry, 'IOService *').pwrMgt.Name:
498        name = Cast(entry, 'IOService *').pwrMgt.Name
499        if str(name) == search_name:
500            print GetRegistryEntrySummary(entry)
501            if stopAfterFirst is True:
502                return True
503
504    # Recurse
505    if plane is None:
506        childKey = kern.globals.gIOServicePlane.keys[1]
507    else:
508        childKey = plane.keys[1]
509    childArray = LookupKeyInOSDict(registryTable, childKey)
510    if childArray is not None:
511        idx = 0
512        ca = Cast(childArray, 'OSArray *')
513        count = unsigned(ca.count)
514        while idx < count:
515            if FindRegistryEntryRecurse(Cast(ca.array[idx], 'IORegistryEntry *'), search_name, stopAfterFirst) is True:
516                return True
517            idx += 1
518    return False
519
520def FindRegistryObjectRecurse(entry, search_name):
521    """ Checks if given registry entry's name matches the search_name we're looking for
522        If yes, return the entry
523        If no, it does nothing and recurses through its children
524        Implicitly stops after finding the first entry
525    """
526    # Setup
527    global plane
528    registryTable = entry.fRegistryTable
529    propertyTable = entry.fPropertyTable
530
531    # Compare
532    name = None
533    name = LookupKeyInOSDict(registryTable, kern.globals.gIOServicePlane.nameKey)
534    if name is None:
535        name = LookupKeyInOSDict(registryTable, kern.globals.gIONameKey)
536    if name is None:
537        name = LookupKeyInOSDict(propertyTable, kern.globals.gIOClassKey)
538
539    if name is not None:
540        if str(Cast(name, 'OSString *').string) == search_name:
541            return entry
542    elif Cast(entry, 'IOService *').pwrMgt and Cast(entry, 'IOService *').pwrMgt.Name:
543        name = Cast(entry, 'IOService *').pwrMgt.Name
544        if str(name) == search_name:
545            return entry
546
547    # Recurse
548    if plane is None:
549        childKey = kern.globals.gIOServicePlane.keys[1]
550    else:
551        childKey = plane.keys[1]
552    childArray = LookupKeyInOSDict(registryTable, childKey)
553    if childArray is not None:
554        ca = Cast(childArray, 'OSArray *')
555        for idx in range(ca.count):
556            registry_object = FindRegistryObjectRecurse(Cast(ca.array[idx], 'IORegistryEntry *'), search_name)
557            if not registry_object or int(registry_object) == int(0):
558                continue
559            else:
560                return registry_object
561    return None
562
563def LookupKeyInOSDict(osdict, key):
564    """ Returns the value corresponding to a given key in a OSDictionary
565        Returns None if the key was not found
566    """
567    if not osdict:
568        return
569    count = unsigned(osdict.count)
570    result = None
571    idx = 0
572    while idx < count and result is None:
573        if key == osdict.dictionary[idx].key:
574            result = osdict.dictionary[idx].value
575        idx += 1
576    return result
577
578def LookupKeyInPropTable(propertyTable, key_str):
579    """ Returns the value corresponding to a given key from a registry entry's property table
580        Returns None if the key was not found
581        The property that is being searched for is specified as a string in key_str
582    """
583    if not propertyTable:
584        return
585    count = unsigned(propertyTable.count)
586    result = None
587    idx = 0
588    while idx < count and result is None:
589        if key_str == str(propertyTable.dictionary[idx].key.string):
590            result = propertyTable.dictionary[idx].value
591        idx += 1
592    return result
593
594def GetRegDictionary(osdict, prefix):
595    """ Returns a specially formatted string summary of the given OSDictionary
596        This is done in order to pretty-print registry property tables in showregistry
597        and other macros
598    """
599    out_string = prefix + "{\n"
600    idx = 0
601    count = unsigned(osdict.count)
602
603    while idx < count:
604        out_string += prefix + "  " + GetObjectSummary(osdict.dictionary[idx].key) + " = " + GetObjectSummary(osdict.dictionary[idx].value) + "\n"
605        idx += 1
606    out_string += prefix + "}\n"
607    return out_string
608
609def GetString(string):
610    """ Returns the python string representation of a given OSString
611    """
612    out_string = "\"{0:s}\"".format(Cast(string, 'OSString *').string)
613    return out_string
614
615def GetNumber(num):
616    out_string = "{0:d}".format(Cast(num, 'OSNumber *').value)
617    return out_string
618
619def GetBoolean(b):
620    """ Shows info about a given OSBoolean
621    """
622    out_string = ""
623    if b == kern.globals.gOSBooleanFalse:
624        out_string += "No"
625    else:
626        out_string += "Yes"
627    return out_string
628
629def GetMetaClass(mc):
630    """ Shows info about a given OSSymbol
631    """
632    out_string = "{0: <5d}x {1: >5d} bytes {2:s}\n".format(mc.instanceCount, mc.classSize, mc.className.string)
633    return out_string
634
635def GetArray(arr):
636    """ Returns a string containing info about a given OSArray
637    """
638    out_string = ""
639    idx = 0
640    count = unsigned(arr.count)
641
642    while idx < count:
643        obj = arr.array[idx]
644        idx += 1
645        out_string += GetObjectSummary(obj)
646        if idx < unsigned(arr.count):
647            out_string += ","
648    return out_string
649
650def GetDictionary(d):
651    """ Returns a string containing info about a given OSDictionary
652    """
653    out_string = "{"
654    idx = 0
655    count = unsigned(d.count)
656
657    while idx < count:
658        obj = d.dictionary[idx].key
659        out_string += GetObjectSummary(obj) + "="
660        obj = d.dictionary[idx].value
661        idx += 1
662        out_string += GetObjectSummary(obj)
663        if idx < count:
664            out_string += ","
665    out_string += "}"
666    return out_string
667
668def GetSet(se):
669    """ Returns a string containing info about a given OSSet
670    """
671    out_string += "[" + GetArray(se.members) + "]"
672    return out_string
673
674def ReadIOPortInt(addr, numbytes, lcpu):
675    """ Prints results after reading a given ioport
676    """
677    result = 0xBAD10AD
678
679    if "kdp" != GetConnectionProtocol():
680        print "Target is not connected over kdp. Nothing to do here."
681        return
682
683    # Set up the manual KDP packet
684    input_address = unsigned(addressof(kern.globals.manual_pkt.input))
685    len_address = unsigned(addressof(kern.globals.manual_pkt.len))
686    data_address = unsigned(addressof(kern.globals.manual_pkt.data))
687    if not WriteInt32ToMemoryAddress(0, input_address):
688        print "0x{0: <4x}: 0x{1: <1x}".format(addr, result)
689        return
690
691    kdp_pkt_size = GetType('kdp_readioport_req_t').GetByteSize()
692    if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address):
693        print "0x{0: <4x}: 0x{1: <1x}".format(addr, result)
694        return
695
696    kgm_pkt = kern.GetValueFromAddress(data_address, 'kdp_readioport_req_t *')
697
698    header_value = GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_READIOPORT'), length = kdp_pkt_size)
699
700    if( WriteInt64ToMemoryAddress((header_value), int(addressof(kgm_pkt.hdr))) and
701        WriteInt16ToMemoryAddress(addr, int(addressof(kgm_pkt.address))) and
702        WriteInt32ToMemoryAddress(numbytes, int(addressof(kgm_pkt.nbytes))) and
703        WriteInt16ToMemoryAddress(lcpu, int(addressof(kgm_pkt.lcpu))) and
704        WriteInt32ToMemoryAddress(1, input_address)
705        ):
706
707        result_pkt = Cast(addressof(kern.globals.manual_pkt.data), 'kdp_readioport_reply_t *')
708
709        if(result_pkt.error == 0):
710            print "This macro is incomplete till <rdar://problem/12868059> is fixed"
711            # FIXME: Uncomment me when <rdar://problem/12868059> is fixed
712            #if numbytes == 1:
713            #    result = dereference(Cast(result_pkt.data, 'uint8_t *'))
714            #elif numbytes == 2:
715            #    result = dereference(Cast(result_pkt.data, 'uint16_t *'))
716            #elif numbytes == 4:
717            #    result = dereference(cast(result_pkt.data, 'uint32_t *'))
718
719    print "0x{0: <4x}: 0x{1: <1x}".format(addr, result)
720
721def WriteIOPortInt(addr, numbytes, value, lcpu):
722    """ Writes 'value' into ioport specified by 'addr'. Prints errors if it encounters any
723    """
724    if "kdp" != GetConnectionProtocol():
725        print "Target is not connected over kdp. Nothing to do here."
726        return
727
728    # Set up the manual KDP packet
729    input_address = unsigned(addressof(kern.globals.manual_pkt.input))
730    len_address = unsigned(addressof(kern.globals.manual_pkt.len))
731    data_address = unsigned(addressof(kern.globals.manual_pkt.data))
732    if not WriteInt32ToMemoryAddress(0, input_address):
733        print "error writing 0x{0: x} to port 0x{1: <4x}".format(value, addr)
734        return
735
736    kdp_pkt_size = GetType('kdp_writeioport_req_t').GetByteSize()
737    if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address):
738        print "error writing 0x{0: x} to port 0x{1: <4x}".format(value, addr)
739        return
740
741    kgm_pkt = kern.GetValueFromAddress(data_address, 'kdp_writeioport_req_t *')
742
743    header_value = GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_WRITEIOPORT'), length = kdp_pkt_size)
744
745    if( WriteInt64ToMemoryAddress((header_value), int(addressof(kgm_pkt.hdr))) and
746        WriteInt16ToMemoryAddress(addr, int(addressof(kgm_pkt.address))) and
747        WriteInt32ToMemoryAddress(numbytes, int(addressof(kgm_pkt.nbytes))) and
748        WriteInt16ToMemoryAddress(lcpu, int(addressof(kgm_pkt.lcpu)))
749        ):
750        print "This macro is incomplete till <rdar://problem/12868059> is fixed"
751        # FIXME: Uncomment me when <rdar://problem/12868059> is fixed
752        #if numbytes == 1:
753        #    if not WriteInt8ToMemoryAddress(value, int(addressof(kgm_pkt.data))):
754        #        print "error writing 0x{0: x} to port 0x{1: <4x}".format(value, addr)
755        #elif numbytes == 2:
756        #    if not WriteInt16ToMemoryAddress(value, int(addressof(kgm_pkt.data))):
757        #        print "error writing 0x{0: x} to port 0x{1: <4x}".format(value, addr)
758        #elif numbytes == 4:
759        #    if not WriteInt32ToMemoryAddress(value, int(addressof(kgm_pkt.data))):
760        #        print "error writing 0x{0: x} to port 0x{1: <4x}".format(value, addr)
761
762        if not WriteInt32ToMemoryAddress(1, input_address):
763            print "error writing 0x{0: x} to port 0x{1: <4x}".format(value, addr)
764            return
765
766        result_pkt = Cast(addressof(kern.globals.manual_pkt.data), 'kdp_writeioport_reply_t *')
767
768        # Done with the write
769        if(result_pkt.error == 0):
770            print "Writing 0x {0: x} to port {1: <4x} was successful".format(value, addr)
771    else:
772        print "error writing 0x{0: x} to port 0x{1: <4x}".format(value, addr)
773
774