Depends on D89283.
The goal of this packet (jTraceGetSupportedType) is to be able to query the gdb-server for the tracing technology that can work for the current debuggeer, which can make the user experience simpler but allowing the user to simply type
thread trace start
to start tracing the current thread without even telling the debugger to use "intel-pt", for example. Similarly, `thread trace start [args...]` would accept args beloging to the working trace type.
Also, if the user typed
help thread trace start
We could directly show the help information of the trace type that is supported for the target, or mention instead that no tracing is supported, if that's the case.
I added some simple tests, besides, when I ran this on my machine with intel-pt support, I got
$ process plugin packet send "jTraceSupportedType"
packet: jTraceSupportedType
response: {"description":"Intel Processor Trace","pluginName":"intel-pt"}
On a machine without intel-pt support, I got
$ process plugin packet send "jTraceSupportedType"
packet: jTraceSupportedType
response: E00;
Reviewed By: clayborg, labath
Differential Revision: https://reviews.llvm.org/D90490
read packet: OK
//----------------------------------------------------------------------
+// jLLDBTraceSupportedType
+//
+// BRIEF
+// Get the processor tracing type supported by the gdb-server for the current
+// inferior. Responses might be different depending on the architecture and
+// capabilities of the underlying OS.
+//
+// The return packet is a JSON object with the following schema
+//
+// {
+// "name": <tracing technology name, e.g. intel-pt, arm-coresight>
+// "description": <description string for this technology>
+// }
+//
+// If no tracing technology is supported for the inferior, or no process is
+// running, then an error should be returned.
+//
+// NOTE
+// This packet is used by Trace plug-ins (see lldb_private::Trace.h) to
+// do live tracing. Specifically, the name of the plug-in should match the name
+// of the tracing technology returned by this packet.
+//----------------------------------------------------------------------
+
+send packet: jLLDBTraceSupportedType
+read packet: {"name": <name>, "description", <description>}/E<error code>;AAAAAAAAA
+
+//----------------------------------------------------------------------
// jTraceStart:
//
+// This packet is deprecated.
+//
// BRIEF
// Packet for starting trace of type lldb::TraceType. The following
// parameters should be appended to the packet formatted as a JSON
//----------------------------------------------------------------------
// jTraceStop:
//
+// This packet is deprecated.
+//
// BRIEF
// Stop tracing instance with trace id <trace id>, of course trace
// needs to be started before. The following parameters should be
//----------------------------------------------------------------------
// jTraceBufferRead:
//
+// This packet is deprecated.
+//
// BRIEF
// Packet for reading the trace for tracing instance <trace id>, i.e the
// id obtained from StartTrace API. The following parameters should be
//----------------------------------------------------------------------
// jTraceMetaRead:
//
+// This packet is deprecated.
+//
// BRIEF
// Similar Packet as above except it reads meta data.
//----------------------------------------------------------------------
/----------------------------------------------------------------------
// jTraceConfigRead:
//
+// This packet is deprecated.
+//
// BRIEF
// Request the trace configuration for the tracing instance with id
// <trace id>.
return Status("Not implemented");
}
+ /// \copydoc Process::GetSupportedTraceType()
+ virtual llvm::Expected<TraceTypeInfo> GetSupportedTraceType() {
+ return llvm::make_error<UnimplementedError>();
+ }
+
protected:
struct SoftwareBreakpoint {
uint32_t ref_count;
#include "lldb/Target/QueueList.h"
#include "lldb/Target/ThreadList.h"
#include "lldb/Target/ThreadPlanStack.h"
+#include "lldb/Target/Trace.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/Broadcaster.h"
#include "lldb/Utility/Event.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StructuredData.h"
#include "lldb/Utility/TraceOptions.h"
+#include "lldb/Utility/UnimplementedError.h"
#include "lldb/Utility/UserIDResolver.h"
#include "lldb/lldb-private.h"
return Status("Not implemented");
}
+ /// Get the processor tracing type supported for this process.
+ /// Responses might be different depending on the architecture and
+ /// capabilities of the underlying OS.
+ ///
+ /// \return
+ /// The supported trace type or an \a llvm::Error if tracing is
+ /// not supported for the inferior.
+ virtual llvm::Expected<TraceTypeInfo> GetSupportedTraceType() {
+ return llvm::make_error<UnimplementedError>();
+ }
+
// This calls a function of the form "void * (*)(void)".
bool CallVoidArgVoidPtrReturn(const Address *address,
lldb::addr_t &returned_func,
/// Processor trace information can also be fetched through the process
/// interfaces during a live debug session if your process supports gathering
/// this information.
+///
+/// In order to support live tracing, the name of the plug-in should match the
+/// name of the tracing type returned by the gdb-remote packet
+/// \a jLLDBTraceSupportedType.
class Trace : public PluginInterface,
public std::enable_shared_from_this<Trace> {
public:
eServerPacketType__m,
eServerPacketType_notify, // '%' notification
- eServerPacketType_jTraceStart,
- eServerPacketType_jTraceBufferRead,
- eServerPacketType_jTraceMetaRead,
- eServerPacketType_jTraceStop,
- eServerPacketType_jTraceConfigRead,
+ eServerPacketType_jTraceStart, // deprecated
+ eServerPacketType_jTraceBufferRead, // deprecated
+ eServerPacketType_jTraceMetaRead, // deprecated
+ eServerPacketType_jTraceStop, // deprecated
+ eServerPacketType_jTraceConfigRead, // deprecated
+
+ eServerPacketType_jLLDBTraceSupportedType,
};
ServerPacketType GetServerPacketType() const;
#include "lldb/Utility/StructuredData.h"
namespace lldb_private {
+
+/// This struct represents a tracing technology.
+struct TraceTypeInfo {
+ /// The name of the technology, e.g. intel-pt or arm-coresight.
+ ///
+ /// In order for a Trace plug-in (see \a lldb_private::Trace.h) to support the
+ /// trace technology given by this struct, it should match its name with this
+ /// field.
+ std::string name;
+ /// A description for the technology.
+ std::string description;
+};
+
class TraceOptions {
public:
TraceOptions() : m_trace_params(new StructuredData::Dictionary()) {}
};
}
+namespace llvm {
+namespace json {
+
+bool fromJSON(const Value &value, lldb_private::TraceTypeInfo &info, Path path);
+
+} // namespace json
+} // namespace llvm
+
#endif // LLDB_UTILITY_TRACEOPTIONS_H
eBasicTypeOther
};
+/// Deprecated
enum TraceType {
eTraceTypeNone = 0,
- // Hardware Trace generated by the processor.
+ /// Intel Processor Trace
eTraceTypeProcessorTrace
};
return error;
}
+llvm::Expected<TraceTypeInfo> NativeProcessLinux::GetSupportedTraceType() {
+ if (ProcessorTraceMonitor::IsSupported())
+ return TraceTypeInfo{"intel-pt", "Intel Processor Trace"};
+ return NativeProcessProtocol::GetSupportedTraceType();
+}
+
lldb::user_id_t
NativeProcessLinux::StartTraceGroup(const TraceOptions &config,
Status &error) {
Status GetTraceConfig(lldb::user_id_t traceid, TraceOptions &config) override;
+ virtual llvm::Expected<TraceTypeInfo> GetSupportedTraceType() override;
+
// Interface used by NativeRegisterContext-derived classes.
static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr,
void *data = nullptr, size_t data_size = 0,
using namespace llvm;
lldb::user_id_t ProcessorTraceMonitor::m_trace_num = 1;
+const char *kOSEventIntelPTTypeFile =
+ "/sys/bus/event_source/devices/intel_pt/type";
Status ProcessorTraceMonitor::GetTraceConfig(TraceOptions &config) const {
#ifndef PERF_ATTR_SIZE_VER5
#endif
}
+Expected<uint32_t> ProcessorTraceMonitor::GetOSEventType() {
+ auto intel_pt_type_text =
+ llvm::MemoryBuffer::getFileAsStream(kOSEventIntelPTTypeFile);
+
+ if (!intel_pt_type_text)
+ return createStringError(inconvertibleErrorCode(),
+ "Can't open the file '%s'",
+ kOSEventIntelPTTypeFile);
+
+ uint32_t intel_pt_type = 0;
+ StringRef buffer = intel_pt_type_text.get()->getBuffer();
+ if (buffer.trim().getAsInteger(10, intel_pt_type))
+ return createStringError(
+ inconvertibleErrorCode(),
+ "The file '%s' has a invalid value. It should be an unsigned int.",
+ kOSEventIntelPTTypeFile);
+ return intel_pt_type;
+}
+
+bool ProcessorTraceMonitor::IsSupported() { return (bool)GetOSEventType(); }
+
Status ProcessorTraceMonitor::StartTrace(lldb::pid_t pid, lldb::tid_t tid,
const TraceOptions &config) {
#ifndef PERF_ATTR_SIZE_VER5
attr.exclude_idle = 1;
attr.mmap = 1;
- int intel_pt_type = 0;
-
- auto ret = llvm::MemoryBuffer::getFileAsStream(
- "/sys/bus/event_source/devices/intel_pt/type");
- if (!ret) {
- LLDB_LOG(log, "failed to open Config file");
- return ret.getError();
- }
+ Expected<uint32_t> intel_pt_type = GetOSEventType();
- StringRef rest = ret.get()->getBuffer();
- if (rest.empty() || rest.trim().getAsInteger(10, intel_pt_type)) {
- LLDB_LOG(log, "failed to read Config file");
- error.SetErrorString("invalid file");
+ if (!intel_pt_type) {
+ error = intel_pt_type.takeError();
return error;
}
- rest.trim().getAsInteger(10, intel_pt_type);
- LLDB_LOG(log, "intel pt type {0}", intel_pt_type);
- attr.type = intel_pt_type;
+ LLDB_LOG(log, "intel pt type {0}", *intel_pt_type);
+ attr.type = *intel_pt_type;
LLDB_LOG(log, "meta buffer size {0}", metabufsize);
LLDB_LOG(log, "buffer size {0} ", bufsize);
void SetThreadID(lldb::tid_t tid) { m_thread_id = tid; }
public:
+ static llvm::Expected<uint32_t> GetOSEventType();
+
+ static bool IsSupported();
+
static Status GetCPUType(TraceOptions &config);
static llvm::Expected<ProcessorTraceMonitorUP>
return SendGetTraceDataPacket(escaped_packet, uid, thread_id, buffer, offset);
}
+llvm::Expected<TraceTypeInfo>
+GDBRemoteCommunicationClient::SendGetSupportedTraceType() {
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+
+ StreamGDBRemote escaped_packet;
+ escaped_packet.PutCString("jLLDBTraceSupportedType");
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
+ true) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (!response.IsNormalResponse())
+ return response.GetStatus().ToError();
+
+ if (llvm::Expected<TraceTypeInfo> type =
+ llvm::json::parse<TraceTypeInfo>(response.Peek()))
+ return *type;
+ else
+ return type.takeError();
+ }
+ LLDB_LOG(log, "failed to send packet: jLLDBTraceSupportedType");
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "failed to send packet: jLLDBTraceSupportedType");
+}
+
Status
GDBRemoteCommunicationClient::SendGetTraceConfigPacket(lldb::user_id_t uid,
TraceOptions &options) {
#include "lldb/Utility/GDBRemote.h"
#include "lldb/Utility/ProcessInfo.h"
#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/TraceOptions.h"
#if defined(_WIN32)
#include "lldb/Host/windows/PosixApi.h"
#endif
Status SendGetTraceConfigPacket(lldb::user_id_t uid, TraceOptions &options);
+ llvm::Expected<TraceTypeInfo> SendGetSupportedTraceType();
+
protected:
LazyBool m_supports_not_sending_acks;
LazyBool m_supports_thread_suffix;
RegisterMemberFunctionHandler(
StringExtractorGDBRemote::eServerPacketType_jTraceConfigRead,
&GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jLLDBTraceSupportedType,
+ &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupportedType);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_g,
&GDBRemoteCommunicationServerLLGS::Handle_g);
}
GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupportedType(
+ StringExtractorGDBRemote &packet) {
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(Status("Process not running."));
+
+ llvm::Expected<TraceTypeInfo> supported_trace_type =
+ m_debugged_process_up->GetSupportedTraceType();
+ if (!supported_trace_type)
+ return SendErrorResponse(supported_trace_type.takeError());
+
+ StreamGDBRemote escaped_response;
+ StructuredData::Dictionary json_packet;
+
+ json_packet.AddStringItem("name", supported_trace_type->name);
+ json_packet.AddStringItem("description", supported_trace_type->description);
+
+ StreamString json_string;
+ json_packet.Dump(json_string, false);
+ escaped_response.PutEscapedBytes(json_string.GetData(),
+ json_string.GetSize());
+ return SendPacketNoLock(escaped_response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead(
StringExtractorGDBRemote &packet) {
PacketResult Handle_jTraceConfigRead(StringExtractorGDBRemote &packet);
+ PacketResult Handle_jLLDBTraceSupportedType(StringExtractorGDBRemote &packet);
+
PacketResult Handle_QRestoreRegisterState(StringExtractorGDBRemote &packet);
PacketResult Handle_vAttach(StringExtractorGDBRemote &packet);
return m_gdb_comm.SendGetTraceConfigPacket(uid, options);
}
+llvm::Expected<TraceTypeInfo> ProcessGDBRemote::GetSupportedTraceType() {
+ return m_gdb_comm.SendGetSupportedTraceType();
+}
+
void ProcessGDBRemote::DidExit() {
// When we exit, disconnect from the GDB server communications
m_gdb_comm.Disconnect();
llvm::MutableArrayRef<uint8_t> &buffer,
size_t offset = 0) override;
+ llvm::Expected<TraceTypeInfo> GetSupportedTraceType() override;
+
Status GetTraceConfig(lldb::user_id_t uid, TraceOptions &options) override;
Status GetWatchpointSupportInfo(uint32_t &num, bool &after) override;
StructuredData.cpp
TildeExpressionResolver.cpp
Timer.cpp
+ TraceOptions.cpp
UnimplementedError.cpp
UUID.cpp
UriParser.cpp
return eServerPacketType_jTraceStart;
if (PACKET_STARTS_WITH("jTraceStop:"))
return eServerPacketType_jTraceStop;
+ if (PACKET_MATCHES("jLLDBTraceSupportedType"))
+ return eServerPacketType_jLLDBTraceSupportedType;
break;
case 'v':
--- /dev/null
+//===-- TraceOptions.cpp ----------------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/TraceOptions.h"
+
+using namespace lldb_private;
+
+namespace llvm {
+namespace json {
+
+bool fromJSON(const Value &value, TraceTypeInfo &info, Path path) {
+ ObjectMapper o(value, path);
+ if (!o)
+ return false;
+ o.map("description", info.description);
+ return o.map("name", info.name);
+}
+
+} // namespace json
+} // namespace llvm
EXPECT_FALSE(result.get().Success());
}
+TEST_F(GDBRemoteCommunicationClientTest, SendTraceSupportedTypePacket) {
+ // Success response
+ {
+ std::future<llvm::Expected<TraceTypeInfo>> result = std::async(
+ std::launch::async, [&] { return client.SendGetSupportedTraceType(); });
+
+ HandlePacket(
+ server, "jLLDBTraceSupportedType",
+ R"({"name":"intel-pt","description":"Intel Processor Trace"}])");
+
+ llvm::Expected<TraceTypeInfo> trace_type_or_err = result.get();
+ EXPECT_THAT_EXPECTED(trace_type_or_err, llvm::Succeeded());
+ ASSERT_STREQ(trace_type_or_err->name.c_str(), "intel-pt");
+ ASSERT_STREQ(trace_type_or_err->description.c_str(),
+ "Intel Processor Trace");
+ }
+
+ // Error response - wrong json
+ {
+ std::future<llvm::Expected<TraceTypeInfo>> result = std::async(
+ std::launch::async, [&] { return client.SendGetSupportedTraceType(); });
+
+ HandlePacket(server, "jLLDBTraceSupportedType", R"({"type":"intel-pt"}])");
+
+ llvm::Expected<TraceTypeInfo> trace_type_or_err = result.get();
+ ASSERT_THAT_EXPECTED(
+ trace_type_or_err,
+ llvm::Failed<StringError>(testing::Property(
+ &StringError::getMessage,
+ testing::HasSubstr("missing value at (root).name"))));
+ }
+
+ // Error response
+ {
+ std::future<llvm::Expected<TraceTypeInfo>> result = std::async(
+ std::launch::async, [&] { return client.SendGetSupportedTraceType(); });
+
+ HandlePacket(server, "jLLDBTraceSupportedType", "E23");
+ llvm::Expected<TraceTypeInfo> trace_type_or_err = result.get();
+ ASSERT_THAT_EXPECTED(trace_type_or_err, llvm::Failed());
+ }
+
+ // Error response with error message
+ {
+ std::future<llvm::Expected<TraceTypeInfo>> result = std::async(
+ std::launch::async, [&] { return client.SendGetSupportedTraceType(); });
+
+ HandlePacket(server, "jLLDBTraceSupportedType",
+ "E23;50726F63657373206E6F742072756E6E696E672E");
+ llvm::Expected<TraceTypeInfo> trace_type_or_err = result.get();
+ ASSERT_THAT_EXPECTED(trace_type_or_err,
+ llvm::Failed<StringError>(testing::Property(
+ &StringError::getMessage,
+ testing::HasSubstr("Process not running."))));
+ }
+}
+
TEST_F(GDBRemoteCommunicationClientTest, SendStartTracePacket) {
TraceOptions options;
Status error;