5 ######################################
7 ######################################
10 #####################################
12 #####################################
13 def CastIOKitClass(obj
, target_type
):
14 """ Type cast an object to another IOKIT CPP class.
16 obj - core.value object representing some C construct in lldb
17 target_type - str : ex 'OSString *'
20 v
= Cast(obj
, target_type
)
21 v
.GetSBValue().SetPreferDynamicValue(lldb
.eNoDynamicValues
)
24 ######################################
26 ######################################
27 @lldb_type_summary(['OSObject *'])
29 def GetObjectSummary(obj
):
30 """ Show info about an OSObject - its vtable ptr and retain count, & more info for simple container classes.
35 vt
= dereference(Cast(obj
, 'uintptr_t *')) - 2 * sizeof('uintptr_t')
36 vtype
= kern
.SymbolicateFromAddress(vt
)
38 vtype_str
= " <" + vtype
[0].GetName() + ">"
41 if hasattr(obj
, 'retainCount'):
42 retCount
= (obj
.retainCount
& 0xffff)
43 cntnrRetCount
= (obj
.retainCount
>> 16)
44 out_string
= "`object 0x{0: <16x}, vt 0x{1: <16x}{2:s}, retain count {3:d}, container retain {4:d}` ".format(obj
, vt
, vtype_str
, retCount
, cntnrRetCount
)
46 out_string
= "`object 0x{0: <16x}, vt 0x{1: <16x}{2:s}` ".format(obj
, vt
, vtype_str
)
48 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV8OSString')
50 out_string
+= GetString(obj
)
53 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV8OSSymbol')
55 out_string
+= GetString(obj
)
58 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV8OSNumber')
60 out_string
+= GetNumber(obj
)
63 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV9OSBoolean')
65 out_string
+= GetBoolean(obj
)
68 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV7OSArray')
70 out_string
+= "(" + GetArray(CastIOKitClass(obj
, 'OSArray *')) + ")"
73 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV5OSSet')
75 out_string
+= GetSet(CastIOKitClass(obj
, 'OSSet *'))
78 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV12OSDictionary')
80 out_string
+= GetDictionary(CastIOKitClass(obj
, 'OSDictionary *'))
86 def GetObjectTypeStr(obj
):
87 """ Return the type of an OSObject's container class
92 vt
= dereference(Cast(obj
, 'uintptr_t *')) - 2 * sizeof('uintptr_t')
93 vtype
= kern
.SymbolicateFromAddress(vt
)
95 return vtype
[0].GetName()
97 # See if the value is in a kext with no symbols
98 for kval
in IterateLinkedList(kern
.globals.kmod
, 'next'):
99 if vt
>= unsigned(kval
.address
) and vt
<= (unsigned(kval
.address
) + unsigned(kval
.size
)):
100 return "kmod:{:s}+{:#0x}".format(kval
.name
, vt
- unsigned(kval
.address
))
104 @lldb_type_summary(['IORegistryEntry *'])
106 def GetRegistryEntrySummary(entry
):
107 """ returns a string containing summary information about an IORegistry
108 object including it's registry id , vtable ptr and retain count
112 registryTable
= entry
.fRegistryTable
113 propertyTable
= entry
.fPropertyTable
115 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
117 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
119 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
122 out_string
+= "+-o {0:s} ".format(GetString(CastIOKitClass(name
, 'OSString *')))
123 elif CastIOKitClass(entry
, 'IOService *').pwrMgt
and CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
:
124 out_string
+= "+-o {0:s} ".format(CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
)
126 out_string
+= "+-o ?? "
128 # I'm using uintptr_t for now to work around <rdar://problem/12749733> FindFirstType & Co. should allow you to make pointer types directly
129 vtableAddr
= dereference(Cast(entry
, 'uintptr_t *')) - 2 * sizeof('uintptr_t *')
130 vtype
= kern
.SymbolicateFromAddress(vtableAddr
)
131 if vtype
is None or len(vtype
) < 1:
132 out_string
+= "<object 0x{0: <16x}, id 0x{1:x}, vtable 0x{2: <16x}".format(entry
, CastIOKitClass(entry
, 'IORegistryEntry *').reserved
.fRegistryEntryID
, vtableAddr
)
134 out_string
+= "<object 0x{0: <16x}, id 0x{1:x}, vtable 0x{2: <16x} <{3:s}>".format(entry
, CastIOKitClass(entry
, 'IORegistryEntry *').reserved
.fRegistryEntryID
,
135 vtableAddr
, vtype
[0].GetName())
137 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV15IORegistryEntry')
138 if vtableAddr
!= ztvAddr
:
140 state
= CastIOKitClass(entry
, 'IOService *').__state
[0]
141 # kIOServiceRegisteredState
144 out_string
+= "registered, "
145 # kIOServiceMatchedState
148 out_string
+= "matched, "
149 #kIOServiceInactiveState
152 busyCount
= (CastIOKitClass(entry
, 'IOService *').__state
[1] & 0xff)
153 retCount
= (CastIOKitClass(entry
, 'IOService *').retainCount
& 0xffff)
154 out_string
+= "active, busy {0}, retain count {1}>".format(busyCount
, retCount
)
157 ######################################
159 ######################################
160 @lldb_command('showallclasses')
161 def ShowAllClasses(cmd_args
=None):
162 """ Show the instance counts and ivar size of all OSObject subclasses.
163 See ioclasscount man page for details
166 count
= unsigned(kern
.globals.sAllClassesDict
.count
)
169 meta
= CastIOKitClass(kern
.globals.sAllClassesDict
.dictionary
[idx
].value
, 'OSMetaClass *')
171 print GetMetaClass(meta
)
173 @lldb_command('showobject')
174 def ShowObject(cmd_args
=None):
175 """ Show info about an OSObject - its vtable ptr and retain count, & more info for simple container classes.
178 print "Please specify the address of the OSObject whose info you want to view. Type help showobject for help"
181 obj
= kern
.GetValueFromAddress(cmd_args
[0], 'OSObject *')
182 print GetObjectSummary(obj
)
185 @lldb_command('dumpobject')
186 def DumpObject(cmd_args
=None):
187 """ Dumps object information if it is a valid object confirmed by showobject
188 Usage: dumpobject <address of object to be dumped> [class/struct type of object]
191 print "No arguments passed"
192 print DumpObject
.__doc
__
195 if len(cmd_args
) == 1:
197 object_info
= lldb_run_command("showobject {:s}".format(cmd_args
[0]))
199 print "Error!! showobject failed due to invalid value"
200 print DumpObject
.__doc
__
203 srch
= re
.search(r
'<vtable for ([A-Za-z].*)>', object_info
)
205 print "Error!! Couldn't find object in registry, input type manually as 2nd argument"
206 print DumpObject
.__doc
__
209 object_type
= srch
.group(1)
211 type_lookup
= lldb_run_command("image lookup -t {:s}".format(cmd_args
[1]))
212 if type_lookup
.find(cmd_args
[1])!= -1:
213 object_type
= cmd_args
[1]
215 print "Error!! Input type {:s} isn't available in image lookup".format(cmd_args
[1])
218 print "******** Object Dump for value \'{:s}\' with type \"{:s}\" ********".format(cmd_args
[0], object_type
)
219 print lldb_run_command("p/x *({:s}*){:s}".format(object_type
, cmd_args
[0]))
221 #EndMacro: dumpobject
223 @lldb_command('setregistryplane')
224 def SetRegistryPlane(cmd_args
=None):
225 """ Set the plane to be used for the IOKit registry macros
226 syntax: (lldb) setregistryplane 0 - will display all known planes
227 syntax: (lldb) setregistryplane 0xaddr - will set the registry plane to 0xaddr
228 syntax: (lldb) setregistryplane gIODTPlane - will set the registry plane to gIODTPlane
231 print "Please specify the name of the plane you want to use with the IOKit registry macros."
232 print SetRegistryPlane
.__doc
__
234 if cmd_args
[0] == "0":
235 print GetObjectSummary(kern
.globals.gIORegistryPlanes
)
238 plane
= kern
.GetValueFromAddress(cmd_args
[0], 'IORegistryPlane *')
241 @lldb_command('showregistryentry')
242 def ShowRegistryEntry(cmd_args
=None):
243 """ Show info about a registry entry; its properties and descendants in the current plane
244 syntax: (lldb) showregistryentry 0xaddr
245 syntax: (lldb) showregistryentry gIOPMRootDomain
248 print "Please specify the address of the registry entry whose info you want to view."
249 print ShowRegistryEntry
.__doc
__
252 entry
= kern
.GetValueFromAddress(cmd_args
[0], 'IORegistryEntry *')
253 ShowRegistryEntryRecurse(entry
, "", True)
255 @lldb_command('showregistry')
256 def ShowRegistry(cmd_args
=None):
257 """ Show info about all registry entries in the current plane
258 If prior to invoking this command no registry plane is specified
259 using 'setregistryplane', the command defaults to the IOService plane
261 ShowRegistryEntryRecurse(kern
.globals.gRegistryRoot
, "", False)
263 @lldb_command('showregistryprops')
264 def ShowRegistryProps(cmd_args
=None):
265 """ Show info about all registry entries in the current plane, and their properties
266 If prior to invoking this command no registry plane is specified
267 using 'setregistryplane', the command defaults to the IOService plane
269 ShowRegistryEntryRecurse(kern
.globals.gRegistryRoot
, "", True)
271 @lldb_command('findregistryentry')
272 def FindRegistryEntry(cmd_args
=None):
273 """ Search for registry entry that matches the given string
274 If prior to invoking this command no registry plane is specified
275 using 'setregistryplane', the command defaults to searching entries from the IOService plane
276 syntax: (lldb) findregistryentries AppleACPICPU - will find the first registry entry that matches AppleACPICPU
279 print "Please specify the name of the registry entry you want to find"
280 print FindRegistryEntry
.__doc
__
283 FindRegistryEntryRecurse(kern
.globals.gRegistryRoot
, cmd_args
[0], True)
285 @lldb_command('findregistryentries')
286 def FindRegistryEntries(cmd_args
=None):
287 """ Search for all registry entries that match the given string
288 If prior to invoking this command no registry plane is specified
289 using 'setregistryplane', the command defaults to searching entries from the IOService plane
290 syntax: (lldb) findregistryentries AppleACPICPU - will find all registry entries that match AppleACPICPU
293 print "Please specify the name of the registry entry/entries you want to find"
294 print FindRegistryEntries
.__doc
__
297 FindRegistryEntryRecurse(kern
.globals.gRegistryRoot
, cmd_args
[0], False)
299 @lldb_command('findregistryprop')
300 def FindRegistryProp(cmd_args
=None):
301 """ Given a registry entry, print out the contents for the property that matches
303 syntax: (lldb) findregistryprop 0xaddr IOSleepSupported
304 syntax: (lldb) findregistryprop gIOPMRootDomain IOSleepSupported
305 syntax: (lldb) findregistryprop gIOPMRootDomain "Supported Features"
307 if not cmd_args
or len(cmd_args
) < 2:
308 print "Please specify the address of a IORegistry entry and the property you're looking for"
309 print FindRegistryProp
.__doc
__
312 entry
= kern
.GetValueFromAddress(cmd_args
[0], 'IOService *')
313 propertyTable
= entry
.fPropertyTable
314 print GetObjectSummary(LookupKeyInPropTable(propertyTable
, cmd_args
[1]))
316 @lldb_command('readioport8')
317 def ReadIOPort8(cmd_args
=None):
318 """ Read value stored in the specified IO port. The CPU can be optionally
320 Prints 0xBAD10AD in case of a bad read
321 Syntax: (lldb) readioport8 <port> [lcpu (kernel's numbering convention)]
324 print "Please specify a port to read out of"
325 print ReadIOPort8
.__doc__
328 portAddr
= ArgumentStringToInt(cmd_args
[0])
329 if len(cmd_args
) >= 2:
330 lcpu
= ArgumentStringToInt(cmd_args
[1])
332 lcpu
= xnudefines
.lcpu_self
334 ReadIOPortInt(portAddr
, 1, lcpu
)
336 @lldb_command('readioport16')
337 def ReadIOPort16(cmd_args
=None):
338 """ Read value stored in the specified IO port. The CPU can be optionally
340 Prints 0xBAD10AD in case of a bad read
341 Syntax: (lldb) readioport16 <port> [lcpu (kernel's numbering convention)]
344 print "Please specify a port to read out of"
345 print ReadIOPort16
.__doc__
348 portAddr
= ArgumentStringToInt(cmd_args
[0])
349 if len(cmd_args
) >= 2:
350 lcpu
= ArgumentStringToInt(cmd_args
[1])
352 lcpu
= xnudefines
.lcpu_self
354 ReadIOPortInt(portAddr
, 2, lcpu
)
356 @lldb_command('readioport32')
357 def ReadIOPort32(cmd_args
=None):
358 """ Read value stored in the specified IO port. The CPU can be optionally
360 Prints 0xBAD10AD in case of a bad read
361 Syntax: (lldb) readioport32 <port> [lcpu (kernel's numbering convention)]
364 print "Please specify a port to read out of"
365 print ReadIOPort32
.__doc__
368 portAddr
= ArgumentStringToInt(cmd_args
[0])
369 if len(cmd_args
) >= 2:
370 lcpu
= ArgumentStringToInt(cmd_args
[1])
372 lcpu
= xnudefines
.lcpu_self
374 ReadIOPortInt(portAddr
, 4, lcpu
)
376 @lldb_command('writeioport8')
377 def WriteIOPort8(cmd_args
=None):
378 """ Write the value to the specified IO port. The size of the value is
379 determined by the name of the command. The CPU used can be optionally
381 Syntax: (lldb) writeioport8 <port> <value> [lcpu (kernel's numbering convention)]
383 if not cmd_args
or len(cmd_args
) < 2:
384 print "Please specify a port to write to, followed by the value you want to write"
385 print WriteIOPort8
.__doc__
388 portAddr
= ArgumentStringToInt(cmd_args
[0])
389 value
= ArgumentStringToInt(cmd_args
[1])
391 if len(cmd_args
) >= 3:
392 lcpu
= ArgumentStringToInt(cmd_args
[2])
394 lcpu
= xnudefines
.lcpu_self
396 WriteIOPortInt(portAddr
, 1, value
, lcpu
)
398 @lldb_command('writeioport16')
399 def WriteIOPort16(cmd_args
=None):
400 """ Write the value to the specified IO port. The size of the value is
401 determined by the name of the command. The CPU used can be optionally
403 Syntax: (lldb) writeioport16 <port> <value> [lcpu (kernel's numbering convention)]
405 if not cmd_args
or len(cmd_args
) < 2:
406 print "Please specify a port to write to, followed by the value you want to write"
407 print WriteIOPort16
.__doc__
410 portAddr
= ArgumentStringToInt(cmd_args
[0])
411 value
= ArgumentStringToInt(cmd_args
[1])
413 if len(cmd_args
) >= 3:
414 lcpu
= ArgumentStringToInt(cmd_args
[2])
416 lcpu
= xnudefines
.lcpu_self
418 WriteIOPortInt(portAddr
, 2, value
, lcpu
)
420 @lldb_command('writeioport32')
421 def WriteIOPort32(cmd_args
=None):
422 """ Write the value to the specified IO port. The size of the value is
423 determined by the name of the command. The CPU used can be optionally
425 Syntax: (lldb) writeioport32 <port> <value> [lcpu (kernel's numbering convention)]
427 if not cmd_args
or len(cmd_args
) < 2:
428 print "Please specify a port to write to, followed by the value you want to write"
429 print WriteIOPort32
.__doc__
432 portAddr
= ArgumentStringToInt(cmd_args
[0])
433 value
= ArgumentStringToInt(cmd_args
[1])
435 if len(cmd_args
) >= 3:
436 lcpu
= ArgumentStringToInt(cmd_args
[2])
438 lcpu
= xnudefines
.lcpu_self
440 WriteIOPortInt(portAddr
, 4, value
, lcpu
)
442 @lldb_command('showioservicepm')
443 def ShowIOServicePM(cmd_args
=None):
444 """ Routine to dump the IOServicePM object
445 Syntax: (lldb) showioservicepm <IOServicePM pointer>
448 print "Please enter the pointer to the IOServicePM object you'd like to introspect"
449 print ShowIOServicePM
.__doc
__
452 iopmpriv
= kern
.GetValueFromAddress(cmd_args
[0], 'IOServicePM *')
453 out_string
= "MachineState {0: <6d} (".format(iopmpriv
.MachineState
)
458 1: 'kIOPM_OurChangeTellClientsPowerDown',
459 2: 'kIOPM_OurChangeTellClientsPowerDown',
460 3: 'kIOPM_OurChangeNotifyInterestedDriversWillChange',
461 4: 'kIOPM_OurChangeSetPowerState',
462 5: 'kIOPM_OurChangeWaitForPowerSettle',
463 6: 'kIOPM_OurChangeNotifyInterestedDriversDidChange',
464 7: 'kIOPM_OurChangeTellCapabilityDidChange',
465 8: 'kIOPM_OurChangeFinish',
466 9: 'Unused_MachineState_9',
467 10: 'kIOPM_ParentChangeTellPriorityClientsPowerDown',
468 11: 'kIOPM_ParentChangeNotifyInterestedDriversWillChange',
469 12: 'kIOPM_ParentChangeSetPowerState',
470 13: 'kIOPM_ParentChangeWaitForPowerSettle',
471 14: 'kIOPM_ParentChangeNotifyInterestedDriversDidChange',
472 15: 'kIOPM_ParentChangeTellCapabilityDidChange',
473 16: 'kIOPM_ParentChangeAcknowledgePowerChange',
474 17: 'kIOPM_NotifyChildrenStart',
475 18: 'kIOPM_NotifyChildrenOrdered',
476 19: 'kIOPM_NotifyChildrenDelayed',
477 20: 'kIOPM_SyncTellClientsPowerDown',
478 21: 'kIOPM_SyncTellPriorityClientsPowerDown',
479 22: 'kIOPM_SyncNotifyWillChange',
480 23: 'kIOPM_SyncNotifyDidChange',
481 24: 'kIOPM_SyncTellCapabilityDidChange',
482 25: 'kIOPM_SyncFinish',
483 26: 'kIOPM_TellCapabilityChangeDone',
484 27: 'kIOPM_DriverThreadCallDone'
486 powerstate
= unsigned(iopmpriv
.MachineState
)
487 if powerstate
in pstate_map
:
488 out_string
+= "{0:s}".format(pstate_map
[powerstate
])
490 out_string
+= "Unknown_MachineState"
493 if iopmpriv
.MachineState
!= 20:
494 out_string
+= "DriverTimer = {0: <6d}, SettleTime = {1: < 6d}, HeadNoteFlags = {2: #12x}, HeadNotePendingAcks = {3: #012x}, ".format(
495 unsigned(iopmpriv
.DriverTimer
),
496 unsigned(iopmpriv
.SettleTimeUS
),
497 unsigned(iopmpriv
.HeadNoteChangeFlags
),
498 unsigned(iopmpriv
.HeadNotePendingAcks
))
500 if iopmpriv
.DeviceOverrideEnabled
!= 0:
501 out_string
+= "DeviceOverrides, "
503 out_string
+= "DeviceDesire = {0: <6d}, DesiredPowerState = {1: <6d}, PreviousRequest = {2: <6d}\n".format(
504 unsigned(iopmpriv
.DeviceDesire
),
505 unsigned(iopmpriv
.DesiredPowerState
),
506 unsigned(iopmpriv
.PreviousRequestPowerFlags
))
510 ######################################
512 ######################################
513 def ShowRegistryEntryRecurse(entry
, prefix
, printProps
):
514 """ prints registry entry summary and recurses through all its children.
519 plen
= (len(prefix
)//2)
520 registryTable
= entry
.fRegistryTable
521 propertyTable
= entry
.fPropertyTable
523 # Print entry details
524 print "{0:s}{1:s}".format(prefix
, GetRegistryEntrySummary(entry
))
525 # Printing large property tables make it look like lldb is 'stuck'
527 print GetRegDictionary(propertyTable
, prefix
+ " | ")
531 childKey
= kern
.globals.gIOServicePlane
.keys
[1]
533 childKey
= plane
.keys
[1]
534 childArray
= LookupKeyInOSDict(registryTable
, childKey
)
535 if childArray
is not None:
537 ca
= CastIOKitClass(childArray
, 'OSArray *')
538 count
= unsigned(ca
.count
)
540 if plen
!= 0 and plen
!= 1 and (plen
& (plen
- 1)) == 0:
541 ShowRegistryEntryRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), prefix
+ "| ", printProps
)
543 ShowRegistryEntryRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), prefix
+ " ", printProps
)
546 def FindRegistryEntryRecurse(entry
, search_name
, stopAfterFirst
):
547 """ Checks if given registry entry's name matches the search_name we're looking for
548 If yes, it prints the entry's summary and then recurses through its children
549 If no, it does nothing and recurses through its children
553 registryTable
= entry
.fRegistryTable
554 propertyTable
= entry
.fPropertyTable
558 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
560 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
562 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
565 if str(CastIOKitClass(name
, 'OSString *').string
) == search_name
:
566 print GetRegistryEntrySummary(entry
)
567 if stopAfterFirst
is True:
569 elif CastIOKitClass(entry
, 'IOService *').pwrMgt
and CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
:
570 name
= CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
571 if str(name
) == search_name
:
572 print GetRegistryEntrySummary(entry
)
573 if stopAfterFirst
is True:
578 childKey
= kern
.globals.gIOServicePlane
.keys
[1]
580 childKey
= plane
.keys
[1]
581 childArray
= LookupKeyInOSDict(registryTable
, childKey
)
582 if childArray
is not None:
584 ca
= CastIOKitClass(childArray
, 'OSArray *')
585 count
= unsigned(ca
.count
)
587 if FindRegistryEntryRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), search_name
, stopAfterFirst
) is True:
592 def FindRegistryObjectRecurse(entry
, search_name
):
593 """ Checks if given registry entry's name matches the search_name we're looking for
594 If yes, return the entry
595 If no, it does nothing and recurses through its children
596 Implicitly stops after finding the first entry
600 registryTable
= entry
.fRegistryTable
601 propertyTable
= entry
.fPropertyTable
605 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
607 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
609 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
612 if str(CastIOKitClass(name
, 'OSString *').string
) == search_name
:
614 elif CastIOKitClass(entry
, 'IOService *').pwrMgt
and CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
:
615 name
= CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
616 if str(name
) == search_name
:
621 childKey
= kern
.globals.gIOServicePlane
.keys
[1]
623 childKey
= plane
.keys
[1]
624 childArray
= LookupKeyInOSDict(registryTable
, childKey
)
625 if childArray
is not None:
626 ca
= CastIOKitClass(childArray
, 'OSArray *')
627 for idx
in range(ca
.count
):
628 registry_object
= FindRegistryObjectRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), search_name
)
629 if not registry_object
or int(registry_object
) == int(0):
632 return registry_object
635 def LookupKeyInOSDict(osdict
, key
):
636 """ Returns the value corresponding to a given key in a OSDictionary
637 Returns None if the key was not found
641 count
= unsigned(osdict
.count
)
644 while idx
< count
and result
is None:
645 if key
== osdict
.dictionary
[idx
].key
:
646 result
= osdict
.dictionary
[idx
].value
650 def LookupKeyInPropTable(propertyTable
, key_str
):
651 """ Returns the value corresponding to a given key from a registry entry's property table
652 Returns None if the key was not found
653 The property that is being searched for is specified as a string in key_str
655 if not propertyTable
:
657 count
= unsigned(propertyTable
.count
)
660 while idx
< count
and result
is None:
661 if key_str
== str(propertyTable
.dictionary
[idx
].key
.string
):
662 result
= propertyTable
.dictionary
[idx
].value
666 def GetRegDictionary(osdict
, prefix
):
667 """ Returns a specially formatted string summary of the given OSDictionary
668 This is done in order to pretty-print registry property tables in showregistry
671 out_string
= prefix
+ "{\n"
673 count
= unsigned(osdict
.count
)
676 out_string
+= prefix
+ " " + GetObjectSummary(osdict
.dictionary
[idx
].key
) + " = " + GetObjectSummary(osdict
.dictionary
[idx
].value
) + "\n"
678 out_string
+= prefix
+ "}\n"
681 def GetString(string
):
682 """ Returns the python string representation of a given OSString
684 out_string
= "\"{0:s}\"".format(CastIOKitClass(string
, 'OSString *').string
)
688 out_string
= "{0:d}".format(CastIOKitClass(num
, 'OSNumber *').value
)
692 """ Shows info about a given OSBoolean
695 if b
== kern
.globals.gOSBooleanFalse
:
701 def GetMetaClass(mc
):
702 """ Shows info about a given OSSymbol
704 out_string
= "{0: <5d}x {1: >5d} bytes {2:s}\n".format(mc
.instanceCount
, mc
.classSize
, mc
.className
.string
)
708 """ Returns a string containing info about a given OSArray
712 count
= unsigned(arr
.count
)
717 out_string
+= GetObjectSummary(obj
)
718 if idx
< unsigned(arr
.count
):
722 def GetDictionary(d
):
723 """ Returns a string containing info about a given OSDictionary
727 count
= unsigned(d
.count
)
730 obj
= d
.dictionary
[idx
].key
731 out_string
+= GetObjectSummary(obj
) + "="
732 obj
= d
.dictionary
[idx
].value
734 out_string
+= GetObjectSummary(obj
)
741 """ Returns a string containing info about a given OSSet
743 out_string
+= "[" + GetArray(se
.members
) + "]"
746 def ReadIOPortInt(addr
, numbytes
, lcpu
):
747 """ Prints results after reading a given ioport
751 if "kdp" != GetConnectionProtocol():
752 print "Target is not connected over kdp. Nothing to do here."
755 # Set up the manual KDP packet
756 input_address
= unsigned(addressof(kern
.globals.manual_pkt
.input))
757 len_address
= unsigned(addressof(kern
.globals.manual_pkt
.len))
758 data_address
= unsigned(addressof(kern
.globals.manual_pkt
.data
))
759 if not WriteInt32ToMemoryAddress(0, input_address
):
760 print "0x{0: <4x}: 0x{1: <1x}".format(addr
, result
)
763 kdp_pkt_size
= GetType('kdp_readioport_req_t').GetByteSize()
764 if not WriteInt32ToMemoryAddress(kdp_pkt_size
, len_address
):
765 print "0x{0: <4x}: 0x{1: <1x}".format(addr
, result
)
768 kgm_pkt
= kern
.GetValueFromAddress(data_address
, 'kdp_readioport_req_t *')
770 header_value
= GetKDPPacketHeaderInt(request
=GetEnumValue('kdp_req_t::KDP_READIOPORT'), length
= kdp_pkt_size
)
772 if( WriteInt64ToMemoryAddress((header_value
), int(addressof(kgm_pkt
.hdr
))) and
773 WriteInt16ToMemoryAddress(addr
, int(addressof(kgm_pkt
.address
))) and
774 WriteInt32ToMemoryAddress(numbytes
, int(addressof(kgm_pkt
.nbytes
))) and
775 WriteInt16ToMemoryAddress(lcpu
, int(addressof(kgm_pkt
.lcpu
))) and
776 WriteInt32ToMemoryAddress(1, input_address
)
779 result_pkt
= Cast(addressof(kern
.globals.manual_pkt
.data
), 'kdp_readioport_reply_t *')
781 if(result_pkt
.error
== 0):
783 result
= dereference(Cast(addressof(result_pkt
.data
), 'uint8_t *'))
785 result
= dereference(Cast(addressof(result_pkt
.data
), 'uint16_t *'))
787 result
= dereference(Cast(addressof(result_pkt
.data
), 'uint32_t *'))
789 print "{0: <#6x}: {1:#0{2}x}".format(addr
, result
, (numbytes
*2)+2)
791 def WriteIOPortInt(addr
, numbytes
, value
, lcpu
):
792 """ Writes 'value' into ioport specified by 'addr'. Prints errors if it encounters any
794 if "kdp" != GetConnectionProtocol():
795 print "Target is not connected over kdp. Nothing to do here."
798 # Set up the manual KDP packet
799 input_address
= unsigned(addressof(kern
.globals.manual_pkt
.input))
800 len_address
= unsigned(addressof(kern
.globals.manual_pkt
.len))
801 data_address
= unsigned(addressof(kern
.globals.manual_pkt
.data
))
802 if not WriteInt32ToMemoryAddress(0, input_address
):
803 print "error writing {0: #x} to port {1: <#6x}: failed to write 0 to input_address".format(value
, addr
)
806 kdp_pkt_size
= GetType('kdp_writeioport_req_t').GetByteSize()
807 if not WriteInt32ToMemoryAddress(kdp_pkt_size
, len_address
):
808 print "error writing {0: #x} to port {1: <#6x}: failed to write kdp_pkt_size".format(value
, addr
)
811 kgm_pkt
= kern
.GetValueFromAddress(data_address
, 'kdp_writeioport_req_t *')
813 header_value
= GetKDPPacketHeaderInt(request
=GetEnumValue('kdp_req_t::KDP_WRITEIOPORT'), length
= kdp_pkt_size
)
815 if( WriteInt64ToMemoryAddress((header_value
), int(addressof(kgm_pkt
.hdr
))) and
816 WriteInt16ToMemoryAddress(addr
, int(addressof(kgm_pkt
.address
))) and
817 WriteInt32ToMemoryAddress(numbytes
, int(addressof(kgm_pkt
.nbytes
))) and
818 WriteInt16ToMemoryAddress(lcpu
, int(addressof(kgm_pkt
.lcpu
)))
821 if not WriteInt8ToMemoryAddress(value
, int(addressof(kgm_pkt
.data
))):
822 print "error writing {0: #x} to port {1: <#6x}: failed to write 8 bit data".format(value
, addr
)
825 if not WriteInt16ToMemoryAddress(value
, int(addressof(kgm_pkt
.data
))):
826 print "error writing {0: #x} to port {1: <#6x}: failed to write 16 bit data".format(value
, addr
)
829 if not WriteInt32ToMemoryAddress(value
, int(addressof(kgm_pkt
.data
))):
830 print "error writing {0: #x} to port {1: <#6x}: failed to write 32 bit data".format(value
, addr
)
832 if not WriteInt32ToMemoryAddress(1, input_address
):
833 print "error writing {0: #x} to port {1: <#6x}: failed to write to input_address".format(value
, addr
)
836 result_pkt
= Cast(addressof(kern
.globals.manual_pkt
.data
), 'kdp_writeioport_reply_t *')
838 # Done with the write
839 if(result_pkt
.error
== 0):
840 print "Writing {0: #x} to port {1: <#6x} was successful".format(value
, addr
)
842 print "error writing {0: #x} to port {1: <#6x}".format(value
, addr
)
844 @lldb_command('showinterruptcounts')
845 def showinterruptcounts(cmd_args
=None):
846 """ Shows event source based interrupt counts by nub name and interrupt index.
847 Does not cover interrupts that are not event source based. Will report 0
848 if interrupt accounting is disabled.
851 header_format
= "{0: <20s} {1: >5s} {2: >20s}"
852 content_format
= "{0: <20s} {1: >5d} {2: >20d}"
854 print header_format
.format("Name", "Index", "Count")
856 for i
in kern
.interrupt_stats
:
857 owner
= CastIOKitClass(i
.owner
, 'IOInterruptEventSource *')
858 nub
= CastIOKitClass(owner
.provider
, 'IORegistryEntry *')
861 # To uniquely identify an interrupt, we need the nub name and the index. The index
862 # is stored with the stats object, but we need to retrieve the name.
864 registryTable
= nub
.fRegistryTable
865 propertyTable
= nub
.fPropertyTable
867 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
869 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
871 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
876 nub_name
= GetString(CastIOKitClass(name
, 'OSString *'))
878 # We now have everything we need; spew the requested data.
880 interrupt_index
= i
.interruptIndex
881 first_level_count
= i
.interruptStatistics
[0]
883 print content_format
.format(nub_name
, interrupt_index
, first_level_count
)
887 @lldb_command('showinterruptstats')
888 def showinterruptstats(cmd_args
=None):
889 """ Shows event source based interrupt statistics by nub name and interrupt index.
890 Does not cover interrupts that are not event source based. Will report 0
891 if interrupt accounting is disabled, or if specific statistics are disabled.
892 Time is reported in ticks of mach_absolute_time. Statistics are:
894 Interrupt Count: Number of times the interrupt context handler was run
895 Interrupt Time: Total time spent in the interrupt context handler (if any)
896 Workloop Count: Number of times the kernel context handler was run
897 Workloop CPU Time: Total CPU time spent running the kernel context handler
898 Workloop Time: Total time spent running the kernel context handler
901 header_format
= "{0: <20s} {1: >5s} {2: >20s} {3: >20s} {4: >20s} {5: >20s} {6: >20s} {7: >20s} {8: >20s} {9: >20s}"
902 content_format
= "{0: <20s} {1: >5d} {2: >20d} {3: >20d} {4: >20d} {5: >20d} {6: >20d} {7: >20d} {8: >20d} {9: >#20x}"
904 print header_format
.format("Name", "Index", "Interrupt Count", "Interrupt Time", "Avg Interrupt Time", "Workloop Count", "Workloop CPU Time", "Workloop Time", "Avg Workloop Time", "Owner")
906 for i
in kern
.interrupt_stats
:
907 owner
= CastIOKitClass(i
.owner
, 'IOInterruptEventSource *')
908 nub
= CastIOKitClass(owner
.provider
, 'IORegistryEntry *')
911 # To uniquely identify an interrupt, we need the nub name and the index. The index
912 # is stored with the stats object, but we need to retrieve the name.
914 registryTable
= nub
.fRegistryTable
915 propertyTable
= nub
.fPropertyTable
917 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
919 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
921 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
926 nub_name
= GetString(CastIOKitClass(name
, 'OSString *'))
928 # We now have everything we need; spew the requested data.
930 interrupt_index
= i
.interruptIndex
931 first_level_count
= i
.interruptStatistics
[0]
932 second_level_count
= i
.interruptStatistics
[1]
933 first_level_time
= i
.interruptStatistics
[2]
934 second_level_cpu_time
= i
.interruptStatistics
[3]
935 second_level_system_time
= i
.interruptStatistics
[4]
937 avg_first_level_time
= 0
938 if first_level_count
!= 0:
939 avg_first_level_time
= first_level_time
/ first_level_count
941 avg_second_level_time
= 0
942 if second_level_count
!= 0:
943 avg_second_level_time
= second_level_system_time
/ second_level_count
945 print content_format
.format(nub_name
, interrupt_index
, first_level_count
, first_level_time
, avg_first_level_time
,
946 second_level_count
, second_level_cpu_time
, second_level_system_time
, avg_second_level_time
, owner
)