/* * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2013, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ #include "DwarfTypeFactory.h" #include #include #include #include #include "ArrayIndexPath.h" #include "Architecture.h" #include "CompilationUnit.h" #include "DebugInfoEntries.h" #include "Dwarf.h" #include "DwarfFile.h" #include "DwarfTargetInterface.h" #include "DwarfUtils.h" #include "DwarfTypes.h" #include "GlobalTypeLookup.h" #include "Register.h" #include "RegisterMap.h" #include "SourceLanguageInfo.h" #include "StringUtils.h" #include "Tracing.h" #include "TypeLookupConstraints.h" #include "ValueLocation.h" namespace { // #pragma mark - HasTypePredicate template struct HasTypePredicate { inline bool operator()(EntryType* entry) const { return entry->GetType() != NULL; } }; // #pragma mark - HasReturnTypePredicate template struct HasReturnTypePredicate { inline bool operator()(EntryType* entry) const { return entry->ReturnType() != NULL; } }; // #pragma mark - HasEnumeratorsPredicate struct HasEnumeratorsPredicate { inline bool operator()(DIEEnumerationType* entry) const { return !entry->Enumerators().IsEmpty(); } }; // #pragma mark - HasDimensionsPredicate struct HasDimensionsPredicate { inline bool operator()(DIEArrayType* entry) const { return !entry->Dimensions().IsEmpty(); } }; // #pragma mark - HasMembersPredicate struct HasMembersPredicate { inline bool operator()(DIECompoundType* entry) const { return !entry->DataMembers().IsEmpty(); } }; // #pragma mark - HasBaseTypesPredicate struct HasBaseTypesPredicate { inline bool operator()(DIEClassBaseType* entry) const { return !entry->BaseTypes().IsEmpty(); } }; // #pragma mark - HasTemplateParametersPredicate struct HasTemplateParametersPredicate { inline bool operator()(DIEClassBaseType* entry) const { return !entry->TemplateParameters().IsEmpty(); } }; // #pragma mark - HasParametersPredicate template struct HasParametersPredicate { inline bool operator()(EntryType* entry) const { return !entry->Parameters().IsEmpty(); } }; // #pragma mark - HasLowerBoundPredicate struct HasLowerBoundPredicate { inline bool operator()(DIESubrangeType* entry) const { return entry->LowerBound()->IsValid(); } }; // #pragma mark - HasUpperBoundPredicate struct HasUpperBoundPredicate { inline bool operator()(DIESubrangeType* entry) const { return entry->UpperBound()->IsValid(); } }; // #pragma mark - HasCountPredicate struct HasCountPredicate { inline bool operator()(DIESubrangeType* entry) const { return entry->Count()->IsValid(); } }; // #pragma mark - HasContainingTypePredicate struct HasContainingTypePredicate { inline bool operator()(DIEPointerToMemberType* entry) const { return entry->ContainingType() != NULL; } }; } // unnamed namespace // #pragma mark - ArtificialIntegerType class DwarfTypeFactory::ArtificialIntegerType : public PrimitiveType { public: ArtificialIntegerType(const BString& id, const BString& name, target_size_t byteSize, uint32 typeConstant) : fID(id), fName(name), fByteSize(byteSize), fTypeConstant(typeConstant) { } static status_t Create(target_size_t byteSize, bool isSigned, Type*& _type) { // get the matching type constant uint32 typeConstant; switch (byteSize) { case 1: typeConstant = isSigned ? B_INT8_TYPE : B_UINT8_TYPE; break; case 2: typeConstant = isSigned ? B_INT16_TYPE : B_UINT16_TYPE; break; case 4: typeConstant = isSigned ? B_INT32_TYPE : B_UINT32_TYPE; break; case 8: typeConstant = isSigned ? B_INT64_TYPE : B_UINT64_TYPE; break; default: return B_BAD_VALUE; } // name and ID char buffer[16]; snprintf(buffer, sizeof(buffer), isSigned ? "int%d" : "uint%d", (int)byteSize * 8); BString id(buffer); if (id.Length() == 0) return B_NO_MEMORY; // create the type ArtificialIntegerType* type = new(std::nothrow) ArtificialIntegerType( id, id, byteSize, typeConstant); if (type == NULL) return B_NO_MEMORY; _type = type; return B_OK; } virtual image_id ImageID() const { return -1; } virtual const BString& ID() const { return fID; } virtual const BString& Name() const { return fName; } virtual target_size_t ByteSize() const { return fByteSize; } virtual status_t ResolveObjectDataLocation( const ValueLocation& objectLocation, ValueLocation*& _location) { // TODO: Implement! return B_UNSUPPORTED; } virtual status_t ResolveObjectDataLocation(target_addr_t objectAddress, ValueLocation*& _location) { // TODO: Implement! return B_UNSUPPORTED; } virtual uint32 TypeConstant() const { return fTypeConstant; } private: BString fID; BString fName; uint32 fByteSize; uint32 fTypeConstant; }; // #pragma mark - DwarfTypeFactory DwarfTypeFactory::DwarfTypeFactory(DwarfTypeContext* typeContext, GlobalTypeLookup* typeLookup, GlobalTypeCache* typeCache) : fTypeContext(typeContext), fTypeLookup(typeLookup), fTypeCache(typeCache) { fTypeContext->AcquireReference(); fTypeCache->AcquireReference(); } DwarfTypeFactory::~DwarfTypeFactory() { fTypeContext->ReleaseReference(); fTypeCache->ReleaseReference(); } status_t DwarfTypeFactory::CreateType(DIEType* typeEntry, DwarfType*& _type) { // try the type cache first BString name; DwarfUtils::GetFullyQualifiedDIEName(typeEntry, name); TypeLookupConstraints constraints( dwarf_tag_to_type_kind(typeEntry->Tag())); int32 subtypeKind = dwarf_tag_to_subtype_kind(typeEntry->Tag()); if (subtypeKind >= 0) constraints.SetSubtypeKind(subtypeKind); AutoLocker cacheLocker(fTypeCache); Type* globalType = name.Length() > 0 ? fTypeCache->GetType(name, constraints) : NULL; if (globalType == NULL) { // lookup by name failed -- try lookup by ID BString id; if (DwarfType::GetTypeID(typeEntry, id)) globalType = fTypeCache->GetTypeByID(id); } if (globalType != NULL) { DwarfType* globalDwarfType = dynamic_cast(globalType); if (globalDwarfType != NULL) { globalDwarfType->AcquireReference(); _type = globalDwarfType; return B_OK; } } cacheLocker.Unlock(); // If the type entry indicates a declaration only, we try to look the // type up globally first. if (typeEntry->IsDeclaration() && name.Length() > 0 && fTypeLookup->GetType(fTypeCache, name, constraints, globalType) == B_OK) { DwarfType* globalDwarfType = dynamic_cast(globalType); if (globalDwarfType != NULL) { _type = globalDwarfType; return B_OK; } globalType->ReleaseReference(); } // No luck yet -- create the type. DwarfType* type; status_t error = _CreateTypeInternal(name, typeEntry, type); if (error != B_OK) return error; BReference typeReference(type, true); // Insert the type into the cache. Re-check, as the type may already // have been inserted (e.g. in the compound type case). cacheLocker.Lock(); if (name.Length() > 0 ? fTypeCache->GetType(name, constraints) == NULL : fTypeCache->GetTypeByID(type->ID()) == NULL) { error = fTypeCache->AddType(type); if (error != B_OK) return error; } cacheLocker.Unlock(); // try to get the type's size uint64 size; if (_ResolveTypeByteSize(typeEntry, size) == B_OK) type->SetByteSize(size); _type = typeReference.Detach(); return B_OK; } status_t DwarfTypeFactory::_CreateTypeInternal(const BString& name, DIEType* typeEntry, DwarfType*& _type) { switch (typeEntry->Tag()) { case DW_TAG_class_type: case DW_TAG_structure_type: case DW_TAG_union_type: case DW_TAG_interface_type: return _CreateCompoundType(name, dynamic_cast(typeEntry), (compound_type_kind)dwarf_tag_to_subtype_kind( typeEntry->Tag()), _type); case DW_TAG_base_type: return _CreatePrimitiveType(name, dynamic_cast(typeEntry), _type); case DW_TAG_pointer_type: return _CreateAddressType(name, dynamic_cast(typeEntry), DERIVED_TYPE_POINTER, _type); case DW_TAG_reference_type: return _CreateAddressType(name, dynamic_cast(typeEntry), DERIVED_TYPE_REFERENCE, _type); case DW_TAG_const_type: return _CreateModifiedType(name, dynamic_cast(typeEntry), TYPE_MODIFIER_CONST, _type); case DW_TAG_packed_type: return _CreateModifiedType(name, dynamic_cast(typeEntry), TYPE_MODIFIER_PACKED, _type); case DW_TAG_volatile_type: return _CreateModifiedType(name, dynamic_cast(typeEntry), TYPE_MODIFIER_VOLATILE, _type); case DW_TAG_restrict_type: return _CreateModifiedType(name, dynamic_cast(typeEntry), TYPE_MODIFIER_RESTRICT, _type); case DW_TAG_shared_type: return _CreateModifiedType(name, dynamic_cast(typeEntry), TYPE_MODIFIER_SHARED, _type); case DW_TAG_typedef: return _CreateTypedefType(name, dynamic_cast(typeEntry), _type); case DW_TAG_array_type: return _CreateArrayType(name, dynamic_cast(typeEntry), _type); case DW_TAG_enumeration_type: return _CreateEnumerationType(name, dynamic_cast(typeEntry), _type); case DW_TAG_subrange_type: return _CreateSubrangeType(name, dynamic_cast(typeEntry), _type); case DW_TAG_unspecified_type: return _CreateUnspecifiedType(name, dynamic_cast(typeEntry), _type); case DW_TAG_subroutine_type: return _CreateFunctionType(name, dynamic_cast(typeEntry), _type); case DW_TAG_ptr_to_member_type: return _CreatePointerToMemberType(name, dynamic_cast(typeEntry), _type); case DW_TAG_string_type: case DW_TAG_file_type: case DW_TAG_set_type: // TODO: Implement (not relevant for C++)! return B_UNSUPPORTED; } return B_UNSUPPORTED; } status_t DwarfTypeFactory::_CreateCompoundType(const BString& name, DIECompoundType* typeEntry, compound_type_kind compoundKind, DwarfType*& _type) { TRACE_LOCALS("DwarfTypeFactory::_CreateCompoundType(\"%s\", %p, %d)\n", name.String(), typeEntry, compoundKind); // create the type DwarfCompoundType* type = new(std::nothrow) DwarfCompoundType(fTypeContext, name, typeEntry, compoundKind); if (type == NULL) return B_NO_MEMORY; BReference typeReference(type, true); // Already add the type at this pointer to the cache, since otherwise // we could run into an infinite recursion when trying to create the types // for the data members. // TODO: Since access to the type lookup context is multi-threaded, the // incomplete type could become visible to other threads. Hence we keep the // context locked, but that essentially kills multi-threading for this context. AutoLocker cacheLocker(fTypeCache); status_t error = fTypeCache->AddType(type); if (error != B_OK) { printf(" -> failed to add type to cache\n"); return error; } // cacheLocker.Unlock(); // find the abstract origin or specification that defines the data members DIECompoundType* memberOwnerEntry = DwarfUtils::GetDIEByPredicate(typeEntry, HasMembersPredicate()); // create the data member objects if (memberOwnerEntry != NULL) { for (DebugInfoEntryList::ConstIterator it = memberOwnerEntry->DataMembers().GetIterator(); DebugInfoEntry* _memberEntry = it.Next();) { DIEMember* memberEntry = dynamic_cast(_memberEntry); TRACE_LOCALS(" member %p\n", memberEntry); // get the type DwarfType* memberType; if (CreateType(memberEntry->GetType(), memberType) != B_OK) continue; BReference memberTypeReference(memberType, true); // get the name BString memberName; DwarfUtils::GetDIEName(memberEntry, memberName); // create and add the member object DwarfDataMember* member = new(std::nothrow) DwarfDataMember( memberEntry, memberName, memberType); BReference memberReference(member, true); if (member == NULL || !type->AddDataMember(member)) { cacheLocker.Lock(); fTypeCache->RemoveType(type); return B_NO_MEMORY; } } } // If the type is a class/struct/interface type, we also need to add its // base types, and possibly template parameters. if (DIEClassBaseType* classTypeEntry = dynamic_cast(typeEntry)) { // find the abstract origin or specification that defines the base types classTypeEntry = DwarfUtils::GetDIEByPredicate(classTypeEntry, HasBaseTypesPredicate()); // create the inheritance objects for the base types if (classTypeEntry != NULL) { for (DebugInfoEntryList::ConstIterator it = classTypeEntry->BaseTypes().GetIterator(); DebugInfoEntry* _inheritanceEntry = it.Next();) { DIEInheritance* inheritanceEntry = dynamic_cast(_inheritanceEntry); // get the type DwarfType* baseType; if (CreateType(inheritanceEntry->GetType(), baseType) != B_OK) continue; BReference baseTypeReference(baseType, true); // create and add the inheritance object DwarfInheritance* inheritance = new(std::nothrow) DwarfInheritance(inheritanceEntry, baseType); BReference inheritanceReference(inheritance, true); if (inheritance == NULL || !type->AddInheritance(inheritance)) { cacheLocker.Lock(); fTypeCache->RemoveType(type); return B_NO_MEMORY; } } } // find the abstract origin or specification that defines the template // parameters classTypeEntry = DwarfUtils::GetDIEByPredicate( dynamic_cast(typeEntry), HasTemplateParametersPredicate()); if (classTypeEntry != NULL) { for (DebugInfoEntryList::ConstIterator it = classTypeEntry->TemplateParameters() .GetIterator(); DebugInfoEntry* _typeEntry = it.Next();) { DIETemplateTypeParameter* templateTypeEntry = dynamic_cast(_typeEntry); DwarfType* templateType; if (templateTypeEntry != NULL) { if (templateTypeEntry->GetType() == NULL || CreateType(templateTypeEntry->GetType(), templateType) != B_OK) { continue; } } else { DIETemplateValueParameter* templateValueEntry = dynamic_cast(_typeEntry); if (CreateType(templateValueEntry->GetType(), templateType) != B_OK) { continue; } } BReference templateTypeReference(templateType, true); DwarfTemplateParameter* parameter = new(std::nothrow) DwarfTemplateParameter(_typeEntry, templateType); if (parameter == NULL) { cacheLocker.Lock(); fTypeCache->RemoveType(type); return B_NO_MEMORY; } if (!type->AddTemplateParameter(parameter)) { cacheLocker.Lock(); fTypeCache->RemoveType(type); return B_NO_MEMORY; } } } } _type = typeReference.Detach(); return B_OK;; } status_t DwarfTypeFactory::_CreatePrimitiveType(const BString& name, DIEBaseType* typeEntry, DwarfType*& _type) { const DynamicAttributeValue* byteSizeValue = typeEntry->ByteSize(); // const DynamicAttributeValue* bitOffsetValue = typeEntry->BitOffset(); const DynamicAttributeValue* bitSizeValue = typeEntry->BitSize(); uint32 bitSize = 0; if (byteSizeValue->IsValid()) { BVariant value; status_t error = fTypeContext->File()->EvaluateDynamicValue( fTypeContext->GetCompilationUnit(), fTypeContext->AddressSize(), fTypeContext->IsBigEndian(), fTypeContext->SubprogramEntry(), byteSizeValue, fTypeContext->TargetInterface(), fTypeContext->InstructionPointer(), fTypeContext->FramePointer(), value); if (error == B_OK && value.IsInteger()) bitSize = value.ToUInt32() * 8; } else if (bitSizeValue->IsValid()) { BVariant value; status_t error = fTypeContext->File()->EvaluateDynamicValue( fTypeContext->GetCompilationUnit(), fTypeContext->AddressSize(), fTypeContext->IsBigEndian(), fTypeContext->SubprogramEntry(), bitSizeValue, fTypeContext->TargetInterface(), fTypeContext->InstructionPointer(), fTypeContext->FramePointer(), value); if (error == B_OK && value.IsInteger()) bitSize = value.ToUInt32(); } // determine type constant uint32 typeConstant = 0; switch (typeEntry->Encoding()) { case DW_ATE_boolean: typeConstant = B_BOOL_TYPE; break; case DW_ATE_float: switch (bitSize) { case 32: typeConstant = B_FLOAT_TYPE; break; case 64: typeConstant = B_DOUBLE_TYPE; break; } break; case DW_ATE_signed: case DW_ATE_signed_char: switch (bitSize) { case 8: typeConstant = B_INT8_TYPE; break; case 16: typeConstant = B_INT16_TYPE; break; case 32: typeConstant = B_INT32_TYPE; break; case 64: typeConstant = B_INT64_TYPE; break; } break; case DW_ATE_address: case DW_ATE_unsigned: case DW_ATE_unsigned_char: switch (bitSize) { case 8: typeConstant = B_UINT8_TYPE; break; case 16: typeConstant = B_UINT16_TYPE; break; case 32: typeConstant = B_UINT32_TYPE; break; case 64: typeConstant = B_UINT64_TYPE; break; } break; case DW_ATE_complex_float: case DW_ATE_imaginary_float: case DW_ATE_packed_decimal: case DW_ATE_numeric_string: case DW_ATE_edited: case DW_ATE_signed_fixed: case DW_ATE_unsigned_fixed: case DW_ATE_decimal_float: default: break; } // create the type DwarfPrimitiveType* type = new(std::nothrow) DwarfPrimitiveType( fTypeContext, name, typeEntry, typeConstant); if (type == NULL) return B_NO_MEMORY; _type = type; return B_OK; } status_t DwarfTypeFactory::_CreateAddressType(const BString& name, DIEAddressingType* typeEntry, address_type_kind addressKind, DwarfType*& _type) { // get the base type entry DIEAddressingType* baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate( typeEntry, HasTypePredicate()); // create the base type DwarfType* baseType; if (baseTypeOwnerEntry != NULL) { status_t error = CreateType(baseTypeOwnerEntry->GetType(), baseType); if (error != B_OK) return error; } else { // According to the DWARF 3 specs a modified type *has* a base type. // GCC 4 doesn't (always?) bother to add one for "void". // TODO: We should probably search for a respective type by name. ATM // we just create a DwarfUnspecifiedType without DIE. TRACE_LOCALS("no base type for address type entry -- creating " "unspecified type\n"); baseType = new(std::nothrow) DwarfUnspecifiedType(fTypeContext, "void", NULL); if (baseType == NULL) return B_NO_MEMORY; } BReference baseTypeReference(baseType, true); DwarfAddressType* type = new(std::nothrow) DwarfAddressType(fTypeContext, name, typeEntry, addressKind, baseType); if (type == NULL) return B_NO_MEMORY; _type = type; return B_OK; } status_t DwarfTypeFactory::_CreateModifiedType(const BString& name, DIEModifiedType* typeEntry, uint32 modifiers, DwarfType*& _type) { // Get the base type entry. If it is a modified type too or a typedef, // collect all modifiers and iterate until hitting an actual base type. DIEType* baseTypeEntry = NULL; DwarfType* baseType = NULL; while (true) { DIEModifiedType* baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate( typeEntry, HasTypePredicate()); if (baseTypeOwnerEntry == NULL) { if (typeEntry->GetType() == NULL) { // in the case of a modified type that points to an // unspecified type (i.e. const void* in C/C++), // gcc appears to omit the base type attribute entirely. status_t result = _CreateUnspecifiedType(name, NULL, baseType); if (result != B_OK) return result; break; } else return B_BAD_VALUE; } else baseTypeEntry = baseTypeOwnerEntry->GetType(); // resolve a typedef if (baseTypeEntry->Tag() == DW_TAG_typedef) { status_t error = _ResolveTypedef( dynamic_cast(baseTypeEntry), baseTypeEntry); if (error != B_OK) return error; } if (baseTypeEntry == NULL) return B_BAD_VALUE; // If the base type is a modified type, too, resolve it. switch (baseTypeEntry->Tag()) { case DW_TAG_const_type: modifiers |= TYPE_MODIFIER_CONST; baseTypeOwnerEntry = dynamic_cast(baseTypeEntry); continue; case DW_TAG_packed_type: modifiers |= TYPE_MODIFIER_PACKED; baseTypeOwnerEntry = dynamic_cast(baseTypeEntry); continue; case DW_TAG_volatile_type: modifiers |= TYPE_MODIFIER_VOLATILE; baseTypeOwnerEntry = dynamic_cast(baseTypeEntry); continue; case DW_TAG_restrict_type: modifiers |= TYPE_MODIFIER_RESTRICT; baseTypeOwnerEntry = dynamic_cast(baseTypeEntry); continue; case DW_TAG_shared_type: modifiers |= TYPE_MODIFIER_SHARED; baseTypeOwnerEntry = dynamic_cast(baseTypeEntry); continue; default: break; } // If we get here, we've found an actual base type. break; } if (baseType == NULL) { // create the base type status_t error = CreateType(baseTypeEntry, baseType); if (error != B_OK) return error; } BReference baseTypeReference(baseType, true); DwarfModifiedType* type = new(std::nothrow) DwarfModifiedType(fTypeContext, name, typeEntry, modifiers, baseType); if (type == NULL) return B_NO_MEMORY; _type = type; return B_OK; } status_t DwarfTypeFactory::_CreateTypedefType(const BString& name, DIETypedef* typeEntry, DwarfType*& _type) { // resolve the base type DIEType* baseTypeEntry; status_t error = _ResolveTypedef(typeEntry, baseTypeEntry); if (error != B_OK) return error; // create the base type DwarfType* baseType; error = CreateType(baseTypeEntry, baseType); if (error != B_OK) return error; BReference baseTypeReference(baseType, true); DwarfTypedefType* type = new(std::nothrow) DwarfTypedefType(fTypeContext, name, typeEntry, baseType); if (type == NULL) return B_NO_MEMORY; _type = type; return B_OK; } status_t DwarfTypeFactory::_CreateArrayType(const BString& name, DIEArrayType* typeEntry, DwarfType*& _type) { TRACE_LOCALS("DwarfTypeFactory::_CreateArrayType(\"%s\", %p)\n", name.String(), typeEntry); // create the base type DIEArrayType* baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate( typeEntry, HasTypePredicate()); if (baseTypeOwnerEntry == NULL) { WARNING("Failed to get base type for array type \"%s\"\n", name.String()); return B_BAD_VALUE; } DwarfType* baseType = NULL; status_t error = CreateType(baseTypeOwnerEntry->GetType(), baseType); if (error != B_OK) { WARNING("Failed to create base type for array type \"%s\": %s\n", name.String(), strerror(error)); return error; } BReference baseTypeReference(baseType, true); // create the array type DwarfArrayType* type = new(std::nothrow) DwarfArrayType(fTypeContext, name, typeEntry, baseType); if (type == NULL) return B_NO_MEMORY; BReference typeReference(type, true); // add the array dimensions DIEArrayType* dimensionOwnerEntry = DwarfUtils::GetDIEByPredicate( typeEntry, HasDimensionsPredicate()); if (dimensionOwnerEntry == NULL) { WARNING("Failed to get dimensions for array type \"%s\"\n", name.String()); return B_BAD_VALUE; } for (DebugInfoEntryList::ConstIterator it = dimensionOwnerEntry->Dimensions().GetIterator(); DebugInfoEntry* _dimensionEntry = it.Next();) { DIEType* dimensionEntry = dynamic_cast(_dimensionEntry); // get/create the dimension type DwarfType* dimensionType = NULL; status_t error = CreateType(dimensionEntry, dimensionType); if (error != B_OK) { WARNING("Failed to create type for array dimension: %s\n", strerror(error)); return error; } BReference dimensionTypeReference(dimensionType, true); // create and add the array dimension object DwarfArrayDimension* dimension = new(std::nothrow) DwarfArrayDimension(dimensionType); BReference dimensionReference(dimension, true); if (dimension == NULL || !type->AddDimension(dimension)) return B_NO_MEMORY; } _type = typeReference.Detach(); return B_OK; } status_t DwarfTypeFactory::_CreateEnumerationType(const BString& name, DIEEnumerationType* typeEntry, DwarfType*& _type) { // create the base type (it's optional) DIEEnumerationType* baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate( typeEntry, HasTypePredicate()); DwarfType* baseType = NULL; if (baseTypeOwnerEntry != NULL) { status_t error = CreateType(baseTypeOwnerEntry->GetType(), baseType); if (error != B_OK) return error; } BReference baseTypeReference(baseType, true); // create the enumeration type DwarfEnumerationType* type = new(std::nothrow) DwarfEnumerationType( fTypeContext, name, typeEntry, baseType); if (type == NULL) return B_NO_MEMORY; BReference typeReference(type, true); // get the enumeration values DIEEnumerationType* enumeratorOwnerEntry = DwarfUtils::GetDIEByPredicate( typeEntry, HasEnumeratorsPredicate()); if (enumeratorOwnerEntry != NULL) { for (DebugInfoEntryList::ConstIterator it = enumeratorOwnerEntry->Enumerators().GetIterator(); DebugInfoEntry* _enumeratorEntry = it.Next();) { DIEEnumerator* enumeratorEntry = dynamic_cast( _enumeratorEntry); // evaluate the value BVariant value; status_t error = fTypeContext->File()->EvaluateConstantValue( fTypeContext->GetCompilationUnit(), fTypeContext->AddressSize(), fTypeContext->IsBigEndian(), fTypeContext->SubprogramEntry(), enumeratorEntry->ConstValue(), fTypeContext->TargetInterface(), fTypeContext->InstructionPointer(), fTypeContext->FramePointer(), value); if (error != B_OK) { // The value is probably not stored -- just ignore the // enumerator. TRACE_LOCALS("Failed to get value for enum type value %s::%s\n", name.String(), enumeratorEntry->Name()); continue; } // create and add the enumeration value object DwarfEnumeratorValue* enumValue = new(std::nothrow) DwarfEnumeratorValue(enumeratorEntry, enumeratorEntry->Name(), value); BReference enumValueReference(enumValue, true); if (enumValue == NULL || !type->AddValue(enumValue)) return B_NO_MEMORY; } } _type = typeReference.Detach(); return B_OK; } status_t DwarfTypeFactory::_CreateSubrangeType(const BString& name, DIESubrangeType* typeEntry, DwarfType*& _type) { // get the base type DIESubrangeType* baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate( typeEntry, HasTypePredicate()); DIEType* baseTypeEntry = baseTypeOwnerEntry != NULL ? baseTypeOwnerEntry->GetType() : NULL; // get the lower bound BVariant lowerBound; DIESubrangeType* lowerBoundOwnerEntry = DwarfUtils::GetDIEByPredicate( typeEntry, HasLowerBoundPredicate()); if (lowerBoundOwnerEntry != NULL) { // evaluate it DIEType* valueType; status_t error = fTypeContext->File()->EvaluateDynamicValue( fTypeContext->GetCompilationUnit(), fTypeContext->AddressSize(), fTypeContext->IsBigEndian(), fTypeContext->SubprogramEntry(), lowerBoundOwnerEntry->LowerBound(), fTypeContext->TargetInterface(), fTypeContext->InstructionPointer(), fTypeContext->FramePointer(), lowerBound, &valueType); if (error != B_OK) { WARNING(" failed to evaluate lower bound: %s\n", strerror(error)); return error; } // If we don't have a base type yet, and the lower bound attribute // refers to an object, the type of that object is our base type. if (baseTypeEntry == NULL) baseTypeEntry = valueType; } else { // that's ok -- use the language default lowerBound.SetTo(fTypeContext->GetCompilationUnit()->SourceLanguage() ->subrangeLowerBound); } // get the upper bound BVariant upperBound; DIESubrangeType* upperBoundOwnerEntry = DwarfUtils::GetDIEByPredicate( typeEntry, HasUpperBoundPredicate()); if (upperBoundOwnerEntry != NULL) { // evaluate it DIEType* valueType; status_t error = fTypeContext->File()->EvaluateDynamicValue( fTypeContext->GetCompilationUnit(), fTypeContext->AddressSize(), fTypeContext->IsBigEndian(), fTypeContext->SubprogramEntry(), upperBoundOwnerEntry->UpperBound(), fTypeContext->TargetInterface(), fTypeContext->InstructionPointer(), fTypeContext->FramePointer(), upperBound, &valueType); if (error != B_OK) { WARNING(" failed to evaluate upper bound: %s\n", strerror(error)); return error; } // If we don't have a base type yet, and the upper bound attribute // refers to an object, the type of that object is our base type. if (baseTypeEntry == NULL) baseTypeEntry = valueType; } else { // get the count instead DIESubrangeType* countOwnerEntry = DwarfUtils::GetDIEByPredicate( typeEntry, HasCountPredicate()); if (countOwnerEntry != NULL) { // evaluate it BVariant count; DIEType* valueType; status_t error = fTypeContext->File()->EvaluateDynamicValue( fTypeContext->GetCompilationUnit(), fTypeContext->AddressSize(), fTypeContext->IsBigEndian(), fTypeContext->SubprogramEntry(), countOwnerEntry->Count(), fTypeContext->TargetInterface(), fTypeContext->InstructionPointer(), fTypeContext->FramePointer(), count, &valueType); if (error != B_OK) { WARNING(" failed to evaluate count: %s\n", strerror(error)); return error; } // If we don't have a base type yet, and the count attribute refers // to an object, the type of that object is our base type. if (baseTypeEntry == NULL) baseTypeEntry = valueType; // we only support integers bool isSigned; if (!lowerBound.IsInteger(&isSigned) || !count.IsInteger()) { WARNING(" count given for subrange type, but lower bound or " "count is not integer\n"); return B_BAD_VALUE; } if (isSigned) upperBound.SetTo(lowerBound.ToInt64() + count.ToInt64() - 1); else upperBound.SetTo(lowerBound.ToUInt64() + count.ToUInt64() - 1); } } // create the base type Type* baseType = NULL; status_t error; if (baseTypeEntry != NULL) { DwarfType* dwarfBaseType; error = CreateType(baseTypeEntry, dwarfBaseType); baseType = dwarfBaseType; } else { // We still don't have a base type yet. In this case the base type is // supposed to be a signed integer type with the same size as an address // for that compilation unit. error = ArtificialIntegerType::Create( fTypeContext->GetCompilationUnit()->AddressSize(), true, baseType); } if (error != B_OK) return error; BReference baseTypeReference(baseType, true); // TODO: Support the thread scaling attribute! // create the type DwarfSubrangeType* type = new(std::nothrow) DwarfSubrangeType(fTypeContext, name, typeEntry, baseType, lowerBound, upperBound); if (type == NULL) return B_NO_MEMORY; _type = type; return B_OK; } status_t DwarfTypeFactory::_CreateUnspecifiedType(const BString& name, DIEUnspecifiedType* typeEntry, DwarfType*& _type) { DwarfUnspecifiedType* type = new(std::nothrow) DwarfUnspecifiedType( fTypeContext, name, typeEntry); if (type == NULL) return B_NO_MEMORY; _type = type; return B_OK; } status_t DwarfTypeFactory::_CreateFunctionType(const BString& name, DIESubroutineType* typeEntry, DwarfType*& _type) { // get the return type DIESubroutineType* returnTypeOwnerEntry = DwarfUtils::GetDIEByPredicate( typeEntry, HasReturnTypePredicate()); // create the base type DwarfType* returnType = NULL; if (returnTypeOwnerEntry != NULL) { status_t error = CreateType(returnTypeOwnerEntry->ReturnType(), returnType); if (error != B_OK) return error; } BReference returnTypeReference(returnType, true); DwarfFunctionType* type = new(std::nothrow) DwarfFunctionType(fTypeContext, name, typeEntry, returnType); if (type == NULL) return B_NO_MEMORY; BReference typeReference(type, true); // get the parameters DIESubroutineType* parameterOwnerEntry = DwarfUtils::GetDIEByPredicate( typeEntry, HasParametersPredicate()); if (parameterOwnerEntry != NULL) { for (DebugInfoEntryList::ConstIterator it = parameterOwnerEntry->Parameters().GetIterator(); DebugInfoEntry* _parameterEntry = it.Next();) { if (_parameterEntry->Tag() == DW_TAG_unspecified_parameters) { type->SetHasVariableArguments(true); continue; } DIEFormalParameter* parameterEntry = dynamic_cast(_parameterEntry); // get the type DIEFormalParameter* typeOwnerEntry = DwarfUtils::GetDIEByPredicate( parameterEntry, HasTypePredicate()); if (typeOwnerEntry == NULL) return B_BAD_VALUE; DwarfType* parameterType; status_t error = CreateType(typeOwnerEntry->GetType(), parameterType); if (error != B_OK) return error; BReference parameterTypeReference(parameterType, true); // get the name BString parameterName; DwarfUtils::GetDIEName(parameterEntry, parameterName); // create and add the parameter object DwarfFunctionParameter* parameter = new(std::nothrow) DwarfFunctionParameter(parameterEntry, parameterName, parameterType); BReference parameterReference(parameter, true); if (parameter == NULL || !type->AddParameter(parameter)) return B_NO_MEMORY; } } _type = typeReference.Detach(); return B_OK; } status_t DwarfTypeFactory::_CreatePointerToMemberType(const BString& name, DIEPointerToMemberType* typeEntry, DwarfType*& _type) { // get the containing and base type entries DIEPointerToMemberType* containingTypeOwnerEntry = DwarfUtils::GetDIEByPredicate(typeEntry, HasContainingTypePredicate()); DIEPointerToMemberType* baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate( typeEntry, HasTypePredicate()); if (containingTypeOwnerEntry == NULL || baseTypeOwnerEntry == NULL) { WARNING("Failed to get containing or base type for pointer to member " "type \"%s\"\n", name.String()); return B_BAD_VALUE; } // create the containing type DwarfType* containingType; status_t error = CreateType(containingTypeOwnerEntry->ContainingType(), containingType); if (error != B_OK) return error; BReference containingTypeReference(containingType, true); DwarfCompoundType* compoundContainingType = dynamic_cast(containingType); if (compoundContainingType == NULL) { WARNING("Containing type for pointer to member type \"%s\" is not a " "compound type.\n", name.String()); return B_BAD_VALUE; } // create the base type DwarfType* baseType; error = CreateType(baseTypeOwnerEntry->GetType(), baseType); if (error != B_OK) return error; BReference baseTypeReference(baseType, true); // create the type object DwarfPointerToMemberType* type = new(std::nothrow) DwarfPointerToMemberType( fTypeContext, name, typeEntry, compoundContainingType, baseType); if (type == NULL) return B_NO_MEMORY; _type = type; return B_OK; } status_t DwarfTypeFactory::_ResolveTypedef(DIETypedef* entry, DIEType*& _baseTypeEntry) { while (true) { // resolve the base type, possibly following abstract origin or // specification DIETypedef* baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate( entry, HasTypePredicate()); if (baseTypeOwnerEntry == NULL) return B_BAD_VALUE; DIEType* baseTypeEntry = baseTypeOwnerEntry->GetType(); if (baseTypeEntry->Tag() != DW_TAG_typedef) { _baseTypeEntry = baseTypeEntry; return B_OK; } entry = dynamic_cast(baseTypeEntry); } } status_t DwarfTypeFactory::_ResolveTypeByteSize(DIEType* typeEntry, uint64& _size) { TRACE_LOCALS("DwarfTypeFactory::_ResolveTypeByteSize(%p)\n", typeEntry); // get the size attribute const DynamicAttributeValue* sizeValue; while (true) { // resolve a typedef if (typeEntry->Tag() == DW_TAG_typedef) { TRACE_LOCALS(" resolving typedef...\n"); status_t error = _ResolveTypedef( dynamic_cast(typeEntry), typeEntry); if (error != B_OK) return error; } sizeValue = typeEntry->ByteSize(); if (sizeValue != NULL && sizeValue->IsValid()) break; // resolve abstract origin if (DIEType* abstractOrigin = dynamic_cast( typeEntry->AbstractOrigin())) { TRACE_LOCALS(" resolving abstract origin (%p)...\n", abstractOrigin); typeEntry = abstractOrigin; sizeValue = typeEntry->ByteSize(); if (sizeValue != NULL && sizeValue->IsValid()) break; } // resolve specification if (DIEType* specification = dynamic_cast( typeEntry->Specification())) { TRACE_LOCALS(" resolving specification (%p)...\n", specification); typeEntry = specification; sizeValue = typeEntry->ByteSize(); if (sizeValue != NULL && sizeValue->IsValid()) break; } // For some types we have a special handling. For modified types we // follow the base type, for address types we know the size anyway. TRACE_LOCALS(" nothing yet, special type handling\n"); switch (typeEntry->Tag()) { case DW_TAG_const_type: case DW_TAG_packed_type: case DW_TAG_volatile_type: case DW_TAG_restrict_type: case DW_TAG_shared_type: typeEntry = dynamic_cast(typeEntry) ->GetType(); TRACE_LOCALS(" following modified type -> %p\n", typeEntry); if (typeEntry == NULL) return B_ENTRY_NOT_FOUND; break; case DW_TAG_pointer_type: case DW_TAG_reference_type: case DW_TAG_ptr_to_member_type: _size = fTypeContext->GetCompilationUnit()->AddressSize(); TRACE_LOCALS(" pointer/reference type: size: %" B_PRIu64 "\n", _size); return B_OK; default: return B_ENTRY_NOT_FOUND; } } TRACE_LOCALS(" found attribute\n"); // get the actual value BVariant size; status_t error = fTypeContext->File()->EvaluateDynamicValue( fTypeContext->GetCompilationUnit(), fTypeContext->AddressSize(), fTypeContext->IsBigEndian(), fTypeContext->SubprogramEntry(), sizeValue, fTypeContext->TargetInterface(), fTypeContext->InstructionPointer(), fTypeContext->FramePointer(), size); if (error != B_OK) { TRACE_LOCALS(" failed to resolve attribute: %s\n", strerror(error)); return error; } _size = size.ToUInt64(); TRACE_LOCALS(" -> size: %" B_PRIu64 "\n", _size); return B_OK; }