4 from core
import caching
6 from collections
import deque
8 ######################################
10 ######################################
13 #####################################
15 #####################################
16 def CastIOKitClass(obj
, target_type
):
17 """ Type cast an object to another IOKIT CPP class.
19 obj - core.value object representing some C construct in lldb
20 target_type - str : ex 'OSString *'
23 v
= Cast(obj
, target_type
)
24 v
.GetSBValue().SetPreferDynamicValue(lldb
.eNoDynamicValues
)
27 ######################################
29 ######################################
30 @lldb_type_summary(['OSObject *'])
32 def GetObjectSummary(obj
):
33 """ Show info about an OSObject - its vtable ptr and retain count, & more info for simple container classes.
38 vt
= dereference(Cast(obj
, 'uintptr_t *')) - 2 * sizeof('uintptr_t')
39 vt
= kern
.StripKernelPAC(vt
)
40 vtype
= kern
.SymbolicateFromAddress(vt
)
42 vtype_str
= " <" + vtype
[0].GetName() + ">"
45 if hasattr(obj
, 'retainCount'):
46 retCount
= (obj
.retainCount
& 0xffff)
47 cntnrRetCount
= (obj
.retainCount
>> 16)
48 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
)
50 out_string
= "`object 0x{0: <16x}, vt 0x{1: <16x}{2:s}` ".format(obj
, vt
, vtype_str
)
52 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV8OSString')
54 out_string
+= GetString(obj
)
57 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV8OSSymbol')
59 out_string
+= GetString(obj
)
62 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV8OSNumber')
64 out_string
+= GetNumber(obj
)
67 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV9OSBoolean')
69 out_string
+= GetBoolean(obj
)
72 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV7OSArray')
74 out_string
+= "(" + GetArray(CastIOKitClass(obj
, 'OSArray *')) + ")"
77 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV5OSSet')
79 out_string
+= GetSet(CastIOKitClass(obj
, 'OSSet *'))
82 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV12OSDictionary')
84 out_string
+= GetDictionary(CastIOKitClass(obj
, 'OSDictionary *'))
90 def GetObjectTypeStr(obj
):
91 """ Return the type of an OSObject's container class
96 vt
= dereference(Cast(obj
, 'uintptr_t *')) - 2 * sizeof('uintptr_t')
97 vt
= kern
.StripKernelPAC(vt
)
98 vtype
= kern
.SymbolicateFromAddress(vt
)
100 return vtype
[0].GetName()
102 # See if the value is in a kext with no symbols
103 for kval
in IterateLinkedList(kern
.globals.kmod
, 'next'):
104 if vt
>= unsigned(kval
.address
) and vt
<= (unsigned(kval
.address
) + unsigned(kval
.size
)):
105 return "kmod:{:s}+{:#0x}".format(kval
.name
, vt
- unsigned(kval
.address
))
109 @lldb_type_summary(['IORegistryEntry *'])
111 def GetRegistryEntrySummary(entry
):
112 """ returns a string containing summary information about an IORegistry
113 object including it's registry id , vtable ptr and retain count
117 registryTable
= entry
.fRegistryTable
118 propertyTable
= entry
.fPropertyTable
120 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
122 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
124 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
127 out_string
+= "+-o {0:s} ".format(GetString(CastIOKitClass(name
, 'OSString *')))
128 elif CastIOKitClass(entry
, 'IOService *').pwrMgt
and CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
:
129 out_string
+= "+-o {0:s} ".format(CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
)
131 out_string
+= "+-o ?? "
133 # I'm using uintptr_t for now to work around <rdar://problem/12749733> FindFirstType & Co. should allow you to make pointer types directly
134 vtableAddr
= dereference(Cast(entry
, 'uintptr_t *')) - 2 * sizeof('uintptr_t *')
135 vtableAddr
= kern
.StripKernelPAC(vtableAddr
)
136 vtype
= kern
.SymbolicateFromAddress(vtableAddr
)
137 if vtype
is None or len(vtype
) < 1:
138 out_string
+= "<object 0x{0: <16x}, id 0x{1:x}, vtable 0x{2: <16x}".format(entry
, CastIOKitClass(entry
, 'IORegistryEntry *').reserved
.fRegistryEntryID
, vtableAddr
)
140 out_string
+= "<object 0x{0: <16x}, id 0x{1:x}, vtable 0x{2: <16x} <{3:s}>".format(entry
, CastIOKitClass(entry
, 'IORegistryEntry *').reserved
.fRegistryEntryID
,
141 vtableAddr
, vtype
[0].GetName())
143 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV15IORegistryEntry')
144 if vtableAddr
!= ztvAddr
:
146 state
= CastIOKitClass(entry
, 'IOService *').__state
[0]
147 # kIOServiceRegisteredState
150 out_string
+= "registered, "
151 # kIOServiceMatchedState
154 out_string
+= "matched, "
155 #kIOServiceInactiveState
158 busyCount
= (CastIOKitClass(entry
, 'IOService *').__state
[1] & 0xff)
159 retCount
= (CastIOKitClass(entry
, 'IOService *').retainCount
& 0xffff)
160 out_string
+= "active, busy {0}, retain count {1}>".format(busyCount
, retCount
)
163 ######################################
165 ######################################
166 @lldb_command('showallclasses')
167 def ShowAllClasses(cmd_args
=None):
168 """ Show the instance counts and ivar size of all OSObject subclasses.
169 See ioclasscount man page for details
172 count
= unsigned(kern
.globals.sAllClassesDict
.count
)
175 meta
= CastIOKitClass(kern
.globals.sAllClassesDict
.dictionary
[idx
].value
, 'OSMetaClass *')
177 print GetMetaClass(meta
)
179 @lldb_command('showobject')
180 def ShowObject(cmd_args
=None):
181 """ Show info about an OSObject - its vtable ptr and retain count, & more info for simple container classes.
184 print "Please specify the address of the OSObject whose info you want to view. Type help showobject for help"
187 obj
= kern
.GetValueFromAddress(cmd_args
[0], 'OSObject *')
188 print GetObjectSummary(obj
)
191 @lldb_command('dumpobject')
192 def DumpObject(cmd_args
=None):
193 """ Dumps object information if it is a valid object confirmed by showobject
194 Usage: dumpobject <address of object to be dumped> [class/struct type of object]
197 print "No arguments passed"
198 print DumpObject
.__doc
__
201 if len(cmd_args
) == 1:
203 object_info
= lldb_run_command("showobject {:s}".format(cmd_args
[0]))
205 print "Error!! showobject failed due to invalid value"
206 print DumpObject
.__doc
__
209 srch
= re
.search(r
'<vtable for ([A-Za-z].*)>', object_info
)
211 print "Error!! Couldn't find object in registry, input type manually as 2nd argument"
212 print DumpObject
.__doc
__
215 object_type
= srch
.group(1)
217 type_lookup
= lldb_run_command("image lookup -t {:s}".format(cmd_args
[1]))
218 if type_lookup
.find(cmd_args
[1])!= -1:
219 object_type
= cmd_args
[1]
221 print "Error!! Input type {:s} isn't available in image lookup".format(cmd_args
[1])
224 print "******** Object Dump for value \'{:s}\' with type \"{:s}\" ********".format(cmd_args
[0], object_type
)
225 print lldb_run_command("p/x *({:s}*){:s}".format(object_type
, cmd_args
[0]))
227 #EndMacro: dumpobject
229 @lldb_command('setregistryplane')
230 def SetRegistryPlane(cmd_args
=None):
231 """ Set the plane to be used for the IOKit registry macros
232 syntax: (lldb) setregistryplane 0 - will display all known planes
233 syntax: (lldb) setregistryplane 0xaddr - will set the registry plane to 0xaddr
234 syntax: (lldb) setregistryplane gIODTPlane - will set the registry plane to gIODTPlane
237 print "Please specify the name of the plane you want to use with the IOKit registry macros."
238 print SetRegistryPlane
.__doc
__
240 if cmd_args
[0] == "0":
241 print GetObjectSummary(kern
.globals.gIORegistryPlanes
)
244 plane
= kern
.GetValueFromAddress(cmd_args
[0], 'IORegistryPlane *')
247 @lldb_command('showregistryentry')
248 def ShowRegistryEntry(cmd_args
=None):
249 """ Show info about a registry entry; its properties and descendants in the current plane
250 syntax: (lldb) showregistryentry 0xaddr
251 syntax: (lldb) showregistryentry gIOPMRootDomain
254 print "Please specify the address of the registry entry whose info you want to view."
255 print ShowRegistryEntry
.__doc
__
258 entry
= kern
.GetValueFromAddress(cmd_args
[0], 'IORegistryEntry *')
259 ShowRegistryEntryRecurse(entry
, "", True)
261 @lldb_command('showregistry')
262 def ShowRegistry(cmd_args
=None):
263 """ Show info about all registry entries in the current plane
264 If prior to invoking this command no registry plane is specified
265 using 'setregistryplane', the command defaults to the IOService plane
267 ShowRegistryEntryRecurse(kern
.globals.gRegistryRoot
, "", False)
269 @lldb_command('showregistryprops')
270 def ShowRegistryProps(cmd_args
=None):
271 """ Show info about all registry entries in the current plane, and their properties
272 If prior to invoking this command no registry plane is specified
273 using 'setregistryplane', the command defaults to the IOService plane
275 ShowRegistryEntryRecurse(kern
.globals.gRegistryRoot
, "", True)
277 @lldb_command('findregistryentry')
278 def FindRegistryEntry(cmd_args
=None):
279 """ Search for registry entry that matches the given string
280 If prior to invoking this command no registry plane is specified
281 using 'setregistryplane', the command defaults to searching entries from the IOService plane
282 syntax: (lldb) findregistryentries AppleACPICPU - will find the first registry entry that matches AppleACPICPU
285 print "Please specify the name of the registry entry you want to find"
286 print FindRegistryEntry
.__doc
__
289 FindRegistryEntryRecurse(kern
.globals.gRegistryRoot
, cmd_args
[0], True)
291 @lldb_command('findregistryentries')
292 def FindRegistryEntries(cmd_args
=None):
293 """ Search for all registry entries that match the given string
294 If prior to invoking this command no registry plane is specified
295 using 'setregistryplane', the command defaults to searching entries from the IOService plane
296 syntax: (lldb) findregistryentries AppleACPICPU - will find all registry entries that match AppleACPICPU
299 print "Please specify the name of the registry entry/entries you want to find"
300 print FindRegistryEntries
.__doc
__
303 FindRegistryEntryRecurse(kern
.globals.gRegistryRoot
, cmd_args
[0], False)
305 @lldb_command('findregistryprop')
306 def FindRegistryProp(cmd_args
=None):
307 """ Given a registry entry, print out the contents for the property that matches
309 syntax: (lldb) findregistryprop 0xaddr IOSleepSupported
310 syntax: (lldb) findregistryprop gIOPMRootDomain IOSleepSupported
311 syntax: (lldb) findregistryprop gIOPMRootDomain "Supported Features"
313 if not cmd_args
or len(cmd_args
) < 2:
314 print "Please specify the address of a IORegistry entry and the property you're looking for"
315 print FindRegistryProp
.__doc
__
318 entry
= kern
.GetValueFromAddress(cmd_args
[0], 'IOService *')
319 propertyTable
= entry
.fPropertyTable
320 print GetObjectSummary(LookupKeyInPropTable(propertyTable
, cmd_args
[1]))
322 @lldb_command('readioport8')
323 def ReadIOPort8(cmd_args
=None):
324 """ Read value stored in the specified IO port. The CPU can be optionally
326 Prints 0xBAD10AD in case of a bad read
327 Syntax: (lldb) readioport8 <port> [lcpu (kernel's numbering convention)]
330 print "Please specify a port to read out of"
331 print ReadIOPort8
.__doc__
334 portAddr
= ArgumentStringToInt(cmd_args
[0])
335 if len(cmd_args
) >= 2:
336 lcpu
= ArgumentStringToInt(cmd_args
[1])
338 lcpu
= xnudefines
.lcpu_self
340 ReadIOPortInt(portAddr
, 1, lcpu
)
342 @lldb_command('readioport16')
343 def ReadIOPort16(cmd_args
=None):
344 """ Read value stored in the specified IO port. The CPU can be optionally
346 Prints 0xBAD10AD in case of a bad read
347 Syntax: (lldb) readioport16 <port> [lcpu (kernel's numbering convention)]
350 print "Please specify a port to read out of"
351 print ReadIOPort16
.__doc__
354 portAddr
= ArgumentStringToInt(cmd_args
[0])
355 if len(cmd_args
) >= 2:
356 lcpu
= ArgumentStringToInt(cmd_args
[1])
358 lcpu
= xnudefines
.lcpu_self
360 ReadIOPortInt(portAddr
, 2, lcpu
)
362 @lldb_command('readioport32')
363 def ReadIOPort32(cmd_args
=None):
364 """ Read value stored in the specified IO port. The CPU can be optionally
366 Prints 0xBAD10AD in case of a bad read
367 Syntax: (lldb) readioport32 <port> [lcpu (kernel's numbering convention)]
370 print "Please specify a port to read out of"
371 print ReadIOPort32
.__doc__
374 portAddr
= ArgumentStringToInt(cmd_args
[0])
375 if len(cmd_args
) >= 2:
376 lcpu
= ArgumentStringToInt(cmd_args
[1])
378 lcpu
= xnudefines
.lcpu_self
380 ReadIOPortInt(portAddr
, 4, lcpu
)
382 @lldb_command('writeioport8')
383 def WriteIOPort8(cmd_args
=None):
384 """ Write the value to the specified IO port. The size of the value is
385 determined by the name of the command. The CPU used can be optionally
387 Syntax: (lldb) writeioport8 <port> <value> [lcpu (kernel's numbering convention)]
389 if not cmd_args
or len(cmd_args
) < 2:
390 print "Please specify a port to write to, followed by the value you want to write"
391 print WriteIOPort8
.__doc__
394 portAddr
= ArgumentStringToInt(cmd_args
[0])
395 value
= ArgumentStringToInt(cmd_args
[1])
397 if len(cmd_args
) >= 3:
398 lcpu
= ArgumentStringToInt(cmd_args
[2])
400 lcpu
= xnudefines
.lcpu_self
402 WriteIOPortInt(portAddr
, 1, value
, lcpu
)
404 @lldb_command('writeioport16')
405 def WriteIOPort16(cmd_args
=None):
406 """ Write the value to the specified IO port. The size of the value is
407 determined by the name of the command. The CPU used can be optionally
409 Syntax: (lldb) writeioport16 <port> <value> [lcpu (kernel's numbering convention)]
411 if not cmd_args
or len(cmd_args
) < 2:
412 print "Please specify a port to write to, followed by the value you want to write"
413 print WriteIOPort16
.__doc__
416 portAddr
= ArgumentStringToInt(cmd_args
[0])
417 value
= ArgumentStringToInt(cmd_args
[1])
419 if len(cmd_args
) >= 3:
420 lcpu
= ArgumentStringToInt(cmd_args
[2])
422 lcpu
= xnudefines
.lcpu_self
424 WriteIOPortInt(portAddr
, 2, value
, lcpu
)
426 @lldb_command('writeioport32')
427 def WriteIOPort32(cmd_args
=None):
428 """ Write the value to the specified IO port. The size of the value is
429 determined by the name of the command. The CPU used can be optionally
431 Syntax: (lldb) writeioport32 <port> <value> [lcpu (kernel's numbering convention)]
433 if not cmd_args
or len(cmd_args
) < 2:
434 print "Please specify a port to write to, followed by the value you want to write"
435 print WriteIOPort32
.__doc__
438 portAddr
= ArgumentStringToInt(cmd_args
[0])
439 value
= ArgumentStringToInt(cmd_args
[1])
441 if len(cmd_args
) >= 3:
442 lcpu
= ArgumentStringToInt(cmd_args
[2])
444 lcpu
= xnudefines
.lcpu_self
446 WriteIOPortInt(portAddr
, 4, value
, lcpu
)
448 @lldb_command('showioservicepm')
449 def ShowIOServicePM(cmd_args
=None):
450 """ Routine to dump the IOServicePM object
451 Syntax: (lldb) showioservicepm <IOServicePM pointer>
454 print "Please enter the pointer to the IOServicePM object you'd like to introspect"
455 print ShowIOServicePM
.__doc
__
458 iopmpriv
= kern
.GetValueFromAddress(cmd_args
[0], 'IOServicePM *')
459 out_string
= "MachineState {0: <6d} (".format(iopmpriv
.MachineState
)
464 1: 'kIOPM_OurChangeTellClientsPowerDown',
465 2: 'kIOPM_OurChangeTellClientsPowerDown',
466 3: 'kIOPM_OurChangeNotifyInterestedDriversWillChange',
467 4: 'kIOPM_OurChangeSetPowerState',
468 5: 'kIOPM_OurChangeWaitForPowerSettle',
469 6: 'kIOPM_OurChangeNotifyInterestedDriversDidChange',
470 7: 'kIOPM_OurChangeTellCapabilityDidChange',
471 8: 'kIOPM_OurChangeFinish',
472 9: 'Unused_MachineState_9',
473 10: 'kIOPM_ParentChangeTellPriorityClientsPowerDown',
474 11: 'kIOPM_ParentChangeNotifyInterestedDriversWillChange',
475 12: 'kIOPM_ParentChangeSetPowerState',
476 13: 'kIOPM_ParentChangeWaitForPowerSettle',
477 14: 'kIOPM_ParentChangeNotifyInterestedDriversDidChange',
478 15: 'kIOPM_ParentChangeTellCapabilityDidChange',
479 16: 'kIOPM_ParentChangeAcknowledgePowerChange',
480 17: 'kIOPM_NotifyChildrenStart',
481 18: 'kIOPM_NotifyChildrenOrdered',
482 19: 'kIOPM_NotifyChildrenDelayed',
483 20: 'kIOPM_SyncTellClientsPowerDown',
484 21: 'kIOPM_SyncTellPriorityClientsPowerDown',
485 22: 'kIOPM_SyncNotifyWillChange',
486 23: 'kIOPM_SyncNotifyDidChange',
487 24: 'kIOPM_SyncTellCapabilityDidChange',
488 25: 'kIOPM_SyncFinish',
489 26: 'kIOPM_TellCapabilityChangeDone',
490 27: 'kIOPM_DriverThreadCallDone'
492 powerstate
= unsigned(iopmpriv
.MachineState
)
493 if powerstate
in pstate_map
:
494 out_string
+= "{0:s}".format(pstate_map
[powerstate
])
496 out_string
+= "Unknown_MachineState"
499 if iopmpriv
.MachineState
!= 20:
500 out_string
+= "DriverTimer = {0: <6d}, SettleTime = {1: < 6d}, HeadNoteFlags = {2: #12x}, HeadNotePendingAcks = {3: #012x}, ".format(
501 unsigned(iopmpriv
.DriverTimer
),
502 unsigned(iopmpriv
.SettleTimeUS
),
503 unsigned(iopmpriv
.HeadNoteChangeFlags
),
504 unsigned(iopmpriv
.HeadNotePendingAcks
))
506 if iopmpriv
.DeviceOverrideEnabled
!= 0:
507 out_string
+= "DeviceOverrides, "
509 out_string
+= "DeviceDesire = {0: <6d}, DesiredPowerState = {1: <6d}, PreviousRequest = {2: <6d}\n".format(
510 unsigned(iopmpriv
.DeviceDesire
),
511 unsigned(iopmpriv
.DesiredPowerState
),
512 unsigned(iopmpriv
.PreviousRequestPowerFlags
))
517 @lldb_command("showinterruptvectors")
518 def ShowInterruptVectorInfo(cmd_args
=None):
520 Shows interrupt vectors.
524 kInterruptTriggerModeMask
= 0x01
525 kInterruptTriggerModeEdge
= 0x00
526 kInterruptTriggerModeLevel
= kInterruptTriggerModeMask
527 kInterruptPolarityMask
= 0x02
528 kInterruptPolarityHigh
= 0x00
529 kInterruptPolarityLow
= kInterruptPolarityMask
530 kInterruptShareableMask
= 0x04
531 kInterruptNotShareable
= 0x00
532 kInterruptIsShareable
= kInterruptShareableMask
533 kIOInterruptTypePCIMessaged
= 0x00010000
535 # Get all interrupt controllers
536 interrupt_controllers
= list(SearchInterruptControllerDrivers())
538 print("Interrupt controllers: ")
539 for ic
in interrupt_controllers
:
540 print(" {}".format(ic
))
543 # Iterate over all entries in the registry
544 for entry
in GetMatchingEntries(lambda _
: True):
545 # Get the name of the entry
546 entry_name
= GetRegistryEntryName(entry
)
548 # Get the location of the entry
549 entry_location
= GetRegistryEntryLocationInPlane(entry
, kern
.globals.gIOServicePlane
)
550 if entry_location
is None:
553 entry_location
= "@" + entry_location
555 # Get the interrupt properties
556 (msi_mode
, vectorDataList
, vectorContList
) = GetRegistryEntryInterruptProperties(entry
)
559 for (vector_data
, vector_cont
) in zip(vectorDataList
, vectorContList
):
560 # vector_cont is the name of the interrupt controller. Find the matching controller from
561 # the list of controllers obtained earlier
562 matching_ics
= filter(lambda ic
: ic
.name
== vector_cont
, interrupt_controllers
)
564 if len(matching_ics
) > 0:
566 # Take the first match
567 matchingIC
= matching_ics
[0]
569 # Use the vector_data to determine the vector and any flags
570 data_ptr
= vector_data
.data
571 data_length
= vector_data
.length
573 # Dereference vector_data as a uint32_t * and add the base vector number
574 gsi
= unsigned(dereference(Cast(data_ptr
, 'uint32_t *')))
575 gsi
+= matchingIC
.base_vector_number
577 # If data_length is >= 8 then vector_data contains interrupt flags
579 # Add sizeof(uint32_t) to data_ptr to get the flags pointer
580 flags_ptr
= kern
.GetValueFromAddress(unsigned(data_ptr
) + sizeof("uint32_t"))
581 flags
= unsigned(dereference(Cast(flags_ptr
, 'uint32_t *')))
582 out_str
+= " +----- [Interrupt Controller {ic}] vector {gsi}, {trigger_level}, {active}, {shareable}{messaged}\n" \
583 .format(ic
=matchingIC
.name
, gsi
=hex(gsi
),
584 trigger_level
="level trigger" if flags
& kInterruptTriggerModeLevel
else "edge trigger",
585 active
="active low" if flags
& kInterruptPolarityLow
else "active high",
586 shareable
="shareable" if flags
& kInterruptIsShareable
else "exclusive",
587 messaged
=", messaged" if flags
& kIOInterruptTypePCIMessaged
else "")
589 out_str
+= " +----- [Interrupt Controller {ic}] vector {gsi}\n".format(ic
=matchingIC
.name
, gsi
=hex(gsi
))
591 print("[ {entry_name}{entry_location} ]{msi_mode}\n{out_str}" \
592 .format(entry_name
=entry_name
,
593 entry_location
=entry_location
,
594 msi_mode
=" - MSIs enabled" if msi_mode
else "",
597 @lldb_command("showiokitclasshierarchy")
598 def ShowIOKitClassHierarchy(cmd_args
=None):
600 Show class hierarchy for a IOKit class
603 print("Usage: showiokitclasshierarchy <IOKit class name>")
606 class_name
= cmd_args
[0]
607 metaclasses
= GetMetaClasses()
608 if class_name
not in metaclasses
:
609 print("Class {} does not exist".format(class_name
))
611 metaclass
= metaclasses
[class_name
]
613 # loop over superclasses
615 current_metaclass
= metaclass
616 while current_metaclass
is not None:
617 hierarchy
.insert(0, current_metaclass
)
618 current_metaclass
= current_metaclass
.superclass()
620 for (index
, mc
) in enumerate(hierarchy
):
621 indent
= (" " * index
) + "+---"
622 print("{}[ {} ] {}".format(indent
, str(mc
.className()), str(mc
.data())))
627 ######################################
629 ######################################
630 def ShowRegistryEntryRecurse(entry
, prefix
, printProps
):
631 """ prints registry entry summary and recurses through all its children.
636 plen
= (len(prefix
)//2)
637 registryTable
= entry
.fRegistryTable
638 propertyTable
= entry
.fPropertyTable
640 # Print entry details
641 print "{0:s}{1:s}".format(prefix
, GetRegistryEntrySummary(entry
))
642 # Printing large property tables make it look like lldb is 'stuck'
644 print GetRegDictionary(propertyTable
, prefix
+ " | ")
648 childKey
= kern
.globals.gIOServicePlane
.keys
[1]
650 childKey
= plane
.keys
[1]
651 childArray
= LookupKeyInOSDict(registryTable
, childKey
)
652 if childArray
is not None:
654 ca
= CastIOKitClass(childArray
, 'OSArray *')
655 count
= unsigned(ca
.count
)
657 if plen
!= 0 and plen
!= 1 and (plen
& (plen
- 1)) == 0:
658 ShowRegistryEntryRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), prefix
+ "| ", printProps
)
660 ShowRegistryEntryRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), prefix
+ " ", printProps
)
663 def FindRegistryEntryRecurse(entry
, search_name
, stopAfterFirst
):
664 """ Checks if given registry entry's name matches the search_name we're looking for
665 If yes, it prints the entry's summary and then recurses through its children
666 If no, it does nothing and recurses through its children
670 registryTable
= entry
.fRegistryTable
671 propertyTable
= entry
.fPropertyTable
675 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
677 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
679 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
682 if str(CastIOKitClass(name
, 'OSString *').string
) == search_name
:
683 print GetRegistryEntrySummary(entry
)
684 if stopAfterFirst
is True:
686 elif CastIOKitClass(entry
, 'IOService *').pwrMgt
and CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
:
687 name
= CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
688 if str(name
) == search_name
:
689 print GetRegistryEntrySummary(entry
)
690 if stopAfterFirst
is True:
695 childKey
= kern
.globals.gIOServicePlane
.keys
[1]
697 childKey
= plane
.keys
[1]
698 childArray
= LookupKeyInOSDict(registryTable
, childKey
)
699 if childArray
is not None:
701 ca
= CastIOKitClass(childArray
, 'OSArray *')
702 count
= unsigned(ca
.count
)
704 if FindRegistryEntryRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), search_name
, stopAfterFirst
) is True:
709 def FindRegistryObjectRecurse(entry
, search_name
):
710 """ Checks if given registry entry's name matches the search_name we're looking for
711 If yes, return the entry
712 If no, it does nothing and recurses through its children
713 Implicitly stops after finding the first entry
717 registryTable
= entry
.fRegistryTable
718 propertyTable
= entry
.fPropertyTable
722 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
724 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
726 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
729 if str(CastIOKitClass(name
, 'OSString *').string
) == search_name
:
731 elif CastIOKitClass(entry
, 'IOService *').pwrMgt
and CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
:
732 name
= CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
733 if str(name
) == search_name
:
738 childKey
= kern
.globals.gIOServicePlane
.keys
[1]
740 childKey
= plane
.keys
[1]
741 childArray
= LookupKeyInOSDict(registryTable
, childKey
)
742 if childArray
is not None:
743 ca
= CastIOKitClass(childArray
, 'OSArray *')
744 for idx
in range(ca
.count
):
745 registry_object
= FindRegistryObjectRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), search_name
)
746 if not registry_object
or int(registry_object
) == int(0):
749 return registry_object
753 class IOKitMetaClass(object):
755 A class that represents a IOKit metaclass. This is used to represent the
756 IOKit inheritance hierarchy.
759 def __init__(self
, meta
):
761 Initialize a IOKitMetaClass object.
764 meta (core.cvalue.value): A LLDB value representing a
768 self
._superclass
= None
773 def setSuperclass(self
, superclass
):
775 Set the superclass for this metaclass.
778 superclass (core.cvalue.value): A LLDB value representing a
781 self
._superclass
= superclass
783 def superclass(self
):
785 Get the superclass for this metaclass (set by the setSuperclass method).
788 core.cvalue.value: A LLDB value representing a OSMetaClass *.
790 return self
._superclass
794 Get the name of the class this metaclass represents.
799 return self
._meta
.className
.string
801 def inheritsFrom(self
, other
):
803 Check if the class represented by this metaclass inherits from a class
804 represented by another metaclass.
807 other (IOKitMetaClass): The other metaclass
810 bool: Returns True if this class inherits from the other class and
814 while current
is not None:
818 current
= current
.superclass()
821 def GetRegistryEntryClassName(entry
):
823 Get the class name of a registry entry.
826 entry (core.cvalue.value): A LLDB value representing a
830 str: The class name of the entry or None if a class name could not be
833 # Check using IOClass key
834 result
= LookupKeyInOSDict(entry
.fPropertyTable
, kern
.globals.gIOClassKey
)
835 if result
is not None:
836 return GetString(result
).replace("\"", "")
838 # Use the vtable of the entry to determine the concrete type
839 vt
= dereference(Cast(entry
, 'uintptr_t *')) - 2 * sizeof('uintptr_t')
840 vt
= kern
.StripKernelPAC(vt
)
841 vtype
= kern
.SymbolicateFromAddress(vt
)
843 vtableName
= vtype
[0].GetName()
844 return vtableName
[11:] # strip off "vtable for "
849 def GetRegistryEntryName(entry
):
851 Get the name of a registry entry.
854 entry (core.cvalue.value): A LLDB value representing a
858 str: The name of the entry or None if a name could not be found.
862 # First check the IOService plane nameKey
863 result
= LookupKeyInOSDict(entry
.fRegistryTable
, kern
.globals.gIOServicePlane
.nameKey
)
864 if result
is not None:
865 name
= GetString(result
)
867 # Check the global IOName key
869 result
= LookupKeyInOSDict(entry
.fRegistryTable
, kern
.globals.gIONameKey
)
870 if result
is not None:
871 name
= GetString(result
)
873 # Check the IOClass key
875 result
= LookupKeyInOSDict(entry
.fPropertyTable
, kern
.globals.gIOClassKey
)
876 if result
is not None:
877 name
= GetString(result
)
879 # Remove extra quotes
881 return name
.replace("\"", "")
883 return GetRegistryEntryClassName(entry
)
886 def GetRegistryEntryLocationInPlane(entry
, plane
):
888 Get the registry entry location in a IOKit plane.
891 entry (core.cvalue.value): A LLDB value representing a
893 plane: An IOKit plane such as kern.globals.gIOServicePlane.
896 str: The location of the entry or None if a location could not be
899 # Check the plane's pathLocationKey
900 sym
= LookupKeyInOSDict(entry
.fRegistryTable
, plane
.pathLocationKey
)
902 # Check the global IOLocation key
904 sym
= LookupKeyInOSDict(entry
.fRegistryTable
, kern
.globals.gIOLocationKey
)
906 return GetString(sym
).replace("\"", "")
911 def GetMetaClasses():
913 Enumerate all IOKit metaclasses. Uses dynamic caching.
916 Dict[str, IOKitMetaClass]: A dictionary mapping each metaclass name to
917 a IOKitMetaClass object representing the metaclass.
919 METACLASS_CACHE_KEY
= "iokit_metaclasses"
920 cached_data
= caching
.GetDynamicCacheData(METACLASS_CACHE_KEY
)
922 # If we have cached data, return immediately
923 if cached_data
is not None:
926 # This method takes a while, so it prints a progress indicator
927 print("Enumerating IOKit metaclasses: ")
929 # Iterate over all classes present in sAllClassesDict
931 count
= unsigned(kern
.globals.sAllClassesDict
.count
)
932 metaclasses_by_address
= {}
934 # Print progress after every 10 items
936 print(" {} metaclass structures parsed...".format(idx
))
938 # Address of metaclass
939 address
= kern
.globals.sAllClassesDict
.dictionary
[idx
].value
941 # Create IOKitMetaClass and store in dict
942 metaclasses_by_address
[int(address
)] = IOKitMetaClass(CastIOKitClass(kern
.globals.sAllClassesDict
.dictionary
[idx
].value
, 'OSMetaClass *'))
945 print(" Enumerated {} metaclasses.".format(count
))
947 # At this point, each metaclass is independent of each other. We don't have superclass links set up yet.
949 for (address
, metaclass
) in metaclasses_by_address
.items():
950 # Get the address of the superclass using the superClassLink in IOMetaClass
951 superclass_address
= int(metaclass
.data().superClassLink
)
953 # Skip null superclass
954 if superclass_address
== 0:
957 # Find the superclass object in the dict
958 if superclass_address
in metaclasses_by_address
:
959 metaclass
.setSuperclass(metaclasses_by_address
[superclass_address
])
961 print("warning: could not find superclass for {}".format(str(metaclass
.data())))
963 # This method returns a dictionary mapping each class name to the associated metaclass object
964 metaclasses_by_name
= {}
965 for (_
, metaclass
) in metaclasses_by_address
.items():
966 metaclasses_by_name
[str(metaclass
.className())] = metaclass
968 # Save the result in the cache
969 caching
.SaveDynamicCacheData(METACLASS_CACHE_KEY
, metaclasses_by_name
)
971 return metaclasses_by_name
974 def GetMatchingEntries(matcher
):
976 Iterate over the IOKit registry and find entries that match specific
980 matcher (function): A matching function that returns True for a match
984 core.cvalue.value: LLDB values that represent IORegistryEntry * for
985 each registry entry found.
988 # Perform a BFS over the IOKit registry tree
990 bfs_queue
.append(kern
.globals.gRegistryRoot
)
991 while len(bfs_queue
) > 0:
993 entry
= bfs_queue
.popleft()
995 # Check if entry matches
999 # Find children of this entry and enqueue them
1000 child_array
= LookupKeyInOSDict(entry
.fRegistryTable
, kern
.globals.gIOServicePlane
.keys
[1])
1001 if child_array
is not None:
1003 ca
= CastIOKitClass(child_array
, 'OSArray *')
1004 count
= unsigned(ca
.count
)
1006 bfs_queue
.append(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'))
1010 def FindMatchingServices(matching_name
):
1012 Finds registry entries that match the given string. Works similarly to:
1015 IOServiceGetMatchingServices(..., IOServiceMatching(matching_name), &iter);
1016 while (( io_object_t next = IOIteratorNext(iter))) { ... }
1019 matching_name (str): The class name to search for.
1022 core.cvalue.value: LLDB values that represent IORegistryEntry * for
1023 each registry entry found.
1026 # Check if the argument is valid
1027 metaclasses
= GetMetaClasses()
1028 if matching_name
not in metaclasses
:
1030 matching_metaclass
= metaclasses
[matching_name
]
1032 # An entry matches if it inherits from matching_metaclass
1034 # Get the class name of the entry and the associated metaclass
1035 entry_name
= GetRegistryEntryClassName(entry
)
1036 if entry_name
in metaclasses
:
1037 entry_metaclass
= metaclasses
[entry_name
]
1038 return entry_metaclass
.inheritsFrom(matching_metaclass
)
1042 # Search for entries
1043 for entry
in GetMatchingEntries(matcher
):
1047 def GetRegistryEntryParent(entry
, iokit_plane
=None):
1049 Gets the parent entry of a registry entry.
1052 entry (core.cvalue.value): A LLDB value representing a
1054 iokit_plane (core.cvalue.value, optional): A LLDB value representing a
1055 IORegistryPlane *. By default, this method uses the IOService
1059 core.cvalue.value: A LLDB value representing a IORegistryEntry* that
1060 is the parent entry of the entry argument in the specified plane.
1061 Returns None if no entry could be found.
1065 if iokit_plane
is None:
1066 parent_key
= kern
.globals.gIOServicePlane
.keys
[kParentSetIndex
]
1068 parent_key
= plane
.keys
[kParentSetIndex
]
1069 parent_array
= LookupKeyInOSDict(entry
.fRegistryTable
, parent_key
)
1071 if parent_array
is not None:
1073 ca
= CastIOKitClass(parent_array
, 'OSArray *')
1074 count
= unsigned(ca
.count
)
1076 parent_entry
= CastIOKitClass(ca
.array
[0], 'IORegistryEntry *')
1080 def GetRegistryEntryInterruptProperties(entry
):
1082 Get the interrupt properties of a registry entry.
1085 entry (core.cvalue.value): A LLDB value representing a IORegistryEntry *.
1088 (bool, List[core.cvalue.value], List[str]): A tuple with the following
1090 - First field (bool): Whether this entry has a non-null
1092 - Second field (List[core.cvalue.value]): A list of LLDB values
1093 representing OSData *. The OSData* pointer points to
1094 interrupt vector data.
1095 - Third field (List[str]): A list of strings representing the
1096 interrupt controller names from the
1097 IOInterruptControllers property.
1099 INTERRUPT_SPECIFIERS_PROPERTY
= "IOInterruptSpecifiers"
1100 INTERRUPT_CONTROLLERS_PROPERTY
= "IOInterruptControllers"
1101 MSI_MODE_PROPERTY
= "IOPCIMSIMode"
1103 # Check IOInterruptSpecifiers
1104 interrupt_specifiers
= LookupKeyInPropTable(entry
.fPropertyTable
, INTERRUPT_SPECIFIERS_PROPERTY
)
1105 if interrupt_specifiers
is not None:
1106 interrupt_specifiers
= CastIOKitClass(interrupt_specifiers
, 'OSArray *')
1108 # Check IOInterruptControllers
1109 interrupt_controllers
= LookupKeyInPropTable(entry
.fPropertyTable
, INTERRUPT_CONTROLLERS_PROPERTY
)
1110 if interrupt_controllers
is not None:
1111 interrupt_controllers
= CastIOKitClass(interrupt_controllers
, 'OSArray *')
1114 msi_mode
= LookupKeyInPropTable(entry
.fPropertyTable
, MSI_MODE_PROPERTY
)
1116 result_vector_data
= []
1117 result_vector_cont
= []
1118 if interrupt_specifiers
is not None and interrupt_controllers
is not None:
1119 interrupt_specifiers_array_count
= unsigned(interrupt_specifiers
.count
)
1120 interrupt_controllers_array_count
= unsigned(interrupt_controllers
.count
)
1121 # The array lengths should be the same
1122 if interrupt_specifiers_array_count
== interrupt_controllers_array_count
and interrupt_specifiers_array_count
> 0:
1124 while idx
< interrupt_specifiers_array_count
:
1125 # IOInterruptSpecifiers is an array of OSData *
1126 vector_data
= CastIOKitClass(interrupt_specifiers
.array
[idx
], "OSData *")
1128 # IOInterruptControllers is an array of OSString *
1129 vector_cont
= GetString(interrupt_controllers
.array
[idx
])
1131 result_vector_data
.append(vector_data
)
1132 result_vector_cont
.append(vector_cont
)
1135 return (msi_mode
is not None, result_vector_data
, result_vector_cont
)
1138 class InterruptControllerDevice(object):
1139 """Represents a IOInterruptController"""
1141 def __init__(self
, device
, driver
, base_vector_number
, name
):
1143 Initialize a InterruptControllerDevice.
1146 device (core.cvalue.value): The device object.
1147 driver (core.cvalue.value): The driver object.
1148 base_vector_number (int): The base interrupt vector.
1149 name (str): The name of this interrupt controller.
1152 Use the factory method makeInterruptControllerDevice to validate
1155 self
.device
= device
1156 self
.driver
= driver
1158 self
.base_vector_number
= base_vector_number
1163 String representation of this InterruptControllerDevice.
1165 return " Name {}, base vector = {}, device = {}, driver = {}".format(
1166 self
.name
, hex(self
.base_vector_number
), str(self
.device
), str(self
.driver
))
1169 def makeInterruptControllerDevice(device
, driver
):
1171 Factory method to create a InterruptControllerDevice.
1174 device (core.cvalue.value): The device object.
1175 driver (core.cvalue.value): The driver object.
1178 InterruptControllerDevice: Returns an instance of
1179 InterruptControllerDevice or None if the arguments do not have
1180 the required properties.
1182 BASE_VECTOR_PROPERTY
= "Base Vector Number"
1183 INTERRUPT_CONTROLLER_NAME_PROPERTY
= "InterruptControllerName"
1184 base_vector
= LookupKeyInPropTable(device
.fPropertyTable
, BASE_VECTOR_PROPERTY
)
1185 if base_vector
is None:
1186 base_vector
= LookupKeyInPropTable(driver
.fPropertyTable
, BASE_VECTOR_PROPERTY
)
1187 device_name
= LookupKeyInPropTable(device
.fPropertyTable
, INTERRUPT_CONTROLLER_NAME_PROPERTY
)
1188 if device_name
is None:
1189 device_name
= LookupKeyInPropTable(driver
.fPropertyTable
, INTERRUPT_CONTROLLER_NAME_PROPERTY
)
1191 if device_name
is not None:
1192 # Some interrupt controllers do not have a base vector number. Assume it is 0.
1193 base_vector_number
= 0
1194 if base_vector
is not None:
1195 base_vector_number
= unsigned(GetNumber(base_vector
))
1196 device_name
= GetString(device_name
)
1197 # Construct object and return
1198 return InterruptControllerDevice(device
, driver
, base_vector_number
, device_name
)
1204 def SearchInterruptControllerDrivers():
1206 Search the IOKit registry for entries that match IOInterruptController.
1209 core.cvalue.value: A LLDB value representing a IORegistryEntry * that
1210 inherits from IOInterruptController.
1212 for entry
in FindMatchingServices("IOInterruptController"):
1214 parent
= GetRegistryEntryParent(entry
)
1216 # Make the interrupt controller object
1217 ic
= InterruptControllerDevice
.makeInterruptControllerDevice(parent
, entry
)
1224 def LookupKeyInOSDict(osdict
, key
):
1225 """ Returns the value corresponding to a given key in a OSDictionary
1226 Returns None if the key was not found
1230 count
= unsigned(osdict
.count
)
1233 while idx
< count
and result
is None:
1234 if key
== osdict
.dictionary
[idx
].key
:
1235 result
= osdict
.dictionary
[idx
].value
1239 def LookupKeyInPropTable(propertyTable
, key_str
):
1240 """ Returns the value corresponding to a given key from a registry entry's property table
1241 Returns None if the key was not found
1242 The property that is being searched for is specified as a string in key_str
1244 if not propertyTable
:
1246 count
= unsigned(propertyTable
.count
)
1249 while idx
< count
and result
is None:
1250 if key_str
== str(propertyTable
.dictionary
[idx
].key
.string
):
1251 result
= propertyTable
.dictionary
[idx
].value
1255 def GetRegDictionary(osdict
, prefix
):
1256 """ Returns a specially formatted string summary of the given OSDictionary
1257 This is done in order to pretty-print registry property tables in showregistry
1260 out_string
= prefix
+ "{\n"
1262 count
= unsigned(osdict
.count
)
1265 out_string
+= prefix
+ " " + GetObjectSummary(osdict
.dictionary
[idx
].key
) + " = " + GetObjectSummary(osdict
.dictionary
[idx
].value
) + "\n"
1267 out_string
+= prefix
+ "}\n"
1270 def GetString(string
):
1271 """ Returns the python string representation of a given OSString
1273 out_string
= "\"{0:s}\"".format(CastIOKitClass(string
, 'OSString *').string
)
1277 out_string
= "{0:d}".format(CastIOKitClass(num
, 'OSNumber *').value
)
1281 """ Shows info about a given OSBoolean
1284 if b
== kern
.globals.gOSBooleanFalse
:
1290 def GetMetaClass(mc
):
1291 """ Shows info about a given OSSymbol
1293 out_string
= "{0: <5d}x {1: >5d} bytes {2:s}\n".format(mc
.instanceCount
, mc
.classSize
, mc
.className
.string
)
1297 """ Returns a string containing info about a given OSArray
1301 count
= unsigned(arr
.count
)
1304 obj
= arr
.array
[idx
]
1306 out_string
+= GetObjectSummary(obj
)
1307 if idx
< unsigned(arr
.count
):
1311 def GetDictionary(d
):
1312 """ Returns a string containing info about a given OSDictionary
1316 count
= unsigned(d
.count
)
1319 obj
= d
.dictionary
[idx
].key
1320 out_string
+= GetObjectSummary(obj
) + "="
1321 obj
= d
.dictionary
[idx
].value
1323 out_string
+= GetObjectSummary(obj
)
1330 """ Returns a string containing info about a given OSSet
1332 out_string
+= "[" + GetArray(se
.members
) + "]"
1335 def ReadIOPortInt(addr
, numbytes
, lcpu
):
1336 """ Prints results after reading a given ioport
1340 if "kdp" != GetConnectionProtocol():
1341 print "Target is not connected over kdp. Nothing to do here."
1344 # Set up the manual KDP packet
1345 input_address
= unsigned(addressof(kern
.globals.manual_pkt
.input))
1346 len_address
= unsigned(addressof(kern
.globals.manual_pkt
.len))
1347 data_address
= unsigned(addressof(kern
.globals.manual_pkt
.data
))
1348 if not WriteInt32ToMemoryAddress(0, input_address
):
1349 print "0x{0: <4x}: 0x{1: <1x}".format(addr
, result
)
1352 kdp_pkt_size
= GetType('kdp_readioport_req_t').GetByteSize()
1353 if not WriteInt32ToMemoryAddress(kdp_pkt_size
, len_address
):
1354 print "0x{0: <4x}: 0x{1: <1x}".format(addr
, result
)
1357 kgm_pkt
= kern
.GetValueFromAddress(data_address
, 'kdp_readioport_req_t *')
1359 header_value
= GetKDPPacketHeaderInt(request
=GetEnumValue('kdp_req_t::KDP_READIOPORT'), length
= kdp_pkt_size
)
1361 if( WriteInt64ToMemoryAddress((header_value
), int(addressof(kgm_pkt
.hdr
))) and
1362 WriteInt16ToMemoryAddress(addr
, int(addressof(kgm_pkt
.address
))) and
1363 WriteInt32ToMemoryAddress(numbytes
, int(addressof(kgm_pkt
.nbytes
))) and
1364 WriteInt16ToMemoryAddress(lcpu
, int(addressof(kgm_pkt
.lcpu
))) and
1365 WriteInt32ToMemoryAddress(1, input_address
)
1368 result_pkt
= Cast(addressof(kern
.globals.manual_pkt
.data
), 'kdp_readioport_reply_t *')
1370 if(result_pkt
.error
== 0):
1372 result
= dereference(Cast(addressof(result_pkt
.data
), 'uint8_t *'))
1374 result
= dereference(Cast(addressof(result_pkt
.data
), 'uint16_t *'))
1376 result
= dereference(Cast(addressof(result_pkt
.data
), 'uint32_t *'))
1378 print "{0: <#6x}: {1:#0{2}x}".format(addr
, result
, (numbytes
*2)+2)
1380 def WriteIOPortInt(addr
, numbytes
, value
, lcpu
):
1381 """ Writes 'value' into ioport specified by 'addr'. Prints errors if it encounters any
1383 if "kdp" != GetConnectionProtocol():
1384 print "Target is not connected over kdp. Nothing to do here."
1387 # Set up the manual KDP packet
1388 input_address
= unsigned(addressof(kern
.globals.manual_pkt
.input))
1389 len_address
= unsigned(addressof(kern
.globals.manual_pkt
.len))
1390 data_address
= unsigned(addressof(kern
.globals.manual_pkt
.data
))
1391 if not WriteInt32ToMemoryAddress(0, input_address
):
1392 print "error writing {0: #x} to port {1: <#6x}: failed to write 0 to input_address".format(value
, addr
)
1395 kdp_pkt_size
= GetType('kdp_writeioport_req_t').GetByteSize()
1396 if not WriteInt32ToMemoryAddress(kdp_pkt_size
, len_address
):
1397 print "error writing {0: #x} to port {1: <#6x}: failed to write kdp_pkt_size".format(value
, addr
)
1400 kgm_pkt
= kern
.GetValueFromAddress(data_address
, 'kdp_writeioport_req_t *')
1402 header_value
= GetKDPPacketHeaderInt(request
=GetEnumValue('kdp_req_t::KDP_WRITEIOPORT'), length
= kdp_pkt_size
)
1404 if( WriteInt64ToMemoryAddress((header_value
), int(addressof(kgm_pkt
.hdr
))) and
1405 WriteInt16ToMemoryAddress(addr
, int(addressof(kgm_pkt
.address
))) and
1406 WriteInt32ToMemoryAddress(numbytes
, int(addressof(kgm_pkt
.nbytes
))) and
1407 WriteInt16ToMemoryAddress(lcpu
, int(addressof(kgm_pkt
.lcpu
)))
1410 if not WriteInt8ToMemoryAddress(value
, int(addressof(kgm_pkt
.data
))):
1411 print "error writing {0: #x} to port {1: <#6x}: failed to write 8 bit data".format(value
, addr
)
1414 if not WriteInt16ToMemoryAddress(value
, int(addressof(kgm_pkt
.data
))):
1415 print "error writing {0: #x} to port {1: <#6x}: failed to write 16 bit data".format(value
, addr
)
1418 if not WriteInt32ToMemoryAddress(value
, int(addressof(kgm_pkt
.data
))):
1419 print "error writing {0: #x} to port {1: <#6x}: failed to write 32 bit data".format(value
, addr
)
1421 if not WriteInt32ToMemoryAddress(1, input_address
):
1422 print "error writing {0: #x} to port {1: <#6x}: failed to write to input_address".format(value
, addr
)
1425 result_pkt
= Cast(addressof(kern
.globals.manual_pkt
.data
), 'kdp_writeioport_reply_t *')
1427 # Done with the write
1428 if(result_pkt
.error
== 0):
1429 print "Writing {0: #x} to port {1: <#6x} was successful".format(value
, addr
)
1431 print "error writing {0: #x} to port {1: <#6x}".format(value
, addr
)
1433 @lldb_command('showinterruptcounts')
1434 def showinterruptcounts(cmd_args
=None):
1435 """ Shows event source based interrupt counts by nub name and interrupt index.
1436 Does not cover interrupts that are not event source based. Will report 0
1437 if interrupt accounting is disabled.
1440 header_format
= "{0: <20s} {1: >5s} {2: >20s}"
1441 content_format
= "{0: <20s} {1: >5d} {2: >20d}"
1443 print header_format
.format("Name", "Index", "Count")
1445 for i
in kern
.interrupt_stats
:
1446 owner
= CastIOKitClass(i
.owner
, 'IOInterruptEventSource *')
1447 nub
= CastIOKitClass(owner
.provider
, 'IORegistryEntry *')
1450 # To uniquely identify an interrupt, we need the nub name and the index. The index
1451 # is stored with the stats object, but we need to retrieve the name.
1453 registryTable
= nub
.fRegistryTable
1454 propertyTable
= nub
.fPropertyTable
1456 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
1458 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
1460 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
1463 nub_name
= "Unknown"
1465 nub_name
= GetString(CastIOKitClass(name
, 'OSString *'))
1467 # We now have everything we need; spew the requested data.
1469 interrupt_index
= i
.interruptIndex
1470 first_level_count
= i
.interruptStatistics
[0]
1472 print content_format
.format(nub_name
, interrupt_index
, first_level_count
)
1476 @lldb_command('showinterruptstats')
1477 def showinterruptstats(cmd_args
=None):
1478 """ Shows event source based interrupt statistics by nub name and interrupt index.
1479 Does not cover interrupts that are not event source based. Will report 0
1480 if interrupt accounting is disabled, or if specific statistics are disabled.
1481 Time is reported in ticks of mach_absolute_time. Statistics are:
1483 Interrupt Count: Number of times the interrupt context handler was run
1484 Interrupt Time: Total time spent in the interrupt context handler (if any)
1485 Workloop Count: Number of times the kernel context handler was run
1486 Workloop CPU Time: Total CPU time spent running the kernel context handler
1487 Workloop Time: Total time spent running the kernel context handler
1490 header_format
= "{0: <20s} {1: >5s} {2: >20s} {3: >20s} {4: >20s} {5: >20s} {6: >20s} {7: >20s} {8: >20s} {9: >20s}"
1491 content_format
= "{0: <20s} {1: >5d} {2: >20d} {3: >20d} {4: >20d} {5: >20d} {6: >20d} {7: >20d} {8: >20d} {9: >#20x}"
1493 print header_format
.format("Name", "Index", "Interrupt Count", "Interrupt Time", "Avg Interrupt Time", "Workloop Count", "Workloop CPU Time", "Workloop Time", "Avg Workloop Time", "Owner")
1495 for i
in kern
.interrupt_stats
:
1496 owner
= CastIOKitClass(i
.owner
, 'IOInterruptEventSource *')
1497 nub
= CastIOKitClass(owner
.provider
, 'IORegistryEntry *')
1500 # To uniquely identify an interrupt, we need the nub name and the index. The index
1501 # is stored with the stats object, but we need to retrieve the name.
1503 registryTable
= nub
.fRegistryTable
1504 propertyTable
= nub
.fPropertyTable
1506 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
1508 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
1510 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
1513 nub_name
= "Unknown"
1515 nub_name
= GetString(CastIOKitClass(name
, 'OSString *'))
1517 # We now have everything we need; spew the requested data.
1519 interrupt_index
= i
.interruptIndex
1520 first_level_count
= i
.interruptStatistics
[0]
1521 second_level_count
= i
.interruptStatistics
[1]
1522 first_level_time
= i
.interruptStatistics
[2]
1523 second_level_cpu_time
= i
.interruptStatistics
[3]
1524 second_level_system_time
= i
.interruptStatistics
[4]
1526 avg_first_level_time
= 0
1527 if first_level_count
!= 0:
1528 avg_first_level_time
= first_level_time
/ first_level_count
1530 avg_second_level_time
= 0
1531 if second_level_count
!= 0:
1532 avg_second_level_time
= second_level_system_time
/ second_level_count
1534 print content_format
.format(nub_name
, interrupt_index
, first_level_count
, first_level_time
, avg_first_level_time
,
1535 second_level_count
, second_level_cpu_time
, second_level_system_time
, avg_second_level_time
, owner
)