status_t DwarfCompoundType::ResolveDataMemberLocation(DataMember* _member, const ValueLocation& parentLocation, ValueLocation*& _location) { DwarfDataMember* member = dynamic_cast<DwarfDataMember*>(_member); if (member == NULL) return B_BAD_VALUE; DwarfTypeContext* typeContext = TypeContext(); bool isBitField = true; DIEMember* memberEntry = member->Entry(); // TODO: handle DW_AT_data_bit_offset if (!memberEntry->ByteSize()->IsValid() && !memberEntry->BitOffset()->IsValid() && !memberEntry->BitSize()->IsValid()) { isBitField = false; } ValueLocation* location; status_t error = _ResolveDataMemberLocation(member->GetDwarfType(), member->Entry()->Location(), parentLocation, isBitField, location); if (error != B_OK) return error; // If the member isn't a bit field, we're done. if (!isBitField) { _location = location; return B_OK; } BReference<ValueLocation> locationReference(location); // get the byte size target_addr_t byteSize; if (memberEntry->ByteSize()->IsValid()) { BVariant value; error = typeContext->File()->EvaluateDynamicValue( typeContext->GetCompilationUnit(), typeContext->AddressSize(), typeContext->SubprogramEntry(), memberEntry->ByteSize(), typeContext->TargetInterface(), typeContext->InstructionPointer(), typeContext->FramePointer(), value); if (error != B_OK) return error; byteSize = value.ToUInt64(); } else byteSize = ByteSize(); // get the bit offset uint64 bitOffset = 0; if (memberEntry->BitOffset()->IsValid()) { BVariant value; error = typeContext->File()->EvaluateDynamicValue( typeContext->GetCompilationUnit(), typeContext->AddressSize(), typeContext->SubprogramEntry(), memberEntry->BitOffset(), typeContext->TargetInterface(), typeContext->InstructionPointer(), typeContext->FramePointer(), value); if (error != B_OK) return error; bitOffset = value.ToUInt64(); } // get the bit size uint64 bitSize = byteSize * 8; if (memberEntry->BitSize()->IsValid()) { BVariant value; error = typeContext->File()->EvaluateDynamicValue( typeContext->GetCompilationUnit(), typeContext->AddressSize(), typeContext->SubprogramEntry(), memberEntry->BitSize(), typeContext->TargetInterface(), typeContext->InstructionPointer(), typeContext->FramePointer(), value); if (error != B_OK) return error; bitSize = value.ToUInt64(); } TRACE_LOCALS("bit field: byte size: %" B_PRIu64 ", bit offset/size: %" B_PRIu64 "/%" B_PRIu64 "\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) return B_NO_MEMORY; BReference<ValueLocation> bitFieldLocationReference(bitFieldLocation, true); if (!bitFieldLocation->SetTo(*location, bitOffset, bitSize)) return B_NO_MEMORY; _location = bitFieldLocationReference.Detach(); 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; }