]> git.saurik.com Git - apple/xnu.git/blob - tools/lldbmacros/ioreg.py
74d2e3baadc06432218c8d654e90250ad5b44b88
[apple/xnu.git] / tools / lldbmacros / ioreg.py
1 from xnu import *
2 from utils import *
3 import sys
4
5 ######################################
6 # Globals
7 ######################################
8 plane = None
9
10 #####################################
11 # Utility functions.
12 #####################################
13 def CastIOKitClass(obj, target_type):
14 """ Type cast an object to another IOKIT CPP class.
15 params:
16 obj - core.value object representing some C construct in lldb
17 target_type - str : ex 'OSString *'
18 - lldb.SBType :
19 """
20 v = Cast(obj, target_type)
21 v.GetSBValue().SetPreferDynamicValue(lldb.eNoDynamicValues)
22 return v
23
24 ######################################
25 # Type Summaries
26 ######################################
27 @lldb_type_summary(['OSObject *'])
28 @header("")
29 def GetObjectSummary(obj):
30 """ Show info about an OSObject - its vtable ptr and retain count, & more info for simple container classes.
31 """
32 if obj is None:
33 return
34
35 vt = dereference(Cast(obj, 'uintptr_t *')) - 2 * sizeof('uintptr_t')
36 vtype = kern.SymbolicateFromAddress(vt)
37 if len(vtype):
38 vtype_str = " <" + vtype[0].GetName() + ">"
39 else:
40 vtype_str = ""
41 if hasattr(obj, 'retainCount'):
42 retCount = (obj.retainCount & 0xffff)
43 cntnrRetCount = (obj.retainCount >> 16)
44 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)
45 else:
46 out_string = "`object 0x{0: <16x}, vt 0x{1: <16x}{2:s}` ".format(obj, vt, vtype_str)
47
48 ztvAddr = kern.GetLoadAddressForSymbol('_ZTV8OSString')
49 if vt == ztvAddr:
50 out_string += GetString(obj)
51 return out_string
52
53 ztvAddr = kern.GetLoadAddressForSymbol('_ZTV8OSSymbol')
54 if vt == ztvAddr:
55 out_string += GetString(obj)
56 return out_string
57
58 ztvAddr = kern.GetLoadAddressForSymbol('_ZTV8OSNumber')
59 if vt == ztvAddr:
60 out_string += GetNumber(obj)
61 return out_string
62
63 ztvAddr = kern.GetLoadAddressForSymbol('_ZTV9OSBoolean')
64 if vt == ztvAddr:
65 out_string += GetBoolean(obj)
66 return out_string
67
68 ztvAddr = kern.GetLoadAddressForSymbol('_ZTV7OSArray')
69 if vt == ztvAddr:
70 out_string += "(" + GetArray(CastIOKitClass(obj, 'OSArray *')) + ")"
71 return out_string
72
73 ztvAddr = kern.GetLoadAddressForSymbol('_ZTV5OSSet')
74 if vt == ztvAddr:
75 out_string += GetSet(CastIOKitClass(obj, 'OSSet *'))
76 return out_string
77
78 ztvAddr = kern.GetLoadAddressForSymbol('_ZTV12OSDictionary')
79 if vt == ztvAddr:
80 out_string += GetDictionary(CastIOKitClass(obj, 'OSDictionary *'))
81 return out_string
82
83 return out_string
84
85
86 def GetObjectTypeStr(obj):
87 """ Return the type of an OSObject's container class
88 """
89 if obj is None:
90 return None
91
92 vt = dereference(Cast(obj, 'uintptr_t *')) - 2 * sizeof('uintptr_t')
93 vtype = kern.SymbolicateFromAddress(vt)
94 if len(vtype):
95 return vtype[0].GetName()
96
97 # See if the value is in a kext with no symbols
98 for kval in IterateLinkedList(kern.globals.kmod, 'next'):
99 if vt >= unsigned(kval.address) and vt <= (unsigned(kval.address) + unsigned(kval.size)):
100 return "kmod:{:s}+{:#0x}".format(kval.name, vt - unsigned(kval.address))
101 return None
102
103
104 @lldb_type_summary(['IORegistryEntry *'])
105 @header("")
106 def GetRegistryEntrySummary(entry):
107 """ returns a string containing summary information about an IORegistry
108 object including it's registry id , vtable ptr and retain count
109 """
110 name = None
111 out_string = ""
112 registryTable = entry.fRegistryTable
113 propertyTable = entry.fPropertyTable
114
115 name = LookupKeyInOSDict(registryTable, kern.globals.gIOServicePlane.nameKey)
116 if name is None:
117 name = LookupKeyInOSDict(registryTable, kern.globals.gIONameKey)
118 if name is None:
119 name = LookupKeyInOSDict(propertyTable, kern.globals.gIOClassKey)
120
121 if name is not None:
122 out_string += "+-o {0:s} ".format(GetString(CastIOKitClass(name, 'OSString *')))
123 elif CastIOKitClass(entry, 'IOService *').pwrMgt and CastIOKitClass(entry, 'IOService *').pwrMgt.Name:
124 out_string += "+-o {0:s} ".format(CastIOKitClass(entry, 'IOService *').pwrMgt.Name)
125 else:
126 out_string += "+-o ?? "
127
128 # I'm using uintptr_t for now to work around <rdar://problem/12749733> FindFirstType & Co. should allow you to make pointer types directly
129 vtableAddr = dereference(Cast(entry, 'uintptr_t *')) - 2 * sizeof('uintptr_t *')
130 vtype = kern.SymbolicateFromAddress(vtableAddr)
131 if vtype is None or len(vtype) < 1:
132 out_string += "<object 0x{0: <16x}, id 0x{1:x}, vtable 0x{2: <16x}".format(entry, CastIOKitClass(entry, 'IORegistryEntry *').reserved.fRegistryEntryID, vtableAddr)
133 else:
134 out_string += "<object 0x{0: <16x}, id 0x{1:x}, vtable 0x{2: <16x} <{3:s}>".format(entry, CastIOKitClass(entry, 'IORegistryEntry *').reserved.fRegistryEntryID,
135 vtableAddr, vtype[0].GetName())
136
137 ztvAddr = kern.GetLoadAddressForSymbol('_ZTV15IORegistryEntry')
138 if vtableAddr != ztvAddr:
139 out_string += ", "
140 state = CastIOKitClass(entry, 'IOService *').__state[0]
141 # kIOServiceRegisteredState
142 if 0 == state & 2:
143 out_string += "!"
144 out_string += "registered, "
145 # kIOServiceMatchedState
146 if 0 == state & 4:
147 out_string += "!"
148 out_string += "matched, "
149 #kIOServiceInactiveState
150 if 0 != state & 1:
151 out_string += "in"
152 busyCount = (CastIOKitClass(entry, 'IOService *').__state[1] & 0xff)
153 retCount = (CastIOKitClass(entry, 'IOService *').retainCount & 0xffff)
154 out_string += "active, busy {0}, retain count {1}>".format(busyCount, retCount)
155 return out_string
156
157 ######################################
158 # Commands
159 ######################################
160 @lldb_command('showallclasses')
161 def ShowAllClasses(cmd_args=None):
162 """ Show the instance counts and ivar size of all OSObject subclasses.
163 See ioclasscount man page for details
164 """
165 idx = 0
166 count = unsigned(kern.globals.sAllClassesDict.count)
167
168 while idx < count:
169 meta = CastIOKitClass(kern.globals.sAllClassesDict.dictionary[idx].value, 'OSMetaClass *')
170 idx += 1
171 print GetMetaClass(meta)
172
173 @lldb_command('showobject')
174 def ShowObject(cmd_args=None):
175 """ Show info about an OSObject - its vtable ptr and retain count, & more info for simple container classes.
176 """
177 if not cmd_args:
178 print "Please specify the address of the OSObject whose info you want to view. Type help showobject for help"
179 return
180
181 obj = kern.GetValueFromAddress(cmd_args[0], 'OSObject *')
182 print GetObjectSummary(obj)
183
184 #Macro: dumpobject
185 @lldb_command('dumpobject')
186 def DumpObject(cmd_args=None):
187 """ Dumps object information if it is a valid object confirmed by showobject
188 Usage: dumpobject <address of object to be dumped> [class/struct type of object]
189 """
190 if not cmd_args:
191 print "No arguments passed"
192 print DumpObject.__doc__
193 return False
194
195 if len(cmd_args) == 1:
196 try:
197 object_info = lldb_run_command("showobject {:s}".format(cmd_args[0]))
198 except:
199 print "Error!! showobject failed due to invalid value"
200 print DumpObject.__doc__
201 return False
202
203 srch = re.search(r'<vtable for ([A-Za-z].*)>', object_info)
204 if not srch:
205 print "Error!! Couldn't find object in registry, input type manually as 2nd argument"
206 print DumpObject.__doc__
207 return False
208
209 object_type = srch.group(1)
210 else:
211 type_lookup = lldb_run_command("image lookup -t {:s}".format(cmd_args[1]))
212 if type_lookup.find(cmd_args[1])!= -1:
213 object_type = cmd_args[1]
214 else:
215 print "Error!! Input type {:s} isn't available in image lookup".format(cmd_args[1])
216 return False
217
218 print "******** Object Dump for value \'{:s}\' with type \"{:s}\" ********".format(cmd_args[0], object_type)
219 print lldb_run_command("p/x *({:s}*){:s}".format(object_type, cmd_args[0]))
220
221 #EndMacro: dumpobject
222
223 @lldb_command('setregistryplane')
224 def SetRegistryPlane(cmd_args=None):
225 """ Set the plane to be used for the IOKit registry macros
226 syntax: (lldb) setregistryplane 0 - will display all known planes
227 syntax: (lldb) setregistryplane 0xaddr - will set the registry plane to 0xaddr
228 syntax: (lldb) setregistryplane gIODTPlane - will set the registry plane to gIODTPlane
229 """
230 if not cmd_args:
231 print "Please specify the name of the plane you want to use with the IOKit registry macros."
232 print SetRegistryPlane.__doc__
233
234 if cmd_args[0] == "0":
235 print GetObjectSummary(kern.globals.gIORegistryPlanes)
236 else:
237 global plane
238 plane = kern.GetValueFromAddress(cmd_args[0], 'IORegistryPlane *')
239 return
240
241 @lldb_command('showregistryentry')
242 def ShowRegistryEntry(cmd_args=None):
243 """ Show info about a registry entry; its properties and descendants in the current plane
244 syntax: (lldb) showregistryentry 0xaddr
245 syntax: (lldb) showregistryentry gIOPMRootDomain
246 """
247 if not cmd_args:
248 print "Please specify the address of the registry entry whose info you want to view."
249 print ShowRegistryEntry.__doc__
250 return
251
252 entry = kern.GetValueFromAddress(cmd_args[0], 'IORegistryEntry *')
253 ShowRegistryEntryRecurse(entry, "", True)
254
255 @lldb_command('showregistry')
256 def ShowRegistry(cmd_args=None):
257 """ Show info about all registry entries in the current plane
258 If prior to invoking this command no registry plane is specified
259 using 'setregistryplane', the command defaults to the IOService plane
260 """
261 ShowRegistryEntryRecurse(kern.globals.gRegistryRoot, "", False)
262
263 @lldb_command('showregistryprops')
264 def ShowRegistryProps(cmd_args=None):
265 """ Show info about all registry entries in the current plane, and their properties
266 If prior to invoking this command no registry plane is specified
267 using 'setregistryplane', the command defaults to the IOService plane
268 """
269 ShowRegistryEntryRecurse(kern.globals.gRegistryRoot, "", True)
270
271 @lldb_command('findregistryentry')
272 def FindRegistryEntry(cmd_args=None):
273 """ Search for registry entry that matches the given string
274 If prior to invoking this command no registry plane is specified
275 using 'setregistryplane', the command defaults to searching entries from the IOService plane
276 syntax: (lldb) findregistryentries AppleACPICPU - will find the first registry entry that matches AppleACPICPU
277 """
278 if not cmd_args:
279 print "Please specify the name of the registry entry you want to find"
280 print FindRegistryEntry.__doc__
281 return
282
283 FindRegistryEntryRecurse(kern.globals.gRegistryRoot, cmd_args[0], True)
284
285 @lldb_command('findregistryentries')
286 def FindRegistryEntries(cmd_args=None):
287 """ Search for all registry entries that match the given string
288 If prior to invoking this command no registry plane is specified
289 using 'setregistryplane', the command defaults to searching entries from the IOService plane
290 syntax: (lldb) findregistryentries AppleACPICPU - will find all registry entries that match AppleACPICPU
291 """
292 if not cmd_args:
293 print "Please specify the name of the registry entry/entries you want to find"
294 print FindRegistryEntries.__doc__
295 return
296
297 FindRegistryEntryRecurse(kern.globals.gRegistryRoot, cmd_args[0], False)
298
299 @lldb_command('findregistryprop')
300 def FindRegistryProp(cmd_args=None):
301 """ Given a registry entry, print out the contents for the property that matches
302 a specific string
303 syntax: (lldb) findregistryprop 0xaddr IOSleepSupported
304 syntax: (lldb) findregistryprop gIOPMRootDomain IOSleepSupported
305 syntax: (lldb) findregistryprop gIOPMRootDomain "Supported Features"
306 """
307 if not cmd_args or len(cmd_args) < 2:
308 print "Please specify the address of a IORegistry entry and the property you're looking for"
309 print FindRegistryProp.__doc__
310 return
311
312 entry = kern.GetValueFromAddress(cmd_args[0], 'IOService *')
313 propertyTable = entry.fPropertyTable
314 print GetObjectSummary(LookupKeyInPropTable(propertyTable, cmd_args[1]))
315
316 @lldb_command('readioport8')
317 def ReadIOPort8(cmd_args=None):
318 """ Read value stored in the specified IO port. The CPU can be optionally
319 specified as well.
320 Prints 0xBAD10AD in case of a bad read
321 Syntax: (lldb) readioport8 <port> [lcpu (kernel's numbering convention)]
322 """
323 if not cmd_args:
324 print "Please specify a port to read out of"
325 print ReadIOPort8.__doc__
326 return
327
328 portAddr = ArgumentStringToInt(cmd_args[0])
329 if len(cmd_args) >= 2:
330 lcpu = ArgumentStringToInt(cmd_args[1])
331 else:
332 lcpu = xnudefines.lcpu_self
333
334 ReadIOPortInt(portAddr, 1, lcpu)
335
336 @lldb_command('readioport16')
337 def ReadIOPort16(cmd_args=None):
338 """ Read value stored in the specified IO port. The CPU can be optionally
339 specified as well.
340 Prints 0xBAD10AD in case of a bad read
341 Syntax: (lldb) readioport16 <port> [lcpu (kernel's numbering convention)]
342 """
343 if not cmd_args:
344 print "Please specify a port to read out of"
345 print ReadIOPort16.__doc__
346 return
347
348 portAddr = ArgumentStringToInt(cmd_args[0])
349 if len(cmd_args) >= 2:
350 lcpu = ArgumentStringToInt(cmd_args[1])
351 else:
352 lcpu = xnudefines.lcpu_self
353
354 ReadIOPortInt(portAddr, 2, lcpu)
355
356 @lldb_command('readioport32')
357 def ReadIOPort32(cmd_args=None):
358 """ Read value stored in the specified IO port. The CPU can be optionally
359 specified as well.
360 Prints 0xBAD10AD in case of a bad read
361 Syntax: (lldb) readioport32 <port> [lcpu (kernel's numbering convention)]
362 """
363 if not cmd_args:
364 print "Please specify a port to read out of"
365 print ReadIOPort32.__doc__
366 return
367
368 portAddr = ArgumentStringToInt(cmd_args[0])
369 if len(cmd_args) >= 2:
370 lcpu = ArgumentStringToInt(cmd_args[1])
371 else:
372 lcpu = xnudefines.lcpu_self
373
374 ReadIOPortInt(portAddr, 4, lcpu)
375
376 @lldb_command('writeioport8')
377 def WriteIOPort8(cmd_args=None):
378 """ Write the value to the specified IO port. The size of the value is
379 determined by the name of the command. The CPU used can be optionally
380 specified as well.
381 Syntax: (lldb) writeioport8 <port> <value> [lcpu (kernel's numbering convention)]
382 """
383 if not cmd_args or len(cmd_args) < 2:
384 print "Please specify a port to write to, followed by the value you want to write"
385 print WriteIOPort8.__doc__
386 return
387
388 portAddr = ArgumentStringToInt(cmd_args[0])
389 value = ArgumentStringToInt(cmd_args[1])
390
391 if len(cmd_args) >= 3:
392 lcpu = ArgumentStringToInt(cmd_args[2])
393 else:
394 lcpu = xnudefines.lcpu_self
395
396 WriteIOPortInt(portAddr, 1, value, lcpu)
397
398 @lldb_command('writeioport16')
399 def WriteIOPort16(cmd_args=None):
400 """ Write the value to the specified IO port. The size of the value is
401 determined by the name of the command. The CPU used can be optionally
402 specified as well.
403 Syntax: (lldb) writeioport16 <port> <value> [lcpu (kernel's numbering convention)]
404 """
405 if not cmd_args or len(cmd_args) < 2:
406 print "Please specify a port to write to, followed by the value you want to write"
407 print WriteIOPort16.__doc__
408 return
409
410 portAddr = ArgumentStringToInt(cmd_args[0])
411 value = ArgumentStringToInt(cmd_args[1])
412
413 if len(cmd_args) >= 3:
414 lcpu = ArgumentStringToInt(cmd_args[2])
415 else:
416 lcpu = xnudefines.lcpu_self
417
418 WriteIOPortInt(portAddr, 2, value, lcpu)
419
420 @lldb_command('writeioport32')
421 def WriteIOPort32(cmd_args=None):
422 """ Write the value to the specified IO port. The size of the value is
423 determined by the name of the command. The CPU used can be optionally
424 specified as well.
425 Syntax: (lldb) writeioport32 <port> <value> [lcpu (kernel's numbering convention)]
426 """
427 if not cmd_args or len(cmd_args) < 2:
428 print "Please specify a port to write to, followed by the value you want to write"
429 print WriteIOPort32.__doc__
430 return
431
432 portAddr = ArgumentStringToInt(cmd_args[0])
433 value = ArgumentStringToInt(cmd_args[1])
434
435 if len(cmd_args) >= 3:
436 lcpu = ArgumentStringToInt(cmd_args[2])
437 else:
438 lcpu = xnudefines.lcpu_self
439
440 WriteIOPortInt(portAddr, 4, value, lcpu)
441
442 @lldb_command('showioservicepm')
443 def ShowIOServicePM(cmd_args=None):
444 """ Routine to dump the IOServicePM object
445 Syntax: (lldb) showioservicepm <IOServicePM pointer>
446 """
447 if not cmd_args:
448 print "Please enter the pointer to the IOServicePM object you'd like to introspect"
449 print ShowIOServicePM.__doc__
450 return
451
452 iopmpriv = kern.GetValueFromAddress(cmd_args[0], 'IOServicePM *')
453 out_string = "MachineState {0: <6d} (".format(iopmpriv.MachineState)
454
455 # Power state map
456 pstate_map = {
457 0: 'kIOPM_Finished',
458 1: 'kIOPM_OurChangeTellClientsPowerDown',
459 2: 'kIOPM_OurChangeTellClientsPowerDown',
460 3: 'kIOPM_OurChangeNotifyInterestedDriversWillChange',
461 4: 'kIOPM_OurChangeSetPowerState',
462 5: 'kIOPM_OurChangeWaitForPowerSettle',
463 6: 'kIOPM_OurChangeNotifyInterestedDriversDidChange',
464 7: 'kIOPM_OurChangeTellCapabilityDidChange',
465 8: 'kIOPM_OurChangeFinish',
466 9: 'Unused_MachineState_9',
467 10: 'kIOPM_ParentChangeTellPriorityClientsPowerDown',
468 11: 'kIOPM_ParentChangeNotifyInterestedDriversWillChange',
469 12: 'kIOPM_ParentChangeSetPowerState',
470 13: 'kIOPM_ParentChangeWaitForPowerSettle',
471 14: 'kIOPM_ParentChangeNotifyInterestedDriversDidChange',
472 15: 'kIOPM_ParentChangeTellCapabilityDidChange',
473 16: 'kIOPM_ParentChangeAcknowledgePowerChange',
474 17: 'kIOPM_NotifyChildrenStart',
475 18: 'kIOPM_NotifyChildrenOrdered',
476 19: 'kIOPM_NotifyChildrenDelayed',
477 20: 'kIOPM_SyncTellClientsPowerDown',
478 21: 'kIOPM_SyncTellPriorityClientsPowerDown',
479 22: 'kIOPM_SyncNotifyWillChange',
480 23: 'kIOPM_SyncNotifyDidChange',
481 24: 'kIOPM_SyncTellCapabilityDidChange',
482 25: 'kIOPM_SyncFinish',
483 26: 'kIOPM_TellCapabilityChangeDone',
484 27: 'kIOPM_DriverThreadCallDone'
485 }
486 powerstate = unsigned(iopmpriv.MachineState)
487 if powerstate in pstate_map:
488 out_string += "{0:s}".format(pstate_map[powerstate])
489 else:
490 out_string += "Unknown_MachineState"
491 out_string += "), "
492
493 if iopmpriv.MachineState != 20:
494 out_string += "DriverTimer = {0: <6d}, SettleTime = {1: < 6d}, HeadNoteFlags = {2: #12x}, HeadNotePendingAcks = {3: #012x}, ".format(
495 unsigned(iopmpriv.DriverTimer),
496 unsigned(iopmpriv.SettleTimeUS),
497 unsigned(iopmpriv.HeadNoteChangeFlags),
498 unsigned(iopmpriv.HeadNotePendingAcks))
499
500 if iopmpriv.DeviceOverrideEnabled != 0:
501 out_string += "DeviceOverrides, "
502
503 out_string += "DeviceDesire = {0: <6d}, DesiredPowerState = {1: <6d}, PreviousRequest = {2: <6d}\n".format(
504 unsigned(iopmpriv.DeviceDesire),
505 unsigned(iopmpriv.DesiredPowerState),
506 unsigned(iopmpriv.PreviousRequestPowerFlags))
507
508 print out_string
509
510 ######################################
511 # Helper routines
512 ######################################
513 def ShowRegistryEntryRecurse(entry, prefix, printProps):
514 """ prints registry entry summary and recurses through all its children.
515 """
516 # Setup
517 global plane
518 out_string = ""
519 plen = (len(prefix)//2)
520 registryTable = entry.fRegistryTable
521 propertyTable = entry.fPropertyTable
522
523 # Print entry details
524 print "{0:s}{1:s}".format(prefix, GetRegistryEntrySummary(entry))
525 # Printing large property tables make it look like lldb is 'stuck'
526 if printProps:
527 print GetRegDictionary(propertyTable, prefix + " | ")
528
529 # Recurse
530 if plane is None:
531 childKey = kern.globals.gIOServicePlane.keys[1]
532 else:
533 childKey = plane.keys[1]
534 childArray = LookupKeyInOSDict(registryTable, childKey)
535 if childArray is not None:
536 idx = 0
537 ca = CastIOKitClass(childArray, 'OSArray *')
538 count = unsigned(ca.count)
539 while idx < count:
540 if plen != 0 and plen != 1 and (plen & (plen - 1)) == 0:
541 ShowRegistryEntryRecurse(CastIOKitClass(ca.array[idx], 'IORegistryEntry *'), prefix + "| ", printProps)
542 else:
543 ShowRegistryEntryRecurse(CastIOKitClass(ca.array[idx], 'IORegistryEntry *'), prefix + " ", printProps)
544 idx += 1
545
546 def FindRegistryEntryRecurse(entry, search_name, stopAfterFirst):
547 """ Checks if given registry entry's name matches the search_name we're looking for
548 If yes, it prints the entry's summary and then recurses through its children
549 If no, it does nothing and recurses through its children
550 """
551 # Setup
552 global plane
553 registryTable = entry.fRegistryTable
554 propertyTable = entry.fPropertyTable
555
556 # Compare
557 name = None
558 name = LookupKeyInOSDict(registryTable, kern.globals.gIOServicePlane.nameKey)
559 if name is None:
560 name = LookupKeyInOSDict(registryTable, kern.globals.gIONameKey)
561 if name is None:
562 name = LookupKeyInOSDict(propertyTable, kern.globals.gIOClassKey)
563
564 if name is not None:
565 if str(CastIOKitClass(name, 'OSString *').string) == search_name:
566 print GetRegistryEntrySummary(entry)
567 if stopAfterFirst is True:
568 return True
569 elif CastIOKitClass(entry, 'IOService *').pwrMgt and CastIOKitClass(entry, 'IOService *').pwrMgt.Name:
570 name = CastIOKitClass(entry, 'IOService *').pwrMgt.Name
571 if str(name) == search_name:
572 print GetRegistryEntrySummary(entry)
573 if stopAfterFirst is True:
574 return True
575
576 # Recurse
577 if plane is None:
578 childKey = kern.globals.gIOServicePlane.keys[1]
579 else:
580 childKey = plane.keys[1]
581 childArray = LookupKeyInOSDict(registryTable, childKey)
582 if childArray is not None:
583 idx = 0
584 ca = CastIOKitClass(childArray, 'OSArray *')
585 count = unsigned(ca.count)
586 while idx < count:
587 if FindRegistryEntryRecurse(CastIOKitClass(ca.array[idx], 'IORegistryEntry *'), search_name, stopAfterFirst) is True:
588 return True
589 idx += 1
590 return False
591
592 def FindRegistryObjectRecurse(entry, search_name):
593 """ Checks if given registry entry's name matches the search_name we're looking for
594 If yes, return the entry
595 If no, it does nothing and recurses through its children
596 Implicitly stops after finding the first entry
597 """
598 # Setup
599 global plane
600 registryTable = entry.fRegistryTable
601 propertyTable = entry.fPropertyTable
602
603 # Compare
604 name = None
605 name = LookupKeyInOSDict(registryTable, kern.globals.gIOServicePlane.nameKey)
606 if name is None:
607 name = LookupKeyInOSDict(registryTable, kern.globals.gIONameKey)
608 if name is None:
609 name = LookupKeyInOSDict(propertyTable, kern.globals.gIOClassKey)
610
611 if name is not None:
612 if str(CastIOKitClass(name, 'OSString *').string) == search_name:
613 return entry
614 elif CastIOKitClass(entry, 'IOService *').pwrMgt and CastIOKitClass(entry, 'IOService *').pwrMgt.Name:
615 name = CastIOKitClass(entry, 'IOService *').pwrMgt.Name
616 if str(name) == search_name:
617 return entry
618
619 # Recurse
620 if plane is None:
621 childKey = kern.globals.gIOServicePlane.keys[1]
622 else:
623 childKey = plane.keys[1]
624 childArray = LookupKeyInOSDict(registryTable, childKey)
625 if childArray is not None:
626 ca = CastIOKitClass(childArray, 'OSArray *')
627 for idx in range(ca.count):
628 registry_object = FindRegistryObjectRecurse(CastIOKitClass(ca.array[idx], 'IORegistryEntry *'), search_name)
629 if not registry_object or int(registry_object) == int(0):
630 continue
631 else:
632 return registry_object
633 return None
634
635 def LookupKeyInOSDict(osdict, key):
636 """ Returns the value corresponding to a given key in a OSDictionary
637 Returns None if the key was not found
638 """
639 if not osdict:
640 return
641 count = unsigned(osdict.count)
642 result = None
643 idx = 0
644 while idx < count and result is None:
645 if key == osdict.dictionary[idx].key:
646 result = osdict.dictionary[idx].value
647 idx += 1
648 return result
649
650 def LookupKeyInPropTable(propertyTable, key_str):
651 """ Returns the value corresponding to a given key from a registry entry's property table
652 Returns None if the key was not found
653 The property that is being searched for is specified as a string in key_str
654 """
655 if not propertyTable:
656 return
657 count = unsigned(propertyTable.count)
658 result = None
659 idx = 0
660 while idx < count and result is None:
661 if key_str == str(propertyTable.dictionary[idx].key.string):
662 result = propertyTable.dictionary[idx].value
663 idx += 1
664 return result
665
666 def GetRegDictionary(osdict, prefix):
667 """ Returns a specially formatted string summary of the given OSDictionary
668 This is done in order to pretty-print registry property tables in showregistry
669 and other macros
670 """
671 out_string = prefix + "{\n"
672 idx = 0
673 count = unsigned(osdict.count)
674
675 while idx < count:
676 out_string += prefix + " " + GetObjectSummary(osdict.dictionary[idx].key) + " = " + GetObjectSummary(osdict.dictionary[idx].value) + "\n"
677 idx += 1
678 out_string += prefix + "}\n"
679 return out_string
680
681 def GetString(string):
682 """ Returns the python string representation of a given OSString
683 """
684 out_string = "\"{0:s}\"".format(CastIOKitClass(string, 'OSString *').string)
685 return out_string
686
687 def GetNumber(num):
688 out_string = "{0:d}".format(CastIOKitClass(num, 'OSNumber *').value)
689 return out_string
690
691 def GetBoolean(b):
692 """ Shows info about a given OSBoolean
693 """
694 out_string = ""
695 if b == kern.globals.gOSBooleanFalse:
696 out_string += "No"
697 else:
698 out_string += "Yes"
699 return out_string
700
701 def GetMetaClass(mc):
702 """ Shows info about a given OSSymbol
703 """
704 out_string = "{0: <5d}x {1: >5d} bytes {2:s}\n".format(mc.instanceCount, mc.classSize, mc.className.string)
705 return out_string
706
707 def GetArray(arr):
708 """ Returns a string containing info about a given OSArray
709 """
710 out_string = ""
711 idx = 0
712 count = unsigned(arr.count)
713
714 while idx < count:
715 obj = arr.array[idx]
716 idx += 1
717 out_string += GetObjectSummary(obj)
718 if idx < unsigned(arr.count):
719 out_string += ","
720 return out_string
721
722 def GetDictionary(d):
723 """ Returns a string containing info about a given OSDictionary
724 """
725 out_string = "{"
726 idx = 0
727 count = unsigned(d.count)
728
729 while idx < count:
730 obj = d.dictionary[idx].key
731 out_string += GetObjectSummary(obj) + "="
732 obj = d.dictionary[idx].value
733 idx += 1
734 out_string += GetObjectSummary(obj)
735 if idx < count:
736 out_string += ","
737 out_string += "}"
738 return out_string
739
740 def GetSet(se):
741 """ Returns a string containing info about a given OSSet
742 """
743 out_string += "[" + GetArray(se.members) + "]"
744 return out_string
745
746 def ReadIOPortInt(addr, numbytes, lcpu):
747 """ Prints results after reading a given ioport
748 """
749 result = 0xBAD10AD
750
751 if "kdp" != GetConnectionProtocol():
752 print "Target is not connected over kdp. Nothing to do here."
753 return
754
755 # Set up the manual KDP packet
756 input_address = unsigned(addressof(kern.globals.manual_pkt.input))
757 len_address = unsigned(addressof(kern.globals.manual_pkt.len))
758 data_address = unsigned(addressof(kern.globals.manual_pkt.data))
759 if not WriteInt32ToMemoryAddress(0, input_address):
760 print "0x{0: <4x}: 0x{1: <1x}".format(addr, result)
761 return
762
763 kdp_pkt_size = GetType('kdp_readioport_req_t').GetByteSize()
764 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address):
765 print "0x{0: <4x}: 0x{1: <1x}".format(addr, result)
766 return
767
768 kgm_pkt = kern.GetValueFromAddress(data_address, 'kdp_readioport_req_t *')
769
770 header_value = GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_READIOPORT'), length = kdp_pkt_size)
771
772 if( WriteInt64ToMemoryAddress((header_value), int(addressof(kgm_pkt.hdr))) and
773 WriteInt16ToMemoryAddress(addr, int(addressof(kgm_pkt.address))) and
774 WriteInt32ToMemoryAddress(numbytes, int(addressof(kgm_pkt.nbytes))) and
775 WriteInt16ToMemoryAddress(lcpu, int(addressof(kgm_pkt.lcpu))) and
776 WriteInt32ToMemoryAddress(1, input_address)
777 ):
778
779 result_pkt = Cast(addressof(kern.globals.manual_pkt.data), 'kdp_readioport_reply_t *')
780
781 if(result_pkt.error == 0):
782 if numbytes == 1:
783 result = dereference(Cast(addressof(result_pkt.data), 'uint8_t *'))
784 elif numbytes == 2:
785 result = dereference(Cast(addressof(result_pkt.data), 'uint16_t *'))
786 elif numbytes == 4:
787 result = dereference(Cast(addressof(result_pkt.data), 'uint32_t *'))
788
789 print "{0: <#6x}: {1:#0{2}x}".format(addr, result, (numbytes*2)+2)
790
791 def WriteIOPortInt(addr, numbytes, value, lcpu):
792 """ Writes 'value' into ioport specified by 'addr'. Prints errors if it encounters any
793 """
794 if "kdp" != GetConnectionProtocol():
795 print "Target is not connected over kdp. Nothing to do here."
796 return
797
798 # Set up the manual KDP packet
799 input_address = unsigned(addressof(kern.globals.manual_pkt.input))
800 len_address = unsigned(addressof(kern.globals.manual_pkt.len))
801 data_address = unsigned(addressof(kern.globals.manual_pkt.data))
802 if not WriteInt32ToMemoryAddress(0, input_address):
803 print "error writing {0: #x} to port {1: <#6x}: failed to write 0 to input_address".format(value, addr)
804 return
805
806 kdp_pkt_size = GetType('kdp_writeioport_req_t').GetByteSize()
807 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address):
808 print "error writing {0: #x} to port {1: <#6x}: failed to write kdp_pkt_size".format(value, addr)
809 return
810
811 kgm_pkt = kern.GetValueFromAddress(data_address, 'kdp_writeioport_req_t *')
812
813 header_value = GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_WRITEIOPORT'), length = kdp_pkt_size)
814
815 if( WriteInt64ToMemoryAddress((header_value), int(addressof(kgm_pkt.hdr))) and
816 WriteInt16ToMemoryAddress(addr, int(addressof(kgm_pkt.address))) and
817 WriteInt32ToMemoryAddress(numbytes, int(addressof(kgm_pkt.nbytes))) and
818 WriteInt16ToMemoryAddress(lcpu, int(addressof(kgm_pkt.lcpu)))
819 ):
820 if numbytes == 1:
821 if not WriteInt8ToMemoryAddress(value, int(addressof(kgm_pkt.data))):
822 print "error writing {0: #x} to port {1: <#6x}: failed to write 8 bit data".format(value, addr)
823 return
824 elif numbytes == 2:
825 if not WriteInt16ToMemoryAddress(value, int(addressof(kgm_pkt.data))):
826 print "error writing {0: #x} to port {1: <#6x}: failed to write 16 bit data".format(value, addr)
827 return
828 elif numbytes == 4:
829 if not WriteInt32ToMemoryAddress(value, int(addressof(kgm_pkt.data))):
830 print "error writing {0: #x} to port {1: <#6x}: failed to write 32 bit data".format(value, addr)
831 return
832 if not WriteInt32ToMemoryAddress(1, input_address):
833 print "error writing {0: #x} to port {1: <#6x}: failed to write to input_address".format(value, addr)
834 return
835
836 result_pkt = Cast(addressof(kern.globals.manual_pkt.data), 'kdp_writeioport_reply_t *')
837
838 # Done with the write
839 if(result_pkt.error == 0):
840 print "Writing {0: #x} to port {1: <#6x} was successful".format(value, addr)
841 else:
842 print "error writing {0: #x} to port {1: <#6x}".format(value, addr)
843
844 @lldb_command('showinterruptcounts')
845 def showinterruptcounts(cmd_args=None):
846 """ Shows event source based interrupt counts by nub name and interrupt index.
847 Does not cover interrupts that are not event source based. Will report 0
848 if interrupt accounting is disabled.
849 """
850
851 header_format = "{0: <20s} {1: >5s} {2: >20s}"
852 content_format = "{0: <20s} {1: >5d} {2: >20d}"
853
854 print header_format.format("Name", "Index", "Count")
855
856 for i in kern.interrupt_stats:
857 owner = CastIOKitClass(i.owner, 'IOInterruptEventSource *')
858 nub = CastIOKitClass(owner.provider, 'IORegistryEntry *')
859 name = None
860
861 # To uniquely identify an interrupt, we need the nub name and the index. The index
862 # is stored with the stats object, but we need to retrieve the name.
863
864 registryTable = nub.fRegistryTable
865 propertyTable = nub.fPropertyTable
866
867 name = LookupKeyInOSDict(registryTable, kern.globals.gIOServicePlane.nameKey)
868 if name is None:
869 name = LookupKeyInOSDict(registryTable, kern.globals.gIONameKey)
870 if name is None:
871 name = LookupKeyInOSDict(propertyTable, kern.globals.gIOClassKey)
872
873 if name is None:
874 nub_name = "Unknown"
875 else:
876 nub_name = GetString(CastIOKitClass(name, 'OSString *'))
877
878 # We now have everything we need; spew the requested data.
879
880 interrupt_index = i.interruptIndex
881 first_level_count = i.interruptStatistics[0]
882
883 print content_format.format(nub_name, interrupt_index, first_level_count)
884
885 return True
886
887 @lldb_command('showinterruptstats')
888 def showinterruptstats(cmd_args=None):
889 """ Shows event source based interrupt statistics by nub name and interrupt index.
890 Does not cover interrupts that are not event source based. Will report 0
891 if interrupt accounting is disabled, or if specific statistics are disabled.
892 Time is reported in ticks of mach_absolute_time. Statistics are:
893
894 Interrupt Count: Number of times the interrupt context handler was run
895 Interrupt Time: Total time spent in the interrupt context handler (if any)
896 Workloop Count: Number of times the kernel context handler was run
897 Workloop CPU Time: Total CPU time spent running the kernel context handler
898 Workloop Time: Total time spent running the kernel context handler
899 """
900
901 header_format = "{0: <20s} {1: >5s} {2: >20s} {3: >20s} {4: >20s} {5: >20s} {6: >20s} {7: >20s} {8: >20s} {9: >20s}"
902 content_format = "{0: <20s} {1: >5d} {2: >20d} {3: >20d} {4: >20d} {5: >20d} {6: >20d} {7: >20d} {8: >20d} {9: >#20x}"
903
904 print header_format.format("Name", "Index", "Interrupt Count", "Interrupt Time", "Avg Interrupt Time", "Workloop Count", "Workloop CPU Time", "Workloop Time", "Avg Workloop Time", "Owner")
905
906 for i in kern.interrupt_stats:
907 owner = CastIOKitClass(i.owner, 'IOInterruptEventSource *')
908 nub = CastIOKitClass(owner.provider, 'IORegistryEntry *')
909 name = None
910
911 # To uniquely identify an interrupt, we need the nub name and the index. The index
912 # is stored with the stats object, but we need to retrieve the name.
913
914 registryTable = nub.fRegistryTable
915 propertyTable = nub.fPropertyTable
916
917 name = LookupKeyInOSDict(registryTable, kern.globals.gIOServicePlane.nameKey)
918 if name is None:
919 name = LookupKeyInOSDict(registryTable, kern.globals.gIONameKey)
920 if name is None:
921 name = LookupKeyInOSDict(propertyTable, kern.globals.gIOClassKey)
922
923 if name is None:
924 nub_name = "Unknown"
925 else:
926 nub_name = GetString(CastIOKitClass(name, 'OSString *'))
927
928 # We now have everything we need; spew the requested data.
929
930 interrupt_index = i.interruptIndex
931 first_level_count = i.interruptStatistics[0]
932 second_level_count = i.interruptStatistics[1]
933 first_level_time = i.interruptStatistics[2]
934 second_level_cpu_time = i.interruptStatistics[3]
935 second_level_system_time = i.interruptStatistics[4]
936
937 avg_first_level_time = 0
938 if first_level_count != 0:
939 avg_first_level_time = first_level_time / first_level_count
940
941 avg_second_level_time = 0
942 if second_level_count != 0:
943 avg_second_level_time = second_level_system_time / second_level_count
944
945 print content_format.format(nub_name, interrupt_index, first_level_count, first_level_time, avg_first_level_time,
946 second_level_count, second_level_cpu_time, second_level_system_time, avg_second_level_time, owner)
947
948 return True
949