6 ######################################
8 ######################################
11 #####################################
13 #####################################
14 def CastIOKitClass(obj
, target_type
):
15 """ Type cast an object to another IOKIT CPP class.
17 obj - core.value object representing some C construct in lldb
18 target_type - str : ex 'OSString *'
21 v
= Cast(obj
, target_type
)
22 v
.GetSBValue().SetPreferDynamicValue(lldb
.eNoDynamicValues
)
25 ######################################
27 ######################################
28 @lldb_type_summary(['OSObject *'])
30 def GetObjectSummary(obj
):
31 """ Show info about an OSObject - its vtable ptr and retain count, & more info for simple container classes.
36 vt
= dereference(Cast(obj
, 'uintptr_t *')) - 2 * sizeof('uintptr_t')
37 vt
= kern
.StripKernelPAC(vt
)
38 vtype
= kern
.SymbolicateFromAddress(vt
)
40 vtype_str
= " <" + vtype
[0].GetName() + ">"
43 if hasattr(obj
, 'retainCount'):
44 retCount
= (obj
.retainCount
& 0xffff)
45 cntnrRetCount
= (obj
.retainCount
>> 16)
46 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
)
48 out_string
= "`object 0x{0: <16x}, vt 0x{1: <16x}{2:s}` ".format(obj
, vt
, vtype_str
)
50 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV8OSString')
52 out_string
+= GetString(obj
)
55 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV8OSSymbol')
57 out_string
+= GetString(obj
)
60 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV8OSNumber')
62 out_string
+= GetNumber(obj
)
65 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV9OSBoolean')
67 out_string
+= GetBoolean(obj
)
70 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV7OSArray')
72 out_string
+= "(" + GetArray(CastIOKitClass(obj
, 'OSArray *')) + ")"
75 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV5OSSet')
77 out_string
+= GetSet(CastIOKitClass(obj
, 'OSSet *'))
80 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV12OSDictionary')
82 out_string
+= GetDictionary(CastIOKitClass(obj
, 'OSDictionary *'))
88 def GetObjectTypeStr(obj
):
89 """ Return the type of an OSObject's container class
94 vt
= dereference(Cast(obj
, 'uintptr_t *')) - 2 * sizeof('uintptr_t')
95 vt
= kern
.StripKernelPAC(vt
)
96 vtype
= kern
.SymbolicateFromAddress(vt
)
98 return vtype
[0].GetName()
100 # See if the value is in a kext with no symbols
101 for kval
in IterateLinkedList(kern
.globals.kmod
, 'next'):
102 if vt
>= unsigned(kval
.address
) and vt
<= (unsigned(kval
.address
) + unsigned(kval
.size
)):
103 return "kmod:{:s}+{:#0x}".format(kval
.name
, vt
- unsigned(kval
.address
))
107 @lldb_type_summary(['IORegistryEntry *'])
109 def GetRegistryEntrySummary(entry
):
110 """ returns a string containing summary information about an IORegistry
111 object including it's registry id , vtable ptr and retain count
115 registryTable
= entry
.fRegistryTable
116 propertyTable
= entry
.fPropertyTable
118 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
120 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
122 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
125 out_string
+= "+-o {0:s} ".format(GetString(CastIOKitClass(name
, 'OSString *')))
126 elif CastIOKitClass(entry
, 'IOService *').pwrMgt
and CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
:
127 out_string
+= "+-o {0:s} ".format(CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
)
129 out_string
+= "+-o ?? "
131 # I'm using uintptr_t for now to work around <rdar://problem/12749733> FindFirstType & Co. should allow you to make pointer types directly
132 vtableAddr
= dereference(Cast(entry
, 'uintptr_t *')) - 2 * sizeof('uintptr_t *')
133 vtableAddr
= kern
.StripKernelPAC(vtableAddr
)
134 vtype
= kern
.SymbolicateFromAddress(vtableAddr
)
135 if vtype
is None or len(vtype
) < 1:
136 out_string
+= "<object 0x{0: <16x}, id 0x{1:x}, vtable 0x{2: <16x}".format(entry
, CastIOKitClass(entry
, 'IORegistryEntry *').reserved
.fRegistryEntryID
, vtableAddr
)
138 out_string
+= "<object 0x{0: <16x}, id 0x{1:x}, vtable 0x{2: <16x} <{3:s}>".format(entry
, CastIOKitClass(entry
, 'IORegistryEntry *').reserved
.fRegistryEntryID
,
139 vtableAddr
, vtype
[0].GetName())
141 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV15IORegistryEntry')
142 if vtableAddr
!= ztvAddr
:
144 state
= CastIOKitClass(entry
, 'IOService *').__state
[0]
145 # kIOServiceRegisteredState
148 out_string
+= "registered, "
149 # kIOServiceMatchedState
152 out_string
+= "matched, "
153 #kIOServiceInactiveState
156 busyCount
= (CastIOKitClass(entry
, 'IOService *').__state
[1] & 0xff)
157 retCount
= (CastIOKitClass(entry
, 'IOService *').retainCount
& 0xffff)
158 out_string
+= "active, busy {0}, retain count {1}>".format(busyCount
, retCount
)
161 ######################################
163 ######################################
164 @lldb_command('showallclasses')
165 def ShowAllClasses(cmd_args
=None):
166 """ Show the instance counts and ivar size of all OSObject subclasses.
167 See ioclasscount man page for details
170 count
= unsigned(kern
.globals.sAllClassesDict
.count
)
173 meta
= CastIOKitClass(kern
.globals.sAllClassesDict
.dictionary
[idx
].value
, 'OSMetaClass *')
175 print GetMetaClass(meta
)
177 @lldb_command('showobject')
178 def ShowObject(cmd_args
=None):
179 """ Show info about an OSObject - its vtable ptr and retain count, & more info for simple container classes.
182 print "Please specify the address of the OSObject whose info you want to view. Type help showobject for help"
185 obj
= kern
.GetValueFromAddress(cmd_args
[0], 'OSObject *')
186 print GetObjectSummary(obj
)
189 @lldb_command('dumpobject')
190 def DumpObject(cmd_args
=None):
191 """ Dumps object information if it is a valid object confirmed by showobject
192 Usage: dumpobject <address of object to be dumped> [class/struct type of object]
195 print "No arguments passed"
196 print DumpObject
.__doc
__
199 if len(cmd_args
) == 1:
201 object_info
= lldb_run_command("showobject {:s}".format(cmd_args
[0]))
203 print "Error!! showobject failed due to invalid value"
204 print DumpObject
.__doc
__
207 srch
= re
.search(r
'<vtable for ([A-Za-z].*)>', object_info
)
209 print "Error!! Couldn't find object in registry, input type manually as 2nd argument"
210 print DumpObject
.__doc
__
213 object_type
= srch
.group(1)
215 type_lookup
= lldb_run_command("image lookup -t {:s}".format(cmd_args
[1]))
216 if type_lookup
.find(cmd_args
[1])!= -1:
217 object_type
= cmd_args
[1]
219 print "Error!! Input type {:s} isn't available in image lookup".format(cmd_args
[1])
222 print "******** Object Dump for value \'{:s}\' with type \"{:s}\" ********".format(cmd_args
[0], object_type
)
223 print lldb_run_command("p/x *({:s}*){:s}".format(object_type
, cmd_args
[0]))
225 #EndMacro: dumpobject
227 @lldb_command('setregistryplane')
228 def SetRegistryPlane(cmd_args
=None):
229 """ Set the plane to be used for the IOKit registry macros
230 syntax: (lldb) setregistryplane 0 - will display all known planes
231 syntax: (lldb) setregistryplane 0xaddr - will set the registry plane to 0xaddr
232 syntax: (lldb) setregistryplane gIODTPlane - will set the registry plane to gIODTPlane
235 print "Please specify the name of the plane you want to use with the IOKit registry macros."
236 print SetRegistryPlane
.__doc
__
238 if cmd_args
[0] == "0":
239 print GetObjectSummary(kern
.globals.gIORegistryPlanes
)
242 plane
= kern
.GetValueFromAddress(cmd_args
[0], 'IORegistryPlane *')
245 @lldb_command('showregistryentry')
246 def ShowRegistryEntry(cmd_args
=None):
247 """ Show info about a registry entry; its properties and descendants in the current plane
248 syntax: (lldb) showregistryentry 0xaddr
249 syntax: (lldb) showregistryentry gIOPMRootDomain
252 print "Please specify the address of the registry entry whose info you want to view."
253 print ShowRegistryEntry
.__doc
__
256 entry
= kern
.GetValueFromAddress(cmd_args
[0], 'IORegistryEntry *')
257 ShowRegistryEntryRecurse(entry
, "", True)
259 @lldb_command('showregistry')
260 def ShowRegistry(cmd_args
=None):
261 """ Show info about all registry entries in the current plane
262 If prior to invoking this command no registry plane is specified
263 using 'setregistryplane', the command defaults to the IOService plane
265 ShowRegistryEntryRecurse(kern
.globals.gRegistryRoot
, "", False)
267 @lldb_command('showregistryprops')
268 def ShowRegistryProps(cmd_args
=None):
269 """ Show info about all registry entries in the current plane, and their properties
270 If prior to invoking this command no registry plane is specified
271 using 'setregistryplane', the command defaults to the IOService plane
273 ShowRegistryEntryRecurse(kern
.globals.gRegistryRoot
, "", True)
275 @lldb_command('findregistryentry')
276 def FindRegistryEntry(cmd_args
=None):
277 """ Search for registry entry that matches the given string
278 If prior to invoking this command no registry plane is specified
279 using 'setregistryplane', the command defaults to searching entries from the IOService plane
280 syntax: (lldb) findregistryentries AppleACPICPU - will find the first registry entry that matches AppleACPICPU
283 print "Please specify the name of the registry entry you want to find"
284 print FindRegistryEntry
.__doc
__
287 FindRegistryEntryRecurse(kern
.globals.gRegistryRoot
, cmd_args
[0], True)
289 @lldb_command('findregistryentries')
290 def FindRegistryEntries(cmd_args
=None):
291 """ Search for all registry entries that match the given string
292 If prior to invoking this command no registry plane is specified
293 using 'setregistryplane', the command defaults to searching entries from the IOService plane
294 syntax: (lldb) findregistryentries AppleACPICPU - will find all registry entries that match AppleACPICPU
297 print "Please specify the name of the registry entry/entries you want to find"
298 print FindRegistryEntries
.__doc
__
301 FindRegistryEntryRecurse(kern
.globals.gRegistryRoot
, cmd_args
[0], False)
303 @lldb_command('findregistryprop')
304 def FindRegistryProp(cmd_args
=None):
305 """ Given a registry entry, print out the contents for the property that matches
307 syntax: (lldb) findregistryprop 0xaddr IOSleepSupported
308 syntax: (lldb) findregistryprop gIOPMRootDomain IOSleepSupported
309 syntax: (lldb) findregistryprop gIOPMRootDomain "Supported Features"
311 if not cmd_args
or len(cmd_args
) < 2:
312 print "Please specify the address of a IORegistry entry and the property you're looking for"
313 print FindRegistryProp
.__doc
__
316 entry
= kern
.GetValueFromAddress(cmd_args
[0], 'IOService *')
317 propertyTable
= entry
.fPropertyTable
318 print GetObjectSummary(LookupKeyInPropTable(propertyTable
, cmd_args
[1]))
320 @lldb_command('readioport8')
321 def ReadIOPort8(cmd_args
=None):
322 """ Read value stored in the specified IO port. The CPU can be optionally
324 Prints 0xBAD10AD in case of a bad read
325 Syntax: (lldb) readioport8 <port> [lcpu (kernel's numbering convention)]
328 print "Please specify a port to read out of"
329 print ReadIOPort8
.__doc__
332 portAddr
= ArgumentStringToInt(cmd_args
[0])
333 if len(cmd_args
) >= 2:
334 lcpu
= ArgumentStringToInt(cmd_args
[1])
336 lcpu
= xnudefines
.lcpu_self
338 ReadIOPortInt(portAddr
, 1, lcpu
)
340 @lldb_command('readioport16')
341 def ReadIOPort16(cmd_args
=None):
342 """ Read value stored in the specified IO port. The CPU can be optionally
344 Prints 0xBAD10AD in case of a bad read
345 Syntax: (lldb) readioport16 <port> [lcpu (kernel's numbering convention)]
348 print "Please specify a port to read out of"
349 print ReadIOPort16
.__doc__
352 portAddr
= ArgumentStringToInt(cmd_args
[0])
353 if len(cmd_args
) >= 2:
354 lcpu
= ArgumentStringToInt(cmd_args
[1])
356 lcpu
= xnudefines
.lcpu_self
358 ReadIOPortInt(portAddr
, 2, lcpu
)
360 @lldb_command('readioport32')
361 def ReadIOPort32(cmd_args
=None):
362 """ Read value stored in the specified IO port. The CPU can be optionally
364 Prints 0xBAD10AD in case of a bad read
365 Syntax: (lldb) readioport32 <port> [lcpu (kernel's numbering convention)]
368 print "Please specify a port to read out of"
369 print ReadIOPort32
.__doc__
372 portAddr
= ArgumentStringToInt(cmd_args
[0])
373 if len(cmd_args
) >= 2:
374 lcpu
= ArgumentStringToInt(cmd_args
[1])
376 lcpu
= xnudefines
.lcpu_self
378 ReadIOPortInt(portAddr
, 4, lcpu
)
380 @lldb_command('writeioport8')
381 def WriteIOPort8(cmd_args
=None):
382 """ Write the value to the specified IO port. The size of the value is
383 determined by the name of the command. The CPU used can be optionally
385 Syntax: (lldb) writeioport8 <port> <value> [lcpu (kernel's numbering convention)]
387 if not cmd_args
or len(cmd_args
) < 2:
388 print "Please specify a port to write to, followed by the value you want to write"
389 print WriteIOPort8
.__doc__
392 portAddr
= ArgumentStringToInt(cmd_args
[0])
393 value
= ArgumentStringToInt(cmd_args
[1])
395 if len(cmd_args
) >= 3:
396 lcpu
= ArgumentStringToInt(cmd_args
[2])
398 lcpu
= xnudefines
.lcpu_self
400 WriteIOPortInt(portAddr
, 1, value
, lcpu
)
402 @lldb_command('writeioport16')
403 def WriteIOPort16(cmd_args
=None):
404 """ Write the value to the specified IO port. The size of the value is
405 determined by the name of the command. The CPU used can be optionally
407 Syntax: (lldb) writeioport16 <port> <value> [lcpu (kernel's numbering convention)]
409 if not cmd_args
or len(cmd_args
) < 2:
410 print "Please specify a port to write to, followed by the value you want to write"
411 print WriteIOPort16
.__doc__
414 portAddr
= ArgumentStringToInt(cmd_args
[0])
415 value
= ArgumentStringToInt(cmd_args
[1])
417 if len(cmd_args
) >= 3:
418 lcpu
= ArgumentStringToInt(cmd_args
[2])
420 lcpu
= xnudefines
.lcpu_self
422 WriteIOPortInt(portAddr
, 2, value
, lcpu
)
424 @lldb_command('writeioport32')
425 def WriteIOPort32(cmd_args
=None):
426 """ Write the value to the specified IO port. The size of the value is
427 determined by the name of the command. The CPU used can be optionally
429 Syntax: (lldb) writeioport32 <port> <value> [lcpu (kernel's numbering convention)]
431 if not cmd_args
or len(cmd_args
) < 2:
432 print "Please specify a port to write to, followed by the value you want to write"
433 print WriteIOPort32
.__doc__
436 portAddr
= ArgumentStringToInt(cmd_args
[0])
437 value
= ArgumentStringToInt(cmd_args
[1])
439 if len(cmd_args
) >= 3:
440 lcpu
= ArgumentStringToInt(cmd_args
[2])
442 lcpu
= xnudefines
.lcpu_self
444 WriteIOPortInt(portAddr
, 4, value
, lcpu
)
446 @lldb_command('showioservicepm')
447 def ShowIOServicePM(cmd_args
=None):
448 """ Routine to dump the IOServicePM object
449 Syntax: (lldb) showioservicepm <IOServicePM pointer>
452 print "Please enter the pointer to the IOServicePM object you'd like to introspect"
453 print ShowIOServicePM
.__doc
__
456 iopmpriv
= kern
.GetValueFromAddress(cmd_args
[0], 'IOServicePM *')
457 out_string
= "MachineState {0: <6d} (".format(iopmpriv
.MachineState
)
462 1: 'kIOPM_OurChangeTellClientsPowerDown',
463 2: 'kIOPM_OurChangeTellClientsPowerDown',
464 3: 'kIOPM_OurChangeNotifyInterestedDriversWillChange',
465 4: 'kIOPM_OurChangeSetPowerState',
466 5: 'kIOPM_OurChangeWaitForPowerSettle',
467 6: 'kIOPM_OurChangeNotifyInterestedDriversDidChange',
468 7: 'kIOPM_OurChangeTellCapabilityDidChange',
469 8: 'kIOPM_OurChangeFinish',
470 9: 'Unused_MachineState_9',
471 10: 'kIOPM_ParentChangeTellPriorityClientsPowerDown',
472 11: 'kIOPM_ParentChangeNotifyInterestedDriversWillChange',
473 12: 'kIOPM_ParentChangeSetPowerState',
474 13: 'kIOPM_ParentChangeWaitForPowerSettle',
475 14: 'kIOPM_ParentChangeNotifyInterestedDriversDidChange',
476 15: 'kIOPM_ParentChangeTellCapabilityDidChange',
477 16: 'kIOPM_ParentChangeAcknowledgePowerChange',
478 17: 'kIOPM_NotifyChildrenStart',
479 18: 'kIOPM_NotifyChildrenOrdered',
480 19: 'kIOPM_NotifyChildrenDelayed',
481 20: 'kIOPM_SyncTellClientsPowerDown',
482 21: 'kIOPM_SyncTellPriorityClientsPowerDown',
483 22: 'kIOPM_SyncNotifyWillChange',
484 23: 'kIOPM_SyncNotifyDidChange',
485 24: 'kIOPM_SyncTellCapabilityDidChange',
486 25: 'kIOPM_SyncFinish',
487 26: 'kIOPM_TellCapabilityChangeDone',
488 27: 'kIOPM_DriverThreadCallDone'
490 powerstate
= unsigned(iopmpriv
.MachineState
)
491 if powerstate
in pstate_map
:
492 out_string
+= "{0:s}".format(pstate_map
[powerstate
])
494 out_string
+= "Unknown_MachineState"
497 if iopmpriv
.MachineState
!= 20:
498 out_string
+= "DriverTimer = {0: <6d}, SettleTime = {1: < 6d}, HeadNoteFlags = {2: #12x}, HeadNotePendingAcks = {3: #012x}, ".format(
499 unsigned(iopmpriv
.DriverTimer
),
500 unsigned(iopmpriv
.SettleTimeUS
),
501 unsigned(iopmpriv
.HeadNoteChangeFlags
),
502 unsigned(iopmpriv
.HeadNotePendingAcks
))
504 if iopmpriv
.DeviceOverrideEnabled
!= 0:
505 out_string
+= "DeviceOverrides, "
507 out_string
+= "DeviceDesire = {0: <6d}, DesiredPowerState = {1: <6d}, PreviousRequest = {2: <6d}\n".format(
508 unsigned(iopmpriv
.DeviceDesire
),
509 unsigned(iopmpriv
.DesiredPowerState
),
510 unsigned(iopmpriv
.PreviousRequestPowerFlags
))
514 ######################################
516 ######################################
517 def ShowRegistryEntryRecurse(entry
, prefix
, printProps
):
518 """ prints registry entry summary and recurses through all its children.
523 plen
= (len(prefix
)//2)
524 registryTable
= entry
.fRegistryTable
525 propertyTable
= entry
.fPropertyTable
527 # Print entry details
528 print "{0:s}{1:s}".format(prefix
, GetRegistryEntrySummary(entry
))
529 # Printing large property tables make it look like lldb is 'stuck'
531 print GetRegDictionary(propertyTable
, prefix
+ " | ")
535 childKey
= kern
.globals.gIOServicePlane
.keys
[1]
537 childKey
= plane
.keys
[1]
538 childArray
= LookupKeyInOSDict(registryTable
, childKey
)
539 if childArray
is not None:
541 ca
= CastIOKitClass(childArray
, 'OSArray *')
542 count
= unsigned(ca
.count
)
544 if plen
!= 0 and plen
!= 1 and (plen
& (plen
- 1)) == 0:
545 ShowRegistryEntryRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), prefix
+ "| ", printProps
)
547 ShowRegistryEntryRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), prefix
+ " ", printProps
)
550 def FindRegistryEntryRecurse(entry
, search_name
, stopAfterFirst
):
551 """ Checks if given registry entry's name matches the search_name we're looking for
552 If yes, it prints the entry's summary and then recurses through its children
553 If no, it does nothing and recurses through its children
557 registryTable
= entry
.fRegistryTable
558 propertyTable
= entry
.fPropertyTable
562 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
564 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
566 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
569 if str(CastIOKitClass(name
, 'OSString *').string
) == search_name
:
570 print GetRegistryEntrySummary(entry
)
571 if stopAfterFirst
is True:
573 elif CastIOKitClass(entry
, 'IOService *').pwrMgt
and CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
:
574 name
= CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
575 if str(name
) == search_name
:
576 print GetRegistryEntrySummary(entry
)
577 if stopAfterFirst
is True:
582 childKey
= kern
.globals.gIOServicePlane
.keys
[1]
584 childKey
= plane
.keys
[1]
585 childArray
= LookupKeyInOSDict(registryTable
, childKey
)
586 if childArray
is not None:
588 ca
= CastIOKitClass(childArray
, 'OSArray *')
589 count
= unsigned(ca
.count
)
591 if FindRegistryEntryRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), search_name
, stopAfterFirst
) is True:
596 def FindRegistryObjectRecurse(entry
, search_name
):
597 """ Checks if given registry entry's name matches the search_name we're looking for
598 If yes, return the entry
599 If no, it does nothing and recurses through its children
600 Implicitly stops after finding the first entry
604 registryTable
= entry
.fRegistryTable
605 propertyTable
= entry
.fPropertyTable
609 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
611 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
613 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
616 if str(CastIOKitClass(name
, 'OSString *').string
) == search_name
:
618 elif CastIOKitClass(entry
, 'IOService *').pwrMgt
and CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
:
619 name
= CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
620 if str(name
) == search_name
:
625 childKey
= kern
.globals.gIOServicePlane
.keys
[1]
627 childKey
= plane
.keys
[1]
628 childArray
= LookupKeyInOSDict(registryTable
, childKey
)
629 if childArray
is not None:
630 ca
= CastIOKitClass(childArray
, 'OSArray *')
631 for idx
in range(ca
.count
):
632 registry_object
= FindRegistryObjectRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), search_name
)
633 if not registry_object
or int(registry_object
) == int(0):
636 return registry_object
639 def LookupKeyInOSDict(osdict
, key
):
640 """ Returns the value corresponding to a given key in a OSDictionary
641 Returns None if the key was not found
645 count
= unsigned(osdict
.count
)
648 while idx
< count
and result
is None:
649 if key
== osdict
.dictionary
[idx
].key
:
650 result
= osdict
.dictionary
[idx
].value
654 def LookupKeyInPropTable(propertyTable
, key_str
):
655 """ Returns the value corresponding to a given key from a registry entry's property table
656 Returns None if the key was not found
657 The property that is being searched for is specified as a string in key_str
659 if not propertyTable
:
661 count
= unsigned(propertyTable
.count
)
664 while idx
< count
and result
is None:
665 if key_str
== str(propertyTable
.dictionary
[idx
].key
.string
):
666 result
= propertyTable
.dictionary
[idx
].value
670 def GetRegDictionary(osdict
, prefix
):
671 """ Returns a specially formatted string summary of the given OSDictionary
672 This is done in order to pretty-print registry property tables in showregistry
675 out_string
= prefix
+ "{\n"
677 count
= unsigned(osdict
.count
)
680 out_string
+= prefix
+ " " + GetObjectSummary(osdict
.dictionary
[idx
].key
) + " = " + GetObjectSummary(osdict
.dictionary
[idx
].value
) + "\n"
682 out_string
+= prefix
+ "}\n"
685 def GetString(string
):
686 """ Returns the python string representation of a given OSString
688 out_string
= "\"{0:s}\"".format(CastIOKitClass(string
, 'OSString *').string
)
692 out_string
= "{0:d}".format(CastIOKitClass(num
, 'OSNumber *').value
)
696 """ Shows info about a given OSBoolean
699 if b
== kern
.globals.gOSBooleanFalse
:
705 def GetMetaClass(mc
):
706 """ Shows info about a given OSSymbol
708 out_string
= "{0: <5d}x {1: >5d} bytes {2:s}\n".format(mc
.instanceCount
, mc
.classSize
, mc
.className
.string
)
712 """ Returns a string containing info about a given OSArray
716 count
= unsigned(arr
.count
)
721 out_string
+= GetObjectSummary(obj
)
722 if idx
< unsigned(arr
.count
):
726 def GetDictionary(d
):
727 """ Returns a string containing info about a given OSDictionary
731 count
= unsigned(d
.count
)
734 obj
= d
.dictionary
[idx
].key
735 out_string
+= GetObjectSummary(obj
) + "="
736 obj
= d
.dictionary
[idx
].value
738 out_string
+= GetObjectSummary(obj
)
745 """ Returns a string containing info about a given OSSet
747 out_string
+= "[" + GetArray(se
.members
) + "]"
750 def ReadIOPortInt(addr
, numbytes
, lcpu
):
751 """ Prints results after reading a given ioport
755 if "kdp" != GetConnectionProtocol():
756 print "Target is not connected over kdp. Nothing to do here."
759 # Set up the manual KDP packet
760 input_address
= unsigned(addressof(kern
.globals.manual_pkt
.input))
761 len_address
= unsigned(addressof(kern
.globals.manual_pkt
.len))
762 data_address
= unsigned(addressof(kern
.globals.manual_pkt
.data
))
763 if not WriteInt32ToMemoryAddress(0, input_address
):
764 print "0x{0: <4x}: 0x{1: <1x}".format(addr
, result
)
767 kdp_pkt_size
= GetType('kdp_readioport_req_t').GetByteSize()
768 if not WriteInt32ToMemoryAddress(kdp_pkt_size
, len_address
):
769 print "0x{0: <4x}: 0x{1: <1x}".format(addr
, result
)
772 kgm_pkt
= kern
.GetValueFromAddress(data_address
, 'kdp_readioport_req_t *')
774 header_value
= GetKDPPacketHeaderInt(request
=GetEnumValue('kdp_req_t::KDP_READIOPORT'), length
= kdp_pkt_size
)
776 if( WriteInt64ToMemoryAddress((header_value
), int(addressof(kgm_pkt
.hdr
))) and
777 WriteInt16ToMemoryAddress(addr
, int(addressof(kgm_pkt
.address
))) and
778 WriteInt32ToMemoryAddress(numbytes
, int(addressof(kgm_pkt
.nbytes
))) and
779 WriteInt16ToMemoryAddress(lcpu
, int(addressof(kgm_pkt
.lcpu
))) and
780 WriteInt32ToMemoryAddress(1, input_address
)
783 result_pkt
= Cast(addressof(kern
.globals.manual_pkt
.data
), 'kdp_readioport_reply_t *')
785 if(result_pkt
.error
== 0):
787 result
= dereference(Cast(addressof(result_pkt
.data
), 'uint8_t *'))
789 result
= dereference(Cast(addressof(result_pkt
.data
), 'uint16_t *'))
791 result
= dereference(Cast(addressof(result_pkt
.data
), 'uint32_t *'))
793 print "{0: <#6x}: {1:#0{2}x}".format(addr
, result
, (numbytes
*2)+2)
795 def WriteIOPortInt(addr
, numbytes
, value
, lcpu
):
796 """ Writes 'value' into ioport specified by 'addr'. Prints errors if it encounters any
798 if "kdp" != GetConnectionProtocol():
799 print "Target is not connected over kdp. Nothing to do here."
802 # Set up the manual KDP packet
803 input_address
= unsigned(addressof(kern
.globals.manual_pkt
.input))
804 len_address
= unsigned(addressof(kern
.globals.manual_pkt
.len))
805 data_address
= unsigned(addressof(kern
.globals.manual_pkt
.data
))
806 if not WriteInt32ToMemoryAddress(0, input_address
):
807 print "error writing {0: #x} to port {1: <#6x}: failed to write 0 to input_address".format(value
, addr
)
810 kdp_pkt_size
= GetType('kdp_writeioport_req_t').GetByteSize()
811 if not WriteInt32ToMemoryAddress(kdp_pkt_size
, len_address
):
812 print "error writing {0: #x} to port {1: <#6x}: failed to write kdp_pkt_size".format(value
, addr
)
815 kgm_pkt
= kern
.GetValueFromAddress(data_address
, 'kdp_writeioport_req_t *')
817 header_value
= GetKDPPacketHeaderInt(request
=GetEnumValue('kdp_req_t::KDP_WRITEIOPORT'), length
= kdp_pkt_size
)
819 if( WriteInt64ToMemoryAddress((header_value
), int(addressof(kgm_pkt
.hdr
))) and
820 WriteInt16ToMemoryAddress(addr
, int(addressof(kgm_pkt
.address
))) and
821 WriteInt32ToMemoryAddress(numbytes
, int(addressof(kgm_pkt
.nbytes
))) and
822 WriteInt16ToMemoryAddress(lcpu
, int(addressof(kgm_pkt
.lcpu
)))
825 if not WriteInt8ToMemoryAddress(value
, int(addressof(kgm_pkt
.data
))):
826 print "error writing {0: #x} to port {1: <#6x}: failed to write 8 bit data".format(value
, addr
)
829 if not WriteInt16ToMemoryAddress(value
, int(addressof(kgm_pkt
.data
))):
830 print "error writing {0: #x} to port {1: <#6x}: failed to write 16 bit data".format(value
, addr
)
833 if not WriteInt32ToMemoryAddress(value
, int(addressof(kgm_pkt
.data
))):
834 print "error writing {0: #x} to port {1: <#6x}: failed to write 32 bit data".format(value
, addr
)
836 if not WriteInt32ToMemoryAddress(1, input_address
):
837 print "error writing {0: #x} to port {1: <#6x}: failed to write to input_address".format(value
, addr
)
840 result_pkt
= Cast(addressof(kern
.globals.manual_pkt
.data
), 'kdp_writeioport_reply_t *')
842 # Done with the write
843 if(result_pkt
.error
== 0):
844 print "Writing {0: #x} to port {1: <#6x} was successful".format(value
, addr
)
846 print "error writing {0: #x} to port {1: <#6x}".format(value
, addr
)
848 @lldb_command('showinterruptcounts')
849 def showinterruptcounts(cmd_args
=None):
850 """ Shows event source based interrupt counts by nub name and interrupt index.
851 Does not cover interrupts that are not event source based. Will report 0
852 if interrupt accounting is disabled.
855 header_format
= "{0: <20s} {1: >5s} {2: >20s}"
856 content_format
= "{0: <20s} {1: >5d} {2: >20d}"
858 print header_format
.format("Name", "Index", "Count")
860 for i
in kern
.interrupt_stats
:
861 owner
= CastIOKitClass(i
.owner
, 'IOInterruptEventSource *')
862 nub
= CastIOKitClass(owner
.provider
, 'IORegistryEntry *')
865 # To uniquely identify an interrupt, we need the nub name and the index. The index
866 # is stored with the stats object, but we need to retrieve the name.
868 registryTable
= nub
.fRegistryTable
869 propertyTable
= nub
.fPropertyTable
871 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
873 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
875 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
880 nub_name
= GetString(CastIOKitClass(name
, 'OSString *'))
882 # We now have everything we need; spew the requested data.
884 interrupt_index
= i
.interruptIndex
885 first_level_count
= i
.interruptStatistics
[0]
887 print content_format
.format(nub_name
, interrupt_index
, first_level_count
)
891 @lldb_command('showinterruptstats')
892 def showinterruptstats(cmd_args
=None):
893 """ Shows event source based interrupt statistics by nub name and interrupt index.
894 Does not cover interrupts that are not event source based. Will report 0
895 if interrupt accounting is disabled, or if specific statistics are disabled.
896 Time is reported in ticks of mach_absolute_time. Statistics are:
898 Interrupt Count: Number of times the interrupt context handler was run
899 Interrupt Time: Total time spent in the interrupt context handler (if any)
900 Workloop Count: Number of times the kernel context handler was run
901 Workloop CPU Time: Total CPU time spent running the kernel context handler
902 Workloop Time: Total time spent running the kernel context handler
905 header_format
= "{0: <20s} {1: >5s} {2: >20s} {3: >20s} {4: >20s} {5: >20s} {6: >20s} {7: >20s} {8: >20s} {9: >20s}"
906 content_format
= "{0: <20s} {1: >5d} {2: >20d} {3: >20d} {4: >20d} {5: >20d} {6: >20d} {7: >20d} {8: >20d} {9: >#20x}"
908 print header_format
.format("Name", "Index", "Interrupt Count", "Interrupt Time", "Avg Interrupt Time", "Workloop Count", "Workloop CPU Time", "Workloop Time", "Avg Workloop Time", "Owner")
910 for i
in kern
.interrupt_stats
:
911 owner
= CastIOKitClass(i
.owner
, 'IOInterruptEventSource *')
912 nub
= CastIOKitClass(owner
.provider
, 'IORegistryEntry *')
915 # To uniquely identify an interrupt, we need the nub name and the index. The index
916 # is stored with the stats object, but we need to retrieve the name.
918 registryTable
= nub
.fRegistryTable
919 propertyTable
= nub
.fPropertyTable
921 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
923 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
925 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
930 nub_name
= GetString(CastIOKitClass(name
, 'OSString *'))
932 # We now have everything we need; spew the requested data.
934 interrupt_index
= i
.interruptIndex
935 first_level_count
= i
.interruptStatistics
[0]
936 second_level_count
= i
.interruptStatistics
[1]
937 first_level_time
= i
.interruptStatistics
[2]
938 second_level_cpu_time
= i
.interruptStatistics
[3]
939 second_level_system_time
= i
.interruptStatistics
[4]
941 avg_first_level_time
= 0
942 if first_level_count
!= 0:
943 avg_first_level_time
= first_level_time
/ first_level_count
945 avg_second_level_time
= 0
946 if second_level_count
!= 0:
947 avg_second_level_time
= second_level_system_time
/ second_level_count
949 print content_format
.format(nub_name
, interrupt_index
, first_level_count
, first_level_time
, avg_first_level_time
,
950 second_level_count
, second_level_cpu_time
, second_level_system_time
, avg_second_level_time
, owner
)