[Lldb-commits] [lldb] [llvm] [lldb][telemetry] Implement LLDB Telemetry (part 1) (PR #119716)
via lldb-commits
lldb-commits at lists.llvm.org
Thu Dec 12 07:53:53 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: Vy Nguyen (oontvoo)
<details>
<summary>Changes</summary>
Details:
- This is a subset of PR/98528.( Pavel's suggestion was to split up the patch to make reviewing easier)
- This contains only the concrete implementation of the framework to be used but no usages yet.
- I plan to send two follow-up patches:
+ part2 : includes changes in the plugin-manager to set up the plugin stuff.
+ part3 : includes changes in LLDB/LLDB-DAP to use the framework
Note: Please ignore all changes under llvm/.... These will be reverted after the pending LLVM patch is submitted.
---
Patch is 32.79 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/119716.diff
9 Files Affected:
- (added) lldb/include/lldb/Core/Telemetry.h (+309)
- (modified) lldb/include/lldb/lldb-enumerations.h (+2-2)
- (modified) lldb/source/Core/CMakeLists.txt (+2)
- (added) lldb/source/Core/Telemetry.cpp (+338)
- (modified) lldb/test/CMakeLists.txt (+10-10)
- (added) llvm/include/llvm/Telemetry/Telemetry.h (+133)
- (modified) llvm/lib/CMakeLists.txt (+1)
- (added) llvm/lib/Telemetry/CMakeLists.txt (+6)
- (added) llvm/lib/Telemetry/Telemetry.cpp (+11)
``````````diff
diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h
new file mode 100644
index 00000000000000..241d957672b6ca
--- /dev/null
+++ b/lldb/include/lldb/Core/Telemetry.h
@@ -0,0 +1,309 @@
+//===-- Telemetry.h ----------------------------------------------*- C++
+//-*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_CORE_TELEMETRY_H
+#define LLDB_CORE_TELEMETRY_H
+
+#include <atomic>
+#include <chrono>
+#include <ctime>
+#include <memory>
+#include <optional>
+#include <string>
+#include <unordered_map>
+
+#include "lldb/Core/StructuredDataImpl.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/lldb-forward.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Telemetry/Telemetry.h"
+
+namespace lldb_private {
+
+using llvm::telemetry::Destination;
+using llvm::telemetry::KindType;
+using llvm::telemetry::Serializer;
+using llvm::telemetry::TelemetryInfo;
+
+struct LldbEntryKind : public ::llvm::telemetry::EntryKind {
+ static const KindType BaseInfo = 0b11000;
+ static const KindType DebuggerInfo = 0b11001;
+ static const KindType TargetInfo = 0b11010;
+ static const KindType ClientInfo = 0b11100;
+ static const KindType CommandInfo = 0b11101;
+ static const KindType MiscInfo = 0b11110;
+};
+
+/// Defines a convenient type for timestamp of various events.
+/// This is used by the EventStats below.
+using SteadyTimePoint = std::chrono::time_point<std::chrono::steady_clock>;
+
+/// Various time (and possibly memory) statistics of an event.
+struct EventStats {
+ // REQUIRED: Start time of an event
+ SteadyTimePoint start;
+ // OPTIONAL: End time of an event - may be empty if not meaningful.
+ std::optional<SteadyTimePoint> end;
+ // TBD: could add some memory stats here too?
+
+ EventStats() = default;
+ EventStats(SteadyTimePoint start) : start(start) {}
+ EventStats(SteadyTimePoint start, SteadyTimePoint end)
+ : start(start), end(end) {}
+};
+
+/// Describes the exit signal of an event.
+struct ExitDescription {
+ int exit_code;
+ std::string description;
+};
+
+struct LldbBaseTelemetryInfo : public TelemetryInfo {
+ EventStats stats;
+
+ // For dyn_cast, isa, etc operations.
+ KindType getKind() const override { return LldbEntryKind::BaseInfo; }
+
+ static bool classof(const TelemetryInfo *t) {
+ if (t == nullptr)
+ return false;
+ // Subclasses of this is also acceptable.
+ return (t->getKind() & LldbEntryKind::BaseInfo) == LldbEntryKind::BaseInfo;
+ }
+
+ void serialize(Serializer &serializer) const override;
+};
+
+struct DebuggerTelemetryInfo : public LldbBaseTelemetryInfo {
+ std::string username;
+ std::string lldb_git_sha;
+ std::string lldb_path;
+ std::string cwd;
+
+ std::optional<ExitDescription> exit_desc;
+ DebuggerTelemetryInfo() = default;
+
+ // Provide a copy ctor because we may need to make a copy before
+ // sanitizing the data.
+ // (The sanitization might differ between different Destination classes).
+ DebuggerTelemetryInfo(const DebuggerTelemetryInfo &other) {
+ username = other.username;
+ lldb_git_sha = other.lldb_git_sha;
+ lldb_path = other.lldb_path;
+ cwd = other.cwd;
+ };
+
+ KindType getKind() const override { return LldbEntryKind::DebuggerInfo; }
+
+ static bool classof(const TelemetryInfo *T) {
+ if (T == nullptr)
+ return false;
+ return T->getKind() == LldbEntryKind::DebuggerInfo;
+ }
+
+ void serialize(Serializer &serializer) const override;
+};
+
+struct TargetTelemetryInfo : public LldbBaseTelemetryInfo {
+ lldb::ModuleSP exec_mod;
+ Target *target_ptr;
+
+ // The same as the executable-module's UUID.
+ std::string target_uuid;
+ std::string file_format;
+
+ std::string binary_path;
+ size_t binary_size;
+
+ std::optional<ExitDescription> exit_desc;
+ TargetTelemetryInfo() = default;
+
+ TargetTelemetryInfo(const TargetTelemetryInfo &other) {
+ exec_mod = other.exec_mod;
+ target_uuid = other.target_uuid;
+ file_format = other.file_format;
+ binary_path = other.binary_path;
+ binary_size = other.binary_size;
+ exit_desc = other.exit_desc;
+ }
+
+ KindType getKind() const override { return LldbEntryKind::TargetInfo; }
+
+ static bool classof(const TelemetryInfo *T) {
+ if (T == nullptr)
+ return false;
+ return T->getKind() == LldbEntryKind::TargetInfo;
+ }
+
+ void serialize(Serializer &serializer) const override;
+};
+
+// Entry from client (eg., SB-API)
+struct ClientTelemetryInfo : public LldbBaseTelemetryInfo {
+ std::string request_name;
+ std::string error_msg;
+
+ ClientTelemetryInfo() = default;
+
+ ClientTelemetryInfo(const ClientTelemetryInfo &other) {
+ request_name = other.request_name;
+ error_msg = other.error_msg;
+ }
+
+ KindType getKind() const override { return LldbEntryKind::ClientInfo; }
+
+ static bool classof(const TelemetryInfo *T) {
+ if (T == nullptr)
+ return false;
+ return T->getKind() == LldbEntryKind::ClientInfo;
+ }
+
+ void serialize(Serializer &serializer) const override;
+};
+
+struct CommandTelemetryInfo : public LldbBaseTelemetryInfo {
+ Target *target_ptr;
+ CommandReturnObject *result;
+
+ // If the command is/can be associated with a target entry,
+ // this field contains that target's UUID.
+ // <EMPTY> otherwise.
+ std::string target_uuid;
+ std::string command_uuid;
+
+ // Eg., "breakpoint set"
+ std::string command_name;
+
+ // !!NOTE!!: The following fields may be omitted due to PII risk.
+ // (Configurable via the telemery::Config struct)
+ std::string original_command;
+ std::string args;
+
+ std::optional<ExitDescription> exit_desc;
+ lldb::ReturnStatus ret_status;
+
+ CommandTelemetryInfo() = default;
+
+ CommandTelemetryInfo(const CommandTelemetryInfo &other) {
+ target_uuid = other.target_uuid;
+ command_uuid = other.command_uuid;
+ command_name = other.command_name;
+ original_command = other.original_command;
+ args = other.args;
+ exit_desc = other.exit_desc;
+ ret_status = other.ret_status;
+ }
+
+ KindType getKind() const override { return LldbEntryKind::CommandInfo; }
+
+ static bool classof(const TelemetryInfo *T) {
+ if (T == nullptr)
+ return false;
+ return T->getKind() == LldbEntryKind::CommandInfo;
+ }
+
+ void serialize(Serializer &serializer) const override;
+};
+
+/// The "catch-all" entry to store a set of custom/non-standard
+/// data.
+struct MiscTelemetryInfo : public LldbBaseTelemetryInfo {
+ /// If the event is/can be associated with a target entry,
+ /// this field contains that target's UUID.
+ /// <EMPTY> otherwise.
+ std::string target_uuid;
+
+ /// Set of key-value pairs for any optional (or impl-specific) data
+ std::map<std::string, std::string> meta_data;
+
+ MiscTelemetryInfo() = default;
+
+ MiscTelemetryInfo(const MiscTelemetryInfo &other) {
+ target_uuid = other.target_uuid;
+ meta_data = other.meta_data;
+ }
+
+ KindType getKind() const override { return LldbEntryKind::MiscInfo; }
+
+ static bool classof(const TelemetryInfo *T) {
+ if (T == nullptr)
+ return false;
+ return T->getKind() == LldbEntryKind::MiscInfo;
+ }
+
+ void serialize(Serializer &serializer) const override;
+};
+
+/// The base Telemetry manager instance in LLDB
+/// This class declares additional instrumentation points
+/// applicable to LLDB.
+class TelemetryManager : public llvm::telemetry::Manager {
+public:
+ /// Creates an instance of TelemetryManager.
+ /// This uses the plugin registry to find an instance:
+ /// - If a vendor supplies a implementation, it will use it.
+ /// - If not, it will either return a no-op instance or a basic
+ /// implementation for testing.
+ ///
+ /// See also lldb_private::TelemetryVendor.
+ static std::unique_ptr<TelemetryManager>
+ CreateInstance(std::unique_ptr<llvm::telemetry::Config> config,
+ Debugger *debugger);
+
+ /// To be invoked upon LLDB startup.
+ virtual void LogStartup(DebuggerTelemetryInfo *entry);
+
+ /// To be invoked upon LLDB exit.
+ virtual void LogExit(DebuggerTelemetryInfo *entry);
+
+ /// To be invoked upon loading the main executable module.
+ /// We log in a fire-n-forget fashion so that if the load
+ /// crashes, we don't lose the entry.
+ virtual void LogMainExecutableLoadStart(TargetTelemetryInfo *entry);
+ virtual void LogMainExecutableLoadEnd(TargetTelemetryInfo *entry);
+
+ /// To be invoked upon process exit.
+ virtual void LogProcessExit(TargetTelemetryInfo *entry);
+
+ /// Invoked for each command
+ /// We log in a fire-n-forget fashion so that if the command execution
+ /// crashes, we don't lose the entry.
+ virtual void LogCommandStart(CommandTelemetryInfo *entry);
+ virtual void LogCommandEnd(CommandTelemetryInfo *entry);
+
+ /// For client (eg., SB API) to send telemetry entries.
+ virtual void
+ LogClientTelemetry(const lldb_private::StructuredDataImpl &entry);
+
+ virtual std::string GetNextUUID() {
+ return std::to_string(uuid_seed.fetch_add(1));
+ }
+
+ llvm::Error dispatch(TelemetryInfo *entry) override;
+ void addDestination(std::unique_ptr<Destination> destination) override;
+
+protected:
+ TelemetryManager(std::unique_ptr<llvm::telemetry::Config> config,
+ Debugger *debugger);
+ TelemetryManager() = default;
+ virtual void CollectMiscBuildInfo();
+
+private:
+ std::atomic<size_t> uuid_seed = 0;
+ std::unique_ptr<llvm::telemetry::Config> m_config;
+ Debugger *m_debugger;
+ const std::string m_session_uuid;
+ std::vector<std::unique_ptr<Destination>> m_destinations;
+};
+
+} // namespace lldb_private
+#endif // LLDB_CORE_TELEMETRY_H
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 938f6e3abe8f2a..8015f42c5ffc8c 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -257,8 +257,8 @@ enum StopReason {
};
/// Command Return Status Types.
-enum ReturnStatus {
- eReturnStatusInvalid,
+enum ReturnStatus : int {
+ eReturnStatusInvalid = 0,
eReturnStatusSuccessFinishNoResult,
eReturnStatusSuccessFinishResult,
eReturnStatusSuccessContinuingNoResult,
diff --git a/lldb/source/Core/CMakeLists.txt b/lldb/source/Core/CMakeLists.txt
index dbc620b91b1ed1..4a02f7f1fc85e5 100644
--- a/lldb/source/Core/CMakeLists.txt
+++ b/lldb/source/Core/CMakeLists.txt
@@ -51,6 +51,7 @@ add_lldb_library(lldbCore
Section.cpp
SourceLocationSpec.cpp
SourceManager.cpp
+ Telemetry.cpp
StreamAsynchronousIO.cpp
ThreadedCommunication.cpp
UserSettingsController.cpp
@@ -94,6 +95,7 @@ add_lldb_library(lldbCore
Support
Demangle
TargetParser
+ Telemetry
)
add_dependencies(lldbCore
diff --git a/lldb/source/Core/Telemetry.cpp b/lldb/source/Core/Telemetry.cpp
new file mode 100644
index 00000000000000..5ddad030ef962e
--- /dev/null
+++ b/lldb/source/Core/Telemetry.cpp
@@ -0,0 +1,338 @@
+
+//===-- Telemetry.cpp -----------------------------------------------------===//
+//
+// 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 "lldb/Core/Telemetry.h"
+
+#include <chrono>
+#include <cstdlib>
+#include <ctime>
+#include <fstream>
+#include <memory>
+#include <string>
+#include <typeinfo>
+#include <utility>
+#include <vector>
+
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBProcess.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Statistics.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/UUID.h"
+#include "lldb/Version/Version.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/LineIterator.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/RandomNumberGenerator.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Telemetry/Telemetry.h"
+
+namespace lldb_private {
+
+using ::llvm::Error;
+using ::llvm::telemetry::Destination;
+using ::llvm::telemetry::TelemetryInfo;
+
+static size_t ToNanosecOrZero(const std::optional<SteadyTimePoint> &Point) {
+ if (!Point.has_value())
+ return 0;
+
+ return Point.value().time_since_epoch().count();
+}
+
+void LldbBaseTelemetryInfo::serialize(Serializer &serializer) const {
+ serializer.writeInt32("EntryKind", getKind());
+ serializer.writeString("SessionId", SessionId);
+}
+
+void DebuggerTelemetryInfo::serialize(Serializer &serializer) const {
+ LldbBaseTelemetryInfo::serialize(serializer);
+ serializer.writeString("username", username);
+ serializer.writeString("lldb_path", lldb_path);
+ serializer.writeString("cwd", cwd);
+ serializer.writeSizeT("start", stats.start.time_since_epoch().count());
+ serializer.writeSizeT("end", ToNanosecOrZero(stats.end));
+}
+
+void ClientTelemetryInfo::serialize(Serializer &serializer) const {
+ LldbBaseTelemetryInfo::serialize(serializer);
+ serializer.writeString("request_name", request_name);
+ serializer.writeString("error_msg", error_msg);
+ serializer.writeSizeT("start", stats.start.time_since_epoch().count());
+ serializer.writeSizeT("end", ToNanosecOrZero(stats.end));
+}
+
+void TargetTelemetryInfo::serialize(Serializer &serializer) const {
+ LldbBaseTelemetryInfo::serialize(serializer);
+ serializer.writeString("target_uuid", target_uuid);
+ serializer.writeString("binary_path", binary_path);
+ serializer.writeSizeT("binary_size", binary_size);
+}
+
+void CommandTelemetryInfo::serialize(Serializer &serializer) const {
+ LldbBaseTelemetryInfo::serialize(serializer);
+ serializer.writeString("target_uuid", target_uuid);
+ serializer.writeString("command_uuid", command_uuid);
+ serializer.writeString("args", args);
+ serializer.writeString("original_command", original_command);
+ serializer.writeSizeT("start", stats.start.time_since_epoch().count());
+ serializer.writeSizeT("end", ToNanosecOrZero(stats.end));
+
+ // If this entry was emitted at the end of the command-execution,
+ // then calculate the runtime too.
+ if (stats.end.has_value()) {
+ serializer.writeSizeT("command_runtime",
+ (stats.end.value() - stats.start).count());
+ if (exit_desc.has_value()) {
+ serializer.writeInt32("exit_code", exit_desc->exit_code);
+ serializer.writeString("exit_msg", exit_desc->description);
+ serializer.writeInt32("return_status", static_cast<int>(ret_status));
+ }
+ }
+}
+
+void MiscTelemetryInfo::serialize(Serializer &serializer) const {
+ LldbBaseTelemetryInfo::serialize(serializer);
+ serializer.writeString("target_uuid", target_uuid);
+ serializer.writeKeyValueMap("meta_data", meta_data);
+}
+
+static std::string MakeUUID(lldb_private::Debugger *debugger) {
+ std::string ret;
+ uint8_t random_bytes[16];
+ if (auto ec = llvm::getRandomBytes(random_bytes, 16)) {
+ LLDB_LOG(GetLog(LLDBLog::Object),
+ "Failed to generate random bytes for UUID: {0}", ec.message());
+ // fallback to using timestamp + debugger ID.
+ ret = std::to_string(
+ std::chrono::steady_clock::now().time_since_epoch().count()) +
+ "_" + std::to_string(debugger->GetID());
+ } else {
+ ret = lldb_private::UUID(random_bytes).GetAsString();
+ }
+
+ return ret;
+}
+
+TelemetryManager::TelemetryManager(
+ std::unique_ptr<llvm::telemetry::Config> config,
+ lldb_private::Debugger *debugger)
+ : m_config(std::move(config)), m_debugger(debugger),
+ m_session_uuid(MakeUUID(debugger)) {}
+
+std::unique_ptr<TelemetryManager> TelemetryManager::CreateInstance(
+ std::unique_ptr<llvm::telemetry::Config> config,
+ lldb_private::Debugger *debugger) {
+
+ TelemetryManager *ins = new TelemetryManager(std::move(config), debugger);
+
+ return std::unique_ptr<TelemetryManager>(ins);
+}
+
+llvm::Error TelemetryManager::dispatch(TelemetryInfo *entry) {
+ entry->SessionId = m_session_uuid;
+
+ for (auto &destination : m_destinations) {
+ llvm::Error err = destination->receiveEntry(entry);
+ if (err) {
+ return std::move(err);
+ }
+ }
+ return Error::success();
+}
+
+void TelemetryManager::addDestination(
+ std::unique_ptr<Destination> destination) {
+ m_destinations.push_back(std::move(destination));
+}
+
+void TelemetryManager::LogStartup(DebuggerTelemetryInfo *entry) {
+ UserIDResolver &resolver = lldb_private::HostInfo::GetUserIDResolver();
+ std::optional<llvm::StringRef> opt_username =
+ resolver.GetUserName(lldb_private::HostInfo::GetUserID());
+ if (opt_username)
+ entry->username = *opt_username;
+
+ entry->lldb_git_sha =
+ lldb_private::GetVersion(); // TODO: find the real git sha?
+
+ llvm::SmallString<64> cwd;
+ if (!llvm::sys::fs::current_path(cwd)) {
+ entry->cwd = cwd.c_str();
+ } else {
+ MiscTelemetryInfo misc_info;
+ misc_info.meta_data["internal_errors"] = "Cannot determine CWD";
+ if (auto er = dispatch(&misc_info)) {
+ LLDB_LOG(GetLog(LLDBLog::Object),
+ "Failed to dispatch misc-info from startup");
+ }
+ }
+
+ if (auto er = dispatch(entry)) {
+ LLDB_LOG(GetLog(LLDBLog::Object), "Failed to dispatch entry from startup");
+ }
+
+ // Optional part
+ CollectMiscBuildInfo();
+}
+
+void TelemetryManager::LogExit(DebuggerTelemetryInfo *entry) {
+ if (auto *selected_target =
+ m_debugger->GetSelectedExecutionContext().GetTargetPtr()) {
+ if (!selected_target->IsDummyTarget()) {
+ const lldb::ProcessSP proc = selected_target->GetProcessSP();
+ if (proc == nullptr) {
+ // no process has been launched yet.
+ entry->exit_desc = {-1, "no process launched."};
+ } else {
+ entry->exit_desc = {proc->GetExitStatus(), ""};
+ if (const char *description = proc->GetExitDescription())
+ entry->exit_desc->description = std::string(description);
+ }
+ }
+ }
+ dispatch(entry);
+}
+
+void TelemetryManager::LogProcessExit(TargetTelemetryInfo *entry) {
+ entry->target_uuid =
+ entry->target_ptr && !entry->target_ptr->IsDummyTarget()
+ ? entry->target_ptr->GetExecutableModule()->GetUUID().GetAsString()
+ : "";
+
+ dispatch(entry);
+}
+
+void TelemetryManager::CollectMiscBuildInfo() {
+ // collecting use-case specific data
+}
+
+void TelemetryManager::LogMainExecutableLoadStart(TargetTelemetryInfo *entry) {
+ entry->binary_path =
+ entry->exec_mod->GetFileSpec().GetPathAsConstString().GetCString();
+ entry->file_format = entry->exec_mod->GetArchitecture().GetArchitectureName();
+ entry->target_uuid = entry->exec_mod->GetUUID().GetAsString();
+ if (auto err = llvm::sys::fs::file_size(
+ entry->exec_mod->GetFileSpec().GetPath(), entry->binary_size)) {
+ // If there was error obtaining it, just reset the size to 0.
+ // Maybe log the error too?
+ entry->binary_size = 0;
+ }
+ dispatch(entry);
+}
+
+void TelemetryManager::LogMainExecutableLoadEnd(TargetTelemetryInfo *entry) {
+ lldb::ModuleSP exec_mod = entry->exec_mod;
+ entry->binary_path =
+ exec_mod->GetFileSpec().GetPathAsConstString().GetCString();
+ entry->file_format = exec_mod->GetArchitecture().GetArchitectureName();
+ entry->target_uuid = exec_mod->GetUUID().GetAsString();
+ entry->binary_size = exec_mod->GetObjectFile()->GetByteSize();
+
+ dispatch(entry);
+
+ // Collect some more info, might be useful?
+ MiscTelemetryInfo misc_info;
+ misc_info.target_uuid = exec_mod->GetUUID().GetAsString();
+ misc_info.m...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/119716
More information about the lldb-commits
mailing list