xref: /llvm-project/llvm/include/llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h (revision 258a5d499e87dc85109d97d1708abef61893a5a0)
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