1 | //===-- WatchpointAlgorithmsTests.cpp -------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "gtest/gtest.h" |
10 | |
11 | #include "lldb/Breakpoint/WatchpointAlgorithms.h" |
12 | |
13 | #include <utility> |
14 | #include <vector> |
15 | |
16 | using namespace lldb; |
17 | using namespace lldb_private; |
18 | |
19 | class WatchpointAlgorithmsTest : public WatchpointAlgorithms { |
20 | public: |
21 | using WatchpointAlgorithms::PowerOf2Watchpoints; |
22 | using WatchpointAlgorithms::Region; |
23 | }; |
24 | |
25 | struct testcase { |
26 | WatchpointAlgorithmsTest::Region user; // What the user requested |
27 | std::vector<WatchpointAlgorithmsTest::Region> |
28 | hw; // The hardware watchpoints we'll use |
29 | }; |
30 | |
31 | void check_testcase(testcase test, |
32 | std::vector<WatchpointAlgorithmsTest::Region> result, |
33 | size_t min_byte_size, size_t max_byte_size, |
34 | uint32_t address_byte_size) { |
35 | |
36 | EXPECT_EQ(result.size(), test.hw.size()); |
37 | for (size_t i = 0; i < result.size(); i++) { |
38 | EXPECT_EQ(result[i].addr, test.hw[i].addr); |
39 | EXPECT_EQ(result[i].size, test.hw[i].size); |
40 | } |
41 | } |
42 | |
43 | TEST(WatchpointAlgorithmsTests, PowerOf2Watchpoints) { |
44 | |
45 | // clang-format off |
46 | std::vector<testcase> doubleword_max = { |
47 | #if defined(__LP64__) |
48 | // These two tests don't work if lldb is built on |
49 | // a 32-bit system (likely with a 32-bit size_t). |
50 | // A 32-bit lldb debugging a 64-bit process isn't |
51 | // critical right now. |
52 | { |
53 | .user: {.addr: 0x7fffffffe83b, .size: 1}, |
54 | .hw: {{.addr: 0x7fffffffe83b, .size: 1}} |
55 | }, |
56 | { |
57 | .user: {.addr: 0x7fffffffe838, .size: 2}, |
58 | .hw: {{.addr: 0x7fffffffe838, .size: 2}} |
59 | }, |
60 | #endif |
61 | { |
62 | .user: {.addr: 0x1012, .size: 8}, |
63 | .hw: {{.addr: 0x1010, .size: 8}, {.addr: 0x1018, .size: 8}} |
64 | }, |
65 | { |
66 | .user: {.addr: 0x1002, .size: 4}, |
67 | .hw: {{.addr: 0x1000, .size: 8}} |
68 | }, |
69 | { |
70 | .user: {.addr: 0x1006, .size: 4}, |
71 | .hw: {{.addr: 0x1004, .size: 4}, {.addr: 0x1008, .size: 4}} |
72 | }, |
73 | { |
74 | .user: {.addr: 0x1006, .size: 8}, |
75 | .hw: {{.addr: 0x1000, .size: 8}, {.addr: 0x1008, .size: 8}} |
76 | }, |
77 | { |
78 | .user: {.addr: 0x1000, .size: 24}, |
79 | .hw: {{.addr: 0x1000, .size: 8}, {.addr: 0x1008, .size: 8}, {.addr: 0x1010, .size: 8}} |
80 | }, |
81 | { |
82 | .user: {.addr: 0x1014, .size: 26}, |
83 | .hw: {{.addr: 0x1010, .size: 8}, {.addr: 0x1018, .size: 8}, {.addr: 0x1020, .size: 8}, {.addr: 0x1028, .size: 8}} |
84 | }, |
85 | }; |
86 | // clang-format on |
87 | for (testcase test : doubleword_max) { |
88 | addr_t user_addr = test.user.addr; |
89 | size_t user_size = test.user.size; |
90 | size_t min_byte_size = 1; |
91 | size_t max_byte_size = 8; |
92 | size_t address_byte_size = 8; |
93 | auto result = WatchpointAlgorithmsTest::PowerOf2Watchpoints( |
94 | user_addr, user_size, min_byte_size, max_byte_size, address_byte_size); |
95 | |
96 | check_testcase(test, result, min_byte_size, max_byte_size, |
97 | address_byte_size); |
98 | } |
99 | |
100 | // clang-format off |
101 | std::vector<testcase> word_max = { |
102 | { |
103 | .user: {.addr: 0x00411050, .size: 4}, |
104 | .hw: {{.addr: 0x00411050, .size: 4}} |
105 | }, |
106 | { |
107 | .user: {.addr: 0x1002, .size: 4}, |
108 | .hw: {{.addr: 0x1000, .size: 4}, {.addr: 0x1004, .size: 4}} |
109 | }, |
110 | }; |
111 | // clang-format on |
112 | for (testcase test : word_max) { |
113 | addr_t user_addr = test.user.addr; |
114 | size_t user_size = test.user.size; |
115 | size_t min_byte_size = 1; |
116 | size_t max_byte_size = 4; |
117 | size_t address_byte_size = 4; |
118 | auto result = WatchpointAlgorithmsTest::PowerOf2Watchpoints( |
119 | user_addr, user_size, min_byte_size, max_byte_size, address_byte_size); |
120 | |
121 | check_testcase(test, result, min_byte_size, max_byte_size, |
122 | address_byte_size); |
123 | } |
124 | |
125 | // clang-format off |
126 | std::vector<testcase> twogig_max = { |
127 | { |
128 | .user: {.addr: 0x1010, .size: 16}, |
129 | .hw: {{.addr: 0x1010, .size: 16}} |
130 | }, |
131 | { |
132 | .user: {.addr: 0x1010, .size: 24}, |
133 | .hw: {{.addr: 0x1000, .size: 64}} |
134 | }, |
135 | |
136 | // We increase 36 to the aligned 64 byte size, but |
137 | // 0x1000-0x1040 doesn't cover the requested region. Then |
138 | // we expand to 128 bytes starting at 0x1000 that does |
139 | // cover it. Is this a good tradeoff for a 36 byte region? |
140 | { |
141 | .user: {.addr: 0x1024, .size: 36}, |
142 | .hw: {{.addr: 0x1000, .size: 128}} |
143 | }, |
144 | { |
145 | .user: {.addr: 0x1000, .size: 192}, |
146 | .hw: {{.addr: 0x1000, .size: 256}} |
147 | }, |
148 | { |
149 | .user: {.addr: 0x1080, .size: 192}, |
150 | .hw: {{.addr: 0x1000, .size: 512}} |
151 | }, |
152 | |
153 | // In this case, our aligned size is 128, and increasing it to 256 |
154 | // still can't watch the requested region. The algorithm |
155 | // falls back to using two 128 byte watchpoints. |
156 | // The alternative would be to use a 1024B watchpoint |
157 | // starting at 0x1000, to watch this 120 byte user request. |
158 | // |
159 | // This still isn't ideal. The user is asking to watch 0x12e0-1358 |
160 | // and could be optimally handled by a |
161 | // 16-byte watchpoint at 0x12e0 and a 128-byte watchpoint at 0x1300 |
162 | { |
163 | .user: {.addr: 0x12e0, .size: 120}, |
164 | .hw: {{.addr: 0x1280, .size: 128}, {.addr: 0x1300, .size: 128}} |
165 | }, |
166 | }; |
167 | // clang-format on |
168 | for (testcase test : twogig_max) { |
169 | addr_t user_addr = test.user.addr; |
170 | size_t user_size = test.user.size; |
171 | size_t min_byte_size = 1; |
172 | size_t max_byte_size = INT32_MAX; |
173 | size_t address_byte_size = 8; |
174 | auto result = WatchpointAlgorithmsTest::PowerOf2Watchpoints( |
175 | user_addr, user_size, min_byte_size, max_byte_size, address_byte_size); |
176 | |
177 | check_testcase(test, result, min_byte_size, max_byte_size, |
178 | address_byte_size); |
179 | } |
180 | |
181 | } |
182 | |