threads and frames
This commit is contained in:
@@ -112,6 +112,9 @@ void LLDBBackend::handle_state_change(lldb::StateType state)
|
||||
}
|
||||
reg_infos.clear();
|
||||
|
||||
this->check_thread_changes();
|
||||
this->check_frame_changes();
|
||||
|
||||
if (state == StateType::eStateStopped)
|
||||
{
|
||||
this->send_state_change(TargetState::paused,
|
||||
@@ -124,6 +127,8 @@ void LLDBBackend::handle_state_change(lldb::StateType state)
|
||||
{
|
||||
case eStateStopped:
|
||||
this->check_reg_changes();
|
||||
this->check_thread_changes();
|
||||
this->check_frame_changes();
|
||||
this->send_state_change(TargetState::paused, StateChangeReason::unknown);
|
||||
break;
|
||||
case eStateRunning:
|
||||
@@ -259,13 +264,15 @@ void LLDBBackend::dump_threads()
|
||||
case eStopReasonSignal:
|
||||
{
|
||||
auto signal_num = thread.GetStopReasonDataAtIndex(0);
|
||||
printf("Thread %lu: TID: %lu, Stop Reason: Signal: %lu\n", i,
|
||||
thread.GetThreadID(), signal_num);
|
||||
printf("Thread %lu (%s: %s): TID: %lu, Stop Reason: Signal: %lu\n", i,
|
||||
thread.GetFrameAtIndex(0).GetDisplayFunctionName(),
|
||||
thread.GetName(), thread.GetThreadID(), signal_num);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("Thread %lu: TID: %lu, Stop Reason: %lu\n", i,
|
||||
thread.GetThreadID(), stop_reason);
|
||||
printf("Thread %lu (%s: %s): TID: %lu, Stop Reason: %lu\n", i,
|
||||
thread.GetFrameAtIndex(0).GetDisplayFunctionName(),
|
||||
thread.GetName(), thread.GetThreadID(), stop_reason);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,6 +342,30 @@ bool LLDBBackend::step_out()
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLDBBackend::cont()
|
||||
{
|
||||
std::lock_guard g{_data_lock};
|
||||
if (!_process)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: error handling
|
||||
_process->Continue();
|
||||
}
|
||||
|
||||
void LLDBBackend::pause()
|
||||
{
|
||||
std::lock_guard g{_data_lock};
|
||||
if (!_process)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: error handling
|
||||
_process->Stop();
|
||||
}
|
||||
|
||||
void LLDBBackend::check_reg_changes()
|
||||
{
|
||||
auto thread = _process->GetSelectedThread();
|
||||
@@ -405,6 +436,223 @@ void LLDBBackend::check_reg_changes()
|
||||
}
|
||||
}
|
||||
|
||||
void LLDBBackend::check_thread_changes()
|
||||
{
|
||||
using namespace lldb;
|
||||
const auto len = _process->GetNumThreads();
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
if (!_threads.empty())
|
||||
{
|
||||
for (size_t i = 0; i < _threads.size(); ++i)
|
||||
{
|
||||
this->send_thread_removed(BackToFront::ThreadRemoved{i});
|
||||
}
|
||||
_threads.clear();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: work with SBThread::GetIndexID instead of relying
|
||||
// on the index order?
|
||||
uint16_t cache_idx = 0;
|
||||
for (uint32_t i = 0; i < len; ++i)
|
||||
{
|
||||
auto thread = _process->GetThreadAtIndex(i);
|
||||
if (!thread.IsValid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto frame = thread.GetFrameAtIndex(0);
|
||||
if (_threads.size() <= cache_idx)
|
||||
{
|
||||
_threads.push_back(
|
||||
Thread{.id = thread.GetThreadID(),
|
||||
.ip = frame.GetPC(),
|
||||
.name = thread.GetName(),
|
||||
.cur_display_fn = frame.GetDisplayFunctionName()});
|
||||
|
||||
auto &info = _threads.back();
|
||||
switch (thread.GetStopReason())
|
||||
{
|
||||
case eStopReasonBreakpoint:
|
||||
info.stop_reason = ThreadStopReason::breakpoint;
|
||||
info.stop_extra = thread.GetStopReasonDataAtIndex(0);
|
||||
break;
|
||||
case eStopReasonWatchpoint:
|
||||
info.stop_reason = ThreadStopReason::watchpoint;
|
||||
info.stop_extra = thread.GetStopReasonDataAtIndex(0);
|
||||
break;
|
||||
case eStopReasonSignal:
|
||||
info.stop_reason = ThreadStopReason::signal;
|
||||
info.stop_extra = thread.GetStopReasonDataAtIndex(0);
|
||||
break;
|
||||
case eStopReasonException:
|
||||
info.stop_reason = ThreadStopReason::exception;
|
||||
break;
|
||||
default: info.stop_reason = ThreadStopReason::unknown; break;
|
||||
}
|
||||
|
||||
this->send_thread_change(BackToFront::ThreadChange{
|
||||
.id = info.id,
|
||||
.ip = info.ip,
|
||||
.stop_extra = info.stop_extra,
|
||||
.idx = cache_idx,
|
||||
.stop_reason = info.stop_reason,
|
||||
.name = info.name,
|
||||
.cur_display_fn = info.cur_display_fn,
|
||||
});
|
||||
cache_idx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto &cache_entry = _threads[cache_idx];
|
||||
auto change_entry = BackToFront::ThreadChange{};
|
||||
change_entry.idx = cache_idx;
|
||||
auto send_change = false;
|
||||
|
||||
if (thread.GetThreadID() != cache_entry.id)
|
||||
{
|
||||
cache_entry.id = thread.GetThreadID();
|
||||
send_change = true;
|
||||
}
|
||||
if (frame.GetPC() != cache_entry.ip)
|
||||
{
|
||||
cache_entry.ip = frame.GetPC();
|
||||
send_change = true;
|
||||
}
|
||||
auto name = std::string_view{thread.GetName()};
|
||||
if (name != cache_entry.name)
|
||||
{
|
||||
change_entry.name = name;
|
||||
send_change = true;
|
||||
}
|
||||
auto display_name = std::string_view{frame.GetDisplayFunctionName()};
|
||||
if (display_name != cache_entry.cur_display_fn)
|
||||
{
|
||||
change_entry.cur_display_fn = display_name;
|
||||
send_change = true;
|
||||
}
|
||||
|
||||
auto stop_reason = cache_entry.stop_reason;
|
||||
auto stop_extra = cache_entry.stop_extra;
|
||||
switch (thread.GetStopReason())
|
||||
{
|
||||
case eStopReasonBreakpoint:
|
||||
stop_reason = ThreadStopReason::breakpoint;
|
||||
stop_extra = thread.GetStopReasonDataAtIndex(0);
|
||||
break;
|
||||
case eStopReasonWatchpoint:
|
||||
stop_reason = ThreadStopReason::watchpoint;
|
||||
stop_extra = thread.GetStopReasonDataAtIndex(0);
|
||||
break;
|
||||
case eStopReasonSignal:
|
||||
stop_reason = ThreadStopReason::signal;
|
||||
stop_extra = thread.GetStopReasonDataAtIndex(0);
|
||||
break;
|
||||
case eStopReasonException:
|
||||
stop_reason = ThreadStopReason::exception;
|
||||
break;
|
||||
default: stop_reason = ThreadStopReason::unknown; break;
|
||||
}
|
||||
if (stop_reason != cache_entry.stop_reason
|
||||
|| stop_extra != cache_entry.stop_extra)
|
||||
{
|
||||
send_change = true;
|
||||
cache_entry.stop_reason = stop_reason;
|
||||
cache_entry.stop_extra = stop_extra;
|
||||
}
|
||||
|
||||
if (send_change)
|
||||
{
|
||||
change_entry.id = cache_entry.id;
|
||||
change_entry.ip = cache_entry.ip;
|
||||
change_entry.stop_reason = cache_entry.stop_reason;
|
||||
change_entry.stop_extra = cache_entry.stop_extra;
|
||||
this->send_thread_change(std::move(change_entry));
|
||||
}
|
||||
|
||||
cache_idx++;
|
||||
}
|
||||
|
||||
if (_threads.size() > cache_idx)
|
||||
{
|
||||
// here cache_idx == num_threads
|
||||
size_t rem_count = _threads.size() - cache_idx;
|
||||
for (size_t i = 0; i < rem_count; ++i)
|
||||
{
|
||||
this->send_thread_removed(
|
||||
BackToFront::ThreadRemoved{_threads.size() - i - 1});
|
||||
_threads.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLDBBackend::check_frame_changes()
|
||||
{
|
||||
using namespace lldb;
|
||||
auto thread = _process->GetSelectedThread();
|
||||
if (!thread.IsValid())
|
||||
{
|
||||
// TODO: cleanup
|
||||
return;
|
||||
}
|
||||
|
||||
size_t len = thread.GetNumFrames();
|
||||
uint16_t cache_idx = 0;
|
||||
size_t selected_idx = 0;
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
{
|
||||
auto frame = thread.GetFrameAtIndex(i);
|
||||
if (!frame.IsValid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (thread.GetSelectedFrame().IsEqual(frame))
|
||||
{
|
||||
selected_idx = cache_idx;
|
||||
}
|
||||
|
||||
auto ip = frame.GetPC();
|
||||
auto name = std::string_view{frame.GetDisplayFunctionName()};
|
||||
if (_frames.size() <= cache_idx)
|
||||
{
|
||||
_frames.push_back(Frame{
|
||||
.ip = ip,
|
||||
.display_name = std::string{name},
|
||||
});
|
||||
|
||||
this->send_frame_changed(BackToFront::FrameChanged{
|
||||
.ip = ip, .idx = cache_idx, .display_name = std::string{name}});
|
||||
cache_idx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto &cache_entry = _frames[cache_idx];
|
||||
if (cache_entry.ip != ip || cache_entry.display_name != name)
|
||||
{
|
||||
this->send_frame_changed(BackToFront::FrameChanged{
|
||||
.ip = ip, .idx = cache_idx, .display_name = std::string{name}});
|
||||
}
|
||||
cache_idx++;
|
||||
}
|
||||
|
||||
if (_frames.size() > cache_idx)
|
||||
{
|
||||
// here cache_idx == num_frames
|
||||
size_t rem_count = _frames.size() - cache_idx;
|
||||
for (size_t i = 0; i < rem_count; ++i)
|
||||
{
|
||||
this->send_frame_removed(
|
||||
BackToFront::FrameRemoved{_frames.size() - i - 1});
|
||||
_frames.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Reg output for x64
|
||||
Got register set General Purpose Registers
|
||||
|
||||
Reference in New Issue
Block a user