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