]> git.saurik.com Git - apple/xnu.git/blob - tools/lldbmacros/structanalyze.py
xnu-7195.101.1.tar.gz
[apple/xnu.git] / tools / lldbmacros / structanalyze.py
1 import lldb
2 from xnu import *
3
4 _UnionStructClass = [ lldb.eTypeClassStruct, lldb.eTypeClassClass, lldb.eTypeClassUnion ]
5
6 def _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
24 def _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
42 def _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)
189 def 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