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