xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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:
operator()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:
operator()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:
Tag(uintptr_t TagValue,uintptr_t TagOffset)77     constexpr Tag(uintptr_t TagValue, uintptr_t TagOffset)
78         : TagMask(TagValue << TagOffset) {}
79 
operator()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:
Untag(uintptr_t TagLen,uintptr_t TagOffset)92     constexpr Untag(uintptr_t TagLen, uintptr_t TagOffset)
93         : UntagMask(~(((uintptr_t(1) << TagLen) - 1) << TagOffset)) {}
94 
operator()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.
ExecutorAddr(uint64_t Addr)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 
getValue()136   uint64_t getValue() const { return Addr; }
setValue(uint64_t Addr)137   void setValue(uint64_t Addr) { this->Addr = Addr; }
isNull()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;
ExecutorAddrRangeExecutorAddrRange224   ExecutorAddrRange(ExecutorAddr Start, ExecutorAddr End)
225       : Start(Start), End(End) {}
ExecutorAddrRangeExecutorAddrRange226   ExecutorAddrRange(ExecutorAddr Start, ExecutorAddrDiff Size)
227       : Start(Start), End(Start + Size) {}
228 
229   template <typename T, typename UnwrapFn = ExecutorAddr::defaultUnwrap<T>>
230   static ExecutorAddrRange fromPtrRange(T *Start, T *End,
231                                         UnwrapFn &&Unwrap = UnwrapFn()) {
232     return {ExecutorAddr::fromPtr(Start, Unwrap),
233             ExecutorAddr::fromPtr(End, Unwrap)};
234   }
235 
236   template <typename T, typename UnwrapFn = ExecutorAddr::defaultUnwrap<T>>
237   static ExecutorAddrRange fromPtrRange(T *Ptr, ExecutorAddrDiff Size,
238                                         UnwrapFn &&Unwrap = UnwrapFn()) {
239     return {ExecutorAddr::fromPtr(Ptr, std::forward<UnwrapFn>(Unwrap)), Size};
240   }
241 
emptyExecutorAddrRange242   bool empty() const { return Start == End; }
sizeExecutorAddrRange243   ExecutorAddrDiff size() const { return End - Start; }
244 
245   friend bool operator==(const ExecutorAddrRange &LHS,
246                          const ExecutorAddrRange &RHS) {
247     return LHS.Start == RHS.Start && LHS.End == RHS.End;
248   }
249   friend bool operator!=(const ExecutorAddrRange &LHS,
250                          const ExecutorAddrRange &RHS) {
251     return !(LHS == RHS);
252   }
253   friend bool operator<(const ExecutorAddrRange &LHS,
254                         const ExecutorAddrRange &RHS) {
255     return LHS.Start < RHS.Start ||
256            (LHS.Start == RHS.Start && LHS.End < RHS.End);
257   }
258   friend bool operator<=(const ExecutorAddrRange &LHS,
259                          const ExecutorAddrRange &RHS) {
260     return LHS.Start < RHS.Start ||
261            (LHS.Start == RHS.Start && LHS.End <= RHS.End);
262   }
263   friend bool operator>(const ExecutorAddrRange &LHS,
264                         const ExecutorAddrRange &RHS) {
265     return LHS.Start > RHS.Start ||
266            (LHS.Start == RHS.Start && LHS.End > RHS.End);
267   }
268   friend bool operator>=(const ExecutorAddrRange &LHS,
269                          const ExecutorAddrRange &RHS) {
270     return LHS.Start > RHS.Start ||
271            (LHS.Start == RHS.Start && LHS.End >= RHS.End);
272   }
273 
containsExecutorAddrRange274   bool contains(ExecutorAddr Addr) const { return Start <= Addr && Addr < End; }
overlapsExecutorAddrRange275   bool overlaps(const ExecutorAddrRange &Other) {
276     return !(Other.End <= Start || End <= Other.Start);
277   }
278 
279   ExecutorAddr Start;
280   ExecutorAddr End;
281 };
282 
283 inline raw_ostream &operator<<(raw_ostream &OS, const ExecutorAddr &A) {
284   return OS << formatv("{0:x}", A.getValue());
285 }
286 
287 inline raw_ostream &operator<<(raw_ostream &OS, const ExecutorAddrRange &R) {
288   return OS << formatv("{0:x} -- {1:x}", R.Start.getValue(), R.End.getValue());
289 }
290 
291 namespace shared {
292 
293 class SPSExecutorAddr {};
294 
295 /// SPS serializatior for ExecutorAddr.
296 template <> class SPSSerializationTraits<SPSExecutorAddr, ExecutorAddr> {
297 public:
size(const ExecutorAddr & EA)298   static size_t size(const ExecutorAddr &EA) {
299     return SPSArgList<uint64_t>::size(EA.getValue());
300   }
301 
serialize(SPSOutputBuffer & BOB,const ExecutorAddr & EA)302   static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddr &EA) {
303     return SPSArgList<uint64_t>::serialize(BOB, EA.getValue());
304   }
305 
deserialize(SPSInputBuffer & BIB,ExecutorAddr & EA)306   static bool deserialize(SPSInputBuffer &BIB, ExecutorAddr &EA) {
307     uint64_t Tmp;
308     if (!SPSArgList<uint64_t>::deserialize(BIB, Tmp))
309       return false;
310     EA = ExecutorAddr(Tmp);
311     return true;
312   }
313 };
314 
315 using SPSExecutorAddrRange = SPSTuple<SPSExecutorAddr, SPSExecutorAddr>;
316 
317 /// Serialization traits for address ranges.
318 template <>
319 class SPSSerializationTraits<SPSExecutorAddrRange, ExecutorAddrRange> {
320 public:
size(const ExecutorAddrRange & Value)321   static size_t size(const ExecutorAddrRange &Value) {
322     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::size(Value.Start,
323                                                               Value.End);
324   }
325 
serialize(SPSOutputBuffer & BOB,const ExecutorAddrRange & Value)326   static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddrRange &Value) {
327     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::serialize(
328         BOB, Value.Start, Value.End);
329   }
330 
deserialize(SPSInputBuffer & BIB,ExecutorAddrRange & Value)331   static bool deserialize(SPSInputBuffer &BIB, ExecutorAddrRange &Value) {
332     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::deserialize(
333         BIB, Value.Start, Value.End);
334   }
335 };
336 
337 using SPSExecutorAddrRangeSequence = SPSSequence<SPSExecutorAddrRange>;
338 
339 } // End namespace shared.
340 } // End namespace orc.
341 
342 // Provide DenseMapInfo for ExecutorAddrs.
343 template <> struct DenseMapInfo<orc::ExecutorAddr> {
344   static inline orc::ExecutorAddr getEmptyKey() {
345     return orc::ExecutorAddr(DenseMapInfo<uint64_t>::getEmptyKey());
346   }
347   static inline orc::ExecutorAddr getTombstoneKey() {
348     return orc::ExecutorAddr(DenseMapInfo<uint64_t>::getTombstoneKey());
349   }
350 
351   static unsigned getHashValue(const orc::ExecutorAddr &Addr) {
352     return DenseMapInfo<uint64_t>::getHashValue(Addr.getValue());
353   }
354 
355   static bool isEqual(const orc::ExecutorAddr &LHS,
356                       const orc::ExecutorAddr &RHS) {
357     return DenseMapInfo<uint64_t>::isEqual(LHS.getValue(), RHS.getValue());
358   }
359 };
360 
361 } // End namespace llvm.
362 
363 #endif // LLVM_EXECUTIONENGINE_ORC_SHARED_EXECUTORADDRESS_H
364