CCTLib
Calling-context and data-object attribution library for Intel Pin
shadow_memory.H
Go to the documentation of this file.
1 // @COPYRIGHT@
2 // Licensed under MIT license.
3 // See LICENSE.TXT file in the project root for more information.
4 // ==============================================================
5 #ifndef __SHADOW_MEMORY__
6 #define __SHADOW_MEMORY__
7 #include <stdint.h>
8 #include <atomic>
9 #include <stdlib.h>
10 #include <sys/mman.h>
11 #include <tuple>
12 
13 // 64KB shadow pages
14 #define PAGE_OFFSET_BITS (16LL)
15 #define PAGE_OFFSET(addr) (addr & 0xFFFF)
16 #define PAGE_OFFSET_MASK (0xFFFF)
17 #define SHADOW_PAGE_SIZE (1 << PAGE_OFFSET_BITS)
18 
19 // 2 level page table
20 #define PTR_SIZE (sizeof(struct Status*))
21 #define LEVEL_1_PAGE_TABLE_BITS (20)
22 #define LEVEL_1_PAGE_TABLE_ENTRIES (1 << LEVEL_1_PAGE_TABLE_BITS)
23 #define LEVEL_1_PAGE_TABLE_SIZE (LEVEL_1_PAGE_TABLE_ENTRIES * PTR_SIZE)
24 
25 #define LEVEL_2_PAGE_TABLE_BITS (12)
26 #define LEVEL_2_PAGE_TABLE_ENTRIES (1 << LEVEL_2_PAGE_TABLE_BITS)
27 #define LEVEL_2_PAGE_TABLE_SIZE (LEVEL_2_PAGE_TABLE_ENTRIES * PTR_SIZE)
28 
29 #define LEVEL_1_PAGE_TABLE_SLOT(addr) ((((uint64_t)addr) >> (LEVEL_2_PAGE_TABLE_BITS + PAGE_OFFSET_BITS)) & 0xfffff)
30 #define LEVEL_2_PAGE_TABLE_SLOT(addr) ((((uint64_t)addr) >> (PAGE_OFFSET_BITS)) & 0xFFF)
31 
32 #define SHADOW_STRUCT_SIZE (sizeof(T))
33 using namespace std;
34 
35 #define PIN_ExitProcess(a) exit(a)
36 
37 /*
38 template <typename... Ts>
39 struct ShadowType {
40  tuple<Ts[SHADOW_PAGE_SIZE]...> f;
41  void * operator new(size_t sz) {
42  void * p = mmap(nullptr, sz, PROT_WRITE | PROT_READ, MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
43  if(p == MAP_FAILED) {
44  perror("mmap l2pg");
45  PIN_ExitProcess(-1);
46  }
47  return p;
48  }
49  void operator delete(void *p) {
50  munmap(p, sizeof(ShadowType<Ts...>));
51  }
52 };
53 */
54 
55 template <class... Args>
56 using ShadowTuple = std::tuple<Args[SHADOW_PAGE_SIZE]...>;
57 
58 
59 #if 1
60 template <typename... Ts>
62  // All fwd declarations
63  atomic<atomic<ShadowTuple<Ts...>*>*>* pageDirectory;
64  // Given a address generated by the program, returns the corresponding shadow address FLOORED to SHADOW_PAGE_SIZE
65  // If the shadow page does not exist a new one is MMAPed
66  public:
68  pageDirectory = (atomic<atomic<ShadowTuple<Ts...>*>*>*)mmap(nullptr, LEVEL_1_PAGE_TABLE_SIZE, PROT_WRITE | PROT_READ, MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
69  if (pageDirectory == MAP_FAILED) {
70  perror("mmap pageDirectory");
71  PIN_ExitProcess(-1);
72  }
73  }
74 
76  for (uint64_t i = 0; i < LEVEL_1_PAGE_TABLE_ENTRIES; i++) {
77  atomic<ShadowTuple<Ts...>*>* l1Page;
78  if ((l1Page = pageDirectory[i].load(memory_order_relaxed)) != nullptr) {
79  for (uint64_t j = 0; j < LEVEL_2_PAGE_TABLE_ENTRIES; j++) {
80  ShadowTuple<Ts...>* l2Page;
81  if ((l2Page = l1Page[j].load(memory_order_relaxed)) != nullptr) {
82  delete l2Page;
83  }
84  }
85  if (0 != munmap(l1Page, LEVEL_2_PAGE_TABLE_SIZE)) {
86  perror("munmap pageDirectory");
87  PIN_ExitProcess(-1);
88  }
89  }
90  }
91  if (0 != munmap(pageDirectory, LEVEL_1_PAGE_TABLE_SIZE)) {
92  perror("munmap pageDirectory");
93  PIN_ExitProcess(-1);
94  }
95  }
96 
97  inline ShadowTuple<Ts...>& GetOrCreateShadowBaseAddress(const size_t address) {
98  atomic<atomic<ShadowTuple<Ts...>*>*>* l1Ptr = &pageDirectory[LEVEL_1_PAGE_TABLE_SLOT(address)];
99  atomic<ShadowTuple<Ts...>*>* v1;
100  if ((v1 = l1Ptr->load(memory_order_consume)) == nullptr) {
101  atomic<ShadowTuple<Ts...>*>* l1pg = (atomic<ShadowTuple<Ts...>*>*)mmap(nullptr, LEVEL_2_PAGE_TABLE_SIZE, PROT_WRITE | PROT_READ, MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
102  if (l1pg == MAP_FAILED) {
103  perror("mmap l1pg");
104  PIN_ExitProcess(-1);
105  }
106 
107  atomic<ShadowTuple<Ts...>*>* nullVal = nullptr;
108  if (!l1Ptr->compare_exchange_strong(nullVal, l1pg, memory_order_acq_rel, memory_order_relaxed)) {
109  // Another thread won the race. Release OUR unused mmap
110  // allocation with munmap -- calling free() on an mmap'd
111  // region is undefined behavior and can corrupt the heap.
112  munmap(l1pg, LEVEL_2_PAGE_TABLE_SIZE);
113  v1 = l1Ptr->load(memory_order_consume);
114  } else {
115  v1 = l1pg;
116  }
117  }
118  atomic<ShadowTuple<Ts...>*>* l2Ptr = &v1[LEVEL_2_PAGE_TABLE_SLOT(address)];
119  ShadowTuple<Ts...>* v2;
120  if ((v2 = l2Ptr->load(memory_order_consume)) == nullptr) {
121  ShadowTuple<Ts...>* l2pg = new ShadowTuple<Ts...>;
122  if (l2pg == MAP_FAILED) {
123  perror("mmap l2pg");
124  PIN_ExitProcess(-1);
125  }
126  ShadowTuple<Ts...>* nullVal = nullptr;
127  if (!l2Ptr->compare_exchange_strong(nullVal, l2pg, memory_order_acq_rel, memory_order_relaxed)) {
128  delete l2pg;
129  v2 = l2Ptr->load(memory_order_consume);
130  } else {
131  v2 = l2pg;
132  }
133  }
134  return (*v2);
135  }
136 };
137 
138 
139 template <int I, typename... Ts>
140 inline __attribute__((always_inline)) typename std::tuple_element<I, tuple<Ts...>>::type* GetOrCreateShadowAddress(ConcurrentShadowMemory<Ts...>& sm, const size_t address) {
141  // `auto&` is load-bearing here. GetOrCreateShadowBaseAddress returns a
142  // reference to a ShadowTuple<Ts...> living inside the mmap'd shadow page.
143  // Binding by value (`auto`) would strip the reference and copy the tuple
144  // (a std::tuple<T[65536]>, hundreds of KB) onto the caller's stack, then
145  // return a pointer into that stack copy -- writes never reach the real
146  // shadow memory and reads observe uninitialized memory (see
147  // tests/shadow_memory_unittest.cpp).
148  auto& shadowPage = sm.GetOrCreateShadowBaseAddress(address);
149  return &(get<I>(shadowPage)[PAGE_OFFSET((uint64_t)address)]);
150 }
151 #endif
152 
153 template <typename... Ts>
155  // All fwd declarations
157  // Given a address generated by the program, returns the corresponding shadow address FLOORED to SHADOW_PAGE_SIZE
158  // If the shadow page does not exist a new one is MMAPed
159  public:
160  inline ShadowMemory() {
161  pageDirectory = (ShadowTuple<Ts...>***)mmap(nullptr, LEVEL_1_PAGE_TABLE_SIZE, PROT_WRITE | PROT_READ, MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
162  if (pageDirectory == MAP_FAILED) {
163  perror("mmap pageDirectory");
164  PIN_ExitProcess(-1);
165  }
166  }
167 
168  inline ~ShadowMemory() {
169  for (uint64_t i = 0; i < LEVEL_1_PAGE_TABLE_ENTRIES; i++) {
170  ShadowTuple<Ts...>** l1Page;
171  if ((l1Page = pageDirectory[i]) != nullptr) {
172  for (uint64_t j = 0; j < LEVEL_2_PAGE_TABLE_ENTRIES; j++) {
173  ShadowTuple<Ts...>* l2Page;
174  if ((l2Page = l1Page[j]) != nullptr) {
175  delete l2Page;
176  }
177  }
178  if (0 != munmap(l1Page, LEVEL_2_PAGE_TABLE_SIZE)) {
179  perror("munmap pageDirectory");
180  PIN_ExitProcess(-1);
181  }
182  }
183  }
184  if (0 != munmap(pageDirectory, LEVEL_1_PAGE_TABLE_SIZE)) {
185  perror("munmap pageDirectory");
186  PIN_ExitProcess(-1);
187  }
188  }
189 
190  inline ShadowTuple<Ts...>& GetOrCreateShadowBaseAddress(const size_t address) {
191  ShadowTuple<Ts...>*** l1Ptr = &pageDirectory[LEVEL_1_PAGE_TABLE_SLOT(address)];
192  ShadowTuple<Ts...>** v1;
193  if ((v1 = *l1Ptr) == nullptr) {
194  ShadowTuple<Ts...>** l1pg = (ShadowTuple<Ts...>**)mmap(nullptr, LEVEL_2_PAGE_TABLE_SIZE, PROT_WRITE | PROT_READ, MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
195  if (l1pg == MAP_FAILED) {
196  perror("mmap l1pg");
197  PIN_ExitProcess(-1);
198  }
199  *l1Ptr = l1pg;
200  v1 = l1pg;
201  }
202  ShadowTuple<Ts...>** l2Ptr = &v1[LEVEL_2_PAGE_TABLE_SLOT(address)];
203  ShadowTuple<Ts...>* v2;
204  if ((v2 = *l2Ptr) == nullptr) {
205  ShadowTuple<Ts...>* l2pg = new ShadowTuple<Ts...>;
206  if (l2pg == MAP_FAILED) {
207  perror("mmap l2pg");
208  PIN_ExitProcess(-1);
209  }
210  *l2Ptr = l2pg;
211  v2 = l2pg;
212  }
213  return (*v2);
214  }
215 };
216 
217 template <int I, typename... Ts>
218 inline __attribute__((always_inline)) typename std::tuple_element<I, tuple<Ts...>>::type* GetOrCreateShadowAddress(ShadowMemory<Ts...>& sm, const size_t address) {
219  // `auto&` is required for correctness -- same reason as the
220  // ConcurrentShadowMemory overload above.
221  auto& shadowPage = sm.GetOrCreateShadowBaseAddress(address);
222  return &(get<I>(shadowPage)[PAGE_OFFSET((uint64_t)address)]);
223 }
224 //#define ConcurrentShadowMemory ShadowMemory
225 
226 #if 0
229 int main(){
230 
231 for(int i = 0; i < 0xffff; i++){
232  GetOrCreateShadowAddress<0>(s, 0x12345678)[0] = 1234;
233  int j = GetOrCreateShadowAddress<0>(s, 0x12345678)[0];
234 
235  GetOrCreateShadowAddress<0>(cs, 0x12345678)[0] = 1234;
236  j = GetOrCreateShadowAddress<0>(cs, 0x12345678)[0];
237 }
238  return 0;
239 }
240 #endif
241 
242 #endif // __SHADOW_MEMORY__
int main(int argc, char *argv[])
atomic< atomic< ShadowTuple< Ts... > * > * > * pageDirectory
Definition: shadow_memory.H:63
ShadowTuple< Ts... > & GetOrCreateShadowBaseAddress(const size_t address)
Definition: shadow_memory.H:97
ShadowTuple< Ts... > *** pageDirectory
ShadowTuple< Ts... > & GetOrCreateShadowBaseAddress(const size_t address)
static ConcurrentShadowMemory< DataHandle_t > sm
Definition: cctlib.cpp:2479
void * address
std::tuple< Args[SHADOW_PAGE_SIZE]... > ShadowTuple
Definition: shadow_memory.H:56
#define LEVEL_2_PAGE_TABLE_SIZE
Definition: shadow_memory.H:27
#define LEVEL_1_PAGE_TABLE_SLOT(addr)
Definition: shadow_memory.H:29
#define PAGE_OFFSET(addr)
Definition: shadow_memory.H:15
#define LEVEL_1_PAGE_TABLE_ENTRIES
Definition: shadow_memory.H:22
#define LEVEL_2_PAGE_TABLE_ENTRIES
Definition: shadow_memory.H:26
#define SHADOW_PAGE_SIZE
Definition: shadow_memory.H:17
#define LEVEL_1_PAGE_TABLE_SIZE
Definition: shadow_memory.H:23
__attribute__((always_inline)) typename std
#define PIN_ExitProcess(a)
Definition: shadow_memory.H:35
#define LEVEL_2_PAGE_TABLE_SLOT(addr)
Definition: shadow_memory.H:30