diff --git a/src/debug_lldb.cc b/src/debug_lldb.cc index 20599e6..303c943 100644 --- a/src/debug_lldb.cc +++ b/src/debug_lldb.cc @@ -10,19 +10,6 @@ #include "process.hpp" #include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; //TODO: remove - extern char **environ; void log(const char *msg, void *) { @@ -112,9 +99,6 @@ std::tuple, std::string, std::vector > Deb void Debug::LLDB::start(const std::string &command, const boost::filesystem::path &path, const std::vector > &breakpoints, - std::function callback, - std::function status_callback, - std::function stop_callback, const std::string &remote_host) { if(!debugger) { lldb::SBDebugger::Initialize(); @@ -136,8 +120,8 @@ void Debug::LLDB::start(const std::string &command, const boost::filesystem::pat auto target=debugger->CreateTarget(executable.c_str()); if(!target.IsValid()) { Terminal::get().async_print("Error (debug): Could not create debug target to: "+executable+'\n', true); - if(callback) - callback(-1); + for(auto &handler: on_exit) + handler.second(-1); return; } @@ -145,8 +129,8 @@ void Debug::LLDB::start(const std::string &command, const boost::filesystem::pat for(auto &breakpoint: breakpoints) { if(!(target.BreakpointCreateByLocation(breakpoint.first.string().c_str(), breakpoint.second)).IsValid()) { Terminal::get().async_print("Error (debug): Could not create breakpoint at: "+breakpoint.first.string()+":"+std::to_string(breakpoint.second)+'\n', true); - if(callback) - callback(-1); + for(auto &handler: on_exit) + handler.second(-1); return; } } @@ -157,8 +141,8 @@ void Debug::LLDB::start(const std::string &command, const boost::filesystem::pat process = std::make_unique(target.ConnectRemote(*listener, connect_string.c_str(), "gdb-remote", error)); if(error.Fail()) { Terminal::get().async_print(std::string("Error (debug): ")+error.GetCString()+'\n', true); - if(callback) - callback(-1); + for(auto &handler: on_exit) + handler.second(-1); return; } lldb::SBEvent event; @@ -199,16 +183,18 @@ void Debug::LLDB::start(const std::string &command, const boost::filesystem::pat } if(error.Fail()) { Terminal::get().async_print(std::string("Error (debug): ")+error.GetCString()+'\n', true); - if(callback) - callback(-1); + for(auto &handler: on_exit) + handler.second(-1); return; } if(debug_thread.joinable()) debug_thread.join(); - debug_thread=std::thread([this, callback, status_callback, stop_callback]() { + for(auto &handler: on_start) + handler.second(*process); + debug_thread=std::thread([this]() { lldb::SBEvent event; while(true) { - std::unique_lock lock(event_mutex); + std::unique_lock lock(mutex); if(listener->GetNextEvent(event)) { if((event.GetType() & lldb::SBProcess::eBroadcastBitStateChanged)>0) { auto state=process->GetStateFromEvent(event); @@ -224,67 +210,17 @@ void Debug::LLDB::start(const std::string &command, const boost::filesystem::pat } } - //Update debug status - lldb::SBStream stream; - event.GetDescription(stream); - std::string event_desc=stream.GetData(); - event_desc.pop_back(); - auto pos=event_desc.rfind(" = "); - if(status_callback && pos!=std::string::npos) { - auto status=event_desc.substr(pos+3); - if(state==lldb::StateType::eStateStopped) { - char buffer[100]; - auto thread=process->GetSelectedThread(); - auto n=thread.GetStopDescription(buffer, 100); - if(n>0) - status+=" ("+std::string(buffer, n<=100?n:100)+")"; - auto line_entry=thread.GetSelectedFrame().GetLineEntry(); - if(line_entry.IsValid()) { - lldb::SBStream stream; - line_entry.GetFileSpec().GetDescription(stream); - status +=" "+boost::filesystem::path(stream.GetData()).filename().string()+":"+std::to_string(line_entry.GetLine()); - } - } - status_callback(status); - } + lock.unlock(); + for(auto &handler: on_event) + handler.second(event); + lock.lock(); - if(state==lldb::StateType::eStateStopped) { - if(stop_callback) { - auto line_entry=process->GetSelectedThread().GetSelectedFrame().GetLineEntry(); - if(line_entry.IsValid()) { - lldb::SBStream stream; - line_entry.GetFileSpec().GetDescription(stream); - auto column=line_entry.GetColumn(); - if(column==0) - column=1; - stop_callback(filesystem::get_normal_path(stream.GetData()), line_entry.GetLine(), column); - } - else - stop_callback("", 0, 0); - } - } - else if(state==lldb::StateType::eStateRunning) { - stop_callback("", 0, 0); - } - else if(state==lldb::StateType::eStateExited) { - auto exit_status=process->GetExitStatus(); - if(callback) - callback(exit_status); - if(status_callback) - status_callback(""); - if(stop_callback) - stop_callback("", 0, 0); - process.reset(); - this->state=lldb::StateType::eStateInvalid; - return; - } - else if(state==lldb::StateType::eStateCrashed) { - if(callback) - callback(-1); - if(status_callback) - status_callback(""); - if(stop_callback) - stop_callback("", 0, 0); + if(state==lldb::StateType::eStateExited || state==lldb::StateType::eStateCrashed) { + auto exit_status=state==lldb::StateType::eStateCrashed?-1:process->GetExitStatus(); + lock.unlock(); + for(auto &handler: on_exit) + handler.second(exit_status); + lock.lock(); process.reset(); this->state=lldb::StateType::eStateInvalid; return; @@ -311,13 +247,13 @@ void Debug::LLDB::start(const std::string &command, const boost::filesystem::pat } void Debug::LLDB::continue_debug() { - std::unique_lock lock(event_mutex); + std::unique_lock lock(mutex); if(state==lldb::StateType::eStateStopped) process->Continue(); } void Debug::LLDB::stop() { - std::unique_lock lock(event_mutex); + std::unique_lock lock(mutex); if(state==lldb::StateType::eStateRunning) { auto error=process->Stop(); if(error.Fail()) @@ -326,7 +262,7 @@ void Debug::LLDB::stop() { } void Debug::LLDB::kill() { - std::unique_lock lock(event_mutex); + std::unique_lock lock(mutex); if(process) { auto error=process->Kill(); if(error.Fail()) @@ -335,21 +271,21 @@ void Debug::LLDB::kill() { } void Debug::LLDB::step_over() { - std::unique_lock lock(event_mutex); + std::unique_lock lock(mutex); if(state==lldb::StateType::eStateStopped) { process->GetSelectedThread().StepOver(); } } void Debug::LLDB::step_into() { - std::unique_lock lock(event_mutex); + std::unique_lock lock(mutex); if(state==lldb::StateType::eStateStopped) { process->GetSelectedThread().StepInto(); } } void Debug::LLDB::step_out() { - std::unique_lock lock(event_mutex); + std::unique_lock lock(mutex); if(state==lldb::StateType::eStateStopped) { process->GetSelectedThread().StepOut(); } @@ -357,7 +293,7 @@ void Debug::LLDB::step_out() { std::pair Debug::LLDB::run_command(const std::string &command) { std::pair command_return; - std::unique_lock lock(event_mutex); + std::unique_lock lock(mutex); if(state==lldb::StateType::eStateStopped || state==lldb::StateType::eStateRunning) { lldb::SBCommandReturnObject command_return_object; debugger->GetCommandInterpreter().HandleCommand(command.c_str(), command_return_object, true); @@ -373,7 +309,7 @@ std::pair Debug::LLDB::run_command(const std::string & std::vector Debug::LLDB::get_backtrace() { std::vector backtrace; - std::unique_lock lock(event_mutex); + std::unique_lock lock(mutex); if(state==lldb::StateType::eStateStopped) { auto thread=process->GetSelectedThread(); for(uint32_t c_f=0;c_f Debug::LLDB::get_backtrace() { std::vector Debug::LLDB::get_variables() { std::vector variables; - std::unique_lock lock(event_mutex); + std::unique_lock lock(mutex); if(state==lldb::StateType::eStateStopped) { for(uint32_t c_t=0;c_tGetNumThreads();c_t++) { auto thread=process->GetThreadAtIndex(c_t); @@ -463,7 +399,7 @@ std::vector Debug::LLDB::get_variables() { } void Debug::LLDB::select_frame(uint32_t frame_index, uint32_t thread_index_id) { - std::unique_lock lock(event_mutex); + std::unique_lock lock(mutex); if(state==lldb::StateType::eStateStopped) { if(thread_index_id!=0) process->SetSelectedThreadByIndexID(thread_index_id); @@ -479,7 +415,7 @@ void Debug::LLDB::cancel() { std::string Debug::LLDB::get_value(const std::string &variable, const boost::filesystem::path &file_path, unsigned int line_nr, unsigned int line_index) { std::string variable_value; - std::unique_lock lock(event_mutex); + std::unique_lock lock(mutex); if(state==lldb::StateType::eStateStopped) { auto frame=process->GetSelectedThread().GetSelectedFrame(); @@ -520,7 +456,7 @@ std::string Debug::LLDB::get_value(const std::string &variable, const boost::fil std::string Debug::LLDB::get_return_value(const boost::filesystem::path &file_path, unsigned int line_nr, unsigned int line_index) { std::string return_value; - std::unique_lock lock(event_mutex); + std::unique_lock lock(mutex); if(state==lldb::StateType::eStateStopped) { auto thread=process->GetSelectedThread(); auto thread_return_value=thread.GetStopReturnValue(); @@ -542,22 +478,22 @@ std::string Debug::LLDB::get_return_value(const boost::filesystem::path &file_pa } bool Debug::LLDB::is_invalid() { - std::unique_lock lock(event_mutex); + std::unique_lock lock(mutex); return state==lldb::StateType::eStateInvalid; } bool Debug::LLDB::is_stopped() { - std::unique_lock lock(event_mutex); + std::unique_lock lock(mutex); return state==lldb::StateType::eStateStopped; } bool Debug::LLDB::is_running() { - std::unique_lock lock(event_mutex); + std::unique_lock lock(mutex); return state==lldb::StateType::eStateRunning; } void Debug::LLDB::add_breakpoint(const boost::filesystem::path &file_path, int line_nr) { - std::unique_lock lock(event_mutex); + std::unique_lock lock(mutex); if(state==lldb::eStateStopped || state==lldb::eStateRunning) { if(!(process->GetTarget().BreakpointCreateByLocation(file_path.string().c_str(), line_nr)).IsValid()) Terminal::get().async_print("Error (debug): Could not create breakpoint at: "+file_path.string()+":"+std::to_string(line_nr)+'\n', true); @@ -565,7 +501,7 @@ void Debug::LLDB::add_breakpoint(const boost::filesystem::path &file_path, int l } void Debug::LLDB::remove_breakpoint(const boost::filesystem::path &file_path, int line_nr, int line_count) { - std::unique_lock lock(event_mutex); + std::unique_lock lock(mutex); if(state==lldb::eStateStopped || state==lldb::eStateRunning) { auto target=process->GetTarget(); for(int line_nr_try=line_nr;line_nr_try lock(event_mutex); + std::unique_lock lock(mutex); if(state==lldb::StateType::eStateRunning) { process->PutSTDIN(buffer.c_str(), buffer.size()); } diff --git a/src/debug_lldb.h b/src/debug_lldb.h index 8c0b28c..ebf07a2 100644 --- a/src/debug_lldb.h +++ b/src/debug_lldb.h @@ -3,9 +3,7 @@ #include #include -#include -#include -#include +#include #include #include #include @@ -41,11 +39,14 @@ namespace Debug { return singleton; } + std::unordered_map> on_start; + std::unordered_map> on_exit; + std::unordered_map> on_event; + + std::mutex mutex; + void start(const std::string &command, const boost::filesystem::path &path="", const std::vector > &breakpoints={}, - std::function callback=nullptr, - std::function status_callback=nullptr, - std::function stop_callback=nullptr, const std::string &remote_host=""); void continue_debug(); //can't use continue as function name void stop(); @@ -81,7 +82,6 @@ namespace Debug { std::thread debug_thread; lldb::StateType state; - std::mutex event_mutex; size_t buffer_size; }; diff --git a/src/project.cc b/src/project.cc index 013a814..66697b6 100644 --- a/src/project.cc +++ b/src/project.cc @@ -447,24 +447,63 @@ void Project::Clang::debug_start() { auto options_it=debug_options.find(project_path->string()); if(options_it!=debug_options.end() && options_it->second.remote_enabled.get_active()) remote_host=options_it->second.remote_host.get_text(); - Debug::LLDB::get().start(*run_arguments, *project_path, breakpoints, [this, run_arguments](int exit_status){ + + Debug::LLDB::get().on_exit["debug_start"]=[this, run_arguments](int exit_status) { debugging=false; Terminal::get().async_print(*run_arguments+" returned: "+std::to_string(exit_status)+'\n'); - }, [this](const std::string &status) { - dispatcher.post([this, status] { - debug_update_status(status); + dispatcher.post([this] { + debug_update_status(""); }); - }, [this](const boost::filesystem::path &file_path, int line_nr, int line_index) { - dispatcher.post([this, file_path, line_nr, line_index] { - Project::debug_stop.first=file_path; - Project::debug_stop.second.first=line_nr-1; - Project::debug_stop.second.second=line_index-1; - + }; + + Debug::LLDB::get().on_event["debug_start"]=[this](const lldb::SBEvent &event) { + std::string status; + boost::filesystem::path stop_path; + unsigned stop_line=0, stop_column=0; + + std::unique_lock lock(Debug::LLDB::get().mutex); + auto process=lldb::SBProcess::GetProcessFromEvent(event); + auto state=lldb::SBProcess::GetStateFromEvent(event); + lldb::SBStream stream; + event.GetDescription(stream); + std::string event_desc=stream.GetData(); + event_desc.pop_back(); + auto pos=event_desc.rfind(" = "); + if(pos!=std::string::npos && pos+30) + status+=" ("+std::string(buffer, n<=100?n:100)+")"; + auto line_entry=thread.GetSelectedFrame().GetLineEntry(); + if(line_entry.IsValid()) { + lldb::SBStream stream; + line_entry.GetFileSpec().GetDescription(stream); + auto line=line_entry.GetLine(); + status +=" "+boost::filesystem::path(stream.GetData()).filename().string()+":"+std::to_string(line); + auto column=line_entry.GetColumn(); + if(column==0) + column=1; + stop_path=filesystem::get_normal_path(stream.GetData()); + stop_line=line-1; + stop_column=column-1; + } + } + + dispatcher.post([this, status=std::move(status), stop_path=std::move(stop_path), stop_line, stop_column] { + debug_update_status(status); + Project::debug_stop.first=stop_path; + Project::debug_stop.second.first=stop_line; + Project::debug_stop.second.second=stop_column; debug_update_stop(); if(auto view=Notebook::get().get_current_view()) view->get_buffer()->place_cursor(view->get_buffer()->get_insert()->get_iter()); }); - }, remote_host); + }; + + Debug::LLDB::get().start(*run_arguments, *project_path, breakpoints, remote_host); }); } }); diff --git a/tests/lldb_test.cc b/tests/lldb_test.cc index 01f5871..e6cc4a5 100644 --- a/tests/lldb_test.cc +++ b/tests/lldb_test.cc @@ -80,15 +80,26 @@ int main() { std::atomic exited(false); int exit_status; std::atomic line_nr(0); + Debug::LLDB::get().on_exit["test"]=[&](int exit_status_) { + exit_status=exit_status_; + exited=true; + }; + Debug::LLDB::get().on_event["test"]=[&](const lldb::SBEvent &event) { + std::unique_lock lock(Debug::LLDB::get().mutex); + auto process=lldb::SBProcess::GetProcessFromEvent(event); + auto state=lldb::SBProcess::GetStateFromEvent(event); + if(state==lldb::StateType::eStateStopped) { + auto line_entry=process.GetSelectedThread().GetSelectedFrame().GetLineEntry(); + if(line_entry.IsValid()) { + lldb::SBStream stream; + line_entry.GetFileSpec().GetDescription(stream); + line_nr=line_entry.GetLine(); + } + } + }; + std::thread debug_thread([&] { - Debug::LLDB::get().start(exec_path.string(), "", breakpoints, [&](int exit_status_){ - exit_status=exit_status_; - exited=true; - }, [](const std::string &status) { - - }, [&](const boost::filesystem::path &file_path, int line_nr_, int line_index) { - line_nr=line_nr_; - }); + Debug::LLDB::get().start(exec_path.string(), "", breakpoints); }); for(;;) {