Skip to content

Commit

Permalink
Merge pull request #473 from ValeevGroup/powellsr/fix/debug-attach-ha…
Browse files Browse the repository at this point in the history
…ndling

Powellsr/fix/debug attach handling
  • Loading branch information
evaleev authored Nov 10, 2024
2 parents fe6d848 + b376b06 commit 87664ae
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 66 deletions.
142 changes: 81 additions & 61 deletions src/TiledArray/util/bug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ Debugger::~Debugger() {
for (int i = 0; i < NSIG; i++) {
if (mysigs_[i]) signals[i] = nullptr;
}
delete[] mysigs_;
}

void Debugger::init() {
Expand All @@ -91,7 +90,7 @@ void Debugger::init() {
debug_ = 1;
wait_for_debugger_ = 1;

mysigs_ = new int[NSIG];
mysigs_ = std::make_unique<int[]>(NSIG);
for (int i = 0; i < NSIG; i++) {
mysigs_[i] = 0;
}
Expand All @@ -106,14 +105,14 @@ static void handler(int sig) {
void Debugger::handle(int sig) {
if (sig >= NSIG) return;
typedef void (*handler_type)(int);
signal(sig, (handler_type)handler);
std::signal(sig, (handler_type)handler);
signals[sig] = this;
mysigs_[sig] = 1;
}

void Debugger::release(int sig) {
if (sig >= NSIG) return;
signal(sig, SIG_DFL);
std::signal(sig, SIG_DFL);
signals[sig] = nullptr;
mysigs_[sig] = 0;
}
Expand Down Expand Up @@ -180,25 +179,48 @@ void Debugger::default_cmd() {
}
}

const std::string Debugger::gdb_cmd_ =
"gdb -ex \"set variable debugger_ready_=1\" --pid=$(PID) $(EXEC)";
const std::string Debugger::lldb_cmd_ =
"lldb -p $(PID) -o \"expr debugger_ready_=1\"";

void Debugger::resolve_cmd_alias() {
if (cmd_ == "gdb_xterm") {
cmd_ =
"xterm -title \"$(PREFIX)$(EXEC)\" -e gdb -ex \"set variable "
"debugger_ready_=1\" --pid=$(PID) $(EXEC) &";
cmd_ = "xterm -title \"$(PREFIX)$(EXEC)\" -e " + gdb_cmd_ + " &";
} else if (cmd_ == "lldb_xterm") {
cmd_ =
"xterm -title \"$(PREFIX)$(EXEC)\" -e lldb -p $(PID) -o \"expr "
"debugger_ready_=1\" &";
cmd_ = "xterm -title \"$(PREFIX)$(EXEC)\" -e " + lldb_cmd_ + " &";
}
}

std::string Debugger::replace_macros(std::string str) {
if (!str.empty()) {
int pid = getpid();
std::string::size_type pos;
std::string pidvar("$(PID)");
while ((pos = str.find(pidvar)) != std::string::npos) {
std::string pidstr;
pidstr += std::to_string(pid);
str.replace(pos, pidvar.size(), pidstr);
}
std::string execvar("$(EXEC)");
while ((pos = str.find(execvar)) != std::string::npos) {
str.replace(pos, execvar.size(), exec_);
}
std::string prefixvar("$(PREFIX)");
while ((pos = str.find(prefixvar)) != std::string::npos) {
str.replace(pos, prefixvar.size(), prefix_);
}
}
return str;
}

void Debugger::set_cmd(const char *cmd) {
if (cmd) {
cmd_ = cmd;
resolve_cmd_alias();
} else {
cmd_.resize(0);
}
this->resolve_cmd_alias();
}

void Debugger::debug(const char *reason) {
Expand All @@ -209,58 +231,48 @@ void Debugger::debug(const char *reason) {
std::cout << "no reason given";
std::cout << std::endl;

if (!cmd_.empty()) {
int pid = getpid();
// contruct the command name
std::string cmd = cmd_;
std::string::size_type pos;
std::string pidvar("$(PID)");
while ((pos = cmd.find(pidvar)) != std::string::npos) {
std::string pidstr;
pidstr += std::to_string(pid);
cmd.replace(pos, pidvar.size(), pidstr);
}
std::string execvar("$(EXEC)");
while ((pos = cmd.find(execvar)) != std::string::npos) {
cmd.replace(pos, execvar.size(), exec_);
}
std::string prefixvar("$(PREFIX)");
while ((pos = cmd.find(prefixvar)) != std::string::npos) {
cmd.replace(pos, prefixvar.size(), prefix_);
}

// start the debugger
// before starting the debugger de-register signal handler for SIGTRAP to
// let the debugger take over
release(SIGTRAP);
const std::string cmd = replace_macros(cmd_);
// start the debugger
// before starting the debugger de-register signal handler for SIGTRAP to
// let the debugger take over
release(SIGTRAP);
int system_retvalue = 0;
if (!cmd.empty()) {
std::cout << prefix_ << "Debugger: starting \"" << cmd << "\"" << std::endl;
debugger_ready_ = 0;
const auto system_retvalue = system(cmd.c_str());
if (system_retvalue != 0) { // call to system() failed
std::cout << prefix_
<< "Failed debugger launch: system() did not succeed ..."
<< std::endl;
} else { // call to system() succeeded
// wait until the debugger is ready
if (sleep_) {
std::cout << prefix_ << "Sleeping " << sleep_
<< " seconds to wait for debugger ..." << std::endl;
sleep(sleep_);
}
if (wait_for_debugger_) {
std::string make_ready_message;
if (cmd_.find(" gdb ") != std::string::npos ||
cmd_.find(" lldb ") != std::string::npos) {
make_ready_message =
" configure debugging session (set breakpoints/watchpoints, "
"etc.) then type 'c' to continue running";
}

std::cout << prefix_ << ": waiting for the user ..."
<< make_ready_message << std::endl;
while (!debugger_ready_)
;
system_retvalue = std::system(cmd.c_str());
}
if (system_retvalue != 0) {
std::cout << prefix_
<< "Failed debugger launch: system() did not succeed ..."
<< std::endl;
} else { // call to system() succeeded
// wait until the debugger is ready
if (sleep_) {
std::cout << prefix_ << "Debugger: sleeping " << sleep_
<< " seconds to wait for debugger ..." << std::endl;
sleep(sleep_);
}
if (wait_for_debugger_) {
std::cout << prefix_ << "Debugger: waiting for the user ...";
if (cmd_.find(" gdb ") != std::string::npos ||
cmd_.find(" lldb ") != std::string::npos) {
std::cout
<< " configure debugging session (set breakpoints/watchpoints, "
"etc.) then type 'c' to continue running";
} else if (cmd.empty()) {
std::cout << " attach debugger to process " << std::to_string(getpid())
<< " as follows:" << std::endl
<< prefix_
<< "Debugger: - if using gdb: " << replace_macros(gdb_cmd_)
<< std::endl
<< prefix_
<< "Debugger: - if using lldb: " << replace_macros(lldb_cmd_);
}
std::cout << std::endl;

debugger_ready_ = 0;
while (!debugger_ready_)
;
}
}
}
Expand All @@ -286,6 +298,10 @@ void Debugger::got_signal(int sig) {
else
signame = "UNKNOWN SIGNAL";

for (auto const &action : actions_) {
action();
}
actions_.clear();
if (traceback_) {
traceback(signame);
}
Expand Down Expand Up @@ -355,6 +371,10 @@ void Debugger::__traceback(const std::string &prefix, const char *reason) {
std::cout << result.str(nframes_to_skip) << std::endl;
}

void Debugger::register_prelaunch_action(std::function<void()> action) {
actions_.push_back(action);
}

void create_debugger(const char *cmd, const char *exec, std::int64_t rank) {
auto debugger = std::make_shared<TiledArray::Debugger>();
if (cmd) debugger->set_cmd(cmd);
Expand Down
25 changes: 20 additions & 5 deletions src/TiledArray/util/bug.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include <cassert>
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
Expand Down Expand Up @@ -291,7 +292,7 @@ class Debugger {
bool sleep_;
bool wait_for_debugger_;
bool handle_sigint_;
int *mysigs_;
std::unique_ptr<int[]> mysigs_;

void init();

Expand Down Expand Up @@ -325,11 +326,11 @@ class Debugger {
@param reason optional string specifying the reason for traceback
*/
virtual void traceback(const char *reason);
/// Turn on or off debugging on a signel. The default is on.
/// Turn on or off debugging on a signal. The default is on.
virtual void set_debug_on_signal(int);
/// Turn on or off traceback on a signel. The default is on.
/// Turn on or off traceback on a signal. The default is on.
virtual void set_traceback_on_signal(int);
/// Turn on or off exit after a signel. The default is on.
/// Turn on or off exit after a signal. The default is on.
virtual void set_exit_on_signal(int);
/** Turn on or off running an infinite loop after the debugger is started.
This loop gives the debugger a chance to attack to the process.
Expand Down Expand Up @@ -370,7 +371,7 @@ class Debugger {
virtual void default_cmd();
/** Set the name of the executable for the current process.
It is up to the programmer to set this, even if the Debugger
is initialized with the KeyVal constructor. */
is initialized with the constructor. */
virtual void set_exec(const char *);

/// Called when signal sig is received. This is mainly for internal use.
Expand All @@ -381,9 +382,23 @@ class Debugger {
/// Return the global default debugger.
static std::shared_ptr<Debugger> default_debugger();

/// Register a (one-time) action to be executed when debugger is launched
/// @param action an action to be executed
/// @note multiple actions registered via this will be executed in order of
/// their registration
void register_prelaunch_action(std::function<void()> action);

private:
/// Replaces alias in cmd_ with its full form
void resolve_cmd_alias();
/// Replace macros (\c PID , \c EXEC , \c PREFIX ) in \p cmd by their values
/// \param cmd a string
/// \return processed str
std::string replace_macros(std::string cmd);

static const std::string gdb_cmd_;
static const std::string lldb_cmd_;
std::vector<std::function<void()>> actions_; // prelaunch actions
};

/// Use this to create a Debugger object and make it the default
Expand Down

0 comments on commit 87664ae

Please sign in to comment.