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 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; }