[lldb] Contribute the GDB-remote packet history to diagnostics bundles (#210418)

Register a Diagnostics artifact provider from ProcessGDBRemote so a
diagnostics bundle captures the GDB-remote packet history, the same data
"process plugin packet history" prints.
This commit is contained in:
Jonas Devlieghere 2026-07-17 16:35:26 -07:00 committed by GitHub
parent ccd75bb4b9
commit ab6ef5680e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 132 additions and 0 deletions

View file

@ -33,6 +33,7 @@
#include "lldb/Breakpoint/WatchpointAlgorithms.h"
#include "lldb/Breakpoint/WatchpointResource.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Diagnostics.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
@ -102,6 +103,7 @@
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Chrono.h"
#include "llvm/Support/ErrorExtras.h"
#include "llvm/Support/FormatAdapters.h"
#include "llvm/Support/Threading.h"
@ -346,10 +348,29 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp,
m_use_g_packet_for_reading =
GetGlobalPluginProperties().GetUseGPacketForReading();
// Contribute the packet history to diagnostics bundles, named with the
// creation timestamp so files from different processes stay distinguishable.
if (Diagnostics::Enabled()) {
llvm::sys::TimePoint<> now = std::chrono::system_clock::now();
std::string name = llvm::formatv(
"gdb-remote-packet-history-{0:%Y-%m-%dT%H-%M-%S}.txt", now);
m_diagnostics_artifact_id = Diagnostics::Instance().AddArtifactProvider(
std::move(name), [this]() -> std::string {
StreamString stream;
DumpPluginHistory(stream);
return stream.GetString().str();
});
}
}
// Destructor
ProcessGDBRemote::~ProcessGDBRemote() {
// Unregister before teardown so a concurrent collection can't run the
// provider on a half-destroyed process.
if (m_diagnostics_artifact_id && Diagnostics::Enabled())
Diagnostics::Instance().RemoveArtifactProvider(*m_diagnostics_artifact_id);
// m_mach_process.UnregisterNotificationCallbacks (this);
Clear();
// We need to call finalize on the process before destroying ourselves to

View file

@ -16,6 +16,7 @@
#include <string>
#include <vector>
#include "lldb/Core/Diagnostics.h"
#include "lldb/Core/LoadedModuleInfoList.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/ThreadSafeValue.h"
@ -285,6 +286,9 @@ protected:
GDBRemoteCommunicationClient m_gdb_comm;
std::atomic<lldb::pid_t> m_debugserver_pid;
/// Registration for the packet-history diagnostics provider, if enabled.
std::optional<Diagnostics::ArtifactProviderID> m_diagnostics_artifact_id;
std::optional<StringExtractorGDBRemote> m_last_stop_packet;
std::recursive_mutex m_last_stop_packet_mutex;

View file

@ -5,6 +5,7 @@ add_lldb_unittest(ProcessGdbRemoteTests
GDBRemoteCommunicationServerTest.cpp
GDBRemoteCommunicationTest.cpp
GDBRemoteTestUtils.cpp
ProcessGDBRemoteTest.cpp
LINK_COMPONENTS
Support

View file

@ -0,0 +1,106 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
#include "Plugins/Platform/MacOSX/PlatformMacOSX.h"
#include "Plugins/Platform/MacOSX/PlatformRemoteMacOSX.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Diagnostics.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/TargetList.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/Listener.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
#include <mutex>
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_gdb_remote;
namespace {
class ProcessGDBRemoteDiagnosticsTest : public ::testing::Test {
public:
void SetUp() override {
FileSystem::Initialize();
HostInfo::Initialize();
PlatformMacOSX::Initialize();
static std::once_flag g_debugger_initialize_flag;
std::call_once(g_debugger_initialize_flag,
[] { Debugger::Initialize(nullptr); });
Diagnostics::Initialize();
}
void TearDown() override {
Diagnostics::Terminate();
PlatformMacOSX::Terminate();
HostInfo::Terminate();
FileSystem::Terminate();
}
};
} // namespace
// A ProcessGDBRemote registers a packet-history provider while alive and
// unregisters it when destroyed.
TEST_F(ProcessGDBRemoteDiagnosticsTest, PacketHistoryContributesToBundle) {
ArchSpec arch("x86_64-apple-macosx-");
Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
DebuggerSP debugger_sp = Debugger::CreateInstance();
ASSERT_TRUE(debugger_sp);
PlatformSP platform_sp;
TargetSP target_sp;
debugger_sp->GetTargetList().CreateTarget(
*debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);
ASSERT_TRUE(target_sp);
ListenerSP listener_sp = Listener::MakeListener("test-listener");
ProcessSP process_sp = ProcessGDBRemote::CreateInstance(
target_sp, listener_sp, /*crash_file_path=*/nullptr,
/*can_connect=*/true);
ASSERT_TRUE(process_sp);
// The provider's file is named with a timestamp, so match it by prefix.
auto has_packet_history = [](const std::vector<std::string> &files) {
return llvm::any_of(files, [](llvm::StringRef f) {
return f.starts_with("gdb-remote-packet-history-");
});
};
ExecutionContext exe_ctx;
// Alive: the provider contributes the history file.
{
llvm::Expected<FileSpec> dir = Diagnostics::CreateUniqueDirectory();
ASSERT_THAT_EXPECTED(dir, llvm::Succeeded());
llvm::Expected<Diagnostics::Report> report =
Diagnostics::Instance().Collect(*debugger_sp, exe_ctx, *dir);
ASSERT_THAT_EXPECTED(report, llvm::Succeeded());
EXPECT_TRUE(has_packet_history(report->attachments.files));
llvm::sys::fs::remove_directories(dir->GetPath());
}
// Destroyed: the provider is gone.
process_sp.reset();
{
llvm::Expected<FileSpec> dir = Diagnostics::CreateUniqueDirectory();
ASSERT_THAT_EXPECTED(dir, llvm::Succeeded());
llvm::Expected<Diagnostics::Report> report =
Diagnostics::Instance().Collect(*debugger_sp, exe_ctx, *dir);
ASSERT_THAT_EXPECTED(report, llvm::Succeeded());
EXPECT_FALSE(has_packet_history(report->attachments.files));
llvm::sys::fs::remove_directories(dir->GetPath());
}
}