1""" 2Miscellaneous (Intel) platform-specific commands. 3""" 4from core import caching 5from xnu import * 6import xnudefines 7 8from scheduler import * 9 10@lldb_command('showmcastate') 11def showMCAstate(cmd_args=None): 12 """ 13 Print machine-check register state after MC exception. 14 """ 15 if kern.arch != 'x86_64': 16 print("Not available for current architecture.") 17 return 18 19 present = ["not present", "present"] 20 print('MCA {:s}, control MSR {:s}, threshold status {:s}'.format( 21 present[int(kern.globals.mca_MCA_present)], 22 present[int(kern.globals.mca_control_MSR_present)], 23 present[int(kern.globals.mca_threshold_status_present)])) 24 print('{:d} error banks, family code {:#0x}, machine-check dump state: {:d}'.format( 25 kern.globals.mca_error_bank_count, 26 kern.globals.mca_dump_state, 27 kern.globals.mca_family)) 28 cpu = 0 29 while kern.globals.cpu_data_ptr[cpu]: 30 cd = kern.globals.cpu_data_ptr[cpu] 31 mc = cd.cpu_mca_state 32 if mc: 33 print('CPU {:d}: mca_mcg_ctl: {:#018x} mca_mcg_status {:#018x}'.format(cpu, mc.mca_mcg_ctl, mc.mca_mcg_status.u64)) 34 hdr = '{:<4s} {:<18s} {:<18s} {:<18s} {:<18s}' 35 val = '{:>3d}: {:#018x} {:#018x} {:#018x} {:#018x}' 36 print(hdr.format('bank', 37 'mca_mci_ctl', 38 'mca_mci_status', 39 'mca_mci_addr', 40 'mca_mci_misc')) 41 for i in range(int(kern.globals.mca_error_bank_count)): 42 bank = mc.mca_error_bank[i] 43 print(val.format(i, 44 bank.mca_mci_ctl, 45 bank.mca_mci_status.u64, 46 bank.mca_mci_addr, 47 bank.mca_mci_misc)) 48 print('register state:') 49 reg = cd.cpu_desc_index.cdi_ktss.ist1 - sizeof('x86_saved_state_t') 50 print(lldb_run_command('p/x *(x86_saved_state_t *) ' + hex(reg))) 51 cpu = cpu + 1 52 53def dumpTimerList(mpqueue, processor=None): 54 """ 55 Utility function to dump the timer entries in list (anchor). 56 anchor is a struct mpqueue_head. 57 """ 58 59 if mpqueue.count == 0: 60 print('(empty)') 61 return 62 63 thdr = ' {:<24s}{:^17s}{:^18s} {:^18s} {:^18s} {:^18s} {:^18s} {:9s} {:^18s} count: {:d} ' 64 tval = ' {:#018x}{:s} {:18d} {:18d} {:18.06f} {:18.06f} {:18.06f} {:18.06f} {:>9s} ({:#018x})({:#018x}, {:#018x}) ({:s}) {:s}' 65 66 print(thdr.format('Entry', 'Soft Deadline', 'Deadline', 'Soft To Go', 'Hard To Go', 'Duration', 'Leeway', 'Flags', '(*func)(param0, param1)', mpqueue.count)) 67 68 recent_timestamp = GetRecentTimestamp() 69 70 for timer_call in ParanoidIterateLinkageChain(mpqueue.head, 'struct timer_call *', 'tc_qlink'): 71 72 func_name = kern.Symbolicate(timer_call.tc_func) 73 74 extra_string = "" 75 76 strip_func = kern.StripKernelPAC(unsigned(timer_call.tc_func)) 77 78 func_syms = kern.SymbolicateFromAddress(strip_func) 79 # returns an array of SBSymbol 80 81 if func_syms and func_syms[0] : 82 func_sym = func_syms[0] 83 func_name = func_sym.GetName() 84 try : 85 86 if "thread_call_delayed_timer" in func_name : 87 group = Cast(timer_call.tc_param0, 'struct thread_call_group *') 88 flavor = Cast(timer_call.tc_param1, 'thread_call_flavor_t') 89 90 # There's got to be a better way to stringify the enum 91 flavorname = str(flavor).partition(" = ")[2] 92 93 extra_string += "{:s} {:s}".format(group.tcg_name, flavorname) 94 95 if "thread_timer_expire" in func_name : 96 thread = Cast(timer_call.tc_param0, 'thread_t') 97 98 tid = thread.thread_id 99 name = GetThreadName(thread) 100 pid = GetProcPIDForTask(thread.t_tro.tro_task) 101 procname = GetProcNameForTask(thread.t_tro.tro_task) 102 103 otherprocessor = "" 104 if processor : 105 if thread.last_processor != processor: 106 otherprocessor = " (Not same processor - was on {:d})".format(thread.last_processor.cpu_id) 107 108 extra_string += "thread: 0x{:x} {:s} task:{:s}[{:d}]{:s}".format( 109 tid, name, procname, pid, otherprocessor) 110 except: 111 print("exception generating extra_string for call: {:#018x}".format(timer_call)) 112 if dumpTimerList.enable_debug : 113 raise 114 115 timer_fire = timer_call.tc_pqlink.deadline - recent_timestamp 116 timer_fire_s = kern.GetNanotimeFromAbstime(timer_fire) / 1000000000.0 117 118 soft_timer_fire = timer_call.tc_soft_deadline - recent_timestamp 119 soft_timer_fire_s = kern.GetNanotimeFromAbstime(soft_timer_fire) / 1000000000.0 120 121 leeway = timer_call.tc_pqlink.deadline - timer_call.tc_soft_deadline 122 leeway_s = kern.GetNanotimeFromAbstime(leeway) / 1000000000.0 123 124 tc_ttd_s = kern.GetNanotimeFromAbstime(timer_call.tc_ttd) / 1000000000.0 125 126 flags = int(timer_call.tc_flags) 127 timer_call_flags = {0x0:'', 0x1:'C', 0x2:'B', 0x4:'X', 0x8:'X', 0x10:'U', 0x20:'E', 128 0x40:'L', 0x80:'R'} 129 130 flags_str = '' 131 mask = 0x1 132 while mask <= 0x80 : 133 flags_str += timer_call_flags[int(flags & mask)] 134 mask = mask << 1 135 136 colon = ":" 137 138 if addressof(timer_call.tc_pqlink) == mpqueue.mpq_pqhead.pq_root : 139 colon = "*" 140 141 print(tval.format(timer_call, colon, 142 timer_call.tc_soft_deadline, 143 timer_call.tc_pqlink.deadline, 144 soft_timer_fire_s, 145 timer_fire_s, 146 tc_ttd_s, 147 leeway_s, 148 flags_str, 149 timer_call.tc_func, 150 timer_call.tc_param0, 151 timer_call.tc_param1, 152 func_name, extra_string)) 153 154dumpTimerList.enable_debug = False 155 156def GetCpuDataForCpuID(cpu_id): 157 """ 158 Find struct cpu_data for a CPU 159 ARM is complicated 160 """ 161 if kern.arch == 'x86_64': 162 cpu_data = kern.globals.cpu_data_ptr[cpu_id] 163 return cpu_data 164 elif kern.arch.startswith('arm'): 165 data_entries_addr = kern.GetLoadAddressForSymbol('CpuDataEntries') 166 data_entries = kern.GetValueFromAddress(data_entries_addr, 'cpu_data_entry_t *') 167 data_entry = data_entries[cpu_id]; 168 cpu_data_addr = data_entry.cpu_data_vaddr 169 return Cast(cpu_data_addr, 'cpu_data_t*') 170 171@lldb_command('longtermtimers') 172def longtermTimers(cmd_args=None): 173 """ 174 Print details of long-term timers and stats. 175 """ 176 177 lt = kern.globals.timer_longterm 178 ltt = lt.threshold 179 EndofAllTime = signed(-1) 180 if signed(ltt.interval) == EndofAllTime: 181 print("Longterm timers disabled") 182 return 183 184 if lt.escalates > 0: 185 ratio = lt.enqueues // lt.escalates 186 else: 187 ratio = lt.enqueues 188 print('Longterm timer object: {:#018x}'.format(addressof(lt))) 189 print(' queue count : {:d}' .format(lt.queue.count)) 190 print(' number of enqueues : {:d}' .format(lt.enqueues)) 191 print(' number of dequeues : {:d}' .format(lt.dequeues)) 192 print(' number of escalates : {:d}' .format(lt.escalates)) 193 print(' enqueues/escalates : {:d}' .format(ratio)) 194 print(' threshold.interval : {:d}' .format(ltt.interval)) 195 print(' threshold.margin : {:d}' .format(ltt.margin)) 196 print(' scan_time : {:#018x} ({:d})'.format(lt.scan_time, lt.scan_time)) 197 if signed(ltt.preempted) == EndofAllTime: 198 print(' threshold.preempted : None') 199 else: 200 print(' threshold.preempted : {:#018x} ({:d})'.format(ltt.preempted, ltt.preempted)) 201 if signed(ltt.deadline) == EndofAllTime: 202 print(' threshold.deadline : None') 203 else: 204 print(' threshold.deadline : {:#018x} ({:d})'.format(ltt.deadline, ltt.deadline)) 205 print(' threshold.call : {:#018x}'.format(ltt.call)) 206 print(' actual deadline set : {:#018x} ({:d})'.format(ltt.deadline_set, ltt.deadline_set)) 207 print(' threshold.scans : {:d}' .format(ltt.scans)) 208 print(' threshold.preempts : {:d}' .format(ltt.preempts)) 209 print(' threshold.latency : {:d}' .format(ltt.latency)) 210 print(' - min : {:d}' .format(ltt.latency_min)) 211 print(' - max : {:d}' .format(ltt.latency_max)) 212 dumpTimerList(lt.queue) 213 214 215@lldb_command('processortimers') 216def processorTimers(cmd_args=None): 217 """ 218 Print details of processor timers, noting anything suspicious 219 Also include long-term timer details 220 221 Callout flags: 222 223 C - Critical 224 B - Background 225 U - User timer 226 E - Explicit Leeway 227 L - Local 228 R - Rate-limited - (App Nap) 229 """ 230 231 recent_timestamp = GetRecentTimestamp() 232 233 hdr = '{:15s}{:<18s} {:<18s} {:<18s} {:<18s} {:<18s} {:<18s} {:<18s} Recent Timestamp: {:d}' 234 print(hdr.format('Processor #', 'Processor pointer', 'Last dispatch', 'Soft deadline', 'Soft To Go', 'Hard deadline', 'Hard To Go', 'Current Leeway', recent_timestamp)) 235 print("=" * 82) 236 p = kern.globals.processor_list 237 EndOfAllTime = signed(-1) 238 while p: 239 cpu = p.cpu_id 240 cpu_data = GetCpuDataForCpuID(cpu) 241 rt_timer = cpu_data.rtclock_timer 242 diff = signed(rt_timer.deadline) - signed(recent_timestamp) 243 diff_s = kern.GetNanotimeFromAbstime(diff) / 1000000000.0 244 valid_deadline = signed(rt_timer.deadline) != EndOfAllTime 245 soft_deadline = rt_timer.queue.earliest_soft_deadline 246 soft_diff = signed(soft_deadline) - signed(recent_timestamp) 247 soft_diff_s = kern.GetNanotimeFromAbstime(soft_diff) / 1000000000.0 248 valid_soft_deadline = signed(soft_deadline) != EndOfAllTime 249 leeway_s = kern.GetNanotimeFromAbstime(rt_timer.deadline - soft_deadline) / 1000000000.0 250 tmr = 'Processor {:<3d}: {:#018x} {:<18d} {:<18s} {:<18s} {:<18s} {:<18s} {:<18s} {:s} {:s}' 251 print(tmr.format(cpu, 252 p, 253 p.last_dispatch, 254 "{:d}".format(soft_deadline) if valid_soft_deadline else "None", 255 "{:<16.06f}".format(soft_diff_s) if valid_soft_deadline else "N/A", 256 "{:d}".format(rt_timer.deadline) if valid_deadline else "None", 257 "{:<16.06f}".format(diff_s) if valid_deadline else "N/A", 258 "{:<16.06f}".format(leeway_s) if valid_soft_deadline and valid_deadline else "N/A", 259 ['(PAST SOFT DEADLINE)', '(soft deadline ok)'][int(soft_diff > 0)] if valid_soft_deadline else "", 260 ['(PAST DEADLINE)', '(deadline ok)'][int(diff > 0)] if valid_deadline else "")) 261 if valid_deadline: 262 if kern.arch == 'x86_64': 263 print('Next deadline set at: {:#018x}. Timer call list:'.format(rt_timer.when_set)) 264 dumpTimerList(rt_timer.queue, p) 265 p = p.processor_list 266 print("-" * 82) 267 longtermTimers() 268 print("Running timers:") 269 ShowRunningTimers() 270 271@header("{:<6s} {:^18s} {:^18s}".format("cpu_id", "Processor", "cpu_data") ) 272@lldb_command('showcpudata') 273def ShowCPUData(cmd_args=[]): 274 """ Prints the CPU Data struct of each processor 275 Passing a CPU ID prints the CPU Data of just that CPU 276 Usage: (lldb) showcpudata [cpu id] 277 """ 278 279 format_string = "{:>#6d}: {: <#018x} {: <#018x}" 280 281 find_cpu_id = None 282 283 if cmd_args: 284 find_cpu_id = ArgumentStringToInt(cmd_args[0]) 285 286 print (ShowCPUData.header) 287 288 processors = [p for p in IterateLinkedList(kern.globals.processor_list, 'processor_list')] 289 290 processors.sort(key=lambda p: p.cpu_id) 291 292 for processor in processors: 293 cpu_id = int(processor.cpu_id) 294 295 if find_cpu_id and cpu_id != find_cpu_id: 296 continue 297 298 cpu_data = GetCpuDataForCpuID(cpu_id) 299 300 print (format_string.format(cpu_id, processor, cpu_data)) 301 302@lldb_command('showtimerwakeupstats') 303def showTimerWakeupStats(cmd_args=None): 304 """ 305 Displays interrupt and platform idle wakeup frequencies 306 associated with each thread, timer time-to-deadline frequencies, and 307 CPU time with user/system break down where applicable, with thread tags. 308 """ 309 for task in kern.tasks: 310 proc = GetProcFromTask(task) 311 print(dereference(task)) 312 (user_time, sys_time) = GetTaskTerminatedUserSysTime(task) 313 print('{:d}({:s}), terminated thread timer wakeups: {:d} {:d} 2ms: {:d} 5ms: {:d} UT: {:d} ST: {:d}'.format( 314 GetProcPID(proc), 315 GetProcName(proc), 316# Commented-out references below to be addressed by rdar://13009660. 317 0, #task.task_interrupt_wakeups, 318 0, #task.task_platform_idle_wakeups, 319 task.task_timer_wakeups_bin_1, 320 task.task_timer_wakeups_bin_2, 321 user_time, sys_time)) 322 tot_wakes = 0 #task.task_interrupt_wakeups 323 tot_platform_wakes = 0 #task.task_platform_idle_wakeups 324 for thread in IterateQueue(task.threads, 'thread_t', 'task_threads'): 325## if thread.thread_interrupt_wakeups == 0: 326## continue 327 (user_time, sys_time) = GetThreadUserSysTime(thread) 328 print('\tThread ID 0x{:x}, Tag 0x{:x}, timer wakeups: {:d} {:d} {:d} {:d} <2ms: {:d}, <5ms: {:d} UT: {:d} ST: {:d}'.format( 329 thread.thread_id, 330 thread.thread_tag, 331 0, #thread.thread_interrupt_wakeups, 332 0, #thread.thread_platform_idle_wakeups, 333 0, #thread.thread_callout_interrupt_wakeups, 334 0, #thread.thread_callout_platform_idle_wakeups, 335 0,0,0,0, 336 thread.thread_timer_wakeups_bin_1, 337 thread.thread_timer_wakeups_bin_2, 338 user_time, sys_time)) 339 tot_wakes += 0 #thread.thread_interrupt_wakeups 340 tot_platform_wakes += 0 #thread.thread_platform_idle_wakeups 341 print('Task total wakeups: {:d} {:d}'.format( 342 tot_wakes, tot_platform_wakes)) 343 344@lldb_command('showrunningtimers') 345def ShowRunningTimers(cmd_args=None): 346 """ 347 Print the state of all running timers. 348 349 Usage: showrunningtimers 350 """ 351 processor_array = kern.globals.processor_array 352 353 recent_timestamp = GetRecentTimestamp() 354 355 hdr = '{:4s} {:^10s} {:^18s} {:^18s} {:^18s} {:^18s}' 356 print(hdr.format('CPU', 'State', 'Quantum', 'To Go', 'kperf', 'To Go', 'Hard To Go')) 357 358 cpu = '{:3d}: {:^10s} {:18d} {:16.06f} {:18d} {:16.06f}' 359 360 i = 0 361 while processor_array[i] != 0: 362 processor = processor_array[i] 363 364 statestr = 'runnning' if processor.running_timers_active else 'idle' 365 366 quantum = unsigned(processor.running_timers[0].tc_pqlink.deadline) 367 quantumdiff = signed(quantum) - signed(recent_timestamp) 368 quantumdiff_s = kern.GetNanotimeFromAbstime(quantumdiff) / 1000000000.0 369 370 kperf = unsigned(processor.running_timers[1].tc_pqlink.deadline) 371 kperfdiff = signed(kperf) - signed(recent_timestamp) 372 kperfdiff_s = kern.GetNanotimeFromAbstime(kperfdiff) / 1000000000.0 373 374 print (cpu.format(i, statestr, quantum, quantumdiff_s, kperf, kperfdiff_s)) 375 i += 1 376 377def DoReadMsr64(msr_address, lcpu): 378 """ Read a 64-bit MSR from the specified CPU 379 Params: 380 msr_address: int - MSR index to read from 381 lcpu: int - CPU identifier 382 Returns: 383 64-bit value read from the MSR 384 """ 385 result = 0xbad10ad 386 387 if "kdp" != GetConnectionProtocol(): 388 print("Target is not connected over kdp. Cannot read MSR.") 389 return result 390 391 input_address = unsigned(addressof(kern.globals.manual_pkt.input)) 392 len_address = unsigned(addressof(kern.globals.manual_pkt.len)) 393 data_address = unsigned(addressof(kern.globals.manual_pkt.data)) 394 if not WriteInt32ToMemoryAddress(0, input_address): 395 print("DoReadMsr64() failed to write 0 to input_address") 396 return result 397 398 kdp_pkt_size = GetType('kdp_readmsr64_req_t').GetByteSize() 399 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address): 400 print("DoReadMsr64() failed to write kdp_pkt_size") 401 return result 402 403 kgm_pkt = kern.GetValueFromAddress(data_address, 'kdp_readmsr64_req_t *') 404 header_value = GetKDPPacketHeaderInt( 405 request=GetEnumValue('kdp_req_t::KDP_READMSR64'), 406 length=kdp_pkt_size) 407 408 if not WriteInt64ToMemoryAddress(header_value, int(addressof(kgm_pkt.hdr))): 409 print("DoReadMsr64() failed to write header_value") 410 return result 411 if not WriteInt32ToMemoryAddress(msr_address, int(addressof(kgm_pkt.address))): 412 print("DoReadMsr64() failed to write msr_address") 413 return result 414 if not WriteInt16ToMemoryAddress(lcpu, int(addressof(kgm_pkt.lcpu))): 415 print("DoReadMsr64() failed to write lcpu") 416 return result 417 if not WriteInt32ToMemoryAddress(1, input_address): 418 print("DoReadMsr64() failed to write to input_address") 419 return result 420 421 result_pkt = Cast(addressof(kern.globals.manual_pkt.data), 422 'kdp_readmsr64_reply_t *') 423 if (result_pkt.error == 0): 424 result = dereference(Cast(addressof(result_pkt.data), 'uint64_t *')) 425 else: 426 print("DoReadMsr64() result_pkt.error != 0") 427 return result 428 429def DoWriteMsr64(msr_address, lcpu, data): 430 """ Write a 64-bit MSR 431 Params: 432 msr_address: int - MSR index to write to 433 lcpu: int - CPU identifier 434 data: int - value to write 435 Returns: 436 True upon success, False if error 437 """ 438 if "kdp" != GetConnectionProtocol(): 439 print("Target is not connected over kdp. Cannot write MSR.") 440 return False 441 442 input_address = unsigned(addressof(kern.globals.manual_pkt.input)) 443 len_address = unsigned(addressof(kern.globals.manual_pkt.len)) 444 data_address = unsigned(addressof(kern.globals.manual_pkt.data)) 445 if not WriteInt32ToMemoryAddress(0, input_address): 446 print("DoWriteMsr64() failed to write 0 to input_address") 447 return False 448 449 kdp_pkt_size = GetType('kdp_writemsr64_req_t').GetByteSize() 450 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address): 451 print("DoWriteMsr64() failed to kdp_pkt_size") 452 return False 453 454 kgm_pkt = kern.GetValueFromAddress(data_address, 'kdp_writemsr64_req_t *') 455 header_value = GetKDPPacketHeaderInt( 456 request=GetEnumValue('kdp_req_t::KDP_WRITEMSR64'), 457 length=kdp_pkt_size) 458 459 if not WriteInt64ToMemoryAddress(header_value, int(addressof(kgm_pkt.hdr))): 460 print("DoWriteMsr64() failed to write header_value") 461 return False 462 if not WriteInt32ToMemoryAddress(msr_address, int(addressof(kgm_pkt.address))): 463 print("DoWriteMsr64() failed to write msr_address") 464 return False 465 if not WriteInt16ToMemoryAddress(lcpu, int(addressof(kgm_pkt.lcpu))): 466 print("DoWriteMsr64() failed to write lcpu") 467 return False 468 if not WriteInt64ToMemoryAddress(data, int(addressof(kgm_pkt.data))): 469 print("DoWriteMsr64() failed to write data") 470 return False 471 if not WriteInt32ToMemoryAddress(1, input_address): 472 print("DoWriteMsr64() failed to write to input_address") 473 return False 474 475 result_pkt = Cast(addressof(kern.globals.manual_pkt.data), 476 'kdp_writemsr64_reply_t *') 477 if not result_pkt.error == 0: 478 print("DoWriteMsr64() error received in reply packet") 479 return False 480 481 return True 482 483@lldb_command('readmsr64') 484def ReadMsr64(cmd_args=None): 485 """ Read the specified MSR. The CPU can be optionally specified 486 Syntax: readmsr64 <msr> [lcpu] 487 """ 488 if cmd_args is None or len(cmd_args) < 1: 489 print(ReadMsr64.__doc__) 490 return 491 492 msr_address = ArgumentStringToInt(cmd_args[0]) 493 if len(cmd_args) > 1: 494 lcpu = ArgumentStringToInt(cmd_args[1]) 495 else: 496 lcpu = int(xnudefines.lcpu_self) 497 498 msr_value = DoReadMsr64(msr_address, lcpu) 499 print("MSR[{:x}]: {:#016x}".format(msr_address, msr_value)) 500 501@lldb_command('writemsr64') 502def WriteMsr64(cmd_args=None): 503 """ Write the specified MSR. The CPU can be optionally specified 504 Syntax: writemsr64 <msr> <value> [lcpu] 505 """ 506 if cmd_args is None or len(cmd_args) < 2: 507 print(WriteMsr64.__doc__) 508 return 509 msr_address = ArgumentStringToInt(cmd_args[0]) 510 write_val = ArgumentStringToInt(cmd_args[1]) 511 if len(cmd_args) > 2: 512 lcpu = ArgumentStringToInt(cmd_args[2]) 513 else: 514 lcpu = xnudefines.lcpu_self 515 516 if not DoWriteMsr64(msr_address, lcpu, write_val): 517 print("writemsr64 FAILED") 518 519 520@caching.cache_statically 521def GetTimebaseInfo(target=None): 522 if kern.arch == 'x86_64': 523 return 1, 1 524 525 rtclockdata_addr = kern.GetLoadAddressForSymbol('RTClockData') 526 rtc = kern.GetValueFromAddress( 527 rtclockdata_addr, 'struct _rtclock_data_ *') 528 tb = rtc.rtc_timebase_const 529 return int(tb.numer), int(tb.denom) 530 531 532def PrintIteratedElem(i, elem, elem_type, do_summary, summary, regex): 533 try: 534 if do_summary and summary: 535 s = summary(elem) 536 if regex: 537 if regex.match(s): 538 print("[{:d}] {:s}".format(i, s)) 539 else: 540 print("[{:d}] {:s}".format(i, s)) 541 else: 542 if regex: 543 if regex.match(str(elem)): 544 print("[{:4d}] ({:s}){:#x}".format(i, elem_type, unsigned(elem))) 545 else: 546 print("[{:4d}] ({:s}){:#x}".format(i, elem_type, unsigned(elem))) 547 except: 548 print("Exception while looking at elem {:#x}".format(unsigned(elem))) 549 return 550 551@lldb_command('q_iterate', "LQSG:") 552def QIterate(cmd_args=None, cmd_options={}): 553 """ Iterate over a LinkageChain or Queue (osfmk/kern/queue.h method 1 or 2 respectively) 554 This is equivalent to the qe_foreach_element() macro 555 usage: 556 iterate [options] {queue_head_ptr} {element_type} {field_name} 557 option: 558 -L iterate over a linkage chain (method 1) [default] 559 -Q iterate over a queue (method 2) 560 561 -S auto-summarize known types 562 -G regex to filter the output 563 e.g. 564 iterate_linkage `&coalitions_q` 'coalition *' coalitions 565 """ 566 if not cmd_args: 567 raise ArgumentError("usage: iterate_linkage {queue_head_ptr} {element_type} {field_name}") 568 569 qhead = kern.GetValueFromAddress(cmd_args[0], 'struct queue_entry *') 570 if not qhead: 571 raise ArgumentError("Unknown queue_head pointer: %r" % cmd_args) 572 elem_type = cmd_args[1] 573 field_name = cmd_args[2] 574 if not elem_type or not field_name: 575 raise ArgumentError("usage: iterate_linkage {queue_head_ptr} {element_type} {field_name}") 576 577 do_queue_iterate = False 578 do_linkage_iterate = True 579 if "-Q" in cmd_options: 580 do_queue_iterate = True 581 do_linkage_iterate = False 582 if "-L" in cmd_options: 583 do_queue_iterate = False 584 do_linkage_iterate = True 585 586 do_summary = False 587 if "-S" in cmd_options: 588 do_summary = True 589 regex = None 590 if "-G" in cmd_options: 591 regex = re.compile(".*{:s}.*".format(cmd_options["-G"])) 592 print("Looking for: {:s}".format(regex.pattern)) 593 594 global lldb_summary_definitions 595 summary = None 596 if elem_type in lldb_summary_definitions: 597 summary = lldb_summary_definitions[elem_type] 598 if do_summary: 599 print(summary.header) 600 601 try: 602 i = 0 603 if do_linkage_iterate: 604 for elem in IterateLinkageChain(qhead, elem_type, field_name): 605 PrintIteratedElem(i, elem, elem_type, do_summary, summary, regex) 606 i = i + 1 607 elif do_queue_iterate: 608 for elem in IterateQueue(qhead, elem_type, field_name): 609 PrintIteratedElem(i, elem, elem_type, do_summary, summary, regex) 610 i = i + 1 611 except: 612 print("Exception while looking at queue_head: {:#x}".format(unsigned(qhead))) 613 614@lldb_command('lbrbt') 615def LBRBacktrace(cmd_args=None): 616 """ 617 Prints symbolicated last branch records captured on Intel systems 618 from a core file. Will not work on a live system. 619 usage: 620 lbrbt 621 options: 622 None 623 """ 624 DecoratedLBRStack = SymbolicateLBR() 625 if (DecoratedLBRStack): 626 print(DecoratedLBRStack) 627 628def SymbolicateLBR(): 629 lbr_size_offset = 5 630 cpu_num_offset = 4 631 LBRMagic = 0x5352424C 632 633 try: 634 phys_carveout_addr = kern.GetLoadAddressForSymbol("phys_carveout") 635 except LookupError: 636 print("Last Branch Recoreds not present in this core file") 637 return None 638 try: 639 phys_carveout_md_addr = kern.GetLoadAddressForSymbol("panic_lbr_header") 640 except LookupError: 641 print("Last Branch Recoreds not present in this core file") 642 return None 643 644 metadata_ptr = kern.GetValueFromAddress(phys_carveout_md_addr, "uint64_t *") 645 metadata = kern.GetValueFromAddress(unsigned(metadata_ptr[0]), "uint8_t *") 646 carveout_ptr = kern.GetValueFromAddress(phys_carveout_addr, "uint64_t *") 647 648 metadata_hdr = kern.GetValueFromAddress(unsigned(metadata_ptr[0]), "uint32_t *") 649 if not (unsigned(metadata_hdr[0]) == LBRMagic): 650 print("'LBRS' not found at beginning of phys_carveout section, cannot proceed.") 651 return None 652 653 lbr_records = unsigned(carveout_ptr[0]) 654 655 num_lbrs = int(metadata[lbr_size_offset]) 656 657 header_line = "".join("{:49s} -> {:s}\n".format("From", "To")) 658 ncpus = int(metadata[cpu_num_offset]) 659 660 output_lines = [] 661 662 target = LazyTarget.GetTarget() 663 664 for cpu in range(ncpus): 665 start_addr_from = lbr_records + num_lbrs * 8 * cpu 666 start_addr_to = start_addr_from + num_lbrs * 8 * ncpus 667 from_lbr = kern.GetValueFromAddress(start_addr_from, "uint64_t *") 668 to_lbr = kern.GetValueFromAddress(start_addr_to, "uint64_t *") 669 for i in range(num_lbrs): 670 if (from_lbr[i] == 0x0 or to_lbr[i] == 0x0): 671 break 672 ## Replace newline with space to include inlined functions 673 ## in a trade off for longer output lines. 674 fprint = str(target.ResolveLoadAddress(int(from_lbr[i]))).replace('\n', ' ') 675 tprint = str(target.ResolveLoadAddress(int(to_lbr[i]))).replace('\n', ' ') 676 output_lines.append(''.join("({:x}) {:30s} -> ({:x}) {:30s}\n".format(from_lbr[i], fprint, to_lbr[i], tprint))) 677 678 return header_line + ''.join(output_lines) 679