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