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(first: std::begin(arr: accessible_pages), last: std::end(arr: accessible_pages), |
13 | val: page) != std::end(arr: 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(addr: nullptr, len: num_pages * pagesize, PROT_READ | PROT_WRITE, |
55 | MAP_PRIVATE | MAP_ANONYMOUS, fd: -1, offset: 0); |
56 | if (mem == MAP_FAILED) { |
57 | perror(s: "mmap" ); |
58 | exit(status: 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(addr: bytes + page * pagesize, len: pagesize) != 0) { |
65 | perror(s: "munmap" ); |
66 | exit(status: 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(dest: p, src: "needle" ); |
86 | |
87 | return 0; // break here |
88 | } |
89 | |