regs and we can step into!

This commit is contained in:
T0b1
2023-06-02 02:06:49 +02:00
parent d4bf6731a3
commit ac3718b12b
17 changed files with 1434 additions and 344 deletions

View File

@@ -1,4 +1,5 @@
#include "frontend.h"
#include "backend/lldb/lldb_backend.h"
#include "imgui.h"
#include "imgui_internal.h"
@@ -6,134 +7,287 @@
using namespace dbgui;
using namespace dbgui::frontend;
void Frontend::run_frame() {
this->draw_open_popup();
this->draw_header();
// main window
float height = ImGui::GetFrameHeight();
const auto vp_size = ImGui::GetMainViewport()->Size;
const auto win_pos = ImVec2{0, height*2};
const auto win_size = ImVec2{vp_size.x, vp_size.y - height*3};
const auto win_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoSavedSettings;
ImGui::SetNextWindowPos(win_pos, ImGuiCond_Always);
ImGui::SetNextWindowSize(win_size, ImGuiCond_Always);
if (ImGui::Begin("Test", nullptr, win_flags)) {
_dock_id = ImGui::GetID("MyDockSpace");
ImGui::DockSpace(_dock_id, ImVec2{0, 0}, ImGuiDockNodeFlags_PassthruCentralNode);
ImGui::End();
}
this->draw_status();
Target::Target(std::string filename)
{
state = TargetState::startup;
this->filename = filename;
id = 0;
backend = std::make_shared<backend::LLDBBackend>(this->filename.c_str());
}
void Frontend::draw_header() {
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_MenuBar;
float height = ImGui::GetFrameHeight();
void Frontend::run_frame()
{
this->handle_msgs();
this->draw_open_popup();
this->draw_header();
if (ImGui::BeginMainMenuBar()) {
if (ImGui::BeginMenu("File")) {
if (ImGui::MenuItem("Open")) {
_draw_open_popup = true;
ImGui::OpenPopup(_open_popup_id);
}
// main window
float height = ImGui::GetFrameHeight();
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}
const auto vp_size = ImGui::GetMainViewport()->Size;
const auto win_pos = ImVec2{0, height * 2};
const auto win_size = ImVec2{vp_size.x, vp_size.y - height * 3};
if (ImGui::BeginViewportSideBar("##SecondaryMenuBar", NULL, ImGuiDir_Up, height, window_flags)) {
if (ImGui::BeginMenuBar()) {
const auto orig_cursor_x = ImGui::GetCursorPosX();
if (_target) {
switch (_target->state) {
using enum backend::TargetState;
const auto win_flags =
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav
| ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollWithMouse
| ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoSavedSettings;
case stopped:
ImGui::Button("Run");
break;
case paused:
ImGui::Button("Continue");
break;
case running:
ImGui::Button("Pause");
break;
}
} else {
ImGui::BeginDisabled();
ImGui::Button("Continue");
ImGui::EndDisabled();
}
ImGui::SetNextWindowPos(win_pos, ImGuiCond_Always);
ImGui::SetNextWindowSize(win_size, ImGuiCond_Always);
// TODO: this depends on font-size, we just want to make sure the the other buttons don't flicker even if the state is changed
ImGui::SetCursorPosX(orig_cursor_x + 71.f);
if (ImGui::Begin("Test", nullptr, win_flags))
{
this->dock_id = ImGui::GetID("MyDockSpace");
ImGui::DockSpace(this->dock_id, ImVec2{0, 0},
ImGuiDockNodeFlags_PassthruCentralNode);
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical, 2.f);
for (auto &window : _windows)
{
window.draw(*this);
}
const auto is_paused = _target && _target->state == backend::TargetState::paused;
const auto is_running = _target && _target->state == backend::TargetState::running;
ImGui::End();
}
if (!is_paused) {
ImGui::BeginDisabled();
}
ImGui::Button("Step Over");
ImGui::Button("Step Into");
ImGui::Button("Step Out");
if (!is_paused) {
ImGui::EndDisabled();
}
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical, 2.f);
if (!is_paused && !is_running) {
ImGui::BeginDisabled();
}
ImGui::Button("Stop");
ImGui::Button("Restart");
if (!is_paused && !is_running) {
ImGui::EndDisabled();
}
ImGui::EndMenuBar();
}
ImGui::End();
}
this->draw_status();
}
void Frontend::draw_status() {
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_MenuBar;
float height = ImGui::GetFrameHeight();
void Frontend::draw_header()
{
ImGuiWindowFlags window_flags =
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings
| ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_MenuBar;
float height = ImGui::GetFrameHeight();
if (ImGui::BeginViewportSideBar("##MainStatusBar", NULL, ImGuiDir_Down, height, window_flags)) {
if (ImGui::BeginMenuBar()) {
ImGui::Text("Happy status bar");
ImGui::EndMenuBar();
}
ImGui::End();
}
if (ImGui::BeginMainMenuBar())
{
if (ImGui::BeginMenu("File"))
{
if (ImGui::MenuItem("Open"))
{
_draw_open_popup = true;
ImGui::OpenPopup(_open_popup_id);
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Window"))
{
if (ImGui::MenuItem("Registers"))
{
_windows.push_back(Window::create_regs(this->window_id++));
}
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}
if (ImGui::BeginViewportSideBar("##SecondaryMenuBar", NULL, ImGuiDir_Up,
height, window_flags))
{
if (ImGui::BeginMenuBar())
{
const auto orig_cursor_x = ImGui::GetCursorPosX();
if (this->target)
{
switch (this->target->state)
{
using enum TargetState;
case startup:
ImGui::BeginDisabled();
// buttons shouldn't flicker that way
ImGui::Button("Continue");
ImGui::EndDisabled();
break;
case stopped: ImGui::Button("Run"); break;
case paused: ImGui::Button("Continue"); break;
case running: ImGui::Button("Pause"); break;
}
} else
{
ImGui::BeginDisabled();
ImGui::Button("Continue");
ImGui::EndDisabled();
}
// TODO: this depends on font-size, we just want to make sure the the other buttons don't flicker even if the state is changed
ImGui::SetCursorPosX(orig_cursor_x + 71.f);
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical, 2.f);
const auto is_paused =
this->target && this->target->state == TargetState::paused;
const auto is_running =
this->target && this->target->state == TargetState::running;
if (!is_paused)
{
ImGui::BeginDisabled();
}
if (ImGui::Button("Step Over")) {}
if (ImGui::Button("Step Into"))
{
if (this->target->backend->step_into())
{
// TODO: already disable the UI into running mode
}
}
ImGui::Button("Step Out");
if (!is_paused)
{
ImGui::EndDisabled();
}
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical, 2.f);
if (!is_paused && !is_running)
{
ImGui::BeginDisabled();
}
ImGui::Button("Stop");
ImGui::Button("Restart");
if (!is_paused && !is_running)
{
ImGui::EndDisabled();
}
ImGui::EndMenuBar();
}
ImGui::End();
}
}
void Frontend::draw_open_popup() {
if (!_open_popup_id) {
_open_popup_id = ImGui::GetID("Open Executable##OpenPopup");
}
if (ImGui::BeginPopupModal("Open Executable##OpenPopup", &_draw_open_popup, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::InputText("File Path", _open_popup_name_buf.data(), _open_popup_name_buf.size());
void Frontend::draw_status()
{
ImGuiWindowFlags window_flags =
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings
| ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_MenuBar;
float height = ImGui::GetFrameHeight();
if (ImGui::Button("Start")) {
}
ImGui::EndPopup();
}
if (ImGui::BeginViewportSideBar("##MainStatusBar", NULL, ImGuiDir_Down,
height, window_flags))
{
if (ImGui::BeginMenuBar())
{
ImGui::Text("Happy status bar");
ImGui::EndMenuBar();
}
ImGui::End();
}
}
void Frontend::draw_open_popup()
{
if (!_open_popup_id)
{
_open_popup_id = ImGui::GetID("Open Executable##OpenPopup");
}
if (ImGui::BeginPopupModal("Open Executable##OpenPopup", &_draw_open_popup,
ImGuiWindowFlags_AlwaysAutoResize))
{
ImGui::InputText("File Path", _open_popup_name_buf.data(),
_open_popup_name_buf.size());
if (ImGui::Button("Start"))
{
this->target = Target{_open_popup_name_buf.data()};
this->target->backend->start();
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}
void Frontend::handle_msgs()
{
if (!this->target)
{
return;
}
while (true)
{
auto opt = this->target->backend->retrieve_msg_for_frontend();
if (!opt)
{
break;
}
auto *msg = opt->get();
printf("Got msg %u\n", msg->type);
switch (msg->type)
{
using enum BackToFront::MsgType;
case state_change:
{
const auto &info = std::get<BackToFront::StateChange>(msg->data);
this->handle_state_change(info);
break;
}
case ip_change:
// TODO
break;
case initial_proc_info:
this->handle_proc_info(
std::move(std::get<BackToFront::InitialProcessInfo>(msg->data)));
break;
case regs_changed:
this->handle_reg_change(std::get<BackToFront::RegsChanged>(msg->data));
break;
}
}
}
void Frontend::handle_state_change(const BackToFront::StateChange &info)
{
this->target->state = info.new_state;
// TODO: display in status bar
printf("State changed to %u because %u\n", info.new_state, info.reason);
}
void Frontend::handle_proc_info(BackToFront::InitialProcessInfo &&info)
{
this->target->arch = info.arch;
this->target->id = info.pid;
auto &sets = this->target->reg_sets;
printf("RegSet Size: %lu\n", info.reg_sets.size());
for (size_t set_idx = 0; set_idx < info.reg_sets.size(); ++set_idx)
{
sets.emplace_back();
auto &set = sets.back();
printf("Got set %s\n", info.reg_sets[set_idx].name.c_str());
set.name = std::move(info.reg_sets[set_idx].name);
for (size_t i = 0; i < info.reg_sets[set_idx].reg_names.size(); ++i)
{
set.regs.emplace_back();
printf(" Got reg %s\n", info.reg_sets[set_idx].reg_names[i].c_str());
set.regs.back().name = std::move(info.reg_sets[set_idx].reg_names[i]);
}
}
}
void Frontend::handle_reg_change(const BackToFront::RegsChanged &info)
{
auto &set = this->target->reg_sets[info.set_idx];
for (const auto &[idx, val] : info.changes)
{
auto &reg = set.regs[idx];
reg.bytes.resize(val.size());
// TODO: opt for uint64?
std::copy(val.begin(), val.end(), reg.bytes.begin());
}
}