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 if hasattr(iopmpriv, "SettleTimeUS"): 556 out_string += "DriverTimer = {0: <6d}, SettleTime = {1: < 6d}, HeadNoteFlags = {2: #12x}, HeadNotePendingAcks = {3: #012x}, ".format( 557 unsigned(iopmpriv.DriverTimer), 558 unsigned(iopmpriv.SettleTimeUS), 559 unsigned(iopmpriv.HeadNoteChangeFlags), 560 unsigned(iopmpriv.HeadNotePendingAcks)) 561 else: 562 out_string += "DriverTimer = {0: <6d}, HeadNoteFlags = {1: #12x}, HeadNotePendingAcks = {2: #012x}, ".format( 563 unsigned(iopmpriv.DriverTimer), 564 unsigned(iopmpriv.HeadNoteChangeFlags), 565 unsigned(iopmpriv.HeadNotePendingAcks)) 566 567 if iopmpriv.DeviceOverrideEnabled != 0: 568 out_string += "DeviceOverrides, " 569 570 out_string += "DeviceDesire = {0: <6d}, DesiredPowerState = {1: <6d}, PreviousRequest = {2: <6d}\n".format( 571 unsigned(iopmpriv.DeviceDesire), 572 unsigned(iopmpriv.DesiredPowerState), 573 unsigned(iopmpriv.PreviousRequestPowerFlags)) 574 575 print(out_string) 576 577@lldb_type_summary(['IOPMWorkQueue *']) 578@header("") 579def GetIOPMWorkQueueSummary(wq): 580 out_str = "" 581 ioservicepm_header = "{:<20s}{:<4s}{:<4s}{:<4s}{:<4s}\n" 582 iopmrequest_indent = " " 583 iopmrequest_header = iopmrequest_indent + "{:<20s}{:<6s}{:<20s}{:<20s}{:<12s}{:<12s}{:<20s}{:<20s}{:<20s}\n" 584 585 for next in IterateQueue(wq.fWorkQueue, 'IOServicePM *', 'WorkChain'): 586 out_str += ioservicepm_header.format("IOService", "ps", "ms", "wr", "name") 587 out_str += "0x{:<16x} {:<2d} {:<2d} {:<2d} {:<s}\n".format( 588 next.Owner, next.CurrentPowerState, next.MachineState, next.WaitReason, next.Name) 589 out_str += iopmrequest_header.format("IOPMRequest", "type", "next_req", "root_req", "work_wait", "free_wait", "arg0", "arg1", "arg2") 590 for request in IterateQueue(next.RequestHead, 'IOPMRequest *', 'fCommandChain'): 591 out_str += iopmrequest_indent 592 out_str += "0x{:<16x} 0x{:<2x} 0x{:<16x} 0x{:<16x}".format( 593 request, request.fRequestType, request.fRequestNext, request.fRequestRoot) 594 out_str += " 0x{:<8x} 0x{:<8x}".format( 595 request.fWorkWaitCount, request.fFreeWaitCount) 596 out_str += " 0x{:<16x} 0x{:<16x} 0x{:<16x}\n".format( 597 request.fArg0, request.fArg1, request.fArg2) 598 return out_str 599 600@lldb_command('showiopmqueues') 601def ShowIOPMQueues(cmd_args=None): 602 """ Show IOKit power management queues and IOPMRequest objects. 603 """ 604 print("IOPMWorkQueue 0x{:<16x} ({:<d} IOServicePM)\n".format( 605 kern.globals.gIOPMWorkQueue, kern.globals.gIOPMWorkQueue.fQueueLength)) 606 print(GetIOPMWorkQueueSummary(kern.globals.gIOPMWorkQueue)) 607 608@lldb_type_summary(['IOService *']) 609@header("") 610def GetIOPMInterest(service): 611 iopm = CastIOKitClass(service.pwrMgt, 'IOServicePM *') 612 if unsigned(iopm) == 0: 613 print("error: no IOServicePM") 614 return 615 616 list = CastIOKitClass(iopm.InterestedDrivers, 'IOPMinformeeList *') 617 out_str = "IOServicePM 0x{:<16x} ({:<d} interest, {:<d} pending ack)\n".format( 618 iopm, list.length, iopm.HeadNotePendingAcks) 619 if list.length == 0: 620 return 621 622 out_str += " {:<20s}{:<8s}{:<10s}{:<20s}{:<20s}{:<20s}{:<s}\n".format( 623 "informee", "active", "ticks", "notifyTime", "service", "regId", "name") 624 next = CastIOKitClass(list.firstItem, 'IOPMinformee *') 625 while unsigned(next) != 0: 626 driver = CastIOKitClass(next.whatObject, 'IOService *') 627 name = GetRegistryEntryName(driver) 628 reg_id = CastIOKitClass(driver, 'IORegistryEntry *').reserved.fRegistryEntryID; 629 out_str += " 0x{:<16x} {:<6s} {:<8d} 0x{:<16x} 0x{:<16x} 0x{:<16x} {:<s}\n".format( 630 next, "Yes" if next.active != 0 else "No" , next.timer, next.startTime, next.whatObject, reg_id, name) 631 next = CastIOKitClass(next.nextInList, 'IOPMinformee *') 632 return out_str 633 634@lldb_command('showiopminterest') 635def ShowIOPMInterest(cmd_args=None): 636 """ Show the interested drivers for an IOService. 637 syntax: (lldb) showiopminterest <IOService> 638 """ 639 if not cmd_args: 640 print("Please specify the address of the IOService") 641 print(ShowIOPMInterest.__doc__) 642 return 643 644 obj = kern.GetValueFromAddress(cmd_args[0], 'IOService *') 645 print(GetIOPMInterest(obj)) 646 647@lldb_command("showinterruptvectors") 648def ShowInterruptVectorInfo(cmd_args=None): 649 """ 650 Shows interrupt vectors. 651 """ 652 653 # Constants 654 kInterruptTriggerModeMask = 0x01 655 kInterruptTriggerModeEdge = 0x00 656 kInterruptTriggerModeLevel = kInterruptTriggerModeMask 657 kInterruptPolarityMask = 0x02 658 kInterruptPolarityHigh = 0x00 659 kInterruptPolarityLow = kInterruptPolarityMask 660 kInterruptShareableMask = 0x04 661 kInterruptNotShareable = 0x00 662 kInterruptIsShareable = kInterruptShareableMask 663 kIOInterruptTypePCIMessaged = 0x00010000 664 665 # Get all interrupt controllers 666 interrupt_controllers = list(SearchInterruptControllerDrivers()) 667 668 print("Interrupt controllers: ") 669 for ic in interrupt_controllers: 670 print(" {}".format(ic)) 671 print("") 672 673 # Iterate over all entries in the registry 674 for entry in GetMatchingEntries(lambda _: True): 675 # Get the name of the entry 676 entry_name = GetRegistryEntryName(entry) 677 678 # Get the location of the entry 679 entry_location = GetRegistryEntryLocationInPlane(entry, kern.globals.gIOServicePlane) 680 if entry_location is None: 681 entry_location = "" 682 else: 683 entry_location = "@" + entry_location 684 685 # Get the interrupt properties 686 (msi_mode, vectorDataList, vectorContList) = GetRegistryEntryInterruptProperties(entry) 687 should_print = False 688 out_str = "" 689 for (vector_data, vector_cont) in zip(vectorDataList, vectorContList): 690 # vector_cont is the name of the interrupt controller. Find the matching controller from 691 # the list of controllers obtained earlier 692 matching_ics = [ic for ic in interrupt_controllers if ic.name == vector_cont] 693 694 if len(matching_ics) > 0: 695 should_print = True 696 # Take the first match 697 matchingIC = matching_ics[0] 698 699 # Use the vector_data to determine the vector and any flags 700 data_ptr = vector_data.data 701 data_length = vector_data.length 702 703 # Dereference vector_data as a uint32_t * and add the base vector number 704 gsi = unsigned(dereference(Cast(data_ptr, 'uint32_t *'))) 705 gsi += matchingIC.base_vector_number 706 707 # If data_length is >= 8 then vector_data contains interrupt flags 708 if data_length >= 8: 709 # Add sizeof(uint32_t) to data_ptr to get the flags pointer 710 flags_ptr = kern.GetValueFromAddress(unsigned(data_ptr) + sizeof("uint32_t")) 711 flags = unsigned(dereference(Cast(flags_ptr, 'uint32_t *'))) 712 out_str += " +----- [Interrupt Controller {ic}] vector {gsi}, {trigger_level}, {active}, {shareable}{messaged}\n" \ 713 .format(ic=matchingIC.name, gsi=hex(gsi), 714 trigger_level="level trigger" if flags & kInterruptTriggerModeLevel else "edge trigger", 715 active="active low" if flags & kInterruptPolarityLow else "active high", 716 shareable="shareable" if flags & kInterruptIsShareable else "exclusive", 717 messaged=", messaged" if flags & kIOInterruptTypePCIMessaged else "") 718 else: 719 out_str += " +----- [Interrupt Controller {ic}] vector {gsi}\n".format(ic=matchingIC.name, gsi=hex(gsi)) 720 if should_print: 721 print("[ {entry_name}{entry_location} ]{msi_mode}\n{out_str}" \ 722 .format(entry_name=entry_name, 723 entry_location=entry_location, 724 msi_mode=" - MSIs enabled" if msi_mode else "", 725 out_str=out_str)) 726 727@lldb_command("showiokitclasshierarchy") 728def ShowIOKitClassHierarchy(cmd_args=None): 729 """ 730 Show class hierarchy for a IOKit class 731 """ 732 if not cmd_args: 733 print("Usage: showiokitclasshierarchy <IOKit class name>") 734 return 735 736 class_name = cmd_args[0] 737 metaclasses = GetMetaClasses() 738 if class_name not in metaclasses: 739 print("Class {} does not exist".format(class_name)) 740 return 741 metaclass = metaclasses[class_name] 742 743 # loop over superclasses 744 hierarchy = [] 745 current_metaclass = metaclass 746 while current_metaclass is not None: 747 hierarchy.insert(0, current_metaclass) 748 current_metaclass = current_metaclass.superclass() 749 750 for (index, mc) in enumerate(hierarchy): 751 indent = (" " * index) + "+---" 752 print("{}[ {} ] {}".format(indent, str(mc.className()), str(mc.data()))) 753 754 755###################################### 756# Helper routines 757###################################### 758def ShowRegistryEntryRecurse(entry, prefix, printProps): 759 """ prints registry entry summary and recurses through all its children. 760 """ 761 # Setup 762 global plane 763 out_string = "" 764 plen = (len(prefix)//2) 765 registryTable = entry.fRegistryTable 766 propertyTable = entry.fPropertyTable 767 768 # Print entry details 769 print("{0:s}{1:s}".format(prefix, GetRegistryEntrySummary(entry))) 770 # Printing large property tables make it look like lldb is 'stuck' 771 if printProps: 772 print(GetRegDictionary(propertyTable, prefix + " | ")) 773 774 # Recurse 775 if plane is None: 776 childKey = kern.globals.gIOServicePlane.keys[1] 777 else: 778 childKey = plane.keys[1] 779 childArray = LookupKeyInOSDict(registryTable, childKey) 780 if childArray is not None: 781 idx = 0 782 ca = CastIOKitClass(childArray, 'OSArray *') 783 count = unsigned(ca.count) 784 while idx < count: 785 if plen != 0 and plen != 1 and (plen & (plen - 1)) == 0: 786 ShowRegistryEntryRecurse(CastIOKitClass(ca.array[idx], 'IORegistryEntry *'), prefix + "| ", printProps) 787 else: 788 ShowRegistryEntryRecurse(CastIOKitClass(ca.array[idx], 'IORegistryEntry *'), prefix + " ", printProps) 789 idx += 1 790 791def FindRegistryEntryRecurse(entry, search_name, stopAfterFirst): 792 """ Checks if given registry entry's name matches the search_name we're looking for 793 If yes, it prints the entry's summary and then recurses through its children 794 If no, it does nothing and recurses through its children 795 """ 796 # Setup 797 global plane 798 registryTable = entry.fRegistryTable 799 propertyTable = entry.fPropertyTable 800 801 # Compare 802 name = None 803 name = LookupKeyInOSDict(registryTable, kern.globals.gIOServicePlane.nameKey) 804 if name is None: 805 name = LookupKeyInOSDict(registryTable, kern.globals.gIONameKey) 806 if name is None: 807 name = LookupKeyInOSDict(propertyTable, kern.globals.gIOClassKey) 808 809 if name is not None: 810 if str(CastIOKitClass(name, 'OSString *').string) == search_name: 811 print(GetRegistryEntrySummary(entry)) 812 if stopAfterFirst is True: 813 return True 814 elif CastIOKitClass(entry, 'IOService *').pwrMgt and CastIOKitClass(entry, 'IOService *').pwrMgt.Name: 815 name = CastIOKitClass(entry, 'IOService *').pwrMgt.Name 816 if str(name) == search_name: 817 print(GetRegistryEntrySummary(entry)) 818 if stopAfterFirst is True: 819 return True 820 821 # Recurse 822 if plane is None: 823 childKey = kern.globals.gIOServicePlane.keys[1] 824 else: 825 childKey = plane.keys[1] 826 childArray = LookupKeyInOSDict(registryTable, childKey) 827 if childArray is not None: 828 idx = 0 829 ca = CastIOKitClass(childArray, 'OSArray *') 830 count = unsigned(ca.count) 831 while idx < count: 832 if FindRegistryEntryRecurse(CastIOKitClass(ca.array[idx], 'IORegistryEntry *'), search_name, stopAfterFirst) is True: 833 return True 834 idx += 1 835 return False 836 837def FindRegistryObjectRecurse(entry, search_name): 838 """ Checks if given registry entry's name matches the search_name we're looking for 839 If yes, return the entry 840 If no, it does nothing and recurses through its children 841 Implicitly stops after finding the first entry 842 """ 843 # Setup 844 global plane 845 registryTable = entry.fRegistryTable 846 propertyTable = entry.fPropertyTable 847 848 # Compare 849 name = None 850 name = LookupKeyInOSDict(registryTable, kern.globals.gIOServicePlane.nameKey) 851 if name is None: 852 name = LookupKeyInOSDict(registryTable, kern.globals.gIONameKey) 853 if name is None: 854 name = LookupKeyInOSDict(propertyTable, kern.globals.gIOClassKey) 855 856 if name is not None: 857 if str(CastIOKitClass(name, 'OSString *').string) == search_name: 858 return entry 859 elif CastIOKitClass(entry, 'IOService *').pwrMgt and CastIOKitClass(entry, 'IOService *').pwrMgt.Name: 860 name = CastIOKitClass(entry, 'IOService *').pwrMgt.Name 861 if str(name) == search_name: 862 return entry 863 864 # Recurse 865 if plane is None: 866 childKey = kern.globals.gIOServicePlane.keys[1] 867 else: 868 childKey = plane.keys[1] 869 childArray = LookupKeyInOSDict(registryTable, childKey) 870 if childArray is not None: 871 ca = CastIOKitClass(childArray, 'OSArray *') 872 for idx in range(ca.count): 873 registry_object = FindRegistryObjectRecurse(CastIOKitClass(ca.array[idx], 'IORegistryEntry *'), search_name) 874 if not registry_object or int(registry_object) == int(0): 875 continue 876 else: 877 return registry_object 878 return None 879 880def CompareStringToOSSymbol(string, os_sym): 881 """ 882 Lexicographically compare python string to OSSymbol 883 Params: 884 string - python string 885 os_sym - OSSymbol 886 887 Returns: 888 0 if string == os_sym 889 1 if string > os_sym 890 -1 if string < os_sym 891 """ 892 os_sym_str = GetString(os_sym) 893 if string > os_sym_str: 894 return 1 895 elif string < os_sym_str: 896 return -1 897 else: 898 return 0 899 900class IOKitMetaClass(object): 901 """ 902 A class that represents a IOKit metaclass. This is used to represent the 903 IOKit inheritance hierarchy. 904 """ 905 906 def __init__(self, meta): 907 """ 908 Initialize a IOKitMetaClass object. 909 910 Args: 911 meta (core.cvalue.value): A LLDB value representing a 912 OSMetaClass *. 913 """ 914 self._meta = meta 915 self._superclass = None 916 917 def data(self): 918 return self._meta 919 920 def setSuperclass(self, superclass): 921 """ 922 Set the superclass for this metaclass. 923 924 Args: 925 superclass (core.cvalue.value): A LLDB value representing a 926 OSMetaClass *. 927 """ 928 self._superclass = superclass 929 930 def superclass(self): 931 """ 932 Get the superclass for this metaclass (set by the setSuperclass method). 933 934 Returns: 935 core.cvalue.value: A LLDB value representing a OSMetaClass *. 936 """ 937 return self._superclass 938 939 def className(self): 940 """ 941 Get the name of the class this metaclass represents. 942 943 Returns: 944 str: The class name 945 """ 946 return self._meta.className.string 947 948 def inheritsFrom(self, other): 949 """ 950 Check if the class represented by this metaclass inherits from a class 951 represented by another metaclass. 952 953 Args: 954 other (IOKitMetaClass): The other metaclass 955 956 Returns: 957 bool: Returns True if this class inherits from the other class and 958 False otherwise. 959 """ 960 current = self 961 while current is not None: 962 if current == other: 963 return True 964 else: 965 current = current.superclass() 966 967 968def GetRegistryEntryClassName(entry): 969 """ 970 Get the class name of a registry entry. 971 972 Args: 973 entry (core.cvalue.value): A LLDB value representing a 974 IORegistryEntry *. 975 976 Returns: 977 str: The class name of the entry or None if a class name could not be 978 found. 979 """ 980 # Check using IOClass key 981 result = LookupKeyInOSDict(entry.fPropertyTable, kern.globals.gIOClassKey) 982 if result is not None: 983 return GetString(result).replace("\"", "") 984 else: 985 # Use the vtable of the entry to determine the concrete type 986 vt = dereference(Cast(entry, 'uintptr_t *')) - 2 * sizeof('uintptr_t') 987 vt = kern.StripKernelPAC(vt) 988 vtype = kern.SymbolicateFromAddress(vt) 989 if len(vtype) > 0: 990 vtableName = vtype[0].GetName() 991 return vtableName[11:] # strip off "vtable for " 992 else: 993 return None 994 995 996def GetRegistryEntryName(entry): 997 """ 998 Get the name of a registry entry. 999 1000 Args: 1001 entry (core.cvalue.value): A LLDB value representing a 1002 IORegistryEntry *. 1003 1004 Returns: 1005 str: The name of the entry or None if a name could not be found. 1006 """ 1007 name = None 1008 1009 # First check the IOService plane nameKey 1010 result = LookupKeyInOSDict(entry.fRegistryTable, kern.globals.gIOServicePlane.nameKey) 1011 if result is not None: 1012 name = GetString(result) 1013 1014 # Check the global IOName key 1015 if name is None: 1016 result = LookupKeyInOSDict(entry.fRegistryTable, kern.globals.gIONameKey) 1017 if result is not None: 1018 name = GetString(result) 1019 1020 # Check the IOClass key 1021 if name is None: 1022 result = LookupKeyInOSDict(entry.fPropertyTable, kern.globals.gIOClassKey) 1023 if result is not None: 1024 name = GetString(result) 1025 1026 # Remove extra quotes 1027 if name is not None: 1028 return name.replace("\"", "") 1029 else: 1030 return GetRegistryEntryClassName(entry) 1031 1032 1033def GetRegistryEntryLocationInPlane(entry, plane): 1034 """ 1035 Get the registry entry location in a IOKit plane. 1036 1037 Args: 1038 entry (core.cvalue.value): A LLDB value representing a 1039 IORegistryEntry *. 1040 plane: An IOKit plane such as kern.globals.gIOServicePlane. 1041 1042 Returns: 1043 str: The location of the entry or None if a location could not be 1044 found. 1045 """ 1046 # Check the plane's pathLocationKey 1047 sym = LookupKeyInOSDict(entry.fRegistryTable, plane.pathLocationKey) 1048 1049 # Check the global IOLocation key 1050 if sym is None: 1051 sym = LookupKeyInOSDict(entry.fRegistryTable, kern.globals.gIOLocationKey) 1052 if sym is not None: 1053 return GetString(sym).replace("\"", "") 1054 else: 1055 return None 1056 1057 1058@caching.cache_dynamically 1059def GetMetaClasses(target=None): 1060 """ 1061 Enumerate all IOKit metaclasses. Uses dynamic caching. 1062 1063 Returns: 1064 Dict[str, IOKitMetaClass]: A dictionary mapping each metaclass name to 1065 a IOKitMetaClass object representing the metaclass. 1066 """ 1067 1068 # This method takes a while, so it prints a progress indicator 1069 print("Enumerating IOKit metaclasses: ") 1070 1071 do_progress = os.isatty(sys.__stderr__.fileno()) 1072 1073 # Iterate over all classes present in sAllClassesDict 1074 count = unsigned(kern.globals.sAllClassesDict.count) 1075 metaclasses_by_address = {} 1076 for idx in range(count): 1077 if do_progress and idx % 10 == 0: 1078 sys.stderr.write("\033[K {} metaclass found...\r".format(idx)) 1079 1080 # Address of metaclass 1081 address = kern.globals.sAllClassesDict.dictionary[idx].value 1082 1083 # Create IOKitMetaClass and store in dict 1084 metaclasses_by_address[int(address)] = IOKitMetaClass(CastIOKitClass(kern.globals.sAllClassesDict.dictionary[idx].value, 'OSMetaClass *')) 1085 1086 # At this point, each metaclass is independent of each other. We don't have superclass links set up yet. 1087 1088 for address, metaclass in metaclasses_by_address.items(): 1089 # Get the address of the superclass using the superClassLink in IOMetaClass 1090 superclass_address = int(metaclass.data().superClassLink) 1091 1092 # Skip null superclass 1093 if superclass_address == 0: 1094 continue 1095 1096 # Find the superclass object in the dict 1097 if superclass_address in metaclasses_by_address: 1098 metaclass.setSuperclass(metaclasses_by_address[superclass_address]) 1099 else: 1100 print("warning: could not find superclass for {}".format(str(metaclass.data()))) 1101 1102 # This method returns a dictionary mapping each class name to the associated metaclass object 1103 metaclasses_by_name = {} 1104 for idx, (_, metaclass) in enumerate(metaclasses_by_address.items()): 1105 if do_progress and idx % 10 == 0: 1106 sys.stderr.write("\033[K {} metaclass indexed...\r".format(idx)) 1107 1108 metaclasses_by_name[str(metaclass.className())] = metaclass 1109 1110 print(" Indexed {} IOKit metaclasses.".format(count)) 1111 return metaclasses_by_name 1112 1113 1114def GetMatchingEntries(matcher): 1115 """ 1116 Iterate over the IOKit registry and find entries that match specific 1117 criteria. 1118 1119 Args: 1120 matcher (function): A matching function that returns True for a match 1121 and False otherwise. 1122 1123 Yields: 1124 core.cvalue.value: LLDB values that represent IORegistryEntry * for 1125 each registry entry found. 1126 """ 1127 1128 # Perform a BFS over the IOKit registry tree 1129 bfs_queue = deque() 1130 bfs_queue.append(kern.globals.gRegistryRoot) 1131 while len(bfs_queue) > 0: 1132 # Dequeue an entry 1133 entry = bfs_queue.popleft() 1134 1135 # Check if entry matches 1136 if matcher(entry): 1137 yield entry 1138 1139 # Find children of this entry and enqueue them 1140 child_array = LookupKeyInOSDict(entry.fRegistryTable, kern.globals.gIOServicePlane.keys[1]) 1141 if child_array is not None: 1142 idx = 0 1143 ca = CastIOKitClass(child_array, 'OSArray *') 1144 count = unsigned(ca.count) 1145 while idx < count: 1146 bfs_queue.append(CastIOKitClass(ca.array[idx], 'IORegistryEntry *')) 1147 idx += 1 1148 1149 1150def FindMatchingServices(matching_name): 1151 """ 1152 Finds registry entries that match the given string. Works similarly to: 1153 1154 io_iterator_t iter; 1155 IOServiceGetMatchingServices(..., IOServiceMatching(matching_name), &iter); 1156 while (( io_object_t next = IOIteratorNext(iter))) { ... } 1157 1158 Args: 1159 matching_name (str): The class name to search for. 1160 1161 Yields: 1162 core.cvalue.value: LLDB values that represent IORegistryEntry * for 1163 each registry entry found. 1164 """ 1165 1166 # Check if the argument is valid 1167 metaclasses = GetMetaClasses() 1168 if matching_name not in metaclasses: 1169 return 1170 matching_metaclass = metaclasses[matching_name] 1171 1172 # An entry matches if it inherits from matching_metaclass 1173 def matcher(entry): 1174 # Get the class name of the entry and the associated metaclass 1175 entry_name = GetRegistryEntryClassName(entry) 1176 if entry_name in metaclasses: 1177 entry_metaclass = metaclasses[entry_name] 1178 return entry_metaclass.inheritsFrom(matching_metaclass) 1179 else: 1180 return False 1181 1182 # Search for entries 1183 for entry in GetMatchingEntries(matcher): 1184 yield entry 1185 1186 1187def GetRegistryEntryParent(entry, iokit_plane=None): 1188 """ 1189 Gets the parent entry of a registry entry. 1190 1191 Args: 1192 entry (core.cvalue.value): A LLDB value representing a 1193 IORegistryEntry *. 1194 iokit_plane (core.cvalue.value, optional): A LLDB value representing a 1195 IORegistryPlane *. By default, this method uses the IOService 1196 plane. 1197 1198 Returns: 1199 core.cvalue.value: A LLDB value representing a IORegistryEntry* that 1200 is the parent entry of the entry argument in the specified plane. 1201 Returns None if no entry could be found. 1202 """ 1203 kParentSetIndex = 0 1204 parent_key = None 1205 if iokit_plane is None: 1206 parent_key = kern.globals.gIOServicePlane.keys[kParentSetIndex] 1207 else: 1208 parent_key = plane.keys[kParentSetIndex] 1209 parent_array = LookupKeyInOSDict(entry.fRegistryTable, parent_key) 1210 parent_entry = None 1211 if parent_array is not None: 1212 idx = 0 1213 ca = CastIOKitClass(parent_array, 'OSArray *') 1214 count = unsigned(ca.count) 1215 if count > 0: 1216 parent_entry = CastIOKitClass(ca.array[0], 'IORegistryEntry *') 1217 return parent_entry 1218 1219 1220def GetRegistryEntryInterruptProperties(entry): 1221 """ 1222 Get the interrupt properties of a registry entry. 1223 1224 Args: 1225 entry (core.cvalue.value): A LLDB value representing a IORegistryEntry *. 1226 1227 Returns: 1228 (bool, List[core.cvalue.value], List[str]): A tuple with the following 1229 fields: 1230 - First field (bool): Whether this entry has a non-null 1231 IOPCIMSIMode. 1232 - Second field (List[core.cvalue.value]): A list of LLDB values 1233 representing OSData *. The OSData* pointer points to 1234 interrupt vector data. 1235 - Third field (List[str]): A list of strings representing the 1236 interrupt controller names from the 1237 IOInterruptControllers property. 1238 """ 1239 INTERRUPT_SPECIFIERS_PROPERTY = "IOInterruptSpecifiers" 1240 INTERRUPT_CONTROLLERS_PROPERTY = "IOInterruptControllers" 1241 MSI_MODE_PROPERTY = "IOPCIMSIMode" 1242 1243 # Check IOInterruptSpecifiers 1244 interrupt_specifiers = LookupKeyInPropTable(entry.fPropertyTable, INTERRUPT_SPECIFIERS_PROPERTY) 1245 if interrupt_specifiers is not None: 1246 interrupt_specifiers = CastIOKitClass(interrupt_specifiers, 'OSArray *') 1247 1248 # Check IOInterruptControllers 1249 interrupt_controllers = LookupKeyInPropTable(entry.fPropertyTable, INTERRUPT_CONTROLLERS_PROPERTY) 1250 if interrupt_controllers is not None: 1251 interrupt_controllers = CastIOKitClass(interrupt_controllers, 'OSArray *') 1252 1253 # Check MSI mode 1254 msi_mode = LookupKeyInPropTable(entry.fPropertyTable, MSI_MODE_PROPERTY) 1255 1256 result_vector_data = [] 1257 result_vector_cont = [] 1258 if interrupt_specifiers is not None and interrupt_controllers is not None: 1259 interrupt_specifiers_array_count = unsigned(interrupt_specifiers.count) 1260 interrupt_controllers_array_count = unsigned(interrupt_controllers.count) 1261 # The array lengths should be the same 1262 if interrupt_specifiers_array_count == interrupt_controllers_array_count and interrupt_specifiers_array_count > 0: 1263 idx = 0 1264 while idx < interrupt_specifiers_array_count: 1265 # IOInterruptSpecifiers is an array of OSData * 1266 vector_data = CastIOKitClass(interrupt_specifiers.array[idx], "OSData *") 1267 1268 # IOInterruptControllers is an array of OSString * 1269 vector_cont = GetString(interrupt_controllers.array[idx]) 1270 1271 result_vector_data.append(vector_data) 1272 result_vector_cont.append(vector_cont) 1273 idx += 1 1274 1275 return (msi_mode is not None, result_vector_data, result_vector_cont) 1276 1277 1278class InterruptControllerDevice(object): 1279 """Represents a IOInterruptController""" 1280 1281 def __init__(self, device, driver, base_vector_number, name): 1282 """ 1283 Initialize a InterruptControllerDevice. 1284 1285 Args: 1286 device (core.cvalue.value): The device object. 1287 driver (core.cvalue.value): The driver object. 1288 base_vector_number (int): The base interrupt vector. 1289 name (str): The name of this interrupt controller. 1290 1291 Note: 1292 Use the factory method makeInterruptControllerDevice to validate 1293 properties. 1294 """ 1295 self.device = device 1296 self.driver = driver 1297 self.name = name 1298 self.base_vector_number = base_vector_number 1299 1300 1301 def __str__(self): 1302 """ 1303 String representation of this InterruptControllerDevice. 1304 """ 1305 return " Name {}, base vector = {}, device = {}, driver = {}".format( 1306 self.name, hex(self.base_vector_number), str(self.device), str(self.driver)) 1307 1308 @staticmethod 1309 def makeInterruptControllerDevice(device, driver): 1310 """ 1311 Factory method to create a InterruptControllerDevice. 1312 1313 Args: 1314 device (core.cvalue.value): The device object. 1315 driver (core.cvalue.value): The driver object. 1316 1317 Returns: 1318 InterruptControllerDevice: Returns an instance of 1319 InterruptControllerDevice or None if the arguments do not have 1320 the required properties. 1321 """ 1322 BASE_VECTOR_PROPERTY = "Base Vector Number" 1323 INTERRUPT_CONTROLLER_NAME_PROPERTY = "InterruptControllerName" 1324 base_vector = LookupKeyInPropTable(device.fPropertyTable, BASE_VECTOR_PROPERTY) 1325 if base_vector is None: 1326 base_vector = LookupKeyInPropTable(driver.fPropertyTable, BASE_VECTOR_PROPERTY) 1327 device_name = LookupKeyInPropTable(device.fPropertyTable, INTERRUPT_CONTROLLER_NAME_PROPERTY) 1328 if device_name is None: 1329 device_name = LookupKeyInPropTable(driver.fPropertyTable, INTERRUPT_CONTROLLER_NAME_PROPERTY) 1330 1331 if device_name is not None: 1332 # Some interrupt controllers do not have a base vector number. Assume it is 0. 1333 base_vector_number = 0 1334 if base_vector is not None: 1335 base_vector_number = unsigned(GetNumber(base_vector)) 1336 device_name = GetString(device_name) 1337 # Construct object and return 1338 return InterruptControllerDevice(device, driver, base_vector_number, device_name) 1339 else: 1340 # error case 1341 return None 1342 1343 1344def SearchInterruptControllerDrivers(): 1345 """ 1346 Search the IOKit registry for entries that match IOInterruptController. 1347 1348 Yields: 1349 core.cvalue.value: A LLDB value representing a IORegistryEntry * that 1350 inherits from IOInterruptController. 1351 """ 1352 for entry in FindMatchingServices("IOInterruptController"): 1353 # Get parent 1354 parent = GetRegistryEntryParent(entry) 1355 1356 # Make the interrupt controller object 1357 ic = InterruptControllerDevice.makeInterruptControllerDevice(parent, entry) 1358 1359 # Yield object 1360 if ic is not None: 1361 yield ic 1362 1363 1364def LookupKeyInOSDict(osdict, key, comparer = None): 1365 """ Returns the value corresponding to a given key in a OSDictionary 1366 Returns None if the key was not found 1367 """ 1368 if not osdict: 1369 return 1370 count = unsigned(osdict.count) 1371 result = None 1372 idx = 0 1373 1374 while idx < count and result is None: 1375 if comparer is not None: 1376 if comparer(key, osdict.dictionary[idx].key) == 0: 1377 result = osdict.dictionary[idx].value 1378 elif key == osdict.dictionary[idx].key: 1379 result = osdict.dictionary[idx].value 1380 idx += 1 1381 return result 1382 1383def LookupKeyInPropTable(propertyTable, key_str): 1384 """ Returns the value corresponding to a given key from a registry entry's property table 1385 Returns None if the key was not found 1386 The property that is being searched for is specified as a string in key_str 1387 """ 1388 if not propertyTable: 1389 return 1390 count = unsigned(propertyTable.count) 1391 result = None 1392 idx = 0 1393 while idx < count and result is None: 1394 if key_str == str(propertyTable.dictionary[idx].key.string): 1395 result = propertyTable.dictionary[idx].value 1396 idx += 1 1397 return result 1398 1399def GetRegDictionary(osdict, prefix): 1400 """ Returns a specially formatted string summary of the given OSDictionary 1401 This is done in order to pretty-print registry property tables in showregistry 1402 and other macros 1403 """ 1404 out_string = prefix + "{\n" 1405 idx = 0 1406 count = unsigned(osdict.count) 1407 1408 while idx < count: 1409 out_string += prefix + " " + GetObjectSummary(osdict.dictionary[idx].key) + " = " + GetObjectSummary(osdict.dictionary[idx].value) + "\n" 1410 idx += 1 1411 out_string += prefix + "}\n" 1412 return out_string 1413 1414def GetString(string): 1415 """ Returns the python string representation of a given OSString 1416 """ 1417 out_string = "{0:s}".format(CastIOKitClass(string, 'OSString *').string) 1418 return out_string 1419 1420def GetNumber(num): 1421 out_string = "{0:d}".format(CastIOKitClass(num, 'OSNumber *').value) 1422 return out_string 1423 1424def GetBoolean(b): 1425 """ Shows info about a given OSBoolean 1426 """ 1427 out_string = "" 1428 if b == kern.globals.gOSBooleanFalse: 1429 out_string += "No" 1430 else: 1431 out_string += "Yes" 1432 return out_string 1433 1434def GetMetaClass(mc): 1435 """ Shows info about a given OSSymbol 1436 """ 1437 out_string = "{0: <5d}x {1: >5d} bytes {2:s}\n".format(mc.instanceCount, mc.classSize, mc.className.string) 1438 return out_string 1439 1440def GetArray(arr): 1441 """ Returns a string containing info about a given OSArray 1442 """ 1443 out_string = "" 1444 idx = 0 1445 count = unsigned(arr.count) 1446 1447 while idx < count: 1448 obj = arr.array[idx] 1449 idx += 1 1450 out_string += GetObjectSummary(obj) 1451 if idx < unsigned(arr.count): 1452 out_string += "," 1453 return out_string 1454 1455def GetDictionary(d): 1456 """ Returns a string containing info about a given OSDictionary 1457 """ 1458 if d is None: 1459 return "" 1460 out_string = "{\n" 1461 idx = 0 1462 count = unsigned(d.count) 1463 1464 while idx < count: 1465 key = d.dictionary[idx].key 1466 value = d.dictionary[idx].value 1467 out_string += " \"{}\" = {}\n".format(GetString(key), GetObjectSummary(value)) 1468 idx += 1 1469 out_string += "}" 1470 return out_string 1471 1472def GetSet(se): 1473 """ Returns a string containing info about a given OSSet 1474 """ 1475 out_string = "[" + GetArray(se.members) + "]" 1476 return out_string 1477 1478def ReadIOPortInt(addr, numbytes, lcpu): 1479 """ Prints results after reading a given ioport 1480 """ 1481 result = 0xBAD10AD 1482 1483 if "kdp" != GetConnectionProtocol(): 1484 print("Target is not connected over kdp. Nothing to do here.") 1485 return 1486 1487 # Set up the manual KDP packet 1488 input_address = unsigned(addressof(kern.globals.manual_pkt.input)) 1489 len_address = unsigned(addressof(kern.globals.manual_pkt.len)) 1490 data_address = unsigned(addressof(kern.globals.manual_pkt.data)) 1491 if not WriteInt32ToMemoryAddress(0, input_address): 1492 print("0x{0: <4x}: 0x{1: <1x}".format(addr, result)) 1493 return 1494 1495 kdp_pkt_size = GetType('kdp_readioport_req_t').GetByteSize() 1496 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address): 1497 print("0x{0: <4x}: 0x{1: <1x}".format(addr, result)) 1498 return 1499 1500 kgm_pkt = kern.GetValueFromAddress(data_address, 'kdp_readioport_req_t *') 1501 1502 header_value = GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_READIOPORT'), length = kdp_pkt_size) 1503 1504 if( WriteInt64ToMemoryAddress((header_value), int(addressof(kgm_pkt.hdr))) and 1505 WriteInt16ToMemoryAddress(addr, int(addressof(kgm_pkt.address))) and 1506 WriteInt32ToMemoryAddress(numbytes, int(addressof(kgm_pkt.nbytes))) and 1507 WriteInt16ToMemoryAddress(lcpu, int(addressof(kgm_pkt.lcpu))) and 1508 WriteInt32ToMemoryAddress(1, input_address) 1509 ): 1510 1511 result_pkt = Cast(addressof(kern.globals.manual_pkt.data), 'kdp_readioport_reply_t *') 1512 1513 if(result_pkt.error == 0): 1514 if numbytes == 1: 1515 result = dereference(Cast(addressof(result_pkt.data), 'uint8_t *')) 1516 elif numbytes == 2: 1517 result = dereference(Cast(addressof(result_pkt.data), 'uint16_t *')) 1518 elif numbytes == 4: 1519 result = dereference(Cast(addressof(result_pkt.data), 'uint32_t *')) 1520 1521 print("{0: <#6x}: {1:#0{2}x}".format(addr, result, (numbytes*2)+2)) 1522 1523def WriteIOPortInt(addr, numbytes, value, lcpu): 1524 """ Writes 'value' into ioport specified by 'addr'. Prints errors if it encounters any 1525 """ 1526 if "kdp" != GetConnectionProtocol(): 1527 print("Target is not connected over kdp. Nothing to do here.") 1528 return 1529 1530 # Set up the manual KDP packet 1531 input_address = unsigned(addressof(kern.globals.manual_pkt.input)) 1532 len_address = unsigned(addressof(kern.globals.manual_pkt.len)) 1533 data_address = unsigned(addressof(kern.globals.manual_pkt.data)) 1534 if not WriteInt32ToMemoryAddress(0, input_address): 1535 print("error writing {0: #x} to port {1: <#6x}: failed to write 0 to input_address".format(value, addr)) 1536 return 1537 1538 kdp_pkt_size = GetType('kdp_writeioport_req_t').GetByteSize() 1539 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address): 1540 print("error writing {0: #x} to port {1: <#6x}: failed to write kdp_pkt_size".format(value, addr)) 1541 return 1542 1543 kgm_pkt = kern.GetValueFromAddress(data_address, 'kdp_writeioport_req_t *') 1544 1545 header_value = GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_WRITEIOPORT'), length = kdp_pkt_size) 1546 1547 if( WriteInt64ToMemoryAddress((header_value), int(addressof(kgm_pkt.hdr))) and 1548 WriteInt16ToMemoryAddress(addr, int(addressof(kgm_pkt.address))) and 1549 WriteInt32ToMemoryAddress(numbytes, int(addressof(kgm_pkt.nbytes))) and 1550 WriteInt16ToMemoryAddress(lcpu, int(addressof(kgm_pkt.lcpu))) 1551 ): 1552 if numbytes == 1: 1553 if not WriteInt8ToMemoryAddress(value, int(addressof(kgm_pkt.data))): 1554 print("error writing {0: #x} to port {1: <#6x}: failed to write 8 bit data".format(value, addr)) 1555 return 1556 elif numbytes == 2: 1557 if not WriteInt16ToMemoryAddress(value, int(addressof(kgm_pkt.data))): 1558 print("error writing {0: #x} to port {1: <#6x}: failed to write 16 bit data".format(value, addr)) 1559 return 1560 elif numbytes == 4: 1561 if not WriteInt32ToMemoryAddress(value, int(addressof(kgm_pkt.data))): 1562 print("error writing {0: #x} to port {1: <#6x}: failed to write 32 bit data".format(value, addr)) 1563 return 1564 if not WriteInt32ToMemoryAddress(1, input_address): 1565 print("error writing {0: #x} to port {1: <#6x}: failed to write to input_address".format(value, addr)) 1566 return 1567 1568 result_pkt = Cast(addressof(kern.globals.manual_pkt.data), 'kdp_writeioport_reply_t *') 1569 1570 # Done with the write 1571 if(result_pkt.error == 0): 1572 print("Writing {0: #x} to port {1: <#6x} was successful".format(value, addr)) 1573 else: 1574 print("error writing {0: #x} to port {1: <#6x}".format(value, addr)) 1575 1576@lldb_command('showinterruptcounts') 1577def showinterruptcounts(cmd_args=None): 1578 """ Shows event source based interrupt counts by nub name and interrupt index. 1579 Does not cover interrupts that are not event source based. Will report 0 1580 if interrupt accounting is disabled. 1581 """ 1582 1583 header_format = "{0: <20s} {1: >5s} {2: >20s}" 1584 content_format = "{0: <20s} {1: >5d} {2: >20d}" 1585 1586 print(header_format.format("Name", "Index", "Count")) 1587 1588 for i in kern.interrupt_stats: 1589 owner = CastIOKitClass(i.owner, 'IOInterruptEventSource *') 1590 nub = CastIOKitClass(owner.provider, 'IORegistryEntry *') 1591 name = None 1592 1593 # To uniquely identify an interrupt, we need the nub name and the index. The index 1594 # is stored with the stats object, but we need to retrieve the name. 1595 1596 registryTable = nub.fRegistryTable 1597 propertyTable = nub.fPropertyTable 1598 1599 name = LookupKeyInOSDict(registryTable, kern.globals.gIOServicePlane.nameKey) 1600 if name is None: 1601 name = LookupKeyInOSDict(registryTable, kern.globals.gIONameKey) 1602 if name is None: 1603 name = LookupKeyInOSDict(propertyTable, kern.globals.gIOClassKey) 1604 1605 if name is None: 1606 nub_name = "Unknown" 1607 else: 1608 nub_name = GetString(CastIOKitClass(name, 'OSString *')) 1609 1610 # We now have everything we need; spew the requested data. 1611 1612 interrupt_index = i.interruptIndex 1613 first_level_count = i.interruptStatistics[0] 1614 1615 print(content_format.format(nub_name, interrupt_index, first_level_count)) 1616 1617 return True 1618 1619@lldb_command('showinterruptstats') 1620def showinterruptstats(cmd_args=None): 1621 """ Shows event source based interrupt statistics by nub name and interrupt index. 1622 Does not cover interrupts that are not event source based. Will report 0 1623 if interrupt accounting is disabled, or if specific statistics are disabled. 1624 Time is reported in ticks of mach_absolute_time. Statistics are: 1625 1626 Interrupt Count: Number of times the interrupt context handler was run 1627 Interrupt Time: Total time spent in the interrupt context handler (if any) 1628 Workloop Count: Number of times the kernel context handler was run 1629 Workloop CPU Time: Total CPU time spent running the kernel context handler 1630 Workloop Time: Total time spent running the kernel context handler 1631 """ 1632 1633 header_format = "{0: <20s} {1: >5s} {2: >20s} {3: >20s} {4: >20s} {5: >20s} {6: >20s} {7: >20s} {8: >20s} {9: >20s}" 1634 content_format = "{0: <20s} {1: >5d} {2: >20d} {3: >20d} {4: >20d} {5: >20d} {6: >20d} {7: >20d} {8: >20d} {9: >#20x}" 1635 1636 print(header_format.format("Name", "Index", "Interrupt Count", "Interrupt Time", "Avg Interrupt Time", "Workloop Count", "Workloop CPU Time", "Workloop Time", "Avg Workloop Time", "Owner")) 1637 1638 for i in kern.interrupt_stats: 1639 owner = CastIOKitClass(i.owner, 'IOInterruptEventSource *') 1640 nub = CastIOKitClass(owner.provider, 'IORegistryEntry *') 1641 name = None 1642 1643 # To uniquely identify an interrupt, we need the nub name and the index. The index 1644 # is stored with the stats object, but we need to retrieve the name. 1645 1646 registryTable = nub.fRegistryTable 1647 propertyTable = nub.fPropertyTable 1648 1649 name = LookupKeyInOSDict(registryTable, kern.globals.gIOServicePlane.nameKey) 1650 if name is None: 1651 name = LookupKeyInOSDict(registryTable, kern.globals.gIONameKey) 1652 if name is None: 1653 name = LookupKeyInOSDict(propertyTable, kern.globals.gIOClassKey) 1654 1655 if name is None: 1656 nub_name = "Unknown" 1657 else: 1658 nub_name = GetString(CastIOKitClass(name, 'OSString *')) 1659 1660 # We now have everything we need; spew the requested data. 1661 1662 interrupt_index = i.interruptIndex 1663 first_level_count = i.interruptStatistics[0] 1664 second_level_count = i.interruptStatistics[1] 1665 first_level_time = i.interruptStatistics[2] 1666 second_level_cpu_time = i.interruptStatistics[3] 1667 second_level_system_time = i.interruptStatistics[4] 1668 1669 avg_first_level_time = 0 1670 if first_level_count != 0: 1671 avg_first_level_time = first_level_time // first_level_count 1672 1673 avg_second_level_time = 0 1674 if second_level_count != 0: 1675 avg_second_level_time = second_level_system_time // second_level_count 1676 1677 print(content_format.format(nub_name, interrupt_index, first_level_count, first_level_time, avg_first_level_time, 1678 second_level_count, second_level_cpu_time, second_level_system_time, avg_second_level_time, owner)) 1679 1680 return True 1681 1682def GetRegistryPlane(plane_name): 1683 """ 1684 Given plane_name, returns IORegistryPlane * object or None if there's no such registry plane 1685 """ 1686 return LookupKeyInOSDict(kern.globals.gIORegistryPlanes, plane_name, CompareStringToOSSymbol) 1687 1688def DecodePreoslogSource(source): 1689 """ 1690 Given preoslog source, return a matching string representation 1691 """ 1692 source_to_str = {0 : "iboot"} 1693 if source in source_to_str: 1694 return source_to_str[source] 1695 return "UNKNOWN" 1696 1697def GetPreoslogHeader(): 1698 """ 1699 Scan IODeviceTree for preoslog and return a python representation of it 1700 """ 1701 edt_plane = GetRegistryPlane("IODeviceTree") 1702 if edt_plane is None: 1703 print("Couldn't obtain a pointer to IODeviceTree") 1704 return None 1705 1706 # Registry API functions operate on "plane" global variable 1707 global plane 1708 prev_plane = plane 1709 plane = edt_plane 1710 chosen = FindRegistryObjectRecurse(kern.globals.gRegistryRoot, "chosen") 1711 if chosen is None: 1712 print("Couldn't obtain /chosen IORegistryEntry") 1713 return None 1714 1715 memory_map = FindRegistryObjectRecurse(chosen, "memory-map") 1716 if memory_map is None: 1717 print("Couldn't obtain memory-map from /chosen") 1718 return None 1719 1720 plane = prev_plane 1721 1722 mm_preoslog = LookupKeyInOSDict(memory_map.fPropertyTable, "preoslog", CompareStringToOSSymbol) 1723 if mm_preoslog is None: 1724 print("Couldn't find preoslog entry in memory-map") 1725 return None 1726 1727 if mm_preoslog.length != 16: 1728 print("preoslog entry in memory-map is malformed, expected len is 16, given len is {:d}".format(mm_preoslog.length)) 1729 return None 1730 1731 data = cast(mm_preoslog.data, "dtptr_t *") 1732 preoslog_paddr = unsigned(data[0]) 1733 preoslog_vaddr = kern.PhysToKernelVirt(preoslog_paddr) 1734 preoslog_size = unsigned(data[1]) 1735 1736 preoslog_header = PreoslogHeader() 1737 1738 # This structure defnition doesn't exist in xnu 1739 """ 1740 typedef struct __attribute__((packed)) { 1741 char magic[4]; 1742 uint32_t size; 1743 uint32_t offset; 1744 uint8_t source; 1745 uint8_t wrapped; 1746 char data[]; 1747 } preoslog_header_t; 1748 """ 1749 preoslog_header_ptr = kern.GetValueFromAddress(preoslog_vaddr, "uint8_t *") 1750 preoslog_header.magic = preoslog_header_ptr[0:4] 1751 preoslog_header.source = DecodePreoslogSource(unsigned(preoslog_header_ptr[12])) 1752 preoslog_header.wrapped = unsigned(preoslog_header_ptr[13]) 1753 preoslog_header_ptr = kern.GetValueFromAddress(preoslog_vaddr, "uint32_t *") 1754 preoslog_header.size = unsigned(preoslog_header_ptr[1]) 1755 preoslog_header.offset = unsigned(preoslog_header_ptr[2]) 1756 1757 for i in range(len(preoslog_header.valid_magic)): 1758 c = chr(unsigned(preoslog_header.magic[i])) 1759 if c != preoslog_header.valid_magic[i]: 1760 string = "Error: magic doesn't match, expected {:.4s}, given {:.4s}" 1761 print(string.format(preoslog_header.valid_magic, preoslog_header.magic)) 1762 return None 1763 1764 if preoslog_header.size != preoslog_size: 1765 string = "Error: size mismatch preoslog_header.size ({}) != preoslog_size ({})" 1766 print(string.format(preoslog_header.size, preoslog_size)) 1767 return None 1768 1769 preoslog_data_ptr = kern.GetValueFromAddress(preoslog_vaddr + 14, "char *") 1770 preoslog_header.data = preoslog_data_ptr.GetSBValue().GetPointeeData(0, preoslog_size) 1771 return preoslog_header 1772 1773@lldb_command("showpreoslog") 1774def showpreoslog(cmd_args=None): 1775 """ Display preoslog buffer """ 1776 1777 preoslog = GetPreoslogHeader() 1778 if preoslog is None: 1779 print("Error: couldn't obtain preoslog header") 1780 return False 1781 1782 header = "".join([ 1783 "----preoslog log header-----\n", 1784 "size - {} bytes\n", 1785 "write offset - {:#x}\n", 1786 "wrapped - {}\n", 1787 "source - {}\n", 1788 "----preoslog log start------" 1789 ]) 1790 1791 print(header.format(preoslog.size, preoslog.offset, preoslog.wrapped, preoslog.source)) 1792 1793 err = lldb.SBError() 1794 if preoslog.wrapped > 0: 1795 print(six.ensure_str(preoslog.data.GetString(err, preoslog.offset + 1))) 1796 print(six.ensure_str(preoslog.data.GetString(err, 0))) 1797 print("-----preoslog log end-------") 1798 return True 1799 1800@lldb_command('showeventsources') 1801def ShowEventSources(cmd_args=None): 1802 """ Show all event sources for a IOWorkLoop 1803 syntax: (lldb) showeventsources <IOWorkLoop *> 1804 """ 1805 if not cmd_args: 1806 print("Please specify the address of the IOWorkLoop") 1807 print(ShowEventSources.__doc__) 1808 return 1809 1810 obj = kern.GetValueFromAddress(cmd_args[0], 'IOWorkLoop *') 1811 idx = 0 1812 event = obj.eventChain 1813 while event != 0: 1814 enabled = event.enabled 1815 print("{}: {} [{}]".format(idx, GetObjectSummary(event), "enabled" if enabled else "disabled")) 1816 event = event.eventChainNext 1817 idx += 1 1818