<rdar://problem/12582031>
authorGreg Clayton <gclayton@apple.com>
Tue, 6 Nov 2012 00:20:41 +0000 (00:20 +0000)
committerGreg Clayton <gclayton@apple.com>
Tue, 6 Nov 2012 00:20:41 +0000 (00:20 +0000)
Unnamed bitfields cause struct layout problems

Synthesize unnamed bitfields when required. Most compilers don't mention unnamed bitfields in the DWARF, so we need to create them to keep clang happy with the types we create from the DWARF. We currently can't do this for ObjC since the DW_AT_bit_offset value for any direct ivars of ObjC classes as the values for these attributes are bogus. A bug has been filed on Clang to fix this, and another bug has been filed on LLDB to make sure we fix the DWARF parser once the clang fix is in by looking the the DW_AT_producer in the compile unit attributes and finding the compiler version and only enabling it for newer versions of clang.

llvm-svn: 167424

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
lldb/source/Symbol/ClangASTContext.cpp

index 5d5c308..69954f4 100644 (file)
@@ -1556,6 +1556,7 @@ SymbolFileDWARF::ParseChildMembers
     std::vector<clang::CXXBaseSpecifier *>& base_classes,
     std::vector<int>& member_accessibilities,
     DWARFDIECollection& member_function_dies,
+    BitfieldMap &bitfield_map,
     DelayedPropertyList& delayed_properties,
     AccessType& default_accessibility,
     bool &is_a_class,
@@ -1759,7 +1760,84 @@ SymbolFileDWARF::ParseChildMembers
                                     accessibility = default_accessibility;
                                 member_accessibilities.push_back(accessibility);
 
