| 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 | |