[intel-pt][trace] Implement a "get supported trace type" packet
authorWalter Erquinigo <a20012251@gmail.com>
Thu, 29 Oct 2020 19:44:13 +0000 (12:44 -0700)
committerWalter Erquinigo <a20012251@gmail.com>
Wed, 11 Nov 2020 18:35:58 +0000 (10:35 -0800)
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

21 files changed:
lldb/docs/lldb-gdb-remote.txt
lldb/include/lldb/Host/common/NativeProcessProtocol.h
lldb/include/lldb/Target/Process.h
lldb/include/lldb/Target/Trace.h
lldb/include/lldb/Utility/StringExtractorGDBRemote.h
lldb/include/lldb/Utility/TraceOptions.h
lldb/include/lldb/lldb-enumerations.h
lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
lldb/source/Plugins/Process/Linux/ProcessorTrace.cpp
lldb/source/Plugins/Process/Linux/ProcessorTrace.h
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
lldb/source/Utility/CMakeLists.txt
lldb/source/Utility/StringExtractorGDBRemote.cpp
lldb/source/Utility/TraceOptions.cpp [new file with mode: 0644]
lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp

index 276beed..91f6a4d 100644 (file)
@@ -235,8 +235,37 @@ send packet: QListThreadsInStopReply
 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
@@ -286,6 +315,8 @@ read packet: <trace id>/E<error code>;AAAAAAAAA
 //----------------------------------------------------------------------
 // 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
@@ -320,6 +351,8 @@ read packet: <OK response>/E<error code>;AAAAAAAAA
 //----------------------------------------------------------------------
 // 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
@@ -353,6 +386,8 @@ read packet: <binary trace data>/E<error code>;AAAAAAAAA
 //----------------------------------------------------------------------
 // jTraceMetaRead:
 //
+// This packet is deprecated.
+//
 // BRIEF
 //  Similar Packet as above except it reads meta data.
 //----------------------------------------------------------------------
@@ -360,6 +395,8 @@ read packet: <binary trace data>/E<error code>;AAAAAAAAA
 /----------------------------------------------------------------------
 // jTraceConfigRead:
 //
+// This packet is deprecated.
+//
 // BRIEF
 //  Request the trace configuration for the tracing instance with id
 //  <trace id>.
index 8bdad59..5be9cb6 100644 (file)
@@ -392,6 +392,11 @@ public:
     return Status("Not implemented");
   }
 
+  /// \copydoc Process::GetSupportedTraceType()
+  virtual llvm::Expected<TraceTypeInfo> GetSupportedTraceType() {
+    return llvm::make_error<UnimplementedError>();
+  }
+
 protected:
   struct SoftwareBreakpoint {
     uint32_t ref_count;
index 90172f3..a1a9760 100644 (file)
@@ -38,6 +38,7 @@
 #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"
@@ -47,6 +48,7 @@
 #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"
 
@@ -2542,6 +2544,17 @@ void PruneThreadPlans();
     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,
index 56e77d8..632a7b8 100644 (file)
@@ -32,6 +32,10 @@ namespace lldb_private {
 /// 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:
index efb4376..3b6ed80 100644 (file)
@@ -162,11 +162,13 @@ 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;
index 97aad33..c9a8d12 100644 (file)
 #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()) {}
@@ -57,4 +70,12 @@ private:
 };
 }
 
+namespace llvm {
+namespace json {
+
+bool fromJSON(const Value &value, lldb_private::TraceTypeInfo &info, Path path);
+
+} // namespace json
+} // namespace llvm
+
 #endif // LLDB_UTILITY_TRACEOPTIONS_H
index 8692dd8..061f385 100644 (file)
@@ -769,10 +769,11 @@ enum BasicType {
   eBasicTypeOther
 };
 
+/// Deprecated
 enum TraceType {
   eTraceTypeNone = 0,
 
-  // Hardware Trace generated by the processor.
+  /// Intel Processor Trace
   eTraceTypeProcessorTrace
 };
 
