bool ValueLocation::SetToByteOffset(const ValueLocation& other, uint64 byteOffset, uint64 byteSize) { Clear(); fBigEndian = other.fBigEndian; ValuePieceLocation piece = other.PieceAt(0); piece.SetToMemory(piece.address + byteOffset); piece.SetSize(byteSize); return AddPiece(piece); }
status_t BListValueNode::BListItemCountNodeChild::ResolveLocation( ValueLoader* valueLoader, ValueLocation*& _location) { ValueLocation* location = new(std::nothrow) ValueLocation(); if (location == NULL) return B_NO_MEMORY; ValuePieceLocation piece; piece.SetToMemory(fLocation.ToUInt64()); piece.SetSize(sizeof(int32)); location->AddPiece(piece); _location = location; return B_OK; }
status_t DwarfType::ResolveObjectDataLocation(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(fTypeContext->GetArchitecture()->IsBigEndian()); if (!location.AddPiece(piece)) return B_NO_MEMORY; return ResolveObjectDataLocation(location, _location); }
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 BListValueNode::BListElementNodeChild::ResolveLocation( ValueLoader* valueLoader, ValueLocation*& _location) { uint8 addressSize = valueLoader->GetArchitecture()->AddressSize(); ValueLocation* location = new(std::nothrow) ValueLocation(); if (location == NULL) return B_NO_MEMORY; uint64 listAddress = fParent->fDataLocation.ToUInt64(); listAddress += fElementIndex * addressSize; ValuePieceLocation piece; piece.SetToMemory(listAddress); piece.SetSize(addressSize); location->AddPiece(piece); _location = location; return B_OK; }
status_t ArchitectureX8664::GetReturnAddressLocation(StackFrame* frame, target_size_t valueSize, ValueLocation*& _location) { // for the calling conventions currently in use on Haiku, // the x86-64 rules for how values are returned are as follows: // // - 64 bit or smaller values are returned in RAX. // - > 64 bit values are returned on the stack. ValueLocation* location = new(std::nothrow) ValueLocation( IsBigEndian()); if (location == NULL) return B_NO_MEMORY; BReference<ValueLocation> locationReference(location, true); if (valueSize <= 8) { ValuePieceLocation piece; piece.SetSize(valueSize); piece.SetToRegister(X86_64_REGISTER_RAX); if (!location->AddPiece(piece)) return B_NO_MEMORY; } else { ValuePieceLocation piece; CpuStateX8664* state = dynamic_cast<CpuStateX8664*>(frame->GetCpuState()); piece.SetToMemory(state->IntRegisterValue(X86_64_REGISTER_RAX)); piece.SetSize(valueSize); if (!location->AddPiece(piece)) return B_NO_MEMORY; } _location = locationReference.Detach(); return B_OK; }
status_t DwarfExpressionEvaluator::EvaluateLocation(const void* expression, size_t size, ValueLocation& _location) { _location.Clear(); // the empty expression is a valid one if (size == 0) { ValuePieceLocation piece; piece.SetToUnknown(); piece.SetSize(0); return _location.AddPiece(piece) ? B_OK : B_NO_MEMORY; } fDataReader.SetTo(expression, size, fContext->AddressSize()); // parse the first (and maybe only) expression try { // push the object address, if any target_addr_t objectAddress; if (fContext->GetObjectAddress(objectAddress)) _Push(objectAddress); ValuePieceLocation piece; status_t error = _Evaluate(&piece); if (error != B_OK) return error; // if that's all, it's only a simple expression without composition if (fDataReader.BytesRemaining() == 0) { if (!piece.IsValid()) piece.SetToMemory(_Pop()); piece.SetSize(0); return _location.AddPiece(piece) ? B_OK : B_NO_MEMORY; } // there's more, so it must be a composition operator uint8 opcode = fDataReader.Read<uint8>(0); if (opcode == DW_OP_piece) { piece.SetSize(fDataReader.ReadUnsignedLEB128(0)); } else if (opcode == DW_OP_bit_piece) { uint64 bitSize = fDataReader.ReadUnsignedLEB128(0); piece.SetSize(bitSize, fDataReader.ReadUnsignedLEB128(0)); } else return B_BAD_DATA; // If there's a composition operator, there must be at least two // simple expressions, so this must not be the end. if (fDataReader.BytesRemaining() == 0) return B_BAD_DATA; } catch (const EvaluationException& exception) { WARNING("DwarfExpressionEvaluator::EvaluateLocation(): %s\n", exception.message); return B_BAD_VALUE; } catch (const std::bad_alloc& exception) { return B_NO_MEMORY; } // parse subsequent expressions (at least one) while (fDataReader.BytesRemaining() > 0) { // Restrict the data reader to the remaining bytes to prevent jumping // back. fDataReader.SetTo(fDataReader.Data(), fDataReader.BytesRemaining(), fDataReader.AddressSize()); try { // push the object address, if any target_addr_t objectAddress; if (fContext->GetObjectAddress(objectAddress)) _Push(objectAddress); ValuePieceLocation piece; status_t error = _Evaluate(&piece); if (error != B_OK) return error; if (!piece.IsValid()) piece.SetToMemory(_Pop()); // each expression must be followed by a composition operator if (fDataReader.BytesRemaining() == 0) return B_BAD_DATA; uint8 opcode = fDataReader.Read<uint8>(0); if (opcode == DW_OP_piece) { piece.SetSize(fDataReader.ReadUnsignedLEB128(0)); } else if (opcode == DW_OP_bit_piece) { uint64 bitSize = fDataReader.ReadUnsignedLEB128(0); piece.SetSize(bitSize, fDataReader.ReadUnsignedLEB128(0)); } else return B_BAD_DATA; } catch (const EvaluationException& exception) { WARNING("DwarfExpressionEvaluator::EvaluateLocation(): %s\n", exception.message); return B_BAD_VALUE; } catch (const std::bad_alloc& exception) { return B_NO_MEMORY; } } 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; }