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