xref: /xnu-8020.121.3/tools/lldbmacros/misc.py (revision fdd8201d7b966f0c3ea610489d29bd841d358941)
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