-                                field_decl = GetClangASTContext().AddFieldToRecordType (class_clang_type, 
+                                // Code to detect unnamed bitifields
+                                if (bit_size > 0 && member_byte_offset != UINT32_MAX)
+                                {
+                                    // Objective C has invalid DW_AT_bit_offset values so we can't use them to detect
+                                    // unnamed bitfields. Once clang is fixed we will enable unnamed bitfields
+                                    // in ObjC classes (<rdar://problem/12636970>)
+                                    
+                                    if (!(class_language == eLanguageTypeObjC || class_language == eLanguageTypeObjC_plus_plus))
+                                    {
+                                        // We have a bitfield, we need to watch out for
+                                        // unnamed bitfields that we need to insert if
+                                        // there is a gap in the bytes as many compilers
+                                        // doesn't emit DWARF DW_TAG_member tags for
+                                        // unnammed bitfields.
+                                        BitfieldMap::iterator bit_pos = bitfield_map.find(member_byte_offset);
+                                        uint32_t unnamed_bit_size = 0;
+                                        uint32_t unnamed_bit_offset = 0;
+                                        if (bit_pos == bitfield_map.end())
+                                        {
+                                            // First bitfield in an integral type.
+                                            
+                                            // We might need to insert a leading unnamed bitfield
+                                            if (bit_offset < byte_size * 8)
+                                            {
+                                                unnamed_bit_size = byte_size * 8 - (bit_size + bit_offset);
+                                                unnamed_bit_offset = byte_size * 8 - unnamed_bit_size;
+                                            }
+                                            
+                                            // Now put the current bitfield info into the map
+                                            bitfield_map[member_byte_offset].bit_size = bit_size;
+                                            bitfield_map[member_byte_offset].bit_offset = bit_offset;
+                                        }
+                                        else
+                                        {
+                                            // Subsequent bitfield in an integral type.
+
+                                            // We have a bitfield that isn't the first for this
+                                            // integral type, check to make sure there aren't any
+                                            // gaps.
+                                            assert (bit_pos->second.bit_size > 0);
+                                            if (bit_offset < bit_pos->second.bit_offset)
+                                            {
+                                                unnamed_bit_size = bit_pos->second.bit_offset - (bit_size + bit_offset);
+                                                unnamed_bit_offset = bit_pos->second.bit_offset - unnamed_bit_size;
+                                            }
+
+                                            // Now put the current bitfield info into the map
+                                            bit_pos->second.bit_size = bit_size;
+                                            bit_pos->second.bit_offset = bit_offset;
+                                        }
+                                        
+                                        if (unnamed_bit_size > 0)
+                                        {
+                                            //printf ("0x%8.8x: Unnamed bitfield added bit_size = 0x%x, bit_offset = 0x%x\n", die->GetOffset(), unnamed_bit_size, unnamed_bit_offset);
+                                            clang::FieldDecl *unnamed_bitfield_decl = GetClangASTContext().AddFieldToRecordType (class_clang_type,
+                                                                                                                                 NULL,
+                                                                                                                                 member_type->GetClangLayoutType(),
+                                                                                                                                 accessibility,
+                                                                                                                                 unnamed_bit_size);
+                                            uint64_t total_bit_offset = 0;
+                                            
+                                            total_bit_offset += (member_byte_offset == UINT32_MAX ? 0 : (member_byte_offset * 8));
+                                            
+                                            if (GetObjectFile()->GetByteOrder() == eByteOrderLittle)
+                                            {
+                                                total_bit_offset += byte_size * 8;
+                                                total_bit_offset -= (unnamed_bit_offset + unnamed_bit_size);
+                                            }
+                                            else
+                                            {
+                                                total_bit_offset += unnamed_bit_size;
+                                            }
+                                            
+                                            layout_info.field_offsets.insert(std::make_pair(unnamed_bitfield_decl, total_bit_offset));
+                                        }
+                                    }
+                                }
+                                field_decl = GetClangASTContext().AddFieldToRecordType (class_clang_type,
                                                                                         name, 
                                                                                         member_type->GetClangLayoutType(), 
                                                                                         accessibility, 
@@ -1798,13 +1876,11 @@ SymbolFileDWARF::ParseChildMembers
                                 // AT_bit_size indicates the size of the field in bits.
                                 /////////////////////////////////////////////////////////////
                                                         
-                                ByteOrder object_endian = GetObjectFile()->GetModule()->GetArchitecture().GetDefaultEndian();
-
                                 uint64_t total_bit_offset = 0;
                                 
                                 total_bit_offset += (member_byte_offset == UINT32_MAX ? 0 : (member_byte_offset * 8));
                                 
-                                if (object_endian == eByteOrderLittle)
+                                if (GetObjectFile()->GetByteOrder() == eByteOrderLittle)
                                 {  
                                     total_bit_offset += byte_size * 8;
                                     total_bit_offset -= (bit_offset + bit_size);
@@ -2167,8 +2243,8 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (lldb::clang_type_t clang_type
                     DWARFDIECollection member_function_dies;
                                         
                     DelayedPropertyList delayed_properties;
-                    
-                    ParseChildMembers (sc, 
+                    BitfieldMap bitfield_map;
+                    ParseChildMembers (sc,
                                        dwarf_cu,
                                        die, 
                                        clang_type,
@@ -2176,6 +2252,7 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (lldb::clang_type_t clang_type
                                        base_classes, 
                                        member_accessibilities,
                                        member_function_dies,
+                                       bitfield_map,
                                        delayed_properties,
                                        default_accessibility, 
                                        is_a_class,
index 5b8fbd9..69dad29 100644 (file)
@@ -59,6 +59,14 @@ class DWARFDIECollection;
 class DWARFFormValue;
 class SymbolFileDWARFDebugMap;
 
+struct BitfieldInfo
+{
+    uint32_t bit_size;
+    uint32_t bit_offset;
+};
+
+typedef std::map<int64_t, BitfieldInfo> BitfieldMap;
+
 class SymbolFileDWARF : public lldb_private::SymbolFile, public lldb_private::UserID
 {
 public:
@@ -345,6 +353,7 @@ protected:
                                 std::vector<clang::CXXBaseSpecifier *>& base_classes,
                                 std::vector<int>& member_accessibilities,
                                 DWARFDIECollection& member_function_dies,
+                                BitfieldMap &bitfield_map,
                                 DelayedPropertyList& delayed_properties,
                                 lldb::AccessType &default_accessibility,
                                 bool &is_a_class,
index 76ec6bc..524b6f6 100644 (file)
@@ -2366,7 +2366,7 @@ ClangASTContext::AddObjCClassIVar
                                               class_interface_decl,
                                               SourceLocation(),
                                               SourceLocation(),
-                                              &identifier_table->get(name), // Identifier
+                                              name ? &identifier_table->get(name) : NULL, // Identifier
                                               QualType::getFromOpaquePtr(ivar_opaque_type), // Field type
                                               NULL, // TypeSourceInfo *
                                               ConvertAccessTypeToObjCIvarAccessControl (access),