status_t DwarfType::ResolveObjectDataLocation(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. // 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(ByteSize()); // TODO: Use bit size and bit offset, if specified! ValueLocation* location = new(std::nothrow) ValueLocation( objectLocation.IsBigEndian()); if (location == NULL || !location->AddPiece(piece)) { delete location; return B_NO_MEMORY; } _location = location; return B_OK; }
status_t DwarfCompoundType::_ResolveDataMemberLocation(DwarfType* memberType, const MemberLocation* memberLocation, const ValueLocation& parentLocation, bool isBitField, ValueLocation*& _location) { // create the value location object for the member ValueLocation* location = new(std::nothrow) ValueLocation( parentLocation.IsBigEndian()); if (location == NULL) return B_NO_MEMORY; BReference<ValueLocation> locationReference(location, true); switch (memberLocation->attributeClass) { case ATTRIBUTE_CLASS_CONSTANT: { if (isBitField) { if (!location->SetTo(parentLocation, memberLocation->constant * 8, memberType->ByteSize() * 8)) { return B_NO_MEMORY; } } else { if (!location->SetToByteOffset(parentLocation, memberLocation->constant, memberType->ByteSize())) { return B_NO_MEMORY; } } break; } case ATTRIBUTE_CLASS_BLOCK: case ATTRIBUTE_CLASS_LOCLISTPTR: { // The attribute is a location description. Since we need to push // the parent object value onto the stack, we require the parent // location to be a memory location. if (parentLocation.CountPieces() != 1) return B_BAD_VALUE; ValuePieceLocation piece = parentLocation.PieceAt(0); if (piece.type != VALUE_PIECE_LOCATION_MEMORY) return B_BAD_VALUE; // convert member location to location description LocationDescription locationDescription; if (memberLocation->attributeClass == ATTRIBUTE_CLASS_BLOCK) { locationDescription.SetToExpression( memberLocation->expression.data, memberLocation->expression.length); } else { locationDescription.SetToLocationList( memberLocation->listOffset); } // evaluate the location description status_t error = memberType->ResolveLocation(TypeContext(), &locationDescription, piece.address, true, *location); if (error != B_OK) return error; break; } default: { // for unions the member location can be omitted -- all members // start at the beginning of the parent object if (fEntry->Tag() != DW_TAG_union_type) return B_BAD_VALUE; // since all members start at the same location, set up // the location by hand since we don't want the size difference // between the overall union and the member being // factored into the assigned address. ValuePieceLocation piece = parentLocation.PieceAt(0); piece.SetSize(memberType->ByteSize()); if (!location->AddPiece(piece)) return B_NO_MEMORY; break; } } _location = locationReference.Detach(); return B_OK; }
status_t DwarfType::ResolveLocation(DwarfTypeContext* typeContext, const LocationDescription* description, target_addr_t objectAddress, bool hasObjectAddress, ValueLocation& _location) { status_t error = typeContext->File()->ResolveLocation( typeContext->GetCompilationUnit(), typeContext->AddressSize(), typeContext->SubprogramEntry(), description, typeContext->TargetInterface(), typeContext->InstructionPointer(), objectAddress, hasObjectAddress, typeContext->FramePointer(), typeContext->RelocationDelta(), _location); if (error != B_OK) return error; // translate the DWARF register indices and the bit offset/size semantics const Register* registers = typeContext->GetArchitecture()->Registers(); bool bigEndian = typeContext->GetArchitecture()->IsBigEndian(); int32 count = _location.CountPieces(); for (int32 i = 0; i < count; i++) { ValuePieceLocation piece = _location.PieceAt(i); if (piece.type == VALUE_PIECE_LOCATION_REGISTER) { int32 reg = typeContext->FromDwarfRegisterMap()->MapRegisterIndex( piece.reg); if (reg >= 0) { piece.reg = reg; // 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(); } 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); if (piece.IsValid() && piece.size == 0 && piece.bitSize == 0) { piece.SetSize(ByteSize()); // TODO: Use bit size and bit offset, if specified! _location.SetPieceAt(0, piece); TRACE_LOCALS(" set single piece size to %" B_PRIu64 "\n", ByteSize()); } } return B_OK; }
status_t DwarfArrayType::ResolveElementLocation(const ArrayIndexPath& indexPath, const ValueLocation& parentLocation, ValueLocation*& _location) { if (indexPath.CountIndices() != CountDimensions()) return B_BAD_VALUE; DwarfTypeContext* typeContext = TypeContext(); // If the array entry has a bit stride, get it. Otherwise fall back to the // element type size. int64 bitStride; DIEArrayType* bitStrideOwnerEntry = NULL; if (fEntry != NULL && (bitStrideOwnerEntry = DwarfUtils::GetDIEByPredicate( fEntry, HasBitStridePredicate<DIEArrayType>()))) { BVariant value; status_t error = typeContext->File()->EvaluateDynamicValue( typeContext->GetCompilationUnit(), typeContext->AddressSize(), typeContext->SubprogramEntry(), bitStrideOwnerEntry->BitStride(), typeContext->TargetInterface(), typeContext->InstructionPointer(), typeContext->FramePointer(), value); if (error != B_OK) return error; if (!value.IsInteger()) return B_BAD_VALUE; bitStride = value.ToInt64(); } else bitStride = BaseType()->ByteSize() * 8; // Iterate backward through the dimensions and compute the total offset of // the element. int64 elementOffset = 0; DwarfArrayDimension* previousDimension = NULL; int64 previousDimensionStride = 0; for (int32 dimensionIndex = CountDimensions() - 1; dimensionIndex >= 0; dimensionIndex--) { DwarfArrayDimension* dimension = DwarfDimensionAt(dimensionIndex); int64 index = indexPath.IndexAt(dimensionIndex); // If the dimension has a special bit/byte stride, get it. int64 dimensionStride = 0; DwarfType* dimensionType = dimension->GetDwarfType(); DIEArrayIndexType* dimensionTypeEntry = dimensionType != NULL ? dynamic_cast<DIEArrayIndexType*>(dimensionType->GetDIEType()) : NULL; if (dimensionTypeEntry != NULL) { DIEArrayIndexType* bitStrideOwnerEntry = DwarfUtils::GetDIEByPredicate(dimensionTypeEntry, HasBitStridePredicate<DIEArrayIndexType>()); if (bitStrideOwnerEntry != NULL) { BVariant value; status_t error = typeContext->File()->EvaluateDynamicValue( typeContext->GetCompilationUnit(), typeContext->AddressSize(), typeContext->SubprogramEntry(), bitStrideOwnerEntry->BitStride(), typeContext->TargetInterface(), typeContext->InstructionPointer(), typeContext->FramePointer(), value); if (error != B_OK) return error; if (!value.IsInteger()) return B_BAD_VALUE; dimensionStride = value.ToInt64(); } else { DIEArrayIndexType* byteStrideOwnerEntry = DwarfUtils::GetDIEByPredicate(dimensionTypeEntry, HasByteStridePredicate<DIEArrayIndexType>()); if (byteStrideOwnerEntry != NULL) { BVariant value; status_t error = typeContext->File()->EvaluateDynamicValue( typeContext->GetCompilationUnit(), typeContext->AddressSize(), typeContext->SubprogramEntry(), byteStrideOwnerEntry->ByteStride(), typeContext->TargetInterface(), typeContext->InstructionPointer(), typeContext->FramePointer(), value); if (error != B_OK) return error; if (!value.IsInteger()) return B_BAD_VALUE; dimensionStride = value.ToInt64() * 8; } } } // If we don't have a stride for the dimension yet, use the stride of // the previous dimension multiplied by the size of the dimension. if (dimensionStride == 0) { if (previousDimension != NULL) { dimensionStride = previousDimensionStride * previousDimension->CountElements(); } else { // the last dimension -- use the element bit stride dimensionStride = bitStride; } } // If the dimension stride is still 0 (that can happen, if the dimension // doesn't have a stride and the previous dimension's element count is // not known), we can only resolve the first element. if (dimensionStride == 0 && index != 0) { WARNING("No dimension bit stride for dimension %" B_PRId32 " and " "element index is not 0.\n", dimensionIndex); return B_BAD_VALUE; } elementOffset += dimensionStride * index; previousDimension = dimension; previousDimensionStride = dimensionStride; } TRACE_LOCALS("total element bit offset: %" B_PRId64 "\n", elementOffset); // create the value location object for the element ValueLocation* location = new(std::nothrow) ValueLocation( parentLocation.IsBigEndian()); if (location == NULL) return B_NO_MEMORY; BReference<ValueLocation> locationReference(location, true); // If we have a single memory piece location for the array, we compute the // element's location by hand -- not uncommonly the array size isn't known. if (parentLocation.CountPieces() == 1) { ValuePieceLocation piece = parentLocation.PieceAt(0); if (piece.type == VALUE_PIECE_LOCATION_MEMORY) { int64 byteOffset = elementOffset >= 0 ? elementOffset / 8 : (elementOffset - 7) / 8; piece.SetToMemory(piece.address + byteOffset); piece.SetSize(BaseType()->ByteSize()); // TODO: Support bit offsets correctly! // TODO: Support bit fields (primitive types) correctly! if (!location->AddPiece(piece)) return B_NO_MEMORY; _location = locationReference.Detach(); return B_OK; } } // We can't deal with negative element offsets at this point. It doesn't // make a lot of sense anyway, if the array location consists of multiple // pieces or lives in a register. if (elementOffset < 0) { WARNING("Negative element offset unsupported for multiple location " "pieces or register pieces.\n"); return B_UNSUPPORTED; } if (!location->SetTo(parentLocation, elementOffset, BaseType()->ByteSize() * 8)) { return B_NO_MEMORY; } _location = locationReference.Detach(); return B_OK; }
bool ValueLocation::SetTo(const ValueLocation& other, uint64 bitOffset, uint64 bitSize) { Clear(); fBigEndian = other.fBigEndian; // compute the total bit size int32 count = other.CountPieces(); uint64 totalBitSize = 0; for (int32 i = 0; i < count; i++) { const ValuePieceLocation &piece = other.PieceAt(i); totalBitSize += piece.bitSize; } // adjust requested bit offset/size to something reasonable, if necessary if (bitOffset + bitSize > totalBitSize) { if (bitOffset >= totalBitSize) return true; bitSize = totalBitSize - bitOffset; } 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. // 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++) { const ValuePieceLocation& tempPiece = other.PieceAt(i); if (tempPiece.bitSize > bitsToSkip) { if (!piece.Copy(tempPiece)) return false; break; } bitsToSkip -= tempPiece.bitSize; } // handle partial piece if (bitsToSkip > 0) { piece.bitOffset += bitsToSkip; 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.bitSize = bitSize; piece.Normalize(fBigEndian); bitSize = 0; } else bitSize -= piece.bitSize; if (!AddPiece(piece)) return false; if (++i >= count) break; if (!piece.Copy(other.PieceAt(i))) return false; } } 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++) { const ValuePieceLocation& tempPiece = other.PieceAt(i); if (tempPiece.bitSize > bitsToSkip) { if (!piece.Copy(tempPiece)) return false; 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; if (!piece.Copy(other.PieceAt(i))) return false; } } return true; }