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