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
)
37 if hasattr(obj
, 'retainCount'):
38 retCount
= (obj
.retainCount
& 0xffff)
39 cntnrRetCount
= (retCount
>> 16)
40 out_string
= "`object 0x{0: <16x}, vt 0x{1: <16x} <{2:s}>, retain count {3:d}, container retain {4:d}` ".format(obj
, vt
, vtype
[0].GetName(), retCount
, cntnrRetCount
)
43 out_string
= "`object 0x{0: <16x}, vt 0x{1: <16x} <{2:s}>` ".format(obj
, vt
, vtype
[0].GetName())
45 out_string
= "`object 0x{0: <16x}, vt 0x{1: <16x}` ".format(obj
, vt
)
47 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV8OSString')
49 out_string
+= GetString(obj
)
52 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV8OSSymbol')
54 out_string
+= GetString(obj
)
57 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV8OSNumber')
59 out_string
+= GetNumber(obj
)
62 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV9OSBoolean')
64 out_string
+= GetBoolean(obj
)
67 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV7OSArray')
69 out_string
+= "(" + GetArray(CastIOKitClass(obj
, 'OSArray *')) + ")"
72 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV5OSSet')
74 out_string
+= GetSet(CastIOKitClass(obj
, 'OSSet *'))
77 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV12OSDictionary')
79 out_string
+= GetDictionary(CastIOKitClass(obj
, 'OSDictionary *'))
84 @lldb_type_summary(['IORegistryEntry *'])
86 def GetRegistryEntrySummary(entry
):
87 """ returns a string containing summary information about an IORegistry
88 object including it's registry id , vtable ptr and retain count
92 registryTable
= entry
.fRegistryTable
93 propertyTable
= entry
.fPropertyTable
95 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
97 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
99 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
102 out_string
+= "+-o {0:s} ".format(GetString(CastIOKitClass(name
, 'OSString *')))
103 elif CastIOKitClass(entry
, 'IOService *').pwrMgt
and CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
:
104 out_string
+= "+-o {0:s} ".format(CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
)
106 out_string
+= "+-o ?? "
108 # I'm using uintptr_t for now to work around <rdar://problem/12749733> FindFirstType & Co. should allow you to make pointer types directly
109 vtableAddr
= dereference(Cast(entry
, 'uintptr_t *')) - 2 * sizeof('uintptr_t *')
110 vtype
= kern
.SymbolicateFromAddress(vtableAddr
)
111 if vtype
is None or len(vtype
) < 1:
112 out_string
+= "<object 0x{0: <16x}, id 0x{1:x}, vtable 0x{2: <16x}".format(entry
, CastIOKitClass(entry
, 'IORegistryEntry *').reserved
.fRegistryEntryID
, vtableAddr
)
114 out_string
+= "<object 0x{0: <16x}, id 0x{1:x}, vtable 0x{2: <16x} <{3:s}>".format(entry
, CastIOKitClass(entry
, 'IORegistryEntry *').reserved
.fRegistryEntryID
,
115 vtableAddr
, vtype
[0].GetName())
117 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV15IORegistryEntry')
118 if vtableAddr
!= ztvAddr
:
120 state
= CastIOKitClass(entry
, 'IOService *').__state
[0]
121 # kIOServiceRegisteredState
124 out_string
+= "registered, "
125 # kIOServiceMatchedState
128 out_string
+= "matched, "
129 #kIOServiceInactiveState
132 busyCount
= (CastIOKitClass(entry
, 'IOService *').__state
[1] & 0xff)
133 retCount
= (CastIOKitClass(entry
, 'IOService *').retainCount
& 0xffff)
134 out_string
+= "active, busy {0}, retain count {1}>".format(busyCount
, retCount
)
137 ######################################
139 ######################################
140 @lldb_command('showallclasses')
141 def ShowAllClasses(cmd_args
=None):
142 """ Show the instance counts and ivar size of all OSObject subclasses.
143 See ioclasscount man page for details
146 count
= unsigned(kern
.globals.sAllClassesDict
.count
)
149 meta
= CastIOKitClass(kern
.globals.sAllClassesDict
.dictionary
[idx
].value
, 'OSMetaClass *')
151 print GetMetaClass(meta
)
153 @lldb_command('showobject')
154 def ShowObject(cmd_args
=None):
155 """ Show info about an OSObject - its vtable ptr and retain count, & more info for simple container classes.
158 print "Please specify the address of the OSObject whose info you want to view. Type help showobject for help"
161 obj
= kern
.GetValueFromAddress(cmd_args
[0], 'OSObject *')
162 print GetObjectSummary(obj
)
164 @lldb_command('setregistryplane')
165 def SetRegistryPlane(cmd_args
=None):
166 """ Set the plane to be used for the IOKit registry macros
167 syntax: (lldb) setregistryplane 0 - will display all known planes
168 syntax: (lldb) setregistryplane 0xaddr - will set the registry plane to 0xaddr
169 syntax: (lldb) setregistryplane gIODTPlane - will set the registry plane to gIODTPlane
172 print "Please specify the name of the plane you want to use with the IOKit registry macros."
173 print SetRegistryPlane
.__doc
__
175 if cmd_args
[0] == "0":
176 print GetObjectSummary(kern
.globals.gIORegistryPlanes
)
179 plane
= kern
.GetValueFromAddress(cmd_args
[0], 'IORegistryPlane *')
182 @lldb_command('showregistryentry')
183 def ShowRegistryEntry(cmd_args
=None):
184 """ Show info about a registry entry; its properties and descendants in the current plane
185 syntax: (lldb) showregistryentry 0xaddr
186 syntax: (lldb) showregistryentry gIOPMRootDomain
189 print "Please specify the address of the registry entry whose info you want to view."
190 print ShowRegistryEntry
.__doc
__
193 entry
= kern
.GetValueFromAddress(cmd_args
[0], 'IORegistryEntry *')
194 ShowRegistryEntryRecurse(entry
, "", True)
196 @lldb_command('showregistry')
197 def ShowRegistry(cmd_args
=None):
198 """ Show info about all registry entries in the current plane
199 If prior to invoking this command no registry plane is specified
200 using 'setregistryplane', the command defaults to the IOService plane
202 ShowRegistryEntryRecurse(kern
.globals.gRegistryRoot
, "", False)
204 @lldb_command('showregistryprops')
205 def ShowRegistryProps(cmd_args
=None):
206 """ Show info about all registry entries in the current plane, and their properties
207 If prior to invoking this command no registry plane is specified
208 using 'setregistryplane', the command defaults to the IOService plane
210 ShowRegistryEntryRecurse(kern
.globals.gRegistryRoot
, "", True)
212 @lldb_command('findregistryentry')
213 def FindRegistryEntry(cmd_args
=None):
214 """ Search for registry entry that matches the given string
215 If prior to invoking this command no registry plane is specified
216 using 'setregistryplane', the command defaults to searching entries from the IOService plane
217 syntax: (lldb) findregistryentries AppleACPICPU - will find the first registry entry that matches AppleACPICPU
220 print "Please specify the name of the registry entry you want to find"
221 print FindRegistryEntry
.__doc
__
224 FindRegistryEntryRecurse(kern
.globals.gRegistryRoot
, cmd_args
[0], True)
226 @lldb_command('findregistryentries')
227 def FindRegistryEntries(cmd_args
=None):
228 """ Search for all registry entries that match the given string
229 If prior to invoking this command no registry plane is specified
230 using 'setregistryplane', the command defaults to searching entries from the IOService plane
231 syntax: (lldb) findregistryentries AppleACPICPU - will find all registry entries that match AppleACPICPU
234 print "Please specify the name of the registry entry/entries you want to find"
235 print FindRegistryEntries
.__doc
__
238 FindRegistryEntryRecurse(kern
.globals.gRegistryRoot
, cmd_args
[0], False)
240 @lldb_command('findregistryprop')
241 def FindRegistryProp(cmd_args
=None):
242 """ Given a registry entry, print out the contents for the property that matches
244 syntax: (lldb) findregistryprop 0xaddr IOSleepSupported
245 syntax: (lldb) findregistryprop gIOPMRootDomain IOSleepSupported
246 syntax: (lldb) findregistryprop gIOPMRootDomain "Supported Features"
248 if not cmd_args
or len(cmd_args
) < 2:
249 print "Please specify the address of a IORegistry entry and the property you're looking for"
250 print FindRegistryProp
.__doc
__
253 entry
= kern
.GetValueFromAddress(cmd_args
[0], 'IOService *')
254 propertyTable
= entry
.fPropertyTable
255 print GetObjectSummary(LookupKeyInPropTable(propertyTable
, cmd_args
[1]))
257 @lldb_command('readioport8')
258 def ReadIOPort8(cmd_args
=None):
259 """ Read value stored in the specified IO port. The CPU can be optionally
261 Prints 0xBAD10AD in case of a bad read
262 Syntax: (lldb) readioport8 <port> [lcpu (kernel's numbering convention)]
265 print "Please specify a port to read out of"
266 print ReadIOPort8
.__doc__
269 portAddr
= ArgumentStringToInt(cmd_args
[0])
270 if len(cmd_args
) >= 2:
271 lcpu
= ArgumentStringToInt(cmd_args
[1])
273 lcpu
= xnudefines
.lcpu_self
275 ReadIOPortInt(portAddr
, 1, lcpu
)
277 @lldb_command('readioport16')
278 def ReadIOPort16(cmd_args
=None):
279 """ Read value stored in the specified IO port. The CPU can be optionally
281 Prints 0xBAD10AD in case of a bad read
282 Syntax: (lldb) readioport16 <port> [lcpu (kernel's numbering convention)]
285 print "Please specify a port to read out of"
286 print ReadIOPort16
.__doc__
289 portAddr
= ArgumentStringToInt(cmd_args
[0])
290 if len(cmd_args
) >= 2:
291 lcpu
= ArgumentStringToInt(cmd_args
[1])
293 lcpu
= xnudefines
.lcpu_self
295 ReadIOPortInt(portAddr
, 2, lcpu
)
297 @lldb_command('readioport32')
298 def ReadIOPort32(cmd_args
=None):
299 """ Read value stored in the specified IO port. The CPU can be optionally
301 Prints 0xBAD10AD in case of a bad read
302 Syntax: (lldb) readioport32 <port> [lcpu (kernel's numbering convention)]
305 print "Please specify a port to read out of"
306 print ReadIOPort32
.__doc__
309 portAddr
= ArgumentStringToInt(cmd_args
[0])
310 if len(cmd_args
) >= 2:
311 lcpu
= ArgumentStringToInt(cmd_args
[1])
313 lcpu
= xnudefines
.lcpu_self
315 ReadIOPortInt(portAddr
, 4, lcpu
)
317 @lldb_command('writeioport8')
318 def WriteIOPort8(cmd_args
=None):
319 """ Write the value to the specified IO port. The size of the value is
320 determined by the name of the command. The CPU used can be optionally
322 Syntax: (lldb) writeioport8 <port> <value> [lcpu (kernel's numbering convention)]
324 if not cmd_args
or len(cmd_args
) < 2:
325 print "Please specify a port to write to, followed by the value you want to write"
326 print WriteIOPort8
.__doc__
329 portAddr
= ArgumentStringToInt(cmd_args
[0])
330 value
= ArgumentStringToInt(cmd_args
[1])
332 if len(cmd_args
) >= 3:
333 lcpu
= ArgumentStringToInt(cmd_args
[2])
335 lcpu
= xnudefines
.lcpu_self
337 WriteIOPortInt(portAddr
, 1, value
, lcpu
)
339 @lldb_command('writeioport16')
340 def WriteIOPort16(cmd_args
=None):
341 """ Write the value to the specified IO port. The size of the value is
342 determined by the name of the command. The CPU used can be optionally
344 Syntax: (lldb) writeioport16 <port> <value> [lcpu (kernel's numbering convention)]
346 if not cmd_args
or len(cmd_args
) < 2:
347 print "Please specify a port to write to, followed by the value you want to write"
348 print WriteIOPort16
.__doc__
351 portAddr
= ArgumentStringToInt(cmd_args
[0])
352 value
= ArgumentStringToInt(cmd_args
[1])
354 if len(cmd_args
) >= 3:
355 lcpu
= ArgumentStringToInt(cmd_args
[2])
357 lcpu
= xnudefines
.lcpu_self
359 WriteIOPortInt(portAddr
, 2, value
, lcpu
)
361 @lldb_command('writeioport32')
362 def WriteIOPort32(cmd_args
=None):
363 """ Write the value to the specified IO port. The size of the value is
364 determined by the name of the command. The CPU used can be optionally
366 Syntax: (lldb) writeioport32 <port> <value> [lcpu (kernel's numbering convention)]
368 if not cmd_args
or len(cmd_args
) < 2:
369 print "Please specify a port to write to, followed by the value you want to write"
370 print WriteIOPort32
.__doc__
373 portAddr
= ArgumentStringToInt(cmd_args
[0])
374 value
= ArgumentStringToInt(cmd_args
[1])
376 if len(cmd_args
) >= 3:
377 lcpu
= ArgumentStringToInt(cmd_args
[2])
379 lcpu
= xnudefines
.lcpu_self
381 WriteIOPortInt(portAddr
, 4, value
, lcpu
)
383 @lldb_command('showioservicepm')
384 def ShowIOServicePM(cmd_args
=None):
385 """ Routine to dump the IOServicePM object
386 Syntax: (lldb) showioservicepm <IOServicePM pointer>
389 print "Please enter the pointer to the IOServicePM object you'd like to introspect"
390 print ShowIOServicePM
.__doc
__
393 iopmpriv
= kern
.GetValueFromAddress(cmd_args
[0], 'IOServicePM *')
394 out_string
= "MachineState {0: <6d} (".format(iopmpriv
.MachineState
)
399 1: 'kIOPM_OurChangeTellClientsPowerDown',
400 2: 'kIOPM_OurChangeTellClientsPowerDown',
401 3: 'kIOPM_OurChangeNotifyInterestedDriversWillChange',
402 4: 'kIOPM_OurChangeSetPowerState',
403 5: 'kIOPM_OurChangeWaitForPowerSettle',
404 6: 'kIOPM_OurChangeNotifyInterestedDriversDidChange',
405 7: 'kIOPM_OurChangeTellCapabilityDidChange',
406 8: 'kIOPM_OurChangeFinish',
407 9: 'Unused_MachineState_9',
408 10: 'kIOPM_ParentChangeTellPriorityClientsPowerDown',
409 11: 'kIOPM_ParentChangeNotifyInterestedDriversWillChange',
410 12: 'kIOPM_ParentChangeSetPowerState',
411 13: 'kIOPM_ParentChangeWaitForPowerSettle',
412 14: 'kIOPM_ParentChangeNotifyInterestedDriversDidChange',
413 15: 'kIOPM_ParentChangeTellCapabilityDidChange',
414 16: 'kIOPM_ParentChangeAcknowledgePowerChange',
415 17: 'kIOPM_NotifyChildrenStart',
416 18: 'kIOPM_NotifyChildrenOrdered',
417 19: 'kIOPM_NotifyChildrenDelayed',
418 20: 'kIOPM_SyncTellClientsPowerDown',
419 21: 'kIOPM_SyncTellPriorityClientsPowerDown',
420 22: 'kIOPM_SyncNotifyWillChange',
421 23: 'kIOPM_SyncNotifyDidChange',
422 24: 'kIOPM_SyncTellCapabilityDidChange',
423 25: 'kIOPM_SyncFinish',
424 26: 'kIOPM_TellCapabilityChangeDone',
425 27: 'kIOPM_DriverThreadCallDone'
427 powerstate
= unsigned(iopmpriv
.MachineState
)
428 if powerstate
in pstate_map
:
429 out_string
+= "{0:s}".format(pstate_map
[powerstate
])
431 out_string
+= "Unknown_MachineState"
434 if iopmpriv
.MachineState
!= 20:
435 out_string
+= "DriverTimer = {0: <6d}, SettleTime = {1: < 6d}, HeadNoteFlags = {2: #12x}, HeadNotePendingAcks = {3: #012x}, ".format(
436 unsigned(iopmpriv
.DriverTimer
),
437 unsigned(iopmpriv
.SettleTimeUS
),
438 unsigned(iopmpriv
.HeadNoteChangeFlags
),
439 unsigned(iopmpriv
.HeadNotePendingAcks
))
441 if iopmpriv
.DeviceOverrideEnabled
!= 0:
442 out_string
+= "DeviceOverrides, "
444 out_string
+= "DeviceDesire = {0: <6d}, DesiredPowerState = {1: <6d}, PreviousRequest = {2: <6d}\n".format(
445 unsigned(iopmpriv
.DeviceDesire
),
446 unsigned(iopmpriv
.DesiredPowerState
),
447 unsigned(iopmpriv
.PreviousRequestPowerFlags
))
451 ######################################
453 ######################################
454 def ShowRegistryEntryRecurse(entry
, prefix
, printProps
):
455 """ prints registry entry summary and recurses through all its children.
460 plen
= (len(prefix
)//2)
461 registryTable
= entry
.fRegistryTable
462 propertyTable
= entry
.fPropertyTable
464 # Print entry details
465 print "{0:s}{1:s}".format(prefix
, GetRegistryEntrySummary(entry
))
466 # Printing large property tables make it look like lldb is 'stuck'
468 print GetRegDictionary(propertyTable
, prefix
+ " | ")
472 childKey
= kern
.globals.gIOServicePlane
.keys
[1]
474 childKey
= plane
.keys
[1]
475 childArray
= LookupKeyInOSDict(registryTable
, childKey
)
476 if childArray
is not None:
478 ca
= CastIOKitClass(childArray
, 'OSArray *')
479 count
= unsigned(ca
.count
)
481 if plen
!= 0 and plen
!= 1 and (plen
& (plen
- 1)) == 0:
482 ShowRegistryEntryRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), prefix
+ "| ", printProps
)
484 ShowRegistryEntryRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), prefix
+ " ", printProps
)
487 def FindRegistryEntryRecurse(entry
, search_name
, stopAfterFirst
):
488 """ Checks if given registry entry's name matches the search_name we're looking for
489 If yes, it prints the entry's summary and then recurses through its children
490 If no, it does nothing and recurses through its children
494 registryTable
= entry
.fRegistryTable
495 propertyTable
= entry
.fPropertyTable
499 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
501 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
503 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
506 if str(CastIOKitClass(name
, 'OSString *').string
) == search_name
:
507 print GetRegistryEntrySummary(entry
)
508 if stopAfterFirst
is True:
510 elif CastIOKitClass(entry
, 'IOService *').pwrMgt
and CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
:
511 name
= CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
512 if str(name
) == search_name
:
513 print GetRegistryEntrySummary(entry
)
514 if stopAfterFirst
is True:
519 childKey
= kern
.globals.gIOServicePlane
.keys
[1]
521 childKey
= plane
.keys
[1]
522 childArray
= LookupKeyInOSDict(registryTable
, childKey
)
523 if childArray
is not None:
525 ca
= CastIOKitClass(childArray
, 'OSArray *')
526 count
= unsigned(ca
.count
)
528 if FindRegistryEntryRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), search_name
, stopAfterFirst
) is True:
533 def FindRegistryObjectRecurse(entry
, search_name
):
534 """ Checks if given registry entry's name matches the search_name we're looking for
535 If yes, return the entry
536 If no, it does nothing and recurses through its children
537 Implicitly stops after finding the first entry
541 registryTable
= entry
.fRegistryTable
542 propertyTable
= entry
.fPropertyTable
546 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
548 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
550 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
553 if str(CastIOKitClass(name
, 'OSString *').string
) == search_name
:
555 elif CastIOKitClass(entry
, 'IOService *').pwrMgt
and CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
:
556 name
= CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
557 if str(name
) == search_name
:
562 childKey
= kern
.globals.gIOServicePlane
.keys
[1]
564 childKey
= plane
.keys
[1]
565 childArray
= LookupKeyInOSDict(registryTable
, childKey
)
566 if childArray
is not None:
567 ca
= CastIOKitClass(childArray
, 'OSArray *')
568 for idx
in range(ca
.count
):
569 registry_object
= FindRegistryObjectRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), search_name
)
570 if not registry_object
or int(registry_object
) == int(0):
573 return registry_object
576 def LookupKeyInOSDict(osdict
, key
):
577 """ Returns the value corresponding to a given key in a OSDictionary
578 Returns None if the key was not found
582 count
= unsigned(osdict
.count
)
585 while idx
< count
and result
is None:
586 if key
== osdict
.dictionary
[idx
].key
:
587 result
= osdict
.dictionary
[idx
].value
591 def LookupKeyInPropTable(propertyTable
, key_str
):
592 """ Returns the value corresponding to a given key from a registry entry's property table
593 Returns None if the key was not found
594 The property that is being searched for is specified as a string in key_str
596 if not propertyTable
:
598 count
= unsigned(propertyTable
.count
)
601 while idx
< count
and result
is None:
602 if key_str
== str(propertyTable
.dictionary
[idx
].key
.string
):
603 result
= propertyTable
.dictionary
[idx
].value
607 def GetRegDictionary(osdict
, prefix
):
608 """ Returns a specially formatted string summary of the given OSDictionary
609 This is done in order to pretty-print registry property tables in showregistry
612 out_string
= prefix
+ "{\n"
614 count
= unsigned(osdict
.count
)
617 out_string
+= prefix
+ " " + GetObjectSummary(osdict
.dictionary
[idx
].key
) + " = " + GetObjectSummary(osdict
.dictionary
[idx
].value
) + "\n"
619 out_string
+= prefix
+ "}\n"
622 def GetString(string
):
623 """ Returns the python string representation of a given OSString
625 out_string
= "\"{0:s}\"".format(CastIOKitClass(string
, 'OSString *').string
)
629 out_string
= "{0:d}".format(CastIOKitClass(num
, 'OSNumber *').value
)
633 """ Shows info about a given OSBoolean
636 if b
== kern
.globals.gOSBooleanFalse
:
642 def GetMetaClass(mc
):
643 """ Shows info about a given OSSymbol
645 out_string
= "{0: <5d}x {1: >5d} bytes {2:s}\n".format(mc
.instanceCount
, mc
.classSize
, mc
.className
.string
)
649 """ Returns a string containing info about a given OSArray
653 count
= unsigned(arr
.count
)
658 out_string
+= GetObjectSummary(obj
)
659 if idx
< unsigned(arr
.count
):
663 def GetDictionary(d
):
664 """ Returns a string containing info about a given OSDictionary
668 count
= unsigned(d
.count
)
671 obj
= d
.dictionary
[idx
].key
672 out_string
+= GetObjectSummary(obj
) + "="
673 obj
= d
.dictionary
[idx
].value
675 out_string
+= GetObjectSummary(obj
)
682 """ Returns a string containing info about a given OSSet
684 out_string
+= "[" + GetArray(se
.members
) + "]"
687 def ReadIOPortInt(addr
, numbytes
, lcpu
):
688 """ Prints results after reading a given ioport
692 if "kdp" != GetConnectionProtocol():
693 print "Target is not connected over kdp. Nothing to do here."
696 # Set up the manual KDP packet
697 input_address
= unsigned(addressof(kern
.globals.manual_pkt
.input))
698 len_address
= unsigned(addressof(kern
.globals.manual_pkt
.len))
699 data_address
= unsigned(addressof(kern
.globals.manual_pkt
.data
))
700 if not WriteInt32ToMemoryAddress(0, input_address
):
701 print "0x{0: <4x}: 0x{1: <1x}".format(addr
, result
)
704 kdp_pkt_size
= GetType('kdp_readioport_req_t').GetByteSize()
705 if not WriteInt32ToMemoryAddress(kdp_pkt_size
, len_address
):
706 print "0x{0: <4x}: 0x{1: <1x}".format(addr
, result
)
709 kgm_pkt
= kern
.GetValueFromAddress(data_address
, 'kdp_readioport_req_t *')
711 header_value
= GetKDPPacketHeaderInt(request
=GetEnumValue('kdp_req_t::KDP_READIOPORT'), length
= kdp_pkt_size
)
713 if( WriteInt64ToMemoryAddress((header_value
), int(addressof(kgm_pkt
.hdr
))) and
714 WriteInt16ToMemoryAddress(addr
, int(addressof(kgm_pkt
.address
))) and
715 WriteInt32ToMemoryAddress(numbytes
, int(addressof(kgm_pkt
.nbytes
))) and
716 WriteInt16ToMemoryAddress(lcpu
, int(addressof(kgm_pkt
.lcpu
))) and
717 WriteInt32ToMemoryAddress(1, input_address
)
720 result_pkt
= Cast(addressof(kern
.globals.manual_pkt
.data
), 'kdp_readioport_reply_t *')
722 if(result_pkt
.error
== 0):
724 result
= dereference(Cast(addressof(result_pkt
.data
), 'uint8_t *'))
726 result
= dereference(Cast(addressof(result_pkt
.data
), 'uint16_t *'))
728 result
= dereference(Cast(addressof(result_pkt
.data
), 'uint32_t *'))
730 print "{0: <#6x}: {1:#0{2}x}".format(addr
, result
, (numbytes
*2)+2)
732 def WriteIOPortInt(addr
, numbytes
, value
, lcpu
):
733 """ Writes 'value' into ioport specified by 'addr'. Prints errors if it encounters any
735 if "kdp" != GetConnectionProtocol():
736 print "Target is not connected over kdp. Nothing to do here."
739 # Set up the manual KDP packet
740 input_address
= unsigned(addressof(kern
.globals.manual_pkt
.input))
741 len_address
= unsigned(addressof(kern
.globals.manual_pkt
.len))
742 data_address
= unsigned(addressof(kern
.globals.manual_pkt
.data
))
743 if not WriteInt32ToMemoryAddress(0, input_address
):
744 print "error writing {0: #x} to port {1: <#6x}: failed to write 0 to input_address".format(value
, addr
)
747 kdp_pkt_size
= GetType('kdp_writeioport_req_t').GetByteSize()
748 if not WriteInt32ToMemoryAddress(kdp_pkt_size
, len_address
):
749 print "error writing {0: #x} to port {1: <#6x}: failed to write kdp_pkt_size".format(value
, addr
)
752 kgm_pkt
= kern
.GetValueFromAddress(data_address
, 'kdp_writeioport_req_t *')
754 header_value
= GetKDPPacketHeaderInt(request
=GetEnumValue('kdp_req_t::KDP_WRITEIOPORT'), length
= kdp_pkt_size
)
756 if( WriteInt64ToMemoryAddress((header_value
), int(addressof(kgm_pkt
.hdr
))) and
757 WriteInt16ToMemoryAddress(addr
, int(addressof(kgm_pkt
.address
))) and
758 WriteInt32ToMemoryAddress(numbytes
, int(addressof(kgm_pkt
.nbytes
))) and
759 WriteInt16ToMemoryAddress(lcpu
, int(addressof(kgm_pkt
.lcpu
)))
762 if not WriteInt8ToMemoryAddress(value
, int(addressof(kgm_pkt
.data
))):
763 print "error writing {0: #x} to port {1: <#6x}: failed to write 8 bit data".format(value
, addr
)
766 if not WriteInt16ToMemoryAddress(value
, int(addressof(kgm_pkt
.data
))):
767 print "error writing {0: #x} to port {1: <#6x}: failed to write 16 bit data".format(value
, addr
)
770 if not WriteInt32ToMemoryAddress(value
, int(addressof(kgm_pkt
.data
))):
771 print "error writing {0: #x} to port {1: <#6x}: failed to write 32 bit data".format(value
, addr
)
773 if not WriteInt32ToMemoryAddress(1, input_address
):
774 print "error writing {0: #x} to port {1: <#6x}: failed to write to input_address".format(value
, addr
)
777 result_pkt
= Cast(addressof(kern
.globals.manual_pkt
.data
), 'kdp_writeioport_reply_t *')
779 # Done with the write
780 if(result_pkt
.error
== 0):
781 print "Writing {0: #x} to port {1: <#6x} was successful".format(value
, addr
)
783 print "error writing {0: #x} to port {1: <#6x}".format(value
, addr
)
785 @lldb_command('showinterruptcounts')
786 def showinterruptcounts(cmd_args
=None):
787 """ Shows event source based interrupt counts by nub name and interrupt index.
788 Does not cover interrupts that are not event source based. Will report 0
789 if interrupt accounting is disabled.
792 header_format
= "{0: <20s} {1: >5s} {2: >20s}"
793 content_format
= "{0: <20s} {1: >5d} {2: >20d}"
795 print header_format
.format("Name", "Index", "Count")
797 for i
in kern
.interrupt_stats
:
798 owner
= CastIOKitClass(i
.owner
, 'IOInterruptEventSource *')
799 nub
= CastIOKitClass(owner
.provider
, 'IORegistryEntry *')
802 # To uniquely identify an interrupt, we need the nub name and the index. The index
803 # is stored with the stats object, but we need to retrieve the name.
805 registryTable
= nub
.fRegistryTable
806 propertyTable
= nub
.fPropertyTable
808 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
810 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
812 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
817 nub_name
= GetString(CastIOKitClass(name
, 'OSString *'))
819 # We now have everything we need; spew the requested data.
821 interrupt_index
= i
.interruptIndex
822 first_level_count
= i
.interruptStatistics
[0]
824 print content_format
.format(nub_name
, interrupt_index
, first_level_count
)
828 @lldb_command('showinterruptstats')
829 def showinterruptstats(cmd_args
=None):
830 """ Shows event source based interrupt statistics by nub name and interrupt index.
831 Does not cover interrupts that are not event source based. Will report 0
832 if interrupt accounting is disabled, or if specific statistics are disabled.
833 Time is reported in ticks of mach_absolute_time. Statistics are:
835 Interrupt Count: Number of times the interrupt context handler was run
836 Interrupt Time: Total time spent in the interrupt context handler (if any)
837 Workloop Count: Number of times the kernel context handler was run
838 Workloop CPU Time: Total CPU time spent running the kernel context handler
839 Workloop Time: Total time spent running the kernel context handler
842 header_format
= "{0: <20s} {1: >5s} {2: >20s} {3: >20s} {4: >20s} {5: >20s} {6: >20s}"
843 content_format
= "{0: <20s} {1: >5d} {2: >20d} {3: >20d} {4: >20d} {5: >20d} {6: >20d}"
845 print header_format
.format("Name", "Index", "Interrupt Count", "Interrupt Time", "Workloop Count", "Workloop CPU Time", "Workloop Time")
847 for i
in kern
.interrupt_stats
:
848 owner
= CastIOKitClass(i
.owner
, 'IOInterruptEventSource *')
849 nub
= CastIOKitClass(owner
.provider
, 'IORegistryEntry *')
852 # To uniquely identify an interrupt, we need the nub name and the index. The index
853 # is stored with the stats object, but we need to retrieve the name.
855 registryTable
= nub
.fRegistryTable
856 propertyTable
= nub
.fPropertyTable
858 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
860 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
862 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
867 nub_name
= GetString(CastIOKitClass(name
, 'OSString *'))
869 # We now have everything we need; spew the requested data.
871 interrupt_index
= i
.interruptIndex
872 first_level_count
= i
.interruptStatistics
[0]
873 second_level_count
= i
.interruptStatistics
[1]
874 first_level_time
= i
.interruptStatistics
[2]
875 second_level_cpu_time
= i
.interruptStatistics
[3]
876 second_level_system_time
= i
.interruptStatistics
[4]
878 print content_format
.format(nub_name
, interrupt_index
, first_level_count
, first_level_time
, second_level_count
, second_level_cpu_time
, second_level_system_time
)