13cab2bb3Spatrick //===-- common.h ------------------------------------------------*- C++ -*-===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick
93cab2bb3Spatrick #ifndef SCUDO_COMMON_H_
103cab2bb3Spatrick #define SCUDO_COMMON_H_
113cab2bb3Spatrick
123cab2bb3Spatrick #include "internal_defs.h"
133cab2bb3Spatrick
143cab2bb3Spatrick #include "fuchsia.h"
153cab2bb3Spatrick #include "linux.h"
16d89ec533Spatrick #include "trusty.h"
173cab2bb3Spatrick
183cab2bb3Spatrick #include <stddef.h>
193cab2bb3Spatrick #include <string.h>
203cab2bb3Spatrick
213cab2bb3Spatrick namespace scudo {
223cab2bb3Spatrick
bit_cast(const Source & S)233cab2bb3Spatrick template <class Dest, class Source> inline Dest bit_cast(const Source &S) {
243cab2bb3Spatrick static_assert(sizeof(Dest) == sizeof(Source), "");
253cab2bb3Spatrick Dest D;
263cab2bb3Spatrick memcpy(&D, &S, sizeof(D));
273cab2bb3Spatrick return D;
283cab2bb3Spatrick }
293cab2bb3Spatrick
roundUpTo(uptr X,uptr Boundary)303cab2bb3Spatrick inline constexpr uptr roundUpTo(uptr X, uptr Boundary) {
313cab2bb3Spatrick return (X + Boundary - 1) & ~(Boundary - 1);
323cab2bb3Spatrick }
333cab2bb3Spatrick
roundDownTo(uptr X,uptr Boundary)343cab2bb3Spatrick inline constexpr uptr roundDownTo(uptr X, uptr Boundary) {
353cab2bb3Spatrick return X & ~(Boundary - 1);
363cab2bb3Spatrick }
373cab2bb3Spatrick
isAligned(uptr X,uptr Alignment)383cab2bb3Spatrick inline constexpr bool isAligned(uptr X, uptr Alignment) {
393cab2bb3Spatrick return (X & (Alignment - 1)) == 0;
403cab2bb3Spatrick }
413cab2bb3Spatrick
Min(T A,T B)423cab2bb3Spatrick template <class T> constexpr T Min(T A, T B) { return A < B ? A : B; }
433cab2bb3Spatrick
Max(T A,T B)443cab2bb3Spatrick template <class T> constexpr T Max(T A, T B) { return A > B ? A : B; }
453cab2bb3Spatrick
Swap(T & A,T & B)463cab2bb3Spatrick template <class T> void Swap(T &A, T &B) {
473cab2bb3Spatrick T Tmp = A;
483cab2bb3Spatrick A = B;
493cab2bb3Spatrick B = Tmp;
503cab2bb3Spatrick }
513cab2bb3Spatrick
isPowerOfTwo(uptr X)523cab2bb3Spatrick inline bool isPowerOfTwo(uptr X) { return (X & (X - 1)) == 0; }
533cab2bb3Spatrick
getMostSignificantSetBitIndex(uptr X)543cab2bb3Spatrick inline uptr getMostSignificantSetBitIndex(uptr X) {
553cab2bb3Spatrick DCHECK_NE(X, 0U);
563cab2bb3Spatrick return SCUDO_WORDSIZE - 1U - static_cast<uptr>(__builtin_clzl(X));
573cab2bb3Spatrick }
583cab2bb3Spatrick
roundUpToPowerOfTwo(uptr Size)593cab2bb3Spatrick inline uptr roundUpToPowerOfTwo(uptr Size) {
603cab2bb3Spatrick DCHECK(Size);
613cab2bb3Spatrick if (isPowerOfTwo(Size))
623cab2bb3Spatrick return Size;
633cab2bb3Spatrick const uptr Up = getMostSignificantSetBitIndex(Size);
643cab2bb3Spatrick DCHECK_LT(Size, (1UL << (Up + 1)));
653cab2bb3Spatrick DCHECK_GT(Size, (1UL << Up));
663cab2bb3Spatrick return 1UL << (Up + 1);
673cab2bb3Spatrick }
683cab2bb3Spatrick
getLeastSignificantSetBitIndex(uptr X)693cab2bb3Spatrick inline uptr getLeastSignificantSetBitIndex(uptr X) {
703cab2bb3Spatrick DCHECK_NE(X, 0U);
713cab2bb3Spatrick return static_cast<uptr>(__builtin_ctzl(X));
723cab2bb3Spatrick }
733cab2bb3Spatrick
getLog2(uptr X)743cab2bb3Spatrick inline uptr getLog2(uptr X) {
753cab2bb3Spatrick DCHECK(isPowerOfTwo(X));
763cab2bb3Spatrick return getLeastSignificantSetBitIndex(X);
773cab2bb3Spatrick }
783cab2bb3Spatrick
getRandomU32(u32 * State)793cab2bb3Spatrick inline u32 getRandomU32(u32 *State) {
803cab2bb3Spatrick // ANSI C linear congruential PRNG (16-bit output).
813cab2bb3Spatrick // return (*State = *State * 1103515245 + 12345) >> 16;
823cab2bb3Spatrick // XorShift (32-bit output).
833cab2bb3Spatrick *State ^= *State << 13;
843cab2bb3Spatrick *State ^= *State >> 17;
853cab2bb3Spatrick *State ^= *State << 5;
863cab2bb3Spatrick return *State;
873cab2bb3Spatrick }
883cab2bb3Spatrick
getRandomModN(u32 * State,u32 N)893cab2bb3Spatrick inline u32 getRandomModN(u32 *State, u32 N) {
903cab2bb3Spatrick return getRandomU32(State) % N; // [0, N)
913cab2bb3Spatrick }
923cab2bb3Spatrick
shuffle(T * A,u32 N,u32 * RandState)933cab2bb3Spatrick template <typename T> inline void shuffle(T *A, u32 N, u32 *RandState) {
943cab2bb3Spatrick if (N <= 1)
953cab2bb3Spatrick return;
963cab2bb3Spatrick u32 State = *RandState;
973cab2bb3Spatrick for (u32 I = N - 1; I > 0; I--)
983cab2bb3Spatrick Swap(A[I], A[getRandomModN(&State, I + 1)]);
993cab2bb3Spatrick *RandState = State;
1003cab2bb3Spatrick }
1013cab2bb3Spatrick
1023cab2bb3Spatrick // Hardware specific inlinable functions.
1033cab2bb3Spatrick
yieldProcessor(UNUSED u8 Count)104*810390e3Srobert inline void yieldProcessor(UNUSED u8 Count) {
1053cab2bb3Spatrick #if defined(__i386__) || defined(__x86_64__)
1063cab2bb3Spatrick __asm__ __volatile__("" ::: "memory");
1073cab2bb3Spatrick for (u8 I = 0; I < Count; I++)
1083cab2bb3Spatrick __asm__ __volatile__("pause");
1093cab2bb3Spatrick #elif defined(__aarch64__) || defined(__arm__)
1103cab2bb3Spatrick __asm__ __volatile__("" ::: "memory");
1113cab2bb3Spatrick for (u8 I = 0; I < Count; I++)
1123cab2bb3Spatrick __asm__ __volatile__("yield");
1133cab2bb3Spatrick #endif
1143cab2bb3Spatrick __asm__ __volatile__("" ::: "memory");
1153cab2bb3Spatrick }
1163cab2bb3Spatrick
1173cab2bb3Spatrick // Platform specific functions.
1183cab2bb3Spatrick
1193cab2bb3Spatrick extern uptr PageSizeCached;
1203cab2bb3Spatrick uptr getPageSizeSlow();
getPageSizeCached()1213cab2bb3Spatrick inline uptr getPageSizeCached() {
1223cab2bb3Spatrick // Bionic uses a hardcoded value.
1233cab2bb3Spatrick if (SCUDO_ANDROID)
1243cab2bb3Spatrick return 4096U;
1253cab2bb3Spatrick if (LIKELY(PageSizeCached))
1263cab2bb3Spatrick return PageSizeCached;
1273cab2bb3Spatrick return getPageSizeSlow();
1283cab2bb3Spatrick }
1293cab2bb3Spatrick
1301f9cb04fSpatrick // Returns 0 if the number of CPUs could not be determined.
1313cab2bb3Spatrick u32 getNumberOfCPUs();
1323cab2bb3Spatrick
1333cab2bb3Spatrick const char *getEnv(const char *Name);
1343cab2bb3Spatrick
135*810390e3Srobert uptr GetRSS();
136*810390e3Srobert
1373cab2bb3Spatrick u64 getMonotonicTime();
1383cab2bb3Spatrick
1391f9cb04fSpatrick u32 getThreadID();
1401f9cb04fSpatrick
1413cab2bb3Spatrick // Our randomness gathering function is limited to 256 bytes to ensure we get
1423cab2bb3Spatrick // as many bytes as requested, and avoid interruptions (on Linux).
1433cab2bb3Spatrick constexpr uptr MaxRandomLength = 256U;
1443cab2bb3Spatrick bool getRandom(void *Buffer, uptr Length, bool Blocking = false);
1453cab2bb3Spatrick
1463cab2bb3Spatrick // Platform memory mapping functions.
1473cab2bb3Spatrick
1483cab2bb3Spatrick #define MAP_ALLOWNOMEM (1U << 0)
1493cab2bb3Spatrick #define MAP_NOACCESS (1U << 1)
1503cab2bb3Spatrick #define MAP_RESIZABLE (1U << 2)
1511f9cb04fSpatrick #define MAP_MEMTAG (1U << 3)
152*810390e3Srobert #define MAP_PRECOMMIT (1U << 4)
1533cab2bb3Spatrick
1543cab2bb3Spatrick // Our platform memory mapping use is restricted to 3 scenarios:
1553cab2bb3Spatrick // - reserve memory at a random address (MAP_NOACCESS);
1563cab2bb3Spatrick // - commit memory in a previously reserved space;
1573cab2bb3Spatrick // - commit memory at a random address.
1583cab2bb3Spatrick // As such, only a subset of parameters combinations is valid, which is checked
1593cab2bb3Spatrick // by the function implementation. The Data parameter allows to pass opaque
1603cab2bb3Spatrick // platform specific data to the function.
1613cab2bb3Spatrick // Returns nullptr on error or dies if MAP_ALLOWNOMEM is not specified.
1623cab2bb3Spatrick void *map(void *Addr, uptr Size, const char *Name, uptr Flags = 0,
1633cab2bb3Spatrick MapPlatformData *Data = nullptr);
1643cab2bb3Spatrick
1653cab2bb3Spatrick // Indicates that we are getting rid of the whole mapping, which might have
1663cab2bb3Spatrick // further consequences on Data, depending on the platform.
1673cab2bb3Spatrick #define UNMAP_ALL (1U << 0)
1683cab2bb3Spatrick
1693cab2bb3Spatrick void unmap(void *Addr, uptr Size, uptr Flags = 0,
1703cab2bb3Spatrick MapPlatformData *Data = nullptr);
1713cab2bb3Spatrick
172d89ec533Spatrick void setMemoryPermission(uptr Addr, uptr Size, uptr Flags,
173d89ec533Spatrick MapPlatformData *Data = nullptr);
174d89ec533Spatrick
1753cab2bb3Spatrick void releasePagesToOS(uptr BaseAddress, uptr Offset, uptr Size,
1763cab2bb3Spatrick MapPlatformData *Data = nullptr);
1773cab2bb3Spatrick
178d89ec533Spatrick // Internal map & unmap fatal error. This must not call map(). SizeIfOOM shall
179d89ec533Spatrick // hold the requested size on an out-of-memory error, 0 otherwise.
180d89ec533Spatrick void NORETURN dieOnMapUnmapError(uptr SizeIfOOM = 0);
1813cab2bb3Spatrick
1823cab2bb3Spatrick // Logging related functions.
1833cab2bb3Spatrick
1843cab2bb3Spatrick void setAbortMessage(const char *Message);
1853cab2bb3Spatrick
1861f9cb04fSpatrick struct BlockInfo {
1871f9cb04fSpatrick uptr BlockBegin;
1881f9cb04fSpatrick uptr BlockSize;
1891f9cb04fSpatrick uptr RegionBegin;
1901f9cb04fSpatrick uptr RegionEnd;
1911f9cb04fSpatrick };
1921f9cb04fSpatrick
193d89ec533Spatrick enum class Option : u8 {
194d89ec533Spatrick ReleaseInterval, // Release to OS interval in milliseconds.
195d89ec533Spatrick MemtagTuning, // Whether to tune tagging for UAF or overflow.
196d89ec533Spatrick ThreadDisableMemInit, // Whether to disable automatic heap initialization and,
197d89ec533Spatrick // where possible, memory tagging, on this thread.
198d89ec533Spatrick MaxCacheEntriesCount, // Maximum number of blocks that can be cached.
199d89ec533Spatrick MaxCacheEntrySize, // Maximum size of a block that can be cached.
200d89ec533Spatrick MaxTSDsCount, // Number of usable TSDs for the shared registry.
201d89ec533Spatrick };
202d89ec533Spatrick
2031f9cb04fSpatrick constexpr unsigned char PatternFillByte = 0xAB;
2041f9cb04fSpatrick
2051f9cb04fSpatrick enum FillContentsMode {
2061f9cb04fSpatrick NoFill = 0,
2071f9cb04fSpatrick ZeroFill = 1,
2081f9cb04fSpatrick PatternOrZeroFill = 2 // Pattern fill unless the memory is known to be
2091f9cb04fSpatrick // zero-initialized already.
2101f9cb04fSpatrick };
2111f9cb04fSpatrick
2123cab2bb3Spatrick } // namespace scudo
2133cab2bb3Spatrick
2143cab2bb3Spatrick #endif // SCUDO_COMMON_H_
215