mirror of https://gitlab.com/cppit/jucipp
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
514 lines
19 KiB
514 lines
19 KiB
|
10 years ago
|
#include "debug_lldb.h"
|
||
|
10 years ago
|
#include <stdio.h>
|
||
|
10 years ago
|
#ifdef __APPLE__
|
||
|
10 years ago
|
#include <stdlib.h>
|
||
|
10 years ago
|
#endif
|
||
|
10 years ago
|
#include <boost/filesystem.hpp>
|
||
|
10 years ago
|
#include <iostream>
|
||
|
|
#include "terminal.h"
|
||
|
10 years ago
|
#include "filesystem.h"
|
||
|
10 years ago
|
#include "process.hpp"
|
||
|
10 years ago
|
#include "config.h"
|
||
|
10 years ago
|
|
||
|
10 years ago
|
#include <lldb/API/SBTarget.h>
|
||
|
|
#include <lldb/API/SBProcess.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 <lldb/API/SBCommandInterpreter.h>
|
||
|
|
#include <lldb/API/SBCommandReturnObject.h>
|
||
|
10 years ago
|
#include <lldb/API/SBBreakpointLocation.h>
|
||
|
10 years ago
|
|
||
|
10 years ago
|
using namespace std; //TODO: remove
|
||
|
10 years ago
|
|
||
|
10 years ago
|
extern char **environ;
|
||
|
10 years ago
|
|
||
|
|
void log(const char *msg, void *) {
|
||
|
10 years ago
|
std::cout << "debugger log: " << msg << std::endl;
|
||
|
10 years ago
|
}
|
||
|
|
|
||
|
10 years ago
|
Debug::LLDB::LLDB(): state(lldb::StateType::eStateInvalid), buffer_size(131072) {
|
||
|
10 years ago
|
#ifdef __APPLE__
|
||
|
10 years ago
|
auto debugserver_path=boost::filesystem::path("/usr/local/opt/llvm/bin/debugserver");
|
||
|
|
if(boost::filesystem::exists(debugserver_path))
|
||
|
|
setenv("LLDB_DEBUGSERVER_PATH", debugserver_path.string().c_str(), 0);
|
||
|
10 years ago
|
#endif
|
||
|
|
}
|
||
|
10 years ago
|
|
||
|
10 years ago
|
void Debug::LLDB::start(const std::string &command, const boost::filesystem::path &path,
|
||
|
10 years ago
|
const std::vector<std::pair<boost::filesystem::path, int> > &breakpoints,
|
||
|
10 years ago
|
std::function<void(int exit_status)> callback,
|
||
|
10 years ago
|
std::function<void(const std::string &status)> status_callback,
|
||
|
10 years ago
|
std::function<void(const boost::filesystem::path &file_path, int line_nr, int line_index)> stop_callback,
|
||
|
10 years ago
|
const std::string &remote_host) {
|
||
|
10 years ago
|
if(!debugger) {
|
||
|
10 years ago
|
lldb::SBDebugger::Initialize();
|
||
|
10 years ago
|
debugger=std::unique_ptr<lldb::SBDebugger>(new lldb::SBDebugger(lldb::SBDebugger::Create(true, log, nullptr)));
|
||
|
|
listener=std::unique_ptr<lldb::SBListener>(new lldb::SBListener("juCi++ lldb listener"));
|
||
|
10 years ago
|
}
|
||
|
10 years ago
|
|
||
|
10 years ago
|
//Create executable string and argument array
|
||
|
|
std::string executable;
|
||
|
|
std::vector<std::string> arguments;
|
||
|
|
size_t start_pos=std::string::npos;
|
||
|
|
bool quote=false;
|
||
|
|
bool double_quote=false;
|
||
|
|
bool symbol=false;
|
||
|
|
for(size_t c=0;c<=command.size();c++) {
|
||
|
|
if(c==command.size() || (!quote && !double_quote && !symbol && command[c]==' ')) {
|
||
|
|
if(c>0 && start_pos!=std::string::npos) {
|
||
|
|
if(executable.empty())
|
||
|
|
executable=filesystem::unescape(command.substr(start_pos, c-start_pos));
|
||
|
|
else
|
||
|
|
arguments.emplace_back(filesystem::unescape(command.substr(start_pos, c-start_pos)));
|
||
|
|
start_pos=std::string::npos;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if(command[c]=='\\' && !quote && !double_quote)
|
||
|
|
symbol=true;
|
||
|
|
else if(symbol)
|
||
|
|
symbol=false;
|
||
|
|
else if(command[c]=='\'' && !double_quote)
|
||
|
|
quote=!quote;
|
||
|
|
else if(command[c]=='"' && !quote)
|
||
|
|
double_quote=!double_quote;
|
||
|
|
if(c<command.size() && start_pos==std::string::npos && command[c]!=' ')
|
||
|
|
start_pos=c;
|
||
|
|
}
|
||
|
|
const char *argv[arguments.size()+1];
|
||
|
|
for(size_t c=0;c<arguments.size();c++)
|
||
|
|
argv[c]=arguments[c].c_str();
|
||
|
|
argv[arguments.size()]=NULL;
|
||
|
|
|
||
|
10 years ago
|
auto target=debugger->CreateTarget(executable.c_str());
|
||
|
10 years ago
|
if(!target.IsValid()) {
|
||
|
10 years ago
|
Terminal::get().async_print("Error (debug): Could not create debug target to: "+executable+'\n', true);
|
||
|
|
if(callback)
|
||
|
|
callback(-1);
|
||
|
10 years ago
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
//Set breakpoints
|
||
|
10 years ago
|
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);
|
||
|
|
return;
|
||
|
10 years ago
|
}
|
||
|
10 years ago
|
}
|
||
|
|
|
||
|
|
lldb::SBError error;
|
||
|
10 years ago
|
if(!remote_host.empty()) {
|
||
|
|
auto connect_string="connect://"+remote_host;
|
||
|
|
process = std::unique_ptr<lldb::SBProcess>(new lldb::SBProcess(target.ConnectRemote(*listener, connect_string.c_str(), "gdb-remote", error)));
|
||
|
10 years ago
|
if(error.Fail()) {
|
||
|
|
Terminal::get().async_print(std::string("Error (debug): ")+error.GetCString()+'\n', true);
|
||
|
|
if(callback)
|
||
|
|
callback(-1);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
lldb::SBEvent event;
|
||
|
|
while(true) {
|
||
|
|
if(listener->GetNextEvent(event)) {
|
||
|
|
if((event.GetType() & lldb::SBProcess::eBroadcastBitStateChanged)>0) {
|
||
|
|
auto state=process->GetStateFromEvent(event);
|
||
|
10 years ago
|
this->state=state;
|
||
|
10 years ago
|
if(state==lldb::StateType::eStateConnected)
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
10 years ago
|
const char *empty_parameter[1];
|
||
|
|
empty_parameter[0]=nullptr;
|
||
|
10 years ago
|
process->RemoteLaunch(argv, empty_parameter, nullptr, nullptr, nullptr, nullptr, lldb::eLaunchFlagNone, false, error);
|
||
|
10 years ago
|
if(!error.Fail())
|
||
|
|
process->Continue();
|
||
|
10 years ago
|
}
|
||
|
10 years ago
|
else
|
||
|
|
process = std::unique_ptr<lldb::SBProcess>(new lldb::SBProcess(target.Launch(*listener, argv, const_cast<const char**>(environ), nullptr, nullptr, nullptr, path.string().c_str(), lldb::eLaunchFlagNone, false, error)));
|
||
|
10 years ago
|
if(error.Fail()) {
|
||
|
|
Terminal::get().async_print(std::string("Error (debug): ")+error.GetCString()+'\n', true);
|
||
|
10 years ago
|
if(callback)
|
||
|
|
callback(-1);
|
||
|
10 years ago
|
return;
|
||
|
|
}
|
||
|
|
if(debug_thread.joinable())
|
||
|
|
debug_thread.join();
|
||
|
10 years ago
|
debug_thread=std::thread([this, callback, status_callback, stop_callback]() {
|
||
|
10 years ago
|
lldb::SBEvent event;
|
||
|
10 years ago
|
while(true) {
|
||
|
10 years ago
|
std::unique_lock<std::mutex> lock(event_mutex);
|
||
|
10 years ago
|
if(listener->GetNextEvent(event)) {
|
||
|
10 years ago
|
if((event.GetType() & lldb::SBProcess::eBroadcastBitStateChanged)>0) {
|
||
|
|
auto state=process->GetStateFromEvent(event);
|
||
|
|
this->state=state;
|
||
|
|
|
||
|
10 years ago
|
if(state==lldb::StateType::eStateStopped) {
|
||
|
|
for(uint32_t c=0;c<process->GetNumThreads();c++) {
|
||
|
|
auto thread=process->GetThreadAtIndex(c);
|
||
|
|
if(thread.GetStopReason()>=2) {
|
||
|
|
process->SetSelectedThreadByIndexID(thread.GetIndexID());
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
//Update debug status
|
||
|
|
lldb::SBStream stream;
|
||
|
|
event.GetDescription(stream);
|
||
|
|
std::string event_desc=stream.GetData();
|
||
|
|
event_desc.pop_back();
|
||
|
|
auto pos=event_desc.rfind(" = ");
|
||
|
10 years ago
|
if(status_callback && pos!=std::string::npos) {
|
||
|
|
auto status=event_desc.substr(pos+3);
|
||
|
|
if(state==lldb::StateType::eStateStopped) {
|
||
|
|
char buffer[100];
|
||
|
10 years ago
|
auto thread=process->GetSelectedThread();
|
||
|
|
auto n=thread.GetStopDescription(buffer, 100);
|
||
|
10 years ago
|
if(n>0)
|
||
|
|
status+=" ("+std::string(buffer, n<=100?n:100)+")";
|
||
|
10 years ago
|
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());
|
||
|
|
}
|
||
|
10 years ago
|
}
|
||
|
|
status_callback(status);
|
||
|
|
}
|
||
|
10 years ago
|
|
||
|
10 years ago
|
if(state==lldb::StateType::eStateStopped) {
|
||
|
|
if(stop_callback) {
|
||
|
10 years ago
|
auto line_entry=process->GetSelectedThread().GetSelectedFrame().GetLineEntry();
|
||
|
10 years ago
|
if(line_entry.IsValid()) {
|
||
|
|
lldb::SBStream stream;
|
||
|
|
line_entry.GetFileSpec().GetDescription(stream);
|
||
|
|
auto column=line_entry.GetColumn();
|
||
|
|
if(column==0)
|
||
|
|
column=1;
|
||
|
10 years ago
|
stop_callback(filesystem::get_canonical_path(stream.GetData()), line_entry.GetLine(), column);
|
||
|
10 years ago
|
}
|
||
|
|
else
|
||
|
|
stop_callback("", 0, 0);
|
||
|
10 years ago
|
}
|
||
|
|
}
|
||
|
10 years ago
|
else if(state==lldb::StateType::eStateRunning) {
|
||
|
|
stop_callback("", 0, 0);
|
||
|
|
}
|
||
|
10 years ago
|
else if(state==lldb::StateType::eStateExited) {
|
||
|
|
auto exit_status=process->GetExitStatus();
|
||
|
|
if(callback)
|
||
|
|
callback(exit_status);
|
||
|
|
if(status_callback)
|
||
|
|
status_callback("");
|
||
|
|
if(stop_callback)
|
||
|
10 years ago
|
stop_callback("", 0, 0);
|
||
|
10 years ago
|
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)
|
||
|
10 years ago
|
stop_callback("", 0, 0);
|
||
|
10 years ago
|
process.reset();
|
||
|
|
this->state=lldb::StateType::eStateInvalid;
|
||
|
|
return;
|
||
|
|
}
|
||
|
10 years ago
|
}
|
||
|
10 years ago
|
if((event.GetType() & lldb::SBProcess::eBroadcastBitSTDOUT)>0) {
|
||
|
|
char buffer[buffer_size];
|
||
|
|
size_t n;
|
||
|
|
while((n=process->GetSTDOUT(buffer, buffer_size))!=0)
|
||
|
|
Terminal::get().async_print(std::string(buffer, n));
|
||
|
10 years ago
|
}
|
||
|
10 years ago
|
//TODO: for some reason stderr is redirected to stdout
|
||
|
|
if((event.GetType() & lldb::SBProcess::eBroadcastBitSTDERR)>0) {
|
||
|
|
char buffer[buffer_size];
|
||
|
|
size_t n;
|
||
|
|
while((n=process->GetSTDERR(buffer, buffer_size))!=0)
|
||
|
|
Terminal::get().async_print(std::string(buffer, n), true);
|
||
|
10 years ago
|
}
|
||
|
|
}
|
||
|
10 years ago
|
lock.unlock();
|
||
|
10 years ago
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||
|
10 years ago
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
10 years ago
|
|
||
|
10 years ago
|
void Debug::LLDB::continue_debug() {
|
||
|
10 years ago
|
std::unique_lock<std::mutex> lock(event_mutex);
|
||
|
10 years ago
|
if(state==lldb::StateType::eStateStopped)
|
||
|
10 years ago
|
process->Continue();
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
void Debug::LLDB::stop() {
|
||
|
10 years ago
|
std::unique_lock<std::mutex> lock(event_mutex);
|
||
|
10 years ago
|
if(state==lldb::StateType::eStateRunning) {
|
||
|
|
auto error=process->Stop();
|
||
|
|
if(error.Fail())
|
||
|
|
Terminal::get().async_print(std::string("Error (debug): ")+error.GetCString()+'\n', true);
|
||
|
10 years ago
|
}
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
void Debug::LLDB::kill() {
|
||
|
10 years ago
|
std::unique_lock<std::mutex> lock(event_mutex);
|
||
|
10 years ago
|
if(process) {
|
||
|
|
auto error=process->Kill();
|
||
|
|
if(error.Fail())
|
||
|
|
Terminal::get().async_print(std::string("Error (debug): ")+error.GetCString()+'\n', true);
|
||
|
10 years ago
|
}
|
||
|
10 years ago
|
}
|
||
|
|
|
||
|
10 years ago
|
void Debug::LLDB::step_over() {
|
||
|
10 years ago
|
std::unique_lock<std::mutex> lock(event_mutex);
|
||
|
10 years ago
|
if(state==lldb::StateType::eStateStopped) {
|
||
|
|
process->GetSelectedThread().StepOver();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
void Debug::LLDB::step_into() {
|
||
|
10 years ago
|
std::unique_lock<std::mutex> lock(event_mutex);
|
||
|
10 years ago
|
if(state==lldb::StateType::eStateStopped) {
|
||
|
|
process->GetSelectedThread().StepInto();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
void Debug::LLDB::step_out() {
|
||
|
10 years ago
|
std::unique_lock<std::mutex> lock(event_mutex);
|
||
|
10 years ago
|
if(state==lldb::StateType::eStateStopped) {
|
||
|
|
process->GetSelectedThread().StepOut();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
std::pair<std::string, std::string> Debug::LLDB::run_command(const std::string &command) {
|
||
|
10 years ago
|
std::pair<std::string, std::string> command_return;
|
||
|
10 years ago
|
std::unique_lock<std::mutex> lock(event_mutex);
|
||
|
10 years ago
|
if(state==lldb::StateType::eStateStopped || state==lldb::StateType::eStateRunning) {
|
||
|
10 years ago
|
lldb::SBCommandReturnObject command_return_object;
|
||
|
10 years ago
|
debugger->GetCommandInterpreter().HandleCommand(command.c_str(), command_return_object, true);
|
||
|
10 years ago
|
command_return.first=command_return_object.GetOutput();
|
||
|
|
command_return.second=command_return_object.GetError();
|
||
|
|
}
|
||
|
|
return command_return;
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
std::vector<Debug::LLDB::Frame> Debug::LLDB::get_backtrace() {
|
||
|
10 years ago
|
std::vector<Frame> backtrace;
|
||
|
10 years ago
|
std::unique_lock<std::mutex> lock(event_mutex);
|
||
|
10 years ago
|
if(state==lldb::StateType::eStateStopped) {
|
||
|
|
auto thread=process->GetSelectedThread();
|
||
|
|
for(uint32_t c_f=0;c_f<thread.GetNumFrames();c_f++) {
|
||
|
|
Frame backtrace_frame;
|
||
|
|
auto frame=thread.GetFrameAtIndex(c_f);
|
||
|
10 years ago
|
|
||
|
|
backtrace_frame.index=c_f;
|
||
|
|
|
||
|
10 years ago
|
if(frame.GetFunctionName()!=NULL)
|
||
|
|
backtrace_frame.function_name=frame.GetFunctionName();
|
||
|
10 years ago
|
|
||
|
|
auto module_filename=frame.GetModule().GetFileSpec().GetFilename();
|
||
|
|
if(module_filename!=NULL) {
|
||
|
|
backtrace_frame.module_filename=module_filename;
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
auto line_entry=frame.GetLineEntry();
|
||
|
|
if(line_entry.IsValid()) {
|
||
|
|
lldb::SBStream stream;
|
||
|
|
line_entry.GetFileSpec().GetDescription(stream);
|
||
|
|
auto column=line_entry.GetColumn();
|
||
|
|
if(column==0)
|
||
|
|
column=1;
|
||
|
10 years ago
|
backtrace_frame.file_path=filesystem::get_canonical_path(stream.GetData());
|
||
|
10 years ago
|
backtrace_frame.line_nr=line_entry.GetLine();
|
||
|
|
backtrace_frame.line_index=column;
|
||
|
|
}
|
||
|
|
backtrace.emplace_back(backtrace_frame);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return backtrace;
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
std::vector<Debug::LLDB::Variable> Debug::LLDB::get_variables() {
|
||
|
|
std::vector<Debug::LLDB::Variable> variables;
|
||
|
10 years ago
|
std::unique_lock<std::mutex> lock(event_mutex);
|
||
|
10 years ago
|
if(state==lldb::StateType::eStateStopped) {
|
||
|
|
for(uint32_t c_t=0;c_t<process->GetNumThreads();c_t++) {
|
||
|
|
auto thread=process->GetThreadAtIndex(c_t);
|
||
|
|
for(uint32_t c_f=0;c_f<thread.GetNumFrames();c_f++) {
|
||
|
|
auto frame=thread.GetFrameAtIndex(c_f);
|
||
|
|
auto values=frame.GetVariables(true, true, true, false);
|
||
|
|
for(uint32_t value_index=0;value_index<values.GetSize();value_index++) {
|
||
|
|
lldb::SBStream stream;
|
||
|
|
auto value=values.GetValueAtIndex(value_index);
|
||
|
|
|
||
|
|
auto declaration=value.GetDeclaration();
|
||
|
|
if(declaration.IsValid()) {
|
||
|
10 years ago
|
Debug::LLDB::Variable variable;
|
||
|
10 years ago
|
|
||
|
10 years ago
|
variable.thread_index_id=thread.GetIndexID();
|
||
|
10 years ago
|
variable.frame_index=c_f;
|
||
|
10 years ago
|
if(value.GetName()!=NULL)
|
||
|
|
variable.name=value.GetName();
|
||
|
10 years ago
|
|
||
|
|
variable.line_nr=declaration.GetLine();
|
||
|
|
variable.line_index=declaration.GetColumn();
|
||
|
|
if(variable.line_index==0)
|
||
|
|
variable.line_index=1;
|
||
|
|
|
||
|
|
auto file_spec=declaration.GetFileSpec();
|
||
|
10 years ago
|
variable.file_path=filesystem::get_canonical_path(file_spec.GetDirectory());
|
||
|
10 years ago
|
variable.file_path/=file_spec.GetFilename();
|
||
|
|
|
||
|
|
value.GetDescription(stream);
|
||
|
|
variable.value=stream.GetData();
|
||
|
|
|
||
|
|
variables.emplace_back(variable);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return variables;
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
void Debug::LLDB::select_frame(uint32_t frame_index, uint32_t thread_index_id) {
|
||
|
10 years ago
|
std::unique_lock<std::mutex> lock(event_mutex);
|
||
|
10 years ago
|
if(state==lldb::StateType::eStateStopped) {
|
||
|
10 years ago
|
if(thread_index_id!=0)
|
||
|
|
process->SetSelectedThreadByIndexID(thread_index_id);
|
||
|
|
process->GetSelectedThread().SetSelectedFrame(frame_index);;
|
||
|
10 years ago
|
}
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
void Debug::LLDB::cancel() {
|
||
|
10 years ago
|
kill();
|
||
|
|
if(debug_thread.joinable())
|
||
|
|
debug_thread.join();
|
||
|
10 years ago
|
}
|
||
|
10 years ago
|
|
||
|
10 years ago
|
std::string Debug::LLDB::get_value(const std::string &variable, const boost::filesystem::path &file_path, unsigned int line_nr, unsigned int line_index) {
|
||
|
10 years ago
|
std::string variable_value;
|
||
|
10 years ago
|
std::unique_lock<std::mutex> lock(event_mutex);
|
||
|
10 years ago
|
if(state==lldb::StateType::eStateStopped) {
|
||
|
10 years ago
|
auto frame=process->GetSelectedThread().GetSelectedFrame();
|
||
|
10 years ago
|
|
||
|
10 years ago
|
auto values=frame.GetVariables(true, true, true, false);
|
||
|
10 years ago
|
//First try to find variable based on name, file and line number
|
||
|
10 years ago
|
for(uint32_t value_index=0;value_index<values.GetSize();value_index++) {
|
||
|
|
lldb::SBStream stream;
|
||
|
|
auto value=values.GetValueAtIndex(value_index);
|
||
|
|
|
||
|
10 years ago
|
if(value.GetName()!=NULL && value.GetName()==variable) {
|
||
|
10 years ago
|
auto declaration=value.GetDeclaration();
|
||
|
|
if(declaration.IsValid()) {
|
||
|
10 years ago
|
if(declaration.GetLine()==line_nr && (declaration.GetColumn()==0 || declaration.GetColumn()==line_index)) {
|
||
|
10 years ago
|
auto file_spec=declaration.GetFileSpec();
|
||
|
10 years ago
|
auto value_decl_path=filesystem::get_canonical_path(file_spec.GetDirectory());
|
||
|
10 years ago
|
value_decl_path/=file_spec.GetFilename();
|
||
|
|
if(value_decl_path==file_path) {
|
||
|
|
value.GetDescription(stream);
|
||
|
|
variable_value=stream.GetData();
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if(variable_value.empty()) {
|
||
|
|
//In case a variable is missing file and line number, only do check on name
|
||
|
10 years ago
|
auto value=frame.GetValueForVariablePath(variable.c_str());
|
||
|
10 years ago
|
if(value.IsValid()) {
|
||
|
10 years ago
|
lldb::SBStream stream;
|
||
|
10 years ago
|
value.GetDescription(stream);
|
||
|
|
variable_value=stream.GetData();
|
||
|
10 years ago
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
10 years ago
|
return variable_value;
|
||
|
10 years ago
|
}
|
||
|
10 years ago
|
|
||
|
10 years ago
|
std::string Debug::LLDB::get_return_value(const boost::filesystem::path &file_path, unsigned int line_nr, unsigned int line_index) {
|
||
|
10 years ago
|
std::string return_value;
|
||
|
10 years ago
|
std::unique_lock<std::mutex> lock(event_mutex);
|
||
|
10 years ago
|
if(state==lldb::StateType::eStateStopped) {
|
||
|
|
auto thread=process->GetSelectedThread();
|
||
|
|
auto thread_return_value=thread.GetStopReturnValue();
|
||
|
|
if(thread_return_value.IsValid()) {
|
||
|
|
auto line_entry=thread.GetSelectedFrame().GetLineEntry();
|
||
|
|
if(line_entry.IsValid()) {
|
||
|
|
lldb::SBStream stream;
|
||
|
|
line_entry.GetFileSpec().GetDescription(stream);
|
||
|
10 years ago
|
if(filesystem::get_canonical_path(stream.GetData())==file_path && line_entry.GetLine()==line_nr &&
|
||
|
10 years ago
|
(line_entry.GetColumn()==0 || line_entry.GetColumn()==line_index)) {
|
||
|
10 years ago
|
lldb::SBStream stream;
|
||
|
|
thread_return_value.GetDescription(stream);
|
||
|
|
return_value=stream.GetData();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return return_value;
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
bool Debug::LLDB::is_invalid() {
|
||
|
10 years ago
|
std::unique_lock<std::mutex> lock(event_mutex);
|
||
|
10 years ago
|
return state==lldb::StateType::eStateInvalid;
|
||
|
10 years ago
|
}
|
||
|
|
|
||
|
10 years ago
|
bool Debug::LLDB::is_stopped() {
|
||
|
10 years ago
|
std::unique_lock<std::mutex> lock(event_mutex);
|
||
|
10 years ago
|
return state==lldb::StateType::eStateStopped;
|
||
|
10 years ago
|
}
|
||
|
|
|
||
|
10 years ago
|
bool Debug::LLDB::is_running() {
|
||
|
10 years ago
|
std::unique_lock<std::mutex> lock(event_mutex);
|
||
|
10 years ago
|
return state==lldb::StateType::eStateRunning;
|
||
|
10 years ago
|
}
|
||
|
|
|
||
|
10 years ago
|
void Debug::LLDB::add_breakpoint(const boost::filesystem::path &file_path, int line_nr) {
|
||
|
10 years ago
|
std::unique_lock<std::mutex> lock(event_mutex);
|
||
|
10 years ago
|
if(state==lldb::eStateStopped || state==lldb::eStateRunning) {
|
||
|
10 years ago
|
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);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
void Debug::LLDB::remove_breakpoint(const boost::filesystem::path &file_path, int line_nr, int line_count) {
|
||
|
10 years ago
|
std::unique_lock<std::mutex> lock(event_mutex);
|
||
|
10 years ago
|
if(state==lldb::eStateStopped || state==lldb::eStateRunning) {
|
||
|
10 years ago
|
auto target=process->GetTarget();
|
||
|
|
for(int line_nr_try=line_nr;line_nr_try<line_count;line_nr_try++) {
|
||
|
|
for(uint32_t b_index=0;b_index<target.GetNumBreakpoints();b_index++) {
|
||
|
|
auto breakpoint=target.GetBreakpointAtIndex(b_index);
|
||
|
|
for(uint32_t l_index=0;l_index<breakpoint.GetNumLocations();l_index++) {
|
||
|
|
auto line_entry=breakpoint.GetLocationAtIndex(l_index).GetAddress().GetLineEntry();
|
||
|
10 years ago
|
if(line_entry.GetLine()==static_cast<uint32_t>(line_nr_try)) {
|
||
|
10 years ago
|
auto file_spec=line_entry.GetFileSpec();
|
||
|
10 years ago
|
auto breakpoint_path=filesystem::get_canonical_path(file_spec.GetDirectory());
|
||
|
10 years ago
|
breakpoint_path/=file_spec.GetFilename();
|
||
|
10 years ago
|
if(breakpoint_path==file_path) {
|
||
|
10 years ago
|
if(!target.BreakpointDelete(breakpoint.GetID()))
|
||
|
10 years ago
|
Terminal::get().async_print("Error (debug): Could not delete breakpoint at: "+file_path.string()+":"+std::to_string(line_nr)+'\n', true);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
10 years ago
|
void Debug::LLDB::write(const std::string &buffer) {
|
||
|
10 years ago
|
std::unique_lock<std::mutex> lock(event_mutex);
|
||
|
10 years ago
|
if(state==lldb::StateType::eStateRunning) {
|
||
|
|
process->PutSTDIN(buffer.c_str(), buffer.size());
|
||
|
|
}
|
||
|
|
}
|