breakpoints
This commit is contained in:
@@ -4,11 +4,12 @@ using namespace dbgui::backend;
|
|||||||
|
|
||||||
Backend::~Backend() {}
|
Backend::~Backend() {}
|
||||||
|
|
||||||
void Backend::send_state_change(TargetState new_state, StateChangeReason reason)
|
void Backend::send_state_change(TargetState new_state, StateChangeReason reason,
|
||||||
|
uint64_t extra)
|
||||||
{
|
{
|
||||||
auto msg = std::make_unique<BackToFront::Msg>(
|
auto msg = std::make_unique<BackToFront::Msg>(
|
||||||
BackToFront::MsgType::state_change,
|
BackToFront::MsgType::state_change,
|
||||||
BackToFront::StateChange{new_state, reason});
|
BackToFront::StateChange{new_state, reason, extra});
|
||||||
this->send_msg(std::move(msg));
|
this->send_msg(std::move(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ namespace dbgui::backend
|
|||||||
virtual void add_data_node(const data::DataNode &) = 0;
|
virtual void add_data_node(const data::DataNode &) = 0;
|
||||||
virtual void remove_data_node(uint64_t id) = 0;
|
virtual void remove_data_node(uint64_t id) = 0;
|
||||||
|
|
||||||
|
virtual void add_breakpoint(uint64_t addr, size_t id) = 0;
|
||||||
|
virtual void remove_breakpoint(size_t id) = 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>>
|
||||||
{
|
{
|
||||||
@@ -51,7 +54,8 @@ namespace dbgui::backend
|
|||||||
_back_front_msgs.emplace_back(std::move(msg));
|
_back_front_msgs.emplace_back(std::move(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_state_change(TargetState new_state, StateChangeReason reason);
|
void send_state_change(TargetState new_state, StateChangeReason reason,
|
||||||
|
uint64_t extra = 0);
|
||||||
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_change(BackToFront::ThreadChange &&);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
using namespace dbgui::backend;
|
using namespace dbgui::backend;
|
||||||
|
|
||||||
@@ -132,13 +133,43 @@ void LLDBBackend::handle_state_change(lldb::StateType state)
|
|||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case eStateStopped:
|
case eStateStopped:
|
||||||
|
{
|
||||||
this->check_reg_changes();
|
this->check_reg_changes();
|
||||||
this->check_thread_changes();
|
this->check_thread_changes();
|
||||||
this->check_frame_changes();
|
this->check_frame_changes();
|
||||||
this->check_data_changes();
|
this->check_data_changes();
|
||||||
_state = TargetState::paused;
|
_state = TargetState::paused;
|
||||||
this->send_state_change(TargetState::paused, StateChangeReason::unknown);
|
// TODO: does the selected thread auto-switch?
|
||||||
|
auto sel_thread = _process->GetSelectedThread();
|
||||||
|
auto change_reason = StateChangeReason::unknown;
|
||||||
|
auto extra = 0;
|
||||||
|
switch (sel_thread.GetStopReason())
|
||||||
|
{
|
||||||
|
case eStopReasonBreakpoint:
|
||||||
|
{
|
||||||
|
// what is location id/N for breakpoints?
|
||||||
|
// does this have to do when there are multiple
|
||||||
|
// place the same source code ends up?
|
||||||
|
auto bp_id = sel_thread.GetStopReasonDataAtIndex(0);
|
||||||
|
|
||||||
|
// clang-format bugs out on this for some reason
|
||||||
|
// clang-format off
|
||||||
|
auto it = std::find_if(
|
||||||
|
_breakpoints.begin(), _breakpoints.end(),
|
||||||
|
[bp_id](const auto &el) { return el.lldb_id == bp_id; });
|
||||||
|
// clang-format on
|
||||||
|
if (it != _breakpoints.end())
|
||||||
|
{
|
||||||
|
change_reason = StateChangeReason::breakpoint;
|
||||||
|
extra = it->id;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->send_state_change(TargetState::paused, change_reason, extra);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case eStateRunning:
|
case eStateRunning:
|
||||||
case eStateStepping:
|
case eStateStepping:
|
||||||
_state = TargetState::running;
|
_state = TargetState::running;
|
||||||
@@ -337,7 +368,7 @@ void LLDBBackend::dump_threads()
|
|||||||
end = start + 0x100;
|
end = start + 0x100;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto buf = std::vector<uint8_t>{};
|
/*auto buf = std::vector<uint8_t>{};
|
||||||
buf.resize(end - start);
|
buf.resize(end - start);
|
||||||
auto err = SBError{};
|
auto err = SBError{};
|
||||||
_target.ReadMemory(SBAddress{start, _target}, buf.data(), buf.size(), err);
|
_target.ReadMemory(SBAddress{start, _target}, buf.data(), buf.size(), err);
|
||||||
@@ -359,7 +390,7 @@ void LLDBBackend::dump_threads()
|
|||||||
{
|
{
|
||||||
printf("Selfprint: %s%s\n", inst.GetMnemonic(_target),
|
printf("Selfprint: %s%s\n", inst.GetMnemonic(_target),
|
||||||
inst.GetOperands(_target));
|
inst.GetOperands(_target));
|
||||||
}
|
}*/
|
||||||
|
|
||||||
//printf("Disasm: %s\n", frame.Disassemble());
|
//printf("Disasm: %s\n", frame.Disassemble());
|
||||||
} else
|
} else
|
||||||
@@ -982,9 +1013,9 @@ dbgui::data::DataResult LLDBBackend::calc_data_res(const data::DataNode &node)
|
|||||||
auto addr = inst.GetAddress().GetLoadAddress(_target);
|
auto addr = inst.GetAddress().GetLoadAddress(_target);
|
||||||
const auto len = inst.GetByteSize();
|
const auto len = inst.GetByteSize();
|
||||||
|
|
||||||
SBStream stream{};
|
//SBStream stream{};
|
||||||
inst.GetDescription(stream);
|
//inst.GetDescription(stream);
|
||||||
printf("Got inst: %.*s\n", stream.GetSize(), stream.GetData());
|
//printf("Got inst: %.*s\n", stream.GetSize(), stream.GetData());
|
||||||
|
|
||||||
if (mnem.size() > 255 || op.size() > 255 || comm.size() > 255)
|
if (mnem.size() > 255 || op.size() > 255 || comm.size() > 255)
|
||||||
{
|
{
|
||||||
@@ -1023,6 +1054,52 @@ dbgui::data::DataResult LLDBBackend::calc_data_res(const data::DataNode &node)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LLDBBackend::add_breakpoint(uint64_t addr, size_t id)
|
||||||
|
{
|
||||||
|
std::lock_guard g{_data_lock};
|
||||||
|
if (!_process)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::find_if(_breakpoints.begin(), _breakpoints.end(),
|
||||||
|
[id](const auto &el) { return el.id == id; })
|
||||||
|
!= _breakpoints.end())
|
||||||
|
{
|
||||||
|
printf("Trying to register same breakpoint id\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto bp = _target.BreakpointCreateByAddress(addr);
|
||||||
|
_breakpoints.push_back(Breakpoint{.id = id, .lldb_id = bp.GetID()});
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLDBBackend::remove_breakpoint(size_t id)
|
||||||
|
{
|
||||||
|
std::lock_guard g{_data_lock};
|
||||||
|
if (!_process)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = std::find_if(_breakpoints.begin(), _breakpoints.end(),
|
||||||
|
[id](const auto &el) { return el.id == id; });
|
||||||
|
|
||||||
|
if (it == _breakpoints.end())
|
||||||
|
{
|
||||||
|
printf("Trying to delete nonexistant breakpoint\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: error handling?
|
||||||
|
_target.BreakpointDelete(it->lldb_id);
|
||||||
|
// TODO: this should check if there are no pending events in the debugger event queue
|
||||||
|
// to make sure we did not hit the breakpoint before deleting it
|
||||||
|
// maybe really add like a custom event type to send to the event queue?
|
||||||
|
// afterwards it should send a bp deleted msg so the UI can sync this, too
|
||||||
|
_breakpoints.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Reg output for x64
|
Reg output for x64
|
||||||
Got register set General Purpose Registers
|
Got register set General Purpose Registers
|
||||||
|
|||||||
@@ -40,6 +40,12 @@ namespace dbgui::backend
|
|||||||
std::string display_name;
|
std::string display_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Breakpoint
|
||||||
|
{
|
||||||
|
size_t id;
|
||||||
|
lldb::break_id_t lldb_id;
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: source_init_file: false
|
// TODO: source_init_file: false
|
||||||
LLDBBackend(std::string filename);
|
LLDBBackend(std::string filename);
|
||||||
virtual ~LLDBBackend();
|
virtual ~LLDBBackend();
|
||||||
@@ -56,6 +62,9 @@ namespace dbgui::backend
|
|||||||
void add_data_node(const data::DataNode &) override;
|
void add_data_node(const data::DataNode &) override;
|
||||||
void remove_data_node(uint64_t id) override;
|
void remove_data_node(uint64_t id) override;
|
||||||
|
|
||||||
|
void add_breakpoint(uint64_t addr, size_t id) override;
|
||||||
|
void remove_breakpoint(size_t id) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void run_msg_loop();
|
void run_msg_loop();
|
||||||
void wait_for_debug_events();
|
void wait_for_debug_events();
|
||||||
@@ -92,5 +101,7 @@ namespace dbgui::backend
|
|||||||
std::vector<size_t> _dag_linear = {};
|
std::vector<size_t> _dag_linear = {};
|
||||||
bool _dag_linear_valid = false;
|
bool _dag_linear_valid = false;
|
||||||
std::vector<data::DataResult> _cached_data_results = {};
|
std::vector<data::DataResult> _cached_data_results = {};
|
||||||
|
|
||||||
|
std::vector<Breakpoint> _breakpoints = {};
|
||||||
};
|
};
|
||||||
} // namespace dbgui::backend
|
} // namespace dbgui::backend
|
||||||
@@ -24,6 +24,7 @@ Frontend::Frontend()
|
|||||||
_windows.push_back(Window::create_threads(window_id++));
|
_windows.push_back(Window::create_threads(window_id++));
|
||||||
_windows.push_back(Window::create_frames(window_id++));
|
_windows.push_back(Window::create_frames(window_id++));
|
||||||
_windows.push_back(Window::create_disas(window_id++));
|
_windows.push_back(Window::create_disas(window_id++));
|
||||||
|
_windows.push_back(Window::create_bp(window_id++));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Frontend::run_frame()
|
void Frontend::run_frame()
|
||||||
@@ -182,7 +183,13 @@ void Frontend::draw_header()
|
|||||||
ImGui::BeginDisabled();
|
ImGui::BeginDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::Button("Step Over")) {}
|
if (ImGui::Button("Step Over"))
|
||||||
|
{
|
||||||
|
if (this->target->backend->step_over())
|
||||||
|
{
|
||||||
|
// TODO: already disable the UI into running mode
|
||||||
|
}
|
||||||
|
}
|
||||||
if (ImGui::Button("Step Into"))
|
if (ImGui::Button("Step Into"))
|
||||||
{
|
{
|
||||||
if (this->target->backend->step_into())
|
if (this->target->backend->step_into())
|
||||||
@@ -190,7 +197,13 @@ void Frontend::draw_header()
|
|||||||
// TODO: already disable the UI into running mode
|
// TODO: already disable the UI into running mode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::Button("Step Out");
|
if (ImGui::Button("Step Out"))
|
||||||
|
{
|
||||||
|
if (this->target->backend->step_out())
|
||||||
|
{
|
||||||
|
// TODO: already disable the UI into running mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_paused)
|
if (!is_paused)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
#include "frontend/target.h"
|
#include "frontend/target.h"
|
||||||
#include "backend/debug_backend.h"
|
#include "backend/debug_backend.h"
|
||||||
|
|||||||
@@ -41,6 +41,13 @@ namespace dbgui::frontend
|
|||||||
std::string display_name;
|
std::string display_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Breakpoint
|
||||||
|
{
|
||||||
|
bool removed = false;
|
||||||
|
// TODO: srcloc
|
||||||
|
uint64_t addr;
|
||||||
|
};
|
||||||
|
|
||||||
Target(std::string filename);
|
Target(std::string filename);
|
||||||
|
|
||||||
TargetState state = TargetState::stopped;
|
TargetState state = TargetState::stopped;
|
||||||
@@ -52,6 +59,7 @@ namespace dbgui::frontend
|
|||||||
std::vector<RegSet> reg_sets;
|
std::vector<RegSet> reg_sets;
|
||||||
std::vector<std::optional<Thread>> threads;
|
std::vector<std::optional<Thread>> threads;
|
||||||
std::vector<std::optional<Frame>> frames;
|
std::vector<std::optional<Frame>> frames;
|
||||||
|
std::vector<Breakpoint> breakpoints;
|
||||||
|
|
||||||
std::shared_ptr<backend::Backend> backend = nullptr;
|
std::shared_ptr<backend::Backend> backend = nullptr;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "frontend.h"
|
#include "frontend.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include "imgui_internal.h"
|
||||||
|
|
||||||
using namespace dbgui;
|
using namespace dbgui;
|
||||||
using namespace dbgui::frontend;
|
using namespace dbgui::frontend;
|
||||||
@@ -18,6 +20,9 @@ bool Window::draw(Frontend &frontend)
|
|||||||
case disassembly:
|
case disassembly:
|
||||||
return std::get<DisasmWindow>(this->data).draw(frontend);
|
return std::get<DisasmWindow>(this->data).draw(frontend);
|
||||||
break;
|
break;
|
||||||
|
case breakpoints:
|
||||||
|
return std::get<BreakpointWindow>(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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -59,6 +64,15 @@ Window Window::create_disas(size_t id)
|
|||||||
DisasmWindow{.id = id_str, .open = true, .first = true}};
|
DisasmWindow{.id = id_str, .open = true, .first = true}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Window Window::create_bp(size_t id)
|
||||||
|
{
|
||||||
|
auto id_str = std::string{"Breakpoints##"};
|
||||||
|
id_str.append(std::to_string(id));
|
||||||
|
|
||||||
|
return Window{.type = WindowType::breakpoints,
|
||||||
|
.data = BreakpointWindow{.id = id_str, .open = true}};
|
||||||
|
}
|
||||||
|
|
||||||
bool RegWindow::draw(const Frontend &frontend)
|
bool RegWindow::draw(const Frontend &frontend)
|
||||||
{
|
{
|
||||||
//ImGui::SetNextWindowDockID(frontend.dock_id, ImGuiCond_Appearing);
|
//ImGui::SetNextWindowDockID(frontend.dock_id, ImGuiCond_Appearing);
|
||||||
@@ -74,6 +88,12 @@ bool RegWindow::draw(const Frontend &frontend)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (frontend.target->state == TargetState::running)
|
||||||
|
{
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text,
|
||||||
|
ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled));
|
||||||
|
}
|
||||||
|
|
||||||
if (ImGui::BeginTable("table", 1,
|
if (ImGui::BeginTable("table", 1,
|
||||||
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
|
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
|
||||||
{
|
{
|
||||||
@@ -151,6 +171,11 @@ bool RegWindow::draw(const Frontend &frontend)
|
|||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (frontend.target->state == TargetState::running)
|
||||||
|
{
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -170,6 +195,12 @@ bool ThreadWindow::draw(const Frontend &frontend)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (frontend.target->state == TargetState::running)
|
||||||
|
{
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text,
|
||||||
|
ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled));
|
||||||
|
}
|
||||||
|
|
||||||
if (ImGui::BeginTable("table", 3,
|
if (ImGui::BeginTable("table", 3,
|
||||||
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
|
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
|
||||||
{
|
{
|
||||||
@@ -211,6 +242,11 @@ bool ThreadWindow::draw(const Frontend &frontend)
|
|||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (frontend.target->state == TargetState::running)
|
||||||
|
{
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -230,6 +266,12 @@ bool FrameWindow::draw(const Frontend &frontend)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (frontend.target->state == TargetState::running)
|
||||||
|
{
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text,
|
||||||
|
ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled));
|
||||||
|
}
|
||||||
|
|
||||||
if (ImGui::BeginTable("table", 1,
|
if (ImGui::BeginTable("table", 1,
|
||||||
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
|
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
|
||||||
{
|
{
|
||||||
@@ -262,6 +304,11 @@ bool FrameWindow::draw(const Frontend &frontend)
|
|||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (frontend.target->state == TargetState::running)
|
||||||
|
{
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -293,6 +340,12 @@ bool DisasmWindow::draw(Frontend &frontend)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (frontend.target->state == TargetState::running)
|
||||||
|
{
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text,
|
||||||
|
ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled));
|
||||||
|
}
|
||||||
|
|
||||||
if (first)
|
if (first)
|
||||||
{
|
{
|
||||||
auto found = false;
|
auto found = false;
|
||||||
@@ -343,12 +396,12 @@ bool DisasmWindow::draw(Frontend &frontend)
|
|||||||
|
|
||||||
auto pad = ImGui::GetStyle().CellPadding;
|
auto pad = ImGui::GetStyle().CellPadding;
|
||||||
pad.x += 10.f;
|
pad.x += 10.f;
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, pad);
|
if (ImGui::BeginTable("table", 3,
|
||||||
if (ImGui::BeginTable("table", 2,
|
|
||||||
ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollY
|
ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollY
|
||||||
| ImGuiTableFlags_RowBg | ImGuiTableFlags_PadOuterX))
|
| ImGuiTableFlags_RowBg | ImGuiTableFlags_PadOuterX))
|
||||||
{
|
{
|
||||||
ImGui::TableSetupScrollFreeze(0, 1);
|
ImGui::TableSetupScrollFreeze(0, 1);
|
||||||
|
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 10.f);
|
||||||
ImGui::TableSetupColumn("Address");
|
ImGui::TableSetupColumn("Address");
|
||||||
ImGui::TableSetupColumn("Instruction");
|
ImGui::TableSetupColumn("Instruction");
|
||||||
ImGui::TableHeadersRow();
|
ImGui::TableHeadersRow();
|
||||||
@@ -360,6 +413,58 @@ bool DisasmWindow::draw(Frontend &frontend)
|
|||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableSetColumnIndex(0);
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
|
||||||
|
ImGui::PushID(idx);
|
||||||
|
// TODO: draw nice break sign
|
||||||
|
auto &bps = frontend.target->breakpoints;
|
||||||
|
const auto bp_it =
|
||||||
|
std::find_if(bps.begin(), bps.end(),
|
||||||
|
[inst](const auto &el) { return el.addr == inst.addr; });
|
||||||
|
const auto is_bp = bp_it != bps.end() && !bp_it->removed;
|
||||||
|
if (is_bp)
|
||||||
|
{
|
||||||
|
auto win_pos = ImGui::GetWindowPos();
|
||||||
|
auto pos = ImGui::GetCursorPos();
|
||||||
|
pos.x += win_pos.x;
|
||||||
|
pos.y += win_pos.y - ImGui::GetScrollY();
|
||||||
|
pos.y += (ImGui::GetTextLineHeight() - 10.f) / 2.f;
|
||||||
|
auto end_pos = pos;
|
||||||
|
end_pos.x += 10.f;
|
||||||
|
end_pos.y += 10.f;
|
||||||
|
ImGui::GetWindowDrawList()->AddRectFilled(pos, end_pos,
|
||||||
|
IM_COL32(255, 0, 0, 255));
|
||||||
|
}
|
||||||
|
if (ImGui::InvisibleButton("Break",
|
||||||
|
ImVec2{10.f, ImGui::GetTextLineHeight()}))
|
||||||
|
{
|
||||||
|
if (!is_bp)
|
||||||
|
{
|
||||||
|
size_t idx = 0;
|
||||||
|
for (; idx < bps.size(); ++idx)
|
||||||
|
{
|
||||||
|
if (bps[idx].removed)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (idx == bps.size())
|
||||||
|
{
|
||||||
|
bps.push_back(
|
||||||
|
Target::Breakpoint{.removed = false, .addr = inst.addr});
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
bps[idx] = Target::Breakpoint{.removed = false, .addr = inst.addr};
|
||||||
|
}
|
||||||
|
frontend.target->backend->add_breakpoint(inst.addr, idx);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
frontend.target->backend->remove_breakpoint(bp_it - bps.begin());
|
||||||
|
bp_it->removed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopID();
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
if (!this->ip_unsuccessful && inst.addr == ip)
|
if (!this->ip_unsuccessful && inst.addr == ip)
|
||||||
{
|
{
|
||||||
// TODO: color config
|
// TODO: color config
|
||||||
@@ -374,7 +479,7 @@ bool DisasmWindow::draw(Frontend &frontend)
|
|||||||
|
|
||||||
// TODO: make some unified handler for int vars
|
// TODO: make some unified handler for int vars
|
||||||
ImGui::PushID(idx);
|
ImGui::PushID(idx);
|
||||||
ImGui::Text("%lX", inst.addr);
|
ImGui::Text("%lX ", inst.addr);
|
||||||
if (ImGui::IsItemHovered()
|
if (ImGui::IsItemHovered()
|
||||||
&& ImGui::IsMouseClicked(ImGuiMouseButton_Right))
|
&& ImGui::IsMouseClicked(ImGuiMouseButton_Right))
|
||||||
{
|
{
|
||||||
@@ -397,13 +502,17 @@ bool DisasmWindow::draw(Frontend &frontend)
|
|||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
const int mnem_space = max_mnem_len - inst.mnem_len + 1;
|
const int mnem_space = max_mnem_len - inst.mnem_len + 1;
|
||||||
const int op_space = max_op_len - inst.op_len + 1;
|
const int op_space = /*max_op_len - inst.op_len +*/ 1;
|
||||||
ImGui::Text(inst.fmt_str.c_str(), mnem_space, ' ', op_space, ' ');
|
ImGui::Text(inst.fmt_str.c_str(), mnem_space, ' ', op_space, ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
ImGui::PopStyleVar();
|
|
||||||
|
if (frontend.target->state == TargetState::running)
|
||||||
|
{
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
@@ -411,6 +520,79 @@ bool DisasmWindow::draw(Frontend &frontend)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BreakpointWindow::draw(Frontend &frontend)
|
||||||
|
{
|
||||||
|
if (!ImGui::Begin(this->id.c_str()))
|
||||||
|
{
|
||||||
|
ImGui::End();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!frontend.target)
|
||||||
|
{
|
||||||
|
ImGui::End();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginTable("table", 2,
|
||||||
|
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
|
||||||
|
{
|
||||||
|
ImGui::TableSetupColumn("ID");
|
||||||
|
ImGui::TableSetupColumn("Address");
|
||||||
|
ImGui::TableHeadersRow();
|
||||||
|
|
||||||
|
auto &bps = frontend.target->breakpoints;
|
||||||
|
for (size_t idx = 0; idx < bps.size(); ++idx)
|
||||||
|
{
|
||||||
|
auto &bp = bps[idx];
|
||||||
|
if (bp.removed)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
|
||||||
|
ImGui::PushID(idx);
|
||||||
|
|
||||||
|
ImGui::Text("%zu", idx);
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
ImGui::Text("%lX", bp.addr);
|
||||||
|
|
||||||
|
auto min_pos =
|
||||||
|
ImGui::TableGetCellBgRect(ImGui::GetCurrentTable(), 0).GetTL();
|
||||||
|
auto max_pos =
|
||||||
|
ImGui::TableGetCellBgRect(ImGui::GetCurrentTable(), 1).GetBR();
|
||||||
|
|
||||||
|
if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)
|
||||||
|
&& ImGui::IsMouseHoveringRect(min_pos, max_pos, false))
|
||||||
|
{
|
||||||
|
ImGui::OpenPopup("Context", ImGuiPopupFlags_NoOpenOverExistingPopup);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginPopup("Context"))
|
||||||
|
{
|
||||||
|
if (ImGui::Selectable("Remove"))
|
||||||
|
{
|
||||||
|
printf("Removing bp %zu\n", idx);
|
||||||
|
frontend.target->backend->remove_breakpoint(idx);
|
||||||
|
bp.removed = true;
|
||||||
|
}
|
||||||
|
// TODO: disable/endable?
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Window::handle_data_res(const BackToFront::DataResult &result)
|
void Window::handle_data_res(const BackToFront::DataResult &result)
|
||||||
{
|
{
|
||||||
switch (this->type)
|
switch (this->type)
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ namespace dbgui::frontend
|
|||||||
frames,
|
frames,
|
||||||
threads,
|
threads,
|
||||||
disassembly,
|
disassembly,
|
||||||
|
breakpoints,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RegWindow
|
struct RegWindow
|
||||||
@@ -98,11 +99,19 @@ namespace dbgui::frontend
|
|||||||
std::vector<Instruction> insts;
|
std::vector<Instruction> insts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BreakpointWindow
|
||||||
|
{
|
||||||
|
bool draw(Frontend &);
|
||||||
|
|
||||||
|
std::string id;
|
||||||
|
bool open;
|
||||||
|
};
|
||||||
|
|
||||||
struct Window
|
struct Window
|
||||||
{
|
{
|
||||||
WindowType type;
|
WindowType type;
|
||||||
std::variant<std::monostate, RegWindow, ThreadWindow, FrameWindow,
|
std::variant<std::monostate, RegWindow, ThreadWindow, FrameWindow,
|
||||||
DisasmWindow>
|
DisasmWindow, BreakpointWindow>
|
||||||
data;
|
data;
|
||||||
|
|
||||||
// if true, window is closed and should be deleted
|
// if true, window is closed and should be deleted
|
||||||
@@ -112,6 +121,7 @@ namespace dbgui::frontend
|
|||||||
static Window create_threads(size_t window_id);
|
static Window create_threads(size_t window_id);
|
||||||
static Window create_frames(size_t window_id);
|
static Window create_frames(size_t window_id);
|
||||||
static Window create_disas(size_t window_id);
|
static Window create_disas(size_t window_id);
|
||||||
|
static Window create_bp(size_t window_id);
|
||||||
|
|
||||||
void handle_data_res(const BackToFront::DataResult &result);
|
void handle_data_res(const BackToFront::DataResult &result);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace ImGui
|
||||||
|
{
|
||||||
|
struct StyleColorPush
|
||||||
|
{
|
||||||
|
StyleColorPush(ImGuiCol col, ImVec4 val)
|
||||||
|
{
|
||||||
|
ImGui::PushStyleColor(col, val);
|
||||||
|
}
|
||||||
|
StyleColorPush(ImGuiCol col, ImU32 val) { ImGui::PushStyleColor(col, val); }
|
||||||
|
|
||||||
|
~StyleColorPush() { ImGui::PopStyleColor(); }
|
||||||
|
};
|
||||||
|
} // namespace ImGui
|
||||||
@@ -77,6 +77,7 @@ namespace dbgui
|
|||||||
{
|
{
|
||||||
TargetState new_state;
|
TargetState new_state;
|
||||||
StateChangeReason reason;
|
StateChangeReason reason;
|
||||||
|
uint64_t extra;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IPChange
|
struct IPChange
|
||||||
|
|||||||
Reference in New Issue
Block a user