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 vtype
= kern
.SymbolicateFromAddress(vt
)
39 vtype_str
= " <" + vtype
[0].GetName() + ">"
42 if hasattr(obj
, 'retainCount'):
43 retCount
= (obj
.retainCount
& 0xffff)
44 cntnrRetCount
= (obj
.retainCount
>> 16)
45 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
)
47 out_string
= "`object 0x{0: <16x}, vt 0x{1: <16x}{2:s}` ".format(obj
, vt
, vtype_str
)
49 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV8OSString')
51 out_string
+= GetString(obj
)
54 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV8OSSymbol')
56 out_string
+= GetString(obj
)
59 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV8OSNumber')
61 out_string
+= GetNumber(obj
)
64 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV9OSBoolean')
66 out_string
+= GetBoolean(obj
)
69 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV7OSArray')
71 out_string
+= "(" + GetArray(CastIOKitClass(obj
, 'OSArray *')) + ")"
74 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV5OSSet')
76 out_string
+= GetSet(CastIOKitClass(obj
, 'OSSet *'))
79 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV12OSDictionary')
81 out_string
+= GetDictionary(CastIOKitClass(obj
, 'OSDictionary *'))
87 def GetObjectTypeStr(obj
):
88 """ Return the type of an OSObject's container class
93 vt
= dereference(Cast(obj
, 'uintptr_t *')) - 2 * sizeof('uintptr_t')
94 vtype
= kern
.SymbolicateFromAddress(vt
)
96 return vtype
[0].GetName()
98 # See if the value is in a kext with no symbols
99 for kval
in IterateLinkedList(kern
.globals.kmod
, 'next'):
100 if vt
>= unsigned(kval
.address
) and vt
<= (unsigned(kval
.address
) + unsigned(kval
.size
)):
101 return "kmod:{:s}+{:#0x}".format(kval
.name
, vt
- unsigned(kval
.address
))
105 @lldb_type_summary(['IORegistryEntry *'])
107 def GetRegistryEntrySummary(entry
):
108 """ returns a string containing summary information about an IORegistry
109 object including it's registry id , vtable ptr and retain count
113 registryTable
= entry
.fRegistryTable
114 propertyTable
= entry
.fPropertyTable
116 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
118 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
120 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
123 out_string
+= "+-o {0:s} ".format(GetString(CastIOKitClass(name
, 'OSString *')))
124 elif CastIOKitClass(entry
, 'IOService *').pwrMgt
and CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
:
125 out_string
+= "+-o {0:s} ".format(CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
)
127 out_string
+= "+-o ?? "
129 # I'm using uintptr_t for now to work around <rdar://problem/12749733> FindFirstType & Co. should allow you to make pointer types directly
130 vtableAddr
= dereference(Cast(entry
, 'uintptr_t *')) - 2 * sizeof('uintptr_t *')
131 vtype
= kern
.SymbolicateFromAddress(vtableAddr
)
132 if vtype
is None or len(vtype
) < 1:
133 out_string
+= "<object 0x{0: <16x}, id 0x{1:x}, vtable 0x{2: <16x}".format(entry
, CastIOKitClass(entry
, 'IORegistryEntry *').reserved
.fRegistryEntryID
, vtableAddr
)
135 out_string
+= "<object 0x{0: <16x}, id 0x{1:x}, vtable 0x{2: <16x} <{3:s}>".format(entry
, CastIOKitClass(entry
, 'IORegistryEntry *').reserved
.fRegistryEntryID
,
136 vtableAddr
, vtype
[0].GetName())
138 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV15IORegistryEntry')
139 if vtableAddr
!= ztvAddr
:
141 state
= CastIOKitClass(entry
, 'IOService *').__state
[0]
142 # kIOServiceRegisteredState
145 out_string
+= "registered, "
146 # kIOServiceMatchedState
149 out_string
+= "matched, "
150 #kIOServiceInactiveState
153 busyCount
= (CastIOKitClass(entry
, 'IOService *').__state
[1] & 0xff)
154 retCount
= (CastIOKitClass(entry
, 'IOService *').retainCount
& 0xffff)
155 out_string
+= "active, busy {0}, retain count {1}>".format(busyCount
, retCount
)
158 ######################################
160 ######################################
161 @lldb_command('showallclasses')
162 def ShowAllClasses(cmd_args
=None):
163 """ Show the instance counts and ivar size of all OSObject subclasses.
164 See ioclasscount man page for details
167 count
= unsigned(kern
.globals.sAllClassesDict
.count
)
170 meta
= CastIOKitClass(kern
.globals.sAllClassesDict
.dictionary
[idx
].value
, 'OSMetaClass *')
172 print GetMetaClass(meta
)
174 @lldb_command('showobject')
175 def ShowObject(cmd_args
=None):
176 """ Show info about an OSObject - its vtable ptr and retain count, & more info for simple container classes.
179 print "Please specify the address of the OSObject whose info you want to view. Type help showobject for help"
182 obj
= kern
.GetValueFromAddress(cmd_args
[0], 'OSObject *')
183 print GetObjectSummary(obj
)
186 @lldb_command('dumpobject')
187 def DumpObject(cmd_args
=None):
188 """ Dumps object information if it is a valid object confirmed by showobject
189 Usage: dumpobject <address of object to be dumped> [class/struct type of object]
192 print "No arguments passed"
193 print DumpObject
.__doc
__
196 if len(cmd_args
) == 1:
198 object_info
= lldb_run_command("showobject {:s}".format(cmd_args
[0]))
200 print "Error!! showobject failed due to invalid value"
201 print DumpObject
.__doc
__
204 srch
= re
.search(r
'<vtable for ([A-Za-z].*)>', object_info
)
206 print "Error!! Couldn't find object in registry, input type manually as 2nd argument"
207 print DumpObject
.__doc
__
210 object_type
= srch
.group(1)
212 type_lookup
= lldb_run_command("image lookup -t {:s}".format(cmd_args
[1]))
213 if type_lookup
.find(cmd_args
[1])!= -1:
214 object_type
= cmd_args
[1]
216 print "Error!! Input type {:s} isn't available in image lookup".format(cmd_args
[1])
219 print "******** Object Dump for value \'{:s}\' with type \"{:s}\" ********".format(cmd_args
[0], object_type
)
220 print lldb_run_command("p/x *({:s}*){:s}".format(object_type
, cmd_args
[0]))
222 #EndMacro: dumpobject
224 @lldb_command('setregistryplane')
225 def SetRegistryPlane(cmd_args
=None):
226 """ Set the plane to be used for the IOKit registry macros
227 syntax: (lldb) setregistryplane 0 - will display all known planes
228 syntax: (lldb) setregistryplane 0xaddr - will set the registry plane to 0xaddr
229 syntax: (lldb) setregistryplane gIODTPlane - will set the registry plane to gIODTPlane
232 print "Please specify the name of the plane you want to use with the IOKit registry macros."
233 print SetRegistryPlane
.__doc
__
235 if cmd_args
[0] == "0":
236 print GetObjectSummary(kern
.globals.gIORegistryPlanes
)
239 plane
= kern
.GetValueFromAddress(cmd_args
[0], 'IORegistryPlane *')
242 @lldb_command('showregistryentry')
243 def ShowRegistryEntry(cmd_args
=None):
244 """ Show info about a registry entry; its properties and descendants in the current plane
245 syntax: (lldb) showregistryentry 0xaddr
246 syntax: (lldb) showregistryentry gIOPMRootDomain
249 print "Please specify the address of the registry entry whose info you want to view."
250 print ShowRegistryEntry
.__doc
__
253 entry
= kern
.GetValueFromAddress(cmd_args
[0], 'IORegistryEntry *')
254 ShowRegistryEntryRecurse(entry
, "", True)
256 @lldb_command('showregistry')
257 def ShowRegistry(cmd_args
=None):
258 """ Show info about all registry entries in the current plane
259 If prior to invoking this command no registry plane is specified
260 using 'setregistryplane', the command defaults to the IOService plane
262 ShowRegistryEntryRecurse(kern
.globals.gRegistryRoot
, "", False)
264 @lldb_command('showregistryprops')
265 def ShowRegistryProps(cmd_args
=None):
266 """ Show info about all registry entries in the current plane, and their properties
267 If prior to invoking this command no registry plane is specified
268 using 'setregistryplane', the command defaults to the IOService plane
270 ShowRegistryEntryRecurse(kern
.globals.gRegistryRoot
, "", True)
272 @lldb_command('findregistryentry')
273 def FindRegistryEntry(cmd_args
=None):
274 """ Search for registry entry that matches the given string
275 If prior to invoking this command no registry plane is specified
276 using 'setregistryplane', the command defaults to searching entries from the IOService plane
277 syntax: (lldb) findregistryentries AppleACPICPU - will find the first registry entry that matches AppleACPICPU
280 print "Please specify the name of the registry entry you want to find"
281 print FindRegistryEntry
.__doc
__
284 FindRegistryEntryRecurse(kern
.globals.gRegistryRoot
, cmd_args
[0], True)
286 @lldb_command('findregistryentries')
287 def FindRegistryEntries(cmd_args
=None):
288 """ Search for all registry entries that match the given string
289 If prior to invoking this command no registry plane is specified
290 using 'setregistryplane', the command defaults to searching entries from the IOService plane
291 syntax: (lldb) findregistryentries AppleACPICPU - will find all registry entries that match AppleACPICPU
294 print "Please specify the name of the registry entry/entries you want to find"
295 print FindRegistryEntries
.__doc
__
298 FindRegistryEntryRecurse(kern
.globals.gRegistryRoot
, cmd_args
[0], False)
300 @lldb_command('findregistryprop')
301 def FindRegistryProp(cmd_args
=None):
302 """ Given a registry entry, print out the contents for the property that matches
304 syntax: (lldb) findregistryprop 0xaddr IOSleepSupported
305 syntax: (lldb) findregistryprop gIOPMRootDomain IOSleepSupported
306 syntax: (lldb) findregistryprop gIOPMRootDomain "Supported Features"
308 if not cmd_args
or len(cmd_args
) < 2:
309 print "Please specify the address of a IORegistry entry and the property you're looking for"
310 print FindRegistryProp
.__doc
__
313 entry
= kern
.GetValueFromAddress(cmd_args
[0], 'IOService *')
314 propertyTable
= entry
.fPropertyTable
315 print GetObjectSummary(LookupKeyInPropTable(propertyTable
, cmd_args
[1]))
317 @lldb_command('readioport8')
318 def ReadIOPort8(cmd_args
=None):
319 """ Read value stored in the specified IO port. The CPU can be optionally
321 Prints 0xBAD10AD in case of a bad read
322 Syntax: (lldb) readioport8 <port> [lcpu (kernel's numbering convention)]
325 print "Please specify a port to read out of"
326 print ReadIOPort8
.__doc__
329 portAddr
= ArgumentStringToInt(cmd_args
[0])
330 if len(cmd_args
) >= 2:
331 lcpu
= ArgumentStringToInt(cmd_args
[1])
333 lcpu
= xnudefines
.lcpu_self
335 ReadIOPortInt(portAddr
, 1, lcpu
)
337 @lldb_command('readioport16')
338 def ReadIOPort16(cmd_args
=None):
339 """ Read value stored in the specified IO port. The CPU can be optionally
341 Prints 0xBAD10AD in case of a bad read
342 Syntax: (lldb) readioport16 <port> [lcpu (kernel's numbering convention)]
345 print "Please specify a port to read out of"
346 print ReadIOPort16
.__doc__
349 portAddr
= ArgumentStringToInt(cmd_args
[0])
350 if len(cmd_args
) >= 2:
351 lcpu
= ArgumentStringToInt(cmd_args
[1])
353 lcpu
= xnudefines
.lcpu_self
355 ReadIOPortInt(portAddr
, 2, lcpu
)
357 @lldb_command('readioport32')
358 def ReadIOPort32(cmd_args
=None):
359 """ Read value stored in the specified IO port. The CPU can be optionally
361 Prints 0xBAD10AD in case of a bad read
362 Syntax: (lldb) readioport32 <port> [lcpu (kernel's numbering convention)]
365 print "Please specify a port to read out of"
366 print ReadIOPort32
.__doc__
369 portAddr
= ArgumentStringToInt(cmd_args
[0])
370 if len(cmd_args
) >= 2:
371 lcpu
= ArgumentStringToInt(cmd_args
[1])
373 lcpu
= xnudefines
.lcpu_self
375 ReadIOPortInt(portAddr
, 4, lcpu
)
377 @lldb_command('writeioport8')
378 def WriteIOPort8(cmd_args
=None):
379 """ Write the value to the specified IO port. The size of the value is
380 determined by the name of the command. The CPU used can be optionally
382 Syntax: (lldb) writeioport8 <port> <value> [lcpu (kernel's numbering convention)]
384 if not cmd_args
or len(cmd_args
) < 2:
385 print "Please specify a port to write to, followed by the value you want to write"
386 print WriteIOPort8
.__doc__
389 portAddr
= ArgumentStringToInt(cmd_args
[0])
390 value
= ArgumentStringToInt(cmd_args
[1])
392 if len(cmd_args
) >= 3:
393 lcpu
= ArgumentStringToInt(cmd_args
[2])
395 lcpu
= xnudefines
.lcpu_self
397 WriteIOPortInt(portAddr
, 1, value
, lcpu
)
399 @lldb_command('writeioport16')
400 def WriteIOPort16(cmd_args
=None):
401 """ Write the value to the specified IO port. The size of the value is
402 determined by the name of the command. The CPU used can be optionally
404 Syntax: (lldb) writeioport16 <port> <value> [lcpu (kernel's numbering convention)]
406 if not cmd_args
or len(cmd_args
) < 2:
407 print "Please specify a port to write to, followed by the value you want to write"
408 print WriteIOPort16
.__doc__
411 portAddr
= ArgumentStringToInt(cmd_args
[0])
412 value
= ArgumentStringToInt(cmd_args
[1])
414 if len(cmd_args
) >= 3:
415 lcpu
= ArgumentStringToInt(cmd_args
[2])
417 lcpu
= xnudefines
.lcpu_self
419 WriteIOPortInt(portAddr
, 2, value
, lcpu
)
421 @lldb_command('writeioport32')
422 def WriteIOPort32(cmd_args
=None):
423 """ Write the value to the specified IO port. The size of the value is
424 determined by the name of the command. The CPU used can be optionally
426 Syntax: (lldb) writeioport32 <port> <value> [lcpu (kernel's numbering convention)]
428 if not cmd_args
or len(cmd_args
) < 2:
429 print "Please specify a port to write to, followed by the value you want to write"
430 print WriteIOPort32
.__doc__
433 portAddr
= ArgumentStringToInt(cmd_args
[0])
434 value
= ArgumentStringToInt(cmd_args
[1])
436 if len(cmd_args
) >= 3:
437 lcpu
= ArgumentStringToInt(cmd_args
[2])
439 lcpu
= xnudefines
.lcpu_self
441 WriteIOPortInt(portAddr
, 4, value
, lcpu
)
443 @lldb_command('showioservicepm')
444 def ShowIOServicePM(cmd_args
=None):
445 """ Routine to dump the IOServicePM object
446 Syntax: (lldb) showioservicepm <IOServicePM pointer>
449 print "Please enter the pointer to the IOServicePM object you'd like to introspect"
450 print ShowIOServicePM
.__doc
__
453 iopmpriv
= kern
.GetValueFromAddress(cmd_args
[0], 'IOServicePM *')
454 out_string
= "MachineState {0: <6d} (".format(iopmpriv
.MachineState
)
459 1: 'kIOPM_OurChangeTellClientsPowerDown',
460 2: 'kIOPM_OurChangeTellClientsPowerDown',
461 3: 'kIOPM_OurChangeNotifyInterestedDriversWillChange',
462 4: 'kIOPM_OurChangeSetPowerState',
463 5: 'kIOPM_OurChangeWaitForPowerSettle',
464 6: 'kIOPM_OurChangeNotifyInterestedDriversDidChange',
465 7: 'kIOPM_OurChangeTellCapabilityDidChange',
466 8: 'kIOPM_OurChangeFinish',
467 9: 'Unused_MachineState_9',
468 10: 'kIOPM_ParentChangeTellPriorityClientsPowerDown',
469 11: 'kIOPM_ParentChangeNotifyInterestedDriversWillChange',
470 12: 'kIOPM_ParentChangeSetPowerState',
471 13: 'kIOPM_ParentChangeWaitForPowerSettle',
472 14: 'kIOPM_ParentChangeNotifyInterestedDriversDidChange',
473 15: 'kIOPM_ParentChangeTellCapabilityDidChange',
474 16: 'kIOPM_ParentChangeAcknowledgePowerChange',
475 17: 'kIOPM_NotifyChildrenStart',
476 18: 'kIOPM_NotifyChildrenOrdered',
477 19: 'kIOPM_NotifyChildrenDelayed',
478 20: 'kIOPM_SyncTellClientsPowerDown',
479 21: 'kIOPM_SyncTellPriorityClientsPowerDown',
480 22: 'kIOPM_SyncNotifyWillChange',
481 23: 'kIOPM_SyncNotifyDidChange',
482 24: 'kIOPM_SyncTellCapabilityDidChange',
483 25: 'kIOPM_SyncFinish',
484 26: 'kIOPM_TellCapabilityChangeDone',
485 27: 'kIOPM_DriverThreadCallDone'
487 powerstate
= unsigned(iopmpriv
.MachineState
)
488 if powerstate
in pstate_map
:
489 out_string
+= "{0:s}".format(pstate_map
[powerstate
])
491 out_string
+= "Unknown_MachineState"
494 if iopmpriv
.MachineState
!= 20:
495 out_string
+= "DriverTimer = {0: <6d}, SettleTime = {1: < 6d}, HeadNoteFlags = {2: #12x}, HeadNotePendingAcks = {3: #012x}, ".format(
496 unsigned(iopmpriv
.DriverTimer
),
497 unsigned(iopmpriv
.SettleTimeUS
),
498 unsigned(iopmpriv
.HeadNoteChangeFlags
),
499 unsigned(iopmpriv
.HeadNotePendingAcks
))
501 if iopmpriv
.DeviceOverrideEnabled
!= 0:
502 out_string
+= "DeviceOverrides, "
504 out_string
+= "DeviceDesire = {0: <6d}, DesiredPowerState = {1: <6d}, PreviousRequest = {2: <6d}\n".format(
505 unsigned(iopmpriv
.DeviceDesire
),
506 unsigned(iopmpriv
.DesiredPowerState
),
507 unsigned(iopmpriv
.PreviousRequestPowerFlags
))
511 ######################################
513 ######################################
514 def ShowRegistryEntryRecurse(entry
, prefix
, printProps
):
515 """ prints registry entry summary and recurses through all its children.
520 plen
= (len(prefix
)//2)
521 registryTable
= entry
.fRegistryTable
522 propertyTable
= entry
.fPropertyTable
524 # Print entry details
525 print "{0:s}{1:s}".format(prefix
, GetRegistryEntrySummary(entry
))
526 # Printing large property tables make it look like lldb is 'stuck'
528 print GetRegDictionary(propertyTable
, prefix
+ " | ")
532 childKey
= kern
.globals.gIOServicePlane
.keys
[1]
534 childKey
= plane
.keys
[1]
535 childArray
= LookupKeyInOSDict(registryTable
, childKey
)
536 if childArray
is not None:
538 ca
= CastIOKitClass(childArray
, 'OSArray *')
539 count
= unsigned(ca
.count
)
541 if plen
!= 0 and plen
!= 1 and (plen
& (plen
- 1)) == 0:
542 ShowRegistryEntryRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), prefix
+ "| ", printProps
)
544 ShowRegistryEntryRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), prefix
+ " ", printProps
)
547 def FindRegistryEntryRecurse(entry
, search_name
, stopAfterFirst
):
548 """ Checks if given registry entry's name matches the search_name we're looking for
549 If yes, it prints the entry's summary and then recurses through its children
550 If no, it does nothing and recurses through its children
554 registryTable
= entry
.fRegistryTable
555 propertyTable
= entry
.fPropertyTable
559 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
561 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
563 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
566 if str(CastIOKitClass(name
, 'OSString *').string
) == search_name
:
567 print GetRegistryEntrySummary(entry
)
568 if stopAfterFirst
is True:
570 elif CastIOKitClass(entry
, 'IOService *').pwrMgt
and CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
:
571 name
= CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
572 if str(name
) == search_name
:
573 print GetRegistryEntrySummary(entry
)
574 if stopAfterFirst
is True:
579 childKey
= kern
.globals.gIOServicePlane
.keys
[1]
581 childKey
= plane
.keys
[1]
582 childArray
= LookupKeyInOSDict(registryTable
, childKey
)
583 if childArray
is not None:
585 ca
= CastIOKitClass(childArray
, 'OSArray *')
586 count
= unsigned(ca
.count
)
588 if FindRegistryEntryRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), search_name
, stopAfterFirst
) is True:
593 def FindRegistryObjectRecurse(entry
, search_name
):
594 """ Checks if given registry entry's name matches the search_name we're looking for
595 If yes, return the entry
596 If no, it does nothing and recurses through its children
597 Implicitly stops after finding the first entry
601 registryTable
= entry
.fRegistryTable
602 propertyTable
= entry
.fPropertyTable
606 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
608 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
610 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
613 if str(CastIOKitClass(name
, 'OSString *').string
) == search_name
:
615 elif CastIOKitClass(entry
, 'IOService *').pwrMgt
and CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
:
616 name
= CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
617 if str(name
) == search_name
:
622 childKey
= kern
.globals.gIOServicePlane
.keys
[1]
624 childKey
= plane
.keys
[1]
625 childArray
= LookupKeyInOSDict(registryTable
, childKey
)
626 if childArray
is not None:
627 ca
= CastIOKitClass(childArray
, 'OSArray *')
628 for idx
in range(ca
.count
):
629 registry_object
= FindRegistryObjectRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), search_name
)
630 if not registry_object
or int(registry_object
) == int(0):
633 return registry_object
636 def LookupKeyInOSDict(osdict
, key
):
637 """ Returns the value corresponding to a given key in a OSDictionary
638 Returns None if the key was not found
642 count
= unsigned(osdict
.count
)
645 while idx
< count
and result
is None:
646 if key
== osdict
.dictionary
[idx
].key
:
647 result
= osdict
.dictionary
[idx
].value
651 def LookupKeyInPropTable(propertyTable
, key_str
):
652 """ Returns the value corresponding to a given key from a registry entry's property table
653 Returns None if the key was not found
654 The property that is being searched for is specified as a string in key_str
656 if not propertyTable
:
658 count
= unsigned(propertyTable
.count
)
661 while idx
< count
and result
is None:
662 if key_str
== str(propertyTable
.dictionary
[idx
].key
.string
):
663 result
= propertyTable
.dictionary
[idx
].value
667 def GetRegDictionary(osdict
, prefix
):
668 """ Returns a specially formatted string summary of the given OSDictionary
669 This is done in order to pretty-print registry property tables in showregistry
672 out_string
= prefix
+ "{\n"
674 count
= unsigned(osdict
.count
)
677 out_string
+= prefix
+ " " + GetObjectSummary(osdict
.dictionary
[idx
].key
) + " = " + GetObjectSummary(osdict
.dictionary
[idx
].value
) + "\n"
679 out_string
+= prefix
+ "}\n"
682 def GetString(string
):
683 """ Returns the python string representation of a given OSString
685 out_string
= "\"{0:s}\"".format(CastIOKitClass(string
, 'OSString *').string
)
689 out_string
= "{0:d}".format(CastIOKitClass(num
, 'OSNumber *').value
)
693 """ Shows info about a given OSBoolean
696 if b
== kern
.globals.gOSBooleanFalse
:
702 def GetMetaClass(mc
):
703 """ Shows info about a given OSSymbol
705 out_string
= "{0: <5d}x {1: >5d} bytes {2:s}\n".format(mc
.instanceCount
, mc
.classSize
, mc
.className
.string
)
709 """ Returns a string containing info about a given OSArray
713 count
= unsigned(arr
.count
)
718 out_string
+= GetObjectSummary(obj
)
719 if idx
< unsigned(arr
.count
):
723 def GetDictionary(d
):
724 """ Returns a string containing info about a given OSDictionary
728 count
= unsigned(d
.count
)
731 obj
= d
.dictionary
[idx
].key
732 out_string
+= GetObjectSummary(obj
) + "="
733 obj
= d
.dictionary
[idx
].value
735 out_string
+= GetObjectSummary(obj
)
742 """ Returns a string containing info about a given OSSet
744 out_string
+= "[" + GetArray(se
.members
) + "]"
747 def ReadIOPortInt(addr
, numbytes
, lcpu
):
748 """ Prints results after reading a given ioport
752 if "kdp" != GetConnectionProtocol():
753 print "Target is not connected over kdp. Nothing to do here."
756 # Set up the manual KDP packet
757 input_address
= unsigned(addressof(kern
.globals.manual_pkt
.input))
758 len_address
= unsigned(addressof(kern
.globals.manual_pkt
.len))
759 data_address
= unsigned(addressof(kern
.globals.manual_pkt
.data
))
760 if not WriteInt32ToMemoryAddress(0, input_address
):
761 print "0x{0: <4x}: 0x{1: <1x}".format(addr
, result
)
764 kdp_pkt_size
= GetType('kdp_readioport_req_t').GetByteSize()
765 if not WriteInt32ToMemoryAddress(kdp_pkt_size
, len_address
):
766 print "0x{0: <4x}: 0x{1: <1x}".format(addr
, result
)
769 kgm_pkt
= kern
.GetValueFromAddress(data_address
, 'kdp_readioport_req_t *')
771 header_value
= GetKDPPacketHeaderInt(request
=GetEnumValue('kdp_req_t::KDP_READIOPORT'), length
= kdp_pkt_size
)
773 if( WriteInt64ToMemoryAddress((header_value
), int(addressof(kgm_pkt
.hdr
))) and
774 WriteInt16ToMemoryAddress(addr
, int(addressof(kgm_pkt
.address
))) and
775 WriteInt32ToMemoryAddress(numbytes
, int(addressof(kgm_pkt
.nbytes
))) and
776 WriteInt16ToMemoryAddress(lcpu
, int(addressof(kgm_pkt
.lcpu
))) and
777 WriteInt32ToMemoryAddress(1, input_address
)
780 result_pkt
= Cast(addressof(kern
.globals.manual_pkt
.data
), 'kdp_readioport_reply_t *')
782 if(result_pkt
.error
== 0):
784 result
= dereference(Cast(addressof(result_pkt
.data
), 'uint8_t *'))
786 result
= dereference(Cast(addressof(result_pkt
.data
), 'uint16_t *'))
788 result
= dereference(Cast(addressof(result_pkt
.data
), 'uint32_t *'))
790 print "{0: <#6x}: {1:#0{2}x}".format(addr
, result
, (numbytes
*2)+2)
792 def WriteIOPortInt(addr
, numbytes
, value
, lcpu
):
793 """ Writes 'value' into ioport specified by 'addr'. Prints errors if it encounters any
795 if "kdp" != GetConnectionProtocol():
796 print "Target is not connected over kdp. Nothing to do here."
799 # Set up the manual KDP packet
800 input_address
= unsigned(addressof(kern
.globals.manual_pkt
.input))
801 len_address
= unsigned(addressof(kern
.globals.manual_pkt
.len))
802 data_address
= unsigned(addressof(kern
.globals.manual_pkt
.data
))
803 if not WriteInt32ToMemoryAddress(0, input_address
):
804 print "error writing {0: #x} to port {1: <#6x}: failed to write 0 to input_address".format(value
, addr
)
807 kdp_pkt_size
= GetType('kdp_writeioport_req_t').GetByteSize()
808 if not WriteInt32ToMemoryAddress(kdp_pkt_size
, len_address
):
809 print "error writing {0: #x} to port {1: <#6x}: failed to write kdp_pkt_size".format(value
, addr
)
812 kgm_pkt
= kern
.GetValueFromAddress(data_address
, 'kdp_writeioport_req_t *')
814 header_value
= GetKDPPacketHeaderInt(request
=GetEnumValue('kdp_req_t::KDP_WRITEIOPORT'), length
= kdp_pkt_size
)
816 if( WriteInt64ToMemoryAddress((header_value
), int(addressof(kgm_pkt
.hdr
))) and
817 WriteInt16ToMemoryAddress(addr
, int(addressof(kgm_pkt
.address
))) and
818 WriteInt32ToMemoryAddress(numbytes
, int(addressof(kgm_pkt
.nbytes
))) and
819 WriteInt16ToMemoryAddress(lcpu
, int(addressof(kgm_pkt
.lcpu
)))
822 if not WriteInt8ToMemoryAddress(value
, int(addressof(kgm_pkt
.data
))):
823 print "error writing {0: #x} to port {1: <#6x}: failed to write 8 bit data".format(value
, addr
)
826 if not WriteInt16ToMemoryAddress(value
, int(addressof(kgm_pkt
.data
))):
827 print "error writing {0: #x} to port {1: <#6x}: failed to write 16 bit data".format(value
, addr
)
830 if not WriteInt32ToMemoryAddress(value
, int(addressof(kgm_pkt
.data
))):
831 print "error writing {0: #x} to port {1: <#6x}: failed to write 32 bit data".format(value
, addr
)
833 if not WriteInt32ToMemoryAddress(1, input_address
):
834 print "error writing {0: #x} to port {1: <#6x}: failed to write to input_address".format(value
, addr
)
837 result_pkt
= Cast(addressof(kern
.globals.manual_pkt
.data
), 'kdp_writeioport_reply_t *')
839 # Done with the write
840 if(result_pkt
.error
== 0):
841 print "Writing {0: #x} to port {1: <#6x} was successful".format(value
, addr
)
843 print "error writing {0: #x} to port {1: <#6x}".format(value
, addr
)
845 @lldb_command('showinterruptcounts')
846 def showinterruptcounts(cmd_args
=None):
847 """ Shows event source based interrupt counts by nub name and interrupt index.
848 Does not cover interrupts that are not event source based. Will report 0
849 if interrupt accounting is disabled.
852 header_format
= "{0: <20s} {1: >5s} {2: >20s}"
853 content_format
= "{0: <20s} {1: >5d} {2: >20d}"
855 print header_format
.format("Name", "Index", "Count")
857 for i
in kern
.interrupt_stats
:
858 owner
= CastIOKitClass(i
.owner
, 'IOInterruptEventSource *')
859 nub
= CastIOKitClass(owner
.provider
, 'IORegistryEntry *')
862 # To uniquely identify an interrupt, we need the nub name and the index. The index
863 # is stored with the stats object, but we need to retrieve the name.
865 registryTable
= nub
.fRegistryTable
866 propertyTable
= nub
.fPropertyTable
868 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
870 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
872 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
877 nub_name
= GetString(CastIOKitClass(name
, 'OSString *'))
879 # We now have everything we need; spew the requested data.
881 interrupt_index
= i
.interruptIndex
882 first_level_count
= i
.interruptStatistics
[0]
884 print content_format
.format(nub_name
, interrupt_index
, first_level_count
)
888 @lldb_command('showinterruptstats')
889 def showinterruptstats(cmd_args
=None):
890 """ Shows event source based interrupt statistics by nub name and interrupt index.
891 Does not cover interrupts that are not event source based. Will report 0
892 if interrupt accounting is disabled, or if specific statistics are disabled.
893 Time is reported in ticks of mach_absolute_time. Statistics are:
895 Interrupt Count: Number of times the interrupt context handler was run
896 Interrupt Time: Total time spent in the interrupt context handler (if any)
897 Workloop Count: Number of times the kernel context handler was run
898 Workloop CPU Time: Total CPU time spent running the kernel context handler
899 Workloop Time: Total time spent running the kernel context handler
902 header_format
= "{0: <20s} {1: >5s} {2: >20s} {3: >20s} {4: >20s} {5: >20s} {6: >20s} {7: >20s} {8: >20s} {9: >20s}"
903 content_format
= "{0: <20s} {1: >5d} {2: >20d} {3: >20d} {4: >20d} {5: >20d} {6: >20d} {7: >20d} {8: >20d} {9: >#20x}"
905 print header_format
.format("Name", "Index", "Interrupt Count", "Interrupt Time", "Avg Interrupt Time", "Workloop Count", "Workloop CPU Time", "Workloop Time", "Avg Workloop Time", "Owner")
907 for i
in kern
.interrupt_stats
:
908 owner
= CastIOKitClass(i
.owner
, 'IOInterruptEventSource *')
909 nub
= CastIOKitClass(owner
.provider
, 'IORegistryEntry *')
912 # To uniquely identify an interrupt, we need the nub name and the index. The index
913 # is stored with the stats object, but we need to retrieve the name.
915 registryTable
= nub
.fRegistryTable
916 propertyTable
= nub
.fPropertyTable
918 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
920 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
922 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
927 nub_name
= GetString(CastIOKitClass(name
, 'OSString *'))
929 # We now have everything we need; spew the requested data.
931 interrupt_index
= i
.interruptIndex
932 first_level_count
= i
.interruptStatistics
[0]
933 second_level_count
= i
.interruptStatistics
[1]
934 first_level_time
= i
.interruptStatistics
[2]
935 second_level_cpu_time
= i
.interruptStatistics
[3]
936 second_level_system_time
= i
.interruptStatistics
[4]
938 avg_first_level_time
= 0
939 if first_level_count
!= 0:
940 avg_first_level_time
= first_level_time
/ first_level_count
942 avg_second_level_time
= 0
943 if second_level_count
!= 0:
944 avg_second_level_time
= second_level_system_time
/ second_level_count
946 print content_format
.format(nub_name
, interrupt_index
, first_level_count
, first_level_time
, avg_first_level_time
,
947 second_level_count
, second_level_cpu_time
, second_level_system_time
, avg_second_level_time
, owner
)