From e82b494112f921f214e2ff6604ddfba1e2ef63a9 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 27 Sep 2009 04:52:43 +0000 Subject: [PATCH] * ValueLocation: - Changed the bit{Offset,Size} semantics. It's now more or less aligned with the semantics of the respective DWARF DIE attributes. DwarfStackFrameDebugInfo does now correctly translate the ValueLocations returned by the DWARF layer (the bit piece location expression semantics is different for some reason). - ValueLocation is now aware of the target's endianess. The SetTo() method needs that information to correctly meddle with the pieces. - Support normalizing the pieces. * Fixed retrieving the values of bit fields in various places. We still don't handle the bit offset/size attributes of types correctly, but I haven't seen those in actual debug info yet. * Added support for enumerations. The variable view shows the enumerator names, when available. * Added partial support for subrange types. C++ doesn't have those -- we only need them for array dimensions. * Started adding support for array types. Still work in progress. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33314 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/debugger/Jobs.cpp | 121 ++- .../debugger/arch/x86/ArchitectureX86.cpp | 2 +- .../debug_info/DwarfImageDebugInfo.cpp | 3 +- .../debug_info/DwarfStackFrameDebugInfo.cpp | 933 +++++++++++++----- .../debug_info/DwarfStackFrameDebugInfo.h | 23 +- .../debug_info/NoOpStackFrameDebugInfo.cpp | 6 +- .../debug_info/NoOpStackFrameDebugInfo.h | 5 +- .../debug_info/StackFrameDebugInfo.cpp | 29 +- .../debugger/debug_info/StackFrameDebugInfo.h | 13 +- .../gui/team_window/VariablesView.cpp | 51 +- src/apps/debugger/model/Type.cpp | 105 ++ src/apps/debugger/model/Type.h | 61 +- src/apps/debugger/model/TypeComponentPath.cpp | 6 + src/apps/debugger/types/ValueLocation.cpp | 193 +++- src/apps/debugger/types/ValueLocation.h | 26 +- 15 files changed, 1240 insertions(+), 337 deletions(-) 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; };