xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/memprof/memprof_mapping.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1e8d8bef9SDimitry Andric //===-- memprof_mapping.h --------------------------------------*- C++ -*-===//
2e8d8bef9SDimitry Andric //
3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e8d8bef9SDimitry Andric //
7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
8e8d8bef9SDimitry Andric //
9e8d8bef9SDimitry Andric // This file is a part of MemProfiler, a memory profiler.
10e8d8bef9SDimitry Andric //
11e8d8bef9SDimitry Andric // Defines MemProf memory mapping.
12e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
13e8d8bef9SDimitry Andric #ifndef MEMPROF_MAPPING_H
14e8d8bef9SDimitry Andric #define MEMPROF_MAPPING_H
15e8d8bef9SDimitry Andric 
16e8d8bef9SDimitry Andric #include "memprof_internal.h"
17e8d8bef9SDimitry Andric 
18e8d8bef9SDimitry Andric static const u64 kDefaultShadowScale = 3;
19e8d8bef9SDimitry Andric #define SHADOW_SCALE kDefaultShadowScale
20e8d8bef9SDimitry Andric 
21e8d8bef9SDimitry Andric #define SHADOW_OFFSET __memprof_shadow_memory_dynamic_address
22e8d8bef9SDimitry Andric 
23e8d8bef9SDimitry Andric #define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
24e8d8bef9SDimitry Andric #define MEMPROF_ALIGNMENT 32
25e8d8bef9SDimitry Andric namespace __memprof {
26e8d8bef9SDimitry Andric 
27e8d8bef9SDimitry Andric extern uptr kHighMemEnd; // Initialized in __memprof_init.
28e8d8bef9SDimitry Andric 
29e8d8bef9SDimitry Andric } // namespace __memprof
30e8d8bef9SDimitry Andric 
31e8d8bef9SDimitry Andric // Size of memory block mapped to a single shadow location
32e8d8bef9SDimitry Andric #define MEM_GRANULARITY 64ULL
33e8d8bef9SDimitry Andric 
34e8d8bef9SDimitry Andric #define SHADOW_MASK ~(MEM_GRANULARITY - 1)
35e8d8bef9SDimitry Andric 
36e8d8bef9SDimitry Andric #define MEM_TO_SHADOW(mem)                                                     \
37e8d8bef9SDimitry Andric   ((((mem) & SHADOW_MASK) >> SHADOW_SCALE) + (SHADOW_OFFSET))
38e8d8bef9SDimitry Andric 
39*0fca6ea1SDimitry Andric // Histogram shadow memory is laid different to the standard configuration:
40*0fca6ea1SDimitry Andric 
41*0fca6ea1SDimitry Andric //             8 bytes
42*0fca6ea1SDimitry Andric //         +---+---+---+  +---+---+---+  +---+---+---+
43*0fca6ea1SDimitry Andric //  Memory |     a     |  |     b     |  |     c     |
44*0fca6ea1SDimitry Andric //         +---+---+---+  +---+---+---+  +---+---+---+
45*0fca6ea1SDimitry Andric 
46*0fca6ea1SDimitry Andric //             +---+          +---+          +---+
47*0fca6ea1SDimitry Andric //  Shadow     | a |          | b |          | c |
48*0fca6ea1SDimitry Andric //             +---+          +---+          +---+
49*0fca6ea1SDimitry Andric //            1 byte
50*0fca6ea1SDimitry Andric //
51*0fca6ea1SDimitry Andric // Where we have a 1 byte counter for each 8 bytes. HISTOGRAM_MEM_TO_SHADOW
52*0fca6ea1SDimitry Andric // translates a memory address to the address of its corresponding shadow
53*0fca6ea1SDimitry Andric // counter memory address. The same data is still provided in MIB whether
54*0fca6ea1SDimitry Andric // histograms are used or not. Total access counts per allocations are
55*0fca6ea1SDimitry Andric // computed by summing up all individual 1 byte counters. This can incur an
56*0fca6ea1SDimitry Andric // accuracy penalty.
57*0fca6ea1SDimitry Andric 
58*0fca6ea1SDimitry Andric #define HISTOGRAM_GRANULARITY 8U
59*0fca6ea1SDimitry Andric 
60*0fca6ea1SDimitry Andric #define HISTOGRAM_MAX_COUNTER 255U
61*0fca6ea1SDimitry Andric 
62*0fca6ea1SDimitry Andric #define HISTOGRAM_SHADOW_MASK ~(HISTOGRAM_GRANULARITY - 1)
63*0fca6ea1SDimitry Andric 
64*0fca6ea1SDimitry Andric #define HISTOGRAM_MEM_TO_SHADOW(mem)                                           \
65*0fca6ea1SDimitry Andric   ((((mem) & HISTOGRAM_SHADOW_MASK) >> SHADOW_SCALE) + (SHADOW_OFFSET))
66*0fca6ea1SDimitry Andric 
67*0fca6ea1SDimitry Andric #define SHADOW_ENTRY_SIZE (MEM_GRANULARITY >> SHADOW_SCALE)
68*0fca6ea1SDimitry Andric 
69e8d8bef9SDimitry Andric #define kLowMemBeg 0
70e8d8bef9SDimitry Andric #define kLowMemEnd (SHADOW_OFFSET ? SHADOW_OFFSET - 1 : 0)
71e8d8bef9SDimitry Andric 
72e8d8bef9SDimitry Andric #define kLowShadowBeg SHADOW_OFFSET
73e8d8bef9SDimitry Andric #define kLowShadowEnd (MEM_TO_SHADOW(kLowMemEnd) + SHADOW_ENTRY_SIZE - 1)
74e8d8bef9SDimitry Andric 
75e8d8bef9SDimitry Andric #define kHighMemBeg (MEM_TO_SHADOW(kHighMemEnd) + 1 + SHADOW_ENTRY_SIZE - 1)
76e8d8bef9SDimitry Andric 
77e8d8bef9SDimitry Andric #define kHighShadowBeg MEM_TO_SHADOW(kHighMemBeg)
78e8d8bef9SDimitry Andric #define kHighShadowEnd (MEM_TO_SHADOW(kHighMemEnd) + SHADOW_ENTRY_SIZE - 1)
79e8d8bef9SDimitry Andric 
80e8d8bef9SDimitry Andric // With the zero shadow base we can not actually map pages starting from 0.
81e8d8bef9SDimitry Andric // This constant is somewhat arbitrary.
82e8d8bef9SDimitry Andric #define kZeroBaseShadowStart 0
83e8d8bef9SDimitry Andric #define kZeroBaseMaxShadowStart (1 << 18)
84e8d8bef9SDimitry Andric 
85e8d8bef9SDimitry Andric #define kShadowGapBeg (kLowShadowEnd ? kLowShadowEnd + 1 : kZeroBaseShadowStart)
86e8d8bef9SDimitry Andric #define kShadowGapEnd (kHighShadowBeg - 1)
87e8d8bef9SDimitry Andric 
88e8d8bef9SDimitry Andric namespace __memprof {
89e8d8bef9SDimitry Andric 
90e8d8bef9SDimitry Andric inline uptr MemToShadowSize(uptr size) { return size >> SHADOW_SCALE; }
91e8d8bef9SDimitry Andric inline bool AddrIsInLowMem(uptr a) { return a <= kLowMemEnd; }
92e8d8bef9SDimitry Andric 
93e8d8bef9SDimitry Andric inline bool AddrIsInLowShadow(uptr a) {
94e8d8bef9SDimitry Andric   return a >= kLowShadowBeg && a <= kLowShadowEnd;
95e8d8bef9SDimitry Andric }
96e8d8bef9SDimitry Andric 
97e8d8bef9SDimitry Andric inline bool AddrIsInHighMem(uptr a) {
98e8d8bef9SDimitry Andric   return kHighMemBeg && a >= kHighMemBeg && a <= kHighMemEnd;
99e8d8bef9SDimitry Andric }
100e8d8bef9SDimitry Andric 
101e8d8bef9SDimitry Andric inline bool AddrIsInHighShadow(uptr a) {
102e8d8bef9SDimitry Andric   return kHighMemBeg && a >= kHighShadowBeg && a <= kHighShadowEnd;
103e8d8bef9SDimitry Andric }
104e8d8bef9SDimitry Andric 
105e8d8bef9SDimitry Andric inline bool AddrIsInShadowGap(uptr a) {
106e8d8bef9SDimitry Andric   // In zero-based shadow mode we treat addresses near zero as addresses
107e8d8bef9SDimitry Andric   // in shadow gap as well.
108e8d8bef9SDimitry Andric   if (SHADOW_OFFSET == 0)
109e8d8bef9SDimitry Andric     return a <= kShadowGapEnd;
110e8d8bef9SDimitry Andric   return a >= kShadowGapBeg && a <= kShadowGapEnd;
111e8d8bef9SDimitry Andric }
112e8d8bef9SDimitry Andric 
113e8d8bef9SDimitry Andric inline bool AddrIsInMem(uptr a) {
114e8d8bef9SDimitry Andric   return AddrIsInLowMem(a) || AddrIsInHighMem(a) ||
115e8d8bef9SDimitry Andric          (flags()->protect_shadow_gap == 0 && AddrIsInShadowGap(a));
116e8d8bef9SDimitry Andric }
117e8d8bef9SDimitry Andric 
118e8d8bef9SDimitry Andric inline uptr MemToShadow(uptr p) {
119e8d8bef9SDimitry Andric   CHECK(AddrIsInMem(p));
120e8d8bef9SDimitry Andric   return MEM_TO_SHADOW(p);
121e8d8bef9SDimitry Andric }
122e8d8bef9SDimitry Andric 
123e8d8bef9SDimitry Andric inline bool AddrIsInShadow(uptr a) {
124e8d8bef9SDimitry Andric   return AddrIsInLowShadow(a) || AddrIsInHighShadow(a);
125e8d8bef9SDimitry Andric }
126e8d8bef9SDimitry Andric 
127e8d8bef9SDimitry Andric inline bool AddrIsAlignedByGranularity(uptr a) {
128e8d8bef9SDimitry Andric   return (a & (SHADOW_GRANULARITY - 1)) == 0;
129e8d8bef9SDimitry Andric }
130e8d8bef9SDimitry Andric 
131e8d8bef9SDimitry Andric inline void RecordAccess(uptr a) {
132e8d8bef9SDimitry Andric   // If we use a different shadow size then the type below needs adjustment.
133e8d8bef9SDimitry Andric   CHECK_EQ(SHADOW_ENTRY_SIZE, 8);
134e8d8bef9SDimitry Andric   u64 *shadow_address = (u64 *)MEM_TO_SHADOW(a);
135e8d8bef9SDimitry Andric   (*shadow_address)++;
136e8d8bef9SDimitry Andric }
137e8d8bef9SDimitry Andric 
138*0fca6ea1SDimitry Andric inline void RecordAccessHistogram(uptr a) {
139*0fca6ea1SDimitry Andric   CHECK_EQ(SHADOW_ENTRY_SIZE, 8);
140*0fca6ea1SDimitry Andric   u8 *shadow_address = (u8 *)HISTOGRAM_MEM_TO_SHADOW(a);
141*0fca6ea1SDimitry Andric   if (*shadow_address < HISTOGRAM_MAX_COUNTER) {
142*0fca6ea1SDimitry Andric     (*shadow_address)++;
143*0fca6ea1SDimitry Andric   }
144*0fca6ea1SDimitry Andric }
145*0fca6ea1SDimitry Andric 
146e8d8bef9SDimitry Andric } // namespace __memprof
147e8d8bef9SDimitry Andric 
148e8d8bef9SDimitry Andric #endif // MEMPROF_MAPPING_H
149