threads and frames

This commit is contained in:
T0b1
2023-06-02 16:54:00 +02:00
parent ac3718b12b
commit ec2eeb10f7
12 changed files with 665 additions and 17 deletions

View File

@@ -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