1from __future__ import absolute_import, division, print_function 2 3from builtins import chr 4from builtins import zip 5from builtins import hex 6from builtins import range 7from builtins import object 8 9from xnu import * 10from utils import * 11from kdp import * 12from core import caching 13from core.pointer import NativePointer 14import sys 15import lldb 16import os 17import sys 18from collections import deque 19 20###################################### 21# Globals 22###################################### 23plane = None 24 25##################################### 26# Utility functions. 27##################################### 28def CastIOKitClass(obj, target_type): 29 """ Type cast an object to another IOKIT CPP class. 30 params: 31 obj - core.value object representing some C construct in lldb 32 target_type - str : ex 'OSString *' 33 - lldb.SBType : 34 """ 35 v = obj.GetSBValue() 36 # We need to do that so that LLDB doesn't try to "helpfully" 37 # Guess which instance type it is... 38 v.SetPreferDynamicValue(lldb.eNoDynamicValues) 39 if isinstance(target_type, six.string_types): 40 target_type = gettype(target_type) 41 return value(v.Cast(target_type)) 42 43##################################### 44# Classes. 45##################################### 46class PreoslogHeader(object): 47 """ 48 Represents preoslog buffer header. There's no symbol in the kernel for it. 49 """ 50 valid_magic = "POSL" 51 def __init__(self): 52 self.magic = "" 53 self.offset = 0 54 self.size = 0 55 self.source = 0 56 self.wrapped = 0 57 self.data = None 58 59 60class IOKitSmartPointer(NativePointer): 61 """ IOKit's smart pointer 62 63 Every smart pointer inherits from libkern::intrusive_shared_ptr. 64 The real pointer is wrapped behind ptr_ member. 65 """ 66 67 @classmethod 68 def match(cls, sbvalue): 69 70 # Smart pointers in IOKit are OSSharedPtr and OSTaggedSharedPtr 71 name = sbvalue.GetType().GetCanonicalType().GetName() 72 if name.startswith(("OSSharedPtr", "OSTaggedSharedPtr")): 73 return cls() 74 75 return None 76 77 def GetPointerSBValue(self, sbvalue): 78 sbv = sbvalue.GetChildMemberWithName('ptr_') 79 return super(IOKitSmartPointer, self).GetPointerSBValue(sbv) 80 81 82###################################### 83# Type Summaries 84###################################### 85@lldb_type_summary(['OSObject *']) 86@header("") 87def GetObjectSummary(obj): 88 """ Show info about an OSObject - its vtable ptr and retain count, & more info for simple container classes. 89 """ 90 if obj is None: 91 return 92 93 vt = dereference(Cast(obj, 'uintptr_t *')) - 2 * sizeof('uintptr_t') 94 vt = kern.StripKernelPAC(vt) 95 vtype = kern.SymbolicateFromAddress(vt) 96 if len(vtype): 97 vtype_str = " <" + vtype[0].GetName() + ">" 98 else: 99 vtype_str = "" 100 if hasattr(obj, 'retainCount'): 101 retCount = (obj.retainCount & 0xffff) 102 cntnrRetCount = (obj.retainCount >> 16) 103 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) 104 else: 105 out_string = "`object 0x{0: <16x}, vt 0x{1: <16x}{2:s}` ".format(obj, vt, vtype_str) 106 107 ztvAddr = kern.GetLoadAddressForSymbol('_ZTV8OSString') 108 if vt == ztvAddr: 109 out_string += GetString(obj) 110 return out_string 111 112 ztvAddr = kern.GetLoadAddressForSymbol('_ZTV8OSSymbol') 113 if vt == ztvAddr: 114 out_string += GetString(obj) 115 return out_string 116 117 ztvAddr = kern.GetLoadAddressForSymbol('_ZTV8OSNumber') 118 if vt == ztvAddr: 119 out_string += GetNumber(obj) 120 return out_string 121 122 ztvAddr = kern.GetLoadAddressForSymbol('_ZTV9OSBoolean') 123 if vt == ztvAddr: 124 out_string += GetBoolean(obj) 125 return out_string 126 127 ztvAddr = kern.GetLoadAddressForSymbol('_ZTV7OSArray') 128 if vt == ztvAddr: 129 out_string += "(" + GetArray(CastIOKitClass(obj, 'OSArray *')) + ")" 130 return out_string 131 132 ztvAddr = kern.GetLoadAddressForSymbol('_ZTV5OSSet') 133 if vt == ztvAddr: 134 out_string += GetSet(CastIOKitClass(obj, 'OSSet *')) 135 return out_string 136 137 ztvAddr = kern.GetLoadAddressForSymbol('_ZTV12OSDictionary') 138 if vt == ztvAddr: 139 out_string += GetDictionary(CastIOKitClass(obj, 'OSDictionary *')) 140 return out_string 141 142 return out_string 143 144 145def GetObjectTypeStr(obj): 146 """ Return the type of an OSObject's container class 147 """ 148 if obj is None: 149 return None 150 151 vt = dereference(Cast(obj, 'uintptr_t *')) - 2 * sizeof('uintptr_t') 152 vt = kern.StripKernelPAC(vt) 153 vtype = kern.SymbolicateFromAddress(vt) 154 if len(vtype): 155 return vtype[0].GetName() 156 157 # See if the value is in a kext with no symbols 158 for kval in IterateLinkedList(kern.globals.kmod, 'next'): 159 if vt >= unsigned(kval.address) and vt <= (unsigned(kval.address) + unsigned(kval.size)): 160 return "kmod:{:s}+{:#0x}".format(kval.name, vt - unsigned(kval.address)) 161 return None 162 163 164@lldb_type_summary(['IORegistryEntry *']) 165@header("") 166def GetRegistryEntrySummary(entry): 167 """ returns a string containing summary information about an IORegistry 168 object including it's registry id , vtable ptr and retain count 169 """ 170 name = None 171 out_string = "" 172 registryTable = entry.fRegistryTable 173 propertyTable = entry.fPropertyTable 174 175 name = LookupKeyInOSDict(registryTable, kern.globals.gIOServicePlane.nameKey) 176 if name is None: 177 name = LookupKeyInOSDict(registryTable, kern.globals.gIONameKey) 178 if name is None: 179 name = LookupKeyInOSDict(propertyTable, kern.globals.gIOClassKey) 180 181 if name is not None: 182 out_string += "+-o {0:s} ".format(GetString(CastIOKitClass(name, 'OSString *'))) 183 elif CastIOKitClass(entry, 'IOService *').pwrMgt and CastIOKitClass(entry, 'IOService *').pwrMgt.Name: 184 out_string += "+-o {0:s} ".format(CastIOKitClass(entry, 'IOService *').pwrMgt.Name) 185 else: 186 out_string += "+-o ?? " 187 188 # I'm using uintptr_t for now to work around <rdar://problem/12749733> FindFirstType & Co. should allow you to make pointer types directly 189 vtableAddr = dereference(Cast(entry, 'uintptr_t *')) - 2 * sizeof('uintptr_t *') 190 vtableAddr = kern.StripKernelPAC(vtableAddr) 191 vtype = kern.SymbolicateFromAddress(vtableAddr) 192 if vtype is None or len(vtype) < 1: 193 out_string += "<object 0x{0: <16x}, id 0x{1:x}, vtable 0x{2: <16x}".format(entry, CastIOKitClass(entry, 'IORegistryEntry *').reserved.fRegistryEntryID, vtableAddr) 194 else: 195 out_string += "<object 0x{0: <16x}, id 0x{1:x}, vtable 0x{2: <16x} <{3:s}>".format(entry, CastIOKitClass(entry, 'IORegistryEntry *').reserved.fRegistryEntryID, 196 vtableAddr, vtype[0].GetName()) 197 198 ztvAddr = kern.GetLoadAddressForSymbol('_ZTV15IORegistryEntry') 199 if vtableAddr != ztvAddr: 200 out_string += ", " 201 state = CastIOKitClass(entry, 'IOService *').__state[0] 202 # kIOServiceRegisteredState 203 if 0 == state & 2: 204 out_string += "!" 205 out_string += "registered, " 206 # kIOServiceMatchedState 207 if 0 == state & 4: 208 out_string += "!" 209 out_string += "matched, " 210 #kIOServiceInactiveState 211 if 0 != state & 1: 212 out_string += "in" 213 busyCount = (CastIOKitClass(entry, 'IOService *').__state[1] & 0xff) 214 retCount = (CastIOKitClass(entry, 'IOService *').retainCount & 0xffff) 215 out_string += "active, busy {0}, retain count {1}>".format(busyCount, retCount) 216 return out_string 217 218###################################### 219# Commands 220###################################### 221@lldb_command('showallclasses') 222def ShowAllClasses(cmd_args=None): 223 """ Show the instance counts and ivar size of all OSObject subclasses. 224 See ioclasscount man page for details 225 """ 226 idx = 0 227 count = unsigned(kern.globals.sAllClassesDict.count) 228 229 while idx < count: 230 meta = CastIOKitClass(kern.globals.sAllClassesDict.dictionary[idx].value, 'OSMetaClass *') 231 idx += 1 232 print(GetMetaClass(meta)) 233 234@lldb_command('showobject') 235def ShowObject(cmd_args=None): 236 """ Show info about an OSObject - its vtable ptr and retain count, & more info for simple container classes. 237 """ 238 if not cmd_args: 239 print("Please specify the address of the OSObject whose info you want to view. Type help showobject for help") 240 return 241 242 obj = kern.GetValueFromAddress(cmd_args[0], 'OSObject *') 243 print(GetObjectSummary(obj)) 244 245#Macro: dumpobject 246@lldb_command('dumpobject') 247def DumpObject(cmd_args=None): 248 """ Dumps object information if it is a valid object confirmed by showobject 249 Usage: dumpobject <address of object to be dumped> [class/struct type of object] 250 """ 251 if not cmd_args: 252 print("No arguments passed") 253 print(DumpObject.__doc__) 254 return False 255 256 if len(cmd_args) == 1: 257 try: 258 object_info = lldb_run_command("showobject {:s}".format(cmd_args[0])) 259 except: 260 print("Error!! showobject failed due to invalid value") 261 print(DumpObject.__doc__) 262 return False 263 264 srch = re.search(r'<vtable for ([A-Za-z].*)>', object_info) 265 if not srch: 266 print("Error!! Couldn't find object in registry, input type manually as 2nd argument") 267 print(DumpObject.__doc__) 268 return False 269 270 object_type = srch.group(1) 271 else: 272 type_lookup = lldb_run_command("image lookup -t {:s}".format(cmd_args[1])) 273 if type_lookup.find(cmd_args[1])!= -1: 274 object_type = cmd_args[1] 275 else: 276 print("Error!! Input type {:s} isn't available in image lookup".format(cmd_args[1])) 277 return False 278 279 print("******** Object Dump for value \'{:s}\' with type \"{:s}\" ********".format(cmd_args[0], object_type)) 280 print(lldb_run_command("p/x *({:s}*){:s}".format(object_type, cmd_args[0]))) 281 282#EndMacro: dumpobject 283 284@lldb_command('setregistryplane') 285def SetRegistryPlane(cmd_args=None): 286 """ Set the plane to be used for the IOKit registry macros 287 syntax: (lldb) setregistryplane 0 - will display all known planes 288 syntax: (lldb) setregistryplane 0xaddr - will set the registry plane to 0xaddr 289 syntax: (lldb) setregistryplane gIODTPlane - will set the registry plane to gIODTPlane 290 """ 291 if not cmd_args: 292 print("Please specify the name of the plane you want to use with the IOKit registry macros.") 293 print(SetRegistryPlane.__doc__) 294 295 if cmd_args[0] == "0": 296 print(GetObjectSummary(kern.globals.gIORegistryPlanes)) 297 else: 298 global plane 299 plane = kern.GetValueFromAddress(cmd_args[0], 'IORegistryPlane *') 300 return 301 302@lldb_command('showregistryentry') 303def ShowRegistryEntry(cmd_args=None): 304 """ Show info about a registry entry; its properties and descendants in the current plane 305 syntax: (lldb) showregistryentry 0xaddr 306 syntax: (lldb) showregistryentry gIOPMRootDomain 307 """ 308 if not cmd_args: 309 print("Please specify the address of the registry entry whose info you want to view.") 310 print(ShowRegistryEntry.__doc__) 311 return 312 313 entry = kern.GetValueFromAddress(cmd_args[0], 'IORegistryEntry *') 314 ShowRegistryEntryRecurse(entry, "", True) 315 316@lldb_command('showregistry') 317def ShowRegistry(cmd_args=None): 318 """ Show info about all registry entries in the current plane 319 If prior to invoking this command no registry plane is specified 320 using 'setregistryplane', the command defaults to the IOService plane 321 """ 322 ShowRegistryEntryRecurse(kern.globals.gRegistryRoot, "", False) 323 324@lldb_command('showregistryprops') 325def ShowRegistryProps(cmd_args=None): 326 """ Show info about all registry entries in the current plane, and their properties 327 If prior to invoking this command no registry plane is specified 328 using 'setregistryplane', the command defaults to the IOService plane 329 """ 330 ShowRegistryEntryRecurse(kern.globals.gRegistryRoot, "", True) 331 332@lldb_command('findregistryentry') 333def FindRegistryEntry(cmd_args=None): 334 """ Search for registry entry that matches the given string 335 If prior to invoking this command no registry plane is specified 336 using 'setregistryplane', the command defaults to searching entries from the IOService plane 337 syntax: (lldb) findregistryentries AppleACPICPU - will find the first registry entry that matches AppleACPICPU 338 """ 339 if not cmd_args: 340 print("Please specify the name of the registry entry you want to find") 341 print(FindRegistryEntry.__doc__) 342 return 343 344 FindRegistryEntryRecurse(kern.globals.gRegistryRoot, cmd_args[0], True) 345 346@lldb_command('findregistryentries') 347def FindRegistryEntries(cmd_args=None): 348 """ Search for all registry entries that match the given string 349 If prior to invoking this command no registry plane is specified 350 using 'setregistryplane', the command defaults to searching entries from the IOService plane 351 syntax: (lldb) findregistryentries AppleACPICPU - will find all registry entries that match AppleACPICPU 352 """ 353 if not cmd_args: 354 print("Please specify the name of the registry entry/entries you want to find") 355 print(FindRegistryEntries.__doc__) 356 return 357 358 FindRegistryEntryRecurse(kern.globals.gRegistryRoot, cmd_args[0], False) 359 360@lldb_command('findregistryprop') 361def FindRegistryProp(cmd_args=None): 362 """ Given a registry entry, print out the contents for the property that matches 363 a specific string 364 syntax: (lldb) findregistryprop 0xaddr IOSleepSupported 365 syntax: (lldb) findregistryprop gIOPMRootDomain IOSleepSupported 366 syntax: (lldb) findregistryprop gIOPMRootDomain "Supported Features" 367 """ 368 if not cmd_args or len(cmd_args) < 2: 369 print("Please specify the address of a IORegistry entry and the property you're looking for") 370 print(FindRegistryProp.__doc__) 371 return 372 373 entry = kern.GetValueFromAddress(cmd_args[0], 'IOService *') 374 propertyTable = entry.fPropertyTable 375 print(GetObjectSummary(LookupKeyInPropTable(propertyTable, cmd_args[1]))) 376 377@lldb_command('readioport8') 378def ReadIOPort8(cmd_args=None): 379 """ Read value stored in the specified IO port. The CPU can be optionally 380 specified as well. 381 Prints 0xBAD10AD in case of a bad read 382 Syntax: (lldb) readioport8 <port> [lcpu (kernel's numbering convention)] 383 """ 384 if not cmd_args: 385 print("Please specify a port to read out of") 386 print(ReadIOPort8.__doc__) 387 return 388 389 portAddr = ArgumentStringToInt(cmd_args[0]) 390 if len(cmd_args) >= 2: 391 lcpu = ArgumentStringToInt(cmd_args[1]) 392 else: 393 lcpu = xnudefines.lcpu_self 394 395 ReadIOPortInt(portAddr, 1, lcpu) 396 397@lldb_command('readioport16') 398def ReadIOPort16(cmd_args=None): 399 """ Read value stored in the specified IO port. The CPU can be optionally 400 specified as well. 401 Prints 0xBAD10AD in case of a bad read 402 Syntax: (lldb) readioport16 <port> [lcpu (kernel's numbering convention)] 403 """ 404 if not cmd_args: 405 print("Please specify a port to read out of") 406 print(ReadIOPort16.__doc__) 407 return 408 409 portAddr = ArgumentStringToInt(cmd_args[0]) 410 if len(cmd_args) >= 2: 411 lcpu = ArgumentStringToInt(cmd_args[1]) 412 else: 413 lcpu = xnudefines.lcpu_self 414 415 ReadIOPortInt(portAddr, 2, lcpu) 416 417@lldb_command('readioport32') 418def ReadIOPort32(cmd_args=None): 419 """ Read value stored in the specified IO port. The CPU can be optionally 420 specified as well. 421 Prints 0xBAD10AD in case of a bad read 422 Syntax: (lldb) readioport32 <port> [lcpu (kernel's numbering convention)] 423 """ 424 if not cmd_args: 425 print("Please specify a port to read out of") 426 print(ReadIOPort32.__doc__) 427 return 428 429 portAddr = ArgumentStringToInt(cmd_args[0]) 430 if len(cmd_args) >= 2: 431 lcpu = ArgumentStringToInt(cmd_args[1]) 432 else: 433 lcpu = xnudefines.lcpu_self 434 435 ReadIOPortInt(portAddr, 4, lcpu) 436 437@lldb_command('writeioport8') 438def WriteIOPort8(cmd_args=None): 439 """ Write the value to the specified IO port. The size of the value is 440 determined by the name of the command. The CPU used can be optionally 441 specified as well. 442 Syntax: (lldb) writeioport8 <port> <value> [lcpu (kernel's numbering convention)] 443 """ 444 if not cmd_args or len(cmd_args) < 2: 445 print("Please specify a port to write to, followed by the value you want to write") 446 print(WriteIOPort8.__doc__) 447 return 448 449 portAddr = ArgumentStringToInt(cmd_args[0]) 450 value = ArgumentStringToInt(cmd_args[1]) 451 452 if len(cmd_args) >= 3: 453 lcpu = ArgumentStringToInt(cmd_args[2]) 454 else: 455 lcpu = xnudefines.lcpu_self 456 457 WriteIOPortInt(portAddr, 1, value, lcpu) 458 459@lldb_command('writeioport16') 460def WriteIOPort16(cmd_args=None): 461 """ Write the value to the specified IO port. The size of the value is 462 determined by the name of the command. The CPU used can be optionally 463 specified as well. 464 Syntax: (lldb) writeioport16 <port> <value> [lcpu (kernel's numbering convention)] 465 """ 466 if not cmd_args or len(cmd_args) < 2: 467 print("Please specify a port to write to, followed by the value you want to write") 468 print(WriteIOPort16.__doc__) 469 return 470 471 portAddr = ArgumentStringToInt(cmd_args[0]) 472 value = ArgumentStringToInt(cmd_args[1]) 473 474 if len(cmd_args) >= 3: 475 lcpu = ArgumentStringToInt(cmd_args[2]) 476 else: 477 lcpu = xnudefines.lcpu_self 478 479 WriteIOPortInt(portAddr, 2, value, lcpu) 480 481@lldb_command('writeioport32') 482def WriteIOPort32(cmd_args=None): 483 """ Write the value to the specified IO port. The size of the value is 484 determined by the name of the command. The CPU used can be optionally 485 specified as well. 486 Syntax: (lldb) writeioport32 <port> <value> [lcpu (kernel's numbering convention)] 487 """ 488 if not cmd_args or len(cmd_args) < 2: 489 print("Please specify a port to write to, followed by the value you want to write") 490 print(WriteIOPort32.__doc__) 491 return 492 493 portAddr = ArgumentStringToInt(cmd_args[0]) 494 value = ArgumentStringToInt(cmd_args[1]) 495 496 if len(cmd_args) >= 3: 497 lcpu = ArgumentStringToInt(cmd_args[2]) 498 else: 499 lcpu = xnudefines.lcpu_self 500 501 WriteIOPortInt(portAddr, 4, value, lcpu) 502 503@lldb_command('showioservicepm') 504def ShowIOServicePM(cmd_args=None): 505 """ Routine to dump the IOServicePM object 506 Syntax: (lldb) showioservicepm <IOServicePM pointer> 507 """ 508 if not cmd_args: 509 print("Please enter the pointer to the IOServicePM object you'd like to introspect") 510 print(ShowIOServicePM.__doc__) 511 return 512 513 iopmpriv = kern.GetValueFromAddress(cmd_args[0], 'IOServicePM *') 514 out_string = "MachineState {0: <6d} (".format(iopmpriv.MachineState) 515 516 # Power state map 517 pstate_map = { 518 0: 'kIOPM_Finished', 519 1: 'kIOPM_OurChangeTellClientsPowerDown', 520 2: 'kIOPM_OurChangeTellClientsPowerDown', 521 3: 'kIOPM_OurChangeNotifyInterestedDriversWillChange', 522 4: 'kIOPM_OurChangeSetPowerState', 523 5: 'kIOPM_OurChangeWaitForPowerSettle', 524 6: 'kIOPM_OurChangeNotifyInterestedDriversDidChange', 525 7: 'kIOPM_OurChangeTellCapabilityDidChange', 526 8: 'kIOPM_OurChangeFinish', 527 9: 'Unused_MachineState_9', 528 10: 'kIOPM_ParentChangeTellPriorityClientsPowerDown', 529 11: 'kIOPM_ParentChangeNotifyInterestedDriversWillChange', 530 12: 'kIOPM_ParentChangeSetPowerState', 531 13: 'kIOPM_ParentChangeWaitForPowerSettle', 532 14: 'kIOPM_ParentChangeNotifyInterestedDriversDidChange', 533 15: 'kIOPM_ParentChangeTellCapabilityDidChange', 534 16: 'kIOPM_ParentChangeAcknowledgePowerChange', 535 17: 'kIOPM_NotifyChildrenStart', 536 18: 'kIOPM_NotifyChildrenOrdered', 537 19: 'kIOPM_NotifyChildrenDelayed', 538 20: 'kIOPM_SyncTellClientsPowerDown', 539 21: 'kIOPM_SyncTellPriorityClientsPowerDown', 540 22: 'kIOPM_SyncNotifyWillChange', 541 23: 'kIOPM_SyncNotifyDidChange', 542 24: 'kIOPM_SyncTellCapabilityDidChange', 543 25: 'kIOPM_SyncFinish', 544 26: 'kIOPM_TellCapabilityChangeDone', 545 27: 'kIOPM_DriverThreadCallDone' 546 } 547 powerstate = unsigned(iopmpriv.MachineState) 548 if powerstate in pstate_map: 549 out_string += "{0:s}".format(pstate_map[powerstate]) 550 else: 551 out_string += "Unknown_MachineState" 552 out_string += "), " 553 554 if iopmpriv.MachineState != 20: 555 out_string += "DriverTimer = {0: <6d}, SettleTime = {1: < 6d}, HeadNoteFlags = {2: #12x}, HeadNotePendingAcks = {3: #012x}, ".format( 556 unsigned(iopmpriv.DriverTimer), 557 unsigned(iopmpriv.SettleTimeUS), 558 unsigned(iopmpriv.HeadNoteChangeFlags), 559 unsigned(iopmpriv.HeadNotePendingAcks)) 560 561 if iopmpriv.DeviceOverrideEnabled != 0: 562 out_string += "DeviceOverrides, " 563 564 out_string += "DeviceDesire = {0: <6d}, DesiredPowerState = {1: <6d}, PreviousRequest = {2: <6d}\n".format( 565 unsigned(iopmpriv.DeviceDesire), 566 unsigned(iopmpriv.DesiredPowerState), 567 unsigned(iopmpriv.PreviousRequestPowerFlags)) 568 569 print(out_string) 570 571@lldb_type_summary(['IOPMWorkQueue *']) 572@header("") 573def GetIOPMWorkQueueSummary(wq): 574 out_str = "" 575 ioservicepm_header = "{:<20s}{:<4s}{:<4s}{:<4s}{:<4s}\n" 576 iopmrequest_indent = " " 577 iopmrequest_header = iopmrequest_indent + "{:<20s}{:<6s}{:<20s}{:<20s}{:<12s}{:<12s}{:<20s}{:<20s}{:<20s}\n" 578 579 for next in IterateQueue(wq.fWorkQueue, 'IOServicePM *', 'WorkChain'): 580 out_str += ioservicepm_header.format("IOService", "ps", "ms", "wr", "name") 581 out_str += "0x{:<16x} {:<2d} {:<2d} {:<2d} {:<s}\n".format( 582 next.Owner, next.CurrentPowerState, next.MachineState, next.WaitReason, next.Name) 583 out_str += iopmrequest_header.format("IOPMRequest", "type", "next_req", "root_req", "work_wait", "free_wait", "arg0", "arg1", "arg2") 584 for request in IterateQueue(next.RequestHead, 'IOPMRequest *', 'fCommandChain'): 585 out_str += iopmrequest_indent 586 out_str += "0x{:<16x} 0x{:<2x} 0x{:<16x} 0x{:<16x}".format( 587 request, request.fRequestType, request.fRequestNext, request.fRequestRoot) 588 out_str += " 0x{:<8x} 0x{:<8x}".format( 589 request.fWorkWaitCount, request.fFreeWaitCount) 590 out_str += " 0x{:<16x} 0x{:<16x} 0x{:<16x}\n".format( 591 request.fArg0, request.fArg1, request.fArg2) 592 return out_str 593 594@lldb_command('showiopmqueues') 595def ShowIOPMQueues(cmd_args=None): 596 """ Show IOKit power management queues and IOPMRequest objects. 597 """ 598 print("IOPMWorkQueue 0x{:<16x} ({:<d} IOServicePM)\n".format( 599 kern.globals.gIOPMWorkQueue, kern.globals.gIOPMWorkQueue.fQueueLength)) 600 print(GetIOPMWorkQueueSummary(kern.globals.gIOPMWorkQueue)) 601 602@lldb_type_summary(['IOService *']) 603@header("") 604def GetIOPMInterest(service): 605 iopm = CastIOKitClass(service.pwrMgt, 'IOServicePM *') 606 if unsigned(iopm) == 0: 607 print("error: no IOServicePM") 608 return 609 610 list = CastIOKitClass(iopm.InterestedDrivers, 'IOPMinformeeList *') 611 out_str = "IOServicePM 0x{:<16x} ({:<d} interest, {:<d} pending ack)\n".format( 612 iopm, list.length, iopm.HeadNotePendingAcks) 613 if list.length == 0: 614 return 615 616 out_str += " {:<20s}{:<8s}{:<10s}{:<20s}{:<20s}{:<20s}{:<s}\n".format( 617 "informee", "active", "ticks", "notifyTime", "service", "regId", "name") 618 next = CastIOKitClass(list.firstItem, 'IOPMinformee *') 619 while unsigned(next) != 0: 620 driver = CastIOKitClass(next.whatObject, 'IOService *') 621 name = GetRegistryEntryName(driver) 622 reg_id = CastIOKitClass(driver, 'IORegistryEntry *').reserved.fRegistryEntryID; 623 out_str += " 0x{:<16x} {:<6s} {:<8d} 0x{:<16x} 0x{:<16x} 0x{:<16x} {:<s}\n".format( 624 next, "Yes" if next.active != 0 else "No" , next.timer, next.startTime, next.whatObject, reg_id, name) 625 next = CastIOKitClass(next.nextInList, 'IOPMinformee *') 626 return out_str 627 628@lldb_command('showiopminterest') 629def ShowIOPMInterest(cmd_args=None): 630 """ Show the interested drivers for an IOService. 631 syntax: (lldb) showiopminterest <IOService> 632 """ 633 if not cmd_args: 634 print("Please specify the address of the IOService") 635 print(ShowIOPMInterest.__doc__) 636 return 637 638 obj = kern.GetValueFromAddress(cmd_args[0], 'IOService *') 639 print(GetIOPMInterest(obj)) 640 641@lldb_command("showinterruptvectors") 642def ShowInterruptVectorInfo(cmd_args=None): 643 """ 644 Shows interrupt vectors. 645 """ 646 647 # Constants 648 kInterruptTriggerModeMask = 0x01 649 kInterruptTriggerModeEdge = 0x00 650 kInterruptTriggerModeLevel = kInterruptTriggerModeMask 651 kInterruptPolarityMask = 0x02 652 kInterruptPolarityHigh = 0x00 653 kInterruptPolarityLow = kInterruptPolarityMask 654 kInterruptShareableMask = 0x04 655 kInterruptNotShareable = 0x00 656 kInterruptIsShareable = kInterruptShareableMask 657 kIOInterruptTypePCIMessaged = 0x00010000 658 659 # Get all interrupt controllers 660 interrupt_controllers = list(SearchInterruptControllerDrivers()) 661 662 print("Interrupt controllers: ") 663 for ic in interrupt_controllers: 664 print(" {}".format(ic)) 665 print("") 666 667 # Iterate over all entries in the registry 668 for entry in GetMatchingEntries(lambda _: True): 669 # Get the name of the entry 670 entry_name = GetRegistryEntryName(entry) 671 672 # Get the location of the entry 673 entry_location = GetRegistryEntryLocationInPlane(entry, kern.globals.gIOServicePlane) 674 if entry_location is None: 675 entry_location = "" 676 else: 677 entry_location = "@" + entry_location 678 679 # Get the interrupt properties 680 (msi_mode, vectorDataList, vectorContList) = GetRegistryEntryInterruptProperties(entry) 681 should_print = False 682 out_str = "" 683 for (vector_data, vector_cont) in zip(vectorDataList, vectorContList): 684 # vector_cont is the name of the interrupt controller. Find the matching controller from 685 # the list of controllers obtained earlier 686 matching_ics = [ic for ic in interrupt_controllers if ic.name == vector_cont] 687 688 if len(matching_ics) > 0: 689 should_print = True 690 # Take the first match 691 matchingIC = matching_ics[0] 692 693 # Use the vector_data to determine the vector and any flags 694 data_ptr = vector_data.data 695 data_length = vector_data.length 696 697 # Dereference vector_data as a uint32_t * and add the base vector number 698 gsi = unsigned(dereference(Cast(data_ptr, 'uint32_t *'))) 699 gsi += matchingIC.base_vector_number 700 701 # If data_length is >= 8 then vector_data contains interrupt flags 702 if data_length >= 8: 703 # Add sizeof(uint32_t) to data_ptr to get the flags pointer 704 flags_ptr = kern.GetValueFromAddress(unsigned(data_ptr) + sizeof("uint32_t")) 705 flags = unsigned(dereference(Cast(flags_ptr, 'uint32_t *'))) 706 out_str += " +----- [Interrupt Controller {ic}] vector {gsi}, {trigger_level}, {active}, {shareable}{messaged}\n" \ 707 .format(ic=matchingIC.name, gsi=hex(gsi), 708 trigger_level="level trigger" if flags & kInterruptTriggerModeLevel else "edge trigger", 709 active="active low" if flags & kInterruptPolarityLow else "active high", 710 shareable="shareable" if flags & kInterruptIsShareable else "exclusive", 711 messaged=", messaged" if flags & kIOInterruptTypePCIMessaged else "") 712 else: 713 out_str += " +----- [Interrupt Controller {ic}] vector {gsi}\n".format(ic=matchingIC.name, gsi=hex(gsi)) 714 if should_print: 715 print("[ {entry_name}{entry_location} ]{msi_mode}\n{out_str}" \ 716 .format(entry_name=entry_name, 717 entry_location=entry_location, 718 msi_mode=" - MSIs enabled" if msi_mode else "", 719 out_str=out_str)) 720 721@lldb_command("showiokitclasshierarchy") 722def ShowIOKitClassHierarchy(cmd_args=None): 723 """ 724 Show class hierarchy for a IOKit class 725 """ 726 if not cmd_args: 727 print("Usage: showiokitclasshierarchy <IOKit class name>") 728 return 729 730 class_name = cmd_args[0] 731 metaclasses = GetMetaClasses() 732 if class_name not in metaclasses: 733 print("Class {} does not exist".format(class_name)) 734 return 735 metaclass = metaclasses[class_name] 736 737 # loop over superclasses 738 hierarchy = [] 739 current_metaclass = metaclass 740 while current_metaclass is not None: 741 hierarchy.insert(0, current_metaclass) 742 current_metaclass = current_metaclass.superclass() 743 744 for (index, mc) in enumerate(hierarchy): 745 indent = (" " * index) + "+---" 746 print("{}[ {} ] {}".format(indent, str(mc.className()), str(mc.data()))) 747 748 749###################################### 750# Helper routines 751###################################### 752def ShowRegistryEntryRecurse(entry, prefix, printProps): 753 """ prints registry entry summary and recurses through all its children. 754 """ 755 # Setup 756 global plane 757 out_string = "" 758 plen = (len(prefix)//2) 759 registryTable = entry.fRegistryTable 760 propertyTable = entry.fPropertyTable 761 762 # Print entry details 763 print("{0:s}{1:s}".format(prefix, GetRegistryEntrySummary(entry))) 764 # Printing large property tables make it look like lldb is 'stuck' 765 if printProps: 766 print(GetRegDictionary(propertyTable, prefix + " | ")) 767 768 # Recurse 769 if plane is None: 770 childKey = kern.globals.gIOServicePlane.keys[1] 771 else: 772 childKey = plane.keys[1] 773 childArray = LookupKeyInOSDict(registryTable, childKey) 774 if childArray is not None: 775 idx = 0 776 ca = CastIOKitClass(childArray, 'OSArray *') 777 count = unsigned(ca.count) 778 while idx < count: 779 if plen != 0 and plen != 1 and (plen & (plen - 1)) == 0: 780 ShowRegistryEntryRecurse(CastIOKitClass(ca.array[idx], 'IORegistryEntry *'), prefix + "| ", printProps) 781 else: 782 ShowRegistryEntryRecurse(CastIOKitClass(ca.array[idx], 'IORegistryEntry *'), prefix + " ", printProps) 783 idx += 1 784 785def FindRegistryEntryRecurse(entry, search_name, stopAfterFirst): 786 """ Checks if given registry entry's name matches the search_name we're looking for 787 If yes, it prints the entry's summary and then recurses through its children 788 If no, it does nothing and recurses through its children 789 """ 790 # Setup 791 global plane 792 registryTable = entry.fRegistryTable 793 propertyTable = entry.fPropertyTable 794 795 # Compare 796 name = None 797 name = LookupKeyInOSDict(registryTable, kern.globals.gIOServicePlane.nameKey) 798 if name is None: 799 name = LookupKeyInOSDict(registryTable, kern.globals.gIONameKey) 800 if name is None: 801 name = LookupKeyInOSDict(propertyTable, kern.globals.gIOClassKey) 802 803 if name is not None: 804 if str(CastIOKitClass(name, 'OSString *').string) == search_name: 805 print(GetRegistryEntrySummary(entry)) 806 if stopAfterFirst is True: 807 return True 808 elif CastIOKitClass(entry, 'IOService *').pwrMgt and CastIOKitClass(entry, 'IOService *').pwrMgt.Name: 809 name = CastIOKitClass(entry, 'IOService *').pwrMgt.Name 810 if str(name) == search_name: 811 print(GetRegistryEntrySummary(entry)) 812 if stopAfterFirst is True: 813 return True 814 815 # Recurse 816 if plane is None: 817 childKey = kern.globals.gIOServicePlane.keys[1] 818 else: 819 childKey = plane.keys[1] 820 childArray = LookupKeyInOSDict(registryTable, childKey) 821 if childArray is not None: 822 idx = 0 823 ca = CastIOKitClass(childArray, 'OSArray *') 824 count = unsigned(ca.count) 825 while idx < count: 826 if FindRegistryEntryRecurse(CastIOKitClass(ca.array[idx], 'IORegistryEntry *'), search_name, stopAfterFirst) is True: 827 return True 828 idx += 1 829 return False 830 831def FindRegistryObjectRecurse(entry, search_name): 832 """ Checks if given registry entry's name matches the search_name we're looking for 833 If yes, return the entry 834 If no, it does nothing and recurses through its children 835 Implicitly stops after finding the first entry 836 """ 837 # Setup 838 global plane 839 registryTable = entry.fRegistryTable 840 propertyTable = entry.fPropertyTable 841 842 # Compare 843 name = None 844 name = LookupKeyInOSDict(registryTable, kern.globals.gIOServicePlane.nameKey) 845 if name is None: 846 name = LookupKeyInOSDict(registryTable, kern.globals.gIONameKey) 847 if name is None: 848 name = LookupKeyInOSDict(propertyTable, kern.globals.gIOClassKey) 849 850 if name is not None: 851 if str(CastIOKitClass(name, 'OSString *').string) == search_name: 852 return entry 853 elif CastIOKitClass(entry, 'IOService *').pwrMgt and CastIOKitClass(entry, 'IOService *').pwrMgt.Name: 854 name = CastIOKitClass(entry, 'IOService *').pwrMgt.Name 855 if str(name) == search_name: 856 return entry 857 858 # Recurse 859 if plane is None: 860 childKey = kern.globals.gIOServicePlane.keys[1] 861 else: 862 childKey = plane.keys[1] 863 childArray = LookupKeyInOSDict(registryTable, childKey) 864 if childArray is not None: 865 ca = CastIOKitClass(childArray, 'OSArray *') 866 for idx in range(ca.count): 867 registry_object = FindRegistryObjectRecurse(CastIOKitClass(ca.array[idx], 'IORegistryEntry *'), search_name) 868 if not registry_object or int(registry_object) == int(0): 869 continue 870 else: 871 return registry_object 872 return None 873 874def CompareStringToOSSymbol(string, os_sym): 875 """ 876 Lexicographically compare python string to OSSymbol 877 Params: 878 string - python string 879 os_sym - OSSymbol 880 881 Returns: 882 0 if string == os_sym 883 1 if string > os_sym 884 -1 if string < os_sym 885 """ 886 os_sym_str = GetString(os_sym) 887 if string > os_sym_str: 888 return 1 889 elif string < os_sym_str: 890 return -1 891 else: 892 return 0 893 894class IOKitMetaClass(object): 895 """ 896 A class that represents a IOKit metaclass. This is used to represent the 897 IOKit inheritance hierarchy. 898 """ 899 900 def __init__(self, meta): 901 """ 902 Initialize a IOKitMetaClass object. 903 904 Args: 905 meta (core.cvalue.value): A LLDB value representing a 906 OSMetaClass *. 907 """ 908 self._meta = meta 909 self._superclass = None 910 911 def data(self): 912 return self._meta 913 914 def setSuperclass(self, superclass): 915 """ 916 Set the superclass for this metaclass. 917 918 Args: 919 superclass (core.cvalue.value): A LLDB value representing a 920 OSMetaClass *. 921 """ 922 self._superclass = superclass 923 924 def superclass(self): 925 """ 926 Get the superclass for this metaclass (set by the setSuperclass method). 927 928 Returns: 929 core.cvalue.value: A LLDB value representing a OSMetaClass *. 930 """ 931 return self._superclass 932 933 def className(self): 934 """ 935 Get the name of the class this metaclass represents. 936 937 Returns: 938 str: The class name 939 """ 940 return self._meta.className.string 941 942 def inheritsFrom(self, other): 943 """ 944 Check if the class represented by this metaclass inherits from a class 945 represented by another metaclass. 946 947 Args: 948 other (IOKitMetaClass): The other metaclass 949 950 Returns: 951 bool: Returns True if this class inherits from the other class and 952 False otherwise. 953 """ 954 current = self 955 while current is not None: 956 if current == other: 957 return True 958 else: 959 current = current.superclass() 960 961 962def GetRegistryEntryClassName(entry): 963 """ 964 Get the class name of a registry entry. 965 966 Args: 967 entry (core.cvalue.value): A LLDB value representing a 968 IORegistryEntry *. 969 970 Returns: 971 str: The class name of the entry or None if a class name could not be 972 found. 973 """ 974 # Check using IOClass key 975 result = LookupKeyInOSDict(entry.fPropertyTable, kern.globals.gIOClassKey) 976 if result is not None: 977 return GetString(result).replace("\"", "") 978 else: 979 # Use the vtable of the entry to determine the concrete type 980 vt = dereference(Cast(entry, 'uintptr_t *')) - 2 * sizeof('uintptr_t') 981 vt = kern.StripKernelPAC(vt) 982 vtype = kern.SymbolicateFromAddress(vt) 983 if len(vtype) > 0: 984 vtableName = vtype[0].GetName() 985 return vtableName[11:] # strip off "vtable for " 986 else: 987 return None 988 989 990def GetRegistryEntryName(entry): 991 """ 992 Get the name of a registry entry. 993 994 Args: 995 entry (core.cvalue.value): A LLDB value representing a 996 IORegistryEntry *. 997 998 Returns: 999 str: The name of the entry or None if a name could not be found. 1000 """ 1001 name = None 1002 1003 # First check the IOService plane nameKey 1004 result = LookupKeyInOSDict(entry.fRegistryTable, kern.globals.gIOServicePlane.nameKey) 1005 if result is not None: 1006 name = GetString(result) 1007 1008 # Check the global IOName key 1009 if name is None: 1010 result = LookupKeyInOSDict(entry.fRegistryTable, kern.globals.gIONameKey) 1011 if result is not None: 1012 name = GetString(result) 1013 1014 # Check the IOClass key 1015 if name is None: 1016 result = LookupKeyInOSDict(entry.fPropertyTable, kern.globals.gIOClassKey) 1017 if result is not None: 1018 name = GetString(result) 1019 1020 # Remove extra quotes 1021 if name is not None: 1022 return name.replace("\"", "") 1023 else: 1024 return GetRegistryEntryClassName(entry) 1025 1026 1027def GetRegistryEntryLocationInPlane(entry, plane): 1028 """ 1029 Get the registry entry location in a IOKit plane. 1030 1031 Args: 1032 entry (core.cvalue.value): A LLDB value representing a 1033 IORegistryEntry *. 1034 plane: An IOKit plane such as kern.globals.gIOServicePlane. 1035 1036 Returns: 1037 str: The location of the entry or None if a location could not be 1038 found. 1039 """ 1040 # Check the plane's pathLocationKey 1041 sym = LookupKeyInOSDict(entry.fRegistryTable, plane.pathLocationKey) 1042 1043 # Check the global IOLocation key 1044 if sym is None: 1045 sym = LookupKeyInOSDict(entry.fRegistryTable, kern.globals.gIOLocationKey) 1046 if sym is not None: 1047 return GetString(sym).replace("\"", "") 1048 else: 1049 return None 1050 1051 1052@caching.cache_dynamically 1053def GetMetaClasses(target=None): 1054 """ 1055 Enumerate all IOKit metaclasses. Uses dynamic caching. 1056 1057 Returns: 1058 Dict[str, IOKitMetaClass]: A dictionary mapping each metaclass name to 1059 a IOKitMetaClass object representing the metaclass. 1060 """ 1061 1062 # This method takes a while, so it prints a progress indicator 1063 print("Enumerating IOKit metaclasses: ") 1064 1065 do_progress = os.isatty(sys.__stderr__.fileno()) 1066 1067 # Iterate over all classes present in sAllClassesDict 1068 count = unsigned(kern.globals.sAllClassesDict.count) 1069 metaclasses_by_address = {} 1070 for idx in range(count): 1071 if do_progress and idx % 10 == 0: 1072 sys.stderr.write("\033[K {} metaclass found...\r".format(idx)) 1073 1074 # Address of metaclass 1075 address = kern.globals.sAllClassesDict.dictionary[idx].value 1076 1077 # Create IOKitMetaClass and store in dict 1078 metaclasses_by_address[int(address)] = IOKitMetaClass(CastIOKitClass(kern.globals.sAllClassesDict.dictionary[idx].value, 'OSMetaClass *')) 1079 1080 # At this point, each metaclass is independent of each other. We don't have superclass links set up yet. 1081 1082 for address, metaclass in metaclasses_by_address.items(): 1083 # Get the address of the superclass using the superClassLink in IOMetaClass 1084 superclass_address = int(metaclass.data().superClassLink) 1085 1086 # Skip null superclass 1087 if superclass_address == 0: 1088 continue 1089 1090 # Find the superclass object in the dict 1091 if superclass_address in metaclasses_by_address: 1092 metaclass.setSuperclass(metaclasses_by_address[superclass_address]) 1093 else: 1094 print("warning: could not find superclass for {}".format(str(metaclass.data()))) 1095 1096 # This method returns a dictionary mapping each class name to the associated metaclass object 1097 metaclasses_by_name = {} 1098 for idx, (_, metaclass) in enumerate(metaclasses_by_address.items()): 1099 if do_progress and idx % 10 == 0: 1100 sys.stderr.write("\033[K {} metaclass indexed...\r".format(idx)) 1101 1102 metaclasses_by_name[str(metaclass.className())] = metaclass 1103 1104 print(" Indexed {} IOKit metaclasses.".format(count)) 1105 return metaclasses_by_name 1106 1107 1108def GetMatchingEntries(matcher): 1109 """ 1110 Iterate over the IOKit registry and find entries that match specific 1111 criteria. 1112 1113 Args: 1114 matcher (function): A matching function that returns True for a match 1115 and False otherwise. 1116 1117 Yields: 1118 core.cvalue.value: LLDB values that represent IORegistryEntry * for 1119 each registry entry found. 1120 """ 1121 1122 # Perform a BFS over the IOKit registry tree 1123 bfs_queue = deque() 1124 bfs_queue.append(kern.globals.gRegistryRoot) 1125 while len(bfs_queue) > 0: 1126 # Dequeue an entry 1127 entry = bfs_queue.popleft() 1128 1129 # Check if entry matches 1130 if matcher(entry): 1131 yield entry 1132 1133 # Find children of this entry and enqueue them 1134 child_array = LookupKeyInOSDict(entry.fRegistryTable, kern.globals.gIOServicePlane.keys[1]) 1135 if child_array is not None: 1136 idx = 0 1137 ca = CastIOKitClass(child_array, 'OSArray *') 1138 count = unsigned(ca.count) 1139 while idx < count: 1140 bfs_queue.append(CastIOKitClass(ca.array[idx], 'IORegistryEntry *')) 1141 idx += 1 1142 1143 1144def FindMatchingServices(matching_name): 1145 """ 1146 Finds registry entries that match the given string. Works similarly to: 1147 1148 io_iterator_t iter; 1149 IOServiceGetMatchingServices(..., IOServiceMatching(matching_name), &iter); 1150 while (( io_object_t next = IOIteratorNext(iter))) { ... } 1151 1152 Args: 1153 matching_name (str): The class name to search for. 1154 1155 Yields: 1156 core.cvalue.value: LLDB values that represent IORegistryEntry * for 1157 each registry entry found. 1158 """ 1159 1160 # Check if the argument is valid 1161 metaclasses = GetMetaClasses() 1162 if matching_name not in metaclasses: 1163 return 1164 matching_metaclass = metaclasses[matching_name] 1165 1166 # An entry matches if it inherits from matching_metaclass 1167 def matcher(entry): 1168 # Get the class name of the entry and the associated metaclass 1169 entry_name = GetRegistryEntryClassName(entry) 1170 if entry_name in metaclasses: 1171 entry_metaclass = metaclasses[entry_name] 1172 return entry_metaclass.inheritsFrom(matching_metaclass) 1173 else: 1174 return False 1175 1176 # Search for entries 1177 for entry in GetMatchingEntries(matcher): 1178 yield entry 1179 1180 1181def GetRegistryEntryParent(entry, iokit_plane=None): 1182 """ 1183 Gets the parent entry of a registry entry. 1184 1185 Args: 1186 entry (core.cvalue.value): A LLDB value representing a 1187 IORegistryEntry *. 1188 iokit_plane (core.cvalue.value, optional): A LLDB value representing a 1189 IORegistryPlane *. By default, this method uses the IOService 1190 plane. 1191 1192 Returns: 1193 core.cvalue.value: A LLDB value representing a IORegistryEntry* that 1194 is the parent entry of the entry argument in the specified plane. 1195 Returns None if no entry could be found. 1196 """ 1197 kParentSetIndex = 0 1198 parent_key = None 1199 if iokit_plane is None: 1200 parent_key = kern.globals.gIOServicePlane.keys[kParentSetIndex] 1201 else: 1202 parent_key = plane.keys[kParentSetIndex] 1203 parent_array = LookupKeyInOSDict(entry.fRegistryTable, parent_key) 1204 parent_entry = None 1205 if parent_array is not None: 1206 idx = 0 1207 ca = CastIOKitClass(parent_array, 'OSArray *') 1208 count = unsigned(ca.count) 1209 if count > 0: 1210 parent_entry = CastIOKitClass(ca.array[0], 'IORegistryEntry *') 1211 return parent_entry 1212 1213 1214def GetRegistryEntryInterruptProperties(entry): 1215 """ 1216 Get the interrupt properties of a registry entry. 1217 1218 Args: 1219 entry (core.cvalue.value): A LLDB value representing a IORegistryEntry *. 1220 1221 Returns: 1222 (bool, List[core.cvalue.value], List[str]): A tuple with the following 1223 fields: 1224 - First field (bool): Whether this entry has a non-null 1225 IOPCIMSIMode. 1226 - Second field (List[core.cvalue.value]): A list of LLDB values 1227 representing OSData *. The OSData* pointer points to 1228 interrupt vector data. 1229 - Third field (List[str]): A list of strings representing the 1230 interrupt controller names from the 1231 IOInterruptControllers property. 1232 """ 1233 INTERRUPT_SPECIFIERS_PROPERTY = "IOInterruptSpecifiers" 1234 INTERRUPT_CONTROLLERS_PROPERTY = "IOInterruptControllers" 1235 MSI_MODE_PROPERTY = "IOPCIMSIMode" 1236 1237 # Check IOInterruptSpecifiers 1238 interrupt_specifiers = LookupKeyInPropTable(entry.fPropertyTable, INTERRUPT_SPECIFIERS_PROPERTY) 1239 if interrupt_specifiers is not None: 1240 interrupt_specifiers = CastIOKitClass(interrupt_specifiers, 'OSArray *') 1241 1242 # Check IOInterruptControllers 1243 interrupt_controllers = LookupKeyInPropTable(entry.fPropertyTable, INTERRUPT_CONTROLLERS_PROPERTY) 1244 if interrupt_controllers is not None: 1245 interrupt_controllers = CastIOKitClass(interrupt_controllers, 'OSArray *') 1246 1247 # Check MSI mode 1248 msi_mode = LookupKeyInPropTable(entry.fPropertyTable, MSI_MODE_PROPERTY) 1249 1250 result_vector_data = [] 1251 result_vector_cont = [] 1252 if interrupt_specifiers is not None and interrupt_controllers is not None: 1253 interrupt_specifiers_array_count = unsigned(interrupt_specifiers.count) 1254 interrupt_controllers_array_count = unsigned(interrupt_controllers.count) 1255 # The array lengths should be the same 1256 if interrupt_specifiers_array_count == interrupt_controllers_array_count and interrupt_specifiers_array_count > 0: 1257 idx = 0 1258 while idx < interrupt_specifiers_array_count: 1259 # IOInterruptSpecifiers is an array of OSData * 1260 vector_data = CastIOKitClass(interrupt_specifiers.array[idx], "OSData *") 1261 1262 # IOInterruptControllers is an array of OSString * 1263 vector_cont = GetString(interrupt_controllers.array[idx]) 1264 1265 result_vector_data.append(vector_data) 1266 result_vector_cont.append(vector_cont) 1267 idx += 1 1268 1269 return (msi_mode is not None, result_vector_data, result_vector_cont) 1270 1271 1272class InterruptControllerDevice(object): 1273 """Represents a IOInterruptController""" 1274 1275 def __init__(self, device, driver, base_vector_number, name): 1276 """ 1277 Initialize a InterruptControllerDevice. 1278 1279 Args: 1280 device (core.cvalue.value): The device object. 1281 driver (core.cvalue.value): The driver object. 1282 base_vector_number (int): The base interrupt vector. 1283 name (str): The name of this interrupt controller. 1284 1285 Note: 1286 Use the factory method makeInterruptControllerDevice to validate 1287 properties. 1288 """ 1289 self.device = device 1290 self.driver = driver 1291 self.name = name 1292 self.base_vector_number = base_vector_number 1293 1294 1295 def __str__(self): 1296 """ 1297 String representation of this InterruptControllerDevice. 1298 """ 1299 return " Name {}, base vector = {}, device = {}, driver = {}".format( 1300 self.name, hex(self.base_vector_number), str(self.device), str(self.driver)) 1301 1302 @staticmethod 1303 def makeInterruptControllerDevice(device, driver): 1304 """ 1305 Factory method to create a InterruptControllerDevice. 1306 1307 Args: 1308 device (core.cvalue.value): The device object. 1309 driver (core.cvalue.value): The driver object. 1310 1311 Returns: 1312 InterruptControllerDevice: Returns an instance of 1313 InterruptControllerDevice or None if the arguments do not have 1314 the required properties. 1315 """ 1316 BASE_VECTOR_PROPERTY = "Base Vector Number" 1317 INTERRUPT_CONTROLLER_NAME_PROPERTY = "InterruptControllerName" 1318 base_vector = LookupKeyInPropTable(device.fPropertyTable, BASE_VECTOR_PROPERTY) 1319 if base_vector is None: 1320 base_vector = LookupKeyInPropTable(driver.fPropertyTable, BASE_VECTOR_PROPERTY) 1321 device_name = LookupKeyInPropTable(device.fPropertyTable, INTERRUPT_CONTROLLER_NAME_PROPERTY) 1322 if device_name is None: 1323 device_name = LookupKeyInPropTable(driver.fPropertyTable, INTERRUPT_CONTROLLER_NAME_PROPERTY) 1324 1325 if device_name is not None: 1326 # Some interrupt controllers do not have a base vector number. Assume it is 0. 1327 base_vector_number = 0 1328 if base_vector is not None: 1329 base_vector_number = unsigned(GetNumber(base_vector)) 1330 device_name = GetString(device_name) 1331 # Construct object and return 1332 return InterruptControllerDevice(device, driver, base_vector_number, device_name) 1333 else: 1334 # error case 1335 return None 1336 1337 1338def SearchInterruptControllerDrivers(): 1339 """ 1340 Search the IOKit registry for entries that match IOInterruptController. 1341 1342 Yields: 1343 core.cvalue.value: A LLDB value representing a IORegistryEntry * that 1344 inherits from IOInterruptController. 1345 """ 1346 for entry in FindMatchingServices("IOInterruptController"): 1347 # Get parent 1348 parent = GetRegistryEntryParent(entry) 1349 1350 # Make the interrupt controller object 1351 ic = InterruptControllerDevice.makeInterruptControllerDevice(parent, entry) 1352 1353 # Yield object 1354 if ic is not None: 1355 yield ic 1356 1357 1358def LookupKeyInOSDict(osdict, key, comparer = None): 1359 """ Returns the value corresponding to a given key in a OSDictionary 1360 Returns None if the key was not found 1361 """ 1362 if not osdict: 1363 return 1364 count = unsigned(osdict.count) 1365 result = None 1366 idx = 0 1367 1368 while idx < count and result is None: 1369 if comparer is not None: 1370 if comparer(key, osdict.dictionary[idx].key) == 0: 1371 result = osdict.dictionary[idx].value 1372 elif key == osdict.dictionary[idx].key: 1373 result = osdict.dictionary[idx].value 1374 idx += 1 1375 return result 1376 1377def LookupKeyInPropTable(propertyTable, key_str): 1378 """ Returns the value corresponding to a given key from a registry entry's property table 1379 Returns None if the key was not found 1380 The property that is being searched for is specified as a string in key_str 1381 """ 1382 if not propertyTable: 1383 return 1384 count = unsigned(propertyTable.count) 1385 result = None 1386 idx = 0 1387 while idx < count and result is None: 1388 if key_str == str(propertyTable.dictionary[idx].key.string): 1389 result = propertyTable.dictionary[idx].value 1390 idx += 1 1391 return result 1392 1393def GetRegDictionary(osdict, prefix): 1394 """ Returns a specially formatted string summary of the given OSDictionary 1395 This is done in order to pretty-print registry property tables in showregistry 1396 and other macros 1397 """ 1398 out_string = prefix + "{\n" 1399 idx = 0 1400 count = unsigned(osdict.count) 1401 1402 while idx < count: 1403 out_string += prefix + " " + GetObjectSummary(osdict.dictionary[idx].key) + " = " + GetObjectSummary(osdict.dictionary[idx].value) + "\n" 1404 idx += 1 1405 out_string += prefix + "}\n" 1406 return out_string 1407 1408def GetString(string): 1409 """ Returns the python string representation of a given OSString 1410 """ 1411 out_string = "{0:s}".format(CastIOKitClass(string, 'OSString *').string) 1412 return out_string 1413 1414def GetNumber(num): 1415 out_string = "{0:d}".format(CastIOKitClass(num, 'OSNumber *').value) 1416 return out_string 1417 1418def GetBoolean(b): 1419 """ Shows info about a given OSBoolean 1420 """ 1421 out_string = "" 1422 if b == kern.globals.gOSBooleanFalse: 1423 out_string += "No" 1424 else: 1425 out_string += "Yes" 1426 return out_string 1427 1428def GetMetaClass(mc): 1429 """ Shows info about a given OSSymbol 1430 """ 1431 out_string = "{0: <5d}x {1: >5d} bytes {2:s}\n".format(mc.instanceCount, mc.classSize, mc.className.string) 1432 return out_string 1433 1434def GetArray(arr): 1435 """ Returns a string containing info about a given OSArray 1436 """ 1437 out_string = "" 1438 idx = 0 1439 count = unsigned(arr.count) 1440 1441 while idx < count: 1442 obj = arr.array[idx] 1443 idx += 1 1444 out_string += GetObjectSummary(obj) 1445 if idx < unsigned(arr.count): 1446 out_string += "," 1447 return out_string 1448 1449def GetDictionary(d): 1450 """ Returns a string containing info about a given OSDictionary 1451 """ 1452 if d is None: 1453 return "" 1454 out_string = "{\n" 1455 idx = 0 1456 count = unsigned(d.count) 1457 1458 while idx < count: 1459 key = d.dictionary[idx].key 1460 value = d.dictionary[idx].value 1461 out_string += " \"{}\" = {}\n".format(GetString(key), GetObjectSummary(value)) 1462 idx += 1 1463 out_string += "}" 1464 return out_string 1465 1466def GetSet(se): 1467 """ Returns a string containing info about a given OSSet 1468 """ 1469 out_string = "[" + GetArray(se.members) + "]" 1470 return out_string 1471 1472def ReadIOPortInt(addr, numbytes, lcpu): 1473 """ Prints results after reading a given ioport 1474 """ 1475 result = 0xBAD10AD 1476 1477 if "kdp" != GetConnectionProtocol(): 1478 print("Target is not connected over kdp. Nothing to do here.") 1479 return 1480 1481 # Set up the manual KDP packet 1482 input_address = unsigned(addressof(kern.globals.manual_pkt.input)) 1483 len_address = unsigned(addressof(kern.globals.manual_pkt.len)) 1484 data_address = unsigned(addressof(kern.globals.manual_pkt.data)) 1485 if not WriteInt32ToMemoryAddress(0, input_address): 1486 print("0x{0: <4x}: 0x{1: <1x}".format(addr, result)) 1487 return 1488 1489 kdp_pkt_size = GetType('kdp_readioport_req_t').GetByteSize() 1490 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address): 1491 print("0x{0: <4x}: 0x{1: <1x}".format(addr, result)) 1492 return 1493 1494 kgm_pkt = kern.GetValueFromAddress(data_address, 'kdp_readioport_req_t *') 1495 1496 header_value = GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_READIOPORT'), length = kdp_pkt_size) 1497 1498 if( WriteInt64ToMemoryAddress((header_value), int(addressof(kgm_pkt.hdr))) and 1499 WriteInt16ToMemoryAddress(addr, int(addressof(kgm_pkt.address))) and 1500 WriteInt32ToMemoryAddress(numbytes, int(addressof(kgm_pkt.nbytes))) and 1501 WriteInt16ToMemoryAddress(lcpu, int(addressof(kgm_pkt.lcpu))) and 1502 WriteInt32ToMemoryAddress(1, input_address) 1503 ): 1504 1505 result_pkt = Cast(addressof(kern.globals.manual_pkt.data), 'kdp_readioport_reply_t *') 1506 1507 if(result_pkt.error == 0): 1508 if numbytes == 1: 1509 result = dereference(Cast(addressof(result_pkt.data), 'uint8_t *')) 1510 elif numbytes == 2: 1511 result = dereference(Cast(addressof(result_pkt.data), 'uint16_t *')) 1512 elif numbytes == 4: 1513 result = dereference(Cast(addressof(result_pkt.data), 'uint32_t *')) 1514 1515 print("{0: <#6x}: {1:#0{2}x}".format(addr, result, (numbytes*2)+2)) 1516 1517def WriteIOPortInt(addr, numbytes, value, lcpu): 1518 """ Writes 'value' into ioport specified by 'addr'. Prints errors if it encounters any 1519 """ 1520 if "kdp" != GetConnectionProtocol(): 1521 print("Target is not connected over kdp. Nothing to do here.") 1522 return 1523 1524 # Set up the manual KDP packet 1525 input_address = unsigned(addressof(kern.globals.manual_pkt.input)) 1526 len_address = unsigned(addressof(kern.globals.manual_pkt.len)) 1527 data_address = unsigned(addressof(kern.globals.manual_pkt.data)) 1528 if not WriteInt32ToMemoryAddress(0, input_address): 1529 print("error writing {0: #x} to port {1: <#6x}: failed to write 0 to input_address".format(value, addr)) 1530 return 1531 1532 kdp_pkt_size = GetType('kdp_writeioport_req_t').GetByteSize() 1533 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address): 1534 print("error writing {0: #x} to port {1: <#6x}: failed to write kdp_pkt_size".format(value, addr)) 1535 return 1536 1537 kgm_pkt = kern.GetValueFromAddress(data_address, 'kdp_writeioport_req_t *') 1538 1539 header_value = GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_WRITEIOPORT'), length = kdp_pkt_size) 1540 1541 if( WriteInt64ToMemoryAddress((header_value), int(addressof(kgm_pkt.hdr))) and 1542 WriteInt16ToMemoryAddress(addr, int(addressof(kgm_pkt.address))) and 1543 WriteInt32ToMemoryAddress(numbytes, int(addressof(kgm_pkt.nbytes))) and 1544 WriteInt16ToMemoryAddress(lcpu, int(addressof(kgm_pkt.lcpu))) 1545 ): 1546 if numbytes == 1: 1547 if not WriteInt8ToMemoryAddress(value, int(addressof(kgm_pkt.data))): 1548 print("error writing {0: #x} to port {1: <#6x}: failed to write 8 bit data".format(value, addr)) 1549 return 1550 elif numbytes == 2: 1551 if not WriteInt16ToMemoryAddress(value, int(addressof(kgm_pkt.data))): 1552 print("error writing {0: #x} to port {1: <#6x}: failed to write 16 bit data".format(value, addr)) 1553 return 1554 elif numbytes == 4: 1555 if not WriteInt32ToMemoryAddress(value, int(addressof(kgm_pkt.data))): 1556 print("error writing {0: #x} to port {1: <#6x}: failed to write 32 bit data".format(value, addr)) 1557 return 1558 if not WriteInt32ToMemoryAddress(1, input_address): 1559 print("error writing {0: #x} to port {1: <#6x}: failed to write to input_address".format(value, addr)) 1560 return 1561 1562 result_pkt = Cast(addressof(kern.globals.manual_pkt.data), 'kdp_writeioport_reply_t *') 1563 1564 # Done with the write 1565 if(result_pkt.error == 0): 1566 print("Writing {0: #x} to port {1: <#6x} was successful".format(value, addr)) 1567 else: 1568 print("error writing {0: #x} to port {1: <#6x}".format(value, addr)) 1569 1570@lldb_command('showinterruptcounts') 1571def showinterruptcounts(cmd_args=None): 1572 """ Shows event source based interrupt counts by nub name and interrupt index. 1573 Does not cover interrupts that are not event source based. Will report 0 1574 if interrupt accounting is disabled. 1575 """ 1576 1577 header_format = "{0: <20s} {1: >5s} {2: >20s}" 1578 content_format = "{0: <20s} {1: >5d} {2: >20d}" 1579 1580 print(header_format.format("Name", "Index", "Count")) 1581 1582 for i in kern.interrupt_stats: 1583 owner = CastIOKitClass(i.owner, 'IOInterruptEventSource *') 1584 nub = CastIOKitClass(owner.provider, 'IORegistryEntry *') 1585 name = None 1586 1587 # To uniquely identify an interrupt, we need the nub name and the index. The index 1588 # is stored with the stats object, but we need to retrieve the name. 1589 1590 registryTable = nub.fRegistryTable 1591 propertyTable = nub.fPropertyTable 1592 1593 name = LookupKeyInOSDict(registryTable, kern.globals.gIOServicePlane.nameKey) 1594 if name is None: 1595 name = LookupKeyInOSDict(registryTable, kern.globals.gIONameKey) 1596 if name is None: 1597 name = LookupKeyInOSDict(propertyTable, kern.globals.gIOClassKey) 1598 1599 if name is None: 1600 nub_name = "Unknown" 1601 else: 1602 nub_name = GetString(CastIOKitClass(name, 'OSString *')) 1603 1604 # We now have everything we need; spew the requested data. 1605 1606 interrupt_index = i.interruptIndex 1607 first_level_count = i.interruptStatistics[0] 1608 1609 print(content_format.format(nub_name, interrupt_index, first_level_count)) 1610 1611 return True 1612 1613@lldb_command('showinterruptstats') 1614def showinterruptstats(cmd_args=None): 1615 """ Shows event source based interrupt statistics by nub name and interrupt index. 1616 Does not cover interrupts that are not event source based. Will report 0 1617 if interrupt accounting is disabled, or if specific statistics are disabled. 1618 Time is reported in ticks of mach_absolute_time. Statistics are: 1619 1620 Interrupt Count: Number of times the interrupt context handler was run 1621 Interrupt Time: Total time spent in the interrupt context handler (if any) 1622 Workloop Count: Number of times the kernel context handler was run 1623 Workloop CPU Time: Total CPU time spent running the kernel context handler 1624 Workloop Time: Total time spent running the kernel context handler 1625 """ 1626 1627 header_format = "{0: <20s} {1: >5s} {2: >20s} {3: >20s} {4: >20s} {5: >20s} {6: >20s} {7: >20s} {8: >20s} {9: >20s}" 1628 content_format = "{0: <20s} {1: >5d} {2: >20d} {3: >20d} {4: >20d} {5: >20d} {6: >20d} {7: >20d} {8: >20d} {9: >#20x}" 1629 1630 print(header_format.format("Name", "Index", "Interrupt Count", "Interrupt Time", "Avg Interrupt Time", "Workloop Count", "Workloop CPU Time", "Workloop Time", "Avg Workloop Time", "Owner")) 1631 1632 for i in kern.interrupt_stats: 1633 owner = CastIOKitClass(i.owner, 'IOInterruptEventSource *') 1634 nub = CastIOKitClass(owner.provider, 'IORegistryEntry *') 1635 name = None 1636 1637 # To uniquely identify an interrupt, we need the nub name and the index. The index 1638 # is stored with the stats object, but we need to retrieve the name. 1639 1640 registryTable = nub.fRegistryTable 1641 propertyTable = nub.fPropertyTable 1642 1643 name = LookupKeyInOSDict(registryTable, kern.globals.gIOServicePlane.nameKey) 1644 if name is None: 1645 name = LookupKeyInOSDict(registryTable, kern.globals.gIONameKey) 1646 if name is None: 1647 name = LookupKeyInOSDict(propertyTable, kern.globals.gIOClassKey) 1648 1649 if name is None: 1650 nub_name = "Unknown" 1651 else: 1652 nub_name = GetString(CastIOKitClass(name, 'OSString *')) 1653 1654 # We now have everything we need; spew the requested data. 1655 1656 interrupt_index = i.interruptIndex 1657 first_level_count = i.interruptStatistics[0] 1658 second_level_count = i.interruptStatistics[1] 1659 first_level_time = i.interruptStatistics[2] 1660 second_level_cpu_time = i.interruptStatistics[3] 1661 second_level_system_time = i.interruptStatistics[4] 1662 1663 avg_first_level_time = 0 1664 if first_level_count != 0: 1665 avg_first_level_time = first_level_time // first_level_count 1666 1667 avg_second_level_time = 0 1668 if second_level_count != 0: 1669 avg_second_level_time = second_level_system_time // second_level_count 1670 1671 print(content_format.format(nub_name, interrupt_index, first_level_count, first_level_time, avg_first_level_time, 1672 second_level_count, second_level_cpu_time, second_level_system_time, avg_second_level_time, owner)) 1673 1674 return True 1675 1676def GetRegistryPlane(plane_name): 1677 """ 1678 Given plane_name, returns IORegistryPlane * object or None if there's no such registry plane 1679 """ 1680 return LookupKeyInOSDict(kern.globals.gIORegistryPlanes, plane_name, CompareStringToOSSymbol) 1681 1682def DecodePreoslogSource(source): 1683 """ 1684 Given preoslog source, return a matching string representation 1685 """ 1686 source_to_str = {0 : "iboot"} 1687 if source in source_to_str: 1688 return source_to_str[source] 1689 return "UNKNOWN" 1690 1691def GetPreoslogHeader(): 1692 """ 1693 Scan IODeviceTree for preoslog and return a python representation of it 1694 """ 1695 edt_plane = GetRegistryPlane("IODeviceTree") 1696 if edt_plane is None: 1697 print("Couldn't obtain a pointer to IODeviceTree") 1698 return None 1699 1700 # Registry API functions operate on "plane" global variable 1701 global plane 1702 prev_plane = plane 1703 plane = edt_plane 1704 chosen = FindRegistryObjectRecurse(kern.globals.gRegistryRoot, "chosen") 1705 if chosen is None: 1706 print("Couldn't obtain /chosen IORegistryEntry") 1707 return None 1708 1709 memory_map = FindRegistryObjectRecurse(chosen, "memory-map") 1710 if memory_map is None: 1711 print("Couldn't obtain memory-map from /chosen") 1712 return None 1713 1714 plane = prev_plane 1715 1716 mm_preoslog = LookupKeyInOSDict(memory_map.fPropertyTable, "preoslog", CompareStringToOSSymbol) 1717 if mm_preoslog is None: 1718 print("Couldn't find preoslog entry in memory-map") 1719 return None 1720 1721 if mm_preoslog.length != 16: 1722 print("preoslog entry in memory-map is malformed, expected len is 16, given len is {:d}".format(mm_preoslog.length)) 1723 return None 1724 1725 data = cast(mm_preoslog.data, "dtptr_t *") 1726 preoslog_paddr = unsigned(data[0]) 1727 preoslog_vaddr = kern.PhysToKernelVirt(preoslog_paddr) 1728 preoslog_size = unsigned(data[1]) 1729 1730 preoslog_header = PreoslogHeader() 1731 1732 # This structure defnition doesn't exist in xnu 1733 """ 1734 typedef struct __attribute__((packed)) { 1735 char magic[4]; 1736 uint32_t size; 1737 uint32_t offset; 1738 uint8_t source; 1739 uint8_t wrapped; 1740 char data[]; 1741 } preoslog_header_t; 1742 """ 1743 preoslog_header_ptr = kern.GetValueFromAddress(preoslog_vaddr, "uint8_t *") 1744 preoslog_header.magic = preoslog_header_ptr[0:4] 1745 preoslog_header.source = DecodePreoslogSource(unsigned(preoslog_header_ptr[12])) 1746 preoslog_header.wrapped = unsigned(preoslog_header_ptr[13]) 1747 preoslog_header_ptr = kern.GetValueFromAddress(preoslog_vaddr, "uint32_t *") 1748 preoslog_header.size = unsigned(preoslog_header_ptr[1]) 1749 preoslog_header.offset = unsigned(preoslog_header_ptr[2]) 1750 1751 for i in range(len(preoslog_header.valid_magic)): 1752 c = chr(unsigned(preoslog_header.magic[i])) 1753 if c != preoslog_header.valid_magic[i]: 1754 string = "Error: magic doesn't match, expected {:.4s}, given {:.4s}" 1755 print(string.format(preoslog_header.valid_magic, preoslog_header.magic)) 1756 return None 1757 1758 if preoslog_header.size != preoslog_size: 1759 string = "Error: size mismatch preoslog_header.size ({}) != preoslog_size ({})" 1760 print(string.format(preoslog_header.size, preoslog_size)) 1761 return None 1762 1763 preoslog_data_ptr = kern.GetValueFromAddress(preoslog_vaddr + 14, "char *") 1764 preoslog_header.data = preoslog_data_ptr.GetSBValue().GetPointeeData(0, preoslog_size) 1765 return preoslog_header 1766 1767@lldb_command("showpreoslog") 1768def showpreoslog(cmd_args=None): 1769 """ Display preoslog buffer """ 1770 1771 preoslog = GetPreoslogHeader() 1772 if preoslog is None: 1773 print("Error: couldn't obtain preoslog header") 1774 return False 1775 1776 header = "".join([ 1777 "----preoslog log header-----\n", 1778 "size - {} bytes\n", 1779 "write offset - {:#x}\n", 1780 "wrapped - {}\n", 1781 "source - {}\n", 1782 "----preoslog log start------" 1783 ]) 1784 1785 print(header.format(preoslog.size, preoslog.offset, preoslog.wrapped, preoslog.source)) 1786 1787 err = lldb.SBError() 1788 if preoslog.wrapped > 0: 1789 print(six.ensure_str(preoslog.data.GetString(err, preoslog.offset + 1))) 1790 print(six.ensure_str(preoslog.data.GetString(err, 0))) 1791 print("-----preoslog log end-------") 1792 return True 1793 1794@lldb_command('showeventsources') 1795def ShowEventSources(cmd_args=None): 1796 """ Show all event sources for a IOWorkLoop 1797 syntax: (lldb) showeventsources <IOWorkLoop *> 1798 """ 1799 if not cmd_args: 1800 print("Please specify the address of the IOWorkLoop") 1801 print(ShowEventSources.__doc__) 1802 return 1803 1804 obj = kern.GetValueFromAddress(cmd_args[0], 'IOWorkLoop *') 1805 idx = 0 1806 event = obj.eventChain 1807 while event != 0: 1808 enabled = event.enabled 1809 print("{}: {} [{}]".format(idx, GetObjectSummary(event), "enabled" if enabled else "disabled")) 1810 event = event.eventChainNext 1811 idx += 1 1812