xref: /freebsd/contrib/llvm-project/compiler-rt/lib/scudo/standalone/common.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- common.h ------------------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #ifndef SCUDO_COMMON_H_
100b57cec5SDimitry Andric #define SCUDO_COMMON_H_
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include "internal_defs.h"
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "fuchsia.h"
150b57cec5SDimitry Andric #include "linux.h"
16fe6060f1SDimitry Andric #include "trusty.h"
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #include <stddef.h>
190b57cec5SDimitry Andric #include <string.h>
205f757f3fSDimitry Andric #include <unistd.h>
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric namespace scudo {
230b57cec5SDimitry Andric 
bit_cast(const Source & S)24480093f4SDimitry Andric template <class Dest, class Source> inline Dest bit_cast(const Source &S) {
25480093f4SDimitry Andric   static_assert(sizeof(Dest) == sizeof(Source), "");
260b57cec5SDimitry Andric   Dest D;
270b57cec5SDimitry Andric   memcpy(&D, &S, sizeof(D));
280b57cec5SDimitry Andric   return D;
290b57cec5SDimitry Andric }
300b57cec5SDimitry Andric 
isPowerOfTwo(uptr X)31*0fca6ea1SDimitry Andric inline constexpr bool isPowerOfTwo(uptr X) {
32*0fca6ea1SDimitry Andric   if (X == 0)
33*0fca6ea1SDimitry Andric     return false;
34*0fca6ea1SDimitry Andric   return (X & (X - 1)) == 0;
35*0fca6ea1SDimitry Andric }
3606c3fb27SDimitry Andric 
roundUp(uptr X,uptr Boundary)3706c3fb27SDimitry Andric inline constexpr uptr roundUp(uptr X, uptr Boundary) {
3806c3fb27SDimitry Andric   DCHECK(isPowerOfTwo(Boundary));
390b57cec5SDimitry Andric   return (X + Boundary - 1) & ~(Boundary - 1);
400b57cec5SDimitry Andric }
roundUpSlow(uptr X,uptr Boundary)4106c3fb27SDimitry Andric inline constexpr uptr roundUpSlow(uptr X, uptr Boundary) {
4206c3fb27SDimitry Andric   return ((X + Boundary - 1) / Boundary) * Boundary;
4306c3fb27SDimitry Andric }
440b57cec5SDimitry Andric 
roundDown(uptr X,uptr Boundary)4506c3fb27SDimitry Andric inline constexpr uptr roundDown(uptr X, uptr Boundary) {
4606c3fb27SDimitry Andric   DCHECK(isPowerOfTwo(Boundary));
470b57cec5SDimitry Andric   return X & ~(Boundary - 1);
480b57cec5SDimitry Andric }
roundDownSlow(uptr X,uptr Boundary)4906c3fb27SDimitry Andric inline constexpr uptr roundDownSlow(uptr X, uptr Boundary) {
5006c3fb27SDimitry Andric   return (X / Boundary) * Boundary;
5106c3fb27SDimitry Andric }
520b57cec5SDimitry Andric 
isAligned(uptr X,uptr Alignment)53480093f4SDimitry Andric inline constexpr bool isAligned(uptr X, uptr Alignment) {
5406c3fb27SDimitry Andric   DCHECK(isPowerOfTwo(Alignment));
550b57cec5SDimitry Andric   return (X & (Alignment - 1)) == 0;
560b57cec5SDimitry Andric }
isAlignedSlow(uptr X,uptr Alignment)5706c3fb27SDimitry Andric inline constexpr bool isAlignedSlow(uptr X, uptr Alignment) {
5806c3fb27SDimitry Andric   return X % Alignment == 0;
5906c3fb27SDimitry Andric }
600b57cec5SDimitry Andric 
Min(T A,T B)610b57cec5SDimitry Andric template <class T> constexpr T Min(T A, T B) { return A < B ? A : B; }
620b57cec5SDimitry Andric 
Max(T A,T B)630b57cec5SDimitry Andric template <class T> constexpr T Max(T A, T B) { return A > B ? A : B; }
640b57cec5SDimitry Andric 
Swap(T & A,T & B)650b57cec5SDimitry Andric template <class T> void Swap(T &A, T &B) {
660b57cec5SDimitry Andric   T Tmp = A;
670b57cec5SDimitry Andric   A = B;
680b57cec5SDimitry Andric   B = Tmp;
690b57cec5SDimitry Andric }
700b57cec5SDimitry Andric 
getMostSignificantSetBitIndex(uptr X)71480093f4SDimitry Andric inline uptr getMostSignificantSetBitIndex(uptr X) {
720b57cec5SDimitry Andric   DCHECK_NE(X, 0U);
730b57cec5SDimitry Andric   return SCUDO_WORDSIZE - 1U - static_cast<uptr>(__builtin_clzl(X));
740b57cec5SDimitry Andric }
750b57cec5SDimitry Andric 
roundUpPowerOfTwo(uptr Size)7606c3fb27SDimitry Andric inline uptr roundUpPowerOfTwo(uptr Size) {
770b57cec5SDimitry Andric   DCHECK(Size);
780b57cec5SDimitry Andric   if (isPowerOfTwo(Size))
790b57cec5SDimitry Andric     return Size;
800b57cec5SDimitry Andric   const uptr Up = getMostSignificantSetBitIndex(Size);
810b57cec5SDimitry Andric   DCHECK_LT(Size, (1UL << (Up + 1)));
820b57cec5SDimitry Andric   DCHECK_GT(Size, (1UL << Up));
830b57cec5SDimitry Andric   return 1UL << (Up + 1);
840b57cec5SDimitry Andric }
850b57cec5SDimitry Andric 
getLeastSignificantSetBitIndex(uptr X)86480093f4SDimitry Andric inline uptr getLeastSignificantSetBitIndex(uptr X) {
870b57cec5SDimitry Andric   DCHECK_NE(X, 0U);
880b57cec5SDimitry Andric   return static_cast<uptr>(__builtin_ctzl(X));
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric 
getLog2(uptr X)91480093f4SDimitry Andric inline uptr getLog2(uptr X) {
920b57cec5SDimitry Andric   DCHECK(isPowerOfTwo(X));
930b57cec5SDimitry Andric   return getLeastSignificantSetBitIndex(X);
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric 
getRandomU32(u32 * State)96480093f4SDimitry Andric inline u32 getRandomU32(u32 *State) {
970b57cec5SDimitry Andric   // ANSI C linear congruential PRNG (16-bit output).
980b57cec5SDimitry Andric   // return (*State = *State * 1103515245 + 12345) >> 16;
990b57cec5SDimitry Andric   // XorShift (32-bit output).
1000b57cec5SDimitry Andric   *State ^= *State << 13;
1010b57cec5SDimitry Andric   *State ^= *State >> 17;
1020b57cec5SDimitry Andric   *State ^= *State << 5;
1030b57cec5SDimitry Andric   return *State;
1040b57cec5SDimitry Andric }
1050b57cec5SDimitry Andric 
getRandomModN(u32 * State,u32 N)106480093f4SDimitry Andric inline u32 getRandomModN(u32 *State, u32 N) {
1070b57cec5SDimitry Andric   return getRandomU32(State) % N; // [0, N)
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric 
shuffle(T * A,u32 N,u32 * RandState)110480093f4SDimitry Andric template <typename T> inline void shuffle(T *A, u32 N, u32 *RandState) {
1110b57cec5SDimitry Andric   if (N <= 1)
1120b57cec5SDimitry Andric     return;
1130b57cec5SDimitry Andric   u32 State = *RandState;
1140b57cec5SDimitry Andric   for (u32 I = N - 1; I > 0; I--)
1150b57cec5SDimitry Andric     Swap(A[I], A[getRandomModN(&State, I + 1)]);
1160b57cec5SDimitry Andric   *RandState = State;
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric 
computePercentage(uptr Numerator,uptr Denominator,uptr * Integral,uptr * Fractional)1195f757f3fSDimitry Andric inline void computePercentage(uptr Numerator, uptr Denominator, uptr *Integral,
1205f757f3fSDimitry Andric                               uptr *Fractional) {
1215f757f3fSDimitry Andric   constexpr uptr Digits = 100;
1225f757f3fSDimitry Andric   if (Denominator == 0) {
1235f757f3fSDimitry Andric     *Integral = 100;
1245f757f3fSDimitry Andric     *Fractional = 0;
1255f757f3fSDimitry Andric     return;
1265f757f3fSDimitry Andric   }
1270b57cec5SDimitry Andric 
1285f757f3fSDimitry Andric   *Integral = Numerator * Digits / Denominator;
1295f757f3fSDimitry Andric   *Fractional =
1305f757f3fSDimitry Andric       (((Numerator * Digits) % Denominator) * Digits + Denominator / 2) /
1315f757f3fSDimitry Andric       Denominator;
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric // Platform specific functions.
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric extern uptr PageSizeCached;
1370b57cec5SDimitry Andric uptr getPageSizeSlow();
getPageSizeCached()138480093f4SDimitry Andric inline uptr getPageSizeCached() {
1395f757f3fSDimitry Andric #if SCUDO_ANDROID && defined(PAGE_SIZE)
1405f757f3fSDimitry Andric   // Most Android builds have a build-time constant page size.
1415f757f3fSDimitry Andric   return PAGE_SIZE;
1425f757f3fSDimitry Andric #endif
1430b57cec5SDimitry Andric   if (LIKELY(PageSizeCached))
1440b57cec5SDimitry Andric     return PageSizeCached;
1450b57cec5SDimitry Andric   return getPageSizeSlow();
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric 
1485ffd83dbSDimitry Andric // Returns 0 if the number of CPUs could not be determined.
1490b57cec5SDimitry Andric u32 getNumberOfCPUs();
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric const char *getEnv(const char *Name);
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric u64 getMonotonicTime();
15406c3fb27SDimitry Andric // Gets the time faster but with less accuracy. Can call getMonotonicTime
15506c3fb27SDimitry Andric // if no fast version is available.
15606c3fb27SDimitry Andric u64 getMonotonicTimeFast();
1570b57cec5SDimitry Andric 
1585ffd83dbSDimitry Andric u32 getThreadID();
1595ffd83dbSDimitry Andric 
1600b57cec5SDimitry Andric // Our randomness gathering function is limited to 256 bytes to ensure we get
1610b57cec5SDimitry Andric // as many bytes as requested, and avoid interruptions (on Linux).
1620b57cec5SDimitry Andric constexpr uptr MaxRandomLength = 256U;
1630b57cec5SDimitry Andric bool getRandom(void *Buffer, uptr Length, bool Blocking = false);
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric // Platform memory mapping functions.
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric #define MAP_ALLOWNOMEM (1U << 0)
1680b57cec5SDimitry Andric #define MAP_NOACCESS (1U << 1)
1690b57cec5SDimitry Andric #define MAP_RESIZABLE (1U << 2)
1705ffd83dbSDimitry Andric #define MAP_MEMTAG (1U << 3)
171bdd1243dSDimitry Andric #define MAP_PRECOMMIT (1U << 4)
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric // Our platform memory mapping use is restricted to 3 scenarios:
1740b57cec5SDimitry Andric // - reserve memory at a random address (MAP_NOACCESS);
1750b57cec5SDimitry Andric // - commit memory in a previously reserved space;
1760b57cec5SDimitry Andric // - commit memory at a random address.
1770b57cec5SDimitry Andric // As such, only a subset of parameters combinations is valid, which is checked
1780b57cec5SDimitry Andric // by the function implementation. The Data parameter allows to pass opaque
1790b57cec5SDimitry Andric // platform specific data to the function.
1800b57cec5SDimitry Andric // Returns nullptr on error or dies if MAP_ALLOWNOMEM is not specified.
1810b57cec5SDimitry Andric void *map(void *Addr, uptr Size, const char *Name, uptr Flags = 0,
1820b57cec5SDimitry Andric           MapPlatformData *Data = nullptr);
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric // Indicates that we are getting rid of the whole mapping, which might have
1850b57cec5SDimitry Andric // further consequences on Data, depending on the platform.
1860b57cec5SDimitry Andric #define UNMAP_ALL (1U << 0)
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric void unmap(void *Addr, uptr Size, uptr Flags = 0,
1890b57cec5SDimitry Andric            MapPlatformData *Data = nullptr);
1900b57cec5SDimitry Andric 
191fe6060f1SDimitry Andric void setMemoryPermission(uptr Addr, uptr Size, uptr Flags,
192fe6060f1SDimitry Andric                          MapPlatformData *Data = nullptr);
193fe6060f1SDimitry Andric 
1940b57cec5SDimitry Andric void releasePagesToOS(uptr BaseAddress, uptr Offset, uptr Size,
1950b57cec5SDimitry Andric                       MapPlatformData *Data = nullptr);
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric // Logging related functions.
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric void setAbortMessage(const char *Message);
2000b57cec5SDimitry Andric 
2015ffd83dbSDimitry Andric struct BlockInfo {
2025ffd83dbSDimitry Andric   uptr BlockBegin;
2035ffd83dbSDimitry Andric   uptr BlockSize;
2045ffd83dbSDimitry Andric   uptr RegionBegin;
2055ffd83dbSDimitry Andric   uptr RegionEnd;
2065ffd83dbSDimitry Andric };
2075ffd83dbSDimitry Andric 
208e8d8bef9SDimitry Andric enum class Option : u8 {
209e8d8bef9SDimitry Andric   ReleaseInterval,      // Release to OS interval in milliseconds.
210e8d8bef9SDimitry Andric   MemtagTuning,         // Whether to tune tagging for UAF or overflow.
211e8d8bef9SDimitry Andric   ThreadDisableMemInit, // Whether to disable automatic heap initialization and,
212e8d8bef9SDimitry Andric                         // where possible, memory tagging, on this thread.
213e8d8bef9SDimitry Andric   MaxCacheEntriesCount, // Maximum number of blocks that can be cached.
214e8d8bef9SDimitry Andric   MaxCacheEntrySize,    // Maximum size of a block that can be cached.
215e8d8bef9SDimitry Andric   MaxTSDsCount,         // Number of usable TSDs for the shared registry.
216e8d8bef9SDimitry Andric };
217e8d8bef9SDimitry Andric 
21806c3fb27SDimitry Andric enum class ReleaseToOS : u8 {
21906c3fb27SDimitry Andric   Normal, // Follow the normal rules for releasing pages to the OS
22006c3fb27SDimitry Andric   Force,  // Force release pages to the OS, but avoid cases that take too long.
22106c3fb27SDimitry Andric   ForceAll, // Force release every page possible regardless of how long it will
22206c3fb27SDimitry Andric             // take.
22306c3fb27SDimitry Andric };
22406c3fb27SDimitry Andric 
2255ffd83dbSDimitry Andric constexpr unsigned char PatternFillByte = 0xAB;
2265ffd83dbSDimitry Andric 
2275ffd83dbSDimitry Andric enum FillContentsMode {
2285ffd83dbSDimitry Andric   NoFill = 0,
2295ffd83dbSDimitry Andric   ZeroFill = 1,
2305ffd83dbSDimitry Andric   PatternOrZeroFill = 2 // Pattern fill unless the memory is known to be
2315ffd83dbSDimitry Andric                         // zero-initialized already.
2325ffd83dbSDimitry Andric };
2335ffd83dbSDimitry Andric 
2340b57cec5SDimitry Andric } // namespace scudo
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric #endif // SCUDO_COMMON_H_
237