1""" 2Miscellaneous (Intel) platform-specific commands. 3""" 4from core import caching 5from xnu import * 6import xnudefines 7 8from scheduler import * 9from xnu import GetTaskTerminatedUserSysTime 10 11@lldb_command('showmcastate') 12def showMCAstate(cmd_args=None): 13 """ 14 Print machine-check register state after MC exception. 15 """ 16 if kern.arch != 'x86_64': 17 print("Not available for current architecture.") 18 return 19 20 present = ["not present", "present"] 21 print('MCA {:s}, control MSR {:s}, threshold status {:s}'.format( 22 present[int(kern.globals.mca_MCA_present)], 23 present[int(kern.globals.mca_control_MSR_present)], 24 present[int(kern.globals.mca_threshold_status_present)])) 25 print('{:d} error banks, family code {:#0x}, machine-check dump state: {:d}'.format( 26 kern.globals.mca_error_bank_count, 27 kern.globals.mca_dump_state, 28 kern.globals.mca_family)) 29 cpu = 0 30 while kern.globals.cpu_data_ptr[cpu]: 31 cd = kern.globals.cpu_data_ptr[cpu] 32 mc = cd.cpu_mca_state 33 if mc: 34 print('CPU {:d}: mca_mcg_ctl: {:#018x} mca_mcg_status {:#018x}'.format(cpu, mc.mca_mcg_ctl, mc.mca_mcg_status.u64)) 35 hdr = '{:<4s} {:<18s} {:<18s} {:<18s} {:<18s}' 36 val = '{:>3d}: {:#018x} {:#018x} {:#018x} {:#018x}' 37 print(hdr.format('bank', 38 'mca_mci_ctl', 39 'mca_mci_status', 40 'mca_mci_addr', 41 'mca_mci_misc')) 42 for i in range(int(kern.globals.mca_error_bank_count)): 43 bank = mc.mca_error_bank[i] 44 print(val.format(i, 45 bank.mca_mci_ctl, 46 bank.mca_mci_status.u64, 47 bank.mca_mci_addr, 48 bank.mca_mci_misc)) 49 print('register state:') 50 reg = cd.cpu_desc_index.cdi_ktss.ist1 - sizeof('x86_saved_state_t') 51 print(lldb_run_command('p/x *(x86_saved_state_t *) ' + hex(reg))) 52 cpu = cpu + 1 53 54def dumpTimerList(mpqueue, processor=None): 55 """ 56 Utility function to dump the timer entries in list (anchor). 57 anchor is a struct mpqueue_head. 58 """ 59 60 if mpqueue.count == 0: 61 print('(empty)') 62 return 63 64 thdr = ' {:<24s}{:^17s}{:^18s} {:^18s} {:^18s} {:^18s} {:^18s} {:9s} {:^18s} count: {:d} ' 65 tval = ' {:#018x}{:s} {:18d} {:18d} {:18.06f} {:18.06f} {:18.06f} {:18.06f} {:>9s} ({:#018x})({:#018x}, {:#018x}) ({:s}) {:s}' 66 67 print(thdr.format('Entry', 'Soft Deadline', 'Deadline', 'Soft To Go', 'Hard To Go', 'Duration', 'Leeway', 'Flags', '(*func)(param0, param1)', mpqueue.count)) 68 69 recent_timestamp = GetRecentTimestamp() 70 71 for timer_call in ParanoidIterateLinkageChain(mpqueue.head, 'struct timer_call *', 'tc_qlink'): 72 73 func_name = kern.Symbolicate(timer_call.tc_func) 74 75 extra_string = "" 76 77 strip_func = kern.StripKernelPAC(unsigned(timer_call.tc_func)) 78 79 func_syms = kern.SymbolicateFromAddress(strip_func) 80 # returns an array of SBSymbol 81 82 if func_syms and func_syms[0] : 83 func_sym = func_syms[0] 84 func_name = func_sym.GetName() 85 try : 86 87 if "thread_call_delayed_timer" in func_name : 88 group = Cast(timer_call.tc_param0, 'struct thread_call_group *') 89 flavor = Cast(timer_call.tc_param1, 'thread_call_flavor_t') 90 91 # There's got to be a better way to stringify the enum 92 flavorname = str(flavor).partition(" = ")[2] 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 344def timer_deadine_string(timer, recent_timestamp): 345 EndOfAllTime = signed(-1) 346 347 deadline = unsigned(timer.tc_pqlink.deadline) 348 deadlinediff = signed(deadline) - signed(recent_timestamp) 349 deadlinediff_s = kern.GetNanotimeFromAbstime(deadlinediff) / 1000000000.0 350 351 if signed(timer.tc_pqlink.deadline) == EndOfAllTime: 352 valid = False 353 else : 354 valid = True 355 356 deadline_str = "{:18d}".format(deadline) if valid else "" 357 deadlinediff_str = "{:16.06f}".format(deadlinediff_s) if valid else "" 358 359 return " {:18s} {:18s}".format(deadline_str, deadlinediff_str) 360 361 362@lldb_command('showrunningtimers') 363def ShowRunningTimers(cmd_args=None): 364 """ 365 Print the state of all running timers. 366 367 Usage: showrunningtimers 368 """ 369 processor_array = kern.globals.processor_array 370 371 recent_timestamp = GetRecentTimestamp() 372 373 hdr = '{:4s} {:^10s} {:^18s} {:^18s} {:^18s} {:^18s} {:^18s} {:^18s} {:^18s} {:^18s}' 374 print(hdr.format('CPU', 'State', 'Quantum', 'To Go', 'Preempt', 'To Go', 'kperf', 'To Go', 'Perfcontrol', 'To Go')) 375 376 cpu = '{:3d}: {:^10s}' 377 378 i = 0 379 while processor_array[i] != 0: 380 processor = processor_array[i] 381 382 statestr = 'runnning' if processor.running_timers_active else 'idle' 383 384 cpustr = cpu.format(i, statestr) 385 386 cpustr += timer_deadine_string(processor.running_timers[GetEnumValue('running_timer::RUNNING_TIMER_QUANTUM')], recent_timestamp) 387 cpustr += timer_deadine_string(processor.running_timers[GetEnumValue('running_timer::RUNNING_TIMER_PREEMPT')], recent_timestamp) 388 cpustr += timer_deadine_string(processor.running_timers[GetEnumValue('running_timer::RUNNING_TIMER_KPERF')], recent_timestamp) 389 cpustr += timer_deadine_string(processor.running_timers[GetEnumValue('running_timer::RUNNING_TIMER_PERFCONTROL')], recent_timestamp) 390 391 print (cpustr) 392 i += 1 393 394def DoReadMsr64(msr_address, lcpu): 395 """ Read a 64-bit MSR from the specified CPU 396 Params: 397 msr_address: int - MSR index to read from 398 lcpu: int - CPU identifier 399 Returns: 400 64-bit value read from the MSR 401 """ 402 result = 0xbad10ad 403 404 if "kdp" != GetConnectionProtocol(): 405 print("Target is not connected over kdp. Cannot read MSR.") 406 return result 407 408 input_address = unsigned(addressof(kern.globals.manual_pkt.input)) 409 len_address = unsigned(addressof(kern.globals.manual_pkt.len)) 410 data_address = unsigned(addressof(kern.globals.manual_pkt.data)) 411 if not WriteInt32ToMemoryAddress(0, input_address): 412 print("DoReadMsr64() failed to write 0 to input_address") 413 return result 414 415 kdp_pkt_size = GetType('kdp_readmsr64_req_t').GetByteSize() 416 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address): 417 print("DoReadMsr64() failed to write kdp_pkt_size") 418 return result 419 420 kgm_pkt = kern.GetValueFromAddress(data_address, 'kdp_readmsr64_req_t *') 421 header_value = GetKDPPacketHeaderInt( 422 request=GetEnumValue('kdp_req_t::KDP_READMSR64'), 423 length=kdp_pkt_size) 424 425 if not WriteInt64ToMemoryAddress(header_value, int(addressof(kgm_pkt.hdr))): 426 print("DoReadMsr64() failed to write header_value") 427 return result 428 if not WriteInt32ToMemoryAddress(msr_address, int(addressof(kgm_pkt.address))): 429 print("DoReadMsr64() failed to write msr_address") 430 return result 431 if not WriteInt16ToMemoryAddress(lcpu, int(addressof(kgm_pkt.lcpu))): 432 print("DoReadMsr64() failed to write lcpu") 433 return result 434 if not WriteInt32ToMemoryAddress(1, input_address): 435 print("DoReadMsr64() failed to write to input_address") 436 return result 437 438 result_pkt = Cast(addressof(kern.globals.manual_pkt.data), 439 'kdp_readmsr64_reply_t *') 440 if (result_pkt.error == 0): 441 result = dereference(Cast(addressof(result_pkt.data), 'uint64_t *')) 442 else: 443 print("DoReadMsr64() result_pkt.error != 0") 444 return result 445 446def DoWriteMsr64(msr_address, lcpu, data): 447 """ Write a 64-bit MSR 448 Params: 449 msr_address: int - MSR index to write to 450 lcpu: int - CPU identifier 451 data: int - value to write 452 Returns: 453 True upon success, False if error 454 """ 455 if "kdp" != GetConnectionProtocol(): 456 print("Target is not connected over kdp. Cannot write MSR.") 457 return False 458 459 input_address = unsigned(addressof(kern.globals.manual_pkt.input)) 460 len_address = unsigned(addressof(kern.globals.manual_pkt.len)) 461 data_address = unsigned(addressof(kern.globals.manual_pkt.data)) 462 if not WriteInt32ToMemoryAddress(0, input_address): 463 print("DoWriteMsr64() failed to write 0 to input_address") 464 return False 465 466 kdp_pkt_size = GetType('kdp_writemsr64_req_t').GetByteSize() 467 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address): 468 print("DoWriteMsr64() failed to kdp_pkt_size") 469 return False 470 471 kgm_pkt = kern.GetValueFromAddress(data_address, 'kdp_writemsr64_req_t *') 472 header_value = GetKDPPacketHeaderInt( 473 request=GetEnumValue('kdp_req_t::KDP_WRITEMSR64'), 474 length=kdp_pkt_size) 475 476 if not WriteInt64ToMemoryAddress(header_value, int(addressof(kgm_pkt.hdr))): 477 print("DoWriteMsr64() failed to write header_value") 478 return False 479 if not WriteInt32ToMemoryAddress(msr_address, int(addressof(kgm_pkt.address))): 480 print("DoWriteMsr64() failed to write msr_address") 481 return False 482 if not WriteInt16ToMemoryAddress(lcpu, int(addressof(kgm_pkt.lcpu))): 483 print("DoWriteMsr64() failed to write lcpu") 484 return False 485 if not WriteInt64ToMemoryAddress(data, int(addressof(kgm_pkt.data))): 486 print("DoWriteMsr64() failed to write data") 487 return False 488 if not WriteInt32ToMemoryAddress(1, input_address): 489 print("DoWriteMsr64() failed to write to input_address") 490 return False 491 492 result_pkt = Cast(addressof(kern.globals.manual_pkt.data), 493 'kdp_writemsr64_reply_t *') 494 if not result_pkt.error == 0: 495 print("DoWriteMsr64() error received in reply packet") 496 return False 497 498 return True 499 500@lldb_command('readmsr64') 501def ReadMsr64(cmd_args=None): 502 """ Read the specified MSR. The CPU can be optionally specified 503 Syntax: readmsr64 <msr> [lcpu] 504 """ 505 if cmd_args is None or len(cmd_args) == 0: 506 raise ArgumentError() 507 508 509 msr_address = ArgumentStringToInt(cmd_args[0]) 510 if len(cmd_args) > 1: 511 lcpu = ArgumentStringToInt(cmd_args[1]) 512 else: 513 lcpu = int(xnudefines.lcpu_self) 514 515 msr_value = DoReadMsr64(msr_address, lcpu) 516 print("MSR[{:x}]: {:#016x}".format(msr_address, msr_value)) 517 518@lldb_command('writemsr64') 519def WriteMsr64(cmd_args=None): 520 """ Write the specified MSR. The CPU can be optionally specified 521 Syntax: writemsr64 <msr> <value> [lcpu] 522 """ 523 if cmd_args is None or len(cmd_args) < 2: 524 raise ArgumentError() 525 526 msr_address = ArgumentStringToInt(cmd_args[0]) 527 write_val = ArgumentStringToInt(cmd_args[1]) 528 if len(cmd_args) > 2: 529 lcpu = ArgumentStringToInt(cmd_args[2]) 530 else: 531 lcpu = xnudefines.lcpu_self 532 533 if not DoWriteMsr64(msr_address, lcpu, write_val): 534 print("writemsr64 FAILED") 535 536 537@caching.cache_statically 538def GetTimebaseInfo(target=None): 539 if kern.arch == 'x86_64': 540 return 1, 1 541 542 rtclockdata_addr = kern.GetLoadAddressForSymbol('RTClockData') 543 rtc = kern.GetValueFromAddress( 544 rtclockdata_addr, 'struct _rtclock_data_ *') 545 tb = rtc.rtc_timebase_const 546 return int(tb.numer), int(tb.denom) 547 548 549def PrintIteratedElem(i, elem, elem_type, do_summary, summary, regex): 550 try: 551 if do_summary and summary: 552 s = summary(elem) 553 if regex: 554 if regex.match(s): 555 print("[{:d}] {:s}".format(i, s)) 556 else: 557 print("[{:d}] {:s}".format(i, s)) 558 else: 559 if regex: 560 if regex.match(str(elem)): 561 print("[{:4d}] ({:s}){:#x}".format(i, elem_type, unsigned(elem))) 562 else: 563 print("[{:4d}] ({:s}){:#x}".format(i, elem_type, unsigned(elem))) 564 except: 565 print("Exception while looking at elem {:#x}".format(unsigned(elem))) 566 return 567 568@lldb_command('q_iterate', "LQSG:") 569def QIterate(cmd_args=None, cmd_options={}): 570 """ Iterate over a LinkageChain or Queue (osfmk/kern/queue.h method 1 or 2 respectively) 571 This is equivalent to the qe_foreach_element() macro 572 usage: 573 iterate [options] {queue_head_ptr} {element_type} {field_name} 574 option: 575 -L iterate over a linkage chain (method 1) [default] 576 -Q iterate over a queue (method 2) 577 578 -S auto-summarize known types 579 -G regex to filter the output 580 e.g. 581 iterate_linkage `&coalitions_q` 'coalition *' coalitions 582 """ 583 if cmd_args is None or len(cmd_args) == 0: 584 raise ArgumentError("usage: iterate_linkage {queue_head_ptr} {element_type} {field_name}") 585 586 qhead = kern.GetValueFromAddress(cmd_args[0], 'struct queue_entry *') 587 if not qhead: 588 raise ArgumentError("Unknown queue_head pointer: %r" % cmd_args) 589 elem_type = cmd_args[1] 590 field_name = cmd_args[2] 591 if not elem_type or not field_name: 592 raise ArgumentError("usage: iterate_linkage {queue_head_ptr} {element_type} {field_name}") 593 594 do_queue_iterate = False 595 do_linkage_iterate = True 596 if "-Q" in cmd_options: 597 do_queue_iterate = True 598 do_linkage_iterate = False 599 if "-L" in cmd_options: 600 do_queue_iterate = False 601 do_linkage_iterate = True 602 603 do_summary = False 604 if "-S" in cmd_options: 605 do_summary = True 606 regex = None 607 if "-G" in cmd_options: 608 regex = re.compile(".*{:s}.*".format(cmd_options["-G"])) 609 print("Looking for: {:s}".format(regex.pattern)) 610 611 global lldb_summary_definitions 612 summary = None 613 if elem_type in lldb_summary_definitions: 614 summary = lldb_summary_definitions[elem_type] 615 if do_summary: 616 print(summary.header) 617 618 try: 619 i = 0 620 if do_linkage_iterate: 621 for elem in IterateLinkageChain(qhead, elem_type, field_name): 622 PrintIteratedElem(i, elem, elem_type, do_summary, summary, regex) 623 i = i + 1 624 elif do_queue_iterate: 625 for elem in IterateQueue(qhead, elem_type, field_name): 626 PrintIteratedElem(i, elem, elem_type, do_summary, summary, regex) 627 i = i + 1 628 except: 629 print("Exception while looking at queue_head: {:#x}".format(unsigned(qhead))) 630 631@lldb_command('lbrbt') 632def LBRBacktrace(cmd_args=None): 633 """ 634 Prints symbolicated last branch records captured on Intel systems 635 from a core file. Will not work on a live system. 636 usage: 637 lbrbt 638 options: 639 None 640 """ 641 if IsDebuggingCore() or kern.arch.startswith('arm'): 642 print("Command is only supported on live Intel systems") 643 return 644 645 DecoratedLBRStack = SymbolicateLBR() 646 if (DecoratedLBRStack): 647 print(DecoratedLBRStack) 648 649def SymbolicateLBR(): 650 lbr_size_offset = 5 651 cpu_num_offset = 4 652 LBRMagic = 0x5352424C 653 654 try: 655 phys_carveout_addr = kern.GetLoadAddressForSymbol("phys_carveout") 656 except LookupError: 657 print("Last Branch Recoreds not present in this core file") 658 return None 659 try: 660 phys_carveout_md_addr = kern.GetLoadAddressForSymbol("panic_lbr_header") 661 except LookupError: 662 print("Last Branch Recoreds not present in this core file") 663 return None 664 665 metadata_ptr = kern.GetValueFromAddress(phys_carveout_md_addr, "uint64_t *") 666 metadata = kern.GetValueFromAddress(unsigned(metadata_ptr[0]), "uint8_t *") 667 carveout_ptr = kern.GetValueFromAddress(phys_carveout_addr, "uint64_t *") 668 669 metadata_hdr = kern.GetValueFromAddress(unsigned(metadata_ptr[0]), "uint32_t *") 670 if not (unsigned(metadata_hdr[0]) == LBRMagic): 671 print("'LBRS' not found at beginning of phys_carveout section, cannot proceed.") 672 return None 673 674 lbr_records = unsigned(carveout_ptr[0]) 675 676 num_lbrs = int(metadata[lbr_size_offset]) 677 678 header_line = "".join("{:49s} -> {:s}\n".format("From", "To")) 679 ncpus = int(metadata[cpu_num_offset]) 680 681 output_lines = [] 682 683 target = LazyTarget.GetTarget() 684 685 for cpu in range(ncpus): 686 start_addr_from = lbr_records + num_lbrs * 8 * cpu 687 start_addr_to = start_addr_from + num_lbrs * 8 * ncpus 688 from_lbr = kern.GetValueFromAddress(start_addr_from, "uint64_t *") 689 to_lbr = kern.GetValueFromAddress(start_addr_to, "uint64_t *") 690 for i in range(num_lbrs): 691 if (from_lbr[i] == 0x0 or to_lbr[i] == 0x0): 692 break 693 ## Replace newline with space to include inlined functions 694 ## in a trade off for longer output lines. 695 fprint = str(target.ResolveLoadAddress(int(from_lbr[i]))).replace('\n', ' ') 696 tprint = str(target.ResolveLoadAddress(int(to_lbr[i]))).replace('\n', ' ') 697 output_lines.append(''.join("({:x}) {:30s} -> ({:x}) {:30s}\n".format(from_lbr[i], fprint, to_lbr[i], tprint))) 698 699 return header_line + ''.join(output_lines) 700