hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/src/debugger/debugger.h
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2025-12-13 12:04:35 +0100
committerhachem <im@hachem.wtf>2025-12-13 12:04:35 +0100
commit643287696ea9baccc90a26643b6adb9fabcdf433 (patch)
treecc614203c39ad7595f96ae4ffa47c8e2ca5ccc29 /src/debugger/debugger.h
parent5529924dec7b1947dc50e1aee6156d43a0ea4e8c (diff)
feat: tracing, instrumentation and sampling in the debugger
Diffstat (limited to 'src/debugger/debugger.h')
-rw-r--r--src/debugger/debugger.h79
1 files changed, 79 insertions, 0 deletions
diff --git a/src/debugger/debugger.h b/src/debugger/debugger.h
index 5e154b2..16bfb6b 100644
--- a/src/debugger/debugger.h
+++ b/src/debugger/debugger.h
@@ -6,12 +6,18 @@
#include <chrono>
#include <cstdint>
#include <filesystem>
+#include <unordered_map>
#include <memory>
#include <span>
#include <string>
#include <string_view>
#include <vector>
+namespace lldb
+{
+ class SBThread;
+}
+
namespace Hsdbg
{
class Debugger
@@ -55,6 +61,15 @@ namespace Hsdbg
auto clear_traces() -> void;
auto traces() const -> std::span<const FunctionTrace> { return m_traces; }
+ auto timeline() const -> std::span<const TimelineSpan> { return m_timeline; }
+
+ auto span_label(uint32_t trace_id) const -> const char*;
+
+ auto instrumentation_active() const -> bool { return m_instr_available; }
+
+ auto set_sampling_enabled(bool enabled) -> void { m_sampling_enabled = enabled; }
+ auto sampling_enabled() const -> bool { return m_sampling_enabled; }
+
auto threads() const -> std::span<const Thread> { return m_threads; }
auto call_stack() const -> std::span<const StackFrame> { return m_call_stack; }
auto locals() const -> std::span<const Variable> { return m_locals; }
@@ -114,8 +129,50 @@ namespace Hsdbg
auto resolve_trace(FunctionTrace& trace) -> void;
auto handle_trace_stop() -> bool;
+ auto record_trace_entry(FunctionTrace& trace, lldb::SBThread& thread) -> void;
+ auto record_trace_return(lldb::SBThread& thread) -> void;
auto trace_now() const -> double;
+ struct InstrRecord;
+ auto resolve_instrumentation() -> void;
+ auto read_instrumentation() -> void;
+ auto apply_instr_record(const InstrRecord& record) -> void;
+ auto intern_instr_function(uint64_t address) -> uint32_t;
+ auto symbol_load_address(const char* name) -> uint64_t;
+
+ struct InstrOpenCall
+ {
+ uint32_t trace_id = 0;
+ uint64_t start_ns = 0;
+ size_t span_index = 0;
+ };
+
+ auto maybe_request_sample() -> void;
+ auto take_sample_and_resume() -> bool;
+ auto take_sample() -> void;
+ auto fold_sample(uint64_t thread_id, const std::vector<uint32_t>& stack, double now) -> void;
+ auto intern_named_function(std::string_view name) -> uint32_t;
+
+ struct OpenSample
+ {
+ uint32_t trace_id = 0;
+ size_t span_index = 0;
+ };
+
+ auto ensure_return_breakpoint(uint64_t address) -> int32_t;
+ auto clear_return_breakpoints() -> void;
+
+ struct PendingCall
+ {
+ uint32_t trace_id = 0;
+ uint64_t thread_id = 0;
+ uint64_t return_pc = 0;
+ uint64_t frame_sp = 0;
+ double start = 0.0;
+ size_t call_index = 0;
+ size_t span_index = 0;
+ };
+
std::unique_ptr<Session> m_session;
TargetState m_state = TargetState::NoTarget;
@@ -129,6 +186,10 @@ namespace Hsdbg
std::vector<FunctionTrace> m_traces;
uint32_t m_next_trace_id = 1;
+ std::vector<PendingCall> m_pending_calls;
+ std::vector<TimelineSpan> m_timeline;
+
+ std::unordered_map<uint64_t, int32_t> m_return_breakpoints;
std::vector<Thread> m_threads;
std::vector<StackFrame> m_call_stack;
@@ -147,5 +208,23 @@ namespace Hsdbg
uint64_t m_resident_memory = 0;
std::chrono::steady_clock::time_point m_trace_epoch = std::chrono::steady_clock::now();
+
+ bool m_instr_checked = false;
+ bool m_instr_available = false;
+ uint64_t m_instr_head_addr = 0;
+ uint64_t m_instr_records_addr = 0;
+ uint64_t m_instr_capacity = 0;
+ uint64_t m_instr_read_count = 0;
+ uint64_t m_instr_base_ns = 0;
+ bool m_instr_base_set = false;
+ std::unordered_map<uint64_t, uint32_t> m_instr_functions;
+ std::unordered_map<uint32_t, std::string> m_instr_names;
+ std::unordered_map<uint64_t, std::vector<InstrOpenCall>> m_instr_stacks;
+
+ bool m_sampling_enabled = false;
+ bool m_sample_pending = false;
+ std::chrono::steady_clock::time_point m_sample_last{};
+ std::unordered_map<std::string, uint32_t> m_sample_functions;
+ std::unordered_map<uint64_t, std::vector<OpenSample>> m_sample_stacks;
};
}