diff options
| author | hachem <im@hachem.wtf> | 2025-09-26 16:58:48 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2025-09-26 16:58:48 +0200 |
| commit | 7e53abd75355caa817532c71a935b6a231b3cd9e (patch) | |
| tree | 61538f78ffa156bea4a85163eb604b4553856424 /src/debugger | |
| parent | 049e7e2aa15debb1ed112494681d7b3e28765679 (diff) | |
feat: attempt to add a profiler...didn't work
Diffstat (limited to 'src/debugger')
| -rw-r--r-- | src/debugger/debugger.cpp | 169 | ||||
| -rw-r--r-- | src/debugger/debugger.h | 20 | ||||
| -rw-r--r-- | src/debugger/types.h | 15 |
3 files changed, 204 insertions, 0 deletions
diff --git a/src/debugger/debugger.cpp b/src/debugger/debugger.cpp index e26bd46..132025a 100644 --- a/src/debugger/debugger.cpp +++ b/src/debugger/debugger.cpp @@ -14,6 +14,8 @@ #include <cstdlib> +#include <libproc.h> + namespace Hsdbg { namespace @@ -22,6 +24,8 @@ namespace Hsdbg #define HSDBG_LLVM_PREFIX "" #endif + constexpr size_t MAX_TRACE_CALLS = 200000; + auto set_environment(const char* name, const std::string& value) -> void { #ifdef HSDBG_WINDOWS @@ -708,6 +712,13 @@ namespace Hsdbg m_process_id = process.GetProcessID(); m_stop_reason = StopReason::None; + m_trace_epoch = std::chrono::steady_clock::now(); + for (FunctionTrace& trace : m_traces) + { + trace.call_count = 0; + trace.calls.clear(); + } + Log::info("debugger: launched '{}' as pid {}", m_target_path.filename().string(), m_process_id); @@ -1206,6 +1217,159 @@ namespace Hsdbg { pump_events(); sync_breakpoints(); + sample_process_stats(); + } + + auto Debugger::sample_process_stats() -> void + { + if (!is_alive(m_session->process)) + { + m_resident_memory = 0; + return; + } + + rusage_info_v2 usage{}; + if (proc_pid_rusage(static_cast<int>(m_process_id), RUSAGE_INFO_V2, + reinterpret_cast<rusage_info_t*>(&usage)) == 0) + { + m_resident_memory = usage.ri_resident_size; + } + } + + auto Debugger::trace_now() const -> double + { + const auto elapsed = std::chrono::steady_clock::now() - m_trace_epoch; + return std::chrono::duration<double>(elapsed).count(); + } + + auto Debugger::add_trace(std::string_view function) -> uint32_t + { + const auto existing = std::ranges::find_if(m_traces, [&](const FunctionTrace& candidate) + { + return candidate.function == function; + }); + + if (existing != m_traces.end()) + return existing->id; + + FunctionTrace trace; + trace.id = m_next_trace_id++; + trace.function = function; + + m_traces.push_back(std::move(trace)); + resolve_trace(m_traces.back()); + + Log::info("debugger: tracing {}()", m_traces.back().function); + + return m_traces.back().id; + } + + auto Debugger::resolve_trace(FunctionTrace& trace) -> void + { + if (!m_session->target.IsValid()) + return; + + lldb::SBBreakpoint created = m_session->target.BreakpointCreateByName( + trace.function.c_str(), m_session->target.GetExecutable().GetFilename()); + + if (!created.IsValid() || created.GetNumLocations() == 0) + { + Log::warn("debugger: could not trace {}()", trace.function); + return; + } + + created.SetEnabled(true); + trace.entry_backend_id = created.GetID(); + + Log::debug("debugger: trace on {}() ({} locations)", + trace.function, created.GetNumLocations()); + } + + auto Debugger::remove_trace(uint32_t id) -> bool + { + const auto entry = std::ranges::find(m_traces, id, &FunctionTrace::id); + if (entry == m_traces.end()) + return false; + + if (entry->entry_backend_id != 0 && m_session->target.IsValid()) + m_session->target.BreakpointDelete(entry->entry_backend_id); + + m_traces.erase(entry); + return true; + } + + auto Debugger::clear_traces() -> void + { + if (m_session->target.IsValid()) + { + for (const FunctionTrace& trace : m_traces) + { + if (trace.entry_backend_id != 0) + m_session->target.BreakpointDelete(trace.entry_backend_id); + } + } + + m_traces.clear(); + } + + auto Debugger::handle_trace_stop() -> bool + { + if (m_traces.empty()) + return false; + + bool any_trace = false; + bool any_other = false; + + const uint32_t thread_count = m_session->process.GetNumThreads(); + + for (uint32_t index = 0; index < thread_count; ++index) + { + lldb::SBThread thread = m_session->process.GetThreadAtIndex(index); + if (!thread.IsValid()) + continue; + + const lldb::StopReason reason = thread.GetStopReason(); + + if (reason == lldb::eStopReasonBreakpoint) + { + const size_t pairs = thread.GetStopReasonDataCount() / 2; + + for (size_t pair = 0; pair < pairs; ++pair) + { + const auto backend_id = + static_cast<int32_t>(thread.GetStopReasonDataAtIndex(pair * 2)); + + const auto trace = std::ranges::find(m_traces, backend_id, + &FunctionTrace::entry_backend_id); + + if (trace != m_traces.end() && backend_id != 0) + { + trace->call_count += 1; + + if (trace->calls.size() < MAX_TRACE_CALLS) + trace->calls.push_back(TraceCall{ trace_now(), 0.0 }); + + any_trace = true; + } + else + { + any_other = true; + } + } + } + else if (reason != lldb::eStopReasonNone && reason != lldb::eStopReasonInvalid) + { + any_other = true; + } + } + + if (any_trace && !any_other) + { + m_session->process.Continue(); + return true; + } + + return false; } auto Debugger::require_stopped() const -> Result<void> @@ -1270,7 +1434,12 @@ namespace Hsdbg case lldb::eStateStopped: if (m_state != TargetState::Stopped) + { + if (handle_trace_stop()) + break; + on_stopped(); + } break; diff --git a/src/debugger/debugger.h b/src/debugger/debugger.h index 06b6ae9..5e154b2 100644 --- a/src/debugger/debugger.h +++ b/src/debugger/debugger.h @@ -3,6 +3,7 @@ #include "core/result.h" #include "debugger/types.h" +#include <chrono> #include <cstdint> #include <filesystem> #include <memory> @@ -49,6 +50,11 @@ namespace Hsdbg auto find_breakpoint(uint32_t id) -> Breakpoint*; auto breakpoints() const -> std::span<const Breakpoint> { return m_breakpoints; } + auto add_trace(std::string_view function) -> uint32_t; + auto remove_trace(uint32_t id) -> bool; + auto clear_traces() -> void; + auto traces() const -> std::span<const FunctionTrace> { return m_traces; } + 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; } @@ -61,6 +67,8 @@ namespace Hsdbg auto read_memory(uint64_t address, size_t size) -> Result<std::vector<uint8_t>>; auto console_output() const -> std::span<const std::string> { return m_console_output; } + auto resident_memory() const -> uint64_t { return m_resident_memory; } + auto select_thread(uint64_t thread_id) -> bool; auto select_frame(uint32_t frame_index) -> bool; auto select_symbol(uint64_t file_address) -> bool; @@ -101,6 +109,12 @@ namespace Hsdbg auto refresh_source_files() -> void; auto refresh_disassembly() -> void; auto load_disassembly(uint64_t file_address) -> void; + auto sample_process_stats() -> void; + + auto resolve_trace(FunctionTrace& trace) -> void; + + auto handle_trace_stop() -> bool; + auto trace_now() const -> double; std::unique_ptr<Session> m_session; @@ -113,6 +127,9 @@ namespace Hsdbg std::vector<Breakpoint> m_breakpoints; uint32_t m_next_breakpoint_id = 1; + std::vector<FunctionTrace> m_traces; + uint32_t m_next_trace_id = 1; + std::vector<Thread> m_threads; std::vector<StackFrame> m_call_stack; std::vector<Variable> m_locals; @@ -127,5 +144,8 @@ namespace Hsdbg uint32_t m_selected_frame = 0; uint64_t m_selected_symbol = 0; uint64_t m_stop_count = 0; + uint64_t m_resident_memory = 0; + + std::chrono::steady_clock::time_point m_trace_epoch = std::chrono::steady_clock::now(); }; } diff --git a/src/debugger/types.h b/src/debugger/types.h index 8428c1d..c586665 100644 --- a/src/debugger/types.h +++ b/src/debugger/types.h @@ -148,4 +148,19 @@ namespace Hsdbg uint64_t address = 0; uint64_t size = 0; }; + + struct TraceCall + { + double start = 0.0; + double duration = 0.0; + }; + + struct FunctionTrace + { + uint32_t id = 0; + std::string function; + int32_t entry_backend_id = 0; + uint64_t call_count = 0; + std::vector<TraceCall> calls; + }; } |
