//===--- RemoteAddress.h - Address of remote memory -------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file defines the RemoteAddress type, which abstracts over an // address in a remote process. // //===----------------------------------------------------------------------===// #ifndef SWIFT_REMOTE_REMOTEADDRESS_H #define SWIFT_REMOTE_REMOTEADDRESS_H #include "swift/ABI/MetadataRef.h" #include "swift/Basic/RelativePointer.h" #include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/Hashing.h" #include #include #include #include #include #include #include #include namespace swift { namespace remote { /// An abstract address in the remote process's address space. class RemoteAddress { public: // The default address space, meaning the remote process address space. static constexpr uint8_t DefaultAddressSpace = 0; explicit RemoteAddress(uint64_t addressData, uint8_t addressSpace) : Data(addressData), AddressSpace(addressSpace) {} explicit RemoteAddress() {} explicit operator bool() const { return Data != 0; } bool operator==(const RemoteAddress rhs) const { return Data == rhs.Data && AddressSpace == rhs.AddressSpace; } bool operator!=(const RemoteAddress other) const { return !operator==(other); } bool inRange(const RemoteAddress &begin, const RemoteAddress &end) const { assert(begin.AddressSpace == end.AddressSpace && "Unexpected address spaces"); if (AddressSpace != begin.AddressSpace) return false; return begin <= *this && *this < end; } bool operator<(const RemoteAddress rhs) const { assert(AddressSpace == rhs.AddressSpace && "Comparing remote addresses of different address spaces"); return Data < rhs.Data; } /// Less than operator to be used for ordering purposes. The default less than /// operator asserts if the address spaces are different, this one takes it /// into account to determine the order of the addresses. bool orderedLessThan(const RemoteAddress rhs) const { if (AddressSpace == rhs.AddressSpace) return Data < rhs.Data; return AddressSpace < rhs.AddressSpace; } bool operator<=(const RemoteAddress rhs) const { assert(AddressSpace == rhs.AddressSpace && "Comparing remote addresses of different address spaces"); return Data <= rhs.Data; } /// Less than or equal operator to be used for ordering purposes. The default /// less than or equal operator asserts if the address spaces are different, /// this one takes it into account to determine the order of the addresses. bool orderedLessThanOrEqual(const RemoteAddress rhs) const { if (AddressSpace == rhs.AddressSpace) return Data <= rhs.Data; return AddressSpace <= rhs.AddressSpace; } bool operator>(const RemoteAddress &rhs) const { assert(AddressSpace == rhs.AddressSpace && "Comparing remote addresses of different address spaces"); return Data > rhs.Data; } bool operator>=(const RemoteAddress &rhs) const { return Data >= rhs.Data; } template RemoteAddress &operator+=(const IntegerType rhs) { Data += rhs; return *this; } template RemoteAddress operator+(const IntegerType &rhs) const { return RemoteAddress(Data + rhs, getAddressSpace()); } template RemoteAddress operator-(const IntegerType &rhs) const { return RemoteAddress(Data - rhs, getAddressSpace()); } uint64_t operator-(const RemoteAddress &rhs) const { assert(AddressSpace == rhs.AddressSpace && "Comparing remote addresses of different address spaces"); return Data - rhs.Data; } template RemoteAddress operator^(const IntegerType &rhs) const { return RemoteAddress(Data ^ rhs, getAddressSpace()); } template RemoteAddress operator&(IntegerType other) const { return RemoteAddress(Data & other, getAddressSpace()); } template RemoteAddress &operator&=(const IntegerType rhs) { Data &= rhs; return *this; } template RemoteAddress &operator|=(const IntegerType rhs) { Data |= rhs; return *this; } template IntegerType operator>>(const IntegerType rhs) const { return (IntegerType)Data >> rhs; } uint64_t getRawAddress() const { return Data; } uint8_t getAddressSpace() const { return AddressSpace; } template RemoteAddress applyRelativeOffset(IntegerType offset) const { auto atOffset = detail::applyRelativeOffset((const char *)Data, offset); return RemoteAddress(atOffset, getAddressSpace()); } template RemoteAddress getRelative( const RelativeDirectPointer *relative) const { auto ptr = relative->getRelative((void *)Data); return RemoteAddress((uint64_t)ptr, getAddressSpace()); } template const T *getLocalPointer() const { return reinterpret_cast(static_cast(Data)); } std::string getDescription() const { std::stringstream sstream; // FIXME: this should print the address space too, but because Node can't // carry the address space yet, comparing the strings produced by this type // and a Node that carries an address would produce incorrect results. // Revisit this once Node carries the address space. sstream << std::hex << Data; return sstream.str(); } friend llvm::hash_code hash_value(const RemoteAddress &address) { using llvm::hash_value; return hash_value(address.Data); } friend struct std::hash; private: uint64_t Data = 0; uint8_t AddressSpace = 0; }; /// A symbolic relocated absolute pointer value. class RemoteAbsolutePointer { /// The symbol name that the pointer refers to. Empty if only an absolute /// address is available. std::string Symbol; /// The offset from the symbol. int64_t Offset = 0; /// The resolved remote address. RemoteAddress Address = RemoteAddress(); public: RemoteAbsolutePointer() = default; RemoteAbsolutePointer(std::nullptr_t) : RemoteAbsolutePointer() {} RemoteAbsolutePointer(llvm::StringRef Symbol, int64_t Offset, RemoteAddress Address) : Symbol(Symbol), Offset(Offset), Address(Address) {} RemoteAbsolutePointer(RemoteAddress Address) : Address(Address) {} llvm::StringRef getSymbol() const { return Symbol; } int64_t getOffset() const { return Offset; } RemoteAddress getResolvedAddress() const { return Address; } explicit operator bool() const { return Address || !Symbol.empty(); } }; template class RemoteTargetProtocolDescriptorRef { TargetProtocolDescriptorRef ProtocolRef; RemoteAddress address; public: RemoteTargetProtocolDescriptorRef(RemoteAddress address) : ProtocolRef(address.getRawAddress()), address(address) {} bool isObjC() const { return ProtocolRef.isObjC(); } RemoteAddress getObjCProtocol() const { auto pointer = ProtocolRef.getObjCProtocol(); return RemoteAddress(pointer, address.getAddressSpace()); } RemoteAddress getSwiftProtocol() const { auto pointer = ProtocolRef.getSwiftProtocol(); return RemoteAddress(pointer, address.getAddressSpace()); } }; } // end namespace remote } // end namespace swift namespace std { template <> struct hash { size_t operator()(const swift::remote::RemoteAddress &address) const { return llvm::hash_combine(address.Data, address.AddressSpace); } }; } // namespace std namespace llvm { template <> struct DenseMapInfo { static swift::remote::RemoteAddress getEmptyKey() { return swift::remote::RemoteAddress(DenseMapInfo::getEmptyKey(), 0); } static swift::remote::RemoteAddress getTombstoneKey() { return swift::remote::RemoteAddress( DenseMapInfo::getTombstoneKey(), 0); } static unsigned getHashValue(swift::remote::RemoteAddress address) { return std::hash()(address); } static bool isEqual(swift::remote::RemoteAddress lhs, swift::remote::RemoteAddress rhs) { return lhs == rhs; } }; } // namespace llvm #endif // SWIFT_REMOTE_REMOTEADDRESS_H