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