xref: /xnu-8019.80.24/tools/lldbmacros/structanalyze.py (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
1import lldb
2from xnu import *
3
4_UnionStructClass = [ lldb.eTypeClassStruct, lldb.eTypeClassClass, lldb.eTypeClassUnion ]
5
6def _get_offset_formatter(ctx, fmt_hex, fmt_dec):
7    """ Returns a formatter of struct member offsets and sizes.
8
9    params:
10        ctx - configuration context
11        fmt_hex - hexadecimal format
12        fmt_dec - decimal format
13    returns:
14        offset formatter
15    """
16    O = ctx[0]
17    use_hex = ctx[1]
18    if use_hex:
19        fmt = fmt_hex
20    else:
21        fmt = fmt_dec
22    return lambda o, s: O.format(fmt, o, s)
23
24def _get_num_formatter(ctx, fmt_hex, fmt_dec):
25    """ Returns a number formatter.
26
27    params:
28        ctx - configuration context
29        fmt_hex - hexadecimal format
30        fmt_dec - decimal format
31    returns:
32        number formatter
33    """
34    O = ctx[0]
35    use_hex = ctx[1]
36    if use_hex:
37        fmt = fmt_hex
38    else:
39        fmt = fmt_dec
40    return lambda n: O.format(fmt, n)
41
42def _showStructPacking(ctx, symbol, begin_offset=0, symsize=0, typedef=None, outerSize=0, memberName=None):
43    """ Recursively parse the field members of structure.
44
45        params :
46            ctx - context containing configuration settings and the output formatter (standard.py) symbol (lldb.SBType) reference to symbol in binary
47        returns:
48            string containing lines of output.
49    """
50
51    O = ctx[0]
52    format_offset = _get_offset_formatter(ctx, "{:#06x},[{:#6x}]", "{:04d},[{:4d}]")
53    format_num = _get_num_formatter(ctx, "{:#04x}", "{:2d}")
54
55    ctype = "unknown type"
56    is_union = False
57    is_class = False
58    union_size = None
59    sym_size = symbol.GetByteSize()
60
61    if symbol.GetTypeClass() == lldb.eTypeClassUnion:
62        ctype = "union"
63        is_union = True
64        union_size = sym_size
65    if symbol.GetTypeClass() == lldb.eTypeClassStruct:
66        ctype = "struct"
67    if symbol.GetTypeClass() == lldb.eTypeClassClass:
68        ctype = "class"
69        is_class = True
70
71    if not outerSize or outerSize == sym_size:
72        outstr = format_offset(begin_offset, sym_size)
73    elif outerSize < sym_size: # happens with c++ inheritance
74        outstr = format_offset(begin_offset, outerSize)
75    else:
76        outstr = O.format("{:s}{VT.DarkRed}{{{:s}}}{VT.Default}",
77                format_offset(begin_offset, sym_size),
78                format_num(outerSize - sym_size))
79
80    if typedef:
81        outstr += O.format(" {0}", typedef)
82    if symbol.IsAnonymousType():
83        outstr += O.format(" ({VT.DarkMagenta}anonymous {0}{VT.Default})", ctype)
84    else:
85        outstr += O.format(" ({VT.DarkMagenta}{0} {1}{VT.Default})", ctype, symbol.GetName())
86    if memberName:
87        outstr += O.format(" {0} {{", memberName)
88    else:
89        outstr += ") {"
90
91    print outstr
92
93    with O.indent():
94        _previous_size = 0
95        _packed_bit_offset = 0
96        _nfields = symbol.GetNumberOfFields()
97
98        if is_class:
99            _next_offset_in_bits = 0
100            _nclasses = symbol.GetNumberOfDirectBaseClasses()
101
102            for i in range(_nclasses):
103                member = symbol.GetDirectBaseClassAtIndex(i)
104                if i < _nclasses - 1:
105                    m_size_bits = symbol.GetDirectBaseClassAtIndex(i + 1).GetOffsetInBits()
106                elif _nfields:
107                    m_size_bits = symbol.GetFieldAtIndex(0).GetOffsetInBits()
108                else:
109                    m_size_bits = symbol.GetByteSize() * 8
110
111                m_offset = member.GetOffsetInBytes() + begin_offset
112                m_type = member.GetType()
113                m_name = member.GetName()
114                m_size = m_size_bits / 8
115
116                _previous_size = m_size
117                _packed_bit_offset = member.GetOffsetInBits() + m_size_bits
118
119                _showStructPacking(ctx, m_type, m_offset, str(m_type), outerSize=m_size, memberName=m_name)
120
121        for i in range(_nfields):
122            member = symbol.GetFieldAtIndex(i)
123            m_offset = member.GetOffsetInBytes() + begin_offset
124            m_offset_bits = member.GetOffsetInBits()
125
126            m_type = member.GetType()
127            m_name = member.GetName()
128            m_size = m_type.GetByteSize()
129
130            if member.IsBitfield():
131                m_is_bitfield = True
132                m_size_bits = member.GetBitfieldSizeInBits()
133            else:
134                m_is_bitfield = False
135                m_size_bits = m_size * 8
136
137            if not is_union and _packed_bit_offset < m_offset_bits:
138                m_previous_offset = begin_offset + _packed_bit_offset / 8
139                m_hole_bits = m_offset_bits - _packed_bit_offset
140                if _packed_bit_offset % 8 == 0:
141                    print O.format("{:s} ({VT.DarkRed}*** padding ***{VT.Default})",
142                           format_offset(m_previous_offset, m_hole_bits / 8))
143                else:
144                    print O.format("{:s} ({VT.Brown}*** padding : {:s} ***{VT.Default})",
145                            format_offset(m_previous_offset, _previous_size),
146                            format_num(m_hole_bits))
147
148            _previous_size = m_size
149            _packed_bit_offset = m_offset_bits + m_size_bits
150
151            _type_class = m_type.GetTypeClass()
152            _canonical_type = m_type.GetCanonicalType()
153            _canonical_type_class = m_type.GetCanonicalType().GetTypeClass()
154
155            if _type_class == lldb.eTypeClassTypedef and _canonical_type_class in _UnionStructClass:
156                _showStructPacking(ctx, _canonical_type, m_offset, str(m_type), outerSize=union_size, memberName=m_name)
157            elif _type_class in _UnionStructClass:
158                _showStructPacking(ctx, m_type, m_offset, outerSize=union_size, memberName=m_name)
159            else:
160                outstr = format_offset(m_offset, m_size)
161                if is_union and union_size != m_size_bits / 8:
162                    outstr += O.format("{VT.DarkRed}{{{:s}}}{VT.Default}",
163                            format_num(union_size - m_size_bits / 8))
164                if m_is_bitfield:
165                    outstr += O.format(" ({VT.DarkGreen}{:s} : {:s}{VT.Default}) {:s}",
166                            m_type.GetName(),
167                            format_num(m_size_bits),
168                            m_name)
169                else:
170                    outstr += O.format(" ({VT.DarkGreen}{:s}{VT.Default}) {:s}",
171                            m_type.GetName(), m_name)
172                print outstr
173
174        referenceSize = min(outerSize, sym_size) or sym_size
175        if not is_union and _packed_bit_offset < referenceSize * 8:
176            m_previous_offset = begin_offset + _packed_bit_offset / 8
177            m_hole_bits = referenceSize * 8 - _packed_bit_offset
178            if _packed_bit_offset % 8 == 0:
179                print O.format("{:s} ({VT.DarkRed}*** padding ***{VT.Default})",
180                        format_offset(m_previous_offset, m_hole_bits / 8))
181            else:
182                print O.format("{:s} ({VT.Brown}padding : {:s}{VT.Default})\n",
183                        format_offset(m_previous_offset, _previous_size),
184                        format_num(m_hole_bits))
185
186    print "}"
187
188@lldb_command('showstructpacking', "X" , fancy=True)
189def showStructInfo(cmd_args=None, cmd_options={}, O=None):
190    """ Show how a structure is packed in the binary.
191
192        Usage: showstructpacking [-X] <type name>
193            -X : prints struct members offsets and sizes in a hexadecimal format (decimal is default)
194
195        The format is:
196            <offset>, [<size_of_member>] (<type>) <name>
197
198        Example:
199            (lldb) showstructpacking pollfd
200                0,[   8] struct pollfd {
201                    0,[   4] (int) fd
202                    4,[   2] (short) events
203                    6,[   2] (short) revents
204                }
205    """
206    if not cmd_args:
207        raise ArgumentError("Please provide a type name.")
208
209    ty_name = cmd_args[0]
210    try:
211        sym = gettype(ty_name)
212    except NameError:
213        return O.error("Cannot find type named {0}", ty_name)
214
215    if sym.GetTypeClass() == lldb.eTypeClassTypedef:
216        sym = sym.GetCanonicalType()
217
218    if sym.GetTypeClass() not in _UnionStructClass:
219        return O.error("{0} is not a structure/union/class type", ty_name)
220
221    ctx = (O, "-X" in cmd_options)
222
223    _showStructPacking(ctx, sym, 0)
224
225# EndMacro: showstructinto
226