Implementation of remote packets for Trace data.

Summary:
The changes consist of new packets for trace manipulation and
trace collection. The new packets are also documented. The packets
are capable of providing custom trace specific parameters to start
tracing and also retrieve such configuration from the server.

Reviewers: clayborg, lldb-commits, tberghammer, labath, zturner

Reviewed By: clayborg, labath

Subscribers: krytarowski, lldb-commits

Differential Revision: https://reviews.llvm.org/D32585

llvm-svn: 303972
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 550ec0e..626ec66 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -30,7 +30,6 @@
 #include "lldb/Utility/JSON.h"
 #include "lldb/Utility/LLDBAssert.h"
 #include "lldb/Utility/Log.h"
-#include "lldb/Utility/StreamGDBRemote.h"
 #include "lldb/Utility/StreamString.h"
 
 // Project includes
@@ -3152,6 +3151,211 @@
          response.IsOKResponse();
 }
 
+lldb::user_id_t
+GDBRemoteCommunicationClient::SendStartTracePacket(const TraceOptions &options,
+                                                   Status &error) {
+  Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+  lldb::user_id_t ret_uid = LLDB_INVALID_UID;
+
+  StreamGDBRemote escaped_packet;
+  escaped_packet.PutCString("jTraceStart:");
+
+  StructuredData::Dictionary json_packet;
+  json_packet.AddIntegerItem("type", options.getType());
+  json_packet.AddIntegerItem("buffersize", options.getTraceBufferSize());
+  json_packet.AddIntegerItem("metabuffersize", options.getMetaDataBufferSize());
+
+  if (options.getThreadID() != LLDB_INVALID_THREAD_ID)
+    json_packet.AddIntegerItem("threadid", options.getThreadID());
+
+  StructuredData::DictionarySP custom_params = options.getTraceParams();
+  if (custom_params)
+    json_packet.AddItem("params", custom_params);
+
+  StreamString json_string;
+  json_packet.Dump(json_string, false);
+  escaped_packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize());
+
+  StringExtractorGDBRemote response;
+  if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
+                                   true) ==
+      GDBRemoteCommunication::PacketResult::Success) {
+    if (!response.IsNormalResponse()) {
+      error.SetError(response.GetError(), eErrorTypeGeneric);
+      LLDB_LOG(log, "Target does not support Tracing");
+    } else {
+      ret_uid = response.GetHexMaxU64(false, LLDB_INVALID_UID);
+    }
+  } else {
+    LLDB_LOG(log, "failed to send packet");
+    error.SetErrorStringWithFormat("failed to send packet: '%s'",
+                                   escaped_packet.GetData());
+  }
+  return ret_uid;
+}
+
+Status
+GDBRemoteCommunicationClient::SendStopTracePacket(lldb::user_id_t uid,
+                                                  lldb::tid_t thread_id) {
+  Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+  StringExtractorGDBRemote response;
+  Status error;
+
+  StructuredData::Dictionary json_packet;
+  StreamGDBRemote escaped_packet;
+  StreamString json_string;
+  escaped_packet.PutCString("jTraceStop:");
+
+  json_packet.AddIntegerItem("traceid", uid);
+
+  if (thread_id != LLDB_INVALID_THREAD_ID)
+    json_packet.AddIntegerItem("threadid", thread_id);
+
+  json_packet.Dump(json_string, false);
+
+  escaped_packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize());
+
+  if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
+                                   true) ==
+      GDBRemoteCommunication::PacketResult::Success) {
+    if (!response.IsOKResponse()) {
+      error.SetError(response.GetError(), eErrorTypeGeneric);
+      LLDB_LOG(log, "stop tracing failed");
+    }
+  } else {
+    LLDB_LOG(log, "failed to send packet");
+    error.SetErrorStringWithFormat(
+        "failed to send packet: '%s' with error '%d'", escaped_packet.GetData(),
+        response.GetError());
+  }
+  return error;
+}
+
+Status GDBRemoteCommunicationClient::SendGetDataPacket(
+    lldb::user_id_t uid, lldb::tid_t thread_id,
+    llvm::MutableArrayRef<uint8_t> &buffer, size_t offset) {
+  StreamGDBRemote escaped_packet;
+  escaped_packet.PutCString("jTraceBufferRead:");
+  return SendGetTraceDataPacket(escaped_packet, uid, thread_id, buffer, offset);
+}
+
+Status GDBRemoteCommunicationClient::SendGetMetaDataPacket(
+    lldb::user_id_t uid, lldb::tid_t thread_id,
+    llvm::MutableArrayRef<uint8_t> &buffer, size_t offset) {
+  StreamGDBRemote escaped_packet;
+  escaped_packet.PutCString("jTraceMetaRead:");
+  return SendGetTraceDataPacket(escaped_packet, uid, thread_id, buffer, offset);
+}
+
+Status
+GDBRemoteCommunicationClient::SendGetTraceConfigPacket(lldb::user_id_t uid,
+                                                       TraceOptions &options) {
+  Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+  StringExtractorGDBRemote response;
+  Status error;
+
+  StreamString json_string;
+  StreamGDBRemote escaped_packet;
+  escaped_packet.PutCString("jTraceConfigRead:");
+
+  StructuredData::Dictionary json_packet;
+  json_packet.AddIntegerItem("traceid", uid);
+
+  if (options.getThreadID() != LLDB_INVALID_THREAD_ID)
+    json_packet.AddIntegerItem("threadid", options.getThreadID());
+
+  json_packet.Dump(json_string, false);
+  escaped_packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize());
+
+  if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
+                                   true) ==
+      GDBRemoteCommunication::PacketResult::Success) {
+    if (response.IsNormalResponse()) {
+      uint64_t type = std::numeric_limits<uint64_t>::max();
+      uint64_t buffersize = std::numeric_limits<uint64_t>::max();
+      uint64_t metabuffersize = std::numeric_limits<uint64_t>::max();
+
+      auto json_object = StructuredData::ParseJSON(response.Peek());
+
+      if (!json_object ||
+          json_object->GetType() != StructuredData::Type::eTypeDictionary) {
+        error.SetErrorString("Invalid Configuration obtained");
+        return error;
+      }
+
+      auto json_dict = json_object->GetAsDictionary();
+
+      json_dict->GetValueForKeyAsInteger<uint64_t>("metabuffersize",
+                                                   metabuffersize);
+      options.setMetaDataBufferSize(metabuffersize);
+
+      json_dict->GetValueForKeyAsInteger<uint64_t>("buffersize", buffersize);
+      options.setTraceBufferSize(buffersize);
+
+      json_dict->GetValueForKeyAsInteger<uint64_t>("type", type);
+      options.setType(static_cast<lldb::TraceType>(type));
+
+      StructuredData::ObjectSP custom_params_sp =
+          json_dict->GetValueForKey("params");
+      if (custom_params_sp) {
+        if (custom_params_sp->GetType() !=
+            StructuredData::Type::eTypeDictionary) {
+          error.SetErrorString("Invalid Configuration obtained");
+          return error;
+        } else
+          options.setTraceParams(
+              static_pointer_cast<StructuredData::Dictionary>(
+                  custom_params_sp));
+      }
+    } else {
+      error.SetError(response.GetError(), eErrorTypeGeneric);
+    }
+  } else {
+    LLDB_LOG(log, "failed to send packet");
+    error.SetErrorStringWithFormat("failed to send packet: '%s'",
+                                   escaped_packet.GetData());
+  }
+  return error;
+}
+
+Status GDBRemoteCommunicationClient::SendGetTraceDataPacket(
+    StreamGDBRemote &packet, lldb::user_id_t uid, lldb::tid_t thread_id,
+    llvm::MutableArrayRef<uint8_t> &buffer, size_t offset) {
+  Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+  Status error;
+
+  StructuredData::Dictionary json_packet;
+
+  json_packet.AddIntegerItem("traceid", uid);
+  json_packet.AddIntegerItem("offset", offset);
+  json_packet.AddIntegerItem("buffersize", buffer.size());
+
+  if (thread_id != LLDB_INVALID_THREAD_ID)
+    json_packet.AddIntegerItem("threadid", thread_id);
+
+  StreamString json_string;
+  json_packet.Dump(json_string, false);
+
+  packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize());
+  StringExtractorGDBRemote response;
+  if (SendPacketAndWaitForResponse(packet.GetString(), response, true) ==
+      GDBRemoteCommunication::PacketResult::Success) {
+    if (response.IsNormalResponse()) {
+      size_t filled_size = response.GetHexBytesAvail(buffer);
+      buffer = llvm::MutableArrayRef<uint8_t>(buffer.data(), filled_size);
+    } else {
+      error.SetError(response.GetError(), eErrorTypeGeneric);
+      buffer = buffer.slice(buffer.size());
+    }
+  } else {
+    LLDB_LOG(log, "failed to send packet");
+    error.SetErrorStringWithFormat("failed to send packet: '%s'",
+                                   packet.GetData());
+    buffer = buffer.slice(buffer.size());
+  }
+  return error;
+}
+
 bool GDBRemoteCommunicationClient::GetModuleInfo(
     const FileSpec &module_file_spec, const lldb_private::ArchSpec &arch_spec,
     ModuleSpec &module_spec) {
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 08d0bd5..6306651 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -25,6 +25,7 @@
 #include "lldb/Core/ArchSpec.h"
 #include "lldb/Core/StructuredData.h"
 #include "lldb/Target/Process.h"
+#include "lldb/Utility/StreamGDBRemote.h"
 
 #include "llvm/ADT/Optional.h"
 
@@ -499,6 +500,21 @@
   ConfigureRemoteStructuredData(const ConstString &type_name,
                                 const StructuredData::ObjectSP &config_sp);
 
+  lldb::user_id_t SendStartTracePacket(const TraceOptions &options,
+                                       Status &error);
+
+  Status SendStopTracePacket(lldb::user_id_t uid, lldb::tid_t thread_id);
+
+  Status SendGetDataPacket(lldb::user_id_t uid, lldb::tid_t thread_id,
+                           llvm::MutableArrayRef<uint8_t> &buffer,
+                           size_t offset = 0);
+
+  Status SendGetMetaDataPacket(lldb::user_id_t uid, lldb::tid_t thread_id,
+                               llvm::MutableArrayRef<uint8_t> &buffer,
+                               size_t offset = 0);
+
+  Status SendGetTraceConfigPacket(lldb::user_id_t uid, TraceOptions &options);
+
 protected:
   LazyBool m_supports_not_sending_acks;
   LazyBool m_supports_thread_suffix;
@@ -587,6 +603,11 @@
       lldb::tid_t tid, StreamString &&payload,
       StringExtractorGDBRemote &response, bool send_async);
 
+  Status SendGetTraceDataPacket(StreamGDBRemote &packet, lldb::user_id_t uid,
+                                lldb::tid_t thread_id,
+                                llvm::MutableArrayRef<uint8_t> &buffer,
+                                size_t offset);
+
 private:
   DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationClient);
 };
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index ec7c2f5..0b3bbfe 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -183,6 +183,22 @@
       StringExtractorGDBRemote::eServerPacketType_QPassSignals,
       &GDBRemoteCommunicationServerLLGS::Handle_QPassSignals);
 
+  RegisterMemberFunctionHandler(
+      StringExtractorGDBRemote::eServerPacketType_jTraceStart,
+      &GDBRemoteCommunicationServerLLGS::Handle_jTraceStart);
+  RegisterMemberFunctionHandler(
+      StringExtractorGDBRemote::eServerPacketType_jTraceBufferRead,
+      &GDBRemoteCommunicationServerLLGS::Handle_jTraceRead);
+  RegisterMemberFunctionHandler(
+      StringExtractorGDBRemote::eServerPacketType_jTraceMetaRead,
+      &GDBRemoteCommunicationServerLLGS::Handle_jTraceRead);
+  RegisterMemberFunctionHandler(
+      StringExtractorGDBRemote::eServerPacketType_jTraceStop,
+      &GDBRemoteCommunicationServerLLGS::Handle_jTraceStop);
+  RegisterMemberFunctionHandler(
+      StringExtractorGDBRemote::eServerPacketType_jTraceConfigRead,
+      &GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead);
+
   RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_k,
                         [this](StringExtractorGDBRemote packet, Status &error,
                                bool &interrupt, bool &quit) {
@@ -1084,6 +1100,232 @@
 }
 
 GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jTraceStart(
+    StringExtractorGDBRemote &packet) {
+  Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+  // Fail if we don't have a current process.
+  if (!m_debugged_process_sp ||
+      (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID))
+    return SendErrorResponse(68);
+
+  if (!packet.ConsumeFront("jTraceStart:"))
+    return SendIllFormedResponse(packet, "jTraceStart: Ill formed packet ");
+
+  TraceOptions options;
+  uint64_t type = std::numeric_limits<uint64_t>::max();
+  uint64_t buffersize = std::numeric_limits<uint64_t>::max();
+  lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+  uint64_t metabuffersize = std::numeric_limits<uint64_t>::max();
+
+  auto json_object = StructuredData::ParseJSON(packet.Peek());
+
+  if (!json_object ||
+      json_object->GetType() != StructuredData::Type::eTypeDictionary)
+    return SendIllFormedResponse(packet, "jTraceStart: Ill formed packet ");
+
+  auto json_dict = json_object->GetAsDictionary();
+
+  json_dict->GetValueForKeyAsInteger<uint64_t>("metabuffersize",
+                                               metabuffersize);
+  options.setMetaDataBufferSize(metabuffersize);
+
+  json_dict->GetValueForKeyAsInteger<uint64_t>("buffersize", buffersize);
+  options.setTraceBufferSize(buffersize);
+
+  json_dict->GetValueForKeyAsInteger<uint64_t>("type", type);
+  options.setType(static_cast<lldb::TraceType>(type));
+
+  json_dict->GetValueForKeyAsInteger<uint64_t>("threadid", tid);
+  options.setThreadID(tid);
+
+  StructuredData::ObjectSP custom_params_sp =
+      json_dict->GetValueForKey("params");
+  if (custom_params_sp &&
+      custom_params_sp->GetType() != StructuredData::Type::eTypeDictionary)
+    return SendIllFormedResponse(packet, "jTraceStart: Ill formed packet ");
+
+  options.setTraceParams(
+      static_pointer_cast<StructuredData::Dictionary>(custom_params_sp));
+
+  if (buffersize == std::numeric_limits<uint64_t>::max() ||
+      type != lldb::TraceType::eTraceTypeProcessorTrace) {
+    LLDB_LOG(log, "Ill formed packet buffersize = {0} type = {1}", buffersize,
+             type);
+    return SendIllFormedResponse(packet, "JTrace:start: Ill formed packet ");
+  }
+
+  Status error;
+  lldb::user_id_t uid = LLDB_INVALID_UID;
+  uid = m_debugged_process_sp->StartTrace(options, error);
+  LLDB_LOG(log, "uid is {0} , error is {1}", uid, error.GetError());
+  if (error.Fail())
+    return SendErrorResponse(error.GetError());
+
+  StreamGDBRemote response;
+  response.Printf("%" PRIx64, uid);
+  return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jTraceStop(
+    StringExtractorGDBRemote &packet) {
+  // Fail if we don't have a current process.
+  if (!m_debugged_process_sp ||
+      (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID))
+    return SendErrorResponse(68);
+
+  if (!packet.ConsumeFront("jTraceStop:"))
+    return SendIllFormedResponse(packet, "jTraceStop: Ill formed packet ");
+
+  lldb::user_id_t uid = LLDB_INVALID_UID;
+  lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+
+  auto json_object = StructuredData::ParseJSON(packet.Peek());
+
+  if (!json_object ||
+      json_object->GetType() != StructuredData::Type::eTypeDictionary)
+    return SendIllFormedResponse(packet, "jTraceStop: Ill formed packet ");
+
+  auto json_dict = json_object->GetAsDictionary();
+
+  if (!json_dict->GetValueForKeyAsInteger<lldb::user_id_t>("traceid", uid))
+    return SendIllFormedResponse(packet, "jTraceStop: Ill formed packet ");
+
+  json_dict->GetValueForKeyAsInteger<lldb::tid_t>("threadid", tid);
+
+  Status error = m_debugged_process_sp->StopTrace(uid, tid);
+
+  if (error.Fail())
+    return SendErrorResponse(error.GetError());
+
+  return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead(
+    StringExtractorGDBRemote &packet) {
+
+  // Fail if we don't have a current process.
+  if (!m_debugged_process_sp ||
+      (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID))
+    return SendErrorResponse(68);
+
+  if (!packet.ConsumeFront("jTraceConfigRead:"))
+    return SendIllFormedResponse(packet,
+                                 "jTraceConfigRead: Ill formed packet ");
+
+  lldb::user_id_t uid = LLDB_INVALID_UID;
+  lldb::tid_t threadid = LLDB_INVALID_THREAD_ID;
+
+  auto json_object = StructuredData::ParseJSON(packet.Peek());
+
+  if (!json_object ||
+      json_object->GetType() != StructuredData::Type::eTypeDictionary)
+    return SendIllFormedResponse(packet,
+                                 "jTraceConfigRead: Ill formed packet ");
+
+  auto json_dict = json_object->GetAsDictionary();
+
+  if (!json_dict->GetValueForKeyAsInteger<lldb::user_id_t>("traceid", uid))
+    return SendIllFormedResponse(packet,
+                                 "jTraceConfigRead: Ill formed packet ");
+
+  json_dict->GetValueForKeyAsInteger<lldb::tid_t>("threadid", threadid);
+
+  TraceOptions options;
+  StreamGDBRemote response;
+
+  options.setThreadID(threadid);
+  Status error = m_debugged_process_sp->GetTraceConfig(uid, options);
+
+  if (error.Fail())
+    return SendErrorResponse(error.GetError());
+
+  StreamGDBRemote escaped_response;
+  StructuredData::Dictionary json_packet;
+
+  json_packet.AddIntegerItem("type", options.getType());
+  json_packet.AddIntegerItem("buffersize", options.getTraceBufferSize());
+  json_packet.AddIntegerItem("metabuffersize", options.getMetaDataBufferSize());
+
+  StructuredData::DictionarySP custom_params = options.getTraceParams();
+  if (custom_params)
+    json_packet.AddItem("params", custom_params);
+
+  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_jTraceRead(
+    StringExtractorGDBRemote &packet) {
+
+  // Fail if we don't have a current process.
+  if (!m_debugged_process_sp ||
+      (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID))
+    return SendErrorResponse(68);
+
+  enum PacketType { MetaData, BufferData };
+  PacketType tracetype = MetaData;
+
+  if (packet.ConsumeFront("jTraceBufferRead:"))
+    tracetype = BufferData;
+  else if (packet.ConsumeFront("jTraceMetaRead:"))
+    tracetype = MetaData;
+  else {
+    return SendIllFormedResponse(packet, "jTrace: Ill formed packet ");
+  }
+
+  lldb::user_id_t uid = LLDB_INVALID_UID;
+
+  size_t byte_count = std::numeric_limits<size_t>::max();
+  lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+  size_t offset = std::numeric_limits<size_t>::max();
+
+  auto json_object = StructuredData::ParseJSON(packet.Peek());
+
+  if (!json_object ||
+      json_object->GetType() != StructuredData::Type::eTypeDictionary)
+    return SendIllFormedResponse(packet, "jTrace: Ill formed packet ");
+
+  auto json_dict = json_object->GetAsDictionary();
+
+  if (!json_dict->GetValueForKeyAsInteger<lldb::user_id_t>("traceid", uid) ||
+      !json_dict->GetValueForKeyAsInteger<uint64_t>("offset", offset) ||
+      !json_dict->GetValueForKeyAsInteger<uint64_t>("buffersize", byte_count))
+    return SendIllFormedResponse(packet, "jTrace: Ill formed packet ");
+
+  json_dict->GetValueForKeyAsInteger<lldb::tid_t>("threadid", tid);
+
+  // Allocate the response buffer.
+  uint8_t *buffer = new (std::nothrow) uint8_t[byte_count];
+  if (buffer == nullptr)
+    return SendErrorResponse(0x78);
+
+  StreamGDBRemote response;
+  Status error;
+  llvm::MutableArrayRef<uint8_t> buf(buffer, byte_count);
+
+  if (tracetype == BufferData)
+    error = m_debugged_process_sp->GetData(uid, tid, buf, offset);
+  else if (tracetype == MetaData)
+    error = m_debugged_process_sp->GetMetaData(uid, tid, buf, offset);
+
+  if (error.Fail())
+    return SendErrorResponse(error.GetError());
+
+  for (size_t i = 0; i < buf.size(); ++i)
+    response.PutHex8(buf[i]);
+
+  StreamGDBRemote escaped_response;
+  escaped_response.PutEscapedBytes(response.GetData(), response.GetSize());
+  return SendPacketNoLock(escaped_response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
 GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo(
     StringExtractorGDBRemote &packet) {
   // Fail if we don't have a current process.
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
index ebda9a9..a7d7850 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -189,6 +189,14 @@
 
   PacketResult Handle_QSaveRegisterState(StringExtractorGDBRemote &packet);
 
+  PacketResult Handle_jTraceStart(StringExtractorGDBRemote &packet);
+
+  PacketResult Handle_jTraceRead(StringExtractorGDBRemote &packet);
+
+  PacketResult Handle_jTraceStop(StringExtractorGDBRemote &packet);
+
+  PacketResult Handle_jTraceConfigRead(StringExtractorGDBRemote &packet);
+
   PacketResult Handle_QRestoreRegisterState(StringExtractorGDBRemote &packet);
 
   PacketResult Handle_vAttach(StringExtractorGDBRemote &packet);
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 64684c5..aeb7c74 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -1236,6 +1236,32 @@
   return error;
 }
 
+lldb::user_id_t ProcessGDBRemote::StartTrace(const TraceOptions &options,
+                                             Status &error) {
+  return m_gdb_comm.SendStartTracePacket(options, error);
+}
+
+Status ProcessGDBRemote::StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) {
+  return m_gdb_comm.SendStopTracePacket(uid, thread_id);
+}
+
+Status ProcessGDBRemote::GetData(lldb::user_id_t uid, lldb::tid_t thread_id,
+                                 llvm::MutableArrayRef<uint8_t> &buffer,
+                                 size_t offset) {
+  return m_gdb_comm.SendGetDataPacket(uid, thread_id, buffer, offset);
+}
+
+Status ProcessGDBRemote::GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
+                                     llvm::MutableArrayRef<uint8_t> &buffer,
+                                     size_t offset) {
+  return m_gdb_comm.SendGetMetaDataPacket(uid, thread_id, buffer, offset);
+}
+
+Status ProcessGDBRemote::GetTraceConfig(lldb::user_id_t uid,
+                                        TraceOptions &options) {
+  return m_gdb_comm.SendGetTraceConfigPacket(uid, options);
+}
+
 void ProcessGDBRemote::DidExit() {
   // When we exit, disconnect from the GDB server communications
   m_gdb_comm.Disconnect();
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 60f0464..d7a4e96 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -31,6 +31,7 @@
 #include "lldb/Target/Thread.h"
 #include "lldb/Utility/ConstString.h"
 #include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamGDBRemote.h"
 #include "lldb/Utility/StreamString.h"
 #include "lldb/Utility/StringExtractor.h"
 #include "lldb/Utility/StringList.h"
@@ -177,6 +178,21 @@
 
   Status GetWatchpointSupportInfo(uint32_t &num) override;
 
+  lldb::user_id_t StartTrace(const TraceOptions &options,
+                             Status &error) override;
+
+  Status StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) override;
+
+  Status GetData(lldb::user_id_t uid, lldb::tid_t thread_id,
+                 llvm::MutableArrayRef<uint8_t> &buffer,
+                 size_t offset = 0) override;
+
+  Status GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
+                     llvm::MutableArrayRef<uint8_t> &buffer,
+                     size_t offset = 0) override;
+
+  Status GetTraceConfig(lldb::user_id_t uid, TraceOptions &options) override;
+
   Status GetWatchpointSupportInfo(uint32_t &num, bool &after) override;
 
   bool StartNoticingNewThreads() override;