1 //===------ ExecutorAddress.h - Executing process address -------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Represents an address in the executing program. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_EXECUTORADDRESS_H 14 #define LLVM_EXECUTIONENGINE_ORC_SHARED_EXECUTORADDRESS_H 15 16 #include "llvm/ADT/DenseMapInfo.h" 17 #include "llvm/ADT/identity.h" 18 #include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h" 19 #include "llvm/Support/FormatVariadic.h" 20 #include "llvm/Support/raw_ostream.h" 21 22 #include <cassert> 23 #if __has_feature(ptrauth_calls) 24 #include <ptrauth.h> 25 #endif 26 #include <type_traits> 27 28 namespace llvm { 29 namespace orc { 30 31 using ExecutorAddrDiff = uint64_t; 32 33 /// Represents an address in the executor process. 34 class ExecutorAddr { 35 public: 36 /// A wrap/unwrap function that leaves pointers unmodified. 37 template <typename T> using rawPtr = llvm::identity<T *>; 38 39 #if __has_feature(ptrauth_calls) 40 template <typename T> class PtrauthSignDefault { 41 public: 42 constexpr T *operator()(T *P) { 43 if (std::is_function_v<T>) 44 return ptrauth_sign_unauthenticated(P, ptrauth_key_function_pointer, 0); 45 else 46 return P; 47 } 48 }; 49 50 template <typename T> class PtrauthStripDefault { 51 public: 52 constexpr T *operator()(T *P) { 53 return ptrauth_strip(P, ptrauth_key_function_pointer); 54 } 55 }; 56 57 /// Default wrap function to use on this host. 58 template <typename T> using defaultWrap = PtrauthSignDefault<T>; 59 60 /// Default unwrap function to use on this host. 61 template <typename T> using defaultUnwrap = PtrauthStripDefault<T>; 62 63 #else 64 65 /// Default wrap function to use on this host. 66 template <typename T> using defaultWrap = rawPtr<T>; 67 68 /// Default unwrap function to use on this host. 69 template <typename T> using defaultUnwrap = rawPtr<T>; 70 71 #endif 72 73 /// Merges a tag into the raw address value: 74 /// P' = P | (TagValue << TagOffset). 75 class Tag { 76 public: 77 constexpr Tag(uintptr_t TagValue, uintptr_t TagOffset) 78 : TagMask(TagValue << TagOffset) {} 79 80 template <typename T> constexpr T *operator()(T *P) { 81 return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(P) | TagMask); 82 } 83 84 private: 85 uintptr_t TagMask; 86 }; 87 88 /// Strips a tag of the given length from the given offset within the pointer: 89 /// P' = P & ~(((1 << TagLen) -1) << TagOffset) 90 class Untag { 91 public: 92 constexpr Untag(uintptr_t TagLen, uintptr_t TagOffset) 93 : UntagMask(~(((uintptr_t(1) << TagLen) - 1) << TagOffset)) {} 94 95 template <typename T> constexpr T *operator()(T *P) { 96 return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(P) & UntagMask); 97 } 98 99 private: 100 uintptr_t UntagMask; 101 }; 102 103 ExecutorAddr() = default; 104 105 /// Create an ExecutorAddr from the given value. 106 explicit constexpr ExecutorAddr(uint64_t Addr) : Addr(Addr) {} 107 108 /// Create an ExecutorAddr from the given pointer. 109 /// Warning: This should only be used when JITing in-process. 110 template <typename T, typename UnwrapFn = defaultUnwrap<T>> 111 static ExecutorAddr fromPtr(T *Ptr, UnwrapFn &&Unwrap = UnwrapFn()) { 112 return ExecutorAddr( 113 static_cast<uint64_t>(reinterpret_cast<uintptr_t>(Unwrap(Ptr)))); 114 } 115 116 /// Cast this ExecutorAddr to a pointer of the given type. 117 /// Warning: This should only be used when JITing in-process. 118 template <typename T, typename WrapFn = defaultWrap<std::remove_pointer_t<T>>> 119 std::enable_if_t<std::is_pointer<T>::value, T> 120 toPtr(WrapFn &&Wrap = WrapFn()) const { 121 uintptr_t IntPtr = static_cast<uintptr_t>(Addr); 122 assert(IntPtr == Addr && "ExecutorAddr value out of range for uintptr_t"); 123 return Wrap(reinterpret_cast<T>(IntPtr)); 124 } 125 126 /// Cast this ExecutorAddr to a pointer of the given function type. 127 /// Warning: This should only be used when JITing in-process. 128 template <typename T, typename WrapFn = defaultWrap<T>> 129 std::enable_if_t<std::is_function<T>::value, T *> 130 toPtr(WrapFn &&Wrap = WrapFn()) const { 131 uintptr_t IntPtr = static_cast<uintptr_t>(Addr); 132 assert(IntPtr == Addr && "ExecutorAddr value out of range for uintptr_t"); 133 return Wrap(reinterpret_cast<T *>(IntPtr)); 134 } 135 136 uint64_t getValue() const { return Addr; } 137 void setValue(uint64_t Addr) { this->Addr = Addr; } 138 bool isNull() const { return Addr == 0; } 139 140 explicit operator bool() const { return Addr != 0; } 141 142 friend bool operator==(const ExecutorAddr &LHS, const ExecutorAddr &RHS) { 143 return LHS.Addr == RHS.Addr; 144 } 145 146 friend bool operator!=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) { 147 return LHS.Addr != RHS.Addr; 148 } 149 150 friend bool operator<(const ExecutorAddr &LHS, const ExecutorAddr &RHS) { 151 return LHS.Addr < RHS.Addr; 152 } 153 154 friend bool operator<=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) { 155 return LHS.Addr <= RHS.Addr; 156 } 157 158 friend bool operator>(const ExecutorAddr &LHS, const ExecutorAddr &RHS) { 159 return LHS.Addr > RHS.Addr; 160 } 161 162 friend bool operator>=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) { 163 return LHS.Addr >= RHS.Addr; 164 } 165 166 ExecutorAddr &operator++() { 167 ++Addr; 168 return *this; 169 } 170 ExecutorAddr &operator--() { 171 --Addr; 172 return *this; 173 } 174 ExecutorAddr operator++(int) { return ExecutorAddr(Addr++); } 175 ExecutorAddr operator--(int) { return ExecutorAddr(Addr--); } 176 177 ExecutorAddr &operator+=(const ExecutorAddrDiff &Delta) { 178 Addr += Delta; 179 return *this; 180 } 181 182 ExecutorAddr &operator-=(const ExecutorAddrDiff &Delta) { 183 Addr -= Delta; 184 return *this; 185 } 186 187 private: 188 uint64_t Addr = 0; 189 }; 190 191 /// Subtracting two addresses yields an offset. 192 inline ExecutorAddrDiff operator-(const ExecutorAddr &LHS, 193 const ExecutorAddr &RHS) { 194 return ExecutorAddrDiff(LHS.getValue() - RHS.getValue()); 195 } 196 197 /// Adding an offset and an address yields an address. 198 inline ExecutorAddr operator+(const ExecutorAddr &LHS, 199 const ExecutorAddrDiff &RHS) { 200 return ExecutorAddr(LHS.getValue() + RHS); 201 } 202 203 /// Adding an address and an offset yields an address. 204 inline ExecutorAddr operator+(const ExecutorAddrDiff &LHS, 205 const ExecutorAddr &RHS) { 206 return ExecutorAddr(LHS + RHS.getValue()); 207 } 208 209 /// Subtracting an offset from an address yields an address. 210 inline ExecutorAddr operator-(const ExecutorAddr &LHS, 211 const ExecutorAddrDiff &RHS) { 212 return ExecutorAddr(LHS.getValue() - RHS); 213 } 214 215 /// Taking the modulus of an address and a diff yields a diff. 216 inline ExecutorAddrDiff operator%(const ExecutorAddr &LHS, 217 const ExecutorAddrDiff &RHS) { 218 return ExecutorAddrDiff(LHS.getValue() % RHS); 219 } 220 221 /// Represents an address range in the exceutor process. 222 struct ExecutorAddrRange { 223 ExecutorAddrRange() = default; 224 ExecutorAddrRange(ExecutorAddr Start, ExecutorAddr End) 225 : Start(Start), End(End) {} 226 ExecutorAddrRange(ExecutorAddr Start, ExecutorAddrDiff Size) 227 : Start(Start), End(Start + Size) {} 228 229 bool empty() const { return Start == End; } 230 ExecutorAddrDiff size() const { return End - Start; } 231 232 friend bool operator==(const ExecutorAddrRange &LHS, 233 const ExecutorAddrRange &RHS) { 234 return LHS.Start == RHS.Start && LHS.End == RHS.End; 235 } 236 friend bool operator!=(const ExecutorAddrRange &LHS, 237 const ExecutorAddrRange &RHS) { 238 return !(LHS == RHS); 239 } 240 friend bool operator<(const ExecutorAddrRange &LHS, 241 const ExecutorAddrRange &RHS) { 242 return LHS.Start < RHS.Start || 243 (LHS.Start == RHS.Start && LHS.End < RHS.End); 244 } 245 friend bool operator<=(const ExecutorAddrRange &LHS, 246 const ExecutorAddrRange &RHS) { 247 return LHS.Start < RHS.Start || 248 (LHS.Start == RHS.Start && LHS.End <= RHS.End); 249 } 250 friend bool operator>(const ExecutorAddrRange &LHS, 251 const ExecutorAddrRange &RHS) { 252 return LHS.Start > RHS.Start || 253 (LHS.Start == RHS.Start && LHS.End > RHS.End); 254 } 255 friend bool operator>=(const ExecutorAddrRange &LHS, 256 const ExecutorAddrRange &RHS) { 257 return LHS.Start > RHS.Start || 258 (LHS.Start == RHS.Start && LHS.End >= RHS.End); 259 } 260 261 bool contains(ExecutorAddr Addr) const { return Start <= Addr && Addr < End; } 262 bool overlaps(const ExecutorAddrRange &Other) { 263 return !(Other.End <= Start || End <= Other.Start); 264 } 265 266 ExecutorAddr Start; 267 ExecutorAddr End; 268 }; 269 270 inline raw_ostream &operator<<(raw_ostream &OS, const ExecutorAddr &A) { 271 return OS << formatv("{0:x}", A.getValue()); 272 } 273 274 inline raw_ostream &operator<<(raw_ostream &OS, const ExecutorAddrRange &R) { 275 return OS << formatv("{0:x} -- {1:x}", R.Start.getValue(), R.End.getValue()); 276 } 277 278 namespace shared { 279 280 class SPSExecutorAddr {}; 281 282 /// SPS serializatior for ExecutorAddr. 283 template <> class SPSSerializationTraits<SPSExecutorAddr, ExecutorAddr> { 284 public: 285 static size_t size(const ExecutorAddr &EA) { 286 return SPSArgList<uint64_t>::size(EA.getValue()); 287 } 288 289 static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddr &EA) { 290 return SPSArgList<uint64_t>::serialize(BOB, EA.getValue()); 291 } 292 293 static bool deserialize(SPSInputBuffer &BIB, ExecutorAddr &EA) { 294 uint64_t Tmp; 295 if (!SPSArgList<uint64_t>::deserialize(BIB, Tmp)) 296 return false; 297 EA = ExecutorAddr(Tmp); 298 return true; 299 } 300 }; 301 302 using SPSExecutorAddrRange = SPSTuple<SPSExecutorAddr, SPSExecutorAddr>; 303 304 /// Serialization traits for address ranges. 305 template <> 306 class SPSSerializationTraits<SPSExecutorAddrRange, ExecutorAddrRange> { 307 public: 308 static size_t size(const ExecutorAddrRange &Value) { 309 return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::size(Value.Start, 310 Value.End); 311 } 312 313 static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddrRange &Value) { 314 return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::serialize( 315 BOB, Value.Start, Value.End); 316 } 317 318 static bool deserialize(SPSInputBuffer &BIB, ExecutorAddrRange &Value) { 319 return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::deserialize( 320 BIB, Value.Start, Value.End); 321 } 322 }; 323 324 using SPSExecutorAddrRangeSequence = SPSSequence<SPSExecutorAddrRange>; 325 326 } // End namespace shared. 327 } // End namespace orc. 328 329 // Provide DenseMapInfo for ExecutorAddrs. 330 template <> struct DenseMapInfo<orc::ExecutorAddr> { 331 static inline orc::ExecutorAddr getEmptyKey() { 332 return orc::ExecutorAddr(DenseMapInfo<uint64_t>::getEmptyKey()); 333 } 334 static inline orc::ExecutorAddr getTombstoneKey() { 335 return orc::ExecutorAddr(DenseMapInfo<uint64_t>::getTombstoneKey()); 336 } 337 338 static unsigned getHashValue(const orc::ExecutorAddr &Addr) { 339 return DenseMapInfo<uint64_t>::getHashValue(Addr.getValue()); 340 } 341 342 static bool isEqual(const orc::ExecutorAddr &LHS, 343 const orc::ExecutorAddr &RHS) { 344 return DenseMapInfo<uint64_t>::isEqual(LHS.getValue(), RHS.getValue()); 345 } 346 }; 347 348 } // End namespace llvm. 349 350 #endif // LLVM_EXECUTIONENGINE_ORC_SHARED_EXECUTORADDRESS_H 351