X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/3903760236c30e3b5ace7a4eefac3a269d68957c..94ff46dc2849db4d43eaaf144872decc522aafb4:/tools/lldbmacros/structanalyze.py diff --git a/tools/lldbmacros/structanalyze.py b/tools/lldbmacros/structanalyze.py old mode 100644 new mode 100755 index 467e2018d..ba262e329 --- a/tools/lldbmacros/structanalyze.py +++ b/tools/lldbmacros/structanalyze.py @@ -1,84 +1,174 @@ import lldb from xnu import * -def _showStructPacking(symbol, prefix, begin_offset=0, typedef=None): - """ - recursively parse the field members of structure. - params : symbol (lldb.SBType) reference to symbol in binary - prefix (string) string to be prefixed for each line of output. Useful for recursive struct parsing. - returns: string containing lines of output. - """ - ctype = "unknown type" - if symbol.GetTypeClass() == lldb.eTypeClassUnion : - ctype = "union" - if symbol.GetTypeClass() == lldb.eTypeClassStruct : - ctype = "struct" - - if typedef: - outstr = "[%4d] (%s) (%s) %s { " % (symbol.GetByteSize(), typedef, ctype, symbol.GetName()) + "\n" - else : - outstr = "[%4d] (%s) %s { " % (symbol.GetByteSize(), ctype, symbol.GetName()) + "\n" - numFields = symbol.GetNumberOfFields() - _has_memory_hole = False - _compact_size = 0 # asuming the struct is perfectly packed - _compact_offset = begin_offset - _previous_bit_offset = 0 - for i in range(numFields): - member = symbol.GetFieldAtIndex(i) - m_offset = member.GetOffsetInBytes() + begin_offset - m_offset_bits = member.GetOffsetInBits() - m_type = member.GetType() - m_name = member.GetName() - m_size = m_type.GetByteSize() - warningstr = "" - debugstr = "" # + str((m_size, m_offset , m_offset_bits, _previous_bit_offset, _compact_offset, begin_offset)) - if _compact_offset != m_offset and (m_offset_bits - _previous_bit_offset) > m_size*8 : - _has_memory_hole = True - warningstr = " *** Possible memory hole ***" - _compact_offset = m_offset - _compact_offset += m_size - - _type_class = m_type.GetTypeClass() - _canonical_type = m_type.GetCanonicalType() - _canonical_type_class = m_type.GetCanonicalType().GetTypeClass() - - if _type_class == lldb.eTypeClassTypedef and (_canonical_type_class == lldb.eTypeClassStruct or _canonical_type_class == lldb.eTypeClassUnion) : - outstr += prefix + ("*%4d," % m_offset) + _showStructPacking(_canonical_type, prefix+" ", m_offset, str(m_type)) + warningstr + debugstr + "\n" - elif _type_class == lldb.eTypeClassStruct or _type_class == lldb.eTypeClassUnion : - outstr += prefix + ("*%4d," % m_offset) + _showStructPacking(m_type, prefix+" ", m_offset) + warningstr + debugstr + "\n" +_UnionStructClass = [ lldb.eTypeClassStruct, lldb.eTypeClassClass, lldb.eTypeClassUnion ] + +def _showStructPacking(O, symbol, begin_offset=0, symsize=0, typedef=None, outerSize=0, memberName=None): + """ + recursively parse the field members of structure. + params : O the output formatter (standard.py) + symbol (lldb.SBType) reference to symbol in binary + returns: string containing lines of output. + """ + ctype = "unknown type" + is_union = False + is_class = False + union_size = None + sym_size = symbol.GetByteSize() + + if symbol.GetTypeClass() == lldb.eTypeClassUnion: + ctype = "union" + is_union = True + union_size = sym_size + if symbol.GetTypeClass() == lldb.eTypeClassStruct: + ctype = "struct" + if symbol.GetTypeClass() == lldb.eTypeClassClass: + ctype = "class" + is_class = True + + if not outerSize or outerSize == sym_size: + outstr = O.format("{:04d},[{:4d}]", begin_offset, sym_size) + elif outerSize < sym_size: # happens with c++ inheritance + outstr = O.format("{:04d},[{:4d}]", begin_offset, outerSize) + else: + outstr = O.format("{:04d},[{:4d}]{VT.DarkRed}{{{:+d}}}{VT.Default}", + begin_offset, sym_size, outerSize - sym_size) + + if typedef: + outstr += O.format(" {0}", typedef) + if symbol.IsAnonymousType(): + outstr += O.format(" ({VT.DarkMagenta}anonymous {0}{VT.Default})", ctype) + else: + outstr += O.format(" ({VT.DarkMagenta}{0} {1}{VT.Default})", ctype, symbol.GetName()) + if memberName: + outstr += O.format(" {0} {{", memberName) else: - outstr += prefix + ("+%4d,[%4d] (%s) %s" % (m_offset, m_size, m_type.GetName(), m_name)) + warningstr + debugstr + "\n" - if i > 0 : - _previous_bit_offset = m_offset_bits - outstr += prefix + "}" - if _has_memory_hole == True : - outstr += " *** Warning: Struct layout leaves memory hole *** " - return outstr - -@lldb_command('showstructpacking') -def showStructInfo(cmd_args=None): - """Show how a structure is packed in the binary. The format is - +, [] () - For example: - (lldb) script lldbmacros.showStructInfo("pollfd") - [ 8] (struct) pollfd { - + 0,[ 4] (int) fd - + 4,[ 2] (short) events - + 6,[ 2] (short) revents - } - syntax: showstructpacking task - """ - if not cmd_args: - raise ArgumentError("Please provide a type name.") - - sym = gettype(cmd_args[0]) - if sym == None: - print "No such struct found" - if sym.GetTypeClass() == lldb.eTypeClassTypedef: - sym = sym.GetCanonicalType() - if sym.GetTypeClass() != lldb.eTypeClassStruct: - print "%s is not a structure" % cmd_args[0] - else: - print _showStructPacking(sym,"", 0) + outstr += ") {" + + print outstr + + with O.indent(): + _previous_size = 0 + _packed_bit_offset = 0 + _nfields = symbol.GetNumberOfFields() + + if is_class: + _next_offset_in_bits = 0 + _nclasses = symbol.GetNumberOfDirectBaseClasses() + + for i in range(_nclasses): + member = symbol.GetDirectBaseClassAtIndex(i) + if i < _nclasses - 1: + m_size_bits = symbol.GetDirectBaseClassAtIndex(i + 1).GetOffsetInBits() + elif _nfields: + m_size_bits = symbol.GetFieldAtIndex(0).GetOffsetInBits() + else: + m_size_bits = symbol.GetByteSize() * 8 + + m_offset = member.GetOffsetInBytes() + begin_offset + m_type = member.GetType() + m_name = member.GetName() + m_size = m_size_bits / 8 + + _previous_size = m_size + _packed_bit_offset = member.GetOffsetInBits() + m_size_bits + + _showStructPacking(O, m_type, m_offset, str(m_type), outerSize=m_size, memberName=m_name) + + for i in range(_nfields): + member = symbol.GetFieldAtIndex(i) + m_offset = member.GetOffsetInBytes() + begin_offset + m_offset_bits = member.GetOffsetInBits() + + m_type = member.GetType() + m_name = member.GetName() + m_size = m_type.GetByteSize() + + if member.IsBitfield(): + m_is_bitfield = True + m_size_bits = member.GetBitfieldSizeInBits() + else: + m_is_bitfield = False + m_size_bits = m_size * 8 + + if not is_union and _packed_bit_offset < m_offset_bits: + m_previous_offset = begin_offset + _packed_bit_offset / 8 + m_hole_bits = m_offset_bits - _packed_bit_offset + if _packed_bit_offset % 8 == 0: + print O.format("{:04d},[{:4d}] ({VT.DarkRed}*** padding ***{VT.Default})", + m_previous_offset, m_hole_bits / 8) + else: + print O.format("{:04d},[{:4d}] ({VT.Brown}*** padding : {:d} ***{VT.Default})", + m_previous_offset, _previous_size, m_hole_bits) + + _previous_size = m_size + _packed_bit_offset = m_offset_bits + m_size_bits + + _type_class = m_type.GetTypeClass() + _canonical_type = m_type.GetCanonicalType() + _canonical_type_class = m_type.GetCanonicalType().GetTypeClass() + + if _type_class == lldb.eTypeClassTypedef and _canonical_type_class in _UnionStructClass: + _showStructPacking(O, _canonical_type, m_offset, str(m_type), outerSize=union_size, memberName=m_name) + elif _type_class in _UnionStructClass: + _showStructPacking(O, m_type, m_offset, outerSize=union_size, memberName=m_name) + else: + outstr = O.format("{:04d},[{:4d}]", m_offset, m_size) + if is_union and union_size != m_size_bits / 8: + outstr += O.format("{VT.DarkRed}{{{:+d}}}{VT.Default}", + union_size - m_size_bits / 8) + if m_is_bitfield: + outstr += O.format(" ({VT.DarkGreen}{:s} : {:d}{VT.Default}) {:s}", + m_type.GetName(), m_size_bits, m_name) + else: + outstr += O.format(" ({VT.DarkGreen}{:s}{VT.Default}) {:s}", + m_type.GetName(), m_name) + print outstr + + referenceSize = min(outerSize, sym_size) or sym_size + if not is_union and _packed_bit_offset < referenceSize * 8: + m_previous_offset = begin_offset + _packed_bit_offset / 8 + m_hole_bits = referenceSize * 8 - _packed_bit_offset + offset = _packed_bit_offset / 8 + begin_offset + if _packed_bit_offset % 8 == 0: + print O.format("{:04d},[{:4d}] ({VT.DarkRed}*** padding ***{VT.Default})", + m_previous_offset, m_hole_bits / 8) + else: + print O.format("{:04d},[{:4d}] ({VT.Brown}padding : {:d}{VT.Default})\n", + m_previous_offset, _previous_size, m_hole_bits) + + print "}" + +@lldb_command('showstructpacking', fancy=True) +def showStructInfo(cmd_args=None, cmd_options={}, O=None): + """Show how a structure is packed in the binary. The format is + , [] () + + For example: + (lldb) showstructpacking pollfd + 0,[ 8] struct pollfd { + 0,[ 4] (int) fd + 4,[ 2] (short) events + 6,[ 2] (short) revents + } + + syntax: showstructpacking task + """ + if not cmd_args: + raise ArgumentError("Please provide a type name.") + + ty_name = cmd_args[0] + try: + sym = gettype(ty_name) + except NameError: + return O.error("Cannot find type named {0}", ty_name) + + if sym.GetTypeClass() == lldb.eTypeClassTypedef: + sym = sym.GetCanonicalType() + + if sym.GetTypeClass() not in _UnionStructClass: + return O.error("{0} is not a structure/union/class type", ty_name) + + _showStructPacking(O, sym, 0) # EndMacro: showstructinto