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