]>
Commit | Line | Data |
---|---|---|
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 |