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