1""" 2Miscellaneous (Intel) platform-specific commands. 3""" 4 5from xnu import * 6import xnudefines 7 8@lldb_command('showmcastate') 9def showMCAstate(cmd_args=None): 10 """ 11 Print machine-check register state after MC exception. 12 """ 13 if kern.arch != 'x86_64': 14 print "Not available for current architecture." 15 return 16 17 present = ["not present", "present"] 18 print 'MCA {:s}, control MSR {:s}, threshold status {:s}'.format( 19 present[int(kern.globals.mca_MCA_present)], 20 present[int(kern.globals.mca_control_MSR_present)], 21 present[int(kern.globals.mca_threshold_status_present)]) 22 print '{:d} error banks, family code {:#0x}, machine-check dump state: {:d}'.format( 23 kern.globals.mca_error_bank_count, 24 kern.globals.mca_dump_state, 25 kern.globals.mca_family) 26 cpu = 0 27 while kern.globals.cpu_data_ptr[cpu]: 28 cd = kern.globals.cpu_data_ptr[cpu] 29 mc = cd.cpu_mca_state 30 if mc: 31 print 'CPU {:d}: mca_mcg_ctl: {:#018x} mca_mcg_status {:#018x}'.format(cpu, mc.mca_mcg_ctl, mc.mca_mcg_status.u64) 32 hdr = '{:<4s} {:<18s} {:<18s} {:<18s} {:<18s}' 33 val = '{:>3d}: {:#018x} {:#018x} {:#018x} {:#018x}' 34 print hdr.format('bank', 35 'mca_mci_ctl', 36 'mca_mci_status', 37 'mca_mci_addr', 38 'mca_mci_misc') 39 for i in range(int(kern.globals.mca_error_bank_count)): 40 bank = mc.mca_error_bank[i] 41 print val.format(i, 42 bank.mca_mci_ctl, 43 bank.mca_mci_status.u64, 44 bank.mca_mci_addr, 45 bank.mca_mci_misc) 46 print 'register state:' 47 reg = cd.cpu_desc_index.cdi_ktss.ist1 - sizeof('x86_saved_state_t') 48 print lldb_run_command('p/x *(x86_saved_state_t *) ' + hex(reg)) 49 cpu = cpu + 1 50 51def dumpTimerList(anchor): 52 """ 53 Utility function to dump the timer entries in list (anchor). 54 """ 55 entry = Cast(anchor.head, 'queue_t') 56 if entry == addressof(anchor): 57 print '(empty)' 58 return 59 60 thdr = ' {:<22s}{:<17s}{:<16s} {:<14s} {:<18s}' 61 print thdr.format('entry:','deadline','soft_deadline','to go','(*func)(param0,param1') 62 while entry != addressof(anchor): 63 timer_call = Cast(entry, 'timer_call_t') 64 call_entry = Cast(entry, 'struct call_entry *') 65 debugger_entry = kern.globals.debugger_entry_time 66 if (debugger_entry < call_entry.deadline): 67 delta_sign = ' ' 68 timer_fire = call_entry.deadline - debugger_entry 69 else: 70 delta_sign = '-' 71 timer_fire = debugger_entry - call_entry.deadline 72 tval = ' {:#018x}: {:16d} {:16d} {:s}{:3d}.{:09d} ({:#018x})({:#018x},{:#018x})' 73 print tval.format(entry, 74 call_entry.deadline, 75 timer_call.soft_deadline, 76 delta_sign, 77 timer_fire/1000000000, 78 timer_fire%1000000000, 79 call_entry.func, 80 call_entry.param0, 81 call_entry.param1) 82 entry = entry.next 83 84@lldb_command('longtermtimers') 85def longtermTimers(cmd_args=None): 86 """ 87 Print details of long-term timers and stats. 88 """ 89 if kern.arch != 'x86_64': 90 print "Not available for current architecture." 91 return 92 93 lt = kern.globals.timer_longterm 94 ltt = lt.threshold 95 EndofAllTime = -1 96 if ltt.interval == EndofAllTime: 97 print "Longterm timers disabled" 98 return 99 100 if lt.escalates > 0: 101 ratio = lt.enqueues / lt.escalates 102 else: 103 ratio = lt.enqueues 104 print 'Longterm timer object: {:#018x}'.format(addressof(lt)) 105 print ' queue count : {:d}' .format(lt.queue.count) 106 print ' number of enqueues : {:d}' .format(lt.enqueues) 107 print ' number of dequeues : {:d}' .format(lt.dequeues) 108 print ' number of escalates : {:d}' .format(lt.escalates) 109 print ' enqueues/escalates : {:d}' .format(ratio) 110 print ' threshold.interval : {:d}' .format(ltt.interval) 111 print ' threshold.margin : {:d}' .format(ltt.margin) 112 print ' scan_time : {:d}' .format(lt.scan_time) 113 if ltt.preempted == EndofAllTime: 114 print ' threshold.preempted : None' 115 else: 116 print ' threshold.preempted : {:d}' .format(ltt.preempted) 117 if ltt.deadline == EndofAllTime: 118 print ' threshold.deadline : None' 119 else: 120 print ' threshold.deadline : {:d}' .format(ltt.deadline) 121 print ' threshold.call : {:#018x}'.format(ltt.call) 122 print ' actual deadline set : {:d}' .format(ltt.deadline_set) 123 print ' threshold.scans : {:d}' .format(ltt.scans) 124 print ' threshold.preempts : {:d}' .format(ltt.preempts) 125 print ' threshold.latency : {:d}' .format(ltt.latency) 126 print ' - min : {:d}' .format(ltt.latency_min) 127 print ' - max : {:d}' .format(ltt.latency_max) 128 dumpTimerList(lt.queue) 129 130 131@lldb_command('processortimers') 132def processorTimers(cmd_args=None): 133 """ 134 Print details of processor timers, noting anything suspicious 135 Also include long-term timer details 136 """ 137 hdr = '{:<32s}{:<18s} {:<18s} {:<18s}' 138 print hdr.format('Processor','Last dispatch','Next deadline','difference') 139 p = kern.globals.processor_list 140 while p: 141 cpu = p.cpu_id 142 rt_timer = kern.globals.cpu_data_ptr[cpu].rtclock_timer 143 diff = p.last_dispatch - rt_timer.deadline 144 tmr = 'Processor {:d}: {:#018x} {:#018x} {:#018x} {:#018x} {:s}' 145 print tmr.format(cpu, 146 p, 147 p.last_dispatch, 148 rt_timer.deadline, 149 diff, 150 ['probably BAD', '(ok)'][int(diff < 0)]) 151 if kern.arch == 'x86_64': 152 print 'Next deadline set at: {:#018x}. Timer call list:'.format(rt_timer.when_set) 153 dumpTimerList(rt_timer.queue) 154 p = p.processor_list 155 longtermTimers() 156 157 158@lldb_command('showtimerwakeupstats') 159def showTimerWakeupStats(cmd_args=None): 160 """ 161 Displays interrupt and platform idle wakeup frequencies 162 associated with each thread, timer time-to-deadline frequencies, and 163 CPU time with user/system break down where applicable, with thread tags. 164 """ 165 for task in kern.tasks: 166 proc = Cast(task.bsd_info, 'proc_t') 167 print dereference(task) 168 print '{:d}({:s}), terminated thread timer wakeups: {:d} {:d} 2ms: {:d} 5ms: {:d} UT: {:d} ST: {:d}'.format( 169 proc.p_pid, 170 proc.p_comm, 171# Commented-out references below to be addressed by rdar://13009660. 172 0, #task.task_interrupt_wakeups, 173 0, #task.task_platform_idle_wakeups, 174 task.task_timer_wakeups_bin_1, 175 task.task_timer_wakeups_bin_2, 176 task.total_user_time, 177 task.total_system_time) 178 tot_wakes = 0 #task.task_interrupt_wakeups 179 tot_platform_wakes = 0 #task.task_platform_idle_wakeups 180 for thread in IterateQueue(task.threads, 'thread_t', 'task_threads'): 181# if thread.thread_interrupt_wakeups == 0: 182# continue 183 print '\tThread ID 0x{:x}, Tag 0x{:x}, timer wakeups: {:d} {:d} {:d} {:d} <2ms: {:d}, <5ms: {:d} UT: {:d} ST: {:d}'.format( 184 thread.thread_id, 185 thread.thread_tag, 186 0, #thread.thread_interrupt_wakeups, 187 0, #thread.thread_platform_idle_wakeups, 188 0, #thread.thread_callout_interrupt_wakeups, 189 0, #thread.thread_callout_platform_idle_wakeups, 190 0,0,0,0, 191 thread.thread_timer_wakeups_bin_1, 192 thread.thread_timer_wakeups_bin_2, 193 thread.user_timer.all_bits, 194 thread.system_timer.all_bits) 195 tot_wakes += 0 #thread.thread_interrupt_wakeups 196 tot_platform_wakes += 0 #thread.thread_platform_idle_wakeups 197 print 'Task total wakeups: {:d} {:d}'.format( 198 tot_wakes, tot_platform_wakes) 199 200def DoReadMsr64(msr_address, lcpu): 201 """ Read a 64-bit MSR from the specified CPU 202 Params: 203 msr_address: int - MSR index to read from 204 lcpu: int - CPU identifier 205 Returns: 206 64-bit value read from the MSR 207 """ 208 result = 0xbad10ad 209 210 if "kdp" != GetConnectionProtocol(): 211 print "Target is not connected over kdp. Cannot read MSR." 212 return result 213 214 input_address = unsigned(addressof(kern.globals.manual_pkt.input)) 215 len_address = unsigned(addressof(kern.globals.manual_pkt.len)) 216 data_address = unsigned(addressof(kern.globals.manual_pkt.data)) 217 if not WriteInt32ToMemoryAddress(0, input_address): 218 print "DoReadMsr64() failed to write 0 to input_address" 219 return result 220 221 kdp_pkt_size = GetType('kdp_readmsr64_req_t').GetByteSize() 222 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address): 223 print "DoReadMsr64() failed to write kdp_pkt_size" 224 return result 225 226 kgm_pkt = kern.GetValueFromAddress(data_address, 'kdp_readmsr64_req_t *') 227 header_value = GetKDPPacketHeaderInt( 228 request=GetEnumValue('kdp_req_t::KDP_READMSR64'), 229 length=kdp_pkt_size) 230 231 if not WriteInt64ToMemoryAddress(header_value, int(addressof(kgm_pkt.hdr))): 232 print "DoReadMsr64() failed to write header_value" 233 return result 234 if not WriteInt32ToMemoryAddress(msr_address, int(addressof(kgm_pkt.address))): 235 print "DoReadMsr64() failed to write msr_address" 236 return result 237 if not WriteInt16ToMemoryAddress(lcpu, int(addressof(kgm_pkt.lcpu))): 238 print "DoReadMsr64() failed to write lcpu" 239 return result 240 if not WriteInt32ToMemoryAddress(1, input_address): 241 print "DoReadMsr64() failed to write to input_address" 242 return result 243 244 result_pkt = Cast(addressof(kern.globals.manual_pkt.data), 245 'kdp_readmsr64_reply_t *') 246 if (result_pkt.error == 0): 247 result = dereference(Cast(addressof(result_pkt.data), 'uint64_t *')) 248 else: 249 print "DoReadMsr64() result_pkt.error != 0" 250 return result 251 252def DoWriteMsr64(msr_address, lcpu, data): 253 """ Write a 64-bit MSR 254 Params: 255 msr_address: int - MSR index to write to 256 lcpu: int - CPU identifier 257 data: int - value to write 258 Returns: 259 True upon success, False if error 260 """ 261 if "kdp" != GetConnectionProtocol(): 262 print "Target is not connected over kdp. Cannot write MSR." 263 return False 264 265 input_address = unsigned(addressof(kern.globals.manual_pkt.input)) 266 len_address = unsigned(addressof(kern.globals.manual_pkt.len)) 267 data_address = unsigned(addressof(kern.globals.manual_pkt.data)) 268 if not WriteInt32ToMemoryAddress(0, input_address): 269 print "DoWriteMsr64() failed to write 0 to input_address" 270 return False 271 272 kdp_pkt_size = GetType('kdp_writemsr64_req_t').GetByteSize() 273 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address): 274 print "DoWriteMsr64() failed to kdp_pkt_size" 275 return False 276 277 kgm_pkt = kern.GetValueFromAddress(data_address, 'kdp_writemsr64_req_t *') 278 header_value = GetKDPPacketHeaderInt( 279 request=GetEnumValue('kdp_req_t::KDP_WRITEMSR64'), 280 length=kdp_pkt_size) 281 282 if not WriteInt64ToMemoryAddress(header_value, int(addressof(kgm_pkt.hdr))): 283 print "DoWriteMsr64() failed to write header_value" 284 return False 285 if not WriteInt32ToMemoryAddress(msr_address, int(addressof(kgm_pkt.address))): 286 print "DoWriteMsr64() failed to write msr_address" 287 return False 288 if not WriteInt16ToMemoryAddress(lcpu, int(addressof(kgm_pkt.lcpu))): 289 print "DoWriteMsr64() failed to write lcpu" 290 return False 291 if not WriteInt64ToMemoryAddress(data, int(addressof(kgm_pkt.data))): 292 print "DoWriteMsr64() failed to write data" 293 return False 294 if not WriteInt32ToMemoryAddress(1, input_address): 295 print "DoWriteMsr64() failed to write to input_address" 296 return False 297 298 result_pkt = Cast(addressof(kern.globals.manual_pkt.data), 299 'kdp_writemsr64_reply_t *') 300 if not result_pkt.error == 0: 301 print "DoWriteMsr64() error received in reply packet" 302 return False 303 304 return True 305 306@lldb_command('readmsr64') 307def ReadMsr64(cmd_args=None): 308 """ Read the specified MSR. The CPU can be optionally specified 309 Syntax: readmsr64 <msr> [lcpu] 310 """ 311 if cmd_args == None or len(cmd_args) < 1: 312 print ReadMsr64.__doc__ 313 return 314 315 msr_address = ArgumentStringToInt(cmd_args[0]) 316 if len(cmd_args) > 1: 317 lcpu = ArgumentStringToInt(cmd_args[1]) 318 else: 319 lcpu = int(xnudefines.lcpu_self) 320 321 msr_value = DoReadMsr64(msr_address, lcpu) 322 print "MSR[{:x}]: {:#016x}".format(msr_address, msr_value) 323 324@lldb_command('writemsr64') 325def WriteMsr64(cmd_args=None): 326 """ Write the specified MSR. The CPU can be optionally specified 327 Syntax: writemsr64 <msr> <value> [lcpu] 328 """ 329 if cmd_args == None or len(cmd_args) < 2: 330 print WriteMsr64.__doc__ 331 return 332 msr_address = ArgumentStringToInt(cmd_args[0]) 333 write_val = ArgumentStringToInt(cmd_args[1]) 334 if len(cmd_args) > 2: 335 lcpu = ArgumentStringToInt(cmd_args[2]) 336 else: 337 lcpu = xnudefines.lcpu_self 338 339 if not DoWriteMsr64(msr_address, lcpu, write_val): 340 print "writemsr64 FAILED" 341 342