Skip to content

Instantly share code, notes, and snippets.

@joevt
Last active September 12, 2024 06:51
Show Gist options
  • Save joevt/da0500cd574f00042f0db61f9af5512f to your computer and use it in GitHub Desktop.
Save joevt/da0500cd574f00042f0db61f9af5512f to your computer and use it in GitHub Desktop.

Revisions

  1. joevt revised this gist Sep 12, 2024. 1 changed file with 27 additions and 9 deletions.
    36 changes: 27 additions & 9 deletions joedwarftohpt.py
    Original file line number Diff line number Diff line change
    @@ -647,12 +647,10 @@ def GetBitSize(self):

    def UpdateBaseClassLists(self):
    if hasattr(self, "AT_virtuality"):
    if debug: dbgprint("UpdateBaseClassLists virtual base class %s" % self.parent.GetAddress())
    if debug: dbgprint("UpdateBaseClassLists virtual base class %s->:%08x: added to %s %s" % (self.GetAddress(), self.AT_type, self.parent.GetAddress(), self.parent.GetName()))
    if not hasattr(self.parent, "VirtualBaseClasses"):
    self.parent.VirtualBaseClasses = []
    self.parent.VirtualBaseClasses.append(self)
    #print("Adding virtual base class %s" % self.GetAddress())

    else:
    if debug: dbgprint("UpdateBaseClassLists direct base class %s" % self.parent.GetAddress())
    if not hasattr(self.parent, "DirectBaseClasses"):
    @@ -765,7 +763,7 @@ def MakeVTables(derivationPath, begin_offset=0):
    prefix = "%*s" % (4 * len(derivationPath), "")
    thefirst = derivationPath[0].DIE
    thelast = derivationPath[-1].DIE
    #print("%sMakeVTables offset:%d first:%s last:%s" % (prefix, begin_offset, thefirst.GetAddress(), thelast.GetAddress()))
    if debug: print("%sMakeVTables offset:%d first:%s last:%s" % (prefix, begin_offset, thefirst.GetAddress(), thelast.GetAddress()))

    # Does this class contain a vPtr?
    numFields = thelast.GetNumberOfFields()
    @@ -805,8 +803,8 @@ def MakeVTables(derivationPath, begin_offset=0):
    numClasses = thelast.GetNumberOfVirtualBaseClasses()
    for i in range(numClasses):
    member = thelast.GetVirtualBaseClassAtIndex(i)
    if debug: print("%s%d Checking virtual base class %s numv:%d" % (prefix, i, member.GetAddress(), len(thefirst.AllVirtualBaseClasses)))
    m_type = member.GetBaseType()
    if debug: print("%s%d/%d Checking virtual base class %s type:%s:%08x: numv:%d thefirst:%s" % (prefix, i, numClasses, member.GetAddress(), m_type.GetAddress(), m_type.address, len(thefirst.AllVirtualBaseClasses), thefirst.GetAddress()))

    if m_type.GetAddress() in thefirst.IncludedVirtualBaseClasses:

    @@ -844,12 +842,13 @@ def MakeVTables(derivationPath, begin_offset=0):
    virtualbaseclassinfo.offset = m_offset
    thefirst.AllVirtualBaseClasses.append(virtualbaseclassinfo)

    thefirst.IncludedVirtualBaseClasses[m_type.address] = virtualbaseclassinfo
    if debug: print("%sAdded %s to %s.IncludedVirtualBaseClasses" % (prefix, m_type.GetAddress(), thefirst.GetAddress()))
    thefirst.IncludedVirtualBaseClasses[m_type.GetAddress()] = virtualbaseclassinfo

    derivationPath.append(derivationItem)
    if debug: print("%s[ virtual 1st derived (%s) classoffset:0x%x baseclassoffset:0x%x member%s type%s" % (prefix, dumpderivationpath(derivationPath), begin_offset, m_offset, member.GetAddress(), m_type.GetAddress()))
    if debug: print("%s[ virtual 1st derived (%s) m_type.address:%08x: classoffset:0x%x baseclassoffset:0x%x member%s type%s" % (prefix, dumpderivationpath(derivationPath), m_type.address, begin_offset, m_offset, member.GetAddress(), m_type.GetAddress()))
    MakeVTables(derivationPath, m_offset)
    if debug: print("%s] virtual 1st derived (%s) classoffset:0x%x baseclassoffset:0x%x member%s type%s" % (prefix, dumpderivationpath(derivationPath), begin_offset, m_offset, member.GetAddress(), m_type.GetAddress()))
    if debug: print("%s] virtual 1st derived (%s) m_type.address:%08x: classoffset:0x%x baseclassoffset:0x%x member%s type%s" % (prefix, dumpderivationpath(derivationPath), m_type.address, begin_offset, m_offset, member.GetAddress(), m_type.GetAddress()))
    derivationPath.pop()

    if vPtrOffset != None:
    @@ -3263,7 +3262,7 @@ def DumpDIE(DIE, level):
    elif attr == "tag" : pass
    elif attr == "AT_decl_file" : pass

    elif attr == "DIELookup" or attr == "Fields" or attr == "VTables" or attr == "VTablesByOffset" or attr == "VTablesVirtual" or attr == "AllVirtualBaseClasses" or attr == "IncludedVirtualBaseClasses" or attr == "VTableEntries":
    elif attr == "DIELookup" or attr == "Fields" or attr == "VTables" or attr == "VTablesByOffset" or attr == "VTablesVirtual" or attr == "VTableEntries":
    dumpstr += (" %s:[%d]" % (attr, len(getattr(DIE, attr))))

    elif attr == "parent" or attr == "duplicateof" or attr == "methodClassDIE":
    @@ -3284,6 +3283,25 @@ def DumpDIE(DIE, level):
    thestr += "%s{%s}" % ("" if thestr == "" else ", ", theinheritance.GetType().GetAddress())
    dumpstr += (" %s:[%s]" % (attr, thestr))

    elif attr == "AllVirtualBaseClasses":
    thestr = ""
    for virtualbaseclassinfo in getattr(DIE, attr):
    member = virtualbaseclassinfo.member
    m_type = member.GetType()
    membertypename = m_type.GetName()
    thestr += "%s{%s}" % ("" if thestr == "" else ", ", membertypename)
    dumpstr += (" %s:[%s]" % (attr, thestr))

    elif attr == "IncludedVirtualBaseClasses":
    thestr = ""
    for address in getattr(DIE, attr):
    virtualbaseclassinfo = getattr(DIE, attr)[address]
    member = virtualbaseclassinfo.member
    m_type = member.GetType()
    membertypename = m_type.GetName()
    thestr += "%s{%s%s}" % ("" if thestr == "" else ", ", address, membertypename)
    dumpstr += (" %s:[%s]" % (attr, thestr))

    else : dumpstr += (" %s:«%s»" % (attr, value))
    dbgprint(dumpstr)
    if hasattr(DIE, "children"):
  2. joevt revised this gist Sep 8, 2024. 1 changed file with 139 additions and 139 deletions.
    278 changes: 139 additions & 139 deletions joedwarftohpt.py
    Original file line number Diff line number Diff line change
    @@ -278,7 +278,7 @@ class lldb(dict):


    #=========================================================================================
    arrtypeRE = re.compile('^(.*?)((?:\[[\]\[\d]*)?)$')
    arrtypeRE = re.compile(r'^(.*?)((?:\[[\]\[\d]*)?)$')

    #=========================================================================================
    class DIEDict(dict):
    @@ -434,15 +434,15 @@ def GetNameForType(self, forType):
    countstr += "[]"
    else:
    countstr += "[%d]" % count

    p = arrtypeRE.match(arrtype)
    if p:
    # handles array of array
    return p.group(1) + countstr + p.group(2)
    else:
    print("Error parsing type name for array %s %s" % (self.GetAddress(), arrtype))
    return arrtype + countstr


    elif self.tag == "TAG_subroutine_type" or self.tag == "TAG_subprogram":
    if self.HasType():
    @@ -514,7 +514,7 @@ def GetByteSizeForAlign0(self, forAlign, class_depth=0):
    m_align = m_type.GetAlign()
    if m_align > max_align:
    max_align = m_align

    return max_align

    if hasattr(self, "AT_byte_size"):
    @@ -600,7 +600,7 @@ def GetCompactSize(self, class_depth=0):

    if m_offset == None:
    m_offset = 0

    del self.GetCompactSizeFlag
    return m_offset
    return self.GetByteSize()
    @@ -668,7 +668,7 @@ def CheckName(self):
    return
    #print("Error: DIE (%s) blank name (%s)" % (self.GetAddress(), self.AT_name))
    del self.AT_name

    def SetName(self, AT_name):
    if hasattr(self, "AT_name") and self.AT_name != AT_name:
    print("Error: DIE (%s) name (%s) changed to (%s)" % (self.GetAddress(), self.AT_name, AT_name))
    @@ -706,7 +706,7 @@ def Settypenumber(self, typenumber):
    self.typenumber = typenumber
    self.dSYM.DIELookup[typenumber] = self
    if debug: dbgprint("Added to DIELookup «%s»" % (self.dSYM.DIELookup[typenumber].typenumber))

    def AppendChild(self, DIE):
    if not hasattr(self, "children"):
    self.children = []
    @@ -970,35 +970,35 @@ def MakeAllVTables(parent):

    #=========================================================================================
    class DSYM_Reader:
    compileUnitRE = re.compile('(0x[0-9a-f]+): Compile Unit: .* addr_size = (0x[0-9a-f]+) .*\n')
    tagRE = re.compile('(0x[0-9a-f]+):( +)(?:Unknown )?(?:DW_)?(TAG(?:_\w+| constant: 0x[0-9a-f]+)).*\n')
    nullRE = re.compile('(0x[0-9a-f]+): +(NULL)\n')
    blankRE = re.compile('\n')
    compileUnitRE = re.compile(r'(0x[0-9a-f]+): Compile Unit: .* addr_size = (0x[0-9a-f]+) .*\n')
    tagRE = re.compile(r'(0x[0-9a-f]+):( +)(?:Unknown )?(?:DW_)?(TAG(?:_\w+| constant: 0x[0-9a-f]+)).*\n')
    nullRE = re.compile(r'(0x[0-9a-f]+): +(NULL)\n')
    blankRE = re.compile(r'\n')

    AT_locationRE = re.compile(' +(.*?) *(\))?\n')
    AT_rangesRE = re.compile(' +(?:\[(0x[0-9a-f]+)(?: - |, )(0x[0-9a-f]+)\)(\)?))| *(End \))\n')
    AT_byte_sizeRE = re.compile(' +(?:\[(0x[0-9a-f]+)(?: - |, )(0x[0-9a-f]+)\)(?::?[^)\n]*)(\)?))| *(End \))\n')
    AT_locationRE = re.compile(r' +(.*?) *(\))?\n')
    AT_rangesRE = re.compile(r' +(?:\[(0x[0-9a-f]+)(?: - |, )(0x[0-9a-f]+)\)(\)?))| *(End \))\n')
    AT_byte_sizeRE = re.compile(r' +(?:\[(0x[0-9a-f]+)(?: - |, )(0x[0-9a-f]+)\)(?::?[^)\n]*)(\)?))| *(End \))\n')

    AT_REList = [
    re.compile(' +(?:DW_)?(AT_location)\t?\( *(0x[0-9a-f]+)(\n)'), # loop until ')\n' is found
    re.compile(' +(?:DW_)?(AT_ranges)\t?\( *(0x[0-9a-f]+)(\n)'), # loop until 'End )\n' is found
    re.compile(' +(?:DW_)?(AT_byte_size)\t?\( *(0x[0-9a-f]+):? *(\n)'), # loop until 'End )\n' is found
    re.compile(' +(?:DW_)?(AT_type)\t?\( *\{(0x[0-9a-f]+)\} \( .*? *\)\n'),
    re.compile(' +(?:DW_)?(AT_vtable_elem_location)\t?\( *<(0x[0-9a-f]+)> ([0-9a-f]{2}) ([0-9a-f]{2})(?: ([0-9a-f]{2})?)? *\)\n'),
    re.compile(' +(?:DW_)?(AT_vtable_elem_location)\t?\( *(?:DW_)?(OP_constu) (0x[0-9a-f]+) *\)\n'),
    re.compile(' +(?:DW_)?(AT_data_member_location)\t?\( *(?:DW_)?(OP_plus_uconst) (0x[0-9a-f]+) *\)\n'), # found this in 10.10.5_14F2511 kernel

    re.compile(' +(?:Unknown )?(?:DW_)?(AT(?:_\w+| constant: 0x[0-9a-f]+))\t?\( *\{(0x[0-9a-f]+)\}".*" *\)\n'),
    re.compile(' +(?:Unknown )?(?:DW_)?(AT(?:_\w+| constant: 0x[0-9a-f]+))\t?\( *\[(.*)\] *\)\n'),
    re.compile(' +(?:Unknown )?(?:DW_)?(AT(?:_\w+| constant: 0x[0-9a-f]+))\t?\( *\{(.*)\} *\)\n'),
    re.compile(' +(?:Unknown )?(?:DW_)?(AT(?:_\w+| constant: 0x[0-9a-f]+))\t?\( *"(.*)" *\)\n'),
    re.compile(' +(?:Unknown )?(?:DW_)?(AT(?:_\w+| constant: 0x[0-9a-f]+))\t?\( *(0x\w+) ".*" *\)\n'),
    re.compile(' +(?:Unknown )?(?:DW_)?(AT(?:_\w+| constant: 0x[0-9a-f]+))\t?\( *(.*) *\)\n'),
    re.compile(r' +(?:DW_)?(AT_location)\t?\( *(0x[0-9a-f]+)(\n)'), # loop until ')\n' is found
    re.compile(r' +(?:DW_)?(AT_ranges)\t?\( *(0x[0-9a-f]+)(\n)'), # loop until 'End )\n' is found
    re.compile(r' +(?:DW_)?(AT_byte_size)\t?\( *(0x[0-9a-f]+):? *(\n)'), # loop until 'End )\n' is found
    re.compile(r' +(?:DW_)?(AT_type)\t?\( *\{(0x[0-9a-f]+)\} \( .*? *\)\n'),
    re.compile(r' +(?:DW_)?(AT_vtable_elem_location)\t?\( *<(0x[0-9a-f]+)> ([0-9a-f]{2}) ([0-9a-f]{2})(?: ([0-9a-f]{2})?)? *\)\n'),
    re.compile(r' +(?:DW_)?(AT_vtable_elem_location)\t?\( *(?:DW_)?(OP_constu) (0x[0-9a-f]+) *\)\n'),
    re.compile(r' +(?:DW_)?(AT_data_member_location)\t?\( *(?:DW_)?(OP_plus_uconst) (0x[0-9a-f]+) *\)\n'), # found this in 10.10.5_14F2511 kernel

    re.compile(r' +(?:Unknown )?(?:DW_)?(AT(?:_\w+| constant: 0x[0-9a-f]+))\t?\( *\{(0x[0-9a-f]+)\}".*" *\)\n'),
    re.compile(r' +(?:Unknown )?(?:DW_)?(AT(?:_\w+| constant: 0x[0-9a-f]+))\t?\( *\[(.*)\] *\)\n'),
    re.compile(r' +(?:Unknown )?(?:DW_)?(AT(?:_\w+| constant: 0x[0-9a-f]+))\t?\( *\{(.*)\} *\)\n'),
    re.compile(r' +(?:Unknown )?(?:DW_)?(AT(?:_\w+| constant: 0x[0-9a-f]+))\t?\( *"(.*)" *\)\n'),
    re.compile(r' +(?:Unknown )?(?:DW_)?(AT(?:_\w+| constant: 0x[0-9a-f]+))\t?\( *(0x\w+) ".*" *\)\n'),
    re.compile(r' +(?:Unknown )?(?:DW_)?(AT(?:_\w+| constant: 0x[0-9a-f]+))\t?\( *(.*) *\)\n'),
    ]

    neghexRE = re.compile('^0x[8-9a-f][0-9a-f]{15} *$')
    hexRE = re.compile('^(0x[0-9a-f]+):? *$')
    decRE = re.compile('^[-+]?\d+ *$')
    neghexRE = re.compile(r'^0x[8-9a-f][0-9a-f]{15} *$')
    hexRE = re.compile(r'^(0x[0-9a-f]+):? *$')
    decRE = re.compile(r'^[-+]?\d+ *$')

    def ReadDIEList(self, f, parent):
    indent = None
    @@ -1010,7 +1010,7 @@ def ReadDIEList(self, f, parent):
    print("Error: unexpected list %s %s" % (parent.GetAddress(), parent.tag))
    for child in parent.children:
    print(" %s %s" % (child.GetAddress(), child.tag))

    unexpectedlist = True

    while True:
    @@ -1039,12 +1039,12 @@ def ReadDIEList(self, f, parent):

    if DIE.tag == "TAG_inheritance":
    DIE.UpdateBaseClassLists()

    elif DIE.tag == "TAG_friend":
    if not hasattr(DIE.parent, "Friends"):
    DIE.parent.Friends = []
    DIE.parent.Friends.append(DIE)

    elif hasattr(DIE, "AT_data_member_location") or hasattr(DIE, "AT_data_bit_offset"):
    if not hasattr(DIE.parent, "Fields"):
    DIE.parent.Fields = []
    @@ -1203,7 +1203,7 @@ def ReadNextDIE(self, f, dSYM):
    return DIE

    def Process_dSYM(self, filename):
    if re.match(".*\.txt", filename):
    if re.match(r'.*\.txt', filename):
    f = open(filename, "r")
    else:
    f = tempfile.NamedTemporaryFile()
    @@ -1400,7 +1400,7 @@ def Process_dSYM(self, filename):
    r{type-information};{lower-bound};{upper-bound}; The ‘r’ type descriptor defines a type as a subrange of another type. It is followed by type information for the type of which it is a subrange, a semicolon, an integral lower bound, a semicolon, an integral upper bound, and a semicolon. The AIX documentation does not specify the trailing semicolon, in an effort to specify array indexes more cleanly, but a subrange which is not an array index has always included a trailing semicolon (see Arrays).
    Instead of an integer, either bound can be one of the following:
    -
    -
    A{offset} - The bound is passed by reference on the stack at offset offset from the argument list. See Parameters, for more information on such offsets.
    T{offset} - The bound is passed by value on the stack at offset offset from the argument list.
    a{register-number} - The bound is passed by reference in register number register-number.
    @@ -1410,7 +1410,7 @@ def Process_dSYM(self, filename):
    Subranges are also used for builtin types; see Traditional Builtin Types.
    Array Types:
    Negative Type Numbers:
    @@ -1467,48 +1467,48 @@ def Process_dSYM(self, filename):
    #=========================================================================================

    class stab_Reader:
    stabRE = re.compile('\[ *(\d+)\] [0-9a-f]{8} ([0-9a-f]{2}) \( *(.+?) *\) ([0-9a-f]{2}) ([0-9a-f]{4}) ([0-9a-f]{16})(?: \'(.*)?\')?')
    stabRE = re.compile(r'\[ *(\d+)\] [0-9a-f]{8} ([0-9a-f]{2}) \( *(.+?) *\) ([0-9a-f]{2}) ([0-9a-f]{4}) ([0-9a-f]{16})(?: \'(.*)?\')?')

    dirpathRE = re.compile('(.*)/$')
    dirpathRE = re.compile(r'(.*)/$')

    stringRE = re.compile('((?:[^:\n]|::)*):((?:pF|pP|Tt|[a-zA-Z])?)(.*)') # \2\t\1\t\t\t\t\t\3

    typeRE = re.compile('(\(\d+,\d+\)|\d+)(=?)(.*)')
    negativeTypeRE = re.compile('(-\d+);(.*)')
    pointerRE = re.compile('([*&kB])(.*)')
    methodRE = re.compile('([#f])(.*)')
    parameterRE = re.compile('(;|,)(.*)')
    methodpropertiesRE = re.compile(':([^;]+);([0-2])([A-D])(?:(\?)|(\.)|(\*)(\d+))(.*)')
    stringRE = re.compile(r'((?:[^:\n]|::)*):((?:pF|pP|Tt|[a-zA-Z])?)(.*)') # \2\t\1\t\t\t\t\t\3

    attributeRE = re.compile('@(?:s(\d+);)(.*)')

    enumerationRE = re.compile('e(.*)')
    enumeratorRE = re.compile('(?:(;)|([^:]+):(-?\d+),)(.*)')
    typeRE = re.compile(r'(\(\d+,\d+\)|\d+)(=?)(.*)')
    negativeTypeRE = re.compile(r'(-\d+);(.*)')
    pointerRE = re.compile(r'([*&kB])(.*)')
    methodRE = re.compile(r'([#f])(.*)')
    parameterRE = re.compile(r'(;|,)(.*)')
    methodpropertiesRE = re.compile(r':([^;]+);([0-2])([A-D])(?:(\?)|(\.)|(\*)(\d+))(.*)')

    subrangeRE = re.compile('r(.*)')
    subrangeLimitsRE = re.compile(';(-?\d+);(-?\d+);(.*)')
    attributeRE = re.compile(r'@(?:s(\d+);)(.*)')

    arrayRE = re.compile('a(.*)')
    enumerationRE = re.compile(r'e(.*)')
    enumeratorRE = re.compile(r'(?:(;)|([^:]+):(-?\d+),)(.*)')

    crossReferenceRE = re.compile('x([sue])((?:::|\w|\$)+):(.*)')

    structRE = re.compile('([su])(\d+)(?:!(\d+),)?(.*)')
    baseclassRE = re.compile('(?:(;)|(\d)(\d)(\d+),)(.*)')
    subrangeRE = re.compile(r'r(.*)')
    subrangeLimitsRE = re.compile(r';(-?\d+);(-?\d+);(.*)')

    fieldnameRE = re.compile('(?:(;)|(?:([^:\n]*)(?:(?:(::)|(:))(?:/([0-2]))?)))(.*)')
    fieldlocationRE = re.compile('(?:(,)(\d+),(\d+)|:(\w+))(.*)')
    arrayRE = re.compile(r'a(.*)')

    methodEndRE = re.compile(';(.*)')
    fieldEndRE = re.compile(';(.*)')

    structContainingRE = re.compile("~%(.*)")
    structContainingEndRE = re.compile(';(.*)')
    crossReferenceRE = re.compile(r'x([sue])((?:::|\w|\$)+):(.*)')

    structRE = re.compile(r'([su])(\d+)(?:!(\d+),)?(.*)')
    baseclassRE = re.compile(r'(?:(;)|(\d)(\d)(\d+),)(.*)')

    fieldnameRE = re.compile(r'(?:(;)|(?:([^:\n]*)(?:(?:(::)|(:))(?:/([0-2]))?)))(.*)')
    fieldlocationRE = re.compile(r'(?:(,)(\d+),(\d+)|:(\w+))(.*)')

    methodEndRE = re.compile(r';(.*)')
    fieldEndRE = re.compile(r';(.*)')

    structContainingRE = re.compile(r"~%(.*)")
    structContainingEndRE = re.compile(r';(.*)')

    path = None
    currentfile = None
    addr_size = 4
    compilationUnitNumber = 0

    def makeDIE(self, parent, Index, tag):
    DIE = DIEDict()
    DIE.dSYM = parent.dSYM
    @@ -1526,7 +1526,7 @@ def makeDIE(self, parent, Index, tag):
    else:
    DIE.compile_unit = parent.dSYM.currentCompileUnit
    return DIE


    def parseStabType(self, leftDIE, parent, Index, tstr):
    p = self.typeRE.match(tstr)
    @@ -1565,7 +1565,7 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    leftDIE.SetName("void")
    else:
    leftDIE.AT_type = typenumber

    return DIE, remaining

    if leftDIE != None:
    @@ -1588,7 +1588,7 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    if p:
    leftDIE.SetTag("TAG_base_type")
    leftDIE.stabsbasetype = int(p.group(1), 10)
    if 1 == 0:
    if 1 == 0:
    pass
    #elif leftDIE.stabsbasetype == -1 : # int, 32 bit signed integral type.
    #elif leftDIE.stabsbasetype == -2 : # char, 8 bit type holding a character. Both GDB and dbx on AIX treat this as signed. GCC uses this type whether char is signed or not, which seems like a bad idea. The AIX compiler (xlc) seems to avoid this type; it uses -5 instead for char.
    @@ -1648,7 +1648,7 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    leftDIE.SetTag("TAG_volatile_type")
    if debug: dbgprint("} leftDIE %s" % leftDIE.tag)
    return None, remaining

    p = self.methodRE.match(remaining)
    if p:
    classDIE, remaining = self.parseStabType(None, parent, Index, p.group(2))
    @@ -1662,7 +1662,7 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    leftDIE.ismethod = 1
    leftDIE.methodClassDIE = classDIE
    leftDIE.SetTag("TAG_subprogram")

    #if not hasattr(classDIE, "pointerclasstypenumber"):
    # pointerclasstypenumber = ("* %s" % classDIE.typenumber)
    # pointerclassDIE = self.makeDIE(parent.parent, Index, "TAG_pointer_type")
    @@ -1717,10 +1717,10 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    leftDIE.AT_type = classDIE.typenumber
    leftDIE.SetTag("TAG_subroutine_type")
    if debug: dbgprint("} isstaticmethod")

    if debug: dbgprint("} leftDIE")
    return None, remaining

    p = self.enumerationRE.match(remaining)
    if p:
    leftDIE.SetTag("TAG_enumeration_type")
    @@ -1741,7 +1741,7 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    DIE.AT_const_value = int(q.group(3), 8)
    else:
    DIE.AT_const_value = int(q.group(3), 10)

    if hasattr(leftDIE, "enumsizemin"):
    if leftDIE.AT_byte_size <= 1 and DIE.AT_const_value >= -0x80 and DIE.AT_const_value <= 0x7f:
    leftDIE.AT_byte_size = 1
    @@ -1761,7 +1761,7 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    break
    if debug: dbgprint("} leftDIE")
    return None, remaining

    p = self.subrangeRE.match(remaining)
    if p:
    if debug: dbgprint("{ subrange type: [%d] «%s»" % (Index, p.group(1)))
    @@ -1776,7 +1776,7 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    leftDIE.selfReference = 1
    else:
    leftDIE.AT_type = typeDIE.typenumber

    boundsDIE = leftDIE

    # This block matches array sub range block below [
    @@ -1841,16 +1841,16 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    leftDIE.AT_byte_size = 4
    elif leftDIE.AT_upper_bound <= 0xffffffffffffffff:
    leftDIE.AT_byte_size = 8

    elif leftDIE.tag != "TAG_base_type":
    print("Error: Expected subrange type to be a base type: [%d] «%s»" % (Index, remaining))

    remaining = q.group(3)
    if debug: dbgprint("} subrange type")
    if debug: dbgprint("} leftDIE")
    return None, remaining
    # arrayRE = re.compile('a(.*)')

    # arrayRE = re.compile(r'a(.*)')
    p = self.arrayRE.match(remaining)
    if p:
    if debug: dbgprint("{ array type: [%d] «%s»" % (Index, p.group(1)))
    @@ -1903,9 +1903,9 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    boundsDIE.AT_count = boundsDIE.AT_upper_bound + 1
    del boundsDIE.AT_lower_bound
    del boundsDIE.AT_upper_bound

    remaining = q.group(3)

    typeDIE, remaining = self.parseStabType(None, parent, Index, remaining)
    if typeDIE == None:
    print("Error: Expected array element type: [%d] «%s»" % (Index, remaining))
    @@ -1924,7 +1924,7 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    if debug: dbgprint("} array type")
    if debug: dbgprint("} leftDIE")
    return None, remaining

    p = self.crossReferenceRE.match(remaining)
    if p:
    if debug: dbgprint("{ cross reference -- [%d] type:«%s» name:«%s» remaining:«%s»" % (Index, p.group(1), p.group(2), p.group(3)))
    @@ -1955,16 +1955,16 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    if debug: dbgprint("{ baseclasses")
    numBaseClasses = int(p.group(3), 10)
    numFoundBaseClasses = 0
    #baseclassRE = re.compile('(?:(;)|(\d)(\d)(\d+),)(.*)')

    #baseclassRE = re.compile(r'(?:(;)|(\d)(\d)(\d+),)(.*)')
    while True:
    if debug: dbgprint("{ baseclassRE")
    q = self.baseclassRE.match(remaining)
    if not q:
    print("Error: Expected base class: [%d] «%s»" % (Index, remaining))
    if debug: dbgprint("} baseclassRE break 1")
    break

    if q.group(1) == ";":
    remaining = q.group(5)
    if debug: dbgprint("} baseclassRE break 2")
    @@ -1995,26 +1995,26 @@ def parseStabType(self, leftDIE, parent, Index, tstr):

    typeDIE, remaining = self.parseStabType(None, leftDIE, Index, q.group(5))
    DIE.AT_type = typeDIE.typenumber

    if debug: dbgprint("{ UpdateBaseClassLists")
    DIE.UpdateBaseClassLists()
    if debug: dbgprint("} UpdateBaseClassLists")
    if debug: dbgprint("} baseclassRE")

    if numFoundBaseClasses > numBaseClasses:
    print("Error: Unexpected number of listed base classes: [%d] «%s» «%s»" % (Index, q.group2, remaining))
    if debug: dbgprint("} baseclasses")

    if debug: dbgprint("{ members")
    while True:
    if debug: dbgprint("{ member «%s»" % remaining)

    q = self.fieldnameRE.match(remaining)
    if not q:
    print("Error: Expected field name: [%d] «%s»" % (Index, remaining))
    if debug: dbgprint("} member error 1")
    break

    # 1 2 3 4 5 6
    # (?:(;)|(?:([^:\n]*)(?:(?:(::)|(:))(?:/([0-2]))?)))(.*)
    if debug: dbgprint("got field -- last:«%s» name:«%s» method:«%s» field:«%s» access:«%s» remaining:«%s»" % (q.group(1), q.group(2), q.group(3), q.group(4), q.group(5), q.group(6)))
    @@ -2035,7 +2035,7 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    print("Error: Expected type «%s»" % remaining)
    if debug: dbgprint("} method break 1")
    break

    DIE.tag = "TAG_subprogram"

    if debug: dbgprint("Duplicating: [%d] «%s»" % (Index, q.group(6)))
    @@ -2062,9 +2062,9 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    print("Error: Expected method properties: [%d] «%s»" % (Index, remaining))
    if debug: dbgprint("} method break 2")
    break

    if debug: dbgprint ("got method properties -- linkage:«%s» access:«%s» modifier«%s» static:«%s» method:«%s» virtual:«%s» location:«%s» remaining:«%s»" % (r.group(1), r.group(2), r.group(3), r.group(4), r.group(5), r.group(6), r.group(7), r.group(8)))

    DIE.AT_MIPS_linkage_name = r.group(1)
    if r.group(2) == "2":
    pass
    @@ -2073,7 +2073,7 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    DIE.AT_accessibility = "ACCESS_protected"
    elif r.group(2) == "0":
    DIE.AT_accessibility = "ACCESS_private"

    # method properties (static/method/virtual):
    if r.group(6) == "*" and hasattr(DIE, "ismethod"):
    DIE.AT_virtuality = "VIRTUALITY_virtual"
    @@ -2087,7 +2087,7 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    DIE.AT_containing_type = containingDIE.typenumber
    if containingDIE.typenumber != leftDIE.typenumber:
    print("Error: containing type «%s» ≠ struct type «%s»" % (containingDIE.typenumber, leftDIE.typenumber))

    s = self.methodEndRE.match(remaining)
    if not s:
    print("Error: Expected ; after virtual method containing type: [%d] «%s»" % (Index, remaining))
    @@ -2141,49 +2141,49 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    # constclassDIE = self.makeDIE(parent.parent, Index, "TAG_const_type")
    # constclassDIE.Settypenumber(constclasstypenumber)
    # constclassDIE.AT_type = classDIE.typenumber
    #
    #
    # pointerconstclasstypenumber = ("* %s" % constclassDIE.typenumber)
    # pointerconstclassDIE = self.makeDIE(parent.parent, Index, "TAG_pointer_type")
    # pointerconstclassDIE.Settypenumber(pointerconstclasstypenumber)
    # pointerconstclassDIE.AT_type = constclassDIE.typenumber
    # classDIE.pointerconstclasstypenumber = pointerconstclasstypenumber
    #
    #
    # DIE.artificalDIE.AT_type = classDIE.pointerconstclasstypenumber
    # elif r.group(3) == "C":
    # if not hasattr(leftDIE, "pointervolatileclasstypenumber"):
    # volatileclasstypenumber = ("v %s" % classDIE.typenumber)
    # volatileclassDIE = self.makeDIE(parent.parent, Index, "TAG_volatile_type")
    # volatileclassDIE.Settypenumber(volatileclasstypenumber)
    # volatileclassDIE.AT_type = classDIE.typenumber
    #
    #
    # pointervolatileclasstypenumber = ("* %s" % volatileclassDIE.typenumber)
    # pointervolatileclassDIE = self.makeDIE(parent.parent, Index, "TAG_pointer_type")
    # pointervolatileclassDIE.Settypenumber(pointervolatileclasstypenumber)
    # pointervolatileclassDIE.AT_type = volatileclassDIE.typenumber
    # classDIE.pointervolatileclasstypenumber = pointervolatileclasstypenumber
    #
    #
    # DIE.artificalDIE.AT_type = classDIE.pointervolatileclasstypenumber
    # elif r.group(3) == "D":
    # if not hasattr(leftDIE, "pointerconstvolatileclasstypenumber"):
    # volatileclasstypenumber = ("v %s" % classDIE.typenumber)
    # volatileclassDIE = self.makeDIE(parent.parent, Index, "TAG_volatile_type")
    # volatileclassDIE.Settypenumber(volatileclasstypenumber)
    # volatileclassDIE.AT_type = classDIE.typenumber
    #
    #
    # constvolatileclasstypenumber = ("c %s" % volatileclassDIE.typenumber)
    # constvolatileclassDIE = self.makeDIE(parent.parent, Index, "TAG_const_type")
    # constvolatileclassDIE.Settypenumber(constvolatileclasstypenumber)
    # constvolatileclassDIE.AT_type = volatileclassDIE.typenumber
    #
    #
    # pointerconstvolatileclasstypenumber = ("* %s" % constvolatileclassDIE.typenumber)
    # pointerconstvolatileclassDIE = self.makeDIE(parent.parent, Index, "TAG_pointer_type")
    # pointerconstvolatileclassDIE.Settypenumber(typenumber)
    # pointerconstvolatileclassDIE.AT_type = classDIE.typenumber
    # classDIE.pointerconstvolatileclasstypenumber = pointerconstvolatileclasstypenumber
    #
    #
    # DIE.artificalDIE.AT_type = classDIE.pointerconstvolatileclasstypenumber
    if debug: dbgprint("} method")

    elif q.group(4) == ":":
    if debug: dbgprint("{ field")
    DIE = self.makeDIE(leftDIE, Index, "TAG_member")
    @@ -2200,7 +2200,7 @@ def parseStabType(self, leftDIE, parent, Index, tstr):

    typeDIE, remaining = self.parseStabType(None, leftDIE, Index, q.group(6))
    DIE.AT_type = typeDIE.typenumber

    q = self.fieldlocationRE.match(remaining)
    if q:
    if q.group(1) == ",":
    @@ -2222,7 +2222,7 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    leftDIE.Fields.append(DIE)
    if hasattr(DIE, "AT_name") and "vptr$" in DIE.AT_name:
    DIE.AT_artificial = 1

    else: # == ":":
    # :{variable_name} for static members
    if debug: dbgprint("got static variable -- linkage:«%s» remaining:«%s»" % (q.group(4), remaining))
    @@ -2247,9 +2247,9 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    if debug: dbgprint("} member")

    if debug: dbgprint("} members")
    #structContainingRE = re.compile("~%(.*)")
    #structContainingEndRE = re.compile(';(.*)')

    #structContainingRE = re.compile(r"~%(.*)")
    #structContainingEndRE = re.compile(r';(.*)')

    s = self.structContainingRE.match(remaining)
    if s:
    @@ -2261,11 +2261,11 @@ def parseStabType(self, leftDIE, parent, Index, tstr):
    print("Error: Expected ; at end of containing class: [%d] «%s»" % (Index, remaining))
    #break
    remaining = t.group(1)

    if debug: dbgprint("} struct")
    if debug: dbgprint("} leftDIE")
    return None, remaining

    print("Error: Uknown type: [%d] «%s»" % (Index, tstr))
    return None, tstr

    @@ -2284,9 +2284,9 @@ def Readstabs(self, f, parent):
    n_value = int(s.group(6), 16)
    n_str = s.group(7)
    remaining = ""

    if n_type == 0x64: # N_SO

    if n_str == None:
    if parent.tag != "TAG_compile_unit":
    if parent.tag == "TAG_include" and parent.dSYM.currentCompileUnit.AT_name == parent.AT_name:
    @@ -2296,7 +2296,7 @@ def Readstabs(self, f, parent):
    print("Error: parent tag (%s) is not TAG_compile_unit: [%6d] %02x (%-13s) %02x %04x %16x '%s'" % (parent.tag, Index, n_type, n_type_str, n_sect, n_desc, n_value, n_str))
    parent.dSYM.popuntiltag = "TAG_compile_unit"
    break

    else:
    p = self.dirpathRE.match(n_str)
    if p:
    @@ -2312,7 +2312,7 @@ def Readstabs(self, f, parent):
    self.currentfile = n_str
    DIE.SetName(n_str)
    DIE.AT_comp_dir = self.path

    if n_desc == 0: pass
    elif n_desc == 0x1: DIE.AT_language = "N_SO_AS" # Assembly language
    elif n_desc == 0x2: DIE.AT_language = "N_SO_C" # K&R traditional C
    @@ -2322,7 +2322,7 @@ def Readstabs(self, f, parent):
    elif n_desc == 0x6: DIE.AT_language = "N_SO_PASCAL" # Pascal
    elif n_desc == 0x7: DIE.AT_language = "N_SO_FORTRAN90" # Fortran90
    elif n_desc == 0x32: DIE.AT_language = "N_SO_OBJC" # Objective-C
    elif n_desc == 0x33: DIE.AT_language = "N_SO_OBJCPLUS" # Objective-C++
    elif n_desc == 0x33: DIE.AT_language = "N_SO_OBJCPLUS" # Objective-C++
    else: print("Error: [%d] Unknown souce language %x" % (Index, n_desc))

    self.Readstabs(f, DIE)
    @@ -2338,15 +2338,15 @@ def Readstabs(self, f, parent):

    elif n_type == 0x84: # N_SOL
    self.currentfile = n_str

    elif n_type == 0x82: # N_BINCL
    DIE = self.makeDIE(parent, Index, "TAG_include") # fake dwarf tag
    savecurrentfile = self.currentfile
    self.currentfile = n_str
    DIE.AT_name = n_str
    self.Readstabs(f, DIE)
    self.currentfile = savecurrentfile

    elif n_type == 0xa2: # N_EINCL
    if parent.tag != "TAG_include":
    print("Error: parent tag (%s) is not TAG_include: [%6d] %02x (%-13s) %02x %04x %16x '%s'" % (parent.tag, Index, n_type, n_type_str, n_sect, n_desc, n_value, n_str))
    @@ -2360,18 +2360,18 @@ def Readstabs(self, f, parent):
    elif n_type == 0x2e: # N_BNSYM
    DIE = self.makeDIE(parent, Index, "TAG_symbol") # fake dwarf tag
    self.Readstabs(f, DIE)

    elif n_type == 0x4e: # N_ENSYM
    if parent.tag != "TAG_symbol":
    print("Error: parent tag (%s) is not TAG_symbol: [%6d] %02x (%-13s) %02x %04x %16x '%s'" % (parent.tag, Index, n_type, n_type_str, n_sect, n_desc, n_value, n_str))
    break

    elif n_type == 0x3c: # N_OPT
    if not hasattr(parent.dSYM, "currentCompileUnit"):
    print("Error: expected N_OPT to be inside an N_SO: [%d] %02x (%-13s) %02x %04x %16x '%s'" % (Index, n_type, n_type_str, n_sect, n_desc, n_value, n_str))
    else:
    parent.dSYM.currentCompileUnit.AT_producer = n_str

    elif n_type == 0x24: # N_FUN
    if n_str == None:
    if parent.tag != "TAG_subprogram":
    @@ -2415,9 +2415,9 @@ def Readstabs(self, f, parent):
    typeDIE = None
    if p.group(2) == "" or p.group(2) == "t" or p.group(2) == "T" or p.group(2) == "Tt":
    typeDIE, remaining = self.parseStabType(None, parent, Index, p.group(3))

    if debug: DumpDIE(typeDIE, 0)

    if p.group(2) != "":
    if not hasattr(typeDIE, "AT_name"):
    if debug: dbgprint("setting type «%s» name to «%s»" % (typeDIE.typenumber, p.group(1)))
    @@ -2483,7 +2483,7 @@ def Readstabs(self, f, parent):
    DIE.AT_type = typeDIE.typenumber
    else:
    DIE = typeDIE

    if DIE != None:
    if n_desc > 0:
    DIE.AT_decl_line = n_desc
    @@ -2525,7 +2525,7 @@ def Readstabs(self, f, parent):
    DIE = self.makeDIE(parent, Index, "TAG_variable")
    elif p.group(2) == "P":
    DIE = self.makeDIE(parent, Index, "TAG_formal_parameter")

    if DIE != None:
    DIE.SetName(p.group(1))
    DIE.AT_type = typeDIE.typenumber
    @@ -2613,10 +2613,10 @@ def Readstabs(self, f, parent):
    pass
    else:
    print("Error: Unknown stab type (0x%x = %s): [%6d] %02x (%-13s) %02x %04x %16x '%s'" % (n_type, n_type_str, Index, n_type, n_type_str, n_sect, n_desc, n_value, n_str))

    if remaining != "":
    print("Error: Unparsed stuff (%s): [%6d] %02x (%-13s) %02x %04x %16x '%s'" % (remaining, Index, n_type, n_type_str, n_sect, n_desc, n_value, n_str))

    else: # if s:
    #print("%s" % line)
    pass
    @@ -2654,7 +2654,7 @@ def CheckDIEs(self, parent):


    def Process_stab(self, filename):
    if re.match(".*\.txt", filename):
    if re.match(r'.*\.txt', filename):
    f = open(filename, "r")
    else:
    f = tempfile.NamedTemporaryFile()
    @@ -2730,9 +2730,9 @@ def _showStructPacking(symbol, typename, fieldname, prefix, depth, class_depth,
    ctype = "struct"
    else:
    ctype = "_unknown_%x" % (classType or 0)

    outstr = outstr + prefix + " friend %s %s\n" % (ctype, friendType.GetName() or "_anon_%x" % friendType.GetAddress())

    """
    Mac OS X 10.8:
    0x009fcff0: TAG_structure_type
    @@ -2752,7 +2752,7 @@ def _showStructPacking(symbol, typename, fieldname, prefix, depth, class_depth,
    0x00b675ca: TAG_friend
    AT_friend (0x00b67148)
    """

    _compact_offset = begin_offset
    max_union_member_size = 0
    max_align = 1
    @@ -2869,7 +2869,7 @@ def _showStructPacking(symbol, typename, fieldname, prefix, depth, class_depth,
    bitfield = " : %d // %d..%d,%d..%d" % (m_size_bits, bitFieldTotalBytes * 8 + m_offset_bits, bitFieldTotalBytes * 8 - 1, 0, m_size_bits + m_offset_bits - 1)
    else:
    bitfield = " : %d // %d..%d,nothing" % (m_size_bits, bitFieldTotalBytes * 8 + m_offset_bits, bitFieldTotalBytes * 8 - 1)

    else:
    bitFieldStartByte = m_offset
    bitFieldTotalBytes = m_size
    @@ -2926,7 +2926,7 @@ def _showStructPacking(symbol, typename, fieldname, prefix, depth, class_depth,
    if align_offset != m_offset :
    # ignore memory holes that may be caused by field alignment
    #_has_memory_hole = True

    if m_align == 8:
    align_offset4 = ((_compact_offset + 4-1) & -4)
    if align_offset4 == m_offset :
    @@ -2985,7 +2985,7 @@ def _showStructPacking(symbol, typename, fieldname, prefix, depth, class_depth,
    return outstr, _compact_offset - begin_offset, max_align


    vtableFunctionRE = re.compile("(.*?) \(\)\(/\*( const)? (.*?) \*,? \*/ ?(.*)\)")
    vtableFunctionRE = re.compile(r'(.*?) \(\)\(/\*( const)? (.*?) \*,? \*/ ?(.*)\)')
    # group(1) = function return type
    # group(2) = ' const'
    # group(3) = class from artificial parameter
    @@ -3089,7 +3089,7 @@ def DumpAllStructs(parent, names, level):
    if typedepth > 20:
    print("Error: type depth is too big «%s» «%s»" % (member.typenumber, member.GetName()))
    break

    if member.GetName() == membertypename:
    # don't do typedef if struct has same name, we'll do the struct when we get there
    member = None
    @@ -3277,13 +3277,13 @@ def DumpDIE(DIE, level):
    for thetype in getattr(DIE, attr):
    thestr += "%s{%s}" % ("" if thestr == "" else ", ", thetype.GetAddress())
    dumpstr += (" %s:[%s]" % (attr, thestr))

    elif attr == "DirectBaseClasses" or attr == "VirtualBaseClasses":
    thestr = ""
    for theinheritance in getattr(DIE, attr):
    thestr += "%s{%s}" % ("" if thestr == "" else ", ", theinheritance.GetType().GetAddress())
    dumpstr += (" %s:[%s]" % (attr, thestr))

    else : dumpstr += (" %s:«%s»" % (attr, value))
    dbgprint(dumpstr)
    if hasattr(DIE, "children"):
    @@ -3302,20 +3302,20 @@ def DumpDIE(DIE, level):

    dostab = False
    for i in range(1, len(sys.argv)):

    if sys.argv[i] == "-s":
    dostab = True
    else:
    print("==========================================================================================")
    print("The file: %s\n" % sys.argv[i])

    if dostab == True:
    stabr = stab_Reader()
    dSYM = stabr.Process_stab(sys.argv[i])
    else:
    dSYMr = DSYM_Reader()
    dSYM = dSYMr.Process_dSYM(sys.argv[i])

    if debug:
    print("==========================================================================================")
    DumpDIE(dSYM, 0)
  3. joevt revised this gist May 18, 2023. 1 changed file with 2095 additions and 408 deletions.
    2,503 changes: 2,095 additions & 408 deletions joedwarftohpt.py
    2,095 additions, 408 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
  4. joevt revised this gist Oct 31, 2022. 1 changed file with 8 additions and 8 deletions.
    16 changes: 8 additions & 8 deletions joedwarftohpt.py
    Original file line number Diff line number Diff line change
    @@ -216,7 +216,7 @@ def AddArray(self, DIE, name, attype):
    # Find multiple sub ranges examples:
    # ^0x\w+:([ ]+)TAG_subrange_type.*\n( +AT_.*\n)*\n0x\w+:\1TAG
    curType = attype
    for i in xrange(len(DIE.children) - 1, 0, -1):
    for i in range(len(DIE.children) - 1, 0, -1):
    child = DIE.children[i]
    if child.tag == "TAG_subrange_type":
    if hasattr(child, "AT_count"):
    @@ -764,7 +764,7 @@ def ReadNextDIE(self, f, dSYM):
    else:
    numbytes = int(m.group(2),16)
    thenum = 0
    for i in xrange(numbytes + 2, 3, -1):
    for i in range(numbytes + 2, 3, -1):
    part = int(m.group(i),16)
    if (i == numbytes + 2) == (part & 128 != 0):
    print("Error: unexpected high bit of elem location byte (%s) :%08x:" % (m.group(3), DIE.address))
    @@ -983,10 +983,10 @@ def MakeVTables(self, derivationPath, begin_offset=0):
    # Trying to build vtable of multiple inheritance is hard.
    # This is probably wrong - maybe check virtuality, and parameters, but then I might as well try to code a C++ compiler.
    # We'll just check the name.
    for k,w in baseClass.VTableEntries.iteritems():
    for k,w in iter(baseClass.VTableEntries.items()):
    namesuper = w.GetName()
    print("%s Looking for vtableitem %s" % (prefix, namesuper))
    for j,v1 in mergedVTableEntries.iteritems():
    for j,v1 in iter(mergedVTableEntries.items()):
    v = v1.DIE
    namebase = v.GetName()
    if (namesuper == namebase or (namesuper[:1] == "~" and namebase[:1] == "~")):
    @@ -1000,7 +1000,7 @@ def MakeVTables(self, derivationPath, begin_offset=0):
    break

    else:
    for j,v in baseClass.VTableEntries.iteritems():
    for j,v in iter(baseClass.VTableEntries.items()):
    namesuper = v.GetName()
    print("%s Adding vtableitem 0x%x %s" % (prefix, v.compile_unit.addr_size * j, namesuper))
    if j in mergedVTableEntries:
    @@ -1387,7 +1387,7 @@ def doOneVTable(symbol, prefix, vtableinfo):
    outstr = outstr + prefix + "vtable for %s {\n" % (symbol.GetName())
    else:
    outstr = outstr + prefix + "vtable for %s 0x%x {\n" % (symbol.GetName(), vtableinfo.vPtrOffset)
    for i in xrange(numEntries):
    for i in range(numEntries):
    if i in vtableinfo.mergedVTableEntries:
    vtableitem = vtableinfo.mergedVTableEntries[i]
    member = vtableitem.DIE
    @@ -1630,7 +1630,7 @@ def DumpAllTypes(Hopper, parent):
    sys.exit(1)

    H = Hopper()
    for i in xrange(1, len(sys.argv)):
    for i in range(1, len(sys.argv)):
    print("==========================================================================================")
    print("The file: %s\n" % sys.argv[i])

    @@ -1646,7 +1646,7 @@ def DumpAllTypes(Hopper, parent):
    pp.pprint(H.UUIDs)
    for k,v in H.UUIDs.items():
    pp.pprint(k)
    for attr, value in v.__dict__.iteritems():
    for attr, value in iter(v.__dict__.items()):
    print attr, value
    print
    '''
  5. joevt created this gist Mar 6, 2022.
    1,652 changes: 1,652 additions & 0 deletions joedwarftohpt.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,1652 @@
    #!/usr/bin/python
    # -*- coding: utf-8 -*-

    import sys
    import tempfile
    import subprocess
    import re
    import uuid
    import pprint
    #import lldb


    #=========================================================================================
    class Hopper(dict):

    BaseTypes = [
    # Base types that exist in Hopper:
    {"uuid":"054086d7b17b4685971643925db72c00", "name":"void" , "size":None , "preferred":False, "encoding":None },
    {"uuid":"054086d7b17b4685971643925db72c01", "name":"int8_t" , "size":1 , "preferred":True , "encoding":"DW_ATE_signed" },
    {"uuid":"054086d7b17b4685971643925db72c02", "name":"uint8_t" , "size":1 , "preferred":True , "encoding":"DW_ATE_unsigned" },
    {"uuid":"054086d7b17b4685971643925db72c03", "name":"int16_t" , "size":2 , "preferred":True , "encoding":"DW_ATE_signed" },
    {"uuid":"054086d7b17b4685971643925db72c04", "name":"uint16_t" , "size":2 , "preferred":True , "encoding":"DW_ATE_unsigned" },
    {"uuid":"054086d7b17b4685971643925db72c05", "name":"int32_t" , "size":4 , "preferred":True , "encoding":"DW_ATE_signed" },
    {"uuid":"054086d7b17b4685971643925db72c06", "name":"uint32_t" , "size":4 , "preferred":True , "encoding":"DW_ATE_unsigned" },
    {"uuid":"054086d7b17b4685971643925db72c07", "name":"int64_t" , "size":8 , "preferred":True , "encoding":"DW_ATE_signed" },
    {"uuid":"054086d7b17b4685971643925db72c08", "name":"uint64_t" , "size":8 , "preferred":True , "encoding":"DW_ATE_unsigned" },
    {"uuid":"054086d7b17b4685971643925db72c09", "name":"float" , "size":4 , "preferred":True , "encoding":"DW_ATE_float" },
    {"uuid":"054086d7b17b4685971643925db72c0a", "name":"double" , "size":8 , "preferred":True , "encoding":"DW_ATE_float" },
    {"uuid":"054086d7b17b4685971643925db72c0b", "name":"int" , "size":None , "preferred":False, "encoding":"DW_ATE_signed" },
    {"uuid":"054086d7b17b4685971643925db72c0c", "name":"unsigned int" , "size":None , "preferred":False, "encoding":"DW_ATE_unsigned" },
    {"uuid":"054086d7b17b4685971643925db72c0d", "name":"long" , "size":8 , "preferred":False, "encoding":"DW_ATE_signed" },
    {"uuid":"054086d7b17b4685971643925db72c0e", "name":"unsigned long" , "size":8 , "preferred":False, "encoding":"DW_ATE_unsigned" },
    {"uuid":"054086d7b17b4685971643925db72c0f", "name":"long long" , "size":8 , "preferred":False, "encoding":"DW_ATE_signed" },
    {"uuid":"054086d7b17b4685971643925db72c10", "name":"unsigned long long" , "size":8 , "preferred":False, "encoding":"DW_ATE_unsigned" },
    {"uuid":"054086d7b17b4685971643925db72c11", "name":"char" , "size":1 , "preferred":True , "encoding":"DW_ATE_signed_char" },
    {"uuid":"054086d7b17b4685971643925db72c12", "name":"short" , "size":2 , "preferred":False, "encoding":"DW_ATE_signed" },
    {"uuid":"054086d7b17b4685971643925db72c13", "name":"unsigned char" , "size":1 , "preferred":True , "encoding":"DW_ATE_unsigned_char"},
    {"uuid":"054086d7b17b4685971643925db72c14", "name":"unsigned short" , "size":2 , "preferred":False, "encoding":"DW_ATE_unsigned" },
    {"uuid":"054086d7b17b4685971643925db72c15", "name":"bool" , "size":1 , "preferred":True , "encoding":"DW_ATE_boolean" },

    # Base types that don't exist in Hopper with substitutes that exist in Hopper:
    {"uuid":"054086d7b17b4685971643925db72c04", "name":"char16_t" , "size":2 , "preferred":True , "encoding":"DW_ATE_UTF" },
    {"uuid":"054086d7b17b4685971643925db72c06", "name":"char32_t" , "size":4 , "preferred":True , "encoding":"DW_ATE_UTF" },

    # Base types that don't exist in Hopper:
    {"uuid":"054086d7b17b4685971643925db72e00", "name":"long double" , "size":16 , "preferred":True , "encoding":"DW_ATE_float" },
    ]

    class Type(dict):
    # Type : 16 byte type uuid, 4 byte len + name, 2 byte type
    TYPE_pointer = 0x0011 # type uuid
    TYPE_struct = 0x0012 # 4 byte numfields * { 4 byte len + name, type uuid, byte format, 4 byte len + comment } null
    TYPE_union = 0x0013 # 4 byte numUnions * { 4 byte len + name, type uuid, byte format, 4 byte null }
    TYPE_array = 0x0014 # 4 byte count, type uuid
    TYPE_typedef = 0x0015 # 4 byte len + name, type uuid
    TYPE_function = 0x001b # flag1 (ff), return type uuid, 2 byte numParams * {4 byte len + name, type uuid, byte format? }, ff=variadic, extra1 (6 null bytes), ff=no return, extra2 (0700=user input, or 0100=header import)
    TYPE_enumeration = 0x001c # extra1 (00=user enum, 04=built-in enums), 4 byte numEnums * { 4 byte len + name, 8 byte signed value }

    FORMAT_DEFAULT = 0
    FORMAT_HEXADECIMAL = 1
    FORMAT_DECIMAL = 2
    FORMAT_OCTAL = 3
    FORMAT_CHARACTER = 4
    FORMAT_STACKVARIABLE = 5
    FORMAT_OFFSET = 6
    FORMAT_ADDRESS = 7
    FORMAT_FLOAT = 8
    FORMAT_BINARY = 9

    FORMAT_STRUCTURED = 10
    FORMAT_ENUM = 11
    FORMAT_ADDRESS_DIFF=12

    FORMAT_NEGATE = 0x20
    FORMAT_LEADINGZEROES = 0x40
    FORMAT_SIGNED = 0x80

    Types = []
    UUIDs = {}


    def NewUUID(self, DIE):
    if hasattr(DIE, 'uuid'):
    print ("Error: uuid already created :0x%08x:" % DIE.address)
    else:
    if DIE.compile_unit.AT_comp_dir in DIE.compile_unit.AT_name:
    DIE.uuid = uuid.uuid5(uuid.NAMESPACE_URL, DIE.compile_unit.AT_name + (":0x%08x" % DIE.address))
    else:
    DIE.uuid = uuid.uuid5(uuid.NAMESPACE_URL, DIE.compile_unit.AT_comp_dir + DIE.compile_unit.AT_name + (":0x%08x" % DIE.address))
    if DIE.uuid in self.UUIDs:
    print ("Error: uuid collision :0x%08x:" % DIE.address)
    else:
    self.UUIDs[DIE.uuid] = DIE

    def AddType(self, name, typetype, DIE):
    type = self.Type()
    type.type = typetype
    type.DIE = DIE
    type.name = name
    type.DIE.type = type
    self.NewUUID(type.DIE)
    self.Types.append(type)
    return type


    def AddFunctionPointer(self, DIE, name, attype):
    # Find artifical
    # ^0x\w+: +TAG_formal_parameter.*\n( +AT_.*\n)* +AT_artificial.*\n( +AT_.*\n)*
    type = self.AddType(name, self.Type.TYPE_function, DIE)

    if attype.HasType():
    type.returntype = attype.GetType()
    else:
    type.returntype = None
    type.variadic = False
    type.params = []
    for child in attype.children:

    if child.tag == "TAG_formal_parameter":
    if child.HasType():
    if hasattr(child, "AT_artificial"):
    if hasattr(child, "AT_name"):
    type.params.append({"name":child.AT_name, "attype":child.GetType()})
    else:
    type.params.append({"name":"this", "attype":child.GetType()})
    elif hasattr(child, "AT_name"):
    type.params.append({"name":child.AT_name, "attype":child.GetType()})
    else:
    type.params.append({"name":None, "attype":child.GetType()})
    else:
    print("Error: unknown parameter type :0x%08x:" % child.address)
    elif child.tag == "TAG_unspecified_parameters":
    type.variadic = True
    else:
    print("Error: unknown parameter type :0x%08x:" % child.address)


    def AddPointerToMember(self, DIE, name, attype):
    # Find TAG_ptr_to_member_type
    # ^0x\w+: +TAG_ptr_to_member_type.*\n( +AT_.*\n)*
    type = self.AddType(name, self.Type.TYPE_struct, DIE)

    DIEf = DIEDict()
    DIEf.dSYM = DIE.dSYM
    DIEf.address = DIE.address+1
    DIEf.tag = "TAG_pointer_type"
    DIEf.attype = DIE.attype
    DIEf.compile_unit = DIE.compile_unit
    DIEf.dSYM.DIELookup[DIEf.address] = DIEf

    DIEc = DIEDict()
    DIEc.dSYM = DIE.dSYM
    DIEc.address = DIE.address+2
    DIEc.tag = "TAG_pointer_type"
    DIEc.attype = DIE.GetContainerType()
    DIEc.compile_unit = DIE.compile_unit
    DIEc.dSYM.DIELookup[DIEc.address] = DIEc

    AddFunctionPointer(DIEf, None, attype)
    AddPointer(DIEc, None, DIEc.attype)

    type.fields = [{"name":None, "attype":DIEf}, {"name":None, "attype":DIEc}]


    def AddPointer(self, DIE, name, attype):
    type = self.AddType(name, self.Type.TYPE_pointer, DIE)
    type.attype = attype


    def AddStruct(self, DIE, name, child):
    # Find multiple inheritance
    # 0x\w+: +TAG_inheritance.*\n( +AT_.*\n)*\n0x(\w+): +TAG_inheritance.*

    # Find bit fields
    # 0x\w+: +TAG_.*\n( +AT_.*\n)* +AT_\w*bit_offset.*\n( +AT_.*\n)*

    type = self.AddType(name, self.Type.TYPE_struct, DIE)
    type.fields = []




    def AddClass(self, DIE, name, child):
    type = self.AddType(name, self.Type.TYPE_struct, DIE)
    type.fields = []


    def AddTypedef(self, DIE, name, attype, atuuid):
    # attype is None for base type, use uuid instead
    type = self.AddType(name, self.Type.TYPE_typedef, DIE)
    type.attype = attype
    type.atuuid = uuid


    def AddBaseType(self, DIE):
    found = False
    for basetype in self.BaseTypes:
    #print(basetype)
    if basetype['name'] == DIE.AT_name and basetype['size'] == DIE.AT_byte_size and basetype['encoding'] == DIE.AT_encoding:
    found = True
    DIE.uuid = basetype['uuid']
    DIE.baseHopperType = True
    break
    if found == False:
    found = False
    for basetype in self.BaseTypes:
    if basetype['preferred'] == True and basetype['size'] == DIE.AT_byte_size and basetype['encoding'] == DIE.AT_encoding:
    found = True
    self.AddTypedef(DIE, DIE.AT_name, None, basetype['uuid'])
    break
    if found == False:
    print("Error: cannot find a base type :0x%08x:" % DIE.address)


    def AddArray(self, DIE, name, attype):
    # Find multiple sub ranges examples:
    # ^0x\w+:([ ]+)TAG_subrange_type.*\n( +AT_.*\n)*\n0x\w+:\1TAG
    curType = attype
    for i in xrange(len(DIE.children) - 1, 0, -1):
    child = DIE.children[i]
    if child.tag == "TAG_subrange_type":
    if hasattr(child, "AT_count"):
    if i == 0:
    type = self.AddType(name, self.Type.TYPE_aray, DIE)
    else:
    type = self.AddType(None, self.Type.TYPE_aray, child)
    type.attype = curType
    type.count = DIE.AT_count
    else:
    print ("Error getting count :0x%08x:" % child.address)
    else:
    print ("Error getting count :0x%08x:" % self.address)
    curType = child


    def AddEnumeration(self, DIE, name):
    # Find multiple enumerations examples:
    # ^0x\w+:([ ]+)TAG_enumerator.*\n( +AT_.*\n)*\n0x\w+:\1TAG
    type = self.AddType(name, self.Type.TYPE_enumeration, DIE)
    type.size = DIE.AT_byte_size
    type.enumerations = []
    for child in DIE.children:
    if child.tag == "TAG_enumerator":
    enumerations.append({"name":child.AT_name, "value":child.AT_const_value})
    else:
    print ("Error getting enumeration :0x%08x:" % child.address)


    def DumpHex(self):
    # create types for unknown base types such as "long double"

    # go through all Types and delete duplicates

    # go through all pointers, if pointer to hopper base type then replace pointer uuid with base type uuid
    # pointer with no type void *
    return


    #=========================================================================================
    class lldb(dict):
    eTypeClassClass = -1
    eTypeClassUnion = -2
    eTypeClassStruct = -3


    #=========================================================================================
    class DIEDict(dict):

    def GetOffsetInBytes(self):
    if hasattr(self, "AT_data_member_location"):
    if (self.AT_data_member_location.__class__.__name__ != "int"):
    print("Error in tag :%08x: %s (AT_data_member_location) containing value (%s)" % (self.address, self.tag, self.AT_data_member_location))
    return 0

    return self.AT_data_member_location
    if hasattr(self, "AT_data_bit_offset"):
    return self.AT_data_bit_offset >> 3
    return None

    def GetOffsetInBits(self):
    if hasattr(self, "AT_bit_offset"):
    return self.AT_bit_offset
    if hasattr(self, "AT_data_bit_offset"):
    return self.AT_data_bit_offset & 7
    return 0

    def GetClass(self):
    ctype = None
    if self.tag == "TAG_class_type":
    ctype = lldb.eTypeClassClass
    elif self.tag == "TAG_union_type":
    ctype = lldb.eTypeClassUnion
    elif self.tag == "TAG_structure_type":
    ctype = lldb.eTypeClassStruct
    return ctype


    def GetNumberOfDirectBaseClasses(self):
    if not hasattr(self, "DirectBaseClasses"):
    return 0
    return len(self.DirectBaseClasses)

    def GetDirectBaseClassAtIndex(self, i):
    return self.DirectBaseClasses[i]


    def GetNumberOfVirtualBaseClasses(self):
    if not hasattr(self, "VirtualBaseClasses"):
    return 0
    return len(self.VirtualBaseClasses)

    def GetVirtualBaseClassAtIndex(self, i):
    return self.VirtualBaseClasses[i]


    def GetNumberOfFields(self):
    if not hasattr(self, "Fields"):
    return 0
    return len(self.Fields)

    def GetFieldAtIndex(self, i):
    return self.Fields[i]


    def HasType(self):
    if hasattr(self, "AT_type"):
    return True
    return False


    def GetType(self):
    if self.HasType():
    return self.dSYM.DIELookup[self.AT_type]
    else:
    print("Error getting type :0x%08x:" % self.address)
    return None


    def GetBaseType(self):
    if self.HasType():
    result = self.GetType()
    if result.tag == "TAG_typedef":
    return result.GetBaseType()
    return result
    else:
    print("Error getting base type :0x%08x:" % self.address)
    return None


    def GetContainerType(self):
    if hasattr(self, "AT_containing_type"):
    return self.dSYM.DIELookup[self.AT_containing_type]
    else:
    print("Error getting conter type :0x%08x:" % self.address)
    return None


    def GetNameForType(self, forType):
    if not forType and hasattr(self, "AT_name"):
    return self.AT_name
    elif self.tag == "TAG_structure_type":
    return "(anonymous struct)"
    elif self.tag == "TAG_union_type":
    return "(anonymous union)"
    elif self.tag == "TAG_class_type":
    return "(anonymous class)"
    elif self.tag == "TAG_enumeration_type":
    return "(anonymous enum)"
    elif self.tag == "TAG_const_type":
    if self.HasType():
    return "const " + self.GetType().GetName()
    else:
    return "const void"
    elif self.tag == "TAG_volatile_type":
    if self.HasType():
    return "volatile " + self.GetType().GetName()
    else:
    return "volatile void"
    elif self.tag == "TAG_pointer_type":
    if self.HasType():
    result = self.GetType().GetName()
    if result[-1:] == "*":
    return result + "*"
    else:
    return result + " *"
    else:
    return "void *"
    elif self.tag == "TAG_reference_type":
    if self.HasType():
    return "&" + self.GetType().GetName()
    else:
    return "& void"
    elif self.tag == "TAG_ptr_to_member_type":
    if self.HasType():
    result = self.GetType().GetName()
    else:
    print("Error getting type :0x%08x:" % self.address)
    result = "void"

    if result[-1:] == "*":
    return result + "*"
    else:
    return result + " *"

    elif self.tag == "TAG_array_type":
    counts = self.GetCounts()

    if self.HasType():
    arrtype = self.GetType().GetName()
    else:
    print("Error getting type :0x%08x:" % self.address)
    arrtype = "void"

    countstr = ""
    for count in counts:
    if count == None:
    countstr += "[]"
    else:
    countstr += "[%d]" % count

    return arrtype + countstr

    elif self.tag == "TAG_subroutine_type" or self.tag == "TAG_subprogram":
    if self.HasType():
    returntype = self.GetType().GetName()
    else:
    returntype = "void"
    i = 0
    result = returntype + " ()("
    for child in self.children:
    i += 1
    if child.HasType():
    if hasattr(child, "AT_artificial"):
    if i < len(self.children):
    result += "/* " + child.GetType().GetName() + ", */ "
    else:
    result += "/* " + child.GetType().GetName() + " */"
    else:
    result += child.GetType().GetName()
    if i < len(self.children):
    result += ", "
    elif child.tag == "TAG_unspecified_parameters":
    result += "..."
    else:
    print("Error: unknown parameter type :0x%08x:" % self.address)
    result += ")"
    return result

    elif self.tag == "TAG_member":
    if self.GetType().GetClass() == lldb.eTypeClassUnion:
    return "" # unnamed union member
    else:
    print("Error getting name for :0x%08x: %s" % (self.address, self.tag))
    return ""


    def GetName(self):
    return self.GetNameForType(False)


    def GetByteSizeForAlign(self, forAlign, class_depth=0):
    if forAlign and (self.tag == "TAG_class_type" or self.tag == "TAG_structure_type" or self.tag == "TAG_union_type"):
    max_align = 1

    numClasses = self.GetNumberOfDirectBaseClasses()
    for i in range(numClasses):
    member = self.GetDirectBaseClassAtIndex(i)
    m_type = member.GetBaseType()
    m_align = m_type.GetAlign(class_depth+1)
    if m_align > max_align:
    max_align = m_align

    numFields = self.GetNumberOfFields()
    for i in range(numFields):
    member = self.GetFieldAtIndex(i)
    m_type = member.GetBaseType()
    m_align = m_type.GetAlign()
    if m_align > max_align:
    max_align = m_align

    if class_depth == 0 and hasattr(self, "AllVirtualBaseClasses"):
    for virtualbaseclassinfo in self.AllVirtualBaseClasses:
    member = virtualbaseclassinfo.member
    m_type = member.GetBaseType()
    m_align = m_type.GetAlign()
    if m_align > max_align:
    max_align = m_align

    return max_align

    if hasattr(self, "AT_byte_size"):
    if self.AT_byte_size == 1 and (self.tag == "TAG_class_type" or self.tag == "TAG_structure_type") and not hasattr(self, "Fields"):
    # classes have size 1 when they don't contain any fields
    return 0
    #print("byte size for :0x%08x: class_depth:%d forAlign:%d" % (self.address, class_depth, forAlign))
    return self.AT_byte_size

    if self.tag == "TAG_const_type":
    return self.GetType().GetByteSizeForAlign(forAlign)
    if self.tag == "TAG_volatile_type":
    return self.GetType().GetByteSizeForAlign(forAlign)
    if self.tag == "TAG_typedef":
    return self.GetType().GetByteSizeForAlign(forAlign)
    if self.tag == "TAG_pointer_type":
    return self.compile_unit.addr_size
    if self.tag == "TAG_ptr_to_member_type":
    return self.compile_unit.addr_size * 2

    if self.tag == "TAG_array_type":
    if forAlign:
    return self.GetType().GetAlign()
    size = self.GetType().GetByteSize()
    counts = self.GetCounts()
    for count in counts:
    if count == None:
    count = 1
    size *= count
    return size

    if self.HasType():
    if forAlign:
    return self.GetType().GetAlign()
    return self.GetType().GetByteSize()

    if hasattr(self, "AT_bit_size") and hasattr(self, "AT_data_bit_offset"):
    return (self.AT_data_bit_offset & 7 + self.AT_bit_size) >> 3

    print("Error getting byte size for :0x%08x: %s %s class_depth:%d forAlign:%d" % (self.address, self.tag, self.AT_name, class_depth, forAlign))
    return 0


    def GetByteSize(self):
    return self.GetByteSizeForAlign(False)


    def GetCompactSize(self, class_depth=0):
    # doesn't include virtual classes
    if self.tag == "TAG_class_type" or self.tag == "TAG_structure_type":
    m_offset = None
    numFields = self.GetNumberOfFields()
    if numFields > 0:
    member = self.GetFieldAtIndex(numFields-1)
    if hasattr(self, "AT_bit_size") and hasattr(self, "AT_data_bit_offset"):
    m_offset = (member.AT_data_bit_offset + member.AT_bit_size + 7) >> 3
    else:
    m_offset = member.GetOffsetInBytes() + member.GetByteSize()

    if m_offset == None:
    numClasses = self.GetNumberOfDirectBaseClasses()
    if numClasses > 0:
    member = self.GetDirectBaseClassAtIndex(numClasses - 1)
    m_type = member.GetBaseType()
    m_offset = member.GetOffsetInBytes() + member.GetCompactSize(class_depth + 1)

    if m_offset == None:
    m_offset = 0
    return m_offset
    return self.GetByteSize()


    def GetAlign(self, class_detph=0):
    m_size = self.GetByteSizeForAlign(True, class_detph)
    if m_size >= 8:
    m_align = 8
    elif m_size >= 4:
    m_align = 4
    elif m_size >= 2:
    m_align = 2
    else:
    m_align = 1
    return m_align


    def GetCounts(self):
    counts = []
    for child in self.children:
    if child.tag == "TAG_subrange_type":
    if hasattr(child, "AT_count"):
    counts.append(child.AT_count)
    else:
    counts.append(None)
    else:
    print ("Error getting count :0x%08x:" % self.address)
    return counts


    def GetBitSize(self):
    if hasattr(self, "AT_bit_size"):
    return self.AT_bit_size
    else:
    return self.GetByteSize() * 8

    #=========================================================================================
    class VTableInfo(dict):
    pass

    class VTableItem(dict):
    pass

    class DerivationItem(dict):
    pass

    class VirtualBaseClassInfo(dict):
    pass

    #=========================================================================================
    class DSYM_Reader:
    compileUnitRE = re.compile('(0x[0-9a-f]+): Compile Unit: .* addr_size = (0x[0-9a-f]+) .*\n')
    tagRE = re.compile('(0x[0-9a-f]+):( +)(?:Unknown )?(?:DW_)?(TAG(?:_\w+| constant: 0x[0-9a-f]+)).*\n')
    nullRE = re.compile('(0x[0-9a-f]+): +(NULL)\n')
    blankRE = re.compile('\n')

    AT_locationRE = re.compile(' +(.*?) *(\))?\n')
    AT_rangesRE = re.compile(' +(?:\[(0x[0-9a-f]+)(?: - |, )(0x[0-9a-f]+)\)(\)?))| *(End \))\n')
    AT_byte_sizeRE = re.compile(' +(?:\[(0x[0-9a-f]+)(?: - |, )(0x[0-9a-f]+)\)(?::?[^)\n]*)(\)?))| *(End \))\n')

    AT_REList = [
    re.compile(' +(?:DW_)?(AT_location)\t?\( *(0x[0-9a-f]+)(\n)'), # loop until ')\n' is found
    re.compile(' +(?:DW_)?(AT_ranges)\t?\( *(0x[0-9a-f]+)(\n)'), # loop until 'End )\n' is found
    re.compile(' +(?:DW_)?(AT_byte_size)\t?\( *(0x[0-9a-f]+):? *(\n)'), # loop until 'End )\n' is found
    re.compile(' +(?:DW_)?(AT_type)\t?\( *\{(0x[0-9a-f]+)\} \( .*? *\)\n'),
    re.compile(' +(?:DW_)?(AT_vtable_elem_location)\t?\( *<(0x[0-9a-f]+)> ([0-9a-f]{2}) ([0-9a-f]{2})(?: ([0-9a-f]{2})?)? *\)\n'),
    re.compile(' +(?:DW_)?(AT_vtable_elem_location)\t?\( *(?:DW_)?(OP_constu) (0x[0-9a-f]+) *\)\n'),
    re.compile(' +(?:DW_)?(AT_data_member_location)\t?\( *(?:DW_)?(OP_plus_uconst) (0x[0-9a-f]+) *\)\n'), # found this in 10.10.5_14F2511 kernel

    re.compile(' +(?:Unknown )?(?:DW_)?(AT(?:_\w+| constant: 0x[0-9a-f]+))\t?\( *\{(0x[0-9a-f]+)\}".*" *\)\n'),
    re.compile(' +(?:Unknown )?(?:DW_)?(AT(?:_\w+| constant: 0x[0-9a-f]+))\t?\( *\[(.*)\] *\)\n'),
    re.compile(' +(?:Unknown )?(?:DW_)?(AT(?:_\w+| constant: 0x[0-9a-f]+))\t?\( *\{(.*)\} *\)\n'),
    re.compile(' +(?:Unknown )?(?:DW_)?(AT(?:_\w+| constant: 0x[0-9a-f]+))\t?\( *"(.*)" *\)\n'),
    re.compile(' +(?:Unknown )?(?:DW_)?(AT(?:_\w+| constant: 0x[0-9a-f]+))\t?\( *(0x\w+) ".*" *\)\n'),
    re.compile(' +(?:Unknown )?(?:DW_)?(AT(?:_\w+| constant: 0x[0-9a-f]+))\t?\( *(.*) *\)\n'),
    ]

    neghexRE = re.compile('^0x[8-9a-f][0-9a-f]{15} *$')
    hexRE = re.compile('^(0x[0-9a-f]+):? *$')
    decRE = re.compile('^[-+]?\d+ *$')

    def ReadDIEList(self, f, parent, dSYM):
    indent = None
    unexpectedlist = False
    if len(parent.children) == 1:
    indent = parent.children[0].indent
    elif len(parent.children) != 0:
    print("Error: unexpected list:0x%08x %s" % (parent.address, parent.tag))
    for child in parent.children:
    print(" :0x%08x %s" % (child.address, child.tag))

    unexpectedlist = True

    while True:
    DIE = self.ReadNextDIE(f, dSYM)
    if DIE == None:
    break

    if unexpectedlist:
    print("Error: first item of unexpected list %s :0x%08x" % (DIE.tag, DIE.address))
    unexpectedlist = False

    if indent == None:
    indent = DIE.indent

    if DIE.indent > indent:
    # indent increased, this record is the first child of the last added record
    #print("{ %d" % DIE.indent)
    DIE.parent = parent.children[-1]
    DIE.parent.children.append(DIE)
    elif DIE.indent < indent:
    print("Error: indentation")
    break
    else:
    DIE.parent = parent
    parent.children.append(DIE)

    if DIE.tag == "TAG_inheritance":
    if hasattr(DIE, "AT_virtuality"):
    if not hasattr(DIE.parent, "VirtualBaseClasses"):
    DIE.parent.VirtualBaseClasses = []
    DIE.parent.VirtualBaseClasses.append(DIE)
    #print("Adding virtual base class :0x%08x:" % DIE.address)

    else:
    if not hasattr(DIE.parent, "DirectBaseClasses"):
    DIE.parent.DirectBaseClasses = []
    DIE.parent.DirectBaseClasses.append(DIE)

    elif DIE.tag == "TAG_friend":
    if not hasattr(DIE.parent, "Friends"):
    DIE.parent.Friends = []
    DIE.parent.Friends.append(DIE)

    elif hasattr(DIE, "AT_data_member_location") or hasattr(DIE, "AT_data_bit_offset"):
    if not hasattr(DIE.parent, "Fields"):
    DIE.parent.Fields = []
    DIE.parent.Fields.append(DIE)
    elif hasattr(DIE, "AT_vtable_elem_location"):
    if not hasattr(DIE.parent, "VTableEntries"):
    DIE.parent.VTableEntries = {}
    if DIE.AT_vtable_elem_location in DIE.parent.VTableEntries:
    nameold = DIE.parent.VTableEntries[DIE.AT_vtable_elem_location].GetName()
    namenew = DIE.GetName()
    print("Error: duplicate VTableEntries 0x%x %s %s" % (DIE.AT_vtable_elem_location * DIE.compile_unit.addr_size, nameold, namenew))
    # workaround problem for Mammal and WingedAnimal examples
    if DIE.AT_vtable_elem_location == 0 and namenew[:1] == "~" and not nameold[:1] == "~" and not 1 in DIE.parent.VTableEntries:
    DIE.parent.VTableEntries[1] = DIE
    else:
    DIE.parent.VTableEntries[DIE.AT_vtable_elem_location] = DIE

    if DIE.indent > indent:
    self.ReadDIEList(f, DIE.parent, dSYM)
    #print("} %d" % DIE.indent)


    def ReadNextDIE(self, f, dSYM):
    DIE = None
    for line in f:
    #print (line)
    if self.nullRE.match(line):
    break
    c = self.compileUnitRE.match(line)
    if c:
    addr_size = int(c.group(2), 16)
    continue

    t = self.tagRE.match(line)
    if t:
    DIE = DIEDict()
    DIE.dSYM = dSYM
    DIE.address = int(t.group(1), 16)
    DIE.indent = len(t.group(2))
    #print("indent: %d" % DIE.indent)
    DIE.tag = t.group(3)
    DIE.children = []
    #print("Added DIE :%08x:" % DIE.address)

    for line in f:
    if self.blankRE.match(line):
    break
    for atRE in self.AT_REList:
    m = atRE.match(line)
    if m:
    if atRE.groups == 2:
    if m.group(1) == "AT_bit_offset" and self.neghexRE.match(m.group(2)):
    DIE.AT_bit_offset = -int(2**64 - int(m.group(2),16))
    else:
    m2 = self.hexRE.match(m.group(2))
    if m2:
    setattr(DIE, m.group(1), int(m2.group(1), 16))
    elif self.decRE.match(m.group(2)):
    setattr(DIE, m.group(1), int(m.group(2), 10))
    else:
    setattr(DIE, m.group(1), m.group(2))

    # the rest of these have more than 2 capture groups (sometimes the third capture group
    # is the linefeed just so we can do the following special processing)
    elif m.group(1) == "AT_data_member_location":
    if m.group(2) == "OP_plus_uconst":
    thenum = int(m.group(3),16)
    DIE.AT_data_member_location = thenum

    elif m.group(1) == "AT_vtable_elem_location":
    #print ("AT_vtable_elem_location «%s•%s•%s»" % (m.group(1), m.group(2), m.group(3)))
    if m.group(2) == "OP_constu":
    thenum = int(m.group(3),16)
    else:
    numbytes = int(m.group(2),16)
    thenum = 0
    for i in xrange(numbytes + 2, 3, -1):
    part = int(m.group(i),16)
    if (i == numbytes + 2) == (part & 128 != 0):
    print("Error: unexpected high bit of elem location byte (%s) :%08x:" % (m.group(3), DIE.address))
    thenum = thenum * 128 + (part & 127)
    if m.group(3) != "10":
    print("Error: unexpected elem location type (%s) :%08x:" % (m.group(3), DIE.address))
    DIE.AT_vtable_elem_location = thenum

    elif m.group(1) == "AT_location":
    setattr(DIE, m.group(1), int(m.group(2), 16))
    lines = []
    for line in f:
    m = self.AT_locationRE.match(line)
    if m:
    lines.append(m.group(1))
    #print ("AT_location «%s•%s»" % (m.group(1), m.group(2)))
    if m.group(2) == ")":
    break # AT_location_list finished with error
    else:
    print("Error in tag :%08x: (AT_location) with line %s" % (DIE.address, line))
    break # AT_location_list finished with error
    DIE.AT_location_list = lines

    elif m.group(1) == "AT_ranges":
    DIE.AT_ranges = int(m.group(2), 16)
    lines = []
    for line in f:
    m = self.AT_rangesRE.match(line)
    if m:
    #print ("«%s•%s•%s•%s»" % (m.group(1), m.group(2), m.group(3), m.group(4)))
    if m.group(4) == 'End )':
    break # AT_ranges_list finished
    lines.append([m.group(1), m.group(2)])
    if m.group(3) == ')':
    break # AT_ranges_list finished
    else:
    print("Error in tag :%08x: (AT_ranges_list) with line %s" % (DIE.address, line))
    break # AT_ranges_list finished with error
    DIE.AT_ranges_list = lines

    elif m.group(1) == "AT_byte_size":
    DIE.AT_byte_size = int(m.group(2), 16)
    lines = []
    for line in f:
    m = self.AT_byte_sizeRE.match(line)
    if m:
    #print ("«%s•%s•%s•%s»" % (m.group(1), m.group(2), m.group(3), m.group(4)))
    if m.group(4) == 'End )':
    break # AT_byte_size_list finished
    lines.append([m.group(1), m.group(2)])
    if m.group(3) == ')':
    break # AT_byte_size_list finished
    else:
    print("Error in tag :%08x: (AT_byte_size_list) with line %s" % (DIE.address, line))
    break # AT_byte_size_list finished with error
    DIE.AT_byte_size_list = lines

    else:
    print("Error in tag :%08x: with line %s" % (DIE.address, line))

    break # AT_ created

    dSYM.DIELookup[DIE.address] = DIE

    if DIE.tag == "TAG_compile_unit":
    dSYM.CompileUnits.append(DIE)
    dSYM.currentCompileUnit = DIE
    DIE.addr_size = addr_size
    else:
    DIE.compile_unit = dSYM.currentCompileUnit

    break # DIE created
    return DIE


    def CheckVTables(self, msg, parent):
    # for every class or structure, make a list of vtables (more than one vtable exists for multiple inheritance)
    for child in parent.children:
    numClasses = child.GetNumberOfVirtualBaseClasses()
    for i in range(numClasses):
    member = child.GetVirtualBaseClassAtIndex(i)
    print("%d :0x%08x: Got virtual base class :0x%08x: %s" % (i, child.address, member.address, msg))
    m_type = member.GetBaseType()
    self.CheckVTables(msg, child)


    def dumpderivationpath(self, derivationPath):
    s = ""
    for derivationItem in derivationPath:
    baseClass = derivationItem.DIE
    if len(s) > 0:
    s += ","
    if derivationItem.isvirtual:
    v = "virtual "
    else:
    v = ""
    s += "%d:%s%s" % (derivationItem.index, v, baseClass.GetName())
    return s


    def MakeVTables(self, derivationPath, begin_offset=0):
    prefix = "%*s" %(4 * len(derivationPath), "")
    thefirst = derivationPath[0].DIE
    thelast = derivationPath[-1].DIE

    # Does this class contain a vPtr?
    numFields = thelast.GetNumberOfFields()
    vPtrOffset = None
    for i in range(numFields):
    member = thelast.GetFieldAtIndex(i)

    thename = member.GetName()
    if thename != None and "vptr" in thename and hasattr(member, "AT_artificial"):
    vPtrOffset = member.GetOffsetInBytes() + begin_offset
    print("%sfound vptr (%s) classoffset:0x%x vptroffset:0x%x" % (prefix, self.dumpderivationpath(derivationPath), begin_offset, vPtrOffset))
    break

    if vPtrOffset == None:
    # No vPtr exists, follow base classes
    numClasses = thelast.GetNumberOfDirectBaseClasses()
    for i in range(numClasses):
    member = thelast.GetDirectBaseClassAtIndex(i)
    m_offset = member.GetOffsetInBytes() + begin_offset
    m_type = member.GetBaseType()

    derivationItem = DerivationItem()
    derivationItem.DIE = m_type
    derivationItem.index = i
    derivationItem.isvirtual = False
    derivationItem.VTables = thefirst.VTables
    derivationItem.derivationPathText = derivationPath[-1].derivationPathText + "%02d" % (i + 1)

    derivationPath.append(derivationItem)
    print("%s[ derived (%s) classoffset:0x%x baseclassoffset:0x%x" % (prefix, self.dumpderivationpath(derivationPath), begin_offset, m_offset))
    self.MakeVTables(derivationPath, m_offset)
    print("%s] derived (%s) classoffset:0x%x baseclassoffset:0x%x" % (prefix, self.dumpderivationpath(derivationPath), begin_offset, m_offset))
    derivationPath.pop()

    numClasses = thelast.GetNumberOfVirtualBaseClasses()
    for i in range(numClasses):
    member = thelast.GetVirtualBaseClassAtIndex(i)
    print("%s%d Checking virtual base class :0x%08x: numv:%d" % (prefix, i, member.address, len(thefirst.AllVirtualBaseClasses)))
    m_type = member.GetBaseType()

    if m_type.address in thefirst.IncludedVirtualBaseClasses:

    virtualbaseclassinfo = thefirst.IncludedVirtualBaseClasses[m_type.address]
    m_offset = virtualbaseclassinfo.offset

    derivationItem = DerivationItem()
    derivationItem.DIE = m_type
    derivationItem.index = 0
    derivationItem.isvirtual = True
    derivationItem.VTables = thefirst.VTablesVirtual
    derivationItem.derivationPathText = derivationPath[-1].derivationPathText + "%02d" % (i + 31)

    derivationPath.append(derivationItem)
    print("%s[ virtual 2nd derived (%s) classoffset:0x%x baseclassoffset:0x%x member:%08x: type:%08x:" % (prefix, self.dumpderivationpath(derivationPath), begin_offset, m_offset, member.address, m_type.address))
    self.MakeVTables(derivationPath, m_offset)
    print("%s] virtual 2nd derived (%s) classoffset:0x%x baseclassoffset:0x%x member:%08x: type:%08x:" % (prefix, self.dumpderivationpath(derivationPath), begin_offset, m_offset, member.address, m_type.address))
    derivationPath.pop()

    else:
    m_offset = thefirst.VirtualBaseClassOffset
    m_align = m_type.GetAlign()
    m_offset = ((m_offset + m_align-1) & -m_align)
    thefirst.VirtualBaseClassOffset += m_type.GetByteSize()

    derivationItem = DerivationItem()
    derivationItem.DIE = m_type
    derivationItem.index = 0
    derivationItem.isvirtual = True
    derivationItem.VTables = thefirst.VTablesVirtual
    derivationItem.derivationPathText = derivationPath[-1].derivationPathText + "%02d" % (i + 61)

    virtualbaseclassinfo = VirtualBaseClassInfo()
    virtualbaseclassinfo.member = member
    virtualbaseclassinfo.offset = m_offset
    thefirst.AllVirtualBaseClasses.append(virtualbaseclassinfo)

    thefirst.IncludedVirtualBaseClasses[m_type.address] = virtualbaseclassinfo

    derivationPath.append(derivationItem)
    print("%s[ virtual 1st derived (%s) classoffset:0x%x baseclassoffset:0x%x member:%08x: type:%08x:" % (prefix, self.dumpderivationpath(derivationPath), begin_offset, m_offset, member.address, m_type.address))
    self.MakeVTables(derivationPath, m_offset)
    print("%s] virtual 1st derived (%s) classoffset:0x%x baseclassoffset:0x%x member:%08x: type:%08x:" % (prefix, self.dumpderivationpath(derivationPath), begin_offset, m_offset, member.address, m_type.address))
    derivationPath.pop()

    if vPtrOffset != None:
    # A vPtr exists, make a vtable for it.

    if vPtrOffset in thefirst.VTablesByOffset:
    vtableinfo = thefirst.VTablesByOffset[vPtrOffset]
    max = vtableinfo.max
    else:
    vtableinfo = VTableInfo()
    vtableinfo.vPtrOffset = vPtrOffset
    vtableinfo.mergedVTableEntries = {}
    vtableinfo.derivationPathText = None

    derivationPath[-1].VTables.append(vtableinfo)
    thefirst.VTablesByOffset[vPtrOffset] = vtableinfo
    max = -1

    mergedVTableEntries = vtableinfo.mergedVTableEntries

    gotmultiinherit = False
    gotvirtual = False
    for derivationItem in reversed(derivationPath):
    baseClass = derivationItem.DIE
    if hasattr(baseClass, "VTableEntries"):
    print("%sProcessing %s path:%s previouspath:%s" % (prefix, baseClass.GetName(), derivationItem.derivationPathText, vtableinfo.derivationPathText))

    if vtableinfo.derivationPathText == None or len(derivationItem.derivationPathText) < len(vtableinfo.derivationPathText):
    if gotvirtual or gotmultiinherit:
    # Trying to build vtable of multiple inheritance is hard.
    # This is probably wrong - maybe check virtuality, and parameters, but then I might as well try to code a C++ compiler.
    # We'll just check the name.
    for k,w in baseClass.VTableEntries.iteritems():
    namesuper = w.GetName()
    print("%s Looking for vtableitem %s" % (prefix, namesuper))
    for j,v1 in mergedVTableEntries.iteritems():
    v = v1.DIE
    namebase = v.GetName()
    if (namesuper == namebase or (namesuper[:1] == "~" and namebase[:1] == "~")):
    # a "non-virtual thunk" to w is what this probably is:
    v1.DIE = w
    if gotvirtual:
    v1.ThunkType = "virtual thunk to "
    else:
    v1.ThunkType = "non-virtual thunk to "
    print("%s Changed vtableitem 0x%x %s%s" % (prefix, v1.DIE.compile_unit.addr_size * j, v1.ThunkType, namesuper))
    break

    else:
    for j,v in baseClass.VTableEntries.iteritems():
    namesuper = v.GetName()
    print("%s Adding vtableitem 0x%x %s" % (prefix, v.compile_unit.addr_size * j, namesuper))
    if j in mergedVTableEntries:
    namebase = mergedVTableEntries[j].DIE.GetName()
    if namesuper != namebase and not (namesuper[:1] == "~" and namebase[:1] == "~"):
    if namesuper[:1] == "~" and j == 0 and 1 in mergedVTableEntries and mergedVTableEntries[1].DIE.GetName()[:1] == "~":
    vtableitem = VTableItem()
    vtableitem.DIE = v
    mergedVTableEntries[1] = vtableitem
    print("Error: performed workaround for vtable entry function name :%08x:%s differing from super :%08x:%s" % (v.address, namebase, mergedVTableEntries[j].DIE.address, namesuper))
    else:
    print("Error: vtable entry function name :%08x:%s differs from super :%08x:%s" % (v.address, namebase, mergedVTableEntries[j].DIE.address, namesuper))

    else:
    vtableitem = VTableItem()
    vtableitem.DIE = v
    mergedVTableEntries[j] = vtableitem
    else:
    if j > max:
    max = j
    vtableitem = VTableItem()
    vtableitem.DIE = v
    mergedVTableEntries[j] = vtableitem
    else:
    print("%sSkipping" % prefix)
    if derivationItem.index > 0 and not gotmultiinherit:
    # index is > 0 for non primary base class of multiple inheritance class. These requires a different method to build vtable.
    print("%sgotmultiinherit max:0x%x" % (prefix, max * baseClass.compile_unit.addr_size))
    gotmultiinherit = True

    if derivationItem.isvirtual and not gotvirtual:
    print("%sgotvirtual max:0x%x" % (prefix, max * baseClass.compile_unit.addr_size))
    gotvirtual = True

    vtableinfo.max = max
    if vtableinfo.derivationPathText == None:
    vtableinfo.derivationPathText = derivationPath[-1].derivationPathText

    print("%sadded vtable (%s) classoffset:0x%x vptroffset:0x%x max:%d numvtables:%d numvirtualvtables:%d" % (prefix, self.dumpderivationpath(derivationPath), begin_offset, vPtrOffset, max, len(thefirst.VTables), len(thefirst.VTablesVirtual)))


    def MakeAllVTables(self, parent):
    # for every class or structure, make a list of vtables (more than one vtable exists for multiple inheritance)
    for child in parent.children:
    if child.tag == "TAG_class_type" or child.tag == "TAG_structure_type":
    child.VTables = []
    child.VTablesByOffset = {}
    child.VTablesVirtual = []
    child.AllVirtualBaseClasses = []
    child.IncludedVirtualBaseClasses = {}
    child.VirtualBaseClassOffset = child.GetCompactSize()

    derivationItem = DerivationItem()
    derivationItem.DIE = child
    derivationItem.index = 0
    derivationItem.isvirtual = False
    derivationItem.VTables = child.VTables
    derivationItem.derivationPathText = "%02d" % 1

    derivationPath = [derivationItem]
    print("[ starting (parent:0x%08x: child:0x%08x: %s)" % (parent.address, child.address, self.dumpderivationpath(derivationPath)))
    self.MakeVTables(derivationPath)
    print("]")

    self.MakeAllVTables(child)


    def Process_dSYM(self, filename):
    if re.match(".*\.txt", filename):
    f = open(filename, "r")
    else:
    f = tempfile.NamedTemporaryFile()
    #print("Created temp file: %s" % f.name)
    subprocess.call(["dwarfdump", filename], stdout=f)

    f.seek(0)

    #print("Processing file: %s" % f.name)

    dSYM = DIEDict()
    dSYM.currentCompileUnit = None
    dSYM.DIELookup = {}
    dSYM.CompileUnits = []
    dSYM.filename = filename
    dSYM.children = []

    self.ReadDIEList(f, dSYM, dSYM)

    del dSYM.currentCompileUnit

    f.close()

    self.MakeAllVTables(dSYM)
    return dSYM


    #=========================================================================================
    def MakeOffsetStr(offset):
    #return "%4d" % offset
    return "%6s" % ("0x%x" % offset)

    # from /Library/Developer/KDKs/KDK_10.11.5_15F34.kdk/System/Library/Kernels/kernel.dSYM/Contents/Resources/Python/lldbmacros/structanalyze.py
    def _showStructPacking(symbol, typename, fieldname, prefix, depth, class_depth, begin_offset=0):
    classType = symbol.GetClass()
    if classType == lldb.eTypeClassClass :
    ctype = "class"
    elif classType == lldb.eTypeClassUnion :
    ctype = "union"
    elif classType == lldb.eTypeClassStruct :
    ctype = "struct"
    else:
    ctype = "_unknown_%x" % (classType or 0)

    if typename == None:
    typename = symbol.GetName() or "_anon_%x" % symbol.address

    if fieldname != None:
    outstr = "[%4d] (%s) %s %s {" % (symbol.GetByteSize(), ctype, typename, fieldname) + "\n"
    else:
    outstr = "[%4d] (%s) %s {" % (symbol.GetByteSize(), ctype, typename) + "\n"

    if hasattr(symbol, "Friends"):
    for friend in symbol.Friends:
    friendType = None
    friendClass = None
    if friend.HasType():
    friendType = friend.GetType()
    elif hasattr(friend, "AT_friend"):
    friendType = friend.dSYM.DIELookup[friend.AT_friend]
    if friendType != None:
    friendClass = friendType.GetClass()
    if friendClass == lldb.eTypeClassClass :
    ctype = "class"
    elif friendClass == lldb.eTypeClassUnion :
    ctype = "union"
    elif friendClass == lldb.eTypeClassStruct :
    ctype = "struct"
    else:
    ctype = "_unknown_%x" % (classType or 0)

    outstr = outstr + prefix + " friend %s %s\n" % (ctype, friendType.GetName() or "_anon_%x" % friendType.address)

    """
    Mac OS X 10.8:
    0x009fcff0: DW_TAG_structure_type
    DW_AT_name ("IOStatistics")
    DW_AT_declaration (0x01)
    0x009fd4d4: DW_TAG_friend
    DW_AT_type (0x009fcff0 "IOStatistics")
    DW_AT_data_member_location (DW_OP_plus_uconst 0x0)
    DW_AT_accessibility (DW_ACCESS_public)
    Mac OS X 10.9:
    0x00b67148: DW_TAG_class_type
    DW_AT_name ("IOStatistics")
    DW_AT_declaration (0x01)
    0x00b675ca: DW_TAG_friend
    DW_AT_friend (0x00b67148)
    """

    _compact_offset = begin_offset
    max_union_member_size = 0
    max_align = 1
    m_align = 1

    numClasses = symbol.GetNumberOfDirectBaseClasses()
    for i in range(numClasses):
    member = symbol.GetDirectBaseClassAtIndex(i)
    m_offset = member.GetOffsetInBytes() + begin_offset
    m_type = member.GetType()
    membertypename = m_type.GetName()
    m_type = member.GetBaseType()
    m_size = m_type.GetByteSize()
    warningstr = ""
    debugstr = "" # + str((begin_offset, m_offset, _compact_offset, m_size))
    #print(prefix, "V", membertypename, debugstr)

    if _compact_offset > m_offset:
    warningstr = " *** Possible memory overlap ***"
    elif _compact_offset < m_offset:
    align_offset = ((_compact_offset + m_align-1) & -m_align)
    if align_offset != m_offset :
    # ignore memory holes that may be caused by field alignment
    #_has_memory_hole = True
    warningstr = " *** Possible memory hole (msize:%d align:%d calc:%d calcaligned:%d actual:%d) ***" % (m_size, m_align, _compact_offset, align_offset, m_offset)
    _compact_offset = m_offset

    s, compact_size, m_align = _showStructPacking(m_type, membertypename, None, prefix+" ", depth + 1, class_depth + 1, m_offset)
    if m_align > max_align:
    max_align = m_align
    #print(prefix, "V", membertypename, "m_align:%d max_align:%d compact_size:%d" % (m_align, max_align, compact_size))
    outstr += prefix + ("*%s," % MakeOffsetStr(m_offset)) + s + warningstr + debugstr + "\n"
    _compact_offset += compact_size

    numFields = symbol.GetNumberOfFields()
    #_has_memory_hole = False

    inBitField = False
    totalBits = 0
    bitFieldStartByte = -1
    bitFieldTotalBytes = -1
    used_bits = 0
    next_used_bits = 0
    next_totalBits = 0

    for i in range(numFields):
    member = symbol.GetFieldAtIndex(i)
    m_offset = member.GetOffsetInBytes() + begin_offset
    m_size_bits = member.GetBitSize()
    m_offset_bits = member.GetOffsetInBits()
    isBitField = hasattr(member, "AT_bit_size")

    m_name = member.GetName()

    m_type = member.GetType()
    membertypename = m_type.GetName()
    m_type = member.GetBaseType()
    membertypeclass = m_type.GetClass()
    m_size = m_type.GetByteSize()

    if inBitField:
    # continuing previously started bit fields?
    if (not isBitField) or classType == lldb.eTypeClassUnion or (m_offset >= (bitFieldStartByte + bitFieldTotalBytes)):
    # no, finish previously started bit field
    if classType != lldb.eTypeClassUnion:
    _compact_offset += bitFieldTotalBytes
    inBitField = False
    bitFieldStartByte = m_offset
    used_bits = 0
    totalBits = 0

    if isBitField:
    if not inBitField:
    # new set of bit fields started
    inBitField = True
    bitFieldStartByte = m_offset
    bitFieldTotalBytes = m_size
    used_bits = next_used_bits
    totalBits = next_totalBits
    next_used_bits = 0
    next_totalBits = 0

    if next_used_bits:
    print("Error: have carry over bits but not in new bit field next_used_bits:0x%08x at :%08x:" % (next_used_bits, member.address))
    next_used_bits = 0
    next_totalBits = 0

    totalBits += m_size_bits
    m_offset_bits += (m_offset - bitFieldStartByte) * 8
    m_offset = bitFieldStartByte

    # the type of a bitfield does not always mean the total size of all bit fields because you can mix sized types in a sequence of bit fields
    while bitFieldTotalBytes * 8 < m_offset_bits + m_size_bits:
    #print("[ bitFieldTotalBytes %d" % bitFieldTotalBytes)
    bitFieldTotalBytes *= 2
    #print("] bitFieldTotalBytes %d" % bitFieldTotalBytes)

    if m_offset_bits >= 0:
    bitfield = " : %d // %d..%d" % (m_size_bits, m_offset_bits, m_offset_bits + m_size_bits - 1)
    elif m_size_bits + m_offset_bits > 0:
    bitfield = " : %d // %d..%d,%d..%d" % (m_size_bits, bitFieldTotalBytes * 8 + m_offset_bits, bitFieldTotalBytes * 8 - 1, 0, m_size_bits + m_offset_bits - 1)
    else:
    bitfield = " : %d // %d..%d,nothing" % (m_size_bits, bitFieldTotalBytes * 8 + m_offset_bits, bitFieldTotalBytes * 8 - 1)

    else:
    bitFieldStartByte = m_offset
    bitFieldTotalBytes = m_size
    used_bits = 0
    totalBits = 0
    bitfield = ""
    if next_used_bits:
    print("Error: have carry over bits but not in bit field next_used_bits:0x%08x at :%08x:" % (next_used_bits, member.address))
    next_used_bits = 0
    next_totalBits = 0

    warningstr = ""

    try:
    if m_offset_bits >= 0:
    thebits = (~(-1 << m_size_bits)) << m_offset_bits
    else:
    next_totalBits = -m_offset_bits
    next_used_bits = (~(-1 << next_totalBits)) << (bitFieldTotalBytes * 8 + m_offset_bits)
    thebits = (~(-1 << (m_size_bits + m_offset_bits))) << 0

    except:
    # negative bit offset means something like bit field overlaps next member... complicated
    print("Error with bits used_bits:0x%08x thebits(previous):0x%08x size:%d offset:%d type:%s at :%08x:" % (used_bits, thebits, m_size_bits, m_offset_bits, m_offset_bits.__class__.__name__, member.address))
    thebits = 0

    if ((thebits & used_bits) != 0) or m_size_bits < 0 or m_size_bits + m_offset_bits > bitFieldTotalBytes * 8:
    warningstr = " *** Possible bit field error ***"
    used_bits = 0
    used_bits |= thebits

    debugstr = "" # + str((begin_offset, m_offset, _compact_offset, m_offset_bits, m_size, m_size_bits, thebits, used_bits))

    if membertypeclass == lldb.eTypeClassStruct or membertypeclass == lldb.eTypeClassUnion or membertypeclass == lldb.eTypeClassClass :
    s, compact_size, m_align = _showStructPacking(m_type, membertypename, m_name, prefix+" ", depth + 1, 0, m_offset)
    outstr += prefix + ("*%s," % MakeOffsetStr(m_offset)) + s
    else:
    outstr += prefix + ("+%s,[%4d] (%s) %s%s" % (MakeOffsetStr(m_offset), m_size, membertypename, m_name, bitfield))
    compact_size = m_size
    m_align = m_type.GetAlign()

    if m_align > max_align:
    max_align = m_align

    #print(prefix, membertypename, m_name, "calcoff:0x%x actualoff:0x%x calcsize:%d actualsize:%d m_align:%d max_align:%d" % (_compact_offset, m_offset, compact_size, m_size, m_align, max_align))

    if _compact_offset > m_offset:
    warningstr = " *** Possible memory overlap (msize:%d align:%d calc:%d actual:%d) ***" % (m_size, m_align, _compact_offset, m_offset)
    elif _compact_offset < m_offset:
    align_offset = ((_compact_offset + m_align-1) & -m_align)
    if align_offset != m_offset :
    # ignore memory holes that may be caused by field alignment
    #_has_memory_hole = True
    warningstr = " *** Possible memory hole (msize:%d align:%d calcoff:0x%x calcaligned:0x%x actualoff:0x%x) ***" % (m_size, m_align, _compact_offset, align_offset, m_offset)
    _compact_offset = m_offset

    if classType == lldb.eTypeClassUnion:
    if m_size > max_union_member_size:
    max_union_member_size = m_size
    elif inBitField == False:
    _compact_offset += m_size

    outstr += warningstr + debugstr + "\n"

    if next_used_bits:
    print("Error: have carry over bits after fields next_used_bits:0x%08x at :%08x:" % (next_used_bits, member.address))
    next_used_bits = 0
    next_totalBits = 0

    if classType != lldb.eTypeClassUnion and inBitField:
    _compact_offset += bitFieldTotalBytes
    inBitField = False

    if class_depth == 0 and hasattr(symbol, "AllVirtualBaseClasses"):
    for virtualbaseclassinfo in symbol.AllVirtualBaseClasses:
    member = virtualbaseclassinfo.member
    m_type = member.GetType()
    membertypename = m_type.GetName()
    m_type = member.GetBaseType()
    m_size = m_type.GetByteSize()

    m_align = m_type.GetAlign()
    m_offset = ((_compact_offset + m_align-1) & -m_align)

    warningstr = " virtual"
    debugstr = "" # + str((begin_offset, m_offset, _compact_offset, m_size))
    #print(prefix, "V", membertypename, debugstr)

    _compact_offset = m_offset

    s, compact_size, a = _showStructPacking(m_type, membertypename, None, prefix+" ", depth + 1, 0, m_offset)
    outstr += prefix + ("*%s," % MakeOffsetStr(m_offset)) + s + warningstr + debugstr + "\n"
    _compact_offset += compact_size

    outstr += prefix + "}"

    if classType == lldb.eTypeClassUnion:
    _compact_offset += max_union_member_size

    #if _has_memory_hole == True :
    # outstr += " *** Warning: Struct layout leaves memory hole ***"
    return outstr, _compact_offset - begin_offset, max_align


    vtableFunctionRE = re.compile("(.*?) \(\)\(/\*( const)? (.*?) \*,? \*/ ?(.*)\)")
    # group(1) = function return type
    # group(2) = ' const'
    # group(3) = class from artificial parameter
    # group(4) = parameters



    def doOneVTable(symbol, prefix, vtableinfo):
    outstr = ""
    numEntries = vtableinfo.max + 1
    if numEntries > 0:
    if vtableinfo.vPtrOffset == 0:
    outstr = outstr + prefix + "vtable for %s {\n" % (symbol.GetName())
    else:
    outstr = outstr + prefix + "vtable for %s 0x%x {\n" % (symbol.GetName(), vtableinfo.vPtrOffset)
    for i in xrange(numEntries):
    if i in vtableinfo.mergedVTableEntries:
    vtableitem = vtableinfo.mergedVTableEntries[i]
    member = vtableitem.DIE
    m_name = member.GetName()
    membertypename = member.GetNameForType(True)
    containertype = member.GetContainerType()
    if containertype != None:
    containertypename = containertype.GetName()
    containertypenamequalifed = containertypename+"::"
    else:
    containertypename = ""
    containertypenamequalifed = ""
    if hasattr(vtableitem, "ThunkType"):
    namemodify = vtableitem.ThunkType
    else:
    namemodify = ""
    else:
    m_name = None
    m_size = symbol.compile_unit.addr_size

    if m_name == None:
    outstr += prefix + ("+%s,[%4d]\n" % (MakeOffsetStr(i * m_size), m_size))
    else:
    m = vtableFunctionRE.match(membertypename)
    if m:
    #print("vtablefunc", m.group(0), m.group(1), m.group(2), m.group(3), m.group(4))
    if containertypename == m.group(3):
    if m.group(2) == None:
    constpart = ""
    else:
    constpart = m.group(2)
    if m.group(1) == "void":
    typepart = ""
    else:
    typepart = m.group(1)
    #outstr += prefix + ("+%s,[%4d] (%s) %s%s\n" % (MakeOffsetStr(i * m_size), m_size, membertypename, containertypenamequalifed, m_name))
    outstr += prefix + ("+%s,[%4d] %s %s%s::%s(%s)%s\n" % (MakeOffsetStr(i * m_size), m_size, typepart, namemodify, containertypename, m_name, m.group(4), constpart))
    else:
    outstr += prefix + ("+%s,[%4d] (%s) %s%s\n" % (MakeOffsetStr(i * m_size), m_size, membertypename, containertypenamequalifed, m_name))
    print("Error: containertype '%s' doesn't match artifical parameter '%s'" % (containertypename, m.group(3)))
    else:
    #print("unknownfunc", membertypename)
    outstr += prefix + ("+%s,[%4d] (%s) %s%s\n" % (MakeOffsetStr(i * m_size), m_size, membertypename, containertypenamequalifed, m_name))
    outstr += prefix + "}"
    return outstr


    def _showVTablePacking(symbol, prefix):
    outstr = ""
    if hasattr(symbol, "VTables"):
    for vtableinfo in symbol.VTables:
    vstr = doOneVTable(symbol, prefix, vtableinfo)
    if len(vstr) > 0:
    if len(outstr) > 0:
    outstr += "\n\n"
    outstr += "%s" % vstr

    if hasattr(symbol, "VTablesVirtual"):
    for vtableinfo in symbol.VTablesVirtual:
    vstr = doOneVTable(symbol, prefix, vtableinfo)
    if len(vstr) > 0:
    if len(outstr) > 0:
    outstr += "\n\n"
    outstr += "%s" % vstr

    return outstr


    def DumpAllStructs(parent,names):
    for child in parent.children:
    if hasattr(child, "AT_name"):
    # only dump named types

    #print("address :%08x:" % member.address)

    # also dump typedef'd structs too
    member = child
    membertypename = member.GetName()
    if member.tag == "TAG_typedef":
    while member.tag == "TAG_typedef" and member.HasType():
    member = member.GetType() # follow typedefs
    if member.GetName() == membertypename:
    # don't do typedef if struct has same name, we'll do the struct when we get there
    member = None

    if member != None and member.GetClass() != None and len(member.children) > 0:

    if names == None or member.GetName() in names:
    print("==========================================================================================")
    if hasattr(child, "AT_decl_file"):
    print('0x%08x: "%s"\n' % (child.address, child.AT_decl_file))
    else:
    print("0x%08x:\n" % child.address)

    s, n, a = _showStructPacking(member, membertypename, None, "", 0, 0, 0)
    print(s)
    print
    s = _showVTablePacking(member, "")
    if s != "":
    print(s)
    print
    print

    #if member.GetName() = "_lck_grp_": break

    DumpAllStructs(child, names)


    def DumpAllTypes(Hopper, parent):
    for child in parent.children:

    name = None
    if hasattr(child, "AT_name"):
    name = child.AT_name

    attype = None
    if child.HasType():
    attype = child.GetType()

    if child.tag == "TAG_compile_unit":
    pass
    elif child.tag == "TAG_variable":
    pass
    elif child.tag == "TAG_inheritance": # handled by TAG_class_type
    pass
    elif child.tag == "TAG_member": # handled by TAG_class_type, TAG_structure_type, TAG_union_type (AT_data_member_location)
    pass
    elif child.tag == "TAG_subprogram": # handled by TAG_class_type (AT_data_member_location)
    pass
    elif child.tag == "TAG_formal_parameter":
    pass
    elif child.tag == "TAG_subroutine_type": # handled by TAG_pointer_type
    pass
    elif child.tag == "TAG_subrange_type": # handled by TAG_array_type
    pass
    elif child.tag == "TAG_unspecified_parameters": # handled by TAG_subroutine_type
    pass
    elif child.tag == "TAG_enumerator": # handled by TAG_enumeration_type
    pass
    elif child.tag == "TAG_lexical_block":
    pass
    elif child.tag == "TAG_inlined_subroutine":
    pass
    elif child.tag == "TAG_GNU_template_parameter_pack": # template
    pass
    elif child.tag == "TAG_imported_declaration":
    pass
    elif child.tag == "TAG_imported_module": # points to TAG_namespace
    pass
    elif child.tag == "TAG_namespace":
    pass
    elif child.tag == "TAG_template_type_parameter":
    pass
    elif child.tag == "TAG_template_value_parameter":
    pass
    elif child.tag == "TAG_unspecified_type":
    pass

    elif child.tag == "TAG_pointer_type":
    if attype != None and attype.tag == "TAG_subroutine_type":
    Hopper.AddFunctionPointer(child, name, attype)
    else:
    Hopper.AddPointer(child, name, attype)

    elif child.tag == "TAG_reference_type":
    if name == None:
    if attype == None:
    name = "&"
    else:
    name = child.GetType().GetName() + " &"
    Hopper.AddPointer(child, name, attype)

    elif child.tag == "TAG_rvalue_reference_type":
    # I don't know whan an rvalue_reference_type looks like so I use &_
    if name == None:
    if attype == None:
    name = "&_"
    else:
    name = child.GetType().GetName() + " &_"
    Hopper.AddPointer(child, name, attype)

    elif child.tag == "TAG_const_type":
    if name == None:
    if attype == None:
    name = 'const'
    else:
    name = 'const ' + child.GetType().GetName()
    Hopper.AddTypedef(child, name, attype, None)

    elif child.tag == "TAG_volatile_type":
    if name == None:
    if attype == None:
    name = 'volatile'
    else:
    name = 'volatile ' + child.GetType().GetName()
    Hopper.AddTypedef(child, name, attype, None)

    elif child.tag == "TAG_class_type":
    Hopper.AddClass(child, name, child)
    # might just be a declaration AT_declaration( true )
    # or it might contain children with AT_data_member_location
    # Direct inheritance TAG_inheritance DirectBaseClasses

    elif child.tag == "TAG_structure_type":
    Hopper.AddStruct(child, name, child)
    # might be a declaration - replace with define if it exists in same compileunit

    elif child.tag == "TAG_union_type":
    Hopper.AddStruct(child, name, child)
    # might be a declaration - replace with define if it exists in same compileunit

    elif child.tag == "TAG_typedef":
    Hopper.AddTypedef(child, name, attype, None)

    elif child.tag == "TAG_base_type":
    Hopper.AddBaseType(child)

    elif child.tag == "TAG_ptr_to_member_type":
    if attype != None and attype.tag == "TAG_subroutine_type":
    Hopper.AddPointerToMember(child, name, attype)
    else:
    print("Error: unexpected tag :%08x:" % child.address)

    elif child.tag == "TAG_array_type":
    Hopper.AddArray(child, name, attype)

    elif child.tag == "TAG_enumeration_type":
    Hopper.AddEnumeration(child, name)
    #bytesize

    else:
    print("Error: unknown tag '%s':" % child.tag)

    DumpAllTypes(Hopper, child)


    if __name__ == '__main__':
    if len(sys.argv) < 1:
    print('Expected usage: {0} <dsym>'.format(sys.argv[0]))
    sys.exit(1)

    H = Hopper()
    for i in xrange(1, len(sys.argv)):
    print("==========================================================================================")
    print("The file: %s\n" % sys.argv[i])

    dSYMr = DSYM_Reader()
    dSYM = dSYMr.Process_dSYM(sys.argv[i])
    DumpAllStructs(dSYM, None)

    #••••••• TO DO: Finish DumpAllTypes
    #DumpAllTypes(H, dSYM)
    '''
    pp = pprint.PrettyPrinter(indent=4, depth=10)
    pp.pprint(H.Types)
    pp.pprint(H.UUIDs)
    for k,v in H.UUIDs.items():
    pp.pprint(k)
    for attr, value in v.__dict__.iteritems():
    print attr, value
    print
    '''