1""" 2Miscellaneous (Intel) platform-specific commands. 3""" 4 5from xnu import * 6import xnudefines 7 8from scheduler import * 9 10@lldb_command('showlogstream') 11def showLogStream(cmd_args=None): 12 """ 13 Dump the state of the kernel log stream 14 """ 15 mbp = kern.globals.oslog_streambufp 16 print "streaming buffer space avail: {0:>#x} of {1:>#x} bytes\n".format(kern.globals.oslog_stream_buf_bytesavail, kern.globals.oslog_stream_buf_size) 17 print " read head: offset {0:>#x}\nwrite head: offset {1:>#x}\n".format(mbp.msg_bufr, mbp.msg_bufx) 18 count = 0 19 print " id timestamp offset size off+size type metadata" 20 for entry in IterateSTAILQ_HEAD(kern.globals.oslog_stream_buf_head, "buf_entries"): 21 next_start = entry.offset + entry.size 22 if (next_start > 0x1000): 23 next_start = next_start - 0x1000 24 print "{0:>4d}: {1:<d} {2:>5x} {3:>4d} {4:>5x} {5:<d} {6:<d}".format(count, entry.timestamp, entry.offset, entry.size, next_start, entry.type, entry.metadata) 25 count = count + 1 26 print "found {} entries".format(count) 27 28 count = 0 29 for entry in IterateSTAILQ_HEAD(kern.globals.oslog_stream_free_head, "buf_entries"): 30 count = count + 1 31 print "free list: {} entries".format(count) 32 33 count = 0 34 for outer in IterateSTAILQ_HEAD(kern.globals.oslog_stream_buf_head, "buf_entries"): 35 for inner in IterateSTAILQ_HEAD(kern.globals.oslog_stream_buf_head, "buf_entries"): 36 if ((outer.offset > inner.offset) and 37 (outer.offset < inner.offset + inner.size)): 38 print "error: overlapping entries: {:>3x} <--> {:>3x}".format(outer.offset, inner.offset) 39 count = count + 1 40 41@lldb_command('showmcastate') 42def showMCAstate(cmd_args=None): 43 """ 44 Print machine-check register state after MC exception. 45 """ 46 if kern.arch != 'x86_64': 47 print "Not available for current architecture." 48 return 49 50 present = ["not present", "present"] 51 print 'MCA {:s}, control MSR {:s}, threshold status {:s}'.format( 52 present[int(kern.globals.mca_MCA_present)], 53 present[int(kern.globals.mca_control_MSR_present)], 54 present[int(kern.globals.mca_threshold_status_present)]) 55 print '{:d} error banks, family code {:#0x}, machine-check dump state: {:d}'.format( 56 kern.globals.mca_error_bank_count, 57 kern.globals.mca_dump_state, 58 kern.globals.mca_family) 59 cpu = 0 60 while kern.globals.cpu_data_ptr[cpu]: 61 cd = kern.globals.cpu_data_ptr[cpu] 62 mc = cd.cpu_mca_state 63 if mc: 64 print 'CPU {:d}: mca_mcg_ctl: {:#018x} mca_mcg_status {:#018x}'.format(cpu, mc.mca_mcg_ctl, mc.mca_mcg_status.u64) 65 hdr = '{:<4s} {:<18s} {:<18s} {:<18s} {:<18s}' 66 val = '{:>3d}: {:#018x} {:#018x} {:#018x} {:#018x}' 67 print hdr.format('bank', 68 'mca_mci_ctl', 69 'mca_mci_status', 70 'mca_mci_addr', 71 'mca_mci_misc') 72 for i in range(int(kern.globals.mca_error_bank_count)): 73 bank = mc.mca_error_bank[i] 74 print val.format(i, 75 bank.mca_mci_ctl, 76 bank.mca_mci_status.u64, 77 bank.mca_mci_addr, 78 bank.mca_mci_misc) 79 print 'register state:' 80 reg = cd.cpu_desc_index.cdi_ktss.ist1 - sizeof('x86_saved_state_t') 81 print lldb_run_command('p/x *(x86_saved_state_t *) ' + hex(reg)) 82 cpu = cpu + 1 83 84def dumpTimerList(mpqueue): 85 """ 86 Utility function to dump the timer entries in list (anchor). 87 anchor is a struct mpqueue_head. 88 """ 89 90 if mpqueue.count == 0: 91 print '(empty)' 92 return 93 94 thdr = ' {:<24s}{:<17s}{:<16s} {:<14s} {:<18s} count: {:d} ' 95 tval = ' {:#018x}: {:16d} {:16d} {:s}{:3d}.{:09d} ({:#018x})({:#018x}, {:#018x}) ({:s}) {:s}' 96 97 print thdr.format('Entry', 'Deadline', 'soft_deadline', 'Secs To Go', '(*func)(param0, param1)', mpqueue.count) 98 99 for timer_call in ParanoidIterateLinkageChain(mpqueue.head, 'struct timer_call *', 'tc_qlink'): 100 recent_timestamp = GetRecentTimestamp() 101 if (recent_timestamp < timer_call.tc_pqlink.deadline): 102 delta_sign = ' ' 103 timer_fire = timer_call.tc_pqlink.deadline - recent_timestamp 104 else: 105 delta_sign = '-' 106 timer_fire = recent_timestamp - timer_call.tc_pqlink.deadline 107 108 func_name = kern.Symbolicate(timer_call.tc_func) 109 110 extra_string = "" 111 112 strip_func = kern.StripKernelPAC(unsigned(timer_call.tc_func)) 113 114 func_syms = kern.SymbolicateFromAddress(strip_func) 115 # returns an array of SBSymbol 116 117 if func_syms and func_syms[0] : 118 func_sym = func_syms[0] 119 func_name = func_sym.GetName() 120 try : 121 122 if "thread_call_delayed_timer" in func_name : 123 group = Cast(timer_call.tc_param0, 'struct thread_call_group *') 124 flavor = Cast(timer_call.tc_param1, 'thread_call_flavor_t') 125 126 # There's got to be a better way to stringify the enum 127 flavorname = str(flavor).partition(" = ")[2] 128 129 extra_string += "{:s} {:s}".format(group.tcg_name, flavorname) 130 131 if "thread_timer_expire" in func_name : 132 thread = Cast(timer_call.tc_param0, 'thread_t') 133 134 tid = thread.thread_id 135 name = GetThreadName(thread) 136 pid = GetProcPIDForTask(thread.t_tro.tro_task) 137 procname = GetProcNameForTask(thread.t_tro.tro_task) 138 139 extra_string += "thread: 0x{:x} {:s} task:{:s}[{:d}]".format( 140 tid, name, procname, pid) 141 except: 142 print "exception generating extra_string for call: {:#018x}".format(timer_call) 143 if dumpTimerList.enable_debug : 144 raise 145 146 tval = ' {:#018x}: {:16d} {:16d} {:s}{:3d}.{:09d} ({:#018x})({:#018x},{:#018x}) ({:s}) {:s}' 147 print tval.format(timer_call, 148 timer_call.tc_pqlink.deadline, 149 timer_call.tc_soft_deadline, 150 delta_sign, 151 timer_fire/1000000000, 152 timer_fire%1000000000, 153 timer_call.tc_func, 154 timer_call.tc_param0, 155 timer_call.tc_param1, 156 func_name, extra_string) 157 158dumpTimerList.enable_debug = False 159 160def GetCpuDataForCpuID(cpu_id): 161 """ 162 Find struct cpu_data for a CPU 163 ARM is complicated 164 """ 165 if kern.arch == 'x86_64': 166 cpu_data = kern.globals.cpu_data_ptr[cpu_id] 167 return cpu_data 168 elif kern.arch.startswith('arm'): 169 data_entries_addr = kern.GetLoadAddressForSymbol('CpuDataEntries') 170 data_entries = kern.GetValueFromAddress(data_entries_addr, 'cpu_data_entry_t *') 171 data_entry = data_entries[cpu_id]; 172 cpu_data_addr = data_entry.cpu_data_vaddr 173 return Cast(cpu_data_addr, 'cpu_data_t*') 174 175@lldb_command('longtermtimers') 176def longtermTimers(cmd_args=None): 177 """ 178 Print details of long-term timers and stats. 179 """ 180 181 lt = kern.globals.timer_longterm 182 ltt = lt.threshold 183 EndofAllTime = long(-1) 184 if long(ltt.interval) == EndofAllTime: 185 print "Longterm timers disabled" 186 return 187 188 if lt.escalates > 0: 189 ratio = lt.enqueues / lt.escalates 190 else: 191 ratio = lt.enqueues 192 print 'Longterm timer object: {:#018x}'.format(addressof(lt)) 193 print ' queue count : {:d}' .format(lt.queue.count) 194 print ' number of enqueues : {:d}' .format(lt.enqueues) 195 print ' number of dequeues : {:d}' .format(lt.dequeues) 196 print ' number of escalates : {:d}' .format(lt.escalates) 197 print ' enqueues/escalates : {:d}' .format(ratio) 198 print ' threshold.interval : {:d}' .format(ltt.interval) 199 print ' threshold.margin : {:d}' .format(ltt.margin) 200 print ' scan_time : {:#018x} ({:d})'.format(lt.scan_time, lt.scan_time) 201 if long(ltt.preempted) == EndofAllTime: 202 print ' threshold.preempted : None' 203 else: 204 print ' threshold.preempted : {:#018x} ({:d})'.format(ltt.preempted, ltt.preempted) 205 if long(ltt.deadline) == EndofAllTime: 206 print ' threshold.deadline : None' 207 else: 208 print ' threshold.deadline : {:#018x} ({:d})'.format(ltt.deadline, ltt.deadline) 209 print ' threshold.call : {:#018x}'.format(ltt.call) 210 print ' actual deadline set : {:#018x} ({:d})'.format(ltt.deadline_set, ltt.deadline_set) 211 print ' threshold.scans : {:d}' .format(ltt.scans) 212 print ' threshold.preempts : {:d}' .format(ltt.preempts) 213 print ' threshold.latency : {:d}' .format(ltt.latency) 214 print ' - min : {:d}' .format(ltt.latency_min) 215 print ' - max : {:d}' .format(ltt.latency_max) 216 dumpTimerList(lt.queue) 217 218 219@lldb_command('processortimers') 220def processorTimers(cmd_args=None): 221 """ 222 Print details of processor timers, noting anything suspicious 223 Also include long-term timer details 224 """ 225 hdr = '{:15s}{:<18s} {:<18s} {:<18s} {:<18s}' 226 print hdr.format('Processor #', 'Processor pointer', 'Last dispatch', 'Next deadline', 'Difference') 227 print "=" * 82 228 p = kern.globals.processor_list 229 EndOfAllTime = long(-1) 230 while p: 231 cpu = p.cpu_id 232 cpu_data = GetCpuDataForCpuID(cpu) 233 rt_timer = cpu_data.rtclock_timer 234 diff = long(rt_timer.deadline) - long(p.last_dispatch) 235 valid_deadline = long(rt_timer.deadline) != EndOfAllTime 236 tmr = 'Processor {:<3d}: {:#018x} {:#018x} {:18s} {:18s} {:s}' 237 print tmr.format(cpu, 238 p, 239 p.last_dispatch, 240 "{:#018x}".format(rt_timer.deadline) if valid_deadline else "None", 241 "{:#018x}".format(diff) if valid_deadline else "N/A", 242 ['(PAST DEADLINE)', '(ok)'][int(diff > 0)] if valid_deadline else "") 243 if valid_deadline: 244 if kern.arch == 'x86_64': 245 print 'Next deadline set at: {:#018x}. Timer call list:'.format(rt_timer.when_set) 246 dumpTimerList(rt_timer.queue) 247 p = p.processor_list 248 print "-" * 82 249 longtermTimers() 250 ShowRunningTimers() 251 252 253@lldb_command('showtimerwakeupstats') 254def showTimerWakeupStats(cmd_args=None): 255 """ 256 Displays interrupt and platform idle wakeup frequencies 257 associated with each thread, timer time-to-deadline frequencies, and 258 CPU time with user/system break down where applicable, with thread tags. 259 """ 260 for task in kern.tasks: 261 proc = Cast(task.bsd_info, 'proc_t') 262 print dereference(task) 263 print '{:d}({:s}), terminated thread timer wakeups: {:d} {:d} 2ms: {:d} 5ms: {:d} UT: {:d} ST: {:d}'.format( 264 GetProcPID(proc), 265 GetProcName(proc), 266# Commented-out references below to be addressed by rdar://13009660. 267 0, #task.task_interrupt_wakeups, 268 0, #task.task_platform_idle_wakeups, 269 task.task_timer_wakeups_bin_1, 270 task.task_timer_wakeups_bin_2, 271 task.total_user_time, 272 task.total_system_time) 273 tot_wakes = 0 #task.task_interrupt_wakeups 274 tot_platform_wakes = 0 #task.task_platform_idle_wakeups 275 for thread in IterateQueue(task.threads, 'thread_t', 'task_threads'): 276## if thread.thread_interrupt_wakeups == 0: 277## continue 278 print '\tThread ID 0x{:x}, Tag 0x{:x}, timer wakeups: {:d} {:d} {:d} {:d} <2ms: {:d}, <5ms: {:d} UT: {:d} ST: {:d}'.format( 279 thread.thread_id, 280 thread.thread_tag, 281 0, #thread.thread_interrupt_wakeups, 282 0, #thread.thread_platform_idle_wakeups, 283 0, #thread.thread_callout_interrupt_wakeups, 284 0, #thread.thread_callout_platform_idle_wakeups, 285 0,0,0,0, 286 thread.thread_timer_wakeups_bin_1, 287 thread.thread_timer_wakeups_bin_2, 288 thread.user_timer.all_bits, 289 thread.system_timer.all_bits) 290 tot_wakes += 0 #thread.thread_interrupt_wakeups 291 tot_platform_wakes += 0 #thread.thread_platform_idle_wakeups 292 print 'Task total wakeups: {:d} {:d}'.format( 293 tot_wakes, tot_platform_wakes) 294 295@lldb_command('showrunningtimers') 296def ShowRunningTimers(cmd_args=None): 297 """ 298 Print the state of all running timers. 299 300 Usage: showrunningtimers 301 """ 302 pset = addressof(kern.globals.pset0) 303 processor_array = kern.globals.processor_array 304 305 i = 0 306 while processor_array[i] != 0: 307 processor = processor_array[i] 308 print('{}: {}'.format( 309 i, 'on' if processor.running_timers_active else 'off')) 310 print('\tquantum: {}'.format( 311 unsigned(processor.running_timers[0].tc_pqlink.deadline))) 312 print('\tkperf: {}'.format( 313 unsigned(processor.running_timers[1].tc_pqlink.deadline))) 314 i += 1 315 316def DoReadMsr64(msr_address, lcpu): 317 """ Read a 64-bit MSR from the specified CPU 318 Params: 319 msr_address: int - MSR index to read from 320 lcpu: int - CPU identifier 321 Returns: 322 64-bit value read from the MSR 323 """ 324 result = 0xbad10ad 325 326 if "kdp" != GetConnectionProtocol(): 327 print "Target is not connected over kdp. Cannot read MSR." 328 return result 329 330 input_address = unsigned(addressof(kern.globals.manual_pkt.input)) 331 len_address = unsigned(addressof(kern.globals.manual_pkt.len)) 332 data_address = unsigned(addressof(kern.globals.manual_pkt.data)) 333 if not WriteInt32ToMemoryAddress(0, input_address): 334 print "DoReadMsr64() failed to write 0 to input_address" 335 return result 336 337 kdp_pkt_size = GetType('kdp_readmsr64_req_t').GetByteSize() 338 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address): 339 print "DoReadMsr64() failed to write kdp_pkt_size" 340 return result 341 342 kgm_pkt = kern.GetValueFromAddress(data_address, 'kdp_readmsr64_req_t *') 343 header_value = GetKDPPacketHeaderInt( 344 request=GetEnumValue('kdp_req_t::KDP_READMSR64'), 345 length=kdp_pkt_size) 346 347 if not WriteInt64ToMemoryAddress(header_value, int(addressof(kgm_pkt.hdr))): 348 print "DoReadMsr64() failed to write header_value" 349 return result 350 if not WriteInt32ToMemoryAddress(msr_address, int(addressof(kgm_pkt.address))): 351 print "DoReadMsr64() failed to write msr_address" 352 return result 353 if not WriteInt16ToMemoryAddress(lcpu, int(addressof(kgm_pkt.lcpu))): 354 print "DoReadMsr64() failed to write lcpu" 355 return result 356 if not WriteInt32ToMemoryAddress(1, input_address): 357 print "DoReadMsr64() failed to write to input_address" 358 return result 359 360 result_pkt = Cast(addressof(kern.globals.manual_pkt.data), 361 'kdp_readmsr64_reply_t *') 362 if (result_pkt.error == 0): 363 result = dereference(Cast(addressof(result_pkt.data), 'uint64_t *')) 364 else: 365 print "DoReadMsr64() result_pkt.error != 0" 366 return result 367 368def DoWriteMsr64(msr_address, lcpu, data): 369 """ Write a 64-bit MSR 370 Params: 371 msr_address: int - MSR index to write to 372 lcpu: int - CPU identifier 373 data: int - value to write 374 Returns: 375 True upon success, False if error 376 """ 377 if "kdp" != GetConnectionProtocol(): 378 print "Target is not connected over kdp. Cannot write MSR." 379 return False 380 381 input_address = unsigned(addressof(kern.globals.manual_pkt.input)) 382 len_address = unsigned(addressof(kern.globals.manual_pkt.len)) 383 data_address = unsigned(addressof(kern.globals.manual_pkt.data)) 384 if not WriteInt32ToMemoryAddress(0, input_address): 385 print "DoWriteMsr64() failed to write 0 to input_address" 386 return False 387 388 kdp_pkt_size = GetType('kdp_writemsr64_req_t').GetByteSize() 389 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address): 390 print "DoWriteMsr64() failed to kdp_pkt_size" 391 return False 392 393 kgm_pkt = kern.GetValueFromAddress(data_address, 'kdp_writemsr64_req_t *') 394 header_value = GetKDPPacketHeaderInt( 395 request=GetEnumValue('kdp_req_t::KDP_WRITEMSR64'), 396 length=kdp_pkt_size) 397 398 if not WriteInt64ToMemoryAddress(header_value, int(addressof(kgm_pkt.hdr))): 399 print "DoWriteMsr64() failed to write header_value" 400 return False 401 if not WriteInt32ToMemoryAddress(msr_address, int(addressof(kgm_pkt.address))): 402 print "DoWriteMsr64() failed to write msr_address" 403 return False 404 if not WriteInt16ToMemoryAddress(lcpu, int(addressof(kgm_pkt.lcpu))): 405 print "DoWriteMsr64() failed to write lcpu" 406 return False 407 if not WriteInt64ToMemoryAddress(data, int(addressof(kgm_pkt.data))): 408 print "DoWriteMsr64() failed to write data" 409 return False 410 if not WriteInt32ToMemoryAddress(1, input_address): 411 print "DoWriteMsr64() failed to write to input_address" 412 return False 413 414 result_pkt = Cast(addressof(kern.globals.manual_pkt.data), 415 'kdp_writemsr64_reply_t *') 416 if not result_pkt.error == 0: 417 print "DoWriteMsr64() error received in reply packet" 418 return False 419 420 return True 421 422@lldb_command('readmsr64') 423def ReadMsr64(cmd_args=None): 424 """ Read the specified MSR. The CPU can be optionally specified 425 Syntax: readmsr64 <msr> [lcpu] 426 """ 427 if cmd_args == None or len(cmd_args) < 1: 428 print ReadMsr64.__doc__ 429 return 430 431 msr_address = ArgumentStringToInt(cmd_args[0]) 432 if len(cmd_args) > 1: 433 lcpu = ArgumentStringToInt(cmd_args[1]) 434 else: 435 lcpu = int(xnudefines.lcpu_self) 436 437 msr_value = DoReadMsr64(msr_address, lcpu) 438 print "MSR[{:x}]: {:#016x}".format(msr_address, msr_value) 439 440@lldb_command('writemsr64') 441def WriteMsr64(cmd_args=None): 442 """ Write the specified MSR. The CPU can be optionally specified 443 Syntax: writemsr64 <msr> <value> [lcpu] 444 """ 445 if cmd_args == None or len(cmd_args) < 2: 446 print WriteMsr64.__doc__ 447 return 448 msr_address = ArgumentStringToInt(cmd_args[0]) 449 write_val = ArgumentStringToInt(cmd_args[1]) 450 if len(cmd_args) > 2: 451 lcpu = ArgumentStringToInt(cmd_args[2]) 452 else: 453 lcpu = xnudefines.lcpu_self 454 455 if not DoWriteMsr64(msr_address, lcpu, write_val): 456 print "writemsr64 FAILED" 457 458def GetKernelDebugBufferEntry(kdbg_entry): 459 """ Extract the information from given kernel debug buffer entry and return the summary 460 params: 461 kdebug_entry - kd_buf - address of kernel debug buffer entry 462 returns: 463 str - formatted output information of kd_buf entry 464 """ 465 out_str = "" 466 code_info_str = "" 467 kdebug_entry = kern.GetValueFromAddress(kdbg_entry, 'kd_buf *') 468 debugid = kdebug_entry.debugid 469 kdebug_arg1 = kdebug_entry.arg1 470 kdebug_arg2 = kdebug_entry.arg2 471 kdebug_arg3 = kdebug_entry.arg3 472 kdebug_arg4 = kdebug_entry.arg4 473 474 if kern.arch == 'x86_64' or kern.arch.startswith('arm64'): 475 kdebug_cpu = kdebug_entry.cpuid 476 ts_hi = (kdebug_entry.timestamp >> 32) & 0xFFFFFFFF 477 ts_lo = kdebug_entry.timestamp & 0xFFFFFFFF 478 else: 479 kdebug_cpu = (kdebug_entry.timestamp >> 56) 480 ts_hi = (kdebug_entry.timestamp >> 32) & 0x00FFFFFF 481 ts_lo = kdebug_entry.timestamp & 0xFFFFFFFF 482 483 kdebug_class = (debugid >> 24) & 0x000FF 484 kdebug_subclass = (debugid >> 16) & 0x000FF 485 kdebug_code = (debugid >> 2) & 0x03FFF 486 kdebug_qual = (debugid) & 0x00003 487 488 if kdebug_qual == 0: 489 kdebug_qual = '-' 490 elif kdebug_qual == 1: 491 kdebug_qual = 'S' 492 elif kdebug_qual == 2: 493 kdebug_qual = 'E' 494 elif kdebug_qual == 3: 495 kdebug_qual = '?' 496 497 # preamble and qual 498 out_str += "{:<#20x} {:>6d} {:>#12x} ".format(kdebug_entry, kdebug_cpu, kdebug_entry.arg5) 499 out_str += " {:#010x}{:08x} {:>6s} ".format(ts_hi, ts_lo, kdebug_qual) 500 501 # class 502 kdbg_class = "" 503 if kdebug_class == 1: 504 kdbg_class = "MACH" 505 elif kdebug_class == 2: 506 kdbg_class = "NET " 507 elif kdebug_class == 3: 508 kdbg_class = "FS " 509 elif kdebug_class == 4: 510 kdbg_class = "BSD " 511 elif kdebug_class == 5: 512 kdbg_class = "IOK " 513 elif kdebug_class == 6: 514 kdbg_class = "DRVR" 515 elif kdebug_class == 7: 516 kdbg_class = "TRAC" 517 elif kdebug_class == 8: 518 kdbg_class = "DLIL" 519 elif kdebug_class == 9: 520 kdbg_class = "WQ " 521 elif kdebug_class == 10: 522 kdbg_class = "CS " 523 elif kdebug_class == 11: 524 kdbg_class = "CG " 525 elif kdebug_class == 20: 526 kdbg_class = "MISC" 527 elif kdebug_class == 30: 528 kdbg_class = "SEC " 529 elif kdebug_class == 31: 530 kdbg_class = "DYLD" 531 elif kdebug_class == 32: 532 kdbg_class = "QT " 533 elif kdebug_class == 33: 534 kdbg_class = "APPS" 535 elif kdebug_class == 34: 536 kdbg_class = "LAUN" 537 elif kdebug_class == 36: 538 kdbg_class = "PPT " 539 elif kdebug_class == 37: 540 kdbg_class = "PERF" 541 elif kdebug_class == 38: 542 kdbg_class = "IMP " 543 elif kdebug_class == 39: 544 kdbg_class = "PCTL" 545 elif kdebug_class == 40: 546 kdbg_class = "BANK" 547 elif kdebug_class == 41: 548 kdbg_class = "XPC " 549 elif kdebug_class == 42: 550 kdbg_class = "ATM " 551 elif kdebug_class == 128: 552 kdbg_class = "ANS " 553 elif kdebug_class == 129: 554 kdbg_class = "SIO " 555 elif kdebug_class == 130: 556 kdbg_class = "SEP " 557 elif kdebug_class == 131: 558 kdbg_class = "ISP " 559 elif kdebug_class == 132: 560 kdbg_class = "OSCA" 561 elif kdebug_class == 133: 562 kdbg_class = "EGFX" 563 elif kdebug_class == 255: 564 kdbg_class = "MIG " 565 else: 566 out_str += "{:^#10x} ".format(kdebug_class) 567 568 if kdbg_class: 569 out_str += "{:^10s} ".format(kdbg_class) 570 571 # subclass and code 572 out_str += " {:>#5x} {:>8d} ".format(kdebug_subclass, kdebug_code) 573 574 # space for debugid-specific processing 575 code_info_str += "arg1={:#010x} ".format(kdebug_arg1) 576 code_info_str += "arg2={:#010x} ".format(kdebug_arg2) 577 code_info_str += "arg3={:#010x} ".format(kdebug_arg3) 578 code_info_str += "arg4={:#010x} ".format(kdebug_arg4) 579 580 # finish up 581 out_str += "{:<25s}\n".format(code_info_str) 582 return out_str 583 584@lldb_command('showkerneldebugbuffercpu') 585@header("{0: ^20s} {1: >6s} {2: >12s} {3: ^20s} {4: >6s} {5: ^10s} {6: >5s} {7: >8s} {8: ^25s}". 586 format('kd_buf', 'CPU', 'Thread', 'Timestamp', 'S/E', 'Class', 'Sub', 'Code', 'Code Specific Info')) 587def ShowKernelDebugBufferCPU(cmd_args=None): 588 """ Prints the last N entries in the kernel debug buffer for specified cpu 589 Syntax: showkerneldebugbuffercpu <cpu_num> <count> 590 """ 591 if cmd_args == None or len(cmd_args) < 2: 592 raise ArgumentError("Invalid arguments passed.") 593 594 out_str = "" 595 kdbg_str = "" 596 cpu_number = ArgumentStringToInt(cmd_args[0]) 597 entry_count = ArgumentStringToInt(cmd_args[1]) 598 debugentriesfound = 0 599 if (kern.globals.kd_ctrl_page_trace.kdebug_flags & xnudefines.KDBG_BUFINIT): 600 out_str += ShowKernelDebugBufferCPU.header + "\n" 601 if entry_count == 0: 602 out_str += "<count> is 0, dumping 50 entries\n" 603 entry_count = 50 604 605 if cpu_number >= kern.globals.kd_ctrl_page_trace.kdebug_cpus: 606 kdbg_str += "cpu number too big\n" 607 else: 608 kdbp = addressof(kern.globals.kd_data_page_trace.kdbip[cpu_number]) 609 kdsp = kdbp.kd_list_head 610 while ((kdsp.raw != 0 and kdsp.raw != 0x00000000ffffffff) and (entry_count > 0)): 611 kd_buffer = kern.globals.kd_data_page_trace.kd_bufs[kdsp.buffer_index] 612 kdsp_actual = addressof(kd_buffer.kdsb_addr[kdsp.offset]) 613 if kdsp_actual.kds_readlast != kdsp_actual.kds_bufindx: 614 kds_buf = kdsp_actual.kds_records[kdsp_actual.kds_bufindx] 615 kds_bufptr = addressof(kds_buf) 616 while (entry_count > 0) and \ 617 (unsigned(kds_bufptr) > unsigned(addressof(kdsp_actual.kds_records[kdsp_actual.kds_readlast]))): 618 kds_bufptr = kds_bufptr - sizeof(kds_buf) 619 entry_count = entry_count - 1 620 kdbg_str += GetKernelDebugBufferEntry(kds_bufptr) 621 kdsp = kdsp_actual.kds_next 622 else: 623 kdbg_str += "Trace buffer not enabled for CPU {:d}\n".format(cpu_number) 624 625 if kdbg_str: 626 out_str += kdbg_str 627 print out_str 628 629@lldb_command('showkerneldebugbuffer') 630def ShowKernelDebugBuffer(cmd_args=None): 631 """ Prints the last N entries in the kernel debug buffer per cpu 632 Syntax: showkerneldebugbuffer <count> 633 """ 634 if cmd_args == None or len(cmd_args) < 1: 635 raise ArgumentError("Invalid arguments passed.") 636 637 if (kern.globals.kd_ctrl_page_trace.kdebug_flags & xnudefines.KDBG_BUFINIT): 638 entrycount = ArgumentStringToInt(cmd_args[0]) 639 if entrycount == 0: 640 print "<count> is 0, dumping 50 entries per cpu\n" 641 entrycount = 50 642 cpu_num = 0 643 while cpu_num < kern.globals.kd_ctrl_page_trace.kdebug_cpus: 644 ShowKernelDebugBufferCPU([str(cpu_num), str(entrycount)]) 645 cpu_num += 1 646 else: 647 print "Trace buffer not enabled\n" 648 649@lldb_command('dumprawtracefile','U:') 650def DumpRawTraceFile(cmd_args=[], cmd_options={}): 651 """ 652 support for ktrace(1) 653 654 NB: trace is not wordsize flexible, so use ktrace(1) compiled for the compatible model, 655 e.g. if you dump from __LP64__ system, you will need to run ktrace(1) compiled __LP64__ to process the raw data file. 656 657 read the kernel's debug trace buffer, and dump to a "raw" ktrace(1) file 658 Usage: dumprawtracefile <output_filename> 659 -U <uptime> : specify system uptime in nsec, obtained e.g. from paniclog 660 Be patient, it is teh slow. 661 662 cf. kdbg_read()\bsd/kern/kdebug.c 663 """ 664 665 if (kern.globals.kd_ctrl_page_trace.kdebug_flags & xnudefines.KDBG_BUFINIT) == 0 : 666 print "Trace buffer not enabled\n" 667 return 668 669 if ((kern.arch == "x86_64") or kern.arch.startswith("arm64")) : 670 lp64 = True 671 elif kern.arch == "arm" : 672 lp64 = False 673 else : 674 print "unknown kern.arch {:s}\n".format(kern.arch) 675 return 676 677 # Various kern.globals are hashed by address, to 678 # a) avoid redundant kdp fetch from, and 679 # b) avoid all stores to 680 # the target system kernel structures. 681 # Stores to hashed structures remain strictly local to the lldb host, 682 # they are never written back to the target. 683 htab = {} 684 685 if lp64 : 686 KDBG_TIMESTAMP_MASK = 0xffffffffffffffff 687 KDBG_CPU_SHIFT = 0 688 else : 689 KDBG_TIMESTAMP_MASK = 0x00ffffffffffffff 690 KDBG_CPU_SHIFT = 56 691 692 barrier_min = 0 693 barrier_max = 0 694 out_of_events = False 695 lostevents = False 696 lostevent_timestamp = 0 697 lostevent_debugid = (((xnudefines.DBG_TRACE & 0xff) << 24) | ((xnudefines.DBG_TRACE_INFO & 0xff) << 16) | ((2 & 0x3fff) << 2)) # 0x01020008 698 events_count_lost = 0 699 events_count_found = 0 700 701 opt_verbose = config['verbosity'] 702 opt_progress = (opt_verbose > vHUMAN) and (opt_verbose < vDETAIL) 703 progress_count = 0 704 progress_stride = 32 705 706 output_filename = str(cmd_args[0]) 707 if opt_verbose > vHUMAN : 708 print "output file : {:s}".format(output_filename) 709 wfd = open(output_filename, "wb") 710 711 uptime = long(-1) 712 if "-U" in cmd_options: 713 uptime = long(cmd_options["-U"]) 714 if opt_verbose > vHUMAN : 715 print "uptime : {:d}".format(uptime) 716 717 nkdbufs = kern.globals.kd_data_page_trace.nkdbufs 718 719 kd_ctrl_page_trace = kern.globals.kd_ctrl_page_trace 720 if not kd_ctrl_page_trace in htab : 721 htab[kd_ctrl_page_trace] = kern.globals.kd_ctrl_page_trace 722 723 if opt_verbose > vHUMAN : 724 print "kd_data_page_trace_nkdbufs {0:#x}, enabled {1:#x}, flags {2:#x}, cpus {3:#x}".format(nkdbufs, htab[kd_ctrl_page_trace].enabled, htab[kd_ctrl_page_trace].kdebug_flags, htab[kd_ctrl_page_trace].kdebug_cpus) 725 726 if nkdbufs == 0 : 727 print "0 kd_data_page_trace_nkdbufs, nothing extracted" 728 return 729 730 if htab[kd_ctrl_page_trace].enabled != 0 : 731 barrier_max = uptime & KDBG_TIMESTAMP_MASK 732 733 f = htab[kd_ctrl_page_trace].kdebug_flags 734 wrapped = f & xnudefines.KDBG_WRAPPED 735 if wrapped != 0 : 736 barrier_min = htab[kd_ctrl_page_trace].oldest_time 737 htab[kd_ctrl_page_trace].kdebug_flags = htab[kd_ctrl_page_trace].kdebug_flags & ~xnudefines.KDBG_WRAPPED 738 htab[kd_ctrl_page_trace].oldest_time = 0 739 740 for cpu in range(htab[kd_ctrl_page_trace].kdebug_cpus) : 741 kdbp = unsigned(addressof(kern.globals.kd_data_page_trace.kdbip[cpu])) 742 if not kdbp in htab : 743 htab[kdbp] = kern.globals.kd_data_page_trace.kdbip[cpu] 744 745 kdsp = htab[kdbp].kd_list_head.raw 746 if kdsp == xnudefines.KDS_PTR_NULL : 747 continue 748 749 ix = htab[kdbp].kd_list_head.buffer_index 750 off = htab[kdbp].kd_list_head.offset 751 kdsp_actual = unsigned(addressof(kern.globals.kd_data_page_trace.kd_bufs[ix].kdsb_addr[off])) 752 if not kdsp_actual in htab : 753 htab[kdsp_actual] = kern.globals.kd_data_page_trace.kd_bufs[ix].kdsb_addr[off] 754 htab[kdsp_actual].kds_lostevents = False 755 756 757 # generate trace file header; threadmap is stubbed/TBD 758 version_no = xnudefines.RAW_VERSION1 759 thread_count = 0 760 TOD_secs = uptime 761 TOD_usecs = 0 762 header = struct.pack('IIqI', version_no, thread_count, TOD_secs, TOD_usecs) 763 pad_bytes = 4096 - (len(header) & 4095) 764 header += "\x00" * pad_bytes 765 wfd.write(buffer(header)) 766 767 count = kern.globals.kd_data_page_trace.nkdbufs 768 while count != 0 : 769 tempbuf = "" 770 tempbuf_number = 0 771 tempbuf_count = min(count, kern.globals.kd_ctrl_page_trace.kdebug_kdcopybuf_count) 772 773 # while space 774 while tempbuf_count != 0 : 775 776 if opt_progress == True : 777 progress_count += 1 778 if (progress_count % progress_stride) == 0 : 779 sys.stderr.write('.') 780 sys.stderr.flush() 781 782 earliest_time = 0xffffffffffffffff 783 min_kdbp = None 784 min_cpu = 0 785 786 # Check all CPUs 787 for cpu in range(htab[kd_ctrl_page_trace].kdebug_cpus) : 788 789 kdbp = unsigned(addressof(kern.globals.kd_data_page_trace.kdbip[cpu])) 790 if not kdbp in htab : 791 htab[kdbp] = kern.globals.kd_data_page_trace.kdbip[cpu] 792 793 # Skip CPUs without data. 794 kdsp = htab[kdbp].kd_list_head 795 if kdsp.raw == xnudefines.KDS_PTR_NULL : 796 continue 797 798 kdsp_shadow = kdsp 799 800 # Get from cpu data to buffer header to buffer 801 ix = kdsp.buffer_index 802 off = kdsp.offset 803 kdsp_actual = unsigned(addressof(kern.globals.kd_data_page_trace.kd_bufs[ix].kdsb_addr[off])) 804 if not kdsp_actual in htab : 805 htab[kdsp_actual] = kern.globals.kd_data_page_trace.kd_bufs[ix].kdsb_addr[off] 806 807 kdsp_actual_shadow = kdsp_actual 808 809 # Skip buffer if there are no events left. 810 rcursor = htab[kdsp_actual].kds_readlast 811 if rcursor == htab[kdsp_actual].kds_bufindx : 812 continue 813 814 t = htab[kdsp_actual].kds_records[rcursor].timestamp & KDBG_TIMESTAMP_MASK 815 816 # Ignore events that have aged out due to wrapping. 817 goto_next_cpu = False; 818 while (t < unsigned(barrier_min)) : 819 r = htab[kdsp_actual].kds_readlast 820 htab[kdsp_actual].kds_readlast = r + 1 821 rcursor = r + 1 822 823 if rcursor >= xnudefines.EVENTS_PER_STORAGE_UNIT : 824 825 kdsp = htab[kdbp].kd_list_head 826 if kdsp.raw == xnudefines.KDS_PTR_NULL : 827 goto_next_cpu = True 828 break 829 830 kdsp_shadow = kdsp; 831 832 ix = kdsp.buffer_index 833 off = kdsp.offset 834 kdsp_actual = unsigned(addressof(kern.globals.kd_data_page_trace.kd_bufs[ix].kdsb_addr[off])) 835 836 kdsp_actual_shadow = kdsp_actual; 837 rcursor = htab[kdsp_actual].kds_readlast; 838 839 t = htab[kdsp_actual].kds_records[rcursor].timestamp & KDBG_TIMESTAMP_MASK 840 841 if goto_next_cpu == True : 842 continue 843 844 if (t > barrier_max) and (barrier_max > 0) : 845 # Need to flush IOPs again before we 846 # can sort any more data from the 847 # buffers. 848 out_of_events = True 849 break 850 851 if t < (htab[kdsp_actual].kds_timestamp & KDBG_TIMESTAMP_MASK) : 852 # indicates we've not yet completed filling 853 # in this event... 854 # this should only occur when we're looking 855 # at the buf that the record head is utilizing 856 # we'll pick these events up on the next 857 # call to kdbg_read 858 # we bail at this point so that we don't 859 # get an out-of-order timestream by continuing 860 # to read events from the other CPUs' timestream(s) 861 out_of_events = True 862 break 863 864 if t < earliest_time : 865 earliest_time = t 866 min_kdbp = kdbp 867 min_cpu = cpu 868 869 870 if (min_kdbp is None) or (out_of_events == True) : 871 # all buffers ran empty 872 out_of_events = True 873 break 874 875 kdsp = htab[min_kdbp].kd_list_head 876 877 ix = kdsp.buffer_index 878 off = kdsp.offset 879 kdsp_actual = unsigned(addressof(kern.globals.kd_data_page_trace.kd_bufs[ix].kdsb_addr[off])) 880 if not kdsp_actual in htab : 881 htab[kdsp_actual] = kern.globals.kd_data_page_trace.kd_bufs[ix].kdsb_addr[off] 882 883 # Copy earliest event into merged events scratch buffer. 884 r = htab[kdsp_actual].kds_readlast 885 htab[kdsp_actual].kds_readlast = r + 1 886 e = htab[kdsp_actual].kds_records[r] 887 888 # Concatenate event into buffer 889 # XXX condition here is on __LP64__ 890 if lp64 : 891 tempbuf += struct.pack('QQQQQQIIQ', 892 unsigned(e.timestamp), 893 unsigned(e.arg1), 894 unsigned(e.arg2), 895 unsigned(e.arg3), 896 unsigned(e.arg4), 897 unsigned(e.arg5), 898 unsigned(e.debugid), 899 unsigned(e.cpuid), 900 unsigned(e.unused)) 901 else : 902 tempbuf += struct.pack('QIIIIII', 903 unsigned(e.timestamp), 904 unsigned(e.arg1), 905 unsigned(e.arg2), 906 unsigned(e.arg3), 907 unsigned(e.arg4), 908 unsigned(e.arg5), 909 unsigned(e.debugid)) 910 911 # Watch for out of order timestamps 912 if earliest_time < (htab[min_kdbp].kd_prev_timebase & KDBG_TIMESTAMP_MASK) : 913 ## if so, use the previous timestamp + 1 cycle 914 htab[min_kdbp].kd_prev_timebase += 1 915 916 e.timestamp = htab[min_kdbp].kd_prev_timebase & KDBG_TIMESTAMP_MASK 917 if not lp64: 918 e.timestamp |= (min_cpu << KDBG_CPU_SHIFT) 919 else : 920 htab[min_kdbp].kd_prev_timebase = earliest_time 921 922 if opt_verbose >= vDETAIL : 923 print "{0:#018x} {1:#018x} {2:#018x} {3:#018x} {4:#018x} {5:#018x} {6:#010x} {7:#010x} {8:#018x}".format( 924 e.timestamp, e.arg1, e.arg2, e.arg3, e.arg4, e.arg5, e.debugid, e.cpuid, e.unused) 925 926 events_count_found += 1 927 928 # nextevent: 929 tempbuf_count -= 1 930 tempbuf_number += 1 931 932 if opt_progress == True : 933 sys.stderr.write('\n') 934 sys.stderr.flush() 935 936 if opt_verbose > vHUMAN : 937 print "events_count_lost {0:#x}, events_count_found {1:#x}, progress_count {2:#x}".format(events_count_lost, events_count_found, progress_count) 938 939 # write trace events to output file 940 if tempbuf_number != 0 : 941 count -= tempbuf_number 942 wfd.write(buffer(tempbuf)) 943 944 if out_of_events == True : 945 # all trace buffers are empty 946 if opt_verbose > vHUMAN : 947 print "out of events" 948 break 949 950 wfd.close() 951 952 return 953 954 955def GetTimebaseInfo(): 956 timebase_key = 'kern.rtc_timebase' 957 numer, denom = caching.GetStaticCacheData(timebase_key, (None, None)) 958 if not numer or not denom: 959 if kern.arch == 'x86_64': 960 numer = 1 961 denom = 1 962 else: 963 rtclockdata_addr = kern.GetLoadAddressForSymbol('RTClockData') 964 rtc = kern.GetValueFromAddress( 965 rtclockdata_addr, 'struct _rtclock_data_ *') 966 tb = rtc.rtc_timebase_const 967 numer = tb.numer 968 denom = tb.denom 969 caching.SaveStaticCacheData(timebase_key, (numer, denom)) 970 return numer, denom 971 972 973def PrintIteratedElem(i, elem, elem_type, do_summary, summary, regex): 974 try: 975 if do_summary and summary: 976 s = summary(elem) 977 if regex: 978 if regex.match(s): 979 print "[{:d}] {:s}".format(i, s) 980 else: 981 print "[{:d}] {:s}".format(i, s) 982 else: 983 if regex: 984 if regex.match(str(elem)): 985 print "[{:4d}] ({:s}){:#x}".format(i, elem_type, unsigned(elem)) 986 else: 987 print "[{:4d}] ({:s}){:#x}".format(i, elem_type, unsigned(elem)) 988 except: 989 print "Exception while looking at elem {:#x}".format(unsigned(elem)) 990 return 991 992@lldb_command('q_iterate', "LQSG:") 993def QIterate(cmd_args=None, cmd_options={}): 994 """ Iterate over a LinkageChain or Queue (osfmk/kern/queue.h method 1 or 2 respectively) 995 This is equivalent to the qe_foreach_element() macro 996 usage: 997 iterate [options] {queue_head_ptr} {element_type} {field_name} 998 option: 999 -L iterate over a linkage chain (method 1) [default] 1000 -Q iterate over a queue (method 2) 1001 1002 -S auto-summarize known types 1003 -G regex to filter the output 1004 e.g. 1005 iterate_linkage `&coalitions_q` 'coalition *' coalitions 1006 """ 1007 if not cmd_args: 1008 raise ArgumentError("usage: iterate_linkage {queue_head_ptr} {element_type} {field_name}") 1009 1010 qhead = kern.GetValueFromAddress(cmd_args[0], 'struct queue_entry *') 1011 if not qhead: 1012 raise ArgumentError("Unknown queue_head pointer: %r" % cmd_args) 1013 elem_type = cmd_args[1] 1014 field_name = cmd_args[2] 1015 if not elem_type or not field_name: 1016 raise ArgumentError("usage: iterate_linkage {queue_head_ptr} {element_type} {field_name}") 1017 1018 do_queue_iterate = False 1019 do_linkage_iterate = True 1020 if "-Q" in cmd_options: 1021 do_queue_iterate = True 1022 do_linkage_iterate = False 1023 if "-L" in cmd_options: 1024 do_queue_iterate = False 1025 do_linkage_iterate = True 1026 1027 do_summary = False 1028 if "-S" in cmd_options: 1029 do_summary = True 1030 regex = None 1031 if "-G" in cmd_options: 1032 regex = re.compile(".*{:s}.*".format(cmd_options["-G"])) 1033 print "Looking for: {:s}".format(regex.pattern) 1034 1035 global lldb_summary_definitions 1036 summary = None 1037 if elem_type in lldb_summary_definitions: 1038 summary = lldb_summary_definitions[elem_type] 1039 if do_summary: 1040 print summary.header 1041 1042 try: 1043 i = 0 1044 if do_linkage_iterate: 1045 for elem in IterateLinkageChain(qhead, elem_type, field_name): 1046 PrintIteratedElem(i, elem, elem_type, do_summary, summary, regex) 1047 i = i + 1 1048 elif do_queue_iterate: 1049 for elem in IterateQueue(qhead, elem_type, field_name): 1050 PrintIteratedElem(i, elem, elem_type, do_summary, summary, regex) 1051 i = i + 1 1052 except: 1053 print "Exception while looking at queue_head: {:#x}".format(unsigned(qhead)) 1054 1055@lldb_command('lbrbt') 1056def LBRBacktrace(cmd_args=None): 1057 """ 1058 Prints symbolicated last branch records captured on Intel systems 1059 from a core file. Will not work on a live system. 1060 usage: 1061 lbrbt 1062 options: 1063 None 1064 """ 1065 DecoratedLBRStack = SymbolicateLBR() 1066 if (DecoratedLBRStack): 1067 print(DecoratedLBRStack) 1068 1069def SymbolicateLBR(): 1070 lbr_size_offset = 5 1071 cpu_num_offset = 4 1072 LBRMagic = 0x5352424C 1073 1074 try: 1075 phys_carveout_addr = kern.GetLoadAddressForSymbol("phys_carveout") 1076 except LookupError: 1077 print("Last Branch Recoreds not present in this core file") 1078 return None 1079 try: 1080 phys_carveout_md_addr = kern.GetLoadAddressForSymbol("phys_carveout_metadata") 1081 except LookupError: 1082 print("Last Branch Recoreds not present in this core file") 1083 return None 1084 1085 metadata_ptr = kern.GetValueFromAddress(phys_carveout_md_addr, "uint64_t *") 1086 metadata = kern.GetValueFromAddress(unsigned(metadata_ptr[0]), "uint8_t *") 1087 carveout_ptr = kern.GetValueFromAddress(phys_carveout_addr, "uint64_t *") 1088 1089 metadata_hdr = kern.GetValueFromAddress(unsigned(metadata_ptr[0]), "uint32_t *") 1090 if not (unsigned(metadata_hdr[0]) == LBRMagic): 1091 print("'LBRS' not found at beginning of phys_carveout section, cannot proceed.") 1092 return None 1093 1094 lbr_records = unsigned(carveout_ptr[0]) 1095 1096 num_lbrs = int(metadata[lbr_size_offset]) 1097 1098 header_line = "".join("{:49s} -> {:s}\n".format("From", "To")) 1099 ncpus = int(metadata[cpu_num_offset]) 1100 1101 output_lines = [] 1102 1103 target = LazyTarget.GetTarget() 1104 1105 for cpu in range(ncpus): 1106 start_addr_from = lbr_records + num_lbrs * 8 * cpu 1107 start_addr_to = start_addr_from + num_lbrs * 8 * ncpus 1108 from_lbr = kern.GetValueFromAddress(start_addr_from, "uint64_t *") 1109 to_lbr = kern.GetValueFromAddress(start_addr_to, "uint64_t *") 1110 for i in range(num_lbrs): 1111 if (from_lbr[i] == 0x0 or to_lbr[i] == 0x0): 1112 break 1113 ## Replace newline with space to include inlined functions 1114 ## in a trade off for longer output lines. 1115 fprint = str(target.ResolveLoadAddress(int(from_lbr[i]))).replace('\n', ' ') 1116 tprint = str(target.ResolveLoadAddress(int(to_lbr[i]))).replace('\n', ' ') 1117 output_lines.append(''.join("({:x}) {:30s} -> ({:x}) {:30s}\n".format(from_lbr[i], fprint, to_lbr[i], tprint))) 1118 1119 return header_line + ''.join(output_lines) 1120