xref: /llvm-project/lldb/test/API/functionalities/memory/holes/main.cpp (revision 181cc75ea8be70e3fa7145456e1bf2331e0bc5e4)
1 #include <algorithm>
2 #include <cstdint>
3 #include <cstdio>
4 #include <cstdlib>
5 #include <cstring>
6 #include <iostream>
7 
8 constexpr size_t num_pages = 7;
9 constexpr size_t accessible_pages[] = {0, 2, 4, 6};
10 
11 bool is_accessible(size_t page) {
12   return std::find(std::begin(accessible_pages), std::end(accessible_pages),
13                    page) != std::end(accessible_pages);
14 }
15 
16 // allocate_memory_with_holes returns a pointer to `num_pages` pages of memory,
17 // where some of the pages are inaccessible (even to debugging APIs). We use
18 // this to test lldb's ability to skip over inaccessible blocks.
19 #ifdef _WIN32
20 #include "Windows.h"
21 
22 int getpagesize() {
23   SYSTEM_INFO system_info;
24   GetSystemInfo(&system_info);
25   return system_info.dwPageSize;
26 }
27 
28 char *allocate_memory_with_holes() {
29   int pagesize = getpagesize();
30   void *mem =
31       VirtualAlloc(nullptr, num_pages * pagesize, MEM_RESERVE, PAGE_NOACCESS);
32   if (!mem) {
33     std::cerr << std::system_category().message(GetLastError()) << std::endl;
34     exit(1);
35   }
36   char *bytes = static_cast<char *>(mem);
37   for (size_t page = 0; page < num_pages; ++page) {
38     if (!is_accessible(page))
39       continue;
40     if (!VirtualAlloc(bytes + page * pagesize, pagesize, MEM_COMMIT,
41                       PAGE_READWRITE)) {
42       std::cerr << std::system_category().message(GetLastError()) << std::endl;
43       exit(1);
44     }
45   }
46   return bytes;
47 }
48 #else
49 #include "sys/mman.h"
50 #include "unistd.h"
51 
52 char *allocate_memory_with_holes() {
53   int pagesize = getpagesize();
54   void *mem = mmap(nullptr, num_pages * pagesize, PROT_READ | PROT_WRITE,
55                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
56   if (mem == MAP_FAILED) {
57     perror("mmap");
58     exit(1);
59   }
60   char *bytes = static_cast<char *>(mem);
61   for (size_t page = 0; page < num_pages; ++page) {
62     if (is_accessible(page))
63       continue;
64     if (munmap(bytes + page * pagesize, pagesize) != 0) {
65       perror("munmap");
66       exit(1);
67     }
68   }
69   return bytes;
70 }
71 #endif
72 
73 int main(int argc, char const *argv[]) {
74   char *mem_with_holes = allocate_memory_with_holes();
75   int pagesize = getpagesize();
76   char *positions[] = {
77       mem_with_holes,                // Beginning of memory
78       mem_with_holes + 2 * pagesize, // After a hole
79       mem_with_holes + 2 * pagesize +
80           pagesize / 2, // Middle of a block, after an existing match.
81       mem_with_holes + 5 * pagesize - 7, // End of a block
82       mem_with_holes + 7 * pagesize - 7, // End of memory
83   };
84   for (char *p : positions)
85     strcpy(p, "needle");
86 
87   return 0; // break here
88 }
89