diff options
| -rw-r--r-- | lldb/include/lldb/Symbol/ClangASTContext.h | 17 | ||||
| -rw-r--r-- | lldb/source/Core/Debugger.cpp | 2 | ||||
| -rw-r--r-- | lldb/source/Core/Value.cpp | 3 | ||||
| -rw-r--r-- | lldb/source/Core/ValueObject.cpp | 4 | ||||
| -rw-r--r-- | lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 9 | ||||
| -rw-r--r-- | lldb/source/Symbol/ClangASTContext.cpp | 732 | ||||
| -rw-r--r-- | lldb/source/Symbol/ClangASTType.cpp | 8 | ||||
| -rw-r--r-- | lldb/source/Target/StackFrame.cpp | 6 | ||||
| -rw-r--r-- | lldb/test/lang/c/struct_types/TestStructTypes.py | 42 | ||||
| -rw-r--r-- | lldb/test/lang/c/struct_types/main.c | 2 |
10 files changed, 448 insertions, 377 deletions
diff --git a/lldb/include/lldb/Symbol/ClangASTContext.h b/lldb/include/lldb/Symbol/ClangASTContext.h index ac09cb0a3db..50875001fda 100644 --- a/lldb/include/lldb/Symbol/ClangASTContext.h +++ b/lldb/include/lldb/Symbol/ClangASTContext.h @@ -785,9 +785,8 @@ public: //------------------------------------------------------------------ lldb::clang_type_t - CreateArrayType (lldb::clang_type_t element_type, - size_t element_count, - uint32_t bit_stride); + CreateArrayType (lldb::clang_type_t element_type, + size_t element_count); //------------------------------------------------------------------ // Tag Declarations @@ -887,15 +886,17 @@ public: static lldb::clang_type_t GetAsArrayType (lldb::clang_type_t clang_type, - lldb::clang_type_t *member_type = NULL, - uint64_t *size = NULL); + lldb::clang_type_t *member_type, + uint64_t *size, + bool *is_incomplete); static bool IsArrayType (lldb::clang_type_t clang_type, - lldb::clang_type_t *member_type = NULL, - uint64_t *size = NULL) + lldb::clang_type_t *member_type, + uint64_t *size, + bool *is_incomplete) { - return GetAsArrayType(clang_type, member_type, size) != 0; + return GetAsArrayType(clang_type, member_type, size, is_incomplete) != 0; } //------------------------------------------------------------------ diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index e9f05ea4ec7..a46bcbf72fb 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -1551,7 +1551,7 @@ Debugger::FormatPrompt } // TODO use flags for these - bool is_array = ClangASTContext::IsArrayType(target->GetClangType()); + bool is_array = ClangASTContext::IsArrayType(target->GetClangType(), NULL, NULL, NULL); bool is_pointer = ClangASTContext::IsPointerType(target->GetClangType()); bool is_aggregate = ClangASTContext::IsAggregateType(target->GetClangType()); diff --git a/lldb/source/Core/Value.cpp b/lldb/source/Core/Value.cpp index b6b4eb76fdc..9a0f686164e 100644 --- a/lldb/source/Core/Value.cpp +++ b/lldb/source/Core/Value.cpp @@ -201,8 +201,7 @@ Value::GetValueByteSize (clang::ASTContext *ast_context, Error *error_ptr) if (GetRegisterInfo()) byte_size = GetRegisterInfo()->byte_size; else if (error_ptr) - error_ptr->SetErrorString ("Can't determine byte size with NULL RegisterInfo *."); - + error_ptr->SetErrorString ("Can't determine byte size with NULL RegisterInfo *."); break; case eContextTypeLLDBType: // Type * diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index 336b25337e7..d8564b85de8 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -675,7 +675,7 @@ ValueObject::CreateChildAtIndex (uint32_t idx, bool synthetic_array_member, int3 child_bitfield_bit_offset, child_is_base_class, child_is_deref_of_parent); - if (child_clang_type && child_byte_size) + if (child_clang_type) { if (synthetic_index) child_byte_offset += child_byte_size * synthetic_index; @@ -1798,7 +1798,7 @@ ValueObject::IsPointerType () bool ValueObject::IsArrayType () { - return ClangASTContext::IsArrayType (GetClangType()); + return ClangASTContext::IsArrayType (GetClangType(), NULL, NULL, NULL); } bool diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 65b80fe895e..453515f9645 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -4218,6 +4218,7 @@ SymbolFileDWARF::ParseChildArrayInfo uint64_t num_elements = 0; uint64_t lower_bound = 0; uint64_t upper_bound = 0; + bool upper_bound_valid = false; uint32_t i; for (i=0; i<num_child_attributes; ++i) { @@ -4247,6 +4248,7 @@ SymbolFileDWARF::ParseChildArrayInfo break; case DW_AT_upper_bound: + upper_bound_valid = true; upper_bound = form_value.Unsigned(); break; @@ -4269,7 +4271,7 @@ SymbolFileDWARF::ParseChildArrayInfo if (num_elements == 0) { - if (upper_bound >= lower_bound) + if (upper_bound_valid && upper_bound >= lower_bound) num_elements = upper_bound - lower_bound + 1; } @@ -6534,10 +6536,9 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, { num_elements = *pos; clang_type = ast.CreateArrayType (array_element_type, - num_elements, - num_elements * array_element_bit_stride); + num_elements); array_element_type = clang_type; - array_element_bit_stride = array_element_bit_stride * num_elements; + array_element_bit_stride = num_elements ? array_element_bit_stride * num_elements : array_element_bit_stride; } ConstString empty_name; type_sp.reset( new Type (MakeUserID(die->GetOffset()), diff --git a/lldb/source/Symbol/ClangASTContext.cpp b/lldb/source/Symbol/ClangASTContext.cpp index 3397b0edea8..d500cad3863 100644 --- a/lldb/source/Symbol/ClangASTContext.cpp +++ b/lldb/source/Symbol/ClangASTContext.cpp @@ -2046,14 +2046,14 @@ ClangASTContext::BuildIndirectFields (clang::ASTContext *ast, typedef llvm::SmallVector <IndirectFieldDecl *, 1> IndirectFieldVector; IndirectFieldVector indirect_fields; - - for (RecordDecl::field_iterator fi = record_decl->field_begin(), fe = record_decl->field_end(); - fi != fe; - ++fi) + RecordDecl::field_iterator field_pos; + RecordDecl::field_iterator field_end_pos = record_decl->field_end(); + RecordDecl::field_iterator last_field_pos = field_end_pos; + for (field_pos = record_decl->field_begin(); field_pos != field_end_pos; last_field_pos = field_pos++) { - if (fi->isAnonymousStructOrUnion()) + if (field_pos->isAnonymousStructOrUnion()) { - QualType field_qual_type = fi->getType(); + QualType field_qual_type = field_pos->getType(); const RecordType *field_record_type = field_qual_type->getAs<RecordType>(); @@ -2072,7 +2072,7 @@ ClangASTContext::BuildIndirectFields (clang::ASTContext *ast, if (FieldDecl *nested_field_decl = dyn_cast<FieldDecl>(*di)) { NamedDecl **chain = new (*ast) NamedDecl*[2]; - chain[0] = *fi; + chain[0] = *field_pos; chain[1] = nested_field_decl; IndirectFieldDecl *indirect_field = IndirectFieldDecl::Create(*ast, record_decl, @@ -2082,7 +2082,7 @@ ClangASTContext::BuildIndirectFields (clang::ASTContext *ast, chain, 2); - indirect_field->setAccess(UnifyAccessSpecifiers(fi->getAccess(), + indirect_field->setAccess(UnifyAccessSpecifiers(field_pos->getAccess(), nested_field_decl->getAccess())); indirect_fields.push_back(indirect_field); @@ -2091,7 +2091,7 @@ ClangASTContext::BuildIndirectFields (clang::ASTContext *ast, { int nested_chain_size = nested_indirect_field_decl->getChainingSize(); NamedDecl **chain = new (*ast) NamedDecl*[nested_chain_size + 1]; - chain[0] = *fi; + chain[0] = *field_pos; int chain_index = 1; for (IndirectFieldDecl::chain_iterator nci = nested_indirect_field_decl->chain_begin(), @@ -2111,7 +2111,7 @@ ClangASTContext::BuildIndirectFields (clang::ASTContext *ast, chain, nested_chain_size + 1); - indirect_field->setAccess(UnifyAccessSpecifiers(fi->getAccess(), + indirect_field->setAccess(UnifyAccessSpecifiers(field_pos->getAccess(), nested_indirect_field_decl->getAccess())); indirect_fields.push_back(indirect_field); @@ -2120,6 +2120,14 @@ ClangASTContext::BuildIndirectFields (clang::ASTContext *ast, } } + // Check the last field to see if it has an incomplete array type as its + // last member and if it does, the tell the record decl about it + if (last_field_pos != field_end_pos) + { + if (last_field_pos->getType()->isIncompleteArrayType()) + record_decl->hasFlexibleArrayMember(); + } + for (IndirectFieldVector::iterator ifi = indirect_fields.begin(), ife = indirect_fields.end(); ifi < ife; ++ifi) @@ -3864,17 +3872,19 @@ ClangASTContext::GetChildClangTypeAtIndex if (parent_clang_type == NULL) return NULL; - if (idx < ClangASTContext::GetNumChildren (ast, parent_clang_type, omit_empty_base_classes)) + QualType parent_qual_type(QualType::getFromOpaquePtr(parent_clang_type)); + const clang::Type::TypeClass parent_type_class = parent_qual_type->getTypeClass(); + child_bitfield_bit_size = 0; + child_bitfield_bit_offset = 0; + child_is_base_class = false; + + const bool idx_is_valid = idx < ClangASTContext::GetNumChildren (ast, parent_clang_type, omit_empty_base_classes); + uint32_t bit_offset; + switch (parent_type_class) { - uint32_t bit_offset; - child_bitfield_bit_size = 0; - child_bitfield_bit_offset = 0; - child_is_base_class = false; - QualType parent_qual_type(QualType::getFromOpaquePtr(parent_clang_type)); - const clang::Type::TypeClass parent_type_class = parent_qual_type->getTypeClass(); - switch (parent_type_class) + case clang::Type::Builtin: + if (idx_is_valid) { - case clang::Type::Builtin: switch (cast<clang::BuiltinType>(parent_qual_type)->getKind()) { case clang::BuiltinType::ObjCId: @@ -3886,270 +3896,272 @@ ClangASTContext::GetChildClangTypeAtIndex default: break; } - break; + } + break; - case clang::Type::Record: - if (GetCompleteQualType (ast, parent_qual_type)) - { - const RecordType *record_type = cast<RecordType>(parent_qual_type.getTypePtr()); - const RecordDecl *record_decl = record_type->getDecl(); - assert(record_decl); - const ASTRecordLayout &record_layout = ast->getASTRecordLayout(record_decl); - uint32_t child_idx = 0; + case clang::Type::Record: + if (idx_is_valid && GetCompleteQualType (ast, parent_qual_type)) + { + const RecordType *record_type = cast<RecordType>(parent_qual_type.getTypePtr()); + const RecordDecl *record_decl = record_type->getDecl(); + assert(record_decl); + const ASTRecordLayout &record_layout = ast->getASTRecordLayout(record_decl); + uint32_t child_idx = 0; - const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); - if (cxx_record_decl) + const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); + if (cxx_record_decl) + { + // We might have base classes to print out first + CXXRecordDecl::base_class_const_iterator base_class, base_class_end; + for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end(); + base_class != base_class_end; + ++base_class) { - // We might have base classes to print out first - CXXRecordDecl::base_class_const_iterator base_class, base_class_end; - for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end(); - base_class != base_class_end; - ++base_class) + const CXXRecordDecl *base_class_decl = NULL; + + // Skip empty base classes + if (omit_empty_base_classes) { - const CXXRecordDecl *base_class_decl = NULL; + base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl()); + if (RecordHasFields(base_class_decl) == false) + continue; + } - // Skip empty base classes - if (omit_empty_base_classes) - { + if (idx == child_idx) + { + if (base_class_decl == NULL) base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl()); - if (RecordHasFields(base_class_decl) == false) - continue; - } - - if (idx == child_idx) - { - if (base_class_decl == NULL) - base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl()); - if (base_class->isVirtual()) - bit_offset = record_layout.getVBaseClassOffset(base_class_decl).getQuantity() * 8; - else - bit_offset = record_layout.getBaseClassOffset(base_class_decl).getQuantity() * 8; + if (base_class->isVirtual()) + bit_offset = record_layout.getVBaseClassOffset(base_class_decl).getQuantity() * 8; + else + bit_offset = record_layout.getBaseClassOffset(base_class_decl).getQuantity() * 8; - // Base classes should be a multiple of 8 bits in size - child_byte_offset = bit_offset/8; - - child_name = ClangASTType::GetTypeNameForQualType(ast, base_class->getType()); + // Base classes should be a multiple of 8 bits in size + child_byte_offset = bit_offset/8; + + child_name = ClangASTType::GetTypeNameForQualType(ast, base_class->getType()); - uint64_t clang_type_info_bit_size = ast->getTypeSize(base_class->getType()); + uint64_t clang_type_info_bit_size = ast->getTypeSize(base_class->getType()); - // Base classes bit sizes should be a multiple of 8 bits in size - assert (clang_type_info_bit_size % 8 == 0); - child_byte_size = clang_type_info_bit_size / 8; - child_is_base_class = true; - return base_class->getType().getAsOpaquePtr(); - } - // We don't increment the child index in the for loop since we might - // be skipping empty base classes - ++child_idx; + // Base classes bit sizes should be a multiple of 8 bits in size + assert (clang_type_info_bit_size % 8 == 0); + child_byte_size = clang_type_info_bit_size / 8; + child_is_base_class = true; + return base_class->getType().getAsOpaquePtr(); } + // We don't increment the child index in the for loop since we might + // be skipping empty base classes + ++child_idx; } - // Make sure index is in range... - uint32_t field_idx = 0; - RecordDecl::field_iterator field, field_end; - for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field, ++field_idx, ++child_idx) + } + // Make sure index is in range... + uint32_t field_idx = 0; + RecordDecl::field_iterator field, field_end; + for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field, ++field_idx, ++child_idx) + { + if (idx == child_idx) { - if (idx == child_idx) - { - // Print the member type if requested - // Print the member name and equal sign - child_name.assign(field->getNameAsString().c_str()); + // Print the member type if requested + // Print the member name and equal sign + child_name.assign(field->getNameAsString().c_str()); - // Figure out the type byte size (field_type_info.first) and - // alignment (field_type_info.second) from the AST context. - std::pair<uint64_t, unsigned> field_type_info = ast->getTypeInfo(field->getType()); - assert(field_idx < record_layout.getFieldCount()); + // Figure out the type byte size (field_type_info.first) and + // alignment (field_type_info.second) from the AST context. + std::pair<uint64_t, unsigned> field_type_info = ast->getTypeInfo(field->getType()); + assert(field_idx < record_layout.getFieldCount()); - child_byte_size = field_type_info.first / 8; + child_byte_size = field_type_info.first / 8; - // Figure out the field offset within the current struct/union/class type - bit_offset = record_layout.getFieldOffset (field_idx); - child_byte_offset = bit_offset / 8; - if (ClangASTContext::FieldIsBitfield (ast, *field, child_bitfield_bit_size)) - child_bitfield_bit_offset = bit_offset % 8; + // Figure out the field offset within the current struct/union/class type + bit_offset = record_layout.getFieldOffset (field_idx); + child_byte_offset = bit_offset / 8; + if (ClangASTContext::FieldIsBitfield (ast, *field, child_bitfield_bit_size)) + child_bitfield_bit_offset = bit_offset % 8; - return field->getType().getAsOpaquePtr(); - } + return field->getType().getAsOpaquePtr(); } } - break; + } + break; - case clang::Type::ObjCObject: - case clang::Type::ObjCInterface: - if (GetCompleteQualType (ast, parent_qual_type)) + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + if (idx_is_valid && GetCompleteQualType (ast, parent_qual_type)) + { + const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(parent_qual_type.getTypePtr()); + assert (objc_class_type); + if (objc_class_type) { - const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(parent_qual_type.getTypePtr()); - assert (objc_class_type); - if (objc_class_type) + uint32_t child_idx = 0; + ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + + if (class_interface_decl) { - uint32_t child_idx = 0; - ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); - - if (class_interface_decl) + + const ASTRecordLayout &interface_layout = ast->getASTObjCInterfaceLayout(class_interface_decl); + ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass(); + if (superclass_interface_decl) { - - const ASTRecordLayout &interface_layout = ast->getASTObjCInterfaceLayout(class_interface_decl); - ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass(); - if (superclass_interface_decl) + if (omit_empty_base_classes) { - if (omit_empty_base_classes) + if (ClangASTContext::GetNumChildren(ast, ast->getObjCInterfaceType(superclass_interface_decl).getAsOpaquePtr(), omit_empty_base_classes) > 0) { - if (ClangASTContext::GetNumChildren(ast, ast->getObjCInterfaceType(superclass_interface_decl).getAsOpaquePtr(), omit_empty_base_classes) > 0) + if (idx == 0) { - if (idx == 0) - { - QualType ivar_qual_type(ast->getObjCInterfaceType(superclass_interface_decl)); - - - child_name.assign(superclass_interface_decl->getNameAsString().c_str()); + QualType ivar_qual_type(ast->getObjCInterfaceType(superclass_interface_decl)); + - std::pair<uint64_t, unsigned> ivar_type_info = ast->getTypeInfo(ivar_qual_type.getTypePtr()); + child_name.assign(superclass_interface_decl->getNameAsString().c_str()); - child_byte_size = ivar_type_info.first / 8; - child_byte_offset = 0; - child_is_base_class = true; + std::pair<uint64_t, unsigned> ivar_type_info = ast->getTypeInfo(ivar_qual_type.getTypePtr()); - return ivar_qual_type.getAsOpaquePtr(); - } + child_byte_size = ivar_type_info.first / 8; + child_byte_offset = 0; + child_is_base_class = true; - ++child_idx; + return ivar_qual_type.getAsOpaquePtr(); } - } - else + ++child_idx; + } } - - const uint32_t superclass_idx = child_idx; + else + ++child_idx; + } - if (idx < (child_idx + class_interface_decl->ivar_size())) + const uint32_t superclass_idx = child_idx; + + if (idx < (child_idx + class_interface_decl->ivar_size())) + { + ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end(); + + for (ivar_pos = class_interface_decl->ivar_begin(); ivar_pos != ivar_end; ++ivar_pos) { - ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end(); - - for (ivar_pos = class_interface_decl->ivar_begin(); ivar_pos != ivar_end; ++ivar_pos) + if (child_idx == idx) { - if (child_idx == idx) + ObjCIvarDecl* ivar_decl = *ivar_pos; + + QualType ivar_qual_type(ivar_decl->getType()); + + child_name.assign(ivar_decl->getNameAsString().c_str()); + + std::pair<uint64_t, unsigned> ivar_type_info = ast->getTypeInfo(ivar_qual_type.getTypePtr()); + + child_byte_size = ivar_type_info.first / 8; + + // Figure out the field offset within the current struct/union/class type + // For ObjC objects, we can't trust the bit offset we get from the Clang AST, since + // that doesn't account for the space taken up by unbacked properties, or from + // the changing size of base classes that are newer than this class. + // So if we have a process around that we can ask about this object, do so. + child_byte_offset = LLDB_INVALID_IVAR_OFFSET; + Process *process = NULL; + if (exe_ctx) + process = exe_ctx->GetProcessPtr(); + if (process) { - ObjCIvarDecl* ivar_decl = *ivar_pos; - - QualType ivar_qual_type(ivar_decl->getType()); - - child_name.assign(ivar_decl->getNameAsString().c_str()); - - std::pair<uint64_t, unsigned> ivar_type_info = ast->getTypeInfo(ivar_qual_type.getTypePtr()); - - child_byte_size = ivar_type_info.first / 8; - - // Figure out the field offset within the current struct/union/class type - // For ObjC objects, we can't trust the bit offset we get from the Clang AST, since - // that doesn't account for the space taken up by unbacked properties, or from - // the changing size of base classes that are newer than this class. - // So if we have a process around that we can ask about this object, do so. - child_byte_offset = LLDB_INVALID_IVAR_OFFSET; - Process *process = NULL; - if (exe_ctx) - process = exe_ctx->GetProcessPtr(); - if (process) + ObjCLanguageRuntime *objc_runtime = process->GetObjCLanguageRuntime(); + if (objc_runtime != NULL) { - ObjCLanguageRuntime *objc_runtime = process->GetObjCLanguageRuntime(); - if (objc_runtime != NULL) - { - ClangASTType parent_ast_type (ast, parent_qual_type.getAsOpaquePtr()); - child_byte_offset = objc_runtime->GetByteOffsetForIvar (parent_ast_type, ivar_decl->getNameAsString().c_str()); - } + ClangASTType parent_ast_type (ast, parent_qual_type.getAsOpaquePtr()); + child_byte_offset = objc_runtime->GetByteOffsetForIvar (parent_ast_type, ivar_decl->getNameAsString().c_str()); } - - // Setting this to UINT32_MAX to make sure we don't compute it twice... - bit_offset = UINT32_MAX; - - if (child_byte_offset == LLDB_INVALID_IVAR_OFFSET) - { + } + + // Setting this to UINT32_MAX to make sure we don't compute it twice... + bit_offset = UINT32_MAX; + + if (child_byte_offset == LLDB_INVALID_IVAR_OFFSET) + { + bit_offset = interface_layout.getFieldOffset (child_idx - superclass_idx); + child_byte_offset = bit_offset / 8; + } + + // Note, the ObjC Ivar Byte offset is just that, it doesn't account for the bit offset + // of a bitfield within its containing object. So regardless of where we get the byte + // offset from, we still need to get the bit offset for bitfields from the layout. + + if (ClangASTContext::FieldIsBitfield (ast, ivar_decl, child_bitfield_bit_size)) + { + if (bit_offset == UINT32_MAX) bit_offset = interface_layout.getFieldOffset (child_idx - superclass_idx); - child_byte_offset = bit_offset / 8; - } - - // Note, the ObjC Ivar Byte offset is just that, it doesn't account for the bit offset - // of a bitfield within its containing object. So regardless of where we get the byte - // offset from, we still need to get the bit offset for bitfields from the layout. - - if (ClangASTContext::FieldIsBitfield (ast, ivar_decl, child_bitfield_bit_size)) - { - if (bit_offset == UINT32_MAX) - bit_offset = interface_layout.getFieldOffset (child_idx - superclass_idx); - - child_bitfield_bit_offset = bit_offset % 8; - } - return ivar_qual_type.getAsOpaquePtr(); + + child_bitfield_bit_offset = bit_offset % 8; } - ++child_idx; + return ivar_qual_type.getAsOpaquePtr(); } + ++child_idx; } } } } - break; - - case clang::Type::ObjCObjectPointer: - { - const ObjCObjectPointerType *pointer_type = cast<ObjCObjectPointerType>(parent_qual_type.getTypePtr()); - QualType pointee_type = pointer_type->getPointeeType(); + } + break; + + case clang::Type::ObjCObjectPointer: + if (idx_is_valid) + { + const ObjCObjectPointerType *pointer_type = cast<ObjCObjectPointerType>(parent_qual_type.getTypePtr()); + QualType pointee_type = pointer_type->getPointeeType(); - if (transparent_pointers && ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) + if (transparent_pointers && ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) + { + child_is_deref_of_parent = false; + bool tmp_child_is_deref_of_parent = false; + return GetChildClangTypeAtIndex (exe_ctx, + ast, + parent_name, + pointer_type->getPointeeType().getAsOpaquePtr(), + idx, + transparent_pointers, + omit_empty_base_classes, + ignore_array_bounds, + child_name, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset, + child_is_base_class, + tmp_child_is_deref_of_parent); + } + else + { + child_is_deref_of_parent = true; + if (parent_name) { - child_is_deref_of_parent = false; - bool tmp_child_is_deref_of_parent = false; - return GetChildClangTypeAtIndex (exe_ctx, - ast, - parent_name, - pointer_type->getPointeeType().getAsOpaquePtr(), - idx, - transparent_pointers, - omit_empty_base_classes, - ignore_array_bounds, - child_name, - child_byte_size, - child_byte_offset, - child_bitfield_bit_size, - child_bitfield_bit_offset, - child_is_base_class, - tmp_child_is_deref_of_parent); + child_name.assign(1, '*'); + child_name += parent_name; } - else - { - child_is_deref_of_parent = true; - if (parent_name) - { - child_name.assign(1, '*'); - child_name += parent_name; - } - // We have a pointer to an simple type - if (idx == 0 && GetCompleteQualType(ast, pointee_type)) - { - std::pair<uint64_t, unsigned> clang_type_info = ast->getTypeInfo(pointee_type); - assert(clang_type_info.first % 8 == 0); - child_byte_size = clang_type_info.first / 8; - child_byte_offset = 0; - return pointee_type.getAsOpaquePtr(); - } + // We have a pointer to an simple type + if (idx == 0 && GetCompleteQualType(ast, pointee_type)) + { + std::pair<uint64_t, unsigned> clang_type_info = ast->getTypeInfo(pointee_type); + assert(clang_type_info.first % 8 == 0); + child_byte_size = clang_type_info.first / 8; + child_byte_offset = 0; + return pointee_type.getAsOpaquePtr(); } } - break; + } + break; case clang::Type::ConstantArray: + case clang::Type::IncompleteArray: + if (ignore_array_bounds || idx_is_valid) { - const ConstantArrayType *array = cast<ConstantArrayType>(parent_qual_type.getTypePtr()); - const uint64_t element_count = array->getSize().getLimitedValue(); - - if (ignore_array_bounds || idx < element_count) + const ArrayType *array = cast<ArrayType>(parent_qual_type.getTypePtr()); + if (array) { if (GetCompleteQualType (ast, array->getElementType())) { std::pair<uint64_t, unsigned> field_type_info = ast->getTypeInfo(array->getElementType()); - + char element_name[64]; ::snprintf (element_name, sizeof (element_name), "[%u]", idx); - + child_name.assign(element_name); assert(field_type_info.first % 8 == 0); child_byte_size = field_type_info.first / 8; @@ -4159,144 +4171,146 @@ ClangASTContext::GetChildClangTypeAtIndex } } break; + - case clang::Type::Pointer: + case clang::Type::Pointer: + if (idx_is_valid) + { + const PointerType *pointer_type = cast<PointerType>(parent_qual_type.getTypePtr()); + QualType pointee_type = pointer_type->getPointeeType(); + + // Don't dereference "void *" pointers + if (pointee_type->isVoidType()) + return NULL; + + if (transparent_pointers && ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) { - const PointerType *pointer_type = cast<PointerType>(parent_qual_type.getTypePtr()); - QualType pointee_type = pointer_type->getPointeeType(); - - // Don't dereference "void *" pointers - if (pointee_type->isVoidType()) - return NULL; + child_is_deref_of_parent = false; + bool tmp_child_is_deref_of_parent = false; + return GetChildClangTypeAtIndex (exe_ctx, + ast, + parent_name, + pointer_type->getPointeeType().getAsOpaquePtr(), + idx, + transparent_pointers, + omit_empty_base_classes, + ignore_array_bounds, + child_name, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset, + child_is_base_class, + tmp_child_is_deref_of_parent); + } + else + { + child_is_deref_of_parent = true; - if (transparent_pointers && ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) + if (parent_name) { - child_is_deref_of_parent = false; - bool tmp_child_is_deref_of_parent = false; - return GetChildClangTypeAtIndex (exe_ctx, - ast, - parent_name, - pointer_type->getPointeeType().getAsOpaquePtr(), - idx, - transparent_pointers, - omit_empty_base_classes, - ignore_array_bounds, - child_name, - child_byte_size, - child_byte_offset, - child_bitfield_bit_size, - child_bitfield_bit_offset, - child_is_base_class, - tmp_child_is_deref_of_parent); + child_name.assign(1, '*'); + child_name += parent_name; } - else - { - child_is_deref_of_parent = true; - if (parent_name) - { - child_name.assign(1, '*'); - child_name += parent_name; - } - - // We have a pointer to an simple type - if (idx == 0) - { - std::pair<uint64_t, unsigned> clang_type_info = ast->getTypeInfo(pointee_type); - assert(clang_type_info.first % 8 == 0); - child_byte_size = clang_type_info.first / 8; - child_byte_offset = 0; - return pointee_type.getAsOpaquePtr(); - } + // We have a pointer to an simple type + if (idx == 0) + { + std::pair<uint64_t, unsigned> clang_type_info = ast->getTypeInfo(pointee_type); + assert(clang_type_info.first % 8 == 0); + child_byte_size = clang_type_info.first / 8; + child_byte_offset = 0; + return pointee_type.getAsOpaquePtr(); } } - break; + } + break; - case clang::Type::LValueReference: - case clang::Type::RValueReference: + case clang::Type::LValueReference: + case clang::Type::RValueReference: + if (idx_is_valid) + { + const ReferenceType *reference_type = cast<ReferenceType>(parent_qual_type.getTypePtr()); + QualType pointee_type(reference_type->getPointeeType()); + clang_type_t pointee_clang_type = pointee_type.getAsOpaquePtr(); + if (transparent_pointers && ClangASTContext::IsAggregateType (pointee_clang_type)) + { + child_is_deref_of_parent = false; + bool tmp_child_is_deref_of_parent = false; + return GetChildClangTypeAtIndex (exe_ctx, + ast, + parent_name, + pointee_clang_type, + idx, + transparent_pointers, + omit_empty_base_classes, + ignore_array_bounds, + child_name, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset, + child_is_base_class, + tmp_child_is_deref_of_parent); + } + else { - const ReferenceType *reference_type = cast<ReferenceType>(parent_qual_type.getTypePtr()); - QualType pointee_type(reference_type->getPointeeType()); - clang_type_t pointee_clang_type = pointee_type.getAsOpaquePtr(); - if (transparent_pointers && ClangASTContext::IsAggregateType (pointee_clang_type)) + if (parent_name) { - child_is_deref_of_parent = false; - bool tmp_child_is_deref_of_parent = false; - return GetChildClangTypeAtIndex (exe_ctx, - ast, - parent_name, - pointee_clang_type, - idx, - transparent_pointers, - omit_empty_base_classes, - ignore_array_bounds, - child_name, - child_byte_size, - child_byte_offset, - child_bitfield_bit_size, - child_bitfield_bit_offset, - child_is_base_class, - tmp_child_is_deref_of_parent); + child_name.assign(1, '&'); + child_name += parent_name; } - else - { - if (parent_name) - { - child_name.assign(1, '&'); - child_name += parent_name; - } - // We have a pointer to an simple type - if (idx == 0) - { - std::pair<uint64_t, unsigned> clang_type_info = ast->getTypeInfo(pointee_type); - assert(clang_type_info.first % 8 == 0); - child_byte_size = clang_type_info.first / 8; - child_byte_offset = 0; - return pointee_type.getAsOpaquePtr(); - } + // We have a pointer to an simple type + if (idx == 0) + { + std::pair<uint64_t, unsigned> clang_type_info = ast->getTypeInfo(pointee_type); + assert(clang_type_info.first % 8 == 0); + child_byte_size = clang_type_info.first / 8; + child_byte_offset = 0; + return pointee_type.getAsOpaquePtr(); } } - break; + } + break; - case clang::Type::Typedef: - return GetChildClangTypeAtIndex (exe_ctx, - ast, - parent_name, - cast<TypedefType>(parent_qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), - idx, - transparent_pointers, - omit_empty_base_classes, - ignore_array_bounds, - child_name, - child_byte_size, - child_byte_offset, - child_bitfield_bit_size, - child_bitfield_bit_offset, - child_is_base_class, - child_is_deref_of_parent); - break; - - case clang::Type::Elaborated: - return GetChildClangTypeAtIndex (exe_ctx, - ast, - parent_name, - cast<ElaboratedType>(parent_qual_type)->getNamedType().getAsOpaquePtr(), - idx, - transparent_pointers, - omit_empty_base_classes, - ignore_array_bounds, - child_name, - child_byte_size, - child_byte_offset, - child_bitfield_bit_size, - child_bitfield_bit_offset, - child_is_base_class, - child_is_deref_of_parent); + case clang::Type::Typedef: + return GetChildClangTypeAtIndex (exe_ctx, + ast, + parent_name, + cast<TypedefType>(parent_qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), + idx, + transparent_pointers, + omit_empty_base_classes, + ignore_array_bounds, + child_name, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset, + child_is_base_class, + child_is_deref_of_parent); + break; - default: - break; - } + case clang::Type::Elaborated: + return GetChildClangTypeAtIndex (exe_ctx, + ast, + parent_name, + cast<ElaboratedType>(parent_qual_type)->getNamedType().getAsOpaquePtr(), + idx, + transparent_pointers, + omit_empty_base_classes, + ignore_array_bounds, + child_name, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset, + child_is_base_class, + child_is_deref_of_parent); + + default: + break; } return NULL; } @@ -5250,17 +5264,27 @@ ClangASTContext::SetFunctionParameters (FunctionDecl *function_decl, ParmVarDecl #pragma mark Array Types clang_type_t -ClangASTContext::CreateArrayType (clang_type_t element_type, size_t element_count, uint32_t bit_stride) +ClangASTContext::CreateArrayType (clang_type_t element_type, size_t element_count) { if (element_type) { ASTContext *ast = getASTContext(); assert (ast != NULL); llvm::APInt ap_element_count (64, element_count); - return ast->getConstantArrayType(QualType::getFromOpaquePtr(element_type), - ap_element_count, - ArrayType::Normal, - 0).getAsOpaquePtr(); // ElemQuals + if (element_count == 0) + { + return ast->getIncompleteArrayType(QualType::getFromOpaquePtr(element_type), + ArrayType::Normal, + 0).getAsOpaquePtr(); + + } + else + { + return ast->getConstantArrayType(QualType::getFromOpaquePtr(element_type), + ap_element_count, + ArrayType::Normal, + 0).getAsOpaquePtr(); // ElemQuals + } } return NULL; } @@ -5931,7 +5955,7 @@ ClangASTContext::IsPointerToScalarType (lldb::clang_type_t clang_type) bool ClangASTContext::IsArrayOfScalarType (lldb::clang_type_t clang_type) { - clang_type = GetAsArrayType(clang_type); + clang_type = GetAsArrayType(clang_type, NULL, NULL, NULL); if (clang_type == 0) return false; @@ -6151,8 +6175,10 @@ ClangASTContext::GetArraySize (clang_type_t clang_type) } clang_type_t -ClangASTContext::GetAsArrayType (clang_type_t clang_type, clang_type_t*member_type, uint64_t *size) +ClangASTContext::GetAsArrayType (clang_type_t clang_type, clang_type_t*member_type, uint64_t *size, bool *is_incomplete) { + if (is_incomplete) + *is_incomplete = false; if (!clang_type) return 0; @@ -6176,6 +6202,8 @@ ClangASTContext::GetAsArrayType (clang_type_t clang_type, clang_type_t*member_ty *member_type = cast<IncompleteArrayType>(qual_type)->getElementType().getAsOpaquePtr(); if (size) *size = 0; + if (is_incomplete) + *is_incomplete = true; return clang_type; case clang::Type::VariableArray: @@ -6195,12 +6223,14 @@ ClangASTContext::GetAsArrayType (clang_type_t clang_type, clang_type_t*member_ty case clang::Type::Typedef: return ClangASTContext::GetAsArrayType (cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), member_type, - size); + size, + is_incomplete); case clang::Type::Elaborated: return ClangASTContext::GetAsArrayType (cast<ElaboratedType>(qual_type)->getNamedType().getAsOpaquePtr(), member_type, - size); + size, + is_incomplete); } return 0; } diff --git a/lldb/source/Symbol/ClangASTType.cpp b/lldb/source/Symbol/ClangASTType.cpp index 8c4ac4fb680..1037aaa7625 100644 --- a/lldb/source/Symbol/ClangASTType.cpp +++ b/lldb/source/Symbol/ClangASTType.cpp @@ -1178,7 +1178,13 @@ ClangASTType::GetClangTypeBitWidth (clang::ASTContext *ast_context, clang_type_t if (ClangASTContext::GetCompleteType (ast_context, clang_type)) { clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type)); - return ast_context->getTypeSize (qual_type); + const uint32_t bit_size = ast_context->getTypeSize (qual_type); + if (bit_size == 0) + { + if (qual_type->isIncompleteArrayType()) + return ast_context->getTypeSize (qual_type->getArrayElementTypeNoTypeQual()->getCanonicalTypeUnqualified()); + } + return bit_size; } return 0; } diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp index d95141da6e6..fd95882d15a 100644 --- a/lldb/source/Target/StackFrame.cpp +++ b/lldb/source/Target/StackFrame.cpp @@ -792,6 +792,7 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, deref = false; } + bool is_incomplete_array = false; if (valobj_sp->IsPointerType ()) { bool is_objc_pointer = true; @@ -855,11 +856,14 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, } } } - else if (ClangASTContext::IsArrayType (valobj_sp->GetClangType(), NULL, NULL)) + else if (ClangASTContext::IsArrayType (valobj_sp->GetClangType(), NULL, NULL, &is_incomplete_array)) { // Pass false to dynamic_value here so we can tell the difference between // no dynamic value and no member of this type... child_valobj_sp = valobj_sp->GetChildAtIndex (child_index, true); + if (!child_valobj_sp && (is_incomplete_array || no_synth_child == false)) + child_valobj_sp = valobj_sp->GetSyntheticArrayMember (child_index, true); + if (!child_valobj_sp) { valobj_sp->GetExpressionPath (var_expr_path_strm, false); diff --git a/lldb/test/lang/c/struct_types/TestStructTypes.py b/lldb/test/lang/c/struct_types/TestStructTypes.py index f3938625c7a..b83e19509c9 100644 --- a/lldb/test/lang/c/struct_types/TestStructTypes.py +++ b/lldb/test/lang/c/struct_types/TestStructTypes.py @@ -14,6 +14,8 @@ class StructTypesTestCase(TestBase): mydir = os.path.join("lang", "c", "struct_types") + # rdar://problem/12566646 + @unittest2.expectedFailure @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") @dsym_test def test_with_dsym(self): @@ -31,19 +33,31 @@ class StructTypesTestCase(TestBase): # Call super's setUp(). TestBase.setUp(self) # Find the line number to break for main.c. - self.line = line_number('main.c', '// Set break point at this line.') - self.first_executable_line = line_number('main.c', + self.source = 'main.c' + self.line = line_number(self.source, '// Set break point at this line.') + self.first_executable_line = line_number(self.source, '// This is the first executable statement.') + self.return_line = line_number(self.source, '// This is the return statement.') def struct_types(self): - """Test that break on a struct declaration has no effect.""" + """Test that break on a struct declaration has no effect and test structure access for zero sized arrays.""" exe = os.path.join(os.getcwd(), "a.out") - self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + # Create a target by the debugger. + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) # Break on the struct declration statement in main.c. lldbutil.run_break_set_by_file_and_line (self, "main.c", self.line, num_expected_locations=1, loc_exact=False) + lldbutil.run_break_set_by_file_and_line (self, "main.c", self.return_line, num_expected_locations=1, loc_exact=True) + + # Now launch the process, and do not stop at entry point. + process = target.LaunchSimple(None, None, os.getcwd()) - self.runCmd("run", RUN_SUCCEEDED) + if not process: + self.fail("SBTarget.Launch() failed") + + thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) # We should be stopped on the first executable statement within the # function where the original breakpoint was attempted. @@ -55,10 +69,26 @@ class StructTypesTestCase(TestBase): self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE, substrs = [' resolved, hit count = 1']) + process.Continue() + thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) + + # Test zero length array access and make sure it succeeds with "frame variable" + self.expect("frame variable pt.padding[0]", + DATA_TYPES_DISPLAYED_CORRECTLY, + substrs = ["pt.padding[0] = '"]) + self.expect("frame variable pt.padding[1]", + DATA_TYPES_DISPLAYED_CORRECTLY, + substrs = ["pt.padding[1] = '"]) + # Test zero length array access and make sure it succeeds with "expression" + self.expect("expression -- pt.padding[0]", + DATA_TYPES_DISPLAYED_CORRECTLY, + substrs = ["(char)", " = '"]) + # The padding should be an array of size 0 self.expect("image lookup -t point_tag", DATA_TYPES_DISPLAYED_CORRECTLY, - substrs = ['padding[0]']) + substrs = ['padding[]']) # Once rdar://problem/12566646 is fixed, this should display correctly + if __name__ == '__main__': diff --git a/lldb/test/lang/c/struct_types/main.c b/lldb/test/lang/c/struct_types/main.c index 174bfccd489..551963134bb 100644 --- a/lldb/test/lang/c/struct_types/main.c +++ b/lldb/test/lang/c/struct_types/main.c @@ -20,5 +20,5 @@ int main (int argc, char const *argv[]) }; struct point_tag pt = { 2, 3, {} }; // This is the first executable statement. struct rect_tag rect = {{1, 2, {}}, {3, 4, {}}}; - return 0; + return 0; // This is the return statement. } |

