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

@@ -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));
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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();
} }

View File

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

View File

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

BIN
tmp/main

Binary file not shown.

View File

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