From f62dda3ff7fb1fe87a2408ed4a466a4c3fc62eab Mon Sep 17 00:00:00 2001 From: Elias Bachaalany Date: Mon, 22 Jun 2026 23:54:44 -0500 Subject: [PATCH] fix(db_info): report real program metadata for the active program (#1) In headless mode (and any session where the client never issued an explicit OpenProgram), db_info reported program_name='active-program' with empty language_id/compiler_spec and image_base=0, because opened_program_ was never populated. The host does know the active program: GetRevision returns its path. db_info now resolves the active program from the revision and best-effort opens it to fill name/language/compiler/image_base, falling back to the real program path (not 'active-program') if the open fails. The analysis-query path is unchanged -- it already runs against the active program, so there is no regression. md5/sha256 stay empty: the host's OpenProgram response doesn't carry them. --- src/lib/src/source_libghidra.cpp | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/lib/src/source_libghidra.cpp b/src/lib/src/source_libghidra.cpp index 1875cea..5a412a4 100644 --- a/src/lib/src/source_libghidra.cpp +++ b/src/lib/src/source_libghidra.cpp @@ -1106,15 +1106,39 @@ class LibGhidraSource final : public Source { out.revision = to_i64(rev.value->modification_number); } + // The host knows the active program's path via the revision even when the client + // never issued an explicit OpenProgram (e.g. headless --binary, where the host binds + // the imported program as the active program). Use it so db_info reports the real + // program instead of the "active-program" placeholder. + std::string active_path = rev.ok() ? rev.value->program_path : std::string(); + if (active_path.empty()) { + active_path = options_.program_path; + } + + if (!opened_program_.has_value() && !active_path.empty()) { + // Best-effort open to populate language/compiler/image-base metadata. Non-fatal: + // analysis queries already run against the active program regardless of this. + libghidra::client::OpenProgramRequest req; + req.project_path = options_.project_path; + req.project_name = options_.project_name; + req.program_path = active_path; + req.read_only = options_.read_only; + auto opened = client_.OpenProgram(req); + if (opened.ok()) { + opened_program_ = *opened.value; + opened_project_ = true; + } + } + if (opened_program_.has_value()) { out.program_name = opened_program_->program_name; out.language_id = opened_program_->language_id; out.compiler_spec = opened_program_->compiler_spec; out.image_base = to_i64(opened_program_->image_base); } else { - out.program_name = options_.program_path.empty() ? "active-program" : options_.program_path; + out.program_name = active_path.empty() ? "active-program" : active_path; } - out.program_path = options_.program_path.empty() ? out.program_name : options_.program_path; + out.program_path = active_path.empty() ? out.program_name : active_path; last_error_.clear(); return true; }