xref: /xnu-8019.80.24/tools/lldbmacros/btlog.py (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
1""" Some of the functionality here is a copy of existing macros from memory.py
2    with the VM specific stuff removed so the macros work with any btlog.
3    Eventually the zstack macros should be refactored to reuse the generic btlog
4    support added here.
5"""
6
7from xnu import *
8
9@lldb_type_summary(['btlog_t *'])
10@header("{0: <20s} {1: <9s} {2: <6s} {3: >9s}".format("btlog", "capacity", "depth", "count"))
11def GetBTLogSummary(btlog):
12    """ Summarizes btlog structure.
13        params: btlog: value - value object representing a btlog in kernel
14        returns: str - summary of the btlog
15    """
16
17    index = btlog.head
18    records = btlog.btrecords
19    record_size = btlog.btrecord_size
20    count = 0
21
22    while index != 0xffffff:
23        addr = records + (index * record_size)
24        record = kern.GetValueFromAddress(addr, 'btlog_record_t *')
25        index = record.next
26        count += 1
27
28    capacity = (btlog.btlog_buffersize - sizeof('btlog_t')) / btlog.btrecord_size
29
30    format_string = "{0: <#20x} {1: <9d} {2: <6d} {3: >9d}"
31
32    return format_string.format(btlog, capacity, btlog.btrecord_btdepth, count)
33
34def GetBTLogEntryBacktrace(depth, record):
35    """ Helper routine for getting a btlog record backtrace stack.
36        params:
37            depth:int - The depth of the stack record
38            record:btlog_record_t * - A btlog record
39        returns:
40            str - string with backtrace in it.
41    """
42    out_str = ''
43    frame = 0
44    if not record:
45        return "no record!"
46
47    depth_val = unsigned(depth)
48    while frame < depth_val:
49        frame_pc = record.bt[frame]
50        if not frame_pc or int(frame_pc) == 0:
51            break
52        symbol_arr = kern.SymbolicateFromAddress(frame_pc)
53        if symbol_arr:
54            symbol_str = str(symbol_arr[0].addr)
55        else:
56            symbol_str = ''
57        out_str += "{0: <#0x} <{1: <s}>\n".format(frame_pc, symbol_str)
58        frame += 1
59    return out_str
60
61def ShowBTLogRecord(record, index, depth, count):
62    """ Helper routine for printing a single btlog record
63        params:
64            record:btlog_record_t * -  A BTLog record
65            index:int - Index for the record in the BTLog table
66            depth:int - Depth of stack
67            count:int - Active count
68        returns:
69            None
70    """
71
72    out_str = ('-' * 8)
73    out_str += " OP {0: <d} Stack Index {1: <d} with active refs {2: <d} of {3: <d} {4: <s}\n".format(record.operation, index, record.ref_count, count, ('-' * 8))
74    print out_str
75    print GetBTLogEntryBacktrace(depth, record)
76    print " \n"
77
78# Macro: showbtlog
79@lldb_command('showbtlog')
80def ShowBTLogHelper(cmd_args=None):
81    """ Display a summary of the specified btlog
82        Usage: showbtlog <btlog address>
83    """
84
85    btlog = kern.GetValueFromAddress(cmd_args[0], 'btlog_t *')
86    if not btlog:
87        raise ("Unknown arguments: %r" % cmd_args)
88
89    print GetBTLogSummary.header
90    print GetBTLogSummary(btlog)
91
92# EndMacro: showbtlog
93
94
95# Macro: showbtlogrecords
96
97@lldb_command('showbtlogrecords', 'E:')
98def ShowBTLog(cmd_args=None, cmd_options={}):
99    """ Print all records in the btlog from head to tail.
100        Usage: showbtlogrecords <btlog addr>
101    """
102    if not cmd_args:
103        print "Print contents of btlog. \nUsage: showbtlogrecords <btlog addr>"
104        return
105
106    if "-E" in cmd_options:
107
108        element = kern.GetValueFromAddress(cmd_options["-E"], 'void *')
109    else:
110        element = None
111
112    btlog = kern.GetValueFromAddress(cmd_args[0], 'btlog_t *')
113    if not btlog:
114        raise ("Unknown arguments: %r" % cmd_args)
115
116    records = btlog.btrecords
117    record_size = btlog.btrecord_size
118    depth = btlog.btrecord_btdepth
119    count = btlog.active_element_count;
120
121    if not element:
122
123        index = btlog.head
124        while index != 0xffffff:
125            addr = records + (index * record_size)
126            record = kern.GetValueFromAddress(addr, 'btlog_record_t *')
127            ShowBTLogRecord(record, index, depth, count)
128            index = record.next
129
130    else:
131
132        if btlog.caller_will_remove_entries_for_element == 1:
133            print "'-E' not supported with this type of btlog"
134            return
135
136        if (element >> 32) != 0:
137            element = element ^ 0xFFFFFFFFFFFFFFFF
138        else:
139            element = element ^ 0xFFFFFFFF
140
141        scan_items = 0
142        hashelem = cast(btlog.elem_linkage_un.element_hash_queue.tqh_first,
143            'btlog_element_t *')
144        while hashelem != 0:
145
146            if unsigned(hashelem.elem) == element:
147                recindex = hashelem.recindex
148                recoffset = recindex * record_size
149                record = kern.GetValueFromAddress(records + recoffset,
150                    'btlog_record_t *')
151                ShowBTLogRecord(record, recindex, depth, count)
152                scan_items = 0
153
154            hashelem = cast(hashelem.element_hash_link.tqe_next, 'btlog_element_t *')
155            scan_items += 1
156            if scan_items % 100 == 0:
157               print "Scanning is ongoing. {0: <d} items scanned since last check." \
158                  .format(scan_items)
159
160# EndMacro : showbtlogrecords
161