|  | //===-- common.h ------------------------------------------------*- C++ -*-===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #ifndef SCUDO_COMMON_H_ | 
|  | #define SCUDO_COMMON_H_ | 
|  |  | 
|  | #include "internal_defs.h" | 
|  |  | 
|  | #include "fuchsia.h" | 
|  | #include "linux.h" | 
|  | #include "trusty.h" | 
|  |  | 
|  | #include <stddef.h> | 
|  | #include <string.h> | 
|  | #include <unistd.h> | 
|  |  | 
|  | namespace scudo { | 
|  |  | 
|  | template <class Dest, class Source> inline Dest bit_cast(const Source &S) { | 
|  | static_assert(sizeof(Dest) == sizeof(Source), ""); | 
|  | Dest D; | 
|  | memcpy(&D, &S, sizeof(D)); | 
|  | return D; | 
|  | } | 
|  |  | 
|  | inline constexpr bool isPowerOfTwo(uptr X) { | 
|  | if (X == 0) | 
|  | return false; | 
|  | return (X & (X - 1)) == 0; | 
|  | } | 
|  |  | 
|  | inline constexpr uptr roundUp(uptr X, uptr Boundary) { | 
|  | DCHECK(isPowerOfTwo(Boundary)); | 
|  | return (X + Boundary - 1) & ~(Boundary - 1); | 
|  | } | 
|  | inline constexpr uptr roundUpSlow(uptr X, uptr Boundary) { | 
|  | return ((X + Boundary - 1) / Boundary) * Boundary; | 
|  | } | 
|  |  | 
|  | inline constexpr uptr roundDown(uptr X, uptr Boundary) { | 
|  | DCHECK(isPowerOfTwo(Boundary)); | 
|  | return X & ~(Boundary - 1); | 
|  | } | 
|  | inline constexpr uptr roundDownSlow(uptr X, uptr Boundary) { | 
|  | return (X / Boundary) * Boundary; | 
|  | } | 
|  |  | 
|  | inline constexpr bool isAligned(uptr X, uptr Alignment) { | 
|  | DCHECK(isPowerOfTwo(Alignment)); | 
|  | return (X & (Alignment - 1)) == 0; | 
|  | } | 
|  | inline constexpr bool isAlignedSlow(uptr X, uptr Alignment) { | 
|  | return X % Alignment == 0; | 
|  | } | 
|  |  | 
|  | template <class T> constexpr T Min(T A, T B) { return A < B ? A : B; } | 
|  |  | 
|  | template <class T> constexpr T Max(T A, T B) { return A > B ? A : B; } | 
|  |  | 
|  | template <class T> void Swap(T &A, T &B) { | 
|  | T Tmp = A; | 
|  | A = B; | 
|  | B = Tmp; | 
|  | } | 
|  |  | 
|  | inline uptr getMostSignificantSetBitIndex(uptr X) { | 
|  | DCHECK_NE(X, 0U); | 
|  | return SCUDO_WORDSIZE - 1U - static_cast<uptr>(__builtin_clzl(X)); | 
|  | } | 
|  |  | 
|  | inline uptr roundUpPowerOfTwo(uptr Size) { | 
|  | DCHECK(Size); | 
|  | if (isPowerOfTwo(Size)) | 
|  | return Size; | 
|  | const uptr Up = getMostSignificantSetBitIndex(Size); | 
|  | DCHECK_LT(Size, (1UL << (Up + 1))); | 
|  | DCHECK_GT(Size, (1UL << Up)); | 
|  | return 1UL << (Up + 1); | 
|  | } | 
|  |  | 
|  | inline uptr getLeastSignificantSetBitIndex(uptr X) { | 
|  | DCHECK_NE(X, 0U); | 
|  | return static_cast<uptr>(__builtin_ctzl(X)); | 
|  | } | 
|  |  | 
|  | inline uptr getLog2(uptr X) { | 
|  | DCHECK(isPowerOfTwo(X)); | 
|  | return getLeastSignificantSetBitIndex(X); | 
|  | } | 
|  |  | 
|  | inline u32 getRandomU32(u32 *State) { | 
|  | // ANSI C linear congruential PRNG (16-bit output). | 
|  | // return (*State = *State * 1103515245 + 12345) >> 16; | 
|  | // XorShift (32-bit output). | 
|  | *State ^= *State << 13; | 
|  | *State ^= *State >> 17; | 
|  | *State ^= *State << 5; | 
|  | return *State; | 
|  | } | 
|  |  | 
|  | inline u32 getRandomModN(u32 *State, u32 N) { | 
|  | return getRandomU32(State) % N; // [0, N) | 
|  | } | 
|  |  | 
|  | template <typename T> inline void shuffle(T *A, u32 N, u32 *RandState) { | 
|  | if (N <= 1) | 
|  | return; | 
|  | u32 State = *RandState; | 
|  | for (u32 I = N - 1; I > 0; I--) | 
|  | Swap(A[I], A[getRandomModN(&State, I + 1)]); | 
|  | *RandState = State; | 
|  | } | 
|  |  | 
|  | inline void computePercentage(uptr Numerator, uptr Denominator, uptr *Integral, | 
|  | uptr *Fractional) { | 
|  | constexpr uptr Digits = 100; | 
|  | if (Denominator == 0) { | 
|  | *Integral = 100; | 
|  | *Fractional = 0; | 
|  | return; | 
|  | } | 
|  |  | 
|  | *Integral = Numerator * Digits / Denominator; | 
|  | *Fractional = | 
|  | (((Numerator * Digits) % Denominator) * Digits + Denominator / 2) / | 
|  | Denominator; | 
|  | } | 
|  |  | 
|  | // Platform specific functions. | 
|  |  | 
|  | #if defined(SCUDO_PAGE_SIZE) | 
|  |  | 
|  | inline constexpr uptr getPageSizeCached() { return SCUDO_PAGE_SIZE; } | 
|  |  | 
|  | inline constexpr uptr getPageSizeSlow() { return getPageSizeCached(); } | 
|  |  | 
|  | inline constexpr uptr getPageSizeLogCached() { | 
|  | return static_cast<uptr>(__builtin_ctzl(SCUDO_PAGE_SIZE)); | 
|  | } | 
|  |  | 
|  | #else | 
|  |  | 
|  | extern uptr PageSizeCached; | 
|  | extern uptr PageSizeLogCached; | 
|  |  | 
|  | uptr getPageSizeSlow(); | 
|  |  | 
|  | inline uptr getPageSizeCached() { | 
|  | if (LIKELY(PageSizeCached)) | 
|  | return PageSizeCached; | 
|  | return getPageSizeSlow(); | 
|  | } | 
|  |  | 
|  | inline uptr getPageSizeLogCached() { | 
|  | if (LIKELY(PageSizeLogCached)) | 
|  | return PageSizeLogCached; | 
|  | // PageSizeLogCached and PageSizeCached are both set in getPageSizeSlow() | 
|  | getPageSizeSlow(); | 
|  | DCHECK_NE(PageSizeLogCached, 0); | 
|  | return PageSizeLogCached; | 
|  | } | 
|  |  | 
|  | #endif | 
|  |  | 
|  | // Returns 0 if the number of CPUs could not be determined. | 
|  | u32 getNumberOfCPUs(); | 
|  |  | 
|  | const char *getEnv(const char *Name); | 
|  |  | 
|  | u64 getMonotonicTime(); | 
|  | // Gets the time faster but with less accuracy. Can call getMonotonicTime | 
|  | // if no fast version is available. | 
|  | u64 getMonotonicTimeFast(); | 
|  |  | 
|  | u32 getThreadID(); | 
|  |  | 
|  | // Our randomness gathering function is limited to 256 bytes to ensure we get | 
|  | // as many bytes as requested, and avoid interruptions (on Linux). | 
|  | constexpr uptr MaxRandomLength = 256U; | 
|  | bool getRandom(void *Buffer, uptr Length, bool Blocking = false); | 
|  |  | 
|  | // Platform memory mapping functions. | 
|  |  | 
|  | #define MAP_ALLOWNOMEM (1U << 0) | 
|  | #define MAP_NOACCESS (1U << 1) | 
|  | #define MAP_RESIZABLE (1U << 2) | 
|  | #define MAP_MEMTAG (1U << 3) | 
|  | #define MAP_PRECOMMIT (1U << 4) | 
|  |  | 
|  | // Our platform memory mapping use is restricted to 3 scenarios: | 
|  | // - reserve memory at a random address (MAP_NOACCESS); | 
|  | // - commit memory in a previously reserved space; | 
|  | // - commit memory at a random address. | 
|  | // As such, only a subset of parameters combinations is valid, which is checked | 
|  | // by the function implementation. The Data parameter allows to pass opaque | 
|  | // platform specific data to the function. | 
|  | // Returns nullptr on error or dies if MAP_ALLOWNOMEM is not specified. | 
|  | void *map(void *Addr, uptr Size, const char *Name, uptr Flags = 0, | 
|  | MapPlatformData *Data = nullptr); | 
|  |  | 
|  | // Indicates that we are getting rid of the whole mapping, which might have | 
|  | // further consequences on Data, depending on the platform. | 
|  | #define UNMAP_ALL (1U << 0) | 
|  |  | 
|  | void unmap(void *Addr, uptr Size, uptr Flags = 0, | 
|  | MapPlatformData *Data = nullptr); | 
|  |  | 
|  | void setMemoryPermission(uptr Addr, uptr Size, uptr Flags, | 
|  | MapPlatformData *Data = nullptr); | 
|  |  | 
|  | void releasePagesToOS(uptr BaseAddress, uptr Offset, uptr Size, | 
|  | MapPlatformData *Data = nullptr); | 
|  |  | 
|  | // Logging related functions. | 
|  |  | 
|  | void setAbortMessage(const char *Message); | 
|  |  | 
|  | struct BlockInfo { | 
|  | uptr BlockBegin; | 
|  | uptr BlockSize; | 
|  | uptr RegionBegin; | 
|  | uptr RegionEnd; | 
|  | }; | 
|  |  | 
|  | enum class Option : u8 { | 
|  | ReleaseInterval,      // Release to OS interval in milliseconds. | 
|  | MemtagTuning,         // Whether to tune tagging for UAF or overflow. | 
|  | ThreadDisableMemInit, // Whether to disable automatic heap initialization and, | 
|  | // where possible, memory tagging, on this thread. | 
|  | MaxCacheEntriesCount, // Maximum number of blocks that can be cached. | 
|  | MaxCacheEntrySize,    // Maximum size of a block that can be cached. | 
|  | MaxTSDsCount,         // Number of usable TSDs for the shared registry. | 
|  | }; | 
|  |  | 
|  | enum class ReleaseToOS : u8 { | 
|  | Normal, // Follow the normal rules for releasing pages to the OS | 
|  | Force,  // Force release pages to the OS, but avoid cases that take too long. | 
|  | ForceAll, // Force release every page possible regardless of how long it will | 
|  | // take. | 
|  | }; | 
|  |  | 
|  | constexpr unsigned char PatternFillByte = 0xAB; | 
|  |  | 
|  | enum FillContentsMode { | 
|  | NoFill = 0, | 
|  | ZeroFill = 1, | 
|  | PatternOrZeroFill = 2 // Pattern fill unless the memory is known to be | 
|  | // zero-initialized already. | 
|  | }; | 
|  |  | 
|  | } // namespace scudo | 
|  |  | 
|  | #endif // SCUDO_COMMON_H_ |