common.h revision 360784
1//===-- common.h ------------------------------------------------*- 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#ifndef SCUDO_COMMON_H_
10#define SCUDO_COMMON_H_
11
12#include "internal_defs.h"
13
14#include "fuchsia.h"
15#include "linux.h"
16
17#include <stddef.h>
18#include <string.h>
19
20namespace scudo {
21
22template <class Dest, class Source> inline Dest bit_cast(const Source &S) {
23  static_assert(sizeof(Dest) == sizeof(Source), "");
24  Dest D;
25  memcpy(&D, &S, sizeof(D));
26  return D;
27}
28
29inline constexpr uptr roundUpTo(uptr X, uptr Boundary) {
30  return (X + Boundary - 1) & ~(Boundary - 1);
31}
32
33inline constexpr uptr roundDownTo(uptr X, uptr Boundary) {
34  return X & ~(Boundary - 1);
35}
36
37inline constexpr bool isAligned(uptr X, uptr Alignment) {
38  return (X & (Alignment - 1)) == 0;
39}
40
41template <class T> constexpr T Min(T A, T B) { return A < B ? A : B; }
42
43template <class T> constexpr T Max(T A, T B) { return A > B ? A : B; }
44
45template <class T> void Swap(T &A, T &B) {
46  T Tmp = A;
47  A = B;
48  B = Tmp;
49}
50
51inline bool isPowerOfTwo(uptr X) { return (X & (X - 1)) == 0; }
52
53inline uptr getMostSignificantSetBitIndex(uptr X) {
54  DCHECK_NE(X, 0U);
55  return SCUDO_WORDSIZE - 1U - static_cast<uptr>(__builtin_clzl(X));
56}
57
58inline uptr roundUpToPowerOfTwo(uptr Size) {
59  DCHECK(Size);
60  if (isPowerOfTwo(Size))
61    return Size;
62  const uptr Up = getMostSignificantSetBitIndex(Size);
63  DCHECK_LT(Size, (1UL << (Up + 1)));
64  DCHECK_GT(Size, (1UL << Up));
65  return 1UL << (Up + 1);
66}
67
68inline uptr getLeastSignificantSetBitIndex(uptr X) {
69  DCHECK_NE(X, 0U);
70  return static_cast<uptr>(__builtin_ctzl(X));
71}
72
73inline uptr getLog2(uptr X) {
74  DCHECK(isPowerOfTwo(X));
75  return getLeastSignificantSetBitIndex(X);
76}
77
78inline u32 getRandomU32(u32 *State) {
79  // ANSI C linear congruential PRNG (16-bit output).
80  // return (*State = *State * 1103515245 + 12345) >> 16;
81  // XorShift (32-bit output).
82  *State ^= *State << 13;
83  *State ^= *State >> 17;
84  *State ^= *State << 5;
85  return *State;
86}
87
88inline u32 getRandomModN(u32 *State, u32 N) {
89  return getRandomU32(State) % N; // [0, N)
90}
91
92template <typename T> inline void shuffle(T *A, u32 N, u32 *RandState) {
93  if (N <= 1)
94    return;
95  u32 State = *RandState;
96  for (u32 I = N - 1; I > 0; I--)
97    Swap(A[I], A[getRandomModN(&State, I + 1)]);
98  *RandState = State;
99}
100
101// Hardware specific inlinable functions.
102
103inline void yieldProcessor(u8 Count) {
104#if defined(__i386__) || defined(__x86_64__)
105  __asm__ __volatile__("" ::: "memory");
106  for (u8 I = 0; I < Count; I++)
107    __asm__ __volatile__("pause");
108#elif defined(__aarch64__) || defined(__arm__)
109  __asm__ __volatile__("" ::: "memory");
110  for (u8 I = 0; I < Count; I++)
111    __asm__ __volatile__("yield");
112#endif
113  __asm__ __volatile__("" ::: "memory");
114}
115
116// Platform specific functions.
117
118extern uptr PageSizeCached;
119uptr getPageSizeSlow();
120inline uptr getPageSizeCached() {
121  // Bionic uses a hardcoded value.
122  if (SCUDO_ANDROID)
123    return 4096U;
124  if (LIKELY(PageSizeCached))
125    return PageSizeCached;
126  return getPageSizeSlow();
127}
128
129u32 getNumberOfCPUs();
130
131const char *getEnv(const char *Name);
132
133u64 getMonotonicTime();
134
135// Our randomness gathering function is limited to 256 bytes to ensure we get
136// as many bytes as requested, and avoid interruptions (on Linux).
137constexpr uptr MaxRandomLength = 256U;
138bool getRandom(void *Buffer, uptr Length, bool Blocking = false);
139
140// Platform memory mapping functions.
141
142#define MAP_ALLOWNOMEM (1U << 0)
143#define MAP_NOACCESS (1U << 1)
144#define MAP_RESIZABLE (1U << 2)
145
146// Our platform memory mapping use is restricted to 3 scenarios:
147// - reserve memory at a random address (MAP_NOACCESS);
148// - commit memory in a previously reserved space;
149// - commit memory at a random address.
150// As such, only a subset of parameters combinations is valid, which is checked
151// by the function implementation. The Data parameter allows to pass opaque
152// platform specific data to the function.
153// Returns nullptr on error or dies if MAP_ALLOWNOMEM is not specified.
154void *map(void *Addr, uptr Size, const char *Name, uptr Flags = 0,
155          MapPlatformData *Data = nullptr);
156
157// Indicates that we are getting rid of the whole mapping, which might have
158// further consequences on Data, depending on the platform.
159#define UNMAP_ALL (1U << 0)
160
161void unmap(void *Addr, uptr Size, uptr Flags = 0,
162           MapPlatformData *Data = nullptr);
163
164void releasePagesToOS(uptr BaseAddress, uptr Offset, uptr Size,
165                      MapPlatformData *Data = nullptr);
166
167// Internal map & unmap fatal error. This must not call map().
168void NORETURN dieOnMapUnmapError(bool OutOfMemory = false);
169
170// Logging related functions.
171
172void setAbortMessage(const char *Message);
173
174} // namespace scudo
175
176#endif // SCUDO_COMMON_H_
177