#include "debug.h" #include #include "lldb/API/SBTarget.h" #include "lldb/API/SBProcess.h" #include "lldb/API/SBListener.h" #include "lldb/API/SBEvent.h" #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBThread.h" #include "lldb/API/SBStream.h" #include "lldb/API/SBDeclaration.h" #include //TODO: remove using namespace std; void log(const char *msg, void *) { cout << "debugger log: " << msg << endl; } Debug::Debug(): stopped(false) { lldb::SBDebugger::Initialize(); debugger=lldb::SBDebugger::Create(true, log, nullptr); } void Debug::start(std::shared_ptr > > breakpoints, const boost::filesystem::path &executable, const boost::filesystem::path &path, std::function callback, std::function status_callback, std::function stop_callback) { std::thread debug_thread([this, breakpoints, executable, path, callback, status_callback, stop_callback]() { auto target=debugger.CreateTarget(executable.string().c_str()); auto listener=lldb::SBListener("juCi++ lldb listener"); if(!target.IsValid()) { cerr << "Error: Could not create debug target to: " << executable << endl; //TODO: output to terminal instead return; } for(auto &breakpoint: *breakpoints) { if(!(target.BreakpointCreateByLocation(breakpoint.first.string().c_str(), breakpoint.second)).IsValid()) { cerr << "Error: Could not create breakpoint at: " << breakpoint.first << ":" << breakpoint.second << endl; //TODO: output to terminal instead return; } } lldb::SBError error; process = std::unique_ptr(new lldb::SBProcess(target.Launch(listener, nullptr, nullptr, nullptr, nullptr, nullptr, path.string().c_str(), lldb::eLaunchFlagNone, false, error))); if(error.Fail()) { cerr << "Error (debug): " << error.GetCString() << endl; //TODO: output to terminal instead return; } lldb::SBEvent event; while(true) { if(listener.WaitForEvent(3, event)) { auto state=process->GetStateFromEvent(event); //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) status_callback(event_desc.substr(pos+3)); bool expected=false; if(state==lldb::StateType::eStateStopped && stopped.compare_exchange_strong(expected, true)) { auto line_entry=process->GetSelectedThread().GetSelectedFrame().GetLineEntry(); if(stop_callback) { lldb::SBStream stream; line_entry.GetFileSpec().GetDescription(stream); stop_callback(stream.GetData(), line_entry.GetLine()); } /*lldb::SBStream stream; process->GetSelectedThread().GetDescription(stream); cout << stream.GetData() << endl;*/ for(uint32_t thread_index=0;thread_indexGetNumThreads();thread_index++) { auto thread=process->GetThreadAtIndex(thread_index); for(uint32_t frame_index=0;frame_indexGetDescription(stream); cout << stream.GetData() << endl; stream.Clear(); process->GetSelectedThread().GetSelectedFrame().GetLineEntry().GetDescription(stream); cout << stream.GetData() << endl;*/ /*lldb::SBStream stream; auto value=values.GetValueAtIndex(value_index); cout << value.GetFrame().GetSymbol().GetName() << endl; auto declaration = value.GetDeclaration(); if(declaration.IsValid()) cout << declaration.GetFileSpec().GetFilename() << ":" << declaration.GetLine() << ":" << declaration.GetColumn() << endl; value.GetDescription(stream); cout << " " << stream.GetData() << endl; stream.Clear(); value.GetData().GetDescription(stream); cout << " " << stream.GetData() << endl;*/ } } } } 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); process.reset(); stopped=false; return; } else if(state==lldb::StateType::eStateCrashed) { if(callback) callback(-1); if(status_callback) status_callback(""); if(stop_callback) stop_callback("", 0); process.reset(); stopped=false; return; } } this_thread::sleep_for(std::chrono::milliseconds(200)); } }); debug_thread.detach(); } void Debug::continue_debug() { bool expected=true; if(stopped.compare_exchange_strong(expected, false)) process->Continue(); } void Debug::stop() { auto error=process->Stop(); if(error.Fail()) { cerr << "Error (debug): " << error.GetCString() << endl; //TODO: output to terminal instead return; } } void Debug::kill() { auto error=process->Kill(); if(error.Fail()) { cerr << "Error (debug): " << error.GetCString() << endl; //TODO: output to terminal instead return; } } std::string Debug::get_value(const std::string &variable) { if(stopped) { auto frame=process->GetSelectedThread().GetSelectedFrame(); auto values=frame.GetVariables(false, true, false, false); for(uint32_t value_index=0;value_index