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
16using namespace lldb;
17using namespace lldb_private;
18
19class WatchpointAlgorithmsTest : public WatchpointAlgorithms {
20public:
21 using WatchpointAlgorithms::PowerOf2Watchpoints;
22 using WatchpointAlgorithms::Region;
23};
24
25struct testcase {
26 WatchpointAlgorithmsTest::Region user; // What the user requested
27 std::vector<WatchpointAlgorithmsTest::Region>
28 hw; // The hardware watchpoints we'll use
29};
30
31void 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
43TEST(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

source code of lldb/unittests/Breakpoint/WatchpointAlgorithmsTests.cpp