ttg 1.0.0
Template Task Graph (TTG): flowgraph-based programming model for high-performance distributed-memory algorithms
Loading...
Searching...
No Matches
bug.h
Go to the documentation of this file.
1// SPDX-License-Identifier: BSD-3-Clause
2//
3// bug.h
4//
5// Copyright (C) 1996 Limit Point Systems, Inc.
6//
7// Author: Curtis Janssen <cljanss@limitpt.com>
8// Maintainer: LPS
9//
10// This file is part of the SC Toolkit.
11//
12// The SC Toolkit is free software; you can redistribute it and/or modify
13// it under the terms of the GNU Library General Public License as published by
14// the Free Software Foundation; either version 2, or (at your option)
15// any later version.
16//
17// The SC Toolkit is distributed in the hope that it will be useful,
18// but WITHOUT ANY WARRANTY; without even the implied warranty of
19// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20// GNU Library General Public License for more details.
21//
22// You should have received a copy of the GNU Library General Public License
23// along with the SC Toolkit; see the file COPYING.LIB. If not, write to
24// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
25//
26// The U.S. Government is granted a limited license as per AL 91-7.
27//
28
29#ifndef TTG_UTIL_MISC_BUG_H_
30#define TTG_UTIL_MISC_BUG_H_
31
32#include <cassert>
33#include <memory>
34#include <stdexcept>
35#include <string>
36#include <unordered_map>
37#include <vector>
38
39#include <pthread.h>
40#if __APPLE__
41#include <mach/mach.h>
42#endif
43
44namespace ttg {
45 namespace detail {
46
52 public:
53 // x86 debugging registers are described in see
54 // https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-system-programming-manual-325384.html
55 enum DebugRegister { kDR0 = 0, kDR1 = 1, kDR2 = 2, kDR3 = 3 };
56
57 enum Size {
58 kByte = 0, // 1 byte - 00
59 kHalfWord = 1, // 2 bytes - 01
60 kWord = 3, // 4 bytes - 11
61 // kDoubleWord = 2, // 8 bytes - 10 NOT SUPPORTED BY SOME CHIPS!
62 kSizeMask = 3 // mask 11
63 };
64
66 kDisabled = 0, // disabled - 00
67 kEnabledLocally = 1, // task local - 01
68 kEnabledGlobally = 2, // global - 10
69 kBreakStateMask = 3 // mask 11
70 };
71
72 enum Condition {
73 kWhenExecuted = 0, // on execution - 00
74 kWhenWritten = 1, // on write - 01
75 kWhenWrittenOrRead = 3, // on read or write - 11
76 kConditionMask = 3 // mask 11
77 };
78
80 class Pool {
81 public:
82 static constexpr const size_t nwatchpoints_per_thread = 4;
83
84 ~Pool() = default;
85
90 static void initialize_instance(const std::vector<const pthread_t *> &threads) {
91 get_instance() = std::shared_ptr<Pool>(new Pool(threads));
92 }
93
95 static std::shared_ptr<Pool> instance() {
96 auto result = get_instance();
97 assert(result && "Pool::instance() called but Pool::initialize_instance() had not been called");
98 return result;
99 }
100
108 Pool &set(void *addr, Size size, Condition cond, const pthread_t *thread) {
109 const auto it = pool_.find(thread);
110 assert(it != pool_.end());
111 // make sure there is no watchpoint for this address already
112 for (auto &watchpt_ptr : it->second) {
113 if (watchpt_ptr && watchpt_ptr->address() == addr) return *this;
114 }
115 // now create a watchpoint
116 for (auto dr = 0; dr != nwatchpoints_per_thread; ++dr) {
117 auto &watchpt_ptr = it->second[dr];
118 if (!watchpt_ptr) {
119 watchpt_ptr =
120 std::make_shared<MemoryWatchpoint_x86_64>(addr, size, cond, static_cast<DebugRegister>(dr), thread);
121 return *this;
122 }
123 }
124 return *this;
125 }
126
131 MemoryWatchpoint_x86_64 *find(void *addr, const pthread_t *thread) {
132 const auto it = pool_.find(thread);
133 assert(it != pool_.end());
134 for (auto &watchpt_ptr : it->second) {
135 if (watchpt_ptr && watchpt_ptr->address() == addr) return watchpt_ptr.get();
136 }
137 return nullptr;
138 }
139
143 Pool &clear(void *addr, const pthread_t *thread) {
144 const auto it = pool_.find(thread);
145 assert(it != pool_.end());
146 for (auto &watchpt_ptr : it->second) {
147 if (watchpt_ptr && watchpt_ptr->address() == addr) {
148 watchpt_ptr.reset();
149 return *this;
150 }
151 }
152 return *this;
153 }
154
155 private:
156 std::unordered_map<const pthread_t *, std::vector<std::shared_ptr<MemoryWatchpoint_x86_64>>> pool_;
157
163 explicit Pool(const std::vector<const pthread_t *> &threads) {
164 for (const auto &thread : threads) {
165 assert(thread != nullptr);
166 pool_[thread].resize(nwatchpoints_per_thread);
167 }
168 }
169
170 static std::shared_ptr<Pool> &get_instance() {
171 static std::shared_ptr<Pool> instance_;
172 return instance_;
173 }
174 };
175
185 MemoryWatchpoint_x86_64(void *addr, Size size, Condition cond, DebugRegister dr, const pthread_t *thread)
186 : addr_(addr), size_(size), cond_(cond), dr_(dr), thread_(thread) {
187 init(true);
188 }
189
190 ~MemoryWatchpoint_x86_64() { init(false); }
191
192 void *address() const { return addr_; }
193 Size size() const { return size_; }
194 Condition condition() const { return cond_; }
195 DebugRegister debug_register() const { return dr_; }
196
197 private:
198 void *addr_;
199 Size size_;
200 Condition cond_;
201 DebugRegister dr_;
202 const pthread_t *thread_;
203
204 inline uint64_t MakeFlags(DebugRegister reg, BreakState state, Condition cond, Size size) {
205 // N.B. each register takes 2 bits in DR7
206 return (state | cond << 16 | size << 24) << (2 * reg);
207 }
208
209 inline uint64_t MakeMask(DebugRegister reg) { return MakeFlags(reg, kBreakStateMask, kConditionMask, kSizeMask); }
210
211 friend class MemoryWatchPool;
212
213 void init(bool create) {
214#if defined(__APPLE__) && defined(__x86_64__)
215 x86_debug_state dr;
216 mach_msg_type_number_t dr_count = x86_DEBUG_STATE_COUNT;
217
218 mach_port_t target_mach_thread = pthread_mach_thread_np(*thread_);
219
220 kern_return_t rc =
221 thread_get_state(target_mach_thread, x86_DEBUG_STATE, reinterpret_cast<thread_state_t>(&dr), &dr_count);
222
223 if (create && rc != KERN_SUCCESS)
224 throw std::runtime_error("MemoryWatchpoint_x86_64::MemoryWatchpoint_x86_64(): thread_get_state failed");
225
226 switch (dr_) {
227 case kDR0:
228 dr.uds.ds64.__dr0 = reinterpret_cast<uint64_t>(addr_);
229 break;
230 case kDR1:
231 dr.uds.ds64.__dr1 = reinterpret_cast<uint64_t>(addr_);
232 break;
233 case kDR2:
234 dr.uds.ds64.__dr2 = reinterpret_cast<uint64_t>(addr_);
235 break;
236 case kDR3:
237 dr.uds.ds64.__dr3 = reinterpret_cast<uint64_t>(addr_);
238 break;
239 }
240
241 dr.uds.ds64.__dr7 &= ~MakeMask(dr_);
242
243 dr.uds.ds64.__dr7 |= MakeFlags(dr_, create ? kEnabledLocally : kDisabled, cond_, size_);
244
245 rc = thread_set_state(target_mach_thread, x86_DEBUG_STATE, reinterpret_cast<thread_state_t>(&dr), dr_count);
246
247 if (create && rc != KERN_SUCCESS)
248 throw std::runtime_error("MemoryWatchpoint_x86_64::MemoryWatchpoint_x86_64(): thread_set_state failed");
249#endif // defined(__APPLE__) && defined(__x86_64__)
250 }
251 };
252
253 } // namespace detail
254
262 void initialize_fpe();
263
271 class Debugger {
272 protected:
273 std::string prefix_;
274 std::string exec_;
275 std::string cmd_;
276 volatile int debugger_ready_;
277
278 bool debug_;
281 bool sleep_;
285
286 void init();
287
288 static std::shared_ptr<Debugger> default_debugger_;
289
296 static void __traceback(const std::string &prefix, const char *reason = nullptr);
297
298 public:
302 explicit Debugger(const char *exec = nullptr);
303 virtual ~Debugger();
304
307 virtual void debug(const char *reason);
315 virtual void traceback(const char *reason);
317 virtual void set_debug_on_signal(int);
319 virtual void set_traceback_on_signal(int);
321 virtual void set_exit_on_signal(int);
325 virtual void set_wait_for_debugger(int);
326
328 virtual void handle(int sig);
330 virtual void release(int sig);
332 virtual void handle_defaults();
333
335 virtual void set_prefix(const char *p);
337 virtual void set_prefix(int p);
338
344 virtual void set_cmd(const char *);
346 virtual void default_cmd();
350 virtual void set_exec(const char *);
351
353 virtual void got_signal(int sig);
354
356 static void set_default_debugger(const std::shared_ptr<Debugger> &);
358 static std::shared_ptr<Debugger> default_debugger();
359
360 private:
362 void resolve_cmd_alias();
363 };
364
365} // namespace ttg
366
367namespace ttg {
368 void launch_debugger(int rank, const char *exec_name, const char *cmd);
369
370 void launch_lldb(int rank = 0, const char *exec_name = "");
371 void launch_gdb(int rank = 0, const char *exec_name = "");
372
373} // namespace ttg
374
375#endif // TTG_UTIL_MISC_BUG_H_
376
377// Local Variables:
378// mode: c++
379// c-file-style: "CLJ"
380// End:
virtual void set_cmd(const char *)
Definition bug.cpp:290
virtual void set_prefix(const char *p)
This sets a prefix which preceeds all messages printing by Debugger.
Definition bug.cpp:258
virtual ~Debugger()
Definition bug.cpp:175
virtual void got_signal(int sig)
Called when signal sig is received. This is mainly for internal use.
Definition bug.cpp:361
int * mysigs_
Definition bug.h:284
static void set_default_debugger(const std::shared_ptr< Debugger > &)
Set the global default debugger. The initial value is null.
Definition bug.cpp:407
static void __traceback(const std::string &prefix, const char *reason=nullptr)
Definition bug.cpp:415
volatile int debugger_ready_
Definition bug.h:276
virtual void handle_defaults()
This calls handle(int) with all of the major signals.
Definition bug.cpp:220
virtual void set_wait_for_debugger(int)
Definition bug.cpp:403
bool debug_
Definition bug.h:278
std::string cmd_
Definition bug.h:275
virtual void traceback(const char *reason)
Definition bug.cpp:413
bool handle_sigint_
Definition bug.h:283
static std::shared_ptr< Debugger > default_debugger()
Return the global default debugger.
Definition bug.cpp:409
std::string exec_
Definition bug.h:274
bool exit_on_signal_
Definition bug.h:280
virtual void default_cmd()
Calls set_cmd with a hopefully suitable default.
Definition bug.cpp:272
virtual void set_exit_on_signal(int)
Turn on or off exit after a signel. The default is on.
Definition bug.cpp:405
void init()
Definition bug.cpp:182
std::string prefix_
Definition bug.h:273
bool traceback_
Definition bug.h:279
virtual void handle(int sig)
The Debugger will be activated when sig is caught.
Definition bug.cpp:205
bool sleep_
Definition bug.h:281
virtual void debug(const char *reason)
Definition bug.cpp:299
virtual void release(int sig)
Reverts the effect of handle(sig) , i.e. the Debugger will not be activated when sig is caught.
Definition bug.cpp:213
static std::shared_ptr< Debugger > default_debugger_
Definition bug.h:288
virtual void set_debug_on_signal(int)
Turn on or off debugging on a signel. The default is on.
Definition bug.cpp:399
bool wait_for_debugger_
Definition bug.h:282
virtual void set_exec(const char *)
Definition bug.cpp:250
virtual void set_traceback_on_signal(int)
Turn on or off traceback on a signel. The default is on.
Definition bug.cpp:401
a singleton pool of MemoryWatchpoint objects
Definition bug.h:80
static std::shared_ptr< Pool > instance()
accesses the unique pool; asserts that the default instance has been initialized by calling initializ...
Definition bug.h:95
Pool & set(void *addr, Size size, Condition cond, const pthread_t *thread)
Definition bug.h:108
MemoryWatchpoint_x86_64 * find(void *addr, const pthread_t *thread)
Definition bug.h:131
static void initialize_instance(const std::vector< const pthread_t * > &threads)
Definition bug.h:90
Pool & clear(void *addr, const pthread_t *thread)
Definition bug.h:143
static constexpr const size_t nwatchpoints_per_thread
Definition bug.h:82
MemoryWatchpoint represents a hardware watchpoint for a memory location Implements a memory watchpoin...
Definition bug.h:51
MemoryWatchpoint_x86_64(void *addr, Size size, Condition cond, DebugRegister dr, const pthread_t *thread)
creates a MemoryWatchpoint watching memory window [addr,addr+size) for condition cond from threads th...
Definition bug.h:185
Condition condition() const
Definition bug.h:194
DebugRegister debug_register() const
Definition bug.h:195
top-level TTG namespace contains runtime-neutral functionality
Definition keymap.h:9
void launch_lldb(int rank, const char *exec_name)
Definition bug.cpp:458
void launch_debugger(int rank, const char *exec_name, const char *cmd)
Definition bug.cpp:446
int rank(World world=default_execution_context())
Definition run.h:127
void initialize_fpe()
Initializes the floating point exceptions.
Definition bug.cpp:52
void launch_gdb(int rank, const char *exec_name)
Definition bug.cpp:459