4 from core
import caching
7 from collections
import deque
9 ######################################
11 ######################################
14 #####################################
16 #####################################
17 def CastIOKitClass(obj
, target_type
):
18 """ Type cast an object to another IOKIT CPP class.
20 obj - core.value object representing some C construct in lldb
21 target_type - str : ex 'OSString *'
24 v
= Cast(obj
, target_type
)
25 v
.GetSBValue().SetPreferDynamicValue(lldb
.eNoDynamicValues
)
28 #####################################
30 #####################################
31 class PreoslogHeader(object):
33 Represents preoslog buffer header. There's no symbol in the kernel for it.
44 ######################################
46 ######################################
47 @lldb_type_summary(['OSObject *'])
49 def GetObjectSummary(obj
):
50 """ Show info about an OSObject - its vtable ptr and retain count, & more info for simple container classes.
55 vt
= dereference(Cast(obj
, 'uintptr_t *')) - 2 * sizeof('uintptr_t')
56 vt
= kern
.StripKernelPAC(vt
)
57 vtype
= kern
.SymbolicateFromAddress(vt
)
59 vtype_str
= " <" + vtype
[0].GetName() + ">"
62 if hasattr(obj
, 'retainCount'):
63 retCount
= (obj
.retainCount
& 0xffff)
64 cntnrRetCount
= (obj
.retainCount
>> 16)
65 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
)
67 out_string
= "`object 0x{0: <16x}, vt 0x{1: <16x}{2:s}` ".format(obj
, vt
, vtype_str
)
69 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV8OSString')
71 out_string
+= GetString(obj
)
74 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV8OSSymbol')
76 out_string
+= GetString(obj
)
79 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV8OSNumber')
81 out_string
+= GetNumber(obj
)
84 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV9OSBoolean')
86 out_string
+= GetBoolean(obj
)
89 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV7OSArray')
91 out_string
+= "(" + GetArray(CastIOKitClass(obj
, 'OSArray *')) + ")"
94 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV5OSSet')
96 out_string
+= GetSet(CastIOKitClass(obj
, 'OSSet *'))
99 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV12OSDictionary')
101 out_string
+= GetDictionary(CastIOKitClass(obj
, 'OSDictionary *'))
107 def GetObjectTypeStr(obj
):
108 """ Return the type of an OSObject's container class
113 vt
= dereference(Cast(obj
, 'uintptr_t *')) - 2 * sizeof('uintptr_t')
114 vt
= kern
.StripKernelPAC(vt
)
115 vtype
= kern
.SymbolicateFromAddress(vt
)
117 return vtype
[0].GetName()
119 # See if the value is in a kext with no symbols
120 for kval
in IterateLinkedList(kern
.globals.kmod
, 'next'):
121 if vt
>= unsigned(kval
.address
) and vt
<= (unsigned(kval
.address
) + unsigned(kval
.size
)):
122 return "kmod:{:s}+{:#0x}".format(kval
.name
, vt
- unsigned(kval
.address
))
126 @lldb_type_summary(['IORegistryEntry *'])
128 def GetRegistryEntrySummary(entry
):
129 """ returns a string containing summary information about an IORegistry
130 object including it's registry id , vtable ptr and retain count
134 registryTable
= entry
.fRegistryTable
135 propertyTable
= entry
.fPropertyTable
137 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
139 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
141 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
144 out_string
+= "+-o {0:s} ".format(GetString(CastIOKitClass(name
, 'OSString *')))
145 elif CastIOKitClass(entry
, 'IOService *').pwrMgt
and CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
:
146 out_string
+= "+-o {0:s} ".format(CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
)
148 out_string
+= "+-o ?? "
150 # I'm using uintptr_t for now to work around <rdar://problem/12749733> FindFirstType & Co. should allow you to make pointer types directly
151 vtableAddr
= dereference(Cast(entry
, 'uintptr_t *')) - 2 * sizeof('uintptr_t *')
152 vtableAddr
= kern
.StripKernelPAC(vtableAddr
)
153 vtype
= kern
.SymbolicateFromAddress(vtableAddr
)
154 if vtype
is None or len(vtype
) < 1:
155 out_string
+= "<object 0x{0: <16x}, id 0x{1:x}, vtable 0x{2: <16x}".format(entry
, CastIOKitClass(entry
, 'IORegistryEntry *').reserved
.fRegistryEntryID
, vtableAddr
)
157 out_string
+= "<object 0x{0: <16x}, id 0x{1:x}, vtable 0x{2: <16x} <{3:s}>".format(entry
, CastIOKitClass(entry
, 'IORegistryEntry *').reserved
.fRegistryEntryID
,
158 vtableAddr
, vtype
[0].GetName())
160 ztvAddr
= kern
.GetLoadAddressForSymbol('_ZTV15IORegistryEntry')
161 if vtableAddr
!= ztvAddr
:
163 state
= CastIOKitClass(entry
, 'IOService *').__state
[0]
164 # kIOServiceRegisteredState
167 out_string
+= "registered, "
168 # kIOServiceMatchedState
171 out_string
+= "matched, "
172 #kIOServiceInactiveState
175 busyCount
= (CastIOKitClass(entry
, 'IOService *').__state
[1] & 0xff)
176 retCount
= (CastIOKitClass(entry
, 'IOService *').retainCount
& 0xffff)
177 out_string
+= "active, busy {0}, retain count {1}>".format(busyCount
, retCount
)
180 ######################################
182 ######################################
183 @lldb_command('showallclasses')
184 def ShowAllClasses(cmd_args
=None):
185 """ Show the instance counts and ivar size of all OSObject subclasses.
186 See ioclasscount man page for details
189 count
= unsigned(kern
.globals.sAllClassesDict
.count
)
192 meta
= CastIOKitClass(kern
.globals.sAllClassesDict
.dictionary
[idx
].value
, 'OSMetaClass *')
194 print GetMetaClass(meta
)
196 @lldb_command('showobject')
197 def ShowObject(cmd_args
=None):
198 """ Show info about an OSObject - its vtable ptr and retain count, & more info for simple container classes.
201 print "Please specify the address of the OSObject whose info you want to view. Type help showobject for help"
204 obj
= kern
.GetValueFromAddress(cmd_args
[0], 'OSObject *')
205 print GetObjectSummary(obj
)
208 @lldb_command('dumpobject')
209 def DumpObject(cmd_args
=None):
210 """ Dumps object information if it is a valid object confirmed by showobject
211 Usage: dumpobject <address of object to be dumped> [class/struct type of object]
214 print "No arguments passed"
215 print DumpObject
.__doc
__
218 if len(cmd_args
) == 1:
220 object_info
= lldb_run_command("showobject {:s}".format(cmd_args
[0]))
222 print "Error!! showobject failed due to invalid value"
223 print DumpObject
.__doc
__
226 srch
= re
.search(r
'<vtable for ([A-Za-z].*)>', object_info
)
228 print "Error!! Couldn't find object in registry, input type manually as 2nd argument"
229 print DumpObject
.__doc
__
232 object_type
= srch
.group(1)
234 type_lookup
= lldb_run_command("image lookup -t {:s}".format(cmd_args
[1]))
235 if type_lookup
.find(cmd_args
[1])!= -1:
236 object_type
= cmd_args
[1]
238 print "Error!! Input type {:s} isn't available in image lookup".format(cmd_args
[1])
241 print "******** Object Dump for value \'{:s}\' with type \"{:s}\" ********".format(cmd_args
[0], object_type
)
242 print lldb_run_command("p/x *({:s}*){:s}".format(object_type
, cmd_args
[0]))
244 #EndMacro: dumpobject
246 @lldb_command('setregistryplane')
247 def SetRegistryPlane(cmd_args
=None):
248 """ Set the plane to be used for the IOKit registry macros
249 syntax: (lldb) setregistryplane 0 - will display all known planes
250 syntax: (lldb) setregistryplane 0xaddr - will set the registry plane to 0xaddr
251 syntax: (lldb) setregistryplane gIODTPlane - will set the registry plane to gIODTPlane
254 print "Please specify the name of the plane you want to use with the IOKit registry macros."
255 print SetRegistryPlane
.__doc
__
257 if cmd_args
[0] == "0":
258 print GetObjectSummary(kern
.globals.gIORegistryPlanes
)
261 plane
= kern
.GetValueFromAddress(cmd_args
[0], 'IORegistryPlane *')
264 @lldb_command('showregistryentry')
265 def ShowRegistryEntry(cmd_args
=None):
266 """ Show info about a registry entry; its properties and descendants in the current plane
267 syntax: (lldb) showregistryentry 0xaddr
268 syntax: (lldb) showregistryentry gIOPMRootDomain
271 print "Please specify the address of the registry entry whose info you want to view."
272 print ShowRegistryEntry
.__doc
__
275 entry
= kern
.GetValueFromAddress(cmd_args
[0], 'IORegistryEntry *')
276 ShowRegistryEntryRecurse(entry
, "", True)
278 @lldb_command('showregistry')
279 def ShowRegistry(cmd_args
=None):
280 """ Show info about all registry entries in the current plane
281 If prior to invoking this command no registry plane is specified
282 using 'setregistryplane', the command defaults to the IOService plane
284 ShowRegistryEntryRecurse(kern
.globals.gRegistryRoot
, "", False)
286 @lldb_command('showregistryprops')
287 def ShowRegistryProps(cmd_args
=None):
288 """ Show info about all registry entries in the current plane, and their properties
289 If prior to invoking this command no registry plane is specified
290 using 'setregistryplane', the command defaults to the IOService plane
292 ShowRegistryEntryRecurse(kern
.globals.gRegistryRoot
, "", True)
294 @lldb_command('findregistryentry')
295 def FindRegistryEntry(cmd_args
=None):
296 """ Search for registry entry that matches the given string
297 If prior to invoking this command no registry plane is specified
298 using 'setregistryplane', the command defaults to searching entries from the IOService plane
299 syntax: (lldb) findregistryentries AppleACPICPU - will find the first registry entry that matches AppleACPICPU
302 print "Please specify the name of the registry entry you want to find"
303 print FindRegistryEntry
.__doc
__
306 FindRegistryEntryRecurse(kern
.globals.gRegistryRoot
, cmd_args
[0], True)
308 @lldb_command('findregistryentries')
309 def FindRegistryEntries(cmd_args
=None):
310 """ Search for all registry entries that match the given string
311 If prior to invoking this command no registry plane is specified
312 using 'setregistryplane', the command defaults to searching entries from the IOService plane
313 syntax: (lldb) findregistryentries AppleACPICPU - will find all registry entries that match AppleACPICPU
316 print "Please specify the name of the registry entry/entries you want to find"
317 print FindRegistryEntries
.__doc
__
320 FindRegistryEntryRecurse(kern
.globals.gRegistryRoot
, cmd_args
[0], False)
322 @lldb_command('findregistryprop')
323 def FindRegistryProp(cmd_args
=None):
324 """ Given a registry entry, print out the contents for the property that matches
326 syntax: (lldb) findregistryprop 0xaddr IOSleepSupported
327 syntax: (lldb) findregistryprop gIOPMRootDomain IOSleepSupported
328 syntax: (lldb) findregistryprop gIOPMRootDomain "Supported Features"
330 if not cmd_args
or len(cmd_args
) < 2:
331 print "Please specify the address of a IORegistry entry and the property you're looking for"
332 print FindRegistryProp
.__doc
__
335 entry
= kern
.GetValueFromAddress(cmd_args
[0], 'IOService *')
336 propertyTable
= entry
.fPropertyTable
337 print GetObjectSummary(LookupKeyInPropTable(propertyTable
, cmd_args
[1]))
339 @lldb_command('readioport8')
340 def ReadIOPort8(cmd_args
=None):
341 """ Read value stored in the specified IO port. The CPU can be optionally
343 Prints 0xBAD10AD in case of a bad read
344 Syntax: (lldb) readioport8 <port> [lcpu (kernel's numbering convention)]
347 print "Please specify a port to read out of"
348 print ReadIOPort8
.__doc__
351 portAddr
= ArgumentStringToInt(cmd_args
[0])
352 if len(cmd_args
) >= 2:
353 lcpu
= ArgumentStringToInt(cmd_args
[1])
355 lcpu
= xnudefines
.lcpu_self
357 ReadIOPortInt(portAddr
, 1, lcpu
)
359 @lldb_command('readioport16')
360 def ReadIOPort16(cmd_args
=None):
361 """ Read value stored in the specified IO port. The CPU can be optionally
363 Prints 0xBAD10AD in case of a bad read
364 Syntax: (lldb) readioport16 <port> [lcpu (kernel's numbering convention)]
367 print "Please specify a port to read out of"
368 print ReadIOPort16
.__doc__
371 portAddr
= ArgumentStringToInt(cmd_args
[0])
372 if len(cmd_args
) >= 2:
373 lcpu
= ArgumentStringToInt(cmd_args
[1])
375 lcpu
= xnudefines
.lcpu_self
377 ReadIOPortInt(portAddr
, 2, lcpu
)
379 @lldb_command('readioport32')
380 def ReadIOPort32(cmd_args
=None):
381 """ Read value stored in the specified IO port. The CPU can be optionally
383 Prints 0xBAD10AD in case of a bad read
384 Syntax: (lldb) readioport32 <port> [lcpu (kernel's numbering convention)]
387 print "Please specify a port to read out of"
388 print ReadIOPort32
.__doc__
391 portAddr
= ArgumentStringToInt(cmd_args
[0])
392 if len(cmd_args
) >= 2:
393 lcpu
= ArgumentStringToInt(cmd_args
[1])
395 lcpu
= xnudefines
.lcpu_self
397 ReadIOPortInt(portAddr
, 4, lcpu
)
399 @lldb_command('writeioport8')
400 def WriteIOPort8(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) writeioport8 <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 WriteIOPort8
.__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
, 1, value
, lcpu
)
421 @lldb_command('writeioport16')
422 def WriteIOPort16(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) writeioport16 <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 WriteIOPort16
.__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
, 2, value
, lcpu
)
443 @lldb_command('writeioport32')
444 def WriteIOPort32(cmd_args
=None):
445 """ Write the value to the specified IO port. The size of the value is
446 determined by the name of the command. The CPU used can be optionally
448 Syntax: (lldb) writeioport32 <port> <value> [lcpu (kernel's numbering convention)]
450 if not cmd_args
or len(cmd_args
) < 2:
451 print "Please specify a port to write to, followed by the value you want to write"
452 print WriteIOPort32
.__doc__
455 portAddr
= ArgumentStringToInt(cmd_args
[0])
456 value
= ArgumentStringToInt(cmd_args
[1])
458 if len(cmd_args
) >= 3:
459 lcpu
= ArgumentStringToInt(cmd_args
[2])
461 lcpu
= xnudefines
.lcpu_self
463 WriteIOPortInt(portAddr
, 4, value
, lcpu
)
465 @lldb_command('showioservicepm')
466 def ShowIOServicePM(cmd_args
=None):
467 """ Routine to dump the IOServicePM object
468 Syntax: (lldb) showioservicepm <IOServicePM pointer>
471 print "Please enter the pointer to the IOServicePM object you'd like to introspect"
472 print ShowIOServicePM
.__doc
__
475 iopmpriv
= kern
.GetValueFromAddress(cmd_args
[0], 'IOServicePM *')
476 out_string
= "MachineState {0: <6d} (".format(iopmpriv
.MachineState
)
481 1: 'kIOPM_OurChangeTellClientsPowerDown',
482 2: 'kIOPM_OurChangeTellClientsPowerDown',
483 3: 'kIOPM_OurChangeNotifyInterestedDriversWillChange',
484 4: 'kIOPM_OurChangeSetPowerState',
485 5: 'kIOPM_OurChangeWaitForPowerSettle',
486 6: 'kIOPM_OurChangeNotifyInterestedDriversDidChange',
487 7: 'kIOPM_OurChangeTellCapabilityDidChange',
488 8: 'kIOPM_OurChangeFinish',
489 9: 'Unused_MachineState_9',
490 10: 'kIOPM_ParentChangeTellPriorityClientsPowerDown',
491 11: 'kIOPM_ParentChangeNotifyInterestedDriversWillChange',
492 12: 'kIOPM_ParentChangeSetPowerState',
493 13: 'kIOPM_ParentChangeWaitForPowerSettle',
494 14: 'kIOPM_ParentChangeNotifyInterestedDriversDidChange',
495 15: 'kIOPM_ParentChangeTellCapabilityDidChange',
496 16: 'kIOPM_ParentChangeAcknowledgePowerChange',
497 17: 'kIOPM_NotifyChildrenStart',
498 18: 'kIOPM_NotifyChildrenOrdered',
499 19: 'kIOPM_NotifyChildrenDelayed',
500 20: 'kIOPM_SyncTellClientsPowerDown',
501 21: 'kIOPM_SyncTellPriorityClientsPowerDown',
502 22: 'kIOPM_SyncNotifyWillChange',
503 23: 'kIOPM_SyncNotifyDidChange',
504 24: 'kIOPM_SyncTellCapabilityDidChange',
505 25: 'kIOPM_SyncFinish',
506 26: 'kIOPM_TellCapabilityChangeDone',
507 27: 'kIOPM_DriverThreadCallDone'
509 powerstate
= unsigned(iopmpriv
.MachineState
)
510 if powerstate
in pstate_map
:
511 out_string
+= "{0:s}".format(pstate_map
[powerstate
])
513 out_string
+= "Unknown_MachineState"
516 if iopmpriv
.MachineState
!= 20:
517 out_string
+= "DriverTimer = {0: <6d}, SettleTime = {1: < 6d}, HeadNoteFlags = {2: #12x}, HeadNotePendingAcks = {3: #012x}, ".format(
518 unsigned(iopmpriv
.DriverTimer
),
519 unsigned(iopmpriv
.SettleTimeUS
),
520 unsigned(iopmpriv
.HeadNoteChangeFlags
),
521 unsigned(iopmpriv
.HeadNotePendingAcks
))
523 if iopmpriv
.DeviceOverrideEnabled
!= 0:
524 out_string
+= "DeviceOverrides, "
526 out_string
+= "DeviceDesire = {0: <6d}, DesiredPowerState = {1: <6d}, PreviousRequest = {2: <6d}\n".format(
527 unsigned(iopmpriv
.DeviceDesire
),
528 unsigned(iopmpriv
.DesiredPowerState
),
529 unsigned(iopmpriv
.PreviousRequestPowerFlags
))
533 @lldb_type_summary(['IOPMWorkQueue *'])
535 def GetIOPMWorkQueueSummary(wq
):
537 ioservicepm_header
= "{:<20s}{:<4s}{:<4s}{:<4s}{:<4s}\n"
538 iopmrequest_indent
= " "
539 iopmrequest_header
= iopmrequest_indent
+ "{:<20s}{:<6s}{:<20s}{:<20s}{:<12s}{:<12s}{:<20s}{:<20s}{:<20s}\n"
541 for next
in IterateQueue(wq
.fWorkQueue
, 'IOServicePM *', 'WorkChain'):
542 out_str
+= ioservicepm_header
.format("IOService", "ps", "ms", "wr", "name")
543 out_str
+= "0x{:<16x} {:<2d} {:<2d} {:<2d} {:<s}\n".format(
544 next
.Owner
, next
.CurrentPowerState
, next
.MachineState
, next
.WaitReason
, next
.Name
)
545 out_str
+= iopmrequest_header
.format("IOPMRequest", "type", "next_req", "root_req", "work_wait", "free_wait", "arg0", "arg1", "arg2")
546 for request
in IterateQueue(next
.RequestHead
, 'IOPMRequest *', 'fCommandChain'):
547 out_str
+= iopmrequest_indent
548 out_str
+= "0x{:<16x} 0x{:<2x} 0x{:<16x} 0x{:<16x}".format(
549 request
, request
.fRequestType
, request
.fRequestNext
, request
.fRequestRoot
)
550 out_str
+= " 0x{:<8x} 0x{:<8x}".format(
551 request
.fWorkWaitCount
, request
.fFreeWaitCount
)
552 out_str
+= " 0x{:<16x} 0x{:<16x} 0x{:<16x}\n".format(
553 request
.fArg0
, request
.fArg1
, request
.fArg2
)
556 @lldb_command('showiopmqueues')
557 def ShowIOPMQueues(cmd_args
=None):
558 """ Show IOKit power management queues and IOPMRequest objects.
560 print "IOPMWorkQueue 0x{:<16x} ({:<d} IOServicePM)\n".format(
561 kern
.globals.gIOPMWorkQueue
, kern
.globals.gIOPMWorkQueue
.fQueueLength
)
562 print GetIOPMWorkQueueSummary(kern
.globals.gIOPMWorkQueue
)
564 @lldb_type_summary(['IOService *'])
566 def GetIOPMInterest(service
):
567 iopm
= CastIOKitClass(service
.pwrMgt
, 'IOServicePM *')
568 if unsigned(iopm
) == 0:
569 print("error: no IOServicePM")
572 list = CastIOKitClass(iopm
.InterestedDrivers
, 'IOPMinformeeList *')
573 out_str
= "IOServicePM 0x{:<16x} ({:<d} interest, {:<d} pending ack)\n".format(
574 iopm
, list.length
, iopm
.HeadNotePendingAcks
)
578 out_str
+= " {:<20s}{:<8s}{:<10s}{:<20s}{:<20s}{:<20s}{:<s}\n".format(
579 "informee", "active", "ticks", "notifyTime", "service", "regId", "name")
580 next
= CastIOKitClass(list.firstItem
, 'IOPMinformee *')
581 while unsigned(next
) != 0:
582 driver
= CastIOKitClass(next
.whatObject
, 'IOService *')
583 name
= GetRegistryEntryName(driver
)
584 reg_id
= CastIOKitClass(driver
, 'IORegistryEntry *').reserved
.fRegistryEntryID
;
585 out_str
+= " 0x{:<16x} {:<6s} {:<8d} 0x{:<16x} 0x{:<16x} 0x{:<16x} {:<s}\n".format(
586 next
, "Yes" if next
.active
!= 0 else "No" , next
.timer
, next
.startTime
, next
.whatObject
, reg_id
, name
)
587 next
= CastIOKitClass(next
.nextInList
, 'IOPMinformee *')
590 @lldb_command('showiopminterest')
591 def ShowIOPMInterest(cmd_args
=None):
592 """ Show the interested drivers for an IOService.
593 syntax: (lldb) showiopminterest <IOService>
596 print "Please specify the address of the IOService"
597 print ShowIOPMInterest
.__doc
__
600 obj
= kern
.GetValueFromAddress(cmd_args
[0], 'IOService *')
601 print GetIOPMInterest(obj
)
603 @lldb_command("showinterruptvectors")
604 def ShowInterruptVectorInfo(cmd_args
=None):
606 Shows interrupt vectors.
610 kInterruptTriggerModeMask
= 0x01
611 kInterruptTriggerModeEdge
= 0x00
612 kInterruptTriggerModeLevel
= kInterruptTriggerModeMask
613 kInterruptPolarityMask
= 0x02
614 kInterruptPolarityHigh
= 0x00
615 kInterruptPolarityLow
= kInterruptPolarityMask
616 kInterruptShareableMask
= 0x04
617 kInterruptNotShareable
= 0x00
618 kInterruptIsShareable
= kInterruptShareableMask
619 kIOInterruptTypePCIMessaged
= 0x00010000
621 # Get all interrupt controllers
622 interrupt_controllers
= list(SearchInterruptControllerDrivers())
624 print("Interrupt controllers: ")
625 for ic
in interrupt_controllers
:
626 print(" {}".format(ic
))
629 # Iterate over all entries in the registry
630 for entry
in GetMatchingEntries(lambda _
: True):
631 # Get the name of the entry
632 entry_name
= GetRegistryEntryName(entry
)
634 # Get the location of the entry
635 entry_location
= GetRegistryEntryLocationInPlane(entry
, kern
.globals.gIOServicePlane
)
636 if entry_location
is None:
639 entry_location
= "@" + entry_location
641 # Get the interrupt properties
642 (msi_mode
, vectorDataList
, vectorContList
) = GetRegistryEntryInterruptProperties(entry
)
645 for (vector_data
, vector_cont
) in zip(vectorDataList
, vectorContList
):
646 # vector_cont is the name of the interrupt controller. Find the matching controller from
647 # the list of controllers obtained earlier
648 matching_ics
= filter(lambda ic
: ic
.name
== vector_cont
, interrupt_controllers
)
650 if len(matching_ics
) > 0:
652 # Take the first match
653 matchingIC
= matching_ics
[0]
655 # Use the vector_data to determine the vector and any flags
656 data_ptr
= vector_data
.data
657 data_length
= vector_data
.length
659 # Dereference vector_data as a uint32_t * and add the base vector number
660 gsi
= unsigned(dereference(Cast(data_ptr
, 'uint32_t *')))
661 gsi
+= matchingIC
.base_vector_number
663 # If data_length is >= 8 then vector_data contains interrupt flags
665 # Add sizeof(uint32_t) to data_ptr to get the flags pointer
666 flags_ptr
= kern
.GetValueFromAddress(unsigned(data_ptr
) + sizeof("uint32_t"))
667 flags
= unsigned(dereference(Cast(flags_ptr
, 'uint32_t *')))
668 out_str
+= " +----- [Interrupt Controller {ic}] vector {gsi}, {trigger_level}, {active}, {shareable}{messaged}\n" \
669 .format(ic
=matchingIC
.name
, gsi
=hex(gsi
),
670 trigger_level
="level trigger" if flags
& kInterruptTriggerModeLevel
else "edge trigger",
671 active
="active low" if flags
& kInterruptPolarityLow
else "active high",
672 shareable
="shareable" if flags
& kInterruptIsShareable
else "exclusive",
673 messaged
=", messaged" if flags
& kIOInterruptTypePCIMessaged
else "")
675 out_str
+= " +----- [Interrupt Controller {ic}] vector {gsi}\n".format(ic
=matchingIC
.name
, gsi
=hex(gsi
))
677 print("[ {entry_name}{entry_location} ]{msi_mode}\n{out_str}" \
678 .format(entry_name
=entry_name
,
679 entry_location
=entry_location
,
680 msi_mode
=" - MSIs enabled" if msi_mode
else "",
683 @lldb_command("showiokitclasshierarchy")
684 def ShowIOKitClassHierarchy(cmd_args
=None):
686 Show class hierarchy for a IOKit class
689 print("Usage: showiokitclasshierarchy <IOKit class name>")
692 class_name
= cmd_args
[0]
693 metaclasses
= GetMetaClasses()
694 if class_name
not in metaclasses
:
695 print("Class {} does not exist".format(class_name
))
697 metaclass
= metaclasses
[class_name
]
699 # loop over superclasses
701 current_metaclass
= metaclass
702 while current_metaclass
is not None:
703 hierarchy
.insert(0, current_metaclass
)
704 current_metaclass
= current_metaclass
.superclass()
706 for (index
, mc
) in enumerate(hierarchy
):
707 indent
= (" " * index
) + "+---"
708 print("{}[ {} ] {}".format(indent
, str(mc
.className()), str(mc
.data())))
711 ######################################
713 ######################################
714 def ShowRegistryEntryRecurse(entry
, prefix
, printProps
):
715 """ prints registry entry summary and recurses through all its children.
720 plen
= (len(prefix
)//2)
721 registryTable
= entry
.fRegistryTable
722 propertyTable
= entry
.fPropertyTable
724 # Print entry details
725 print "{0:s}{1:s}".format(prefix
, GetRegistryEntrySummary(entry
))
726 # Printing large property tables make it look like lldb is 'stuck'
728 print GetRegDictionary(propertyTable
, prefix
+ " | ")
732 childKey
= kern
.globals.gIOServicePlane
.keys
[1]
734 childKey
= plane
.keys
[1]
735 childArray
= LookupKeyInOSDict(registryTable
, childKey
)
736 if childArray
is not None:
738 ca
= CastIOKitClass(childArray
, 'OSArray *')
739 count
= unsigned(ca
.count
)
741 if plen
!= 0 and plen
!= 1 and (plen
& (plen
- 1)) == 0:
742 ShowRegistryEntryRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), prefix
+ "| ", printProps
)
744 ShowRegistryEntryRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), prefix
+ " ", printProps
)
747 def FindRegistryEntryRecurse(entry
, search_name
, stopAfterFirst
):
748 """ Checks if given registry entry's name matches the search_name we're looking for
749 If yes, it prints the entry's summary and then recurses through its children
750 If no, it does nothing and recurses through its children
754 registryTable
= entry
.fRegistryTable
755 propertyTable
= entry
.fPropertyTable
759 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
761 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
763 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
766 if str(CastIOKitClass(name
, 'OSString *').string
) == search_name
:
767 print GetRegistryEntrySummary(entry
)
768 if stopAfterFirst
is True:
770 elif CastIOKitClass(entry
, 'IOService *').pwrMgt
and CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
:
771 name
= CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
772 if str(name
) == search_name
:
773 print GetRegistryEntrySummary(entry
)
774 if stopAfterFirst
is True:
779 childKey
= kern
.globals.gIOServicePlane
.keys
[1]
781 childKey
= plane
.keys
[1]
782 childArray
= LookupKeyInOSDict(registryTable
, childKey
)
783 if childArray
is not None:
785 ca
= CastIOKitClass(childArray
, 'OSArray *')
786 count
= unsigned(ca
.count
)
788 if FindRegistryEntryRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), search_name
, stopAfterFirst
) is True:
793 def FindRegistryObjectRecurse(entry
, search_name
):
794 """ Checks if given registry entry's name matches the search_name we're looking for
795 If yes, return the entry
796 If no, it does nothing and recurses through its children
797 Implicitly stops after finding the first entry
801 registryTable
= entry
.fRegistryTable
802 propertyTable
= entry
.fPropertyTable
806 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
808 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
810 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
813 if str(CastIOKitClass(name
, 'OSString *').string
) == search_name
:
815 elif CastIOKitClass(entry
, 'IOService *').pwrMgt
and CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
:
816 name
= CastIOKitClass(entry
, 'IOService *').pwrMgt
.Name
817 if str(name
) == search_name
:
822 childKey
= kern
.globals.gIOServicePlane
.keys
[1]
824 childKey
= plane
.keys
[1]
825 childArray
= LookupKeyInOSDict(registryTable
, childKey
)
826 if childArray
is not None:
827 ca
= CastIOKitClass(childArray
, 'OSArray *')
828 for idx
in range(ca
.count
):
829 registry_object
= FindRegistryObjectRecurse(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'), search_name
)
830 if not registry_object
or int(registry_object
) == int(0):
833 return registry_object
836 def CompareStringToOSSymbol(string
, os_sym
):
838 Lexicographically compare python string to OSSymbol
840 string - python string
844 0 if string == os_sym
846 -1 if string < os_sym
848 os_sym_str
= GetString(os_sym
)
849 if string
> os_sym_str
:
851 elif string
< os_sym_str
:
856 class IOKitMetaClass(object):
858 A class that represents a IOKit metaclass. This is used to represent the
859 IOKit inheritance hierarchy.
862 def __init__(self
, meta
):
864 Initialize a IOKitMetaClass object.
867 meta (core.cvalue.value): A LLDB value representing a
871 self
._superclass
= None
876 def setSuperclass(self
, superclass
):
878 Set the superclass for this metaclass.
881 superclass (core.cvalue.value): A LLDB value representing a
884 self
._superclass
= superclass
886 def superclass(self
):
888 Get the superclass for this metaclass (set by the setSuperclass method).
891 core.cvalue.value: A LLDB value representing a OSMetaClass *.
893 return self
._superclass
897 Get the name of the class this metaclass represents.
902 return self
._meta
.className
.string
904 def inheritsFrom(self
, other
):
906 Check if the class represented by this metaclass inherits from a class
907 represented by another metaclass.
910 other (IOKitMetaClass): The other metaclass
913 bool: Returns True if this class inherits from the other class and
917 while current
is not None:
921 current
= current
.superclass()
924 def GetRegistryEntryClassName(entry
):
926 Get the class name of a registry entry.
929 entry (core.cvalue.value): A LLDB value representing a
933 str: The class name of the entry or None if a class name could not be
936 # Check using IOClass key
937 result
= LookupKeyInOSDict(entry
.fPropertyTable
, kern
.globals.gIOClassKey
)
938 if result
is not None:
939 return GetString(result
).replace("\"", "")
941 # Use the vtable of the entry to determine the concrete type
942 vt
= dereference(Cast(entry
, 'uintptr_t *')) - 2 * sizeof('uintptr_t')
943 vt
= kern
.StripKernelPAC(vt
)
944 vtype
= kern
.SymbolicateFromAddress(vt
)
946 vtableName
= vtype
[0].GetName()
947 return vtableName
[11:] # strip off "vtable for "
952 def GetRegistryEntryName(entry
):
954 Get the name of a registry entry.
957 entry (core.cvalue.value): A LLDB value representing a
961 str: The name of the entry or None if a name could not be found.
965 # First check the IOService plane nameKey
966 result
= LookupKeyInOSDict(entry
.fRegistryTable
, kern
.globals.gIOServicePlane
.nameKey
)
967 if result
is not None:
968 name
= GetString(result
)
970 # Check the global IOName key
972 result
= LookupKeyInOSDict(entry
.fRegistryTable
, kern
.globals.gIONameKey
)
973 if result
is not None:
974 name
= GetString(result
)
976 # Check the IOClass key
978 result
= LookupKeyInOSDict(entry
.fPropertyTable
, kern
.globals.gIOClassKey
)
979 if result
is not None:
980 name
= GetString(result
)
982 # Remove extra quotes
984 return name
.replace("\"", "")
986 return GetRegistryEntryClassName(entry
)
989 def GetRegistryEntryLocationInPlane(entry
, plane
):
991 Get the registry entry location in a IOKit plane.
994 entry (core.cvalue.value): A LLDB value representing a
996 plane: An IOKit plane such as kern.globals.gIOServicePlane.
999 str: The location of the entry or None if a location could not be
1002 # Check the plane's pathLocationKey
1003 sym
= LookupKeyInOSDict(entry
.fRegistryTable
, plane
.pathLocationKey
)
1005 # Check the global IOLocation key
1007 sym
= LookupKeyInOSDict(entry
.fRegistryTable
, kern
.globals.gIOLocationKey
)
1009 return GetString(sym
).replace("\"", "")
1014 def GetMetaClasses():
1016 Enumerate all IOKit metaclasses. Uses dynamic caching.
1019 Dict[str, IOKitMetaClass]: A dictionary mapping each metaclass name to
1020 a IOKitMetaClass object representing the metaclass.
1022 METACLASS_CACHE_KEY
= "iokit_metaclasses"
1023 cached_data
= caching
.GetDynamicCacheData(METACLASS_CACHE_KEY
)
1025 # If we have cached data, return immediately
1026 if cached_data
is not None:
1029 # This method takes a while, so it prints a progress indicator
1030 print("Enumerating IOKit metaclasses: ")
1032 # Iterate over all classes present in sAllClassesDict
1034 count
= unsigned(kern
.globals.sAllClassesDict
.count
)
1035 metaclasses_by_address
= {}
1037 # Print progress after every 10 items
1039 print(" {} metaclass structures parsed...".format(idx
))
1041 # Address of metaclass
1042 address
= kern
.globals.sAllClassesDict
.dictionary
[idx
].value
1044 # Create IOKitMetaClass and store in dict
1045 metaclasses_by_address
[int(address
)] = IOKitMetaClass(CastIOKitClass(kern
.globals.sAllClassesDict
.dictionary
[idx
].value
, 'OSMetaClass *'))
1048 print(" Enumerated {} metaclasses.".format(count
))
1050 # At this point, each metaclass is independent of each other. We don't have superclass links set up yet.
1052 for (address
, metaclass
) in metaclasses_by_address
.items():
1053 # Get the address of the superclass using the superClassLink in IOMetaClass
1054 superclass_address
= int(metaclass
.data().superClassLink
)
1056 # Skip null superclass
1057 if superclass_address
== 0:
1060 # Find the superclass object in the dict
1061 if superclass_address
in metaclasses_by_address
:
1062 metaclass
.setSuperclass(metaclasses_by_address
[superclass_address
])
1064 print("warning: could not find superclass for {}".format(str(metaclass
.data())))
1066 # This method returns a dictionary mapping each class name to the associated metaclass object
1067 metaclasses_by_name
= {}
1068 for (_
, metaclass
) in metaclasses_by_address
.items():
1069 metaclasses_by_name
[str(metaclass
.className())] = metaclass
1071 # Save the result in the cache
1072 caching
.SaveDynamicCacheData(METACLASS_CACHE_KEY
, metaclasses_by_name
)
1074 return metaclasses_by_name
1077 def GetMatchingEntries(matcher
):
1079 Iterate over the IOKit registry and find entries that match specific
1083 matcher (function): A matching function that returns True for a match
1084 and False otherwise.
1087 core.cvalue.value: LLDB values that represent IORegistryEntry * for
1088 each registry entry found.
1091 # Perform a BFS over the IOKit registry tree
1093 bfs_queue
.append(kern
.globals.gRegistryRoot
)
1094 while len(bfs_queue
) > 0:
1096 entry
= bfs_queue
.popleft()
1098 # Check if entry matches
1102 # Find children of this entry and enqueue them
1103 child_array
= LookupKeyInOSDict(entry
.fRegistryTable
, kern
.globals.gIOServicePlane
.keys
[1])
1104 if child_array
is not None:
1106 ca
= CastIOKitClass(child_array
, 'OSArray *')
1107 count
= unsigned(ca
.count
)
1109 bfs_queue
.append(CastIOKitClass(ca
.array
[idx
], 'IORegistryEntry *'))
1113 def FindMatchingServices(matching_name
):
1115 Finds registry entries that match the given string. Works similarly to:
1118 IOServiceGetMatchingServices(..., IOServiceMatching(matching_name), &iter);
1119 while (( io_object_t next = IOIteratorNext(iter))) { ... }
1122 matching_name (str): The class name to search for.
1125 core.cvalue.value: LLDB values that represent IORegistryEntry * for
1126 each registry entry found.
1129 # Check if the argument is valid
1130 metaclasses
= GetMetaClasses()
1131 if matching_name
not in metaclasses
:
1133 matching_metaclass
= metaclasses
[matching_name
]
1135 # An entry matches if it inherits from matching_metaclass
1137 # Get the class name of the entry and the associated metaclass
1138 entry_name
= GetRegistryEntryClassName(entry
)
1139 if entry_name
in metaclasses
:
1140 entry_metaclass
= metaclasses
[entry_name
]
1141 return entry_metaclass
.inheritsFrom(matching_metaclass
)
1145 # Search for entries
1146 for entry
in GetMatchingEntries(matcher
):
1150 def GetRegistryEntryParent(entry
, iokit_plane
=None):
1152 Gets the parent entry of a registry entry.
1155 entry (core.cvalue.value): A LLDB value representing a
1157 iokit_plane (core.cvalue.value, optional): A LLDB value representing a
1158 IORegistryPlane *. By default, this method uses the IOService
1162 core.cvalue.value: A LLDB value representing a IORegistryEntry* that
1163 is the parent entry of the entry argument in the specified plane.
1164 Returns None if no entry could be found.
1168 if iokit_plane
is None:
1169 parent_key
= kern
.globals.gIOServicePlane
.keys
[kParentSetIndex
]
1171 parent_key
= plane
.keys
[kParentSetIndex
]
1172 parent_array
= LookupKeyInOSDict(entry
.fRegistryTable
, parent_key
)
1174 if parent_array
is not None:
1176 ca
= CastIOKitClass(parent_array
, 'OSArray *')
1177 count
= unsigned(ca
.count
)
1179 parent_entry
= CastIOKitClass(ca
.array
[0], 'IORegistryEntry *')
1183 def GetRegistryEntryInterruptProperties(entry
):
1185 Get the interrupt properties of a registry entry.
1188 entry (core.cvalue.value): A LLDB value representing a IORegistryEntry *.
1191 (bool, List[core.cvalue.value], List[str]): A tuple with the following
1193 - First field (bool): Whether this entry has a non-null
1195 - Second field (List[core.cvalue.value]): A list of LLDB values
1196 representing OSData *. The OSData* pointer points to
1197 interrupt vector data.
1198 - Third field (List[str]): A list of strings representing the
1199 interrupt controller names from the
1200 IOInterruptControllers property.
1202 INTERRUPT_SPECIFIERS_PROPERTY
= "IOInterruptSpecifiers"
1203 INTERRUPT_CONTROLLERS_PROPERTY
= "IOInterruptControllers"
1204 MSI_MODE_PROPERTY
= "IOPCIMSIMode"
1206 # Check IOInterruptSpecifiers
1207 interrupt_specifiers
= LookupKeyInPropTable(entry
.fPropertyTable
, INTERRUPT_SPECIFIERS_PROPERTY
)
1208 if interrupt_specifiers
is not None:
1209 interrupt_specifiers
= CastIOKitClass(interrupt_specifiers
, 'OSArray *')
1211 # Check IOInterruptControllers
1212 interrupt_controllers
= LookupKeyInPropTable(entry
.fPropertyTable
, INTERRUPT_CONTROLLERS_PROPERTY
)
1213 if interrupt_controllers
is not None:
1214 interrupt_controllers
= CastIOKitClass(interrupt_controllers
, 'OSArray *')
1217 msi_mode
= LookupKeyInPropTable(entry
.fPropertyTable
, MSI_MODE_PROPERTY
)
1219 result_vector_data
= []
1220 result_vector_cont
= []
1221 if interrupt_specifiers
is not None and interrupt_controllers
is not None:
1222 interrupt_specifiers_array_count
= unsigned(interrupt_specifiers
.count
)
1223 interrupt_controllers_array_count
= unsigned(interrupt_controllers
.count
)
1224 # The array lengths should be the same
1225 if interrupt_specifiers_array_count
== interrupt_controllers_array_count
and interrupt_specifiers_array_count
> 0:
1227 while idx
< interrupt_specifiers_array_count
:
1228 # IOInterruptSpecifiers is an array of OSData *
1229 vector_data
= CastIOKitClass(interrupt_specifiers
.array
[idx
], "OSData *")
1231 # IOInterruptControllers is an array of OSString *
1232 vector_cont
= GetString(interrupt_controllers
.array
[idx
])
1234 result_vector_data
.append(vector_data
)
1235 result_vector_cont
.append(vector_cont
)
1238 return (msi_mode
is not None, result_vector_data
, result_vector_cont
)
1241 class InterruptControllerDevice(object):
1242 """Represents a IOInterruptController"""
1244 def __init__(self
, device
, driver
, base_vector_number
, name
):
1246 Initialize a InterruptControllerDevice.
1249 device (core.cvalue.value): The device object.
1250 driver (core.cvalue.value): The driver object.
1251 base_vector_number (int): The base interrupt vector.
1252 name (str): The name of this interrupt controller.
1255 Use the factory method makeInterruptControllerDevice to validate
1258 self
.device
= device
1259 self
.driver
= driver
1261 self
.base_vector_number
= base_vector_number
1266 String representation of this InterruptControllerDevice.
1268 return " Name {}, base vector = {}, device = {}, driver = {}".format(
1269 self
.name
, hex(self
.base_vector_number
), str(self
.device
), str(self
.driver
))
1272 def makeInterruptControllerDevice(device
, driver
):
1274 Factory method to create a InterruptControllerDevice.
1277 device (core.cvalue.value): The device object.
1278 driver (core.cvalue.value): The driver object.
1281 InterruptControllerDevice: Returns an instance of
1282 InterruptControllerDevice or None if the arguments do not have
1283 the required properties.
1285 BASE_VECTOR_PROPERTY
= "Base Vector Number"
1286 INTERRUPT_CONTROLLER_NAME_PROPERTY
= "InterruptControllerName"
1287 base_vector
= LookupKeyInPropTable(device
.fPropertyTable
, BASE_VECTOR_PROPERTY
)
1288 if base_vector
is None:
1289 base_vector
= LookupKeyInPropTable(driver
.fPropertyTable
, BASE_VECTOR_PROPERTY
)
1290 device_name
= LookupKeyInPropTable(device
.fPropertyTable
, INTERRUPT_CONTROLLER_NAME_PROPERTY
)
1291 if device_name
is None:
1292 device_name
= LookupKeyInPropTable(driver
.fPropertyTable
, INTERRUPT_CONTROLLER_NAME_PROPERTY
)
1294 if device_name
is not None:
1295 # Some interrupt controllers do not have a base vector number. Assume it is 0.
1296 base_vector_number
= 0
1297 if base_vector
is not None:
1298 base_vector_number
= unsigned(GetNumber(base_vector
))
1299 device_name
= GetString(device_name
)
1300 # Construct object and return
1301 return InterruptControllerDevice(device
, driver
, base_vector_number
, device_name
)
1307 def SearchInterruptControllerDrivers():
1309 Search the IOKit registry for entries that match IOInterruptController.
1312 core.cvalue.value: A LLDB value representing a IORegistryEntry * that
1313 inherits from IOInterruptController.
1315 for entry
in FindMatchingServices("IOInterruptController"):
1317 parent
= GetRegistryEntryParent(entry
)
1319 # Make the interrupt controller object
1320 ic
= InterruptControllerDevice
.makeInterruptControllerDevice(parent
, entry
)
1327 def LookupKeyInOSDict(osdict
, key
, comparer
= None):
1328 """ Returns the value corresponding to a given key in a OSDictionary
1329 Returns None if the key was not found
1333 count
= unsigned(osdict
.count
)
1338 # When comparer is specified, "key" argument can be of any type as "comparer" knows how to compare "key" to a key from "osdict".
1339 # When comparer is not specified, key is of cpp_obj type.
1341 while idx
< count
and result
is None:
1342 if comparer
is not None:
1343 if comparer(key
, osdict
.dictionary
[idx
].key
) == 0:
1344 result
= osdict
.dictionary
[idx
].value
1345 elif key
== osdict
.dictionary
[idx
].key
:
1346 result
= osdict
.dictionary
[idx
].value
1350 def LookupKeyInPropTable(propertyTable
, key_str
):
1351 """ Returns the value corresponding to a given key from a registry entry's property table
1352 Returns None if the key was not found
1353 The property that is being searched for is specified as a string in key_str
1355 if not propertyTable
:
1357 count
= unsigned(propertyTable
.count
)
1360 while idx
< count
and result
is None:
1361 if key_str
== str(propertyTable
.dictionary
[idx
].key
.string
):
1362 result
= propertyTable
.dictionary
[idx
].value
1366 def GetRegDictionary(osdict
, prefix
):
1367 """ Returns a specially formatted string summary of the given OSDictionary
1368 This is done in order to pretty-print registry property tables in showregistry
1371 out_string
= prefix
+ "{\n"
1373 count
= unsigned(osdict
.count
)
1376 out_string
+= prefix
+ " " + GetObjectSummary(osdict
.dictionary
[idx
].key
) + " = " + GetObjectSummary(osdict
.dictionary
[idx
].value
) + "\n"
1378 out_string
+= prefix
+ "}\n"
1381 def GetString(string
):
1382 """ Returns the python string representation of a given OSString
1384 out_string
= "{0:s}".format(CastIOKitClass(string
, 'OSString *').string
)
1388 out_string
= "{0:d}".format(CastIOKitClass(num
, 'OSNumber *').value
)
1392 """ Shows info about a given OSBoolean
1395 if b
== kern
.globals.gOSBooleanFalse
:
1401 def GetMetaClass(mc
):
1402 """ Shows info about a given OSSymbol
1404 out_string
= "{0: <5d}x {1: >5d} bytes {2:s}\n".format(mc
.instanceCount
, mc
.classSize
, mc
.className
.string
)
1408 """ Returns a string containing info about a given OSArray
1412 count
= unsigned(arr
.count
)
1415 obj
= arr
.array
[idx
]
1417 out_string
+= GetObjectSummary(obj
)
1418 if idx
< unsigned(arr
.count
):
1422 def GetDictionary(d
):
1423 """ Returns a string containing info about a given OSDictionary
1429 count
= unsigned(d
.count
)
1432 key
= d
.dictionary
[idx
].key
1433 value
= d
.dictionary
[idx
].value
1434 out_string
+= " \"{}\" = {}\n".format(GetString(key
), GetObjectSummary(value
))
1440 """ Returns a string containing info about a given OSSet
1442 out_string
= "[" + GetArray(se
.members
) + "]"
1445 def ReadIOPortInt(addr
, numbytes
, lcpu
):
1446 """ Prints results after reading a given ioport
1450 if "kdp" != GetConnectionProtocol():
1451 print "Target is not connected over kdp. Nothing to do here."
1454 # Set up the manual KDP packet
1455 input_address
= unsigned(addressof(kern
.globals.manual_pkt
.input))
1456 len_address
= unsigned(addressof(kern
.globals.manual_pkt
.len))
1457 data_address
= unsigned(addressof(kern
.globals.manual_pkt
.data
))
1458 if not WriteInt32ToMemoryAddress(0, input_address
):
1459 print "0x{0: <4x}: 0x{1: <1x}".format(addr
, result
)
1462 kdp_pkt_size
= GetType('kdp_readioport_req_t').GetByteSize()
1463 if not WriteInt32ToMemoryAddress(kdp_pkt_size
, len_address
):
1464 print "0x{0: <4x}: 0x{1: <1x}".format(addr
, result
)
1467 kgm_pkt
= kern
.GetValueFromAddress(data_address
, 'kdp_readioport_req_t *')
1469 header_value
= GetKDPPacketHeaderInt(request
=GetEnumValue('kdp_req_t::KDP_READIOPORT'), length
= kdp_pkt_size
)
1471 if( WriteInt64ToMemoryAddress((header_value
), int(addressof(kgm_pkt
.hdr
))) and
1472 WriteInt16ToMemoryAddress(addr
, int(addressof(kgm_pkt
.address
))) and
1473 WriteInt32ToMemoryAddress(numbytes
, int(addressof(kgm_pkt
.nbytes
))) and
1474 WriteInt16ToMemoryAddress(lcpu
, int(addressof(kgm_pkt
.lcpu
))) and
1475 WriteInt32ToMemoryAddress(1, input_address
)
1478 result_pkt
= Cast(addressof(kern
.globals.manual_pkt
.data
), 'kdp_readioport_reply_t *')
1480 if(result_pkt
.error
== 0):
1482 result
= dereference(Cast(addressof(result_pkt
.data
), 'uint8_t *'))
1484 result
= dereference(Cast(addressof(result_pkt
.data
), 'uint16_t *'))
1486 result
= dereference(Cast(addressof(result_pkt
.data
), 'uint32_t *'))
1488 print "{0: <#6x}: {1:#0{2}x}".format(addr
, result
, (numbytes
*2)+2)
1490 def WriteIOPortInt(addr
, numbytes
, value
, lcpu
):
1491 """ Writes 'value' into ioport specified by 'addr'. Prints errors if it encounters any
1493 if "kdp" != GetConnectionProtocol():
1494 print "Target is not connected over kdp. Nothing to do here."
1497 # Set up the manual KDP packet
1498 input_address
= unsigned(addressof(kern
.globals.manual_pkt
.input))
1499 len_address
= unsigned(addressof(kern
.globals.manual_pkt
.len))
1500 data_address
= unsigned(addressof(kern
.globals.manual_pkt
.data
))
1501 if not WriteInt32ToMemoryAddress(0, input_address
):
1502 print "error writing {0: #x} to port {1: <#6x}: failed to write 0 to input_address".format(value
, addr
)
1505 kdp_pkt_size
= GetType('kdp_writeioport_req_t').GetByteSize()
1506 if not WriteInt32ToMemoryAddress(kdp_pkt_size
, len_address
):
1507 print "error writing {0: #x} to port {1: <#6x}: failed to write kdp_pkt_size".format(value
, addr
)
1510 kgm_pkt
= kern
.GetValueFromAddress(data_address
, 'kdp_writeioport_req_t *')
1512 header_value
= GetKDPPacketHeaderInt(request
=GetEnumValue('kdp_req_t::KDP_WRITEIOPORT'), length
= kdp_pkt_size
)
1514 if( WriteInt64ToMemoryAddress((header_value
), int(addressof(kgm_pkt
.hdr
))) and
1515 WriteInt16ToMemoryAddress(addr
, int(addressof(kgm_pkt
.address
))) and
1516 WriteInt32ToMemoryAddress(numbytes
, int(addressof(kgm_pkt
.nbytes
))) and
1517 WriteInt16ToMemoryAddress(lcpu
, int(addressof(kgm_pkt
.lcpu
)))
1520 if not WriteInt8ToMemoryAddress(value
, int(addressof(kgm_pkt
.data
))):
1521 print "error writing {0: #x} to port {1: <#6x}: failed to write 8 bit data".format(value
, addr
)
1524 if not WriteInt16ToMemoryAddress(value
, int(addressof(kgm_pkt
.data
))):
1525 print "error writing {0: #x} to port {1: <#6x}: failed to write 16 bit data".format(value
, addr
)
1528 if not WriteInt32ToMemoryAddress(value
, int(addressof(kgm_pkt
.data
))):
1529 print "error writing {0: #x} to port {1: <#6x}: failed to write 32 bit data".format(value
, addr
)
1531 if not WriteInt32ToMemoryAddress(1, input_address
):
1532 print "error writing {0: #x} to port {1: <#6x}: failed to write to input_address".format(value
, addr
)
1535 result_pkt
= Cast(addressof(kern
.globals.manual_pkt
.data
), 'kdp_writeioport_reply_t *')
1537 # Done with the write
1538 if(result_pkt
.error
== 0):
1539 print "Writing {0: #x} to port {1: <#6x} was successful".format(value
, addr
)
1541 print "error writing {0: #x} to port {1: <#6x}".format(value
, addr
)
1543 @lldb_command('showinterruptcounts')
1544 def showinterruptcounts(cmd_args
=None):
1545 """ Shows event source based interrupt counts by nub name and interrupt index.
1546 Does not cover interrupts that are not event source based. Will report 0
1547 if interrupt accounting is disabled.
1550 header_format
= "{0: <20s} {1: >5s} {2: >20s}"
1551 content_format
= "{0: <20s} {1: >5d} {2: >20d}"
1553 print header_format
.format("Name", "Index", "Count")
1555 for i
in kern
.interrupt_stats
:
1556 owner
= CastIOKitClass(i
.owner
, 'IOInterruptEventSource *')
1557 nub
= CastIOKitClass(owner
.provider
, 'IORegistryEntry *')
1560 # To uniquely identify an interrupt, we need the nub name and the index. The index
1561 # is stored with the stats object, but we need to retrieve the name.
1563 registryTable
= nub
.fRegistryTable
1564 propertyTable
= nub
.fPropertyTable
1566 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
1568 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
1570 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
1573 nub_name
= "Unknown"
1575 nub_name
= GetString(CastIOKitClass(name
, 'OSString *'))
1577 # We now have everything we need; spew the requested data.
1579 interrupt_index
= i
.interruptIndex
1580 first_level_count
= i
.interruptStatistics
[0]
1582 print content_format
.format(nub_name
, interrupt_index
, first_level_count
)
1586 @lldb_command('showinterruptstats')
1587 def showinterruptstats(cmd_args
=None):
1588 """ Shows event source based interrupt statistics by nub name and interrupt index.
1589 Does not cover interrupts that are not event source based. Will report 0
1590 if interrupt accounting is disabled, or if specific statistics are disabled.
1591 Time is reported in ticks of mach_absolute_time. Statistics are:
1593 Interrupt Count: Number of times the interrupt context handler was run
1594 Interrupt Time: Total time spent in the interrupt context handler (if any)
1595 Workloop Count: Number of times the kernel context handler was run
1596 Workloop CPU Time: Total CPU time spent running the kernel context handler
1597 Workloop Time: Total time spent running the kernel context handler
1600 header_format
= "{0: <20s} {1: >5s} {2: >20s} {3: >20s} {4: >20s} {5: >20s} {6: >20s} {7: >20s} {8: >20s} {9: >20s}"
1601 content_format
= "{0: <20s} {1: >5d} {2: >20d} {3: >20d} {4: >20d} {5: >20d} {6: >20d} {7: >20d} {8: >20d} {9: >#20x}"
1603 print header_format
.format("Name", "Index", "Interrupt Count", "Interrupt Time", "Avg Interrupt Time", "Workloop Count", "Workloop CPU Time", "Workloop Time", "Avg Workloop Time", "Owner")
1605 for i
in kern
.interrupt_stats
:
1606 owner
= CastIOKitClass(i
.owner
, 'IOInterruptEventSource *')
1607 nub
= CastIOKitClass(owner
.provider
, 'IORegistryEntry *')
1610 # To uniquely identify an interrupt, we need the nub name and the index. The index
1611 # is stored with the stats object, but we need to retrieve the name.
1613 registryTable
= nub
.fRegistryTable
1614 propertyTable
= nub
.fPropertyTable
1616 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIOServicePlane
.nameKey
)
1618 name
= LookupKeyInOSDict(registryTable
, kern
.globals.gIONameKey
)
1620 name
= LookupKeyInOSDict(propertyTable
, kern
.globals.gIOClassKey
)
1623 nub_name
= "Unknown"
1625 nub_name
= GetString(CastIOKitClass(name
, 'OSString *'))
1627 # We now have everything we need; spew the requested data.
1629 interrupt_index
= i
.interruptIndex
1630 first_level_count
= i
.interruptStatistics
[0]
1631 second_level_count
= i
.interruptStatistics
[1]
1632 first_level_time
= i
.interruptStatistics
[2]
1633 second_level_cpu_time
= i
.interruptStatistics
[3]
1634 second_level_system_time
= i
.interruptStatistics
[4]
1636 avg_first_level_time
= 0
1637 if first_level_count
!= 0:
1638 avg_first_level_time
= first_level_time
/ first_level_count
1640 avg_second_level_time
= 0
1641 if second_level_count
!= 0:
1642 avg_second_level_time
= second_level_system_time
/ second_level_count
1644 print content_format
.format(nub_name
, interrupt_index
, first_level_count
, first_level_time
, avg_first_level_time
,
1645 second_level_count
, second_level_cpu_time
, second_level_system_time
, avg_second_level_time
, owner
)
1649 def GetRegistryPlane(plane_name
):
1651 Given plane_name, returns IORegistryPlane * object or None if there's no such registry plane
1653 return LookupKeyInOSDict(kern
.globals.gIORegistryPlanes
, plane_name
, CompareStringToOSSymbol
)
1655 def DecodePreoslogSource(source
):
1657 Given preoslog source, return a matching string representation
1659 source_to_str
= {0 : "iboot"}
1660 if source
in source_to_str
:
1661 return source_to_str
[source
]
1664 def GetPreoslogHeader():
1666 Scan IODeviceTree for preoslog and return a python representation of it
1668 edt_plane
= GetRegistryPlane("IODeviceTree")
1669 if edt_plane
is None:
1670 print "Couldn't obtain a pointer to IODeviceTree"
1673 # Registry API functions operate on "plane" global variable
1677 chosen
= FindRegistryObjectRecurse(kern
.globals.gRegistryRoot
, "chosen")
1679 print "Couldn't obtain /chosen IORegistryEntry"
1682 memory_map
= FindRegistryObjectRecurse(chosen
, "memory-map")
1683 if memory_map
is None:
1684 print "Couldn't obtain memory-map from /chosen"
1689 mm_preoslog
= LookupKeyInOSDict(memory_map
.fPropertyTable
, "preoslog", CompareStringToOSSymbol
)
1690 if mm_preoslog
is None:
1691 print "Couldn't find preoslog entry in memory-map"
1694 if mm_preoslog
.length
!= 16:
1695 print "preoslog entry in memory-map is malformed, expected len is 16, given len is {}".format(preoslog
.length
)
1698 data
= cast(mm_preoslog
.data
, "dtptr_t *")
1699 preoslog_paddr
= unsigned(data
[0])
1700 preoslog_vaddr
= kern
.PhysToKernelVirt(preoslog_paddr
)
1701 preoslog_size
= unsigned(data
[1])
1703 preoslog_header
= PreoslogHeader()
1705 # This structure defnition doesn't exist in xnu
1707 typedef struct __attribute__((packed)) {
1714 } preoslog_header_t;
1716 preoslog_header_ptr
= kern
.GetValueFromAddress(preoslog_vaddr
, "uint8_t *")
1717 preoslog_header
.magic
= preoslog_header_ptr
[0:4]
1718 preoslog_header
.source
= DecodePreoslogSource(unsigned(preoslog_header_ptr
[12]))
1719 preoslog_header
.wrapped
= unsigned(preoslog_header_ptr
[13])
1720 preoslog_header_ptr
= kern
.GetValueFromAddress(preoslog_vaddr
, "uint32_t *")
1721 preoslog_header
.size
= unsigned(preoslog_header_ptr
[1])
1722 preoslog_header
.offset
= unsigned(preoslog_header_ptr
[2])
1724 for i
in xrange(len(preoslog_header
.valid_magic
)):
1725 c
= chr(unsigned(preoslog_header
.magic
[i
]))
1726 if c
!= preoslog_header
.valid_magic
[i
]:
1727 string
= "Error: magic doesn't match, expected {:.4s}, given {:.4s}"
1728 print string
.format(preoslog_header
.valid_magic
, preoslog_header
.magic
)
1731 if preoslog_header
.size
!= preoslog_size
:
1732 string
= "Error: size mismatch preoslog_header.size ({}) != preoslog_size ({})"
1733 print string
.format(preoslog_header
.size
, preoslog_size
)
1736 preoslog_data_ptr
= kern
.GetValueFromAddress(preoslog_vaddr
+ 14, "char *")
1737 preoslog_header
.data
= preoslog_data_ptr
.sbvalue
.GetPointeeData(0, preoslog_size
)
1738 return preoslog_header
1740 @lldb_command("showpreoslog")
1741 def showpreoslog(cmd_args
=None):
1742 """ Display preoslog buffer """
1744 preoslog
= GetPreoslogHeader()
1745 if preoslog
is None:
1746 print "Error: couldn't obtain preoslog header"
1750 "----preoslog log header-----\n",
1751 "size - {} bytes\n",
1752 "write offset - {:#x}\n",
1755 "----preoslog log start------"
1758 print header
.format(preoslog
.size
, preoslog
.offset
, preoslog
.wrapped
, preoslog
.source
)
1760 err
= lldb
.SBError()
1761 if preoslog
.wrapped
> 0:
1762 print preoslog
.data
.GetString(err
, preoslog
.offset
+ 1)
1763 print preoslog
.data
.GetString(err
, 0)
1764 print "-----preoslog log end-------"