forked from libp2p/cpp-libp2p
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_your_hardware_tracker.cpp
More file actions
339 lines (257 loc) · 9.92 KB
/
test_your_hardware_tracker.cpp
File metadata and controls
339 lines (257 loc) · 9.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
#include <iostream>
#include <memory>
#include <vector>
#include <thread>
#include <chrono>
#include <signal.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/perf_event.h>
#include <linux/hw_breakpoint.h>
#include <execinfo.h>
#include <atomic>
#include <cstring>
// Простая заглушка для YamuxedConnection для тестирования hardware tracker'а
class YamuxedConnection {
public:
YamuxedConnection(int id) : id_(id) {
std::cout << "YamuxedConnection(" << id_ << ") создан по адресу " << this << std::endl;
}
~YamuxedConnection() {
std::cout << "YamuxedConnection(" << id_ << ") удален с адреса " << this << std::endl;
}
int getId() const { return id_; }
private:
int id_;
};
class HardwareSharedPtrTracker {
public:
static HardwareSharedPtrTracker& getInstance() {
static HardwareSharedPtrTracker instance;
return instance;
}
// Start tracking the reference count of a shared_ptr
void startTracking(std::shared_ptr<YamuxedConnection> ptr);
// Stop current tracking
void stopTracking();
// Check if tracking is active
bool isTracking() const { return is_tracking_; }
// Enable/disable tracking
void enable() { enabled_ = true; }
void disable() { enabled_ = false; }
private:
HardwareSharedPtrTracker();
~HardwareSharedPtrTracker();
// Get the address of the reference count in a shared_ptr
void* getRefCountAddress(const std::shared_ptr<YamuxedConnection>& ptr);
// Set hardware watchpoint
bool setHardwareWatchpoint(void* address);
// Remove hardware watchpoint
bool removeHardwareWatchpoint();
// Signal handler for memory changes
static void signalHandler(int sig, siginfo_t* info, void* context);
// Print stack trace
void printStackTrace();
// Check counter and switch to the next object if needed
void checkAndSwitchIfNeeded();
private:
std::atomic<bool> enabled_{false};
std::atomic<bool> is_tracking_{false};
std::atomic<bool> should_stop_{false}; // Flag for signal handler
void* watched_address_{nullptr};
int watchpoint_fd_{-1}; // Store perf_event fd
std::weak_ptr<YamuxedConnection> current_tracked_ptr_;
// For debug registers
static constexpr int DR7_L0 = 1; // Local enable for DR0
static constexpr int DR7_RW0_WRITE = (1 << 16); // Watch writes to DR0
static constexpr int DR7_LEN0_4BYTES = (3 << 18); // 4-byte length for DR0
static HardwareSharedPtrTracker* instance_;
struct sigaction old_sigtrap_action_;
};
// Global function for setting in yamux.cpp
void trackNextYamuxedConnection(std::shared_ptr<YamuxedConnection> ptr);
// Macros for convenience
#define YAMUX_HARDWARE_TRACK_ENABLE() \
libp2p::connection::HardwareSharedPtrTracker::getInstance().enable()
#define YAMUX_HARDWARE_TRACK_DISABLE() \
libp2p::connection::HardwareSharedPtrTracker::getInstance().disable()
#define YAMUX_HARDWARE_TRACK_SHARED_PTR(ptr) \
libp2p::connection::trackNextYamuxedConnection(ptr)
HardwareSharedPtrTracker* HardwareSharedPtrTracker::instance_ = nullptr;
HardwareSharedPtrTracker::HardwareSharedPtrTracker() {
instance_ = this;
struct sigaction sa;
sa.sa_sigaction = signalHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO | SA_RESTART;
if (sigaction(SIGTRAP, &sa, &old_sigtrap_action_) == -1) {
std::cerr << "Failed to install SIGTRAP handler\n";
}
std::cout << "HardwareSharedPtrTracker initialized\n";
}
HardwareSharedPtrTracker::~HardwareSharedPtrTracker() {
stopTracking();
sigaction(SIGTRAP, &old_sigtrap_action_, nullptr);
instance_ = nullptr;
}
void* HardwareSharedPtrTracker::getRefCountAddress(const std::shared_ptr<YamuxedConnection>& ptr) {
struct shared_ptr_internal {
void* ptr;
void* control_block;
};
auto* internal = reinterpret_cast<const shared_ptr_internal*>(&ptr);
void* control_block = internal->control_block;
if (!control_block) {
return nullptr;
}
void* ref_count_addr = control_block;
std::cout << "Control block address: " << control_block << "\n";
std::cout << "Reference count address: " << ref_count_addr << "\n";
std::cout << "Current use_count: " << ptr.use_count() << "\n";
return ref_count_addr;
}
bool HardwareSharedPtrTracker::setHardwareWatchpoint(void* address) {
struct perf_event_attr pe;
memset(&pe, 0, sizeof(pe));
pe.type = PERF_TYPE_BREAKPOINT;
pe.size = sizeof(pe);
pe.config = 0;
pe.bp_type = HW_BREAKPOINT_W | HW_BREAKPOINT_R;
pe.bp_addr = reinterpret_cast<uint64_t>(address);
pe.bp_len = sizeof(long);
pe.disabled = 0;
pe.exclude_kernel = 1;
pe.exclude_hv = 1;
int fd = syscall(__NR_perf_event_open, &pe, 0, -1, -1, 0);
if (fd == -1) {
perror("perf_event_open for hardware watchpoint failed");
return false;
}
watchpoint_fd_ = fd;
std::cout << "Hardware watchpoint set on address " << address
<< " (fd=" << fd << ")\n";
return true;
}
bool HardwareSharedPtrTracker::removeHardwareWatchpoint() {
if (watchpoint_fd_ != -1) {
close(watchpoint_fd_);
watchpoint_fd_ = -1;
std::cout << "Hardware watchpoint removed\n";
return true;
}
return false;
}
void HardwareSharedPtrTracker::signalHandler(int sig, siginfo_t* info, void* context) {
if (!instance_ || sig != SIGTRAP) {
return;
}
// printStackTrace();
static int call_number = 0;
call_number++;
const char msg[] = "\n=== HARDWARE BREAKPOINT: REFERENCE COUNT CHANGED ===\n";
write(STDOUT_FILENO, msg, sizeof(msg) - 1);
char call_msg[100];
int len = snprintf(call_msg, sizeof(call_msg), "Call #%d - Address: %p\n", call_number, info->si_addr);
write(STDOUT_FILENO, call_msg, len);
const int max_frames = 15;
void* buffer[max_frames];
const char stack_msg[] = "Stack trace (exact location of reference count change):\n";
write(STDOUT_FILENO, stack_msg, sizeof(stack_msg) - 1);
int nframes = backtrace(buffer, max_frames);
backtrace_symbols_fd(buffer, nframes, STDOUT_FILENO);
const char end_msg[] = "================================================\n\n";
write(STDOUT_FILENO, end_msg, sizeof(end_msg) - 1);
//instance_->signal_count_.fetch_add(1, std::memory_order_relaxed);
}
void HardwareSharedPtrTracker::printStackTrace() {
const int max_frames = 7;
void* buffer[max_frames];
int nframes = backtrace(buffer, max_frames);
char** symbols = backtrace_symbols(buffer, nframes);
std::cout << "Stack trace (reference count change):\n";
for (int i = 0; i < nframes; ++i) {
std::cout << " [" << i << "] " << (symbols ? symbols[i] : "???") << "\n";
}
if (symbols) {
free(symbols);
}
}
void HardwareSharedPtrTracker::checkAndSwitchIfNeeded() {
if (should_stop_.exchange(false)) {
std::cout << "\n=== HARDWARE BREAKPOINT TRIGGERED ===\n";
printStackTrace();
if (auto ptr = current_tracked_ptr_.lock()) {
long count = ptr.use_count();
std::cout << "Current use_count: " << count << "\n";
if (count <= 1) {
std::cout << "Object will be deleted soon (use_count=" << count << ")\n";
std::cout << "Stopping hardware tracking\n";
stopTracking();
}
} else {
std::cout << "Tracked object already deleted\n";
std::cout << "Stopping hardware tracking\n";
stopTracking();
}
std::cout << "====================================\n\n";
}
}
void HardwareSharedPtrTracker::startTracking(std::shared_ptr<YamuxedConnection> ptr) {
if (!enabled_) {
return;
}
if (!current_tracked_ptr_.expired()) {
std::cout << "Already tracking another YamuxedConnection (address: active"
<< "), ignoring new request\n";
return;
}
stopTracking();
std::cout << "\n=== HARDWARE TRACKING STARTED ===\n";
std::cout << "YamuxedConnection address: " << ptr.get() << "\n";
std::cout << "shared_ptr use_count: " << ptr.use_count() << "\n";
void* ref_count_addr = getRefCountAddress(ptr);
if (!ref_count_addr) {
std::cerr << "Failed to get reference count address\n";
return;
}
if (!setHardwareWatchpoint(ref_count_addr)) {
std::cerr << "Failed to set hardware watchpoint\n";
return;
}
watched_address_ = ref_count_addr;
current_tracked_ptr_ = ptr;
is_tracking_ = true;
should_stop_ = false;
std::cout << "Hardware tracking activated\n";
std::cout << "=================================\n\n";
}
void HardwareSharedPtrTracker::stopTracking() {
if (!is_tracking_) {
return;
}
std::cout << "\n=== HARDWARE TRACKING STOPPED ===\n";
removeHardwareWatchpoint();
watched_address_ = nullptr;
current_tracked_ptr_.reset();
is_tracking_ = false;
should_stop_ = false;
std::cout << "Hardware tracking stopped\n";
std::cout << "=================================\n\n";
}
void trackNextYamuxedConnection(std::shared_ptr<YamuxedConnection> ptr) {
auto& tracker = HardwareSharedPtrTracker::getInstance();
tracker.startTracking(std::move(ptr));
}
int main() {
auto& tracker = HardwareSharedPtrTracker::getInstance();
tracker.enable();
std::shared_ptr<YamuxedConnection> ptr1 = std::make_shared<YamuxedConnection>(1);
trackNextYamuxedConnection(ptr1);
std::shared_ptr<YamuxedConnection> ptr2 = ptr1;
ptr2.reset();
ptr1.reset();
std::shared_ptr<YamuxedConnection> ptr = std::make_shared<YamuxedConnection>(10);
trackNextYamuxedConnection(ptr);
ptr.reset();
return 0;
}