threads and frames
This commit is contained in:
@@ -24,4 +24,30 @@ void Backend::send_reg_change(BackToFront::RegsChanged &&info)
|
|||||||
auto msg = std::make_unique<BackToFront::Msg>(
|
auto msg = std::make_unique<BackToFront::Msg>(
|
||||||
BackToFront::MsgType::regs_changed, std::move(info));
|
BackToFront::MsgType::regs_changed, std::move(info));
|
||||||
this->send_msg(std::move(msg));
|
this->send_msg(std::move(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::send_thread_change(BackToFront::ThreadChange &&info)
|
||||||
|
{
|
||||||
|
auto msg = std::make_unique<BackToFront::Msg>(
|
||||||
|
BackToFront::MsgType::thread_changed, std::move(info));
|
||||||
|
this->send_msg(std::move(msg));
|
||||||
|
}
|
||||||
|
void Backend::send_thread_removed(BackToFront::ThreadRemoved &&info)
|
||||||
|
{
|
||||||
|
auto msg = std::make_unique<BackToFront::Msg>(
|
||||||
|
BackToFront::MsgType::thread_removed, std::move(info));
|
||||||
|
this->send_msg(std::move(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::send_frame_changed(BackToFront::FrameChanged &&info)
|
||||||
|
{
|
||||||
|
auto msg = std::make_unique<BackToFront::Msg>(
|
||||||
|
BackToFront::MsgType::frame_changed, std::move(info));
|
||||||
|
this->send_msg(std::move(msg));
|
||||||
|
}
|
||||||
|
void Backend::send_frame_removed(BackToFront::FrameRemoved &&info)
|
||||||
|
{
|
||||||
|
auto msg = std::make_unique<BackToFront::Msg>(
|
||||||
|
BackToFront::MsgType::frame_removed, std::move(info));
|
||||||
|
this->send_msg(std::move(msg));
|
||||||
}
|
}
|
||||||
@@ -23,6 +23,9 @@ namespace dbgui::backend
|
|||||||
virtual bool step_over() = 0;
|
virtual bool step_over() = 0;
|
||||||
virtual bool step_out() = 0;
|
virtual bool step_out() = 0;
|
||||||
|
|
||||||
|
virtual void cont() = 0;
|
||||||
|
virtual void pause() = 0;
|
||||||
|
|
||||||
auto retrieve_msg_for_frontend()
|
auto retrieve_msg_for_frontend()
|
||||||
-> std::optional<std::unique_ptr<BackToFront::Msg>>
|
-> std::optional<std::unique_ptr<BackToFront::Msg>>
|
||||||
{
|
{
|
||||||
@@ -48,6 +51,10 @@ namespace dbgui::backend
|
|||||||
void send_state_change(TargetState new_state, StateChangeReason reason);
|
void send_state_change(TargetState new_state, StateChangeReason reason);
|
||||||
void send_proc_info(BackToFront::InitialProcessInfo &&);
|
void send_proc_info(BackToFront::InitialProcessInfo &&);
|
||||||
void send_reg_change(BackToFront::RegsChanged &&);
|
void send_reg_change(BackToFront::RegsChanged &&);
|
||||||
|
void send_thread_change(BackToFront::ThreadChange &&);
|
||||||
|
void send_thread_removed(BackToFront::ThreadRemoved &&);
|
||||||
|
void send_frame_changed(BackToFront::FrameChanged &&);
|
||||||
|
void send_frame_removed(BackToFront::FrameRemoved &&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::mutex _back_front_msg_mutex;
|
std::mutex _back_front_msg_mutex;
|
||||||
|
|||||||
@@ -112,6 +112,9 @@ void LLDBBackend::handle_state_change(lldb::StateType state)
|
|||||||
}
|
}
|
||||||
reg_infos.clear();
|
reg_infos.clear();
|
||||||
|
|
||||||
|
this->check_thread_changes();
|
||||||
|
this->check_frame_changes();
|
||||||
|
|
||||||
if (state == StateType::eStateStopped)
|
if (state == StateType::eStateStopped)
|
||||||
{
|
{
|
||||||
this->send_state_change(TargetState::paused,
|
this->send_state_change(TargetState::paused,
|
||||||
@@ -124,6 +127,8 @@ void LLDBBackend::handle_state_change(lldb::StateType state)
|
|||||||
{
|
{
|
||||||
case eStateStopped:
|
case eStateStopped:
|
||||||
this->check_reg_changes();
|
this->check_reg_changes();
|
||||||
|
this->check_thread_changes();
|
||||||
|
this->check_frame_changes();
|
||||||
this->send_state_change(TargetState::paused, StateChangeReason::unknown);
|
this->send_state_change(TargetState::paused, StateChangeReason::unknown);
|
||||||
break;
|
break;
|
||||||
case eStateRunning:
|
case eStateRunning:
|
||||||
@@ -259,13 +264,15 @@ void LLDBBackend::dump_threads()
|
|||||||
case eStopReasonSignal:
|
case eStopReasonSignal:
|
||||||
{
|
{
|
||||||
auto signal_num = thread.GetStopReasonDataAtIndex(0);
|
auto signal_num = thread.GetStopReasonDataAtIndex(0);
|
||||||
printf("Thread %lu: TID: %lu, Stop Reason: Signal: %lu\n", i,
|
printf("Thread %lu (%s: %s): TID: %lu, Stop Reason: Signal: %lu\n", i,
|
||||||
thread.GetThreadID(), signal_num);
|
thread.GetFrameAtIndex(0).GetDisplayFunctionName(),
|
||||||
|
thread.GetName(), thread.GetThreadID(), signal_num);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
printf("Thread %lu: TID: %lu, Stop Reason: %lu\n", i,
|
printf("Thread %lu (%s: %s): TID: %lu, Stop Reason: %lu\n", i,
|
||||||
thread.GetThreadID(), stop_reason);
|
thread.GetFrameAtIndex(0).GetDisplayFunctionName(),
|
||||||
|
thread.GetName(), thread.GetThreadID(), stop_reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,6 +342,30 @@ bool LLDBBackend::step_out()
|
|||||||
return false;
|
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()
|
void LLDBBackend::check_reg_changes()
|
||||||
{
|
{
|
||||||
auto thread = _process->GetSelectedThread();
|
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
|
Reg output for x64
|
||||||
Got register set General Purpose Registers
|
Got register set General Purpose Registers
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace dbgui::backend
|
|||||||
{
|
{
|
||||||
struct RegSet
|
struct RegSet
|
||||||
{
|
{
|
||||||
std::string set_name;
|
std::string set_name;
|
||||||
// map from debugger reg idx to frontend reg idx
|
// map from debugger reg idx to frontend reg idx
|
||||||
// std::vector<uint16_t> idx_map;
|
// std::vector<uint16_t> idx_map;
|
||||||
std::vector<const char *> names;
|
std::vector<const char *> names;
|
||||||
@@ -22,6 +22,22 @@ namespace dbgui::backend
|
|||||||
std::vector<std::vector<uint8_t>> values;
|
std::vector<std::vector<uint8_t>> values;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Thread
|
||||||
|
{
|
||||||
|
uint64_t id;
|
||||||
|
uint64_t ip;
|
||||||
|
uint64_t stop_extra;
|
||||||
|
ThreadStopReason stop_reason;
|
||||||
|
std::string name;
|
||||||
|
std::string cur_display_fn;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Frame
|
||||||
|
{
|
||||||
|
uint64_t ip;
|
||||||
|
std::string display_name;
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: source_init_file: false
|
// TODO: source_init_file: false
|
||||||
LLDBBackend(std::string filename);
|
LLDBBackend(std::string filename);
|
||||||
virtual ~LLDBBackend();
|
virtual ~LLDBBackend();
|
||||||
@@ -32,6 +48,9 @@ namespace dbgui::backend
|
|||||||
bool step_over() override;
|
bool step_over() override;
|
||||||
bool step_out() override;
|
bool step_out() override;
|
||||||
|
|
||||||
|
void cont() override;
|
||||||
|
void pause() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void run_msg_loop();
|
void run_msg_loop();
|
||||||
void wait_for_debug_events();
|
void wait_for_debug_events();
|
||||||
@@ -42,6 +61,8 @@ namespace dbgui::backend
|
|||||||
std::vector<BackToFront::RegsChanged> &);
|
std::vector<BackToFront::RegsChanged> &);
|
||||||
void dump_threads();
|
void dump_threads();
|
||||||
void check_reg_changes();
|
void check_reg_changes();
|
||||||
|
void check_thread_changes();
|
||||||
|
void check_frame_changes();
|
||||||
|
|
||||||
std::string _filename;
|
std::string _filename;
|
||||||
lldb::SBDebugger _instance;
|
lldb::SBDebugger _instance;
|
||||||
@@ -55,5 +76,8 @@ namespace dbgui::backend
|
|||||||
bool _first_run = true;
|
bool _first_run = true;
|
||||||
TargetState _state = TargetState::stopped;
|
TargetState _state = TargetState::stopped;
|
||||||
std::vector<RegSet> _reg_sets = {};
|
std::vector<RegSet> _reg_sets = {};
|
||||||
|
std::vector<Thread> _threads = {};
|
||||||
|
std::vector<Frame> _frames = {};
|
||||||
|
uint16_t _selected_frame = 0;
|
||||||
};
|
};
|
||||||
} // namespace dbgui::backend
|
} // namespace dbgui::backend
|
||||||
@@ -15,6 +15,16 @@ Target::Target(std::string filename)
|
|||||||
backend = std::make_shared<backend::LLDBBackend>(this->filename.c_str());
|
backend = std::make_shared<backend::LLDBBackend>(this->filename.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Frontend::Frontend()
|
||||||
|
{
|
||||||
|
_open_popup_name_buf.resize(512);
|
||||||
|
const char *str = "/home/klee/projects/dbgui/tmp/main";
|
||||||
|
std::memcpy(_open_popup_name_buf.data(), str, strlen(str) + 1);
|
||||||
|
_windows.push_back(Window::create_regs(window_id++));
|
||||||
|
_windows.push_back(Window::create_threads(window_id++));
|
||||||
|
_windows.push_back(Window::create_frames(window_id++));
|
||||||
|
}
|
||||||
|
|
||||||
void Frontend::run_frame()
|
void Frontend::run_frame()
|
||||||
{
|
{
|
||||||
this->handle_msgs();
|
this->handle_msgs();
|
||||||
@@ -38,6 +48,12 @@ void Frontend::run_frame()
|
|||||||
|
|
||||||
if (ImGui::Begin("Test", nullptr, win_flags))
|
if (ImGui::Begin("Test", nullptr, win_flags))
|
||||||
{
|
{
|
||||||
|
// TODO: if we just do SetNextWindowDockID in each of the windows
|
||||||
|
// this seems to crash once the first window is docked to it?
|
||||||
|
// so some id change is necessary
|
||||||
|
// so we should try to figure out what the dock id for the "topleft"
|
||||||
|
// window is or whatever and use that for new windows
|
||||||
|
// spawning them floating looks bad (and might reuse saved positions)
|
||||||
this->dock_id = ImGui::GetID("MyDockSpace");
|
this->dock_id = ImGui::GetID("MyDockSpace");
|
||||||
ImGui::DockSpace(this->dock_id, ImVec2{0, 0},
|
ImGui::DockSpace(this->dock_id, ImVec2{0, 0},
|
||||||
ImGuiDockNodeFlags_PassthruCentralNode);
|
ImGuiDockNodeFlags_PassthruCentralNode);
|
||||||
@@ -45,6 +61,7 @@ void Frontend::run_frame()
|
|||||||
for (auto &window : _windows)
|
for (auto &window : _windows)
|
||||||
{
|
{
|
||||||
window.draw(*this);
|
window.draw(*this);
|
||||||
|
//this->dock_id = ImGui::GetWindowDockID();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
@@ -104,8 +121,19 @@ void Frontend::draw_header()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case stopped: ImGui::Button("Run"); break;
|
case stopped: ImGui::Button("Run"); break;
|
||||||
case paused: ImGui::Button("Continue"); break;
|
case paused:
|
||||||
case running: ImGui::Button("Pause"); break;
|
if (ImGui::Button("Continue"))
|
||||||
|
{
|
||||||
|
this->target->backend->cont();
|
||||||
|
// TODO: mark target already as running to prevent input?
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case running:
|
||||||
|
if (ImGui::Button("Pause"))
|
||||||
|
{
|
||||||
|
this->target->backend->pause();
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
@@ -244,6 +272,22 @@ void Frontend::handle_msgs()
|
|||||||
case regs_changed:
|
case regs_changed:
|
||||||
this->handle_reg_change(std::get<BackToFront::RegsChanged>(msg->data));
|
this->handle_reg_change(std::get<BackToFront::RegsChanged>(msg->data));
|
||||||
break;
|
break;
|
||||||
|
case thread_changed:
|
||||||
|
this->handle_thread_change(
|
||||||
|
std::move(std::get<BackToFront::ThreadChange>(msg->data)));
|
||||||
|
break;
|
||||||
|
case thread_removed:
|
||||||
|
this->handle_thread_remove(
|
||||||
|
std::get<BackToFront::ThreadRemoved>(msg->data));
|
||||||
|
break;
|
||||||
|
case frame_changed:
|
||||||
|
this->handle_frame_change(
|
||||||
|
std::move(std::get<BackToFront::FrameChanged>(msg->data)));
|
||||||
|
break;
|
||||||
|
case frame_removed:
|
||||||
|
this->handle_frame_remove(
|
||||||
|
std::get<BackToFront::FrameRemoved>(msg->data));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -290,4 +334,90 @@ void Frontend::handle_reg_change(const BackToFront::RegsChanged &info)
|
|||||||
// TODO: opt for uint64?
|
// TODO: opt for uint64?
|
||||||
std::copy(val.begin(), val.end(), reg.bytes.begin());
|
std::copy(val.begin(), val.end(), reg.bytes.begin());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Frontend::handle_thread_remove(const BackToFront::ThreadRemoved &info)
|
||||||
|
{
|
||||||
|
auto &threads = this->target->threads;
|
||||||
|
if (threads.size() >= info.idx)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
threads[info.idx] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void Frontend::handle_thread_change(BackToFront::ThreadChange &&info)
|
||||||
|
{
|
||||||
|
auto &threads = this->target->threads;
|
||||||
|
if (threads.size() <= info.idx)
|
||||||
|
{
|
||||||
|
threads.resize(info.idx + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &thread = threads[info.idx];
|
||||||
|
if (!thread)
|
||||||
|
{
|
||||||
|
thread = Target::Thread{
|
||||||
|
.id = info.id,
|
||||||
|
.ip = info.ip,
|
||||||
|
.stop_extra = info.stop_extra,
|
||||||
|
.stop_reason = info.stop_reason,
|
||||||
|
};
|
||||||
|
if (info.name)
|
||||||
|
{
|
||||||
|
thread->name = std::move(*info.name);
|
||||||
|
}
|
||||||
|
if (info.cur_display_fn)
|
||||||
|
{
|
||||||
|
thread->cur_display_fn = std::move(*info.cur_display_fn);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread->id = info.id;
|
||||||
|
thread->ip = info.ip;
|
||||||
|
thread->stop_reason = info.stop_reason;
|
||||||
|
thread->stop_extra = info.stop_extra;
|
||||||
|
if (info.name)
|
||||||
|
{
|
||||||
|
thread->name = std::move(*info.name);
|
||||||
|
}
|
||||||
|
if (info.cur_display_fn)
|
||||||
|
{
|
||||||
|
thread->cur_display_fn = std::move(*info.cur_display_fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Frontend::handle_frame_remove(const BackToFront::FrameRemoved &info)
|
||||||
|
{
|
||||||
|
auto &frames = this->target->frames;
|
||||||
|
if (frames.size() >= info.idx)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
frames[info.idx] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void Frontend::handle_frame_change(BackToFront::FrameChanged &&info)
|
||||||
|
{
|
||||||
|
auto &frames = this->target->frames;
|
||||||
|
if (frames.size() <= info.idx)
|
||||||
|
{
|
||||||
|
frames.resize(info.idx + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &frame = frames[info.idx];
|
||||||
|
if (!frame)
|
||||||
|
{
|
||||||
|
frame = Target::Frame{
|
||||||
|
.ip = info.ip,
|
||||||
|
.display_name = info.display_name,
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->ip = info.ip;
|
||||||
|
frame->display_name = info.display_name;
|
||||||
}
|
}
|
||||||
@@ -17,12 +17,7 @@ namespace dbgui::frontend
|
|||||||
|
|
||||||
struct Frontend
|
struct Frontend
|
||||||
{
|
{
|
||||||
Frontend()
|
Frontend();
|
||||||
{
|
|
||||||
_open_popup_name_buf.resize(512);
|
|
||||||
const char *str = "/home/klee/projects/dbgui/tmp/main";
|
|
||||||
std::memcpy(_open_popup_name_buf.data(), str, strlen(str) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void run_frame();
|
void run_frame();
|
||||||
|
|
||||||
@@ -39,6 +34,10 @@ namespace dbgui::frontend
|
|||||||
void handle_state_change(const BackToFront::StateChange &);
|
void handle_state_change(const BackToFront::StateChange &);
|
||||||
void handle_proc_info(BackToFront::InitialProcessInfo &&);
|
void handle_proc_info(BackToFront::InitialProcessInfo &&);
|
||||||
void handle_reg_change(const BackToFront::RegsChanged &);
|
void handle_reg_change(const BackToFront::RegsChanged &);
|
||||||
|
void handle_thread_remove(const BackToFront::ThreadRemoved &);
|
||||||
|
void handle_thread_change(BackToFront::ThreadChange &&);
|
||||||
|
void handle_frame_remove(const BackToFront::FrameRemoved &);
|
||||||
|
void handle_frame_change(BackToFront::FrameChanged &&);
|
||||||
|
|
||||||
bool _draw_second = false;
|
bool _draw_second = false;
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,22 @@ namespace dbgui::frontend
|
|||||||
std::vector<Reg> regs;
|
std::vector<Reg> regs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Thread
|
||||||
|
{
|
||||||
|
uint64_t id;
|
||||||
|
uint64_t ip;
|
||||||
|
uint64_t stop_extra;
|
||||||
|
ThreadStopReason stop_reason;
|
||||||
|
std::string name;
|
||||||
|
std::string cur_display_fn;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Frame
|
||||||
|
{
|
||||||
|
uint64_t ip;
|
||||||
|
std::string display_name;
|
||||||
|
};
|
||||||
|
|
||||||
Target(std::string filename);
|
Target(std::string filename);
|
||||||
|
|
||||||
TargetState state = TargetState::stopped;
|
TargetState state = TargetState::stopped;
|
||||||
@@ -33,6 +49,8 @@ namespace dbgui::frontend
|
|||||||
Arch arch;
|
Arch arch;
|
||||||
|
|
||||||
std::vector<RegSet> reg_sets;
|
std::vector<RegSet> reg_sets;
|
||||||
|
std::vector<std::optional<Thread>> threads;
|
||||||
|
std::vector<std::optional<Frame>> frames;
|
||||||
|
|
||||||
std::shared_ptr<backend::Backend> backend = nullptr;
|
std::shared_ptr<backend::Backend> backend = nullptr;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ void Window::draw(const Frontend &frontend)
|
|||||||
using enum WindowType;
|
using enum WindowType;
|
||||||
|
|
||||||
case regs: std::get<RegWindow>(this->data).draw(frontend); break;
|
case regs: std::get<RegWindow>(this->data).draw(frontend); break;
|
||||||
|
case threads: std::get<ThreadWindow>(this->data).draw(frontend); break;
|
||||||
|
case frames: std::get<FrameWindow>(this->data).draw(frontend); break;
|
||||||
default: printf("Unhandled window draw: %u\n", this->type); exit(1);
|
default: printf("Unhandled window draw: %u\n", this->type); exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,9 +26,27 @@ Window Window::create_regs(size_t id)
|
|||||||
.data = RegWindow{.id = id_str, .open = true}};
|
.data = RegWindow{.id = id_str, .open = true}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Window Window::create_threads(size_t id)
|
||||||
|
{
|
||||||
|
auto id_str = std::string{"Threads##"};
|
||||||
|
id_str.append(std::to_string(id));
|
||||||
|
|
||||||
|
return Window{.type = WindowType::threads,
|
||||||
|
.data = ThreadWindow{.id = id_str, .open = true}};
|
||||||
|
}
|
||||||
|
|
||||||
|
Window Window::create_frames(size_t id)
|
||||||
|
{
|
||||||
|
auto id_str = std::string{"Frames##"};
|
||||||
|
id_str.append(std::to_string(id));
|
||||||
|
|
||||||
|
return Window{.type = WindowType::frames,
|
||||||
|
.data = FrameWindow{.id = id_str, .open = true}};
|
||||||
|
}
|
||||||
|
|
||||||
void RegWindow::draw(const Frontend &frontend)
|
void RegWindow::draw(const Frontend &frontend)
|
||||||
{
|
{
|
||||||
ImGui::SetNextWindowDockID(frontend.dock_id, ImGuiCond_Appearing);
|
//ImGui::SetNextWindowDockID(frontend.dock_id, ImGuiCond_Appearing);
|
||||||
if (!ImGui::Begin(this->id.c_str()))
|
if (!ImGui::Begin(this->id.c_str()))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -97,5 +117,112 @@ void RegWindow::draw(const Frontend &frontend)
|
|||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadWindow::draw(const Frontend &frontend)
|
||||||
|
{
|
||||||
|
//ImGui::SetNextWindowDockID(frontend.dock_id, ImGuiCond_Appearing);
|
||||||
|
if (!ImGui::Begin(this->id.c_str()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!frontend.target)
|
||||||
|
{
|
||||||
|
ImGui::End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginTable("table", 3,
|
||||||
|
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
|
||||||
|
{
|
||||||
|
ImGui::TableSetupColumn("ID");
|
||||||
|
ImGui::TableSetupColumn("Name");
|
||||||
|
ImGui::TableSetupColumn("Location");
|
||||||
|
ImGui::TableHeadersRow();
|
||||||
|
|
||||||
|
const auto &threads = frontend.target->threads;
|
||||||
|
char buf[32];
|
||||||
|
for (size_t idx = 0; idx < threads.size(); ++idx)
|
||||||
|
{
|
||||||
|
const auto &thread = threads[idx];
|
||||||
|
if (!thread)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
|
||||||
|
std::snprintf(buf, sizeof(buf), "%lu", thread->id);
|
||||||
|
ImGui::Text(buf);
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
ImGui::Text(thread->name.c_str());
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
if (thread->cur_display_fn != "")
|
||||||
|
{
|
||||||
|
ImGui::Text(thread->cur_display_fn.c_str());
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
std::snprintf(buf, sizeof(buf), "%lX", thread->ip);
|
||||||
|
ImGui::Text(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameWindow::draw(const Frontend &frontend)
|
||||||
|
{
|
||||||
|
//ImGui::SetNextWindowDockID(frontend.dock_id, ImGuiCond_Appearing);
|
||||||
|
if (!ImGui::Begin(this->id.c_str()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!frontend.target)
|
||||||
|
{
|
||||||
|
ImGui::End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginTable("table", 1,
|
||||||
|
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
|
||||||
|
{
|
||||||
|
ImGui::TableSetupColumn("Location");
|
||||||
|
ImGui::TableHeadersRow();
|
||||||
|
|
||||||
|
const auto &frames = frontend.target->frames;
|
||||||
|
char buf[32];
|
||||||
|
for (size_t idx = 0; idx < frames.size(); ++idx)
|
||||||
|
{
|
||||||
|
const auto &frame = frames[idx];
|
||||||
|
if (!frame)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
|
||||||
|
if (frame->display_name != "")
|
||||||
|
{
|
||||||
|
ImGui::Text(frame->display_name.c_str());
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
std::snprintf(buf, sizeof(buf), "%lX", frame->ip);
|
||||||
|
ImGui::Text(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ namespace dbgui::frontend
|
|||||||
source,
|
source,
|
||||||
memory,
|
memory,
|
||||||
variables,
|
variables,
|
||||||
stack,
|
frames,
|
||||||
threads,
|
threads,
|
||||||
disassembly,
|
disassembly,
|
||||||
};
|
};
|
||||||
@@ -55,13 +55,31 @@ namespace dbgui::frontend
|
|||||||
bool open;
|
bool open;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ThreadWindow
|
||||||
|
{
|
||||||
|
void draw(const Frontend &);
|
||||||
|
|
||||||
|
std::string id;
|
||||||
|
bool open;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FrameWindow
|
||||||
|
{
|
||||||
|
void draw(const Frontend &);
|
||||||
|
|
||||||
|
std::string id;
|
||||||
|
bool open;
|
||||||
|
};
|
||||||
|
|
||||||
struct Window
|
struct Window
|
||||||
{
|
{
|
||||||
WindowType type;
|
WindowType type;
|
||||||
std::variant<std::monostate, RegWindow> data;
|
std::variant<std::monostate, RegWindow, ThreadWindow, FrameWindow> data;
|
||||||
|
|
||||||
void draw(const Frontend &);
|
void draw(const Frontend &);
|
||||||
|
|
||||||
static Window create_regs(size_t window_id);
|
static Window create_regs(size_t window_id);
|
||||||
|
static Window create_threads(size_t window_id);
|
||||||
|
static Window create_frames(size_t window_id);
|
||||||
};
|
};
|
||||||
} // namespace dbgui::frontend
|
} // namespace dbgui::frontend
|
||||||
47
src/msg.h
47
src/msg.h
@@ -4,6 +4,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
namespace dbgui
|
namespace dbgui
|
||||||
{
|
{
|
||||||
@@ -31,6 +32,15 @@ namespace dbgui
|
|||||||
// x86
|
// x86
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class ThreadStopReason : uint8_t
|
||||||
|
{
|
||||||
|
unknown,
|
||||||
|
breakpoint,
|
||||||
|
watchpoint,
|
||||||
|
signal,
|
||||||
|
exception,
|
||||||
|
};
|
||||||
|
|
||||||
namespace FrontToBack
|
namespace FrontToBack
|
||||||
{
|
{
|
||||||
enum class MsgType : uint8_t
|
enum class MsgType : uint8_t
|
||||||
@@ -52,6 +62,12 @@ namespace dbgui
|
|||||||
ip_change,
|
ip_change,
|
||||||
initial_proc_info,
|
initial_proc_info,
|
||||||
regs_changed,
|
regs_changed,
|
||||||
|
// TODO: thread_added?
|
||||||
|
thread_changed,
|
||||||
|
thread_removed,
|
||||||
|
frame_changed,
|
||||||
|
frame_removed,
|
||||||
|
// TODO: frame_moved, frame_added, etc?
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StateChange
|
struct StateChange
|
||||||
@@ -84,11 +100,40 @@ namespace dbgui
|
|||||||
std::vector<std::pair<uint16_t, std::vector<uint8_t>>> changes;
|
std::vector<std::pair<uint16_t, std::vector<uint8_t>>> changes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ThreadChange
|
||||||
|
{
|
||||||
|
uint64_t id;
|
||||||
|
uint64_t ip;
|
||||||
|
uint64_t stop_extra;
|
||||||
|
uint16_t idx;
|
||||||
|
ThreadStopReason stop_reason;
|
||||||
|
std::optional<std::string> name;
|
||||||
|
std::optional<std::string> cur_display_fn;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ThreadRemoved
|
||||||
|
{
|
||||||
|
size_t idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FrameChanged
|
||||||
|
{
|
||||||
|
uint64_t ip;
|
||||||
|
uint16_t idx;
|
||||||
|
std::string display_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FrameRemoved
|
||||||
|
{
|
||||||
|
size_t idx;
|
||||||
|
};
|
||||||
|
|
||||||
struct Msg
|
struct Msg
|
||||||
{
|
{
|
||||||
MsgType type;
|
MsgType type;
|
||||||
std::variant<std::monostate, StateChange, IPChange, InitialProcessInfo,
|
std::variant<std::monostate, StateChange, IPChange, InitialProcessInfo,
|
||||||
RegsChanged>
|
RegsChanged, ThreadChange, ThreadRemoved, FrameChanged,
|
||||||
|
FrameRemoved>
|
||||||
data;
|
data;
|
||||||
};
|
};
|
||||||
} // namespace BackToFront
|
} // namespace BackToFront
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
|
int tmp = 10;
|
||||||
|
while (tmp != 0) {
|
||||||
|
sleep(1);
|
||||||
|
tmp--;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user