[lldb][NFC] Extract single member parsing out of DWARFASTParserClang::ParseChildMembers

ParseChildMembers does a few things, only one part is actually parsing a single
member. This extracts the member parsing logic into its own function.

This commit just moves the code as-is into its own function and forwards the parameters/
local variables to it, which means it should be NFC.

The only actual changes to the code are replacing 'break's (and one very curious 'continue'
that behaves like a 'break') with 'return's.
This commit is contained in:
Raphael Isemann 2019-12-04 09:38:49 +01:00
parent 3b47e6efb9
commit 4d37f18b29
2 changed files with 509 additions and 462 deletions

View File

@ -2448,6 +2448,470 @@ Function *DWARFASTParserClang::ParseFunctionFromDWARF(CompileUnit &comp_unit,
return nullptr;
}
void DWARFASTParserClang::ParseSingleMember(
const DWARFDIE &die, const DWARFDIE &parent_die,
lldb_private::CompilerType &class_clang_type,
const lldb::LanguageType class_language,
std::vector<int> &member_accessibilities,
lldb::AccessType &default_accessibility,
DelayedPropertyList &delayed_properties,
lldb_private::ClangASTImporter::LayoutInfo &layout_info,
BitfieldInfo &last_field_info) {
ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule();
const dw_tag_t tag = die.Tag();
// Get the parent byte size so we can verify any members will fit
const uint64_t parent_byte_size =
parent_die.GetAttributeValueAsUnsigned(DW_AT_byte_size, UINT64_MAX);
const uint64_t parent_bit_size =
parent_byte_size == UINT64_MAX ? UINT64_MAX : parent_byte_size * 8;
DWARFAttributes attributes;
const size_t num_attributes = die.GetAttributes(attributes);
if (num_attributes > 0) {
const char *name = nullptr;
const char *prop_name = nullptr;
const char *prop_getter_name = nullptr;
const char *prop_setter_name = nullptr;
uint32_t prop_attributes = 0;
bool is_artificial = false;
DWARFFormValue encoding_form;
AccessType accessibility = eAccessNone;
uint32_t member_byte_offset =
(parent_die.Tag() == DW_TAG_union_type) ? 0 : UINT32_MAX;
llvm::Optional<uint64_t> byte_size;
int64_t bit_offset = 0;
uint64_t data_bit_offset = UINT64_MAX;
size_t bit_size = 0;
bool is_external =
false; // On DW_TAG_members, this means the member is static
uint32_t i;
for (i = 0; i < num_attributes && !is_artificial; ++i) {
const dw_attr_t attr = attributes.AttributeAtIndex(i);
DWARFFormValue form_value;
if (attributes.ExtractFormValueAtIndex(i, form_value)) {
switch (attr) {
case DW_AT_name:
name = form_value.AsCString();
break;
case DW_AT_type:
encoding_form = form_value;
break;
case DW_AT_bit_offset:
bit_offset = form_value.Signed();
break;
case DW_AT_bit_size:
bit_size = form_value.Unsigned();
break;
case DW_AT_byte_size:
byte_size = form_value.Unsigned();
break;
case DW_AT_data_bit_offset:
data_bit_offset = form_value.Unsigned();
break;
case DW_AT_data_member_location:
if (form_value.BlockData()) {
Value initialValue(0);
Value memberOffset(0);
const DWARFDataExtractor &debug_info_data = die.GetData();
uint32_t block_length = form_value.Unsigned();
uint32_t block_offset =
form_value.BlockData() - debug_info_data.GetDataStart();
if (DWARFExpression::Evaluate(
nullptr, // ExecutionContext *
nullptr, // RegisterContext *
module_sp,
DataExtractor(debug_info_data, block_offset, block_length),
die.GetCU(), eRegisterKindDWARF, &initialValue, nullptr,
memberOffset, nullptr)) {
member_byte_offset = memberOffset.ResolveValue(nullptr).UInt();
}
} else {
// With DWARF 3 and later, if the value is an integer constant,
// this form value is the offset in bytes from the beginning of
// the containing entity.
member_byte_offset = form_value.Unsigned();
}
break;
case DW_AT_accessibility:
accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned());
break;
case DW_AT_artificial:
is_artificial = form_value.Boolean();
break;
case DW_AT_APPLE_property_name:
prop_name = form_value.AsCString();
break;
case DW_AT_APPLE_property_getter:
prop_getter_name = form_value.AsCString();
break;
case DW_AT_APPLE_property_setter:
prop_setter_name = form_value.AsCString();
break;
case DW_AT_APPLE_property_attribute:
prop_attributes = form_value.Unsigned();
break;
case DW_AT_external:
is_external = form_value.Boolean();
break;
default:
case DW_AT_declaration:
case DW_AT_description:
case DW_AT_mutable:
case DW_AT_visibility:
case DW_AT_sibling:
break;
}
}
}
if (prop_name) {
ConstString fixed_getter;
ConstString fixed_setter;
// Check if the property getter/setter were provided as full names.
// We want basenames, so we extract them.
if (prop_getter_name && prop_getter_name[0] == '-') {
ObjCLanguage::MethodName prop_getter_method(prop_getter_name, true);
prop_getter_name = prop_getter_method.GetSelector().GetCString();
}
if (prop_setter_name && prop_setter_name[0] == '-') {
ObjCLanguage::MethodName prop_setter_method(prop_setter_name, true);
prop_setter_name = prop_setter_method.GetSelector().GetCString();
}
// If the names haven't been provided, they need to be filled in.
if (!prop_getter_name) {
prop_getter_name = prop_name;
}
if (!prop_setter_name && prop_name[0] &&
!(prop_attributes & DW_APPLE_PROPERTY_readonly)) {
StreamString ss;
ss.Printf("set%c%s:", toupper(prop_name[0]), &prop_name[1]);
fixed_setter.SetString(ss.GetString());
prop_setter_name = fixed_setter.GetCString();
}
}
// Clang has a DWARF generation bug where sometimes it represents
// fields that are references with bad byte size and bit size/offset
// information such as:
//
// DW_AT_byte_size( 0x00 )
// DW_AT_bit_size( 0x40 )
// DW_AT_bit_offset( 0xffffffffffffffc0 )
//
// So check the bit offset to make sure it is sane, and if the values
// are not sane, remove them. If we don't do this then we will end up
// with a crash if we try to use this type in an expression when clang
// becomes unhappy with its recycled debug info.
if (byte_size.getValueOr(0) == 0 && bit_offset < 0) {
bit_size = 0;
bit_offset = 0;
}
// FIXME: Make Clang ignore Objective-C accessibility for expressions
if (class_language == eLanguageTypeObjC ||
class_language == eLanguageTypeObjC_plus_plus)
accessibility = eAccessNone;
// Handle static members
if (is_external && member_byte_offset == UINT32_MAX) {
Type *var_type = die.ResolveTypeUID(encoding_form.Reference());
if (var_type) {
if (accessibility == eAccessNone)
accessibility = eAccessPublic;
ClangASTContext::AddVariableToRecordType(
class_clang_type, name, var_type->GetLayoutCompilerType(),
accessibility);
}
return;
}
if (!is_artificial) {
Type *member_type = die.ResolveTypeUID(encoding_form.Reference());
clang::FieldDecl *field_decl = nullptr;
if (tag == DW_TAG_member) {
if (member_type) {
if (accessibility == eAccessNone)
accessibility = default_accessibility;
member_accessibilities.push_back(accessibility);
uint64_t field_bit_offset =
(member_byte_offset == UINT32_MAX ? 0 : (member_byte_offset * 8));
if (bit_size > 0) {
BitfieldInfo this_field_info;
this_field_info.bit_offset = field_bit_offset;
this_field_info.bit_size = bit_size;
/////////////////////////////////////////////////////////////
// How to locate a field given the DWARF debug information
//
// AT_byte_size indicates the size of the word in which the bit
// offset must be interpreted.
//
// AT_data_member_location indicates the byte offset of the
// word from the base address of the structure.
//
// AT_bit_offset indicates how many bits into the word
// (according to the host endianness) the low-order bit of the
// field starts. AT_bit_offset can be negative.
//
// AT_bit_size indicates the size of the field in bits.
/////////////////////////////////////////////////////////////
if (data_bit_offset != UINT64_MAX) {
this_field_info.bit_offset = data_bit_offset;
} else {
if (!byte_size)
byte_size = member_type->GetByteSize();
ObjectFile *objfile = die.GetDWARF()->GetObjectFile();
if (objfile->GetByteOrder() == eByteOrderLittle) {
this_field_info.bit_offset += byte_size.getValueOr(0) * 8;
this_field_info.bit_offset -= (bit_offset + bit_size);
} else {
this_field_info.bit_offset += bit_offset;
}
}
if ((this_field_info.bit_offset >= parent_bit_size) ||
!last_field_info.NextBitfieldOffsetIsValid(
this_field_info.bit_offset)) {
ObjectFile *objfile = die.GetDWARF()->GetObjectFile();
objfile->GetModule()->ReportWarning(
"0x%8.8" PRIx64 ": %s bitfield named \"%s\" has invalid "
"bit offset (0x%8.8" PRIx64
") member will be ignored. Please file a bug against the "
"compiler and include the preprocessed output for %s\n",
die.GetID(), DW_TAG_value_to_name(tag), name,
this_field_info.bit_offset, GetUnitName(parent_die).c_str());
this_field_info.Clear();
return;
}
// Update the field bit offset we will report for layout
field_bit_offset = this_field_info.bit_offset;
// If the member to be emitted did not start on a character
// boundary and there is empty space between the last field and
// this one, then we need to emit an anonymous member filling
// up the space up to its start. There are three cases here:
//
// 1 If the previous member ended on a character boundary, then
// we can emit an
// anonymous member starting at the most recent character
// boundary.
//
// 2 If the previous member did not end on a character boundary
// and the distance
// from the end of the previous member to the current member
// is less than a
// word width, then we can emit an anonymous member starting
// right after the
// previous member and right before this member.
//
// 3 If the previous member did not end on a character boundary
// and the distance
// from the end of the previous member to the current member
// is greater than
// or equal a word width, then we act as in Case 1.
const uint64_t character_width = 8;
const uint64_t word_width = 32;
// Objective-C has invalid DW_AT_bit_offset values in older
// versions of clang, so we have to be careful and only insert
// unnamed bitfields if we have a new enough clang.
bool detect_unnamed_bitfields = true;
if (class_language == eLanguageTypeObjC ||
class_language == eLanguageTypeObjC_plus_plus)
detect_unnamed_bitfields =
die.GetCU()->Supports_unnamed_objc_bitfields();
if (detect_unnamed_bitfields) {
BitfieldInfo anon_field_info;
if ((this_field_info.bit_offset % character_width) !=
0) // not char aligned
{
uint64_t last_field_end = 0;
if (last_field_info.IsValid())
last_field_end =
last_field_info.bit_offset + last_field_info.bit_size;
if (this_field_info.bit_offset != last_field_end) {
if (((last_field_end % character_width) == 0) || // case 1
(this_field_info.bit_offset - last_field_end >=
word_width)) // case 3
{
anon_field_info.bit_size =
this_field_info.bit_offset % character_width;
anon_field_info.bit_offset =
this_field_info.bit_offset - anon_field_info.bit_size;
} else // case 2
{
anon_field_info.bit_size =
this_field_info.bit_offset - last_field_end;
anon_field_info.bit_offset = last_field_end;
}
}
}
if (anon_field_info.IsValid()) {
clang::FieldDecl *unnamed_bitfield_decl =
ClangASTContext::AddFieldToRecordType(
class_clang_type, llvm::StringRef(),
m_ast.GetBuiltinTypeForEncodingAndBitSize(eEncodingSint,
word_width),
accessibility, anon_field_info.bit_size);
layout_info.field_offsets.insert(std::make_pair(
unnamed_bitfield_decl, anon_field_info.bit_offset));
}
}
last_field_info = this_field_info;
} else {
last_field_info.Clear();
}
CompilerType member_clang_type = member_type->GetLayoutCompilerType();
if (!member_clang_type.IsCompleteType())
member_clang_type.GetCompleteType();
{
// Older versions of clang emit array[0] and array[1] in the
// same way (<rdar://problem/12566646>). If the current field
// is at the end of the structure, then there is definitely no
// room for extra elements and we override the type to
// array[0].
CompilerType member_array_element_type;
uint64_t member_array_size;
bool member_array_is_incomplete;
if (member_clang_type.IsArrayType(&member_array_element_type,
&member_array_size,
&member_array_is_incomplete) &&
!member_array_is_incomplete) {
uint64_t parent_byte_size =
parent_die.GetAttributeValueAsUnsigned(DW_AT_byte_size,
UINT64_MAX);
if (member_byte_offset >= parent_byte_size) {
if (member_array_size != 1 &&
(member_array_size != 0 ||
member_byte_offset > parent_byte_size)) {
module_sp->ReportError(
"0x%8.8" PRIx64
": DW_TAG_member '%s' refers to type 0x%8.8x"
" which extends beyond the bounds of 0x%8.8" PRIx64,
die.GetID(), name, encoding_form.Reference().GetOffset(),
parent_die.GetID());
}
member_clang_type =
m_ast.CreateArrayType(member_array_element_type, 0, false);
}
}
}
if (ClangASTContext::IsCXXClassType(member_clang_type) &&
!member_clang_type.GetCompleteType()) {
if (die.GetCU()->GetProducer() == eProducerClang)
module_sp->ReportError(
"DWARF DIE at 0x%8.8x (class %s) has a member variable "
"0x%8.8x (%s) whose type is a forward declaration, not a "
"complete definition.\nTry compiling the source file "
"with -fstandalone-debug",
parent_die.GetOffset(), parent_die.GetName(), die.GetOffset(),
name);
else
module_sp->ReportError(
"DWARF DIE at 0x%8.8x (class %s) has a member variable "
"0x%8.8x (%s) whose type is a forward declaration, not a "
"complete definition.\nPlease file a bug against the "
"compiler and include the preprocessed output for %s",
parent_die.GetOffset(), parent_die.GetName(), die.GetOffset(),
name, GetUnitName(parent_die).c_str());
// We have no choice other than to pretend that the member
// class is complete. If we don't do this, clang will crash
// when trying to layout the class. Since we provide layout
// assistance, all ivars in this class and other classes will
// be fine, this is the best we can do short of crashing.
if (ClangASTContext::StartTagDeclarationDefinition(
member_clang_type)) {
ClangASTContext::CompleteTagDeclarationDefinition(
member_clang_type);
} else {
module_sp->ReportError(
"DWARF DIE at 0x%8.8x (class %s) has a member variable "
"0x%8.8x (%s) whose type claims to be a C++ class but we "
"were not able to start its definition.\nPlease file a "
"bug and attach the file at the start of this error "
"message",
parent_die.GetOffset(), parent_die.GetName(), die.GetOffset(),
name);
}
}
field_decl = ClangASTContext::AddFieldToRecordType(
class_clang_type, name, member_clang_type, accessibility,
bit_size);
m_ast.SetMetadataAsUserID(field_decl, die.GetID());
layout_info.field_offsets.insert(
std::make_pair(field_decl, field_bit_offset));
} else {
if (name)
module_sp->ReportError(
"0x%8.8" PRIx64 ": DW_TAG_member '%s' refers to type 0x%8.8x"
" which was unable to be parsed",
die.GetID(), name, encoding_form.Reference().GetOffset());
else
module_sp->ReportError(
"0x%8.8" PRIx64 ": DW_TAG_member refers to type 0x%8.8x"
" which was unable to be parsed",
die.GetID(), encoding_form.Reference().GetOffset());
}
}
if (prop_name != nullptr && member_type) {
clang::ObjCIvarDecl *ivar_decl = nullptr;
if (field_decl) {
ivar_decl = clang::dyn_cast<clang::ObjCIvarDecl>(field_decl);
assert(ivar_decl != nullptr);
}
ClangASTMetadata metadata;
metadata.SetUserID(die.GetID());
delayed_properties.push_back(DelayedAddObjCClassProperty(
class_clang_type, prop_name, member_type->GetLayoutCompilerType(),
ivar_decl, prop_setter_name, prop_getter_name, prop_attributes,
&metadata));
if (ivar_decl)
m_ast.SetMetadataAsUserID(ivar_decl, die.GetID());
}
}
}
}
bool DWARFASTParserClang::ParseChildMembers(
const DWARFDIE &parent_die, CompilerType &class_clang_type,
const LanguageType class_language,
@ -2459,12 +2923,6 @@ bool DWARFASTParserClang::ParseChildMembers(
if (!parent_die)
return false;
// Get the parent byte size so we can verify any members will fit
const uint64_t parent_byte_size =
parent_die.GetAttributeValueAsUnsigned(DW_AT_byte_size, UINT64_MAX);
const uint64_t parent_bit_size =
parent_byte_size == UINT64_MAX ? UINT64_MAX : parent_byte_size * 8;
BitfieldInfo last_field_info;
ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule();
@ -2479,462 +2937,11 @@ bool DWARFASTParserClang::ParseChildMembers(
switch (tag) {
case DW_TAG_member:
case DW_TAG_APPLE_property: {
DWARFAttributes attributes;
const size_t num_attributes = die.GetAttributes(attributes);
if (num_attributes > 0) {
const char *name = nullptr;
const char *prop_name = nullptr;
const char *prop_getter_name = nullptr;
const char *prop_setter_name = nullptr;
uint32_t prop_attributes = 0;
bool is_artificial = false;
DWARFFormValue encoding_form;
AccessType accessibility = eAccessNone;
uint32_t member_byte_offset =
(parent_die.Tag() == DW_TAG_union_type) ? 0 : UINT32_MAX;
llvm::Optional<uint64_t> byte_size;
int64_t bit_offset = 0;
uint64_t data_bit_offset = UINT64_MAX;
size_t bit_size = 0;
bool is_external =
false; // On DW_TAG_members, this means the member is static
uint32_t i;
for (i = 0; i < num_attributes && !is_artificial; ++i) {
const dw_attr_t attr = attributes.AttributeAtIndex(i);
DWARFFormValue form_value;
if (attributes.ExtractFormValueAtIndex(i, form_value)) {
switch (attr) {
case DW_AT_name:
name = form_value.AsCString();
break;
case DW_AT_type:
encoding_form = form_value;
break;
case DW_AT_bit_offset:
bit_offset = form_value.Signed();
break;
case DW_AT_bit_size:
bit_size = form_value.Unsigned();
break;
case DW_AT_byte_size:
byte_size = form_value.Unsigned();
break;
case DW_AT_data_bit_offset:
data_bit_offset = form_value.Unsigned();
break;
case DW_AT_data_member_location:
if (form_value.BlockData()) {
Value initialValue(0);
Value memberOffset(0);
const DWARFDataExtractor &debug_info_data = die.GetData();
uint32_t block_length = form_value.Unsigned();
uint32_t block_offset =
form_value.BlockData() - debug_info_data.GetDataStart();
if (DWARFExpression::Evaluate(
nullptr, // ExecutionContext *
nullptr, // RegisterContext *
module_sp,
DataExtractor(debug_info_data, block_offset,
block_length),
die.GetCU(), eRegisterKindDWARF, &initialValue, nullptr,
memberOffset, nullptr)) {
member_byte_offset =
memberOffset.ResolveValue(nullptr).UInt();
}
} else {
// With DWARF 3 and later, if the value is an integer constant,
// this form value is the offset in bytes from the beginning of
// the containing entity.
member_byte_offset = form_value.Unsigned();
}
break;
case DW_AT_accessibility:
accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned());
break;
case DW_AT_artificial:
is_artificial = form_value.Boolean();
break;
case DW_AT_APPLE_property_name:
prop_name = form_value.AsCString();
break;
case DW_AT_APPLE_property_getter:
prop_getter_name = form_value.AsCString();
break;
case DW_AT_APPLE_property_setter:
prop_setter_name = form_value.AsCString();
break;
case DW_AT_APPLE_property_attribute:
prop_attributes = form_value.Unsigned();
break;
case DW_AT_external:
is_external = form_value.Boolean();
break;
default:
case DW_AT_declaration:
case DW_AT_description:
case DW_AT_mutable:
case DW_AT_visibility:
case DW_AT_sibling:
break;
}
}
}
if (prop_name) {
ConstString fixed_getter;
ConstString fixed_setter;
// Check if the property getter/setter were provided as full names.
// We want basenames, so we extract them.
if (prop_getter_name && prop_getter_name[0] == '-') {
ObjCLanguage::MethodName prop_getter_method(prop_getter_name, true);
prop_getter_name = prop_getter_method.GetSelector().GetCString();
}
if (prop_setter_name && prop_setter_name[0] == '-') {
ObjCLanguage::MethodName prop_setter_method(prop_setter_name, true);
prop_setter_name = prop_setter_method.GetSelector().GetCString();
}
// If the names haven't been provided, they need to be filled in.
if (!prop_getter_name) {
prop_getter_name = prop_name;
}
if (!prop_setter_name && prop_name[0] &&
!(prop_attributes & DW_APPLE_PROPERTY_readonly)) {
StreamString ss;
ss.Printf("set%c%s:", toupper(prop_name[0]), &prop_name[1]);
fixed_setter.SetString(ss.GetString());
prop_setter_name = fixed_setter.GetCString();
}
}
// Clang has a DWARF generation bug where sometimes it represents
// fields that are references with bad byte size and bit size/offset
// information such as:
//
// DW_AT_byte_size( 0x00 )
// DW_AT_bit_size( 0x40 )
// DW_AT_bit_offset( 0xffffffffffffffc0 )
//
// So check the bit offset to make sure it is sane, and if the values
// are not sane, remove them. If we don't do this then we will end up
// with a crash if we try to use this type in an expression when clang
// becomes unhappy with its recycled debug info.
if (byte_size.getValueOr(0) == 0 && bit_offset < 0) {
bit_size = 0;
bit_offset = 0;
}
// FIXME: Make Clang ignore Objective-C accessibility for expressions
if (class_language == eLanguageTypeObjC ||
class_language == eLanguageTypeObjC_plus_plus)
accessibility = eAccessNone;
// Handle static members
if (is_external && member_byte_offset == UINT32_MAX) {
Type *var_type = die.ResolveTypeUID(encoding_form.Reference());
if (var_type) {
if (accessibility == eAccessNone)
accessibility = eAccessPublic;
ClangASTContext::AddVariableToRecordType(
class_clang_type, name, var_type->GetLayoutCompilerType(),
accessibility);
}
break;
}
if (!is_artificial) {
Type *member_type = die.ResolveTypeUID(encoding_form.Reference());
clang::FieldDecl *field_decl = nullptr;
if (tag == DW_TAG_member) {
if (member_type) {
if (accessibility == eAccessNone)
accessibility = default_accessibility;
member_accessibilities.push_back(accessibility);
uint64_t field_bit_offset =
(member_byte_offset == UINT32_MAX ? 0
: (member_byte_offset * 8));
if (bit_size > 0) {
BitfieldInfo this_field_info;
this_field_info.bit_offset = field_bit_offset;
this_field_info.bit_size = bit_size;
/////////////////////////////////////////////////////////////
// How to locate a field given the DWARF debug information
//
// AT_byte_size indicates the size of the word in which the bit
// offset must be interpreted.
//
// AT_data_member_location indicates the byte offset of the
// word from the base address of the structure.
//
// AT_bit_offset indicates how many bits into the word
// (according to the host endianness) the low-order bit of the
// field starts. AT_bit_offset can be negative.
//
// AT_bit_size indicates the size of the field in bits.
/////////////////////////////////////////////////////////////
if (data_bit_offset != UINT64_MAX) {
this_field_info.bit_offset = data_bit_offset;
} else {
if (!byte_size)
byte_size = member_type->GetByteSize();
ObjectFile *objfile = die.GetDWARF()->GetObjectFile();
if (objfile->GetByteOrder() == eByteOrderLittle) {
this_field_info.bit_offset += byte_size.getValueOr(0) * 8;
this_field_info.bit_offset -= (bit_offset + bit_size);
} else {
this_field_info.bit_offset += bit_offset;
}
}
if ((this_field_info.bit_offset >= parent_bit_size) ||
!last_field_info.NextBitfieldOffsetIsValid(
this_field_info.bit_offset)) {
ObjectFile *objfile = die.GetDWARF()->GetObjectFile();
objfile->GetModule()->ReportWarning(
"0x%8.8" PRIx64 ": %s bitfield named \"%s\" has invalid "
"bit offset (0x%8.8" PRIx64
") member will be ignored. Please file a bug against the "
"compiler and include the preprocessed output for %s\n",
die.GetID(), DW_TAG_value_to_name(tag), name,
this_field_info.bit_offset,
GetUnitName(parent_die).c_str());
this_field_info.Clear();
continue;
}
// Update the field bit offset we will report for layout
field_bit_offset = this_field_info.bit_offset;
// If the member to be emitted did not start on a character
// boundary and there is empty space between the last field and
// this one, then we need to emit an anonymous member filling
// up the space up to its start. There are three cases here:
//
// 1 If the previous member ended on a character boundary, then
// we can emit an
// anonymous member starting at the most recent character
// boundary.
//
// 2 If the previous member did not end on a character boundary
// and the distance
// from the end of the previous member to the current member
// is less than a
// word width, then we can emit an anonymous member starting
// right after the
// previous member and right before this member.
//
// 3 If the previous member did not end on a character boundary
// and the distance
// from the end of the previous member to the current member
// is greater than
// or equal a word width, then we act as in Case 1.
const uint64_t character_width = 8;
const uint64_t word_width = 32;
// Objective-C has invalid DW_AT_bit_offset values in older
// versions of clang, so we have to be careful and only insert
// unnamed bitfields if we have a new enough clang.
bool detect_unnamed_bitfields = true;
if (class_language == eLanguageTypeObjC ||
class_language == eLanguageTypeObjC_plus_plus)
detect_unnamed_bitfields =
die.GetCU()->Supports_unnamed_objc_bitfields();
if (detect_unnamed_bitfields) {
BitfieldInfo anon_field_info;
if ((this_field_info.bit_offset % character_width) !=
0) // not char aligned
{
uint64_t last_field_end = 0;
if (last_field_info.IsValid())
last_field_end =
last_field_info.bit_offset + last_field_info.bit_size;
if (this_field_info.bit_offset != last_field_end) {
if (((last_field_end % character_width) == 0) || // case 1
(this_field_info.bit_offset - last_field_end >=
word_width)) // case 3
{
anon_field_info.bit_size =
this_field_info.bit_offset % character_width;
anon_field_info.bit_offset =
this_field_info.bit_offset -
anon_field_info.bit_size;
} else // case 2
{
anon_field_info.bit_size =
this_field_info.bit_offset - last_field_end;
anon_field_info.bit_offset = last_field_end;
}
}
}
if (anon_field_info.IsValid()) {
clang::FieldDecl *unnamed_bitfield_decl =
ClangASTContext::AddFieldToRecordType(
class_clang_type, llvm::StringRef(),
m_ast.GetBuiltinTypeForEncodingAndBitSize(
eEncodingSint, word_width),
accessibility, anon_field_info.bit_size);
layout_info.field_offsets.insert(std::make_pair(
unnamed_bitfield_decl, anon_field_info.bit_offset));
}
}
last_field_info = this_field_info;
} else {
last_field_info.Clear();
}
CompilerType member_clang_type =
member_type->GetLayoutCompilerType();
if (!member_clang_type.IsCompleteType())
member_clang_type.GetCompleteType();
{
// Older versions of clang emit array[0] and array[1] in the
// same way (<rdar://problem/12566646>). If the current field
// is at the end of the structure, then there is definitely no
// room for extra elements and we override the type to
// array[0].
CompilerType member_array_element_type;
uint64_t member_array_size;
bool member_array_is_incomplete;
if (member_clang_type.IsArrayType(
&member_array_element_type, &member_array_size,
&member_array_is_incomplete) &&
!member_array_is_incomplete) {
uint64_t parent_byte_size =
parent_die.GetAttributeValueAsUnsigned(DW_AT_byte_size,
UINT64_MAX);
if (member_byte_offset >= parent_byte_size) {
if (member_array_size != 1 &&
(member_array_size != 0 ||
member_byte_offset > parent_byte_size)) {
module_sp->ReportError(
"0x%8.8" PRIx64
": DW_TAG_member '%s' refers to type 0x%8.8x"
" which extends beyond the bounds of 0x%8.8" PRIx64,
die.GetID(), name,
encoding_form.Reference().GetOffset(),
parent_die.GetID());
}
member_clang_type = m_ast.CreateArrayType(
member_array_element_type, 0, false);
}
}
}
if (ClangASTContext::IsCXXClassType(member_clang_type) &&
!member_clang_type.GetCompleteType()) {
if (die.GetCU()->GetProducer() == eProducerClang)
module_sp->ReportError(
"DWARF DIE at 0x%8.8x (class %s) has a member variable "
"0x%8.8x (%s) whose type is a forward declaration, not a "
"complete definition.\nTry compiling the source file "
"with -fstandalone-debug",
parent_die.GetOffset(), parent_die.GetName(),
die.GetOffset(), name);
else
module_sp->ReportError(
"DWARF DIE at 0x%8.8x (class %s) has a member variable "
"0x%8.8x (%s) whose type is a forward declaration, not a "
"complete definition.\nPlease file a bug against the "
"compiler and include the preprocessed output for %s",
parent_die.GetOffset(), parent_die.GetName(),
die.GetOffset(), name, GetUnitName(parent_die).c_str());
// We have no choice other than to pretend that the member
// class is complete. If we don't do this, clang will crash
// when trying to layout the class. Since we provide layout
// assistance, all ivars in this class and other classes will
// be fine, this is the best we can do short of crashing.
if (ClangASTContext::StartTagDeclarationDefinition(
member_clang_type)) {
ClangASTContext::CompleteTagDeclarationDefinition(
member_clang_type);
} else {
module_sp->ReportError(
"DWARF DIE at 0x%8.8x (class %s) has a member variable "
"0x%8.8x (%s) whose type claims to be a C++ class but we "
"were not able to start its definition.\nPlease file a "
"bug and attach the file at the start of this error "
"message",
parent_die.GetOffset(), parent_die.GetName(),
die.GetOffset(), name);
}
}
field_decl = ClangASTContext::AddFieldToRecordType(
class_clang_type, name, member_clang_type, accessibility,
bit_size);
m_ast.SetMetadataAsUserID(field_decl, die.GetID());
layout_info.field_offsets.insert(
std::make_pair(field_decl, field_bit_offset));
} else {
if (name)
module_sp->ReportError(
"0x%8.8" PRIx64
": DW_TAG_member '%s' refers to type 0x%8.8x"
" which was unable to be parsed",
die.GetID(), name, encoding_form.Reference().GetOffset());
else
module_sp->ReportError(
"0x%8.8" PRIx64 ": DW_TAG_member refers to type 0x%8.8x"
" which was unable to be parsed",
die.GetID(), encoding_form.Reference().GetOffset());
}
}
if (prop_name != nullptr && member_type) {
clang::ObjCIvarDecl *ivar_decl = nullptr;
if (field_decl) {
ivar_decl = clang::dyn_cast<clang::ObjCIvarDecl>(field_decl);
assert(ivar_decl != nullptr);
}
ClangASTMetadata metadata;
metadata.SetUserID(die.GetID());
delayed_properties.push_back(DelayedAddObjCClassProperty(
class_clang_type, prop_name,
member_type->GetLayoutCompilerType(), ivar_decl,
prop_setter_name, prop_getter_name, prop_attributes,
&metadata));
if (ivar_decl)
m_ast.SetMetadataAsUserID(ivar_decl, die.GetID());
}
}
}
} break;
case DW_TAG_APPLE_property:
ParseSingleMember(die, parent_die, class_clang_type, class_language,
member_accessibilities, default_accessibility,
delayed_properties, layout_info, last_field_info);
break;
case DW_TAG_subprogram:
// Let the type parsing code handle this one for us.

View File

@ -170,6 +170,46 @@ protected:
lldb::ModuleSP GetModuleForType(const DWARFDIE &die);
private:
struct BitfieldInfo {
uint64_t bit_size;
uint64_t bit_offset;
BitfieldInfo()
: bit_size(LLDB_INVALID_ADDRESS), bit_offset(LLDB_INVALID_ADDRESS) {}
void Clear() {
bit_size = LLDB_INVALID_ADDRESS;
bit_offset = LLDB_INVALID_ADDRESS;
}
bool IsValid() const {
return (bit_size != LLDB_INVALID_ADDRESS) &&
(bit_offset != LLDB_INVALID_ADDRESS);
}
bool NextBitfieldOffsetIsValid(const uint64_t next_bit_offset) const {
if (IsValid()) {
// This bitfield info is valid, so any subsequent bitfields must not
// overlap and must be at a higher bit offset than any previous bitfield
// + size.
return (bit_size + bit_offset) <= next_bit_offset;
} else {
// If the this BitfieldInfo is not valid, then any offset isOK
return true;
}
}
};
void
ParseSingleMember(const DWARFDIE &die, const DWARFDIE &parent_die,
lldb_private::CompilerType &class_clang_type,
const lldb::LanguageType class_language,
std::vector<int> &member_accessibilities,
lldb::AccessType &default_accessibility,
DelayedPropertyList &delayed_properties,
lldb_private::ClangASTImporter::LayoutInfo &layout_info,
BitfieldInfo &last_field_info);
bool CompleteRecordType(const DWARFDIE &die, lldb_private::Type *type,
lldb_private::CompilerType &clang_type);
bool CompleteEnumType(const DWARFDIE &die, lldb_private::Type *type,