diff --git a/src/apps/debugger/Jobs.cpp b/src/apps/debugger/Jobs.cpp index bfbc727dee..609b376712 100644 --- a/src/apps/debugger/Jobs.cpp +++ b/src/apps/debugger/Jobs.cpp @@ -519,10 +519,13 @@ GetStackFrameValueJob::_GetValue() // find out the type of the data we want to read type_code valueType = 0; + bool shortValueIsFine = false; while (valueType == 0) { switch (type->Kind()) { case TYPE_PRIMITIVE: valueType = dynamic_cast(type)->TypeConstant(); + shortValueIsFine = BVariant::TypeIsInteger(valueType) + || valueType == B_BOOL_TYPE; TRACE_LOCALS(" TYPE_PRIMITIVE: '%c%c%c%c'\n", int(valueType >> 24), int(valueType >> 16), @@ -560,6 +563,38 @@ GetStackFrameValueJob::_GetValue() // recursion work smoothly, we have to set the type and // location at least. return _SetValue(BVariant(), actualType, location); + case TYPE_ENUMERATION: + { + TRACE_LOCALS(" TYPE_ENUMERATION\n"); + // If a base type is known, use that. + EnumerationType* enumType + = dynamic_cast(type); + if (enumType->BaseType() != NULL) { + type = enumType->BaseType(); + break; + } + + // get the value type constant + // TODO: This is C source language specific! + switch (enumType->ByteSize()) { + case 1: + valueType = B_INT8_TYPE; + break; + case 2: + valueType = B_INT16_TYPE; + break; + case 4: + default: + valueType = B_INT32_TYPE; + break; + case 8: + valueType = B_INT64_TYPE; + break; + } + + shortValueIsFine = true; + break; + } default: TRACE_LOCALS(" default -> unsupported\n"); return B_UNSUPPORTED; @@ -578,7 +613,7 @@ GetStackFrameValueJob::_GetValue() // check whether we know the complete location int32 count = location->CountPieces(); - TRACE_LOCALS(" location: %p, %ld pieces\n", location, count); + TRACE_LOCALS_ONLY(location->Dump();) if (count == 0) { TRACE_LOCALS(" -> no location\n"); @@ -592,7 +627,7 @@ GetStackFrameValueJob::_GetValue() if (piece.type == VALUE_PIECE_LOCATION_MEMORY) { ValueLocation* dataLocation; error = fStackFrame->DebugInfo()->ResolveObjectDataLocation( - fStackFrame, type, piece.address, dataLocation); + fStackFrame, type, *location, dataLocation); if (error != B_OK) return error; @@ -601,7 +636,7 @@ GetStackFrameValueJob::_GetValue() } } - target_size_t totalSize = 0; + static const size_t kMaxPieceSize = 16; uint64 totalBitSize = 0; for (int32 i = 0; i < count; i++) { ValuePieceLocation piece = location->PieceAt(i); @@ -614,48 +649,51 @@ GetStackFrameValueJob::_GetValue() break; } - totalSize += piece.size; + if (piece.size > kMaxPieceSize) { + TRACE_LOCALS(" -> overly long piece size (%llu bytes)\n", + piece.size); + return B_UNSUPPORTED; + } + totalBitSize += piece.bitSize; } - TRACE_LOCALS(" -> totalSize: %llu, totalBitSize: %llu\n", totalSize, - totalBitSize); + TRACE_LOCALS(" -> totalBitSize: %llu\n", totalBitSize); - if (totalSize == 0 && totalBitSize == 0) { + if (totalBitSize == 0) { TRACE_LOCALS(" -> no size\n"); return B_ENTRY_NOT_FOUND; } - if (totalSize > 8 || totalSize + (totalBitSize + 7) / 8 > 8) { - TRACE_LOCALS(" -> longer than 8 bytes: unsupported\n"); + if (totalBitSize > 64) { + TRACE_LOCALS(" -> longer than 64 bits: unsupported\n"); return B_UNSUPPORTED; } - if (totalSize + (totalBitSize + 7) / 8 < BVariant::SizeOfType(valueType)) { - TRACE_LOCALS(" -> too short for value type (%llu vs. %lu)\n", - totalSize + (totalBitSize + 7) / 8, - BVariant::SizeOfType(valueType)); + uint64 valueBitSize = BVariant::SizeOfType(valueType) * 8; + if (!shortValueIsFine && totalBitSize < valueBitSize) { + TRACE_LOCALS(" -> too short for value type (%llu vs. %llu bits)\n", + totalBitSize, valueBitSize); return B_BAD_VALUE; } - // load the data + // Load the data. Since the BitBuffer class we're using only supports big + // endian bit semantics, we convert all data to big endian before pushing + // them to the buffer. For later conversion to BVariant we need to make sure + // the final buffer has the size of the value type, so we pad the most + // significant bits with zeros. BitBuffer valueBuffer; + if (totalBitSize < valueBitSize) + valueBuffer.AddZeroBits(valueBitSize - totalBitSize); - // If the total bit size is not byte aligned, push the respective number of - // 0 bits on a big endian architecture to get an immediately usable value. - // On a little endian architecture we'll play with the last read byte - // instead. - if (fArchitecture->IsBigEndian() && totalBitSize % 8 != 0) { - const uint8 zero = 0; - valueBuffer.AddBits(&zero, 8 - totalBitSize % 8, 0); - } - + bool bigEndian = fArchitecture->IsBigEndian(); const Register* registers = fArchitecture->Registers(); for (int32 i = 0; i < count; i++) { - ValuePieceLocation piece = location->PieceAt(i); + ValuePieceLocation piece = location->PieceAt( + bigEndian ? i : count - i - 1); + uint32 bytesToRead = piece.size; + uint32 bitSize = piece.bitSize; uint8 bitOffset = piece.bitOffset; - uint32 bitSize = piece.size * 8 + piece.bitSize; - uint32 bytesToRead = (bitSize + 7) / 8; switch (piece.type) { case VALUE_PIECE_LOCATION_INVALID: @@ -663,13 +701,12 @@ GetStackFrameValueJob::_GetValue() return B_ENTRY_NOT_FOUND; case VALUE_PIECE_LOCATION_MEMORY: { - target_addr_t address = piece.address + bitOffset / 8; + target_addr_t address = piece.address; TRACE_LOCALS(" piece %ld: memory address: %#llx, bits: %lu\n", i, address, bitSize); - bitOffset %= 8; - uint8 pieceBuffer[8]; + uint8 pieceBuffer[kMaxPieceSize]; ssize_t bytesRead = fDebuggerInterface->ReadMemory(address, pieceBuffer, bytesToRead); if (bytesRead < 0) @@ -684,6 +721,14 @@ GetStackFrameValueJob::_GetValue() TRACE_LOCALS("\n"); ) + // convert to big endian + if (!bigEndian) { + for (int32 k = bytesRead / 2 - 1; k >= 0; k--) { + std::swap(pieceBuffer[k], + pieceBuffer[bytesRead - k - 1]); + } + } + valueBuffer.AddBits(pieceBuffer, bitSize, bitOffset); break; } @@ -700,7 +745,7 @@ GetStackFrameValueJob::_GetValue() if (registerValue.Size() < bytesToRead) return B_ENTRY_NOT_FOUND; - if (!fArchitecture->IsHostEndian()) + if (!bigEndian) registerValue.SwapEndianess(); valueBuffer.AddBits(registerValue.Bytes(), bitSize, bitOffset); break; @@ -708,12 +753,9 @@ GetStackFrameValueJob::_GetValue() } } - // If the total bit size is not byte aligned, shift the last byte by the - // respective number of bits on a little endian architecture to get a usable - // value. - if (!fArchitecture->IsBigEndian() && totalBitSize % 8 != 0) - valueBuffer.Bytes()[totalBitSize / 8] >>= 8 - totalBitSize % 8; - // TODO: Verify that this is the way to handle it! + // If we don't have enough bits in the buffer apparently adding some failed. + if (valueBuffer.BitSize() < valueBitSize) + return B_NO_MEMORY; // convert the bits into something we can work with BVariant value; @@ -723,8 +765,10 @@ GetStackFrameValueJob::_GetValue() return error; } - if (!fArchitecture->IsHostEndian()) + // convert to host endianess + #if B_HOST_IS_LENDIAN value.SwapEndianess(); + #endif return _SetValue(value, actualType, location); } @@ -788,9 +832,10 @@ GetStackFrameValueJob::_ResolveTypeAndLocation(Type*& _type, TypeComponent component = fPath->ComponentAt(componentCount - 1); switch (component.typeKind) { case TYPE_PRIMITIVE: + case TYPE_ENUMERATION: // cannot happen TRACE_LOCALS("GetStackFrameValueJob::_ResolveTypeAndLocation(): " - "TYPE_PRIMITIVE subcomponent!\n"); + "TYPE_PRIMITIVE/TYPE_ENUMERATION subcomponent!\n"); return B_BAD_VALUE; case TYPE_COMPOUND: { diff --git a/src/apps/debugger/arch/x86/ArchitectureX86.cpp b/src/apps/debugger/arch/x86/ArchitectureX86.cpp index 3b8c2ccb0b..b545e2cbee 100644 --- a/src/apps/debugger/arch/x86/ArchitectureX86.cpp +++ b/src/apps/debugger/arch/x86/ArchitectureX86.cpp @@ -322,7 +322,7 @@ ArchitectureX86::CreateStackFrame(Image* image, FunctionDebugInfo* function, // create the stack frame StackFrameDebugInfo* stackFrameDebugInfo - = new(std::nothrow) NoOpStackFrameDebugInfo; + = new(std::nothrow) NoOpStackFrameDebugInfo(this); if (stackFrameDebugInfo == NULL) return B_NO_MEMORY; Reference stackFrameDebugInfoReference( diff --git a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp index 394f795752..94471dde29 100644 --- a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp @@ -44,7 +44,6 @@ #include "TeamMemory.h" #include "Tracing.h" #include "UnsupportedLanguage.h" -#include "ValueLocation.h" #include "Variable.h" @@ -397,7 +396,7 @@ DwarfImageDebugInfo::CreateFrame(Image* image, // create the stack frame debug info DIESubprogram* subprogramEntry = function->SubprogramEntry(); DwarfStackFrameDebugInfo* stackFrameDebugInfo - = new(std::nothrow) DwarfStackFrameDebugInfo(fFile, unit, + = new(std::nothrow) DwarfStackFrameDebugInfo(fArchitecture, fFile, unit, subprogramEntry, instructionPointer, framePointer, inputInterface, fromDwarfMap); if (stackFrameDebugInfo == NULL) diff --git a/src/apps/debugger/debug_info/DwarfStackFrameDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfStackFrameDebugInfo.cpp index ad51564484..fe8783f635 100644 --- a/src/apps/debugger/debug_info/DwarfStackFrameDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfStackFrameDebugInfo.cpp @@ -11,6 +11,7 @@ #include +#include "Architecture.h" #include "CompilationUnit.h" #include "DebugInfoEntries.h" #include "Dwarf.h" @@ -19,13 +20,110 @@ #include "FunctionID.h" #include "FunctionParameterID.h" #include "LocalVariableID.h" +#include "Register.h" #include "RegisterMap.h" +#include "SourceLanguageInfo.h" #include "StringUtils.h" #include "Tracing.h" #include "ValueLocation.h" #include "Variable.h" +namespace { + + +// #pragma mark - HasTypePredicate + + +template +struct HasTypePredicate { + inline bool operator()(EntryType* entry) const + { + return entry->GetType() != 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 - 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(); + } +}; + + +} // unnamed namespace + + // #pragma mark - DwarfFunctionParameterID @@ -229,6 +327,75 @@ private: }; +// #pragma mark - DwarfEnumerationValue + + +struct DwarfStackFrameDebugInfo::DwarfEnumerationValue : EnumerationValue { +public: + DwarfEnumerationValue(DIEEnumerator* entry, const BString& name, + const BVariant& value) + : + fEntry(entry), + fName(name), + fValue(value) + { + } + + ~DwarfEnumerationValue() + { + } + + virtual const char* Name() const + { + return fName.Length() > 0 ? fName.String() : NULL; + } + + DIEEnumerator* Entry() const + { + return fEntry; + } + + virtual BVariant Value() const + { + return fValue; + } + +private: + DIEEnumerator* fEntry; + BString fName; + BVariant fValue; + +}; + + +// #pragma mark - DwarfArrayDimension + + +struct DwarfStackFrameDebugInfo::DwarfArrayDimension : ArrayDimension { +public: + DwarfArrayDimension(DwarfType* type) + : + fType(type) + { + fType->AcquireReference(); + } + + ~DwarfArrayDimension() + { + fType->ReleaseReference(); + } + + virtual Type* GetType() const + { + return fType; + } + +private: + DwarfType* fType; + +}; + + // #pragma mark - DwarfPrimitiveType @@ -482,22 +649,95 @@ private: }; -// #pragma mark - DwarfArrayType +// #pragma mark - DwarfEnumerationType -struct DwarfStackFrameDebugInfo::DwarfArrayType : ArrayType, DwarfType { - DwarfArrayType(const BString& name, DIEArrayType* entry, - DwarfType* baseType, target_size_t elementCount) +struct DwarfStackFrameDebugInfo::DwarfEnumerationType : EnumerationType, + DwarfType { +public: + DwarfEnumerationType(const BString& name, DIEEnumerationType* entry, + DwarfType* baseType) + : + DwarfType(name), + fEntry(entry), + fBaseType(baseType) + { + if (fBaseType != NULL) + fBaseType->AcquireReference(); + } + + ~DwarfEnumerationType() + { + for (int32 i = 0; DwarfEnumerationValue* value = fValues.ItemAt(i); i++) + value->ReleaseReference(); + + if (fBaseType != NULL) + fBaseType->ReleaseReference(); + } + + virtual Type* BaseType() const + { + return fBaseType; + } + + virtual int32 CountValues() const + { + return fValues.CountItems(); + } + + virtual EnumerationValue* ValueAt(int32 index) const + { + return fValues.ItemAt(index); + } + + virtual DIEType* GetDIEType() const + { + return fEntry; + } + + DIEEnumerationType* Entry() const + { + return fEntry; + } + + bool AddValue(DwarfEnumerationValue* value) + { + if (!fValues.AddItem(value)) + return false; + + value->AcquireReference(); + return true; + } + +private: + typedef BObjectList ValueList; + +private: + DIEEnumerationType* fEntry; + DwarfType* fBaseType; + ValueList fValues; +}; + + +// #pragma mark - DwarfSubrangeType + + +struct DwarfStackFrameDebugInfo::DwarfSubrangeType : SubrangeType, DwarfType { +public: + DwarfSubrangeType(const BString& name, DIESubrangeType* entry, + DwarfType* baseType, const BVariant& lowerBound, + const BVariant& upperBound) : DwarfType(name), fEntry(entry), fBaseType(baseType), - fElementCount(elementCount) + fLowerBound(lowerBound), + fUpperBound(upperBound) { fBaseType->AcquireReference(); } - ~DwarfArrayType() + ~DwarfSubrangeType() { fBaseType->ReleaseReference(); } @@ -507,9 +747,71 @@ struct DwarfStackFrameDebugInfo::DwarfArrayType : ArrayType, DwarfType { return fBaseType; } - virtual target_size_t CountElements() const + virtual DIEType* GetDIEType() const { - return fElementCount; + return fEntry; + } + + virtual BVariant LowerBound() const + { + return fLowerBound; + } + + virtual BVariant UpperBound() const + { + return fUpperBound; + } + + DIESubrangeType* Entry() const + { + return fEntry; + } + +private: + DIESubrangeType* fEntry; + DwarfType* fBaseType; + BVariant fLowerBound; + BVariant fUpperBound; +}; + + +// #pragma mark - DwarfArrayType + + +struct DwarfStackFrameDebugInfo::DwarfArrayType : ArrayType, DwarfType { + DwarfArrayType(const BString& name, DIEArrayType* entry, + DwarfType* baseType) + : + DwarfType(name), + fEntry(entry), + fBaseType(baseType) + { + fBaseType->AcquireReference(); + } + + ~DwarfArrayType() + { + for (int32 i = 0; + DwarfArrayDimension* dimension = fDimensions.ItemAt(i); i++) { + dimension->ReleaseReference(); + } + + fBaseType->ReleaseReference(); + } + + virtual Type* BaseType() const + { + return fBaseType; + } + + virtual int32 CountDimensions() const + { + return fDimensions.CountItems(); + } + + virtual ArrayDimension* DimensionAt(int32 index) const + { + return fDimensions.ItemAt(index); } virtual DIEType* GetDIEType() const @@ -522,10 +824,22 @@ struct DwarfStackFrameDebugInfo::DwarfArrayType : ArrayType, DwarfType { return fEntry; } + bool AddDimension(DwarfArrayDimension* dimension) + { + if (!fDimensions.AddItem(dimension)) + return false; + + dimension->AcquireReference(); + return true; + } + +private: + typedef BObjectList DimensionList; + private: DIEArrayType* fEntry; DwarfType* fBaseType; - target_size_t fElementCount; + DimensionList fDimensions; }; @@ -561,11 +875,13 @@ struct DwarfStackFrameDebugInfo::DwarfTypeHashDefinition { // #pragma mark - DwarfStackFrameDebugInfo -DwarfStackFrameDebugInfo::DwarfStackFrameDebugInfo(DwarfFile* file, - CompilationUnit* compilationUnit, DIESubprogram* subprogramEntry, - target_addr_t instructionPointer, target_addr_t framePointer, - DwarfTargetInterface* targetInterface, RegisterMap* fromDwarfRegisterMap) +DwarfStackFrameDebugInfo::DwarfStackFrameDebugInfo(Architecture* architecture, + DwarfFile* file, CompilationUnit* compilationUnit, + DIESubprogram* subprogramEntry, target_addr_t instructionPointer, + target_addr_t framePointer, DwarfTargetInterface* targetInterface, + RegisterMap* fromDwarfRegisterMap) : + StackFrameDebugInfo(architecture), fFile(file), fCompilationUnit(compilationUnit), fSubprogramEntry(subprogramEntry), @@ -606,17 +922,37 @@ DwarfStackFrameDebugInfo::Init() status_t DwarfStackFrameDebugInfo::ResolveObjectDataLocation(StackFrame* stackFrame, - Type* type, target_addr_t objectAddress, ValueLocation*& _location) + Type* type, const ValueLocation& objectLocation, ValueLocation*& _location) { // TODO: In some source languages the object address might be a pointer to // a descriptor, not the actual object data. - ValuePieceLocation piece; - piece.SetToMemory(objectAddress); + // If the given location looks good already, just clone it. + int32 count = objectLocation.CountPieces(); + if (count == 0) + return B_BAD_VALUE; + + ValuePieceLocation piece = objectLocation.PieceAt(0); + if (count > 1 || piece.type != VALUE_PIECE_LOCATION_MEMORY + || piece.size != 0 || piece.bitSize != 0) { + ValueLocation* location + = new(std::nothrow) ValueLocation(objectLocation); + if (location == NULL || location->CountPieces() != count) { + delete location; + return B_NO_MEMORY; + } + + _location = location; + return B_OK; + } + + // The location contains just a single address piece with a zero size -- set + // the type's size. piece.SetSize(type->ByteSize()); // TODO: Use bit size and bit offset, if specified! - ValueLocation* location = new(std::nothrow) ValueLocation; + ValueLocation* location = new(std::nothrow) ValueLocation( + objectLocation.IsBigEndian()); if (location == NULL || !location->AddPiece(piece)) { delete location; return B_NO_MEMORY; @@ -684,7 +1020,7 @@ DwarfStackFrameDebugInfo::ResolveDataMemberLocation(StackFrame* stackFrame, byteSize = type->ByteSize(); // get the bit offset - uint64 bitOffset; + uint64 bitOffset = 0; if (memberEntry->BitOffset()->IsValid()) { BVariant value; error = fFile->EvaluateDynamicValue(fCompilationUnit, fSubprogramEntry, @@ -693,8 +1029,7 @@ DwarfStackFrameDebugInfo::ResolveDataMemberLocation(StackFrame* stackFrame, if (error != B_OK) return error; bitOffset = value.ToUInt64(); - } else - bitOffset = 0; + } // get the bit size uint64 bitSize = byteSize * 8; @@ -705,12 +1040,15 @@ DwarfStackFrameDebugInfo::ResolveDataMemberLocation(StackFrame* stackFrame, fFramePointer, value); if (error != B_OK) return error; - bitSize = std::min(bitSize, value.ToUInt64()); + bitSize = value.ToUInt64(); } TRACE_LOCALS("bit field: byte size: %llu, bit offset/size: %llu/%llu\n", byteSize, bitOffset, bitSize); + if (bitOffset + bitSize > byteSize * 8) + return B_BAD_VALUE; + // create the bit field value location ValueLocation* bitFieldLocation = new(std::nothrow) ValueLocation; if (bitFieldLocation == NULL) @@ -804,7 +1142,8 @@ DwarfStackFrameDebugInfo::_ResolveDataMemberLocation(StackFrame* stackFrame, ValueLocation*& _location) { // create the value location object for the member - ValueLocation* location = new(std::nothrow) ValueLocation; + ValueLocation* location = new(std::nothrow) ValueLocation( + parentLocation.IsBigEndian()); if (location == NULL) return B_NO_MEMORY; Reference locationReference(location, true); @@ -843,22 +1182,11 @@ DwarfStackFrameDebugInfo::_ResolveDataMemberLocation(StackFrame* stackFrame, } // evaluate the location description - status_t error = fFile->ResolveLocation(fCompilationUnit, - fSubprogramEntry, &locationDescription, fTargetInterface, - fInstructionPointer, piece.address, fFramePointer, *location); + status_t error = _ResolveLocation(&locationDescription, + piece.address, memberType, *location); if (error != B_OK) return error; - // If we only have a location but no size, use the size from the - // type. - if (location->CountPieces() == 1) { - piece = location->PieceAt(0); - if (piece.size == 0 && piece.bitSize == 0) { - piece.size = memberType->ByteSize(); - location->SetPieceAt(0, piece); - } - } - break; } default: @@ -966,18 +1294,24 @@ DwarfStackFrameDebugInfo::_CreateTypeInternal(DIEType* typeEntry, 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: case DW_TAG_subroutine_type: - case DW_TAG_enumeration_type: case DW_TAG_ptr_to_member_type: - case DW_TAG_subrange_type: // TODO: Implement! return B_UNSUPPORTED; case DW_TAG_string_type: case DW_TAG_file_type: case DW_TAG_set_type: - // TODO: Implement! + // TODO: Implement (not relevant for C++)! return B_UNSUPPORTED; } @@ -1005,94 +1339,70 @@ DwarfStackFrameDebugInfo::_CreateCompoundType(const BString& name, fTypes->Insert(type); // find the abstract origin or specification that defines the data members - DIECompoundType* originalTypeEntry = typeEntry; - if (typeEntry->DataMembers().IsEmpty()) { - TRACE_LOCALS(" no data members yet, trying abstract origin...\n"); - - if (DIECompoundType* abstractOrigin = dynamic_cast( - typeEntry->AbstractOrigin())) { - typeEntry = abstractOrigin; - } - } - - if (typeEntry->DataMembers().IsEmpty()) { - TRACE_LOCALS(" no data members yet, trying specification...\n"); - - if (DIECompoundType* specification = dynamic_cast( - typeEntry->Specification())) { - typeEntry = specification; - } - } + DIECompoundType* memberOwnerEntry = DwarfUtils::GetDIEByPredicate(typeEntry, + HasMembersPredicate()); // create the data member objects - for (DebugInfoEntryList::ConstIterator it - = typeEntry->DataMembers().GetIterator(); - DebugInfoEntry* _memberEntry = it.Next();) { - DIEMember* memberEntry = dynamic_cast(_memberEntry); + 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); + TRACE_LOCALS(" member %p\n", memberEntry); - // get the type - DwarfType* memberType; - if (_CreateType(memberEntry->GetType(), memberType) != B_OK) - continue; - Reference memberTypeReference(memberType, true); + // get the type + DwarfType* memberType; + if (_CreateType(memberEntry->GetType(), memberType) != B_OK) + continue; + Reference memberTypeReference(memberType, true); - // get the name - BString memberName; - DwarfUtils::GetDIEName(memberEntry, memberName); + // get the name + BString memberName; + DwarfUtils::GetDIEName(memberEntry, memberName); - // create and add the member object - DwarfDataMember* member = new(std::nothrow) DwarfDataMember(memberEntry, - memberName, memberType); - Reference memberReference(member, true); - if (member == NULL || !type->AddDataMember(member)) { - fTypes->Remove(type); - return B_NO_MEMORY; + // create and add the member object + DwarfDataMember* member = new(std::nothrow) DwarfDataMember( + memberEntry, memberName, memberType); + Reference memberReference(member, true); + if (member == NULL || !type->AddDataMember(member)) { + fTypes->Remove(type); + return B_NO_MEMORY; + } } } // If the type is a class/struct/interface type, we also need to add its // base types. if (DIEClassBaseType* classTypeEntry - = dynamic_cast(originalTypeEntry)) { + = dynamic_cast(typeEntry)) { // find the abstract origin or specification that defines the base types - if (classTypeEntry->DataMembers().IsEmpty()) { - if (DIEClassBaseType* abstractOrigin - = dynamic_cast( - classTypeEntry->AbstractOrigin())) { - classTypeEntry = abstractOrigin; - } - } - - if (classTypeEntry->DataMembers().IsEmpty()) { - if (DIEClassBaseType* specification - = dynamic_cast( - classTypeEntry->Specification())) { - classTypeEntry = specification; - } - } + classTypeEntry = DwarfUtils::GetDIEByPredicate(classTypeEntry, + HasBaseTypesPredicate()); // create the inheritance objects for the base types - for (DebugInfoEntryList::ConstIterator it - = classTypeEntry->BaseTypes().GetIterator(); - DebugInfoEntry* _inheritanceEntry = it.Next();) { - DIEInheritance* inheritanceEntry = dynamic_cast( - _inheritanceEntry); + 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; - Reference baseTypeReference(baseType, true); + // get the type + DwarfType* baseType; + if (_CreateType(inheritanceEntry->GetType(), baseType) != B_OK) + continue; + Reference baseTypeReference(baseType, true); - // create and add the inheritance object - DwarfInheritance* inheritance = new(std::nothrow) DwarfInheritance( - inheritanceEntry, baseType); - Reference inheritanceReference(inheritance, true); - if (inheritance == NULL || !type->AddInheritance(inheritance)) { - fTypes->Remove(type); - return B_NO_MEMORY; + // create and add the inheritance object + DwarfInheritance* inheritance = new(std::nothrow) + DwarfInheritance(inheritanceEntry, baseType); + Reference inheritanceReference(inheritance, + true); + if (inheritance == NULL || !type->AddInheritance(inheritance)) { + fTypes->Remove(type); + return B_NO_MEMORY; + } } } } @@ -1211,31 +1521,14 @@ DwarfStackFrameDebugInfo::_CreateAddressType(const BString& name, DwarfType*& _type) { // get the base type entry - DIEAddressingType* baseTypeOwnerEntry = typeEntry; - DIEType* baseTypeEntry = baseTypeOwnerEntry->GetType(); - if (baseTypeEntry == NULL) { - if (DIEAddressingType* abstractOrigin - = dynamic_cast( - baseTypeOwnerEntry->AbstractOrigin())) { - baseTypeOwnerEntry = abstractOrigin; - baseTypeEntry = baseTypeOwnerEntry->GetType(); - } - } - - if (baseTypeEntry == NULL) { - if (DIEAddressingType* specification = dynamic_cast( - baseTypeOwnerEntry->Specification())) { - baseTypeOwnerEntry = specification; - baseTypeEntry = baseTypeOwnerEntry->GetType(); - } - } - - if (baseTypeEntry == NULL) + DIEAddressingType* baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate( + typeEntry, HasTypePredicate()); + if (baseTypeOwnerEntry == NULL) return B_BAD_VALUE; // create the base type DwarfType* baseType; - status_t error = _CreateType(baseTypeEntry, baseType); + status_t error = _CreateType(baseTypeOwnerEntry->GetType(), baseType); if (error != B_OK) return error; Reference baseTypeReference(baseType, true); @@ -1256,29 +1549,17 @@ DwarfStackFrameDebugInfo::_CreateModifiedType(const BString& name, { // 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. - DIEModifiedType* baseTypeOwnerEntry = typeEntry; DIEType* baseTypeEntry; while (true) { - baseTypeEntry = baseTypeOwnerEntry->GetType(); - if (baseTypeEntry == NULL) { - if (DIEModifiedType* abstractOrigin - = dynamic_cast( - baseTypeOwnerEntry->AbstractOrigin())) { - baseTypeOwnerEntry = abstractOrigin; - baseTypeEntry = baseTypeOwnerEntry->GetType(); - } - } + DIEModifiedType* baseTypeOwnerEntry = DwarfUtils::GetDIEByPredicate( + typeEntry, HasTypePredicate()); + if (baseTypeOwnerEntry == NULL) + return B_BAD_VALUE; - if (baseTypeEntry == NULL) { - if (DIEModifiedType* specification = dynamic_cast( - baseTypeOwnerEntry->Specification())) { - baseTypeOwnerEntry = specification; - baseTypeEntry = baseTypeOwnerEntry->GetType(); - } - } + baseTypeEntry = baseTypeOwnerEntry->GetType(); // resolve a typedef - if (baseTypeEntry != NULL && baseTypeEntry->Tag() == DW_TAG_typedef) { + if (baseTypeEntry->Tag() == DW_TAG_typedef) { status_t error = _ResolveTypedef( dynamic_cast(baseTypeEntry), baseTypeEntry); if (error != B_OK) @@ -1372,28 +1653,225 @@ status_t DwarfStackFrameDebugInfo::_CreateArrayType(const BString& name, DIEArrayType* typeEntry, DwarfType*& _type) { -#if 0 - // get the base type entry - DIEArrayType* baseTypeOwnerEntry = typeEntry; - DIEType* baseTypeEntry = baseTypeOwnerEntry->GetType(); - if (baseTypeEntry == NULL) { - if (DIEArrayType* abstractOrigin = dynamic_cast( - baseTypeOwnerEntry->AbstractOrigin())) { - baseTypeOwnerEntry = abstractOrigin; - baseTypeEntry = baseTypeOwnerEntry->GetType(); - } - } - - if (baseTypeEntry == NULL) { - if (DIEArrayType* specification = dynamic_cast( - baseTypeOwnerEntry->Specification())) { - baseTypeOwnerEntry = specification; - baseTypeEntry = baseTypeOwnerEntry->GetType(); - } - } - - if (baseTypeEntry == NULL) + // 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) + return error; + Reference baseTypeReference(baseType, true); + + // create the array type + DwarfArrayType* type = new(std::nothrow) DwarfArrayType(name, typeEntry, + baseType); + if (type == NULL) + return B_NO_MEMORY; + Reference 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) + return error; + Reference dimensionTypeReference(dimensionType, true); + + // create and add the array dimension object + DwarfArrayDimension* dimension + = new(std::nothrow) DwarfArrayDimension(dimensionType); + Reference dimensionReference(dimension, true); + if (dimension == NULL || !type->AddDimension(dimension)) + return B_NO_MEMORY; + } + + _type = typeReference.Detach(); + return B_OK; +} + + +status_t +DwarfStackFrameDebugInfo::_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; + } + Reference baseTypeReference(baseType, true); + + // create the enumeration type + DwarfEnumerationType* type = new(std::nothrow) DwarfEnumerationType(name, + typeEntry, baseType); + if (type == NULL) + return B_NO_MEMORY; + Reference 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 = fFile->EvaluateConstantValue(fCompilationUnit, + fSubprogramEntry, enumeratorEntry->ConstValue(), + fTargetInterface, fInstructionPointer, fFramePointer, 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 + DwarfEnumerationValue* enumValue + = new(std::nothrow) DwarfEnumerationValue(enumeratorEntry, + enumeratorEntry->Name(), value); + Reference enumValueReference(enumValue, true); + if (enumValue == NULL || !type->AddValue(enumValue)) + return B_NO_MEMORY; + } + } + + _type = typeReference.Detach(); + return B_OK; +} + + +status_t +DwarfStackFrameDebugInfo::_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 = fFile->EvaluateDynamicValue(fCompilationUnit, + fSubprogramEntry, lowerBoundOwnerEntry->LowerBound(), + fTargetInterface, fInstructionPointer, fFramePointer, 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( + fCompilationUnit->SourceLanguage()->subrangeLowerBound); + } + + // get the upper bound + BVariant upperBound; + DIESubrangeType* upperBoundOwnerEntry = DwarfUtils::GetDIEByPredicate( + typeEntry, HasUpperBoundPredicate()); + if (upperBoundOwnerEntry != NULL) { + // evaluate it + DIEType* valueType; + status_t error = fFile->EvaluateDynamicValue(fCompilationUnit, + fSubprogramEntry, upperBoundOwnerEntry->UpperBound(), + fTargetInterface, fInstructionPointer, fFramePointer, 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 = fFile->EvaluateDynamicValue(fCompilationUnit, + fSubprogramEntry, countOwnerEntry->Count(), fTargetInterface, + fInstructionPointer, fFramePointer, 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()); + else + upperBound.SetTo(lowerBound.ToUInt64() + count.ToUInt64()); + } + } + + // If we still don't have a base type yet, the base type is supposed to be + // the a signed integer type with the same size as an address for that + // compilation unit. + if (baseTypeEntry == NULL) { + // TODO: Implement! + WARNING("Base type fallback for subrange type not implemented yet!\n"); + return B_UNSUPPORTED; + } // create the base type DwarfType* baseType; @@ -1402,17 +1880,16 @@ DwarfStackFrameDebugInfo::_CreateArrayType(const BString& name, return error; Reference baseTypeReference(baseType, true); - DwarfArrayType* type = new(std::nothrow) DwarfArrayType(name, typeEntry, - baseType, elementCount); + // TODO: Support the thread scaling attribute! + + // create the type + DwarfSubrangeType* type = new(std::nothrow) DwarfSubrangeType(name, + typeEntry, baseType, lowerBound, upperBound); if (type == NULL) return B_NO_MEMORY; _type = type; return B_OK; -#endif - - // TODO:... - return B_UNSUPPORTED; } @@ -1424,20 +1901,6 @@ DwarfStackFrameDebugInfo::_CreateVariable(ObjectID* id, const BString& name, if (typeEntry == NULL) return B_BAD_VALUE; - // get the location, if possible - ValueLocation* location = new(std::nothrow) ValueLocation; - if (location == NULL) - return B_NO_MEMORY; - Reference locationReference(location, true); - - if (locationDescription->IsValid()) { - fFile->ResolveLocation(fCompilationUnit, - fSubprogramEntry, locationDescription, fTargetInterface, - fInstructionPointer, 0, fFramePointer, *location); - - TRACE_LOCALS_ONLY(location->Dump()); - } - // create the type DwarfType* type; status_t error = _CreateType(typeEntry, type); @@ -1445,7 +1908,21 @@ DwarfStackFrameDebugInfo::_CreateVariable(ObjectID* id, const BString& name, return error; Reference typeReference(type, true); - _FixLocation(location, type); + // get the location, if possible + ValueLocation* location = new(std::nothrow) ValueLocation( + fArchitecture->IsBigEndian()); + if (location == NULL) + return B_NO_MEMORY; + Reference locationReference(location, true); + + if (locationDescription->IsValid()) { + status_t error = _ResolveLocation(locationDescription, 0, type, + *location); + if (error != B_OK) + return error; + + TRACE_LOCALS_ONLY(location->Dump()); + } // create the variable Variable* variable = new(std::nothrow) Variable(id, name, type, location); @@ -1464,27 +1941,12 @@ DwarfStackFrameDebugInfo::_ResolveTypedef(DIETypedef* entry, while (true) { // resolve the base type, possibly following abstract origin or // specification - DIEType* baseTypeEntry = entry->GetType(); - - if (baseTypeEntry == NULL) { - if (DIETypedef* abstractOrigin = dynamic_cast( - entry->AbstractOrigin())) { - entry = abstractOrigin; - baseTypeEntry = entry->GetType(); - } - } - - if (baseTypeEntry == NULL) { - if (DIETypedef* specification = dynamic_cast( - entry->Specification())) { - entry = specification; - baseTypeEntry = entry->GetType(); - } - } - - if (baseTypeEntry == NULL) + 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; @@ -1593,38 +2055,65 @@ DwarfStackFrameDebugInfo::_ResolveTypeByteSize(DIEType* typeEntry, } -void -DwarfStackFrameDebugInfo::_FixLocation(ValueLocation* location, DwarfType* type) +status_t +DwarfStackFrameDebugInfo::_ResolveLocation( + const LocationDescription* description, target_addr_t objectAddress, + Type* type, ValueLocation& _location) { - TRACE_LOCALS("DwarfStackFrameDebugInfo::_FixLocation(%p, %p), type entry: " - "%p\n", location, type, type->GetDIEType()); + status_t error = fFile->ResolveLocation(fCompilationUnit, + fSubprogramEntry, description, fTargetInterface, + fInstructionPointer, objectAddress, fFramePointer, _location); + if (error != B_OK) + return error; - // translate the DWARF register indices - int32 count = location->CountPieces(); + // translate the DWARF register indices and the bit offset/size semantics + const Register* registers = fArchitecture->Registers(); + bool bigEndian = fArchitecture->IsBigEndian(); + int32 count = _location.CountPieces(); for (int32 i = 0; i < count; i++) { - ValuePieceLocation piece = location->PieceAt(i); + ValuePieceLocation piece = _location.PieceAt(i); if (piece.type == VALUE_PIECE_LOCATION_REGISTER) { int32 reg = fFromDwarfRegisterMap->MapRegisterIndex(piece.reg); - if (reg >= 0) + if (reg >= 0) { piece.reg = reg; - else + // The bit offset for registers is to the least + // significant bit, while we want the offset to the most + // significant bit. + if (registers[reg].BitSize() > piece.bitSize) { + piece.bitOffset = registers[reg].BitSize() - piece.bitSize + - piece.bitOffset; + } + } else piece.SetToUnknown(); - - location->SetPieceAt(i, piece); + } else if (piece.type == VALUE_PIECE_LOCATION_MEMORY) { + // Whether the bit offset is to the least or most significant bit + // is target architecture and source language specific. + // TODO: Check whether this is correct! + // TODO: Source language! + if (!bigEndian && piece.size * 8 > piece.bitSize) { + piece.bitOffset = piece.size * 8 - piece.bitSize + - piece.bitOffset; + } } + + piece.Normalize(bigEndian); + _location.SetPieceAt(i, piece); } // If we only have one piece and that doesn't have a size, try to retrieve // the size of the type. if (count == 1) { - ValuePieceLocation piece = location->PieceAt(0); + ValuePieceLocation piece = _location.PieceAt(0); if (piece.IsValid() && piece.size == 0 && piece.bitSize == 0) { piece.SetSize(type->ByteSize()); - location->SetPieceAt(0, piece); + // TODO: Use bit size and bit offset, if specified! + _location.SetPieceAt(0, piece); TRACE_LOCALS(" set single piece size to %llu\n", type->ByteSize()); } } + + return B_OK; } diff --git a/src/apps/debugger/debug_info/DwarfStackFrameDebugInfo.h b/src/apps/debugger/debug_info/DwarfStackFrameDebugInfo.h index e37e77cefd..fdd62ff8db 100644 --- a/src/apps/debugger/debug_info/DwarfStackFrameDebugInfo.h +++ b/src/apps/debugger/debug_info/DwarfStackFrameDebugInfo.h @@ -19,9 +19,11 @@ class DIEAddressingType; class DIEArrayType; class DIEBaseType; class DIECompoundType; +class DIEEnumerationType; class DIEFormalParameter; class DIEModifiedType; class DIESubprogram; +class DIESubrangeType; class DIEType; class DIETypedef; class DIEVariable; @@ -37,7 +39,8 @@ class Variable; class DwarfStackFrameDebugInfo : public StackFrameDebugInfo { public: - DwarfStackFrameDebugInfo(DwarfFile* file, + DwarfStackFrameDebugInfo( + Architecture* architecture, DwarfFile* file, CompilationUnit* compilationUnit, DIESubprogram* subprogramEntry, target_addr_t instructionPointer, @@ -50,7 +53,7 @@ public: virtual status_t ResolveObjectDataLocation( StackFrame* stackFrame, Type* type, - target_addr_t objectAddress, + const ValueLocation& objectLocation, ValueLocation*& _location); virtual status_t ResolveBaseTypeLocation( StackFrame* stackFrame, Type* type, @@ -80,11 +83,15 @@ private: struct DwarfType; struct DwarfInheritance; struct DwarfDataMember; + struct DwarfEnumerationValue; + struct DwarfArrayDimension; struct DwarfPrimitiveType; struct DwarfCompoundType; struct DwarfModifiedType; struct DwarfTypedefType; struct DwarfAddressType; + struct DwarfEnumerationType; + struct DwarfSubrangeType; struct DwarfArrayType; struct DwarfTypeHashDefinition; @@ -123,6 +130,12 @@ private: status_t _CreateArrayType(const BString& name, DIEArrayType* typeEntry, DwarfType*& _type); + status_t _CreateEnumerationType(const BString& name, + DIEEnumerationType* typeEntry, + DwarfType*& _type); + status_t _CreateSubrangeType(const BString& name, + DIESubrangeType* typeEntry, + DwarfType*& _type); status_t _CreateVariable(ObjectID* id, const BString& name, DIEType* typeEntry, @@ -134,8 +147,10 @@ private: status_t _ResolveTypeByteSize(DIEType* typeEntry, uint64& _size); - void _FixLocation(ValueLocation* location, - DwarfType* type); + status_t _ResolveLocation( + const LocationDescription* description, + target_addr_t objectAddress, Type* type, + ValueLocation& _location); template static DIEType* _GetDIEType(EntryType* entry); diff --git a/src/apps/debugger/debug_info/NoOpStackFrameDebugInfo.cpp b/src/apps/debugger/debug_info/NoOpStackFrameDebugInfo.cpp index d6eca46811..8fdf26128e 100644 --- a/src/apps/debugger/debug_info/NoOpStackFrameDebugInfo.cpp +++ b/src/apps/debugger/debug_info/NoOpStackFrameDebugInfo.cpp @@ -7,7 +7,9 @@ #include "NoOpStackFrameDebugInfo.h" -NoOpStackFrameDebugInfo::NoOpStackFrameDebugInfo() +NoOpStackFrameDebugInfo::NoOpStackFrameDebugInfo(Architecture* architecture) + : + StackFrameDebugInfo(architecture) { } @@ -19,7 +21,7 @@ NoOpStackFrameDebugInfo::~NoOpStackFrameDebugInfo() status_t NoOpStackFrameDebugInfo::ResolveObjectDataLocation(StackFrame* stackFrame, - Type* type, target_addr_t objectAddress, ValueLocation*& _location) + Type* type, const ValueLocation& objectLocation, ValueLocation*& _location) { return B_UNSUPPORTED; } diff --git a/src/apps/debugger/debug_info/NoOpStackFrameDebugInfo.h b/src/apps/debugger/debug_info/NoOpStackFrameDebugInfo.h index 73516465d6..f2a9f96afb 100644 --- a/src/apps/debugger/debug_info/NoOpStackFrameDebugInfo.h +++ b/src/apps/debugger/debug_info/NoOpStackFrameDebugInfo.h @@ -11,12 +11,13 @@ class NoOpStackFrameDebugInfo : public StackFrameDebugInfo { public: - NoOpStackFrameDebugInfo(); + NoOpStackFrameDebugInfo( + Architecture* architecture); virtual ~NoOpStackFrameDebugInfo(); virtual status_t ResolveObjectDataLocation( StackFrame* stackFrame, Type* type, - target_addr_t objectAddress, + const ValueLocation& objectLocation, ValueLocation*& _location); virtual status_t ResolveBaseTypeLocation( StackFrame* stackFrame, Type* type, diff --git a/src/apps/debugger/debug_info/StackFrameDebugInfo.cpp b/src/apps/debugger/debug_info/StackFrameDebugInfo.cpp index 85c05a7adc..61878b986b 100644 --- a/src/apps/debugger/debug_info/StackFrameDebugInfo.cpp +++ b/src/apps/debugger/debug_info/StackFrameDebugInfo.cpp @@ -6,12 +6,39 @@ #include "StackFrameDebugInfo.h" +#include "Architecture.h" +#include "ValueLocation.h" -StackFrameDebugInfo::StackFrameDebugInfo() + +StackFrameDebugInfo::StackFrameDebugInfo(Architecture* architecture) + : + fArchitecture(architecture) { + fArchitecture->AcquireReference(); } StackFrameDebugInfo::~StackFrameDebugInfo() { + fArchitecture->ReleaseReference(); +} + + +status_t +StackFrameDebugInfo::ResolveObjectDataLocation(StackFrame* stackFrame, + Type* type, target_addr_t objectAddress, ValueLocation*& _location) +{ + ValuePieceLocation piece; + piece.SetToMemory(objectAddress); + piece.SetSize(0); + // We set the piece size to 0 as an indicator that the size has to be + // set. + // TODO: We could set the byte size from type, but that may not be + // accurate. We may want to add bit offset and size to Type. + + ValueLocation location(fArchitecture->IsBigEndian()); + if (!location.AddPiece(piece)) + return B_NO_MEMORY; + + return ResolveObjectDataLocation(stackFrame, type, location, _location); } diff --git a/src/apps/debugger/debug_info/StackFrameDebugInfo.h b/src/apps/debugger/debug_info/StackFrameDebugInfo.h index e407630561..bf3cf8d836 100644 --- a/src/apps/debugger/debug_info/StackFrameDebugInfo.h +++ b/src/apps/debugger/debug_info/StackFrameDebugInfo.h @@ -11,6 +11,7 @@ #include "Types.h" +class Architecture; class BaseType; class DataMember; class StackFrame; @@ -20,14 +21,19 @@ class ValueLocation; class StackFrameDebugInfo : public Referenceable { public: - StackFrameDebugInfo(); + StackFrameDebugInfo(Architecture* architecture); virtual ~StackFrameDebugInfo(); virtual status_t ResolveObjectDataLocation( StackFrame* stackFrame, Type* type, - target_addr_t objectAddress, + const ValueLocation& objectLocation, ValueLocation*& _location) = 0; // returns a reference + status_t ResolveObjectDataLocation( + StackFrame* stackFrame, Type* type, + target_addr_t objectAddress, + ValueLocation*& _location); + // returns a reference virtual status_t ResolveBaseTypeLocation( StackFrame* stackFrame, Type* type, BaseType* baseType, @@ -40,6 +46,9 @@ public: const ValueLocation& parentLocation, ValueLocation*& _location) = 0; // returns a reference + +protected: + Architecture* fArchitecture; }; diff --git a/src/apps/debugger/gui/team_window/VariablesView.cpp b/src/apps/debugger/gui/team_window/VariablesView.cpp index f071bb901f..f36f2a9769 100644 --- a/src/apps/debugger/gui/team_window/VariablesView.cpp +++ b/src/apps/debugger/gui/team_window/VariablesView.cpp @@ -24,7 +24,12 @@ #include "Variable.h" -class VariablesView::ValueNode : Referenceable { +enum { + VALUE_NODE_TYPE = 'valn' +}; + + +class VariablesView::ValueNode : public Referenceable { public: ValueNode(ValueNode* parent, Variable* variable, TypeComponentPath* path, const BString& name, Type* type) @@ -34,11 +39,13 @@ public: fPath(path), fName(name), fType(type), + fRawType(type->ResolveRawType()), fChildrenAdded(false) { fVariable->AcquireReference(); fPath->AcquireReference(); fType->AcquireReference(); + fRawType->AcquireReference(); } ~ValueNode() @@ -49,6 +56,7 @@ public: fVariable->ReleaseReference(); fPath->ReleaseReference(); fType->ReleaseReference(); + fRawType->ReleaseReference(); } ValueNode* Parent() const @@ -76,6 +84,11 @@ public: return fType; } + Type* RawType() const + { + return fRawType; + } + const BVariant& Value() const { return fValue; @@ -129,6 +142,7 @@ private: TypeComponentPath* fPath; BString fName; Type* fType; + Type* fRawType; BVariant fValue; ChildList fChildren; bool fChildrenAdded; @@ -150,16 +164,21 @@ public: } protected: - virtual BField* PrepareField(const BVariant& value) const + virtual BField* PrepareField(const BVariant& _value) const { + BVariant value = _ResolveValue(_value); + char buffer[64]; return StringTableColumn::PrepareField( BVariant(_ToString(value, buffer, sizeof(buffer)), B_VARIANT_DONT_COPY_DATA)); } - virtual int CompareValues(const BVariant& a, const BVariant& b) + virtual int CompareValues(const BVariant& _a, const BVariant& _b) { + BVariant a = _ResolveValue(_a); + BVariant b = _ResolveValue(_b); + // If neither value is a number, compare the strings. If only one value // is a number, it is considered to be greater. if (!a.IsNumber()) { @@ -190,6 +209,26 @@ protected: } private: + BVariant _ResolveValue(const BVariant& nodeValue) const + { + BVariant value; + if (nodeValue.Type() != VALUE_NODE_TYPE) + return BVariant(); + + ValueNode* node = dynamic_cast(nodeValue.ToReferenceable()); + + // replace enumerations values with their names + if (node->RawType()->Kind() == TYPE_ENUMERATION) { + EnumerationValue* enumValue + = dynamic_cast(node->RawType()) + ->ValueFor(node->Value()); + if (enumValue != NULL) + return enumValue->Name(); + } + + return node->Value(); + } + const char* _ToString(const BVariant& value, char* buffer, size_t bufferSize) const { @@ -329,7 +368,7 @@ public: if (node->Value().Type() == 0) return false; - _value = node->Value(); + _value.SetTo(node, VALUE_NODE_TYPE); return true; default: return false; @@ -484,6 +523,10 @@ private: TRACE_LOCALS("TYPE_ARRAY\n"); // TODO:... return; + case TYPE_ENUMERATION: + TRACE_LOCALS("TYPE_ENUMERATION\n"); + done = true; + return; default: TRACE_LOCALS("unknown\n"); return; diff --git a/src/apps/debugger/model/Type.cpp b/src/apps/debugger/model/Type.cpp index 79d5204858..6fa71d6bf9 100644 --- a/src/apps/debugger/model/Type.cpp +++ b/src/apps/debugger/model/Type.cpp @@ -23,6 +23,47 @@ DataMember::~DataMember() } +// #pragma mark - EnumerationValue + + +EnumerationValue::~EnumerationValue() +{ +} + + +// #pragma mark - ArrayDimension + + +ArrayDimension::~ArrayDimension() +{ +} + + +uint64 +ArrayDimension::CountElements() const +{ + Type* type = GetType(); + + if (type->Kind() == TYPE_ENUMERATION) + return dynamic_cast(type)->CountValues(); + + if (type->Kind() == TYPE_SUBRANGE) { + SubrangeType* subrangeType = dynamic_cast(type); + BVariant lower = subrangeType->LowerBound(); + BVariant upper = subrangeType->LowerBound(); + bool isSigned; + if (!lower.IsInteger(&isSigned) || !upper.IsInteger()) + return 0; + + return isSigned + ? upper.ToInt64() - lower.ToInt64() + : upper.ToUInt64() - lower.ToUInt64(); + } + + return 0; +} + + // #pragma mark - Type @@ -31,6 +72,13 @@ Type::~Type() } +Type* +Type::ResolveRawType() const +{ + return const_cast(this); +} + + // #pragma mark - PrimitiveType @@ -76,6 +124,13 @@ ModifiedType::Kind() const } +Type* +ModifiedType::ResolveRawType() const +{ + return BaseType(); +} + + // #pragma mark - TypedefType @@ -91,6 +146,13 @@ TypedefType::Kind() const } +Type* +TypedefType::ResolveRawType() const +{ + return BaseType(); +} + + // #pragma mark - AddressType @@ -106,6 +168,49 @@ AddressType::Kind() const } +// #pragma mark - EnumerationType + + +EnumerationType::~EnumerationType() +{ +} + + +type_kind +EnumerationType::Kind() const +{ + return TYPE_ENUMERATION; +} + + +EnumerationValue* +EnumerationType::ValueFor(const BVariant& value) const +{ + // TODO: Optimize? + for (int32 i = 0; EnumerationValue* enumValue = ValueAt(i); i++) { + if (enumValue->Value() == value) + return enumValue; + } + + return NULL; +} + + +// #pragma mark - SubrangeType + + +SubrangeType::~SubrangeType() +{ +} + + +type_kind +SubrangeType::Kind() const +{ + return TYPE_SUBRANGE; +} + + // #pragma mark - ArrayType diff --git a/src/apps/debugger/model/Type.h b/src/apps/debugger/model/Type.h index e4e3b71b04..0e8adac556 100644 --- a/src/apps/debugger/model/Type.h +++ b/src/apps/debugger/model/Type.h @@ -7,6 +7,7 @@ #include +#include #include "Types.h" @@ -17,6 +18,8 @@ enum type_kind { TYPE_MODIFIED, TYPE_TYPEDEF, TYPE_ADDRESS, + TYPE_ENUMERATION, + TYPE_SUBRANGE, TYPE_ARRAY }; @@ -56,6 +59,26 @@ public: }; +class EnumerationValue : public Referenceable { +public: + virtual ~EnumerationValue(); + + virtual const char* Name() const = 0; + virtual BVariant Value() const = 0; +}; + + +class ArrayDimension : public Referenceable { +public: + virtual ~ArrayDimension(); + + virtual Type* GetType() const = 0; + // subrange or enumeration + virtual uint64 CountElements() const; + // returns 0, if unknown +}; + + class Type : public Referenceable { public: virtual ~Type(); @@ -63,6 +86,8 @@ public: virtual const char* Name() const = 0; virtual type_kind Kind() const = 0; virtual target_size_t ByteSize() const = 0; + virtual Type* ResolveRawType() const; + // strips modifiers and typedefs }; @@ -98,6 +123,7 @@ public: virtual uint32 Modifiers() const = 0; virtual Type* BaseType() const = 0; + virtual Type* ResolveRawType() const; }; @@ -108,6 +134,7 @@ public: virtual type_kind Kind() const; virtual Type* BaseType() const = 0; + virtual Type* ResolveRawType() const; }; @@ -122,6 +149,34 @@ public: }; +class EnumerationType : public virtual Type { +public: + virtual ~EnumerationType(); + + virtual type_kind Kind() const; + + virtual Type* BaseType() const = 0; + // may return NULL + + virtual int32 CountValues() const = 0; + virtual EnumerationValue* ValueAt(int32 index) const = 0; + virtual EnumerationValue* ValueFor(const BVariant& value) const; +}; + + +class SubrangeType : public virtual Type { +public: + virtual ~SubrangeType(); + + virtual type_kind Kind() const; + + virtual Type* BaseType() const = 0; + + virtual BVariant LowerBound() const = 0; + virtual BVariant UpperBound() const = 0; +}; + + class ArrayType : public virtual Type { public: virtual ~ArrayType(); @@ -129,9 +184,9 @@ public: virtual type_kind Kind() const; virtual Type* BaseType() const = 0; - virtual target_size_t CountElements() const = 0; - // TODO: That doesn't work. We need a list of dimensions which in turn - // are enumeration or subrange types. + + virtual int32 CountDimensions() const = 0; + virtual ArrayDimension* DimensionAt(int32 index) const = 0; }; diff --git a/src/apps/debugger/model/TypeComponentPath.cpp b/src/apps/debugger/model/TypeComponentPath.cpp index c391789e81..b0dd5aa1ec 100644 --- a/src/apps/debugger/model/TypeComponentPath.cpp +++ b/src/apps/debugger/model/TypeComponentPath.cpp @@ -43,6 +43,12 @@ TypeComponent::Dump() const case TYPE_ADDRESS: printf("address"); break; + case TYPE_ENUMERATION: + printf("enum"); + break; + case TYPE_SUBRANGE: + printf("subrange"); + break; case TYPE_ARRAY: printf("array"); break; diff --git a/src/apps/debugger/types/ValueLocation.cpp b/src/apps/debugger/types/ValueLocation.cpp index 9b40ea2b4d..453de97a28 100644 --- a/src/apps/debugger/types/ValueLocation.cpp +++ b/src/apps/debugger/types/ValueLocation.cpp @@ -7,12 +7,59 @@ #include "ValueLocation.h" +// #pragma mark - ValuePieceLocation + + +ValuePieceLocation& +ValuePieceLocation::Normalize(bool bigEndian) +{ + uint64 excessMSBs = bitOffset / 8; + uint64 excessLSBs = size - (bitOffset + bitSize + 7) / 8; + + if (excessMSBs > 0 || excessLSBs > 0) { + switch (type) { + case VALUE_PIECE_LOCATION_MEMORY: + if (bigEndian) + address += excessMSBs; + else + address += excessLSBs; + bitOffset -= excessMSBs * 8; + size -= excessMSBs + excessLSBs; + break; + case VALUE_PIECE_LOCATION_UNKNOWN: + bitOffset -= excessMSBs * 8; + size -= excessMSBs + excessLSBs; + break; + case VALUE_PIECE_LOCATION_REGISTER: + default: + break; + } + } + + return *this; +} + + +// #pragma mark - ValueLocation + + ValueLocation::ValueLocation() + : + fBigEndian(false) { } -ValueLocation::ValueLocation(const ValuePieceLocation& piece) +ValueLocation::ValueLocation(bool bigEndian) + : + fBigEndian(bigEndian) +{ +} + + +ValueLocation::ValueLocation(bool bigEndian, const ValuePieceLocation& piece) + : + fBigEndian(bigEndian) { AddPiece(piece); } @@ -20,7 +67,8 @@ ValueLocation::ValueLocation(const ValuePieceLocation& piece) ValueLocation::ValueLocation(const ValueLocation& other) : - fPieces(other.fPieces) + fPieces(other.fPieces), + fBigEndian(other.fBigEndian) { } @@ -31,60 +79,105 @@ ValueLocation::SetTo(const ValueLocation& other, uint64 bitOffset, { Clear(); - // skip pieces before the offset + fBigEndian = other.fBigEndian; + + // compute the total bit size int32 count = other.CountPieces(); - int32 i; - ValuePieceLocation piece; - for (i = 0; i < count; i++) { - piece = other.PieceAt(i); - if (piece.size * 8 + piece.bitSize > bitOffset) - break; - bitOffset -= piece.size * 8 + piece.bitSize; + uint64 totalBitSize = 0; + for (int32 i = 0; i < count; i++) { + ValuePieceLocation piece = other.PieceAt(i); + totalBitSize += piece.bitSize; } - if (i >= count) - return true; + // adjust requested bit offset/size to something reasonable, if necessary + if (bitOffset + bitSize > totalBitSize) { + if (bitOffset >= totalBitSize) + return true; + bitSize = totalBitSize - bitOffset; + } - // handle partial piece - if (bitOffset > 0) { - uint64 remainingBits = piece.size * 8 + piece.bitSize - bitOffset; - piece.size = remainingBits / 8; - piece.bitSize = remainingBits % 8; + if (fBigEndian) { + // Big endian: Skip the superfluous most significant bits, copy the + // pieces we need (cutting the first and the last one as needed) and + // ignore the remaining pieces. - switch (piece.type) { - case VALUE_PIECE_LOCATION_MEMORY: - piece.address += (bitOffset + piece.bitOffset) / 8; - piece.bitOffset = (bitOffset + piece.bitOffset) % 8; - break; - case VALUE_PIECE_LOCATION_UNKNOWN: - piece.bitOffset = 0; - break; - case VALUE_PIECE_LOCATION_REGISTER: - piece.bitOffset += bitOffset; - break; - default: + // skip pieces for the most significant bits we don't need anymore + uint64 bitsToSkip = bitOffset; + int32 i; + ValuePieceLocation piece; + for (i = 0; i < count; i++) { + piece = other.PieceAt(i); + if (piece.bitSize > bitsToSkip) break; + bitsToSkip -= piece.bitSize; } - } - // handle remaining pieces - while (bitSize > 0) { - target_addr_t pieceSize = piece.size * 8 + piece.bitSize; - if (pieceSize > bitSize) { - // the piece is bigger than the remaining size -- cut it - piece.size = bitSize / 8; - piece.bitSize = bitSize % 8; - bitSize = 0; - } else - bitSize -= pieceSize; + // handle partial piece + if (bitsToSkip > 0) { + piece.bitOffset += bitsToSkip; + piece.bitSize -= bitsToSkip; + piece.Normalize(fBigEndian); + } - if (!AddPiece(piece)) - return false; + // handle remaining pieces + while (bitSize > 0) { + if (piece.bitSize > bitSize) { + // the piece is bigger than the remaining size -- cut it + piece.bitSize = bitSize; + piece.Normalize(fBigEndian); + bitSize = 0; + } else + bitSize -= piece.bitSize; - if (++i >= count) - break; + if (!AddPiece(piece)) + return false; - piece = other.PieceAt(i); + if (++i >= count) + break; + + piece = other.PieceAt(i); + } + } else { + // Little endian: Skip the superfluous least significant bits, copy the + // pieces we need (cutting the first and the last one as needed) and + // ignore the remaining pieces. + + // skip pieces for the least significant bits we don't need anymore + uint64 bitsToSkip = totalBitSize - bitOffset - bitSize; + int32 i; + ValuePieceLocation piece; + for (i = 0; i < count; i++) { + piece = other.PieceAt(i); + if (piece.bitSize > bitsToSkip) + break; + bitsToSkip -= piece.bitSize; + } + + // handle partial piece + if (bitsToSkip > 0) { + piece.bitSize -= bitsToSkip; + piece.Normalize(fBigEndian); + } + + // handle remaining pieces + while (bitSize > 0) { + if (piece.bitSize > bitSize) { + // the piece is bigger than the remaining size -- cut it + piece.bitOffset += piece.bitSize - bitSize; + piece.bitSize = bitSize; + piece.Normalize(fBigEndian); + bitSize = 0; + } else + bitSize -= piece.bitSize; + + if (!AddPiece(piece)) + return false; + + if (++i >= count) + break; + + piece = other.PieceAt(i); + } } return true; @@ -101,6 +194,8 @@ ValueLocation::Clear() bool ValueLocation::AddPiece(const ValuePieceLocation& piece) { + // Just add, don't normalize. This allows for using the class with different + // semantics (e.g. in the DWARF code). return fPieces.Add(piece); } @@ -136,6 +231,7 @@ ValueLocation& ValueLocation::operator=(const ValueLocation& other) { fPieces = other.fPieces; + fBigEndian = other.fBigEndian; return *this; } @@ -144,7 +240,8 @@ void ValueLocation::Dump() const { int32 count = fPieces.Size(); - printf("ValueLocation: %ld pieces:\n", count); + printf("ValueLocation: %s endian, %ld pieces:\n", + fBigEndian ? "big" : "little", count); for (int32 i = 0; i < count; i++) { const ValuePieceLocation& piece = fPieces[i]; @@ -163,7 +260,7 @@ ValueLocation::Dump() const break; } - printf(" size: %llu+%u, offset: %u\n", piece.size, piece.bitSize, - piece.bitOffset); + printf(" size: %llu (%llu bits), offset: %llu bits\n", piece.size, + piece.bitSize, piece.bitOffset); } } diff --git a/src/apps/debugger/types/ValueLocation.h b/src/apps/debugger/types/ValueLocation.h index 51251aaa2b..c6065e7180 100644 --- a/src/apps/debugger/types/ValueLocation.h +++ b/src/apps/debugger/types/ValueLocation.h @@ -25,9 +25,11 @@ struct ValuePieceLocation { target_addr_t address; // memory address uint32 reg; // register number }; - target_size_t size; // size in bytes (complete ones) - uint8 bitSize; // totalBitSize = size * 8 + bitSize - uint8 bitOffset; // offset in bits + target_size_t size; // size in bytes (including + // incomplete ones) + uint64 bitSize; // total size in bits + uint64 bitOffset; // bit offset (to the most + // significant bit) value_piece_location_type type; ValuePieceLocation() @@ -61,29 +63,36 @@ struct ValuePieceLocation { void SetSize(target_size_t size) { this->size = size; - this->bitSize = 0; + this->bitSize = size * 8; this->bitOffset = 0; } - void SetSize(uint64 bitSize, uint8 bitOffset) + void SetSize(uint64 bitSize, uint64 bitOffset) { - this->size = bitSize / 8; - this->bitSize = bitSize % 8; + this->size = (bitOffset + bitSize + 7) / 8; + this->bitSize = bitSize; this->bitOffset = bitOffset; } + + ValuePieceLocation& Normalize(bool bigEndian); }; class ValueLocation : public Referenceable { public: ValueLocation(); - ValueLocation(const ValuePieceLocation& piece); + ValueLocation(bool bigEndian); + ValueLocation(bool bigEndian, + const ValuePieceLocation& piece); ValueLocation(const ValueLocation& other); bool SetTo(const ValueLocation& other, uint64 bitOffset, uint64 bitSize); void Clear(); + + bool IsBigEndian() const { return fBigEndian; } + bool AddPiece(const ValuePieceLocation& piece); int32 CountPieces() const; @@ -100,6 +109,7 @@ private: private: PieceArray fPieces; + bool fBigEndian; };