hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2024-11-29 21:32:31 +0100
committerhachem <im@hachem.wtf>2024-11-29 21:32:31 +0100
commit42100ac963a5de424a1407885599f049335036f9 (patch)
tree707fdd61114d903b70bad460dc4921f39652766f /src
parentbcdc3f6311221bbe6ce9b180b5c35f3556b34aa8 (diff)
feat: breakpoint conditions and skip counts
Diffstat (limited to 'src')
-rw-r--r--src/debugger/debugger.cpp80
-rw-r--r--src/debugger/debugger.h2
-rw-r--r--src/debugger/types.h2
-rw-r--r--src/ui/ui.cpp27
4 files changed, 103 insertions, 8 deletions
diff --git a/src/debugger/debugger.cpp b/src/debugger/debugger.cpp
index 5b72365..77cc1b8 100644
--- a/src/debugger/debugger.cpp
+++ b/src/debugger/debugger.cpp
@@ -41,7 +41,11 @@ namespace Hsdbg
llvm_prefix / "bin" / "debugserver",
};
#elif defined(HSDBG_LINUX)
- return { llvm_prefix / "bin" / "lldb-server" };
+ return {
+ llvm_prefix / "bin" / "lldb-server",
+ "/usr/bin/lldb-server",
+ "/usr/local/bin/lldb-server",
+ };
#else
return {};
#endif
@@ -70,7 +74,12 @@ namespace Hsdbg
return;
}
- Log::warn("debugger: no debug server found, launching a target will fail");
+ Log::warn("debugger: no debug server found, leaving lldb to locate one");
+ }
+
+ auto text_or(const char* text, std::string_view fallback) -> std::string
+ {
+ return text != nullptr && text[0] != '\0' ? std::string(text) : std::string(fallback);
}
auto path_of(lldb::SBFileSpec spec) -> std::filesystem::path
@@ -171,11 +180,6 @@ namespace Hsdbg
constexpr uint32_t MAX_VARIABLE_DEPTH = 3;
constexpr uint32_t MAX_VARIABLE_CHILDREN = 64;
- auto text_or(const char* text, std::string_view fallback) -> std::string
- {
- return text != nullptr && text[0] != '\0' ? std::string(text) : std::string(fallback);
- }
-
auto frame_of(lldb::SBProcess& process, uint64_t thread_id, uint32_t frame_index) -> lldb::SBFrame
{
lldb::SBThread thread = process.GetThreadByID(thread_id);
@@ -410,6 +414,17 @@ namespace Hsdbg
if (spec.stop_at_entry)
info.SetLaunchFlags(info.GetLaunchFlags() | lldb::eLaunchFlagStopAtEntry);
+ for (const Breakpoint& breakpoint : m_breakpoints)
+ {
+ if (breakpoint.backend_id == 0)
+ continue;
+
+ lldb::SBBreakpoint source = m_session->target.FindBreakpointByID(breakpoint.backend_id);
+
+ if (source.IsValid())
+ source.SetIgnoreCount(breakpoint.ignore_count);
+ }
+
set_state(TargetState::Launching);
lldb::SBError error;
@@ -727,6 +742,51 @@ namespace Hsdbg
return true;
}
+ auto Debugger::set_breakpoint_condition(uint32_t id, std::string_view condition) -> bool
+ {
+ Breakpoint* breakpoint = find_breakpoint(id);
+ if (breakpoint == nullptr)
+ return false;
+
+ breakpoint->condition = condition;
+
+ if (breakpoint->backend_id != 0 && m_session->target.IsValid())
+ {
+ lldb::SBBreakpoint source = m_session->target.FindBreakpointByID(breakpoint->backend_id);
+
+ if (source.IsValid())
+ source.SetCondition(breakpoint->condition.c_str());
+ }
+
+ if (breakpoint->condition.empty())
+ Log::info("debugger: breakpoint {} is unconditional", id);
+ else
+ Log::info("debugger: breakpoint {} stops when '{}'", id, breakpoint->condition);
+
+ return true;
+ }
+
+ auto Debugger::set_breakpoint_ignore_count(uint32_t id, uint32_t count) -> bool
+ {
+ Breakpoint* breakpoint = find_breakpoint(id);
+ if (breakpoint == nullptr)
+ return false;
+
+ breakpoint->ignore_count = count;
+
+ if (breakpoint->backend_id != 0 && m_session->target.IsValid())
+ {
+ lldb::SBBreakpoint source = m_session->target.FindBreakpointByID(breakpoint->backend_id);
+
+ if (source.IsValid())
+ source.SetIgnoreCount(count);
+ }
+
+ Log::info("debugger: breakpoint {} ignores {} hits", id, count);
+
+ return true;
+ }
+
auto Debugger::clear_breakpoints() -> void
{
if (m_session->target.IsValid())
@@ -1159,6 +1219,12 @@ namespace Hsdbg
created.SetEnabled(breakpoint.enabled);
+ if (!breakpoint.condition.empty())
+ created.SetCondition(breakpoint.condition.c_str());
+
+ if (breakpoint.ignore_count != 0)
+ created.SetIgnoreCount(breakpoint.ignore_count);
+
breakpoint.backend_id = created.GetID();
read_back(m_session->target, created, breakpoint);
diff --git a/src/debugger/debugger.h b/src/debugger/debugger.h
index 021c92a..a62a9bd 100644
--- a/src/debugger/debugger.h
+++ b/src/debugger/debugger.h
@@ -42,6 +42,8 @@ namespace Hsdbg
auto add_function_breakpoint(std::string_view function) -> uint32_t;
auto remove_breakpoint(uint32_t id) -> bool;
auto set_breakpoint_enabled(uint32_t id, bool enabled) -> bool;
+ auto set_breakpoint_condition(uint32_t id, std::string_view condition) -> bool;
+ auto set_breakpoint_ignore_count(uint32_t id, uint32_t count) -> bool;
auto clear_breakpoints() -> void;
auto find_breakpoint(uint32_t id) -> Breakpoint*;
auto breakpoints() const -> std::span<const Breakpoint> { return m_breakpoints; }
diff --git a/src/debugger/types.h b/src/debugger/types.h
index 5f9d040..1ceee29 100644
--- a/src/debugger/types.h
+++ b/src/debugger/types.h
@@ -85,6 +85,8 @@ namespace Hsdbg
std::string function;
uint64_t address = 0;
std::string condition;
+
+ uint32_t ignore_count = 0;
uint32_t hit_count = 0;
bool enabled = true;
bool resolved = false;
diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp
index 9abb872..7c0970a 100644
--- a/src/ui/ui.cpp
+++ b/src/ui/ui.cpp
@@ -512,12 +512,14 @@ namespace Hsdbg
ImGuiTableFlags_SizingStretchProp |
ImGuiTableFlags_ScrollY;
- if (ImGui::BeginTable("##breakpoints", 6, flags))
+ if (ImGui::BeginTable("##breakpoints", 8, flags))
{
ImGui::TableSetupColumn("on", ImGuiTableColumnFlags_WidthFixed, 26.0f);
ImGui::TableSetupColumn("id", ImGuiTableColumnFlags_WidthFixed, 30.0f);
ImGui::TableSetupColumn("location");
ImGui::TableSetupColumn("address");
+ ImGui::TableSetupColumn("condition");
+ ImGui::TableSetupColumn("skip", ImGuiTableColumnFlags_WidthFixed, 50.0f);
ImGui::TableSetupColumn("hits", ImGuiTableColumnFlags_WidthFixed, 40.0f);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 26.0f);
ImGui::TableSetupScrollFreeze(0, 1);
@@ -567,6 +569,29 @@ namespace Hsdbg
}
ImGui::TableNextColumn();
+ std::string condition = breakpoint.condition;
+ ImGui::SetNextItemWidth(-1.0f);
+
+ if (ImGui::InputTextWithHint("##condition",
+ "stop when",
+ &condition,
+ ImGuiInputTextFlags_EnterReturnsTrue))
+ {
+ debugger.set_breakpoint_condition(breakpoint.id, condition);
+ }
+
+ ImGui::TableNextColumn();
+ int ignore_count = static_cast<int>(breakpoint.ignore_count);
+ ImGui::SetNextItemWidth(-1.0f);
+
+ if (ImGui::InputInt("##skip", &ignore_count, 0, 0,
+ ImGuiInputTextFlags_EnterReturnsTrue))
+ {
+ debugger.set_breakpoint_ignore_count(breakpoint.id,
+ static_cast<uint32_t>(std::max(ignore_count, 0)));
+ }
+
+ ImGui::TableNextColumn();
ImGui::Text("%u", breakpoint.hit_count);
ImGui::TableNextColumn();