index 5d28737..9883e1c 100644 (file)
@@ -1995,6 +1995,12 @@ Status NativeProcessLinux::GetTraceConfig(lldb::user_id_t traceid,
   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) {
index ba953d3..b7d70a6 100644 (file)
@@ -117,6 +117,8 @@ public:
 
   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,
index 9bb01f2..1a8aa36 100644 (file)
@@ -26,6 +26,8 @@ using namespace process_linux;
 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
@@ -44,6 +46,27 @@ Status ProcessorTraceMonitor::GetTraceConfig(TraceOptions &config) const {
 #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
@@ -76,25 +99,15 @@ Status ProcessorTraceMonitor::StartTrace(lldb::pid_t pid, lldb::tid_t tid,
   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);
index de9bd8c..29f98cc 100644 (file)
@@ -93,6 +93,10 @@ class ProcessorTraceMonitor {
   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>
index dd0f698..d661423 100644 (file)
@@ -3454,6 +3454,32 @@ Status GDBRemoteCommunicationClient::SendGetMetaDataPacket(
   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) {
index 61acfad..af3755f 100644 (file)
@@ -22,6 +22,7 @@
 #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
@@ -519,6 +520,8 @@ public:
 
   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;
index 02b6ca4..2e57d7e 100644 (file)
@@ -191,6 +191,9 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
   RegisterMemberFunctionHandler(
       StringExtractorGDBRemote::eServerPacketType_jTraceConfigRead,
       &GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead);
+  RegisterMemberFunctionHandler(
+      StringExtractorGDBRemote::eServerPacketType_jLLDBTraceSupportedType,
+      &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupportedType);
 
   RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_g,
                                 &GDBRemoteCommunicationServerLLGS::Handle_g);
@@ -1227,6 +1230,33 @@ GDBRemoteCommunicationServerLLGS::Handle_jTraceStop(
 }
 
 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) {
 
index 2a2f4ad..ae8928c 100644 (file)
@@ -164,6 +164,8 @@ protected:
 
   PacketResult Handle_jTraceConfigRead(StringExtractorGDBRemote &packet);
 
+  PacketResult Handle_jLLDBTraceSupportedType(StringExtractorGDBRemote &packet);
+
   PacketResult Handle_QRestoreRegisterState(StringExtractorGDBRemote &packet);
 
   PacketResult Handle_vAttach(StringExtractorGDBRemote &packet);
index e8cc90e..0cd97ab 100644 (file)
@@ -1224,6 +1224,10 @@ Status ProcessGDBRemote::GetTraceConfig(lldb::user_id_t uid,
   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();
index ba96772..e47300f 100644 (file)
@@ -175,6 +175,8 @@ public:
                      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;
index 8757381..3aca72d 100644 (file)
@@ -65,6 +65,7 @@ add_lldb_library(lldbUtility
   StructuredData.cpp
   TildeExpressionResolver.cpp
   Timer.cpp
+  TraceOptions.cpp
   UnimplementedError.cpp
   UUID.cpp
   UriParser.cpp
index 2901500..def0968 100644 (file)
@@ -310,6 +310,8 @@ StringExtractorGDBRemote::GetServerPacketType() const {
       return eServerPacketType_jTraceStart;
     if (PACKET_STARTS_WITH("jTraceStop:"))
       return eServerPacketType_jTraceStop;
+    if (PACKET_MATCHES("jLLDBTraceSupportedType"))
+      return eServerPacketType_jLLDBTraceSupportedType;
     break;
 
   case 'v':
diff --git a/lldb/source/Utility/TraceOptions.cpp b/lldb/source/Utility/TraceOptions.cpp
new file mode 100644 (file)
index 0000000..292fb60
--- /dev/null
@@ -0,0 +1,25 @@
+//===-- 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
index 6fba1cb..d4f7b25 100644 (file)
@@ -362,6 +362,63 @@ TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfoInvalidResponse) {
   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;