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