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 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 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 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 } 4106c3fb27SDimitry Andric inline constexpr uptr roundUpSlow(uptr X, uptr Boundary) { 4206c3fb27SDimitry Andric return ((X + Boundary - 1) / Boundary) * Boundary; 4306c3fb27SDimitry Andric } 440b57cec5SDimitry Andric 4506c3fb27SDimitry Andric inline constexpr uptr roundDown(uptr X, uptr Boundary) { 4606c3fb27SDimitry Andric DCHECK(isPowerOfTwo(Boundary)); 470b57cec5SDimitry Andric return X & ~(Boundary - 1); 480b57cec5SDimitry Andric } 4906c3fb27SDimitry Andric inline constexpr uptr roundDownSlow(uptr X, uptr Boundary) { 5006c3fb27SDimitry Andric return (X / Boundary) * Boundary; 5106c3fb27SDimitry Andric } 520b57cec5SDimitry Andric 53480093f4SDimitry Andric inline constexpr bool isAligned(uptr X, uptr Alignment) { 5406c3fb27SDimitry Andric DCHECK(isPowerOfTwo(Alignment)); 550b57cec5SDimitry Andric return (X & (Alignment - 1)) == 0; 560b57cec5SDimitry Andric } 5706c3fb27SDimitry Andric inline constexpr bool isAlignedSlow(uptr X, uptr Alignment) { 5806c3fb27SDimitry Andric return X % Alignment == 0; 5906c3fb27SDimitry Andric } 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric template <class T> constexpr T Min(T A, T B) { return A < B ? A : B; } 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric template <class T> constexpr T Max(T A, T B) { return A > B ? A : B; } 640b57cec5SDimitry Andric 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 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 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 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 91480093f4SDimitry Andric inline uptr getLog2(uptr X) { 920b57cec5SDimitry Andric DCHECK(isPowerOfTwo(X)); 930b57cec5SDimitry Andric return getLeastSignificantSetBitIndex(X); 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 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 106480093f4SDimitry Andric inline u32 getRandomModN(u32 *State, u32 N) { 1070b57cec5SDimitry Andric return getRandomU32(State) % N; // [0, N) 1080b57cec5SDimitry Andric } 1090b57cec5SDimitry Andric 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 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(); 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