ravitheja updated this revision to Diff 98599.
ravitheja added a comment.

Changes for the feedback recieved in first round of review.


https://reviews.llvm.org/D32585

Files:
  docs/lldb-gdb-remote.txt
  include/lldb/API/SBTrace.h
  include/lldb/Core/TraceOptions.h
  include/lldb/Host/common/NativeProcessProtocol.h
  include/lldb/Target/Process.h
  include/lldb/Utility/StringExtractor.h
  source/API/SBProcess.cpp
  source/API/SBTrace.cpp
  source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
  source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
  source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
  source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
  source/Utility/StringExtractor.cpp
  source/Utility/StringExtractorGDBRemote.cpp
  source/Utility/StringExtractorGDBRemote.h

Index: source/Utility/StringExtractorGDBRemote.h
===================================================================
--- source/Utility/StringExtractorGDBRemote.h
+++ source/Utility/StringExtractorGDBRemote.h
@@ -164,6 +164,12 @@
     eServerPacketType__M,
     eServerPacketType__m,
     eServerPacketType_notify, // '%' notification
+
+    eServerPacketType_JTrace_Start,
+    eServerPacketType_jTraceBufferRead,
+    eServerPacketType_jTraceMetaRead,
+    eServerPacketType_JTrace_Stop,
+    eServerPacketType_jTraceConfigRead,
   };
 
   ServerPacketType GetServerPacketType() const;
Index: source/Utility/StringExtractorGDBRemote.cpp
===================================================================
--- source/Utility/StringExtractorGDBRemote.cpp
+++ source/Utility/StringExtractorGDBRemote.cpp
@@ -279,13 +279,26 @@
     }
     break;
 
+  case 'J':
+    if (PACKET_STARTS_WITH("JTrace:start:"))
+      return eServerPacketType_JTrace_Start;
+    if (PACKET_STARTS_WITH("JTrace:stop:"))
+      return eServerPacketType_JTrace_Stop;
+    break;
+
   case 'j':
     if (PACKET_STARTS_WITH("jModulesInfo:"))
       return eServerPacketType_jModulesInfo;
     if (PACKET_MATCHES("jSignalsInfo"))
       return eServerPacketType_jSignalsInfo;
     if (PACKET_MATCHES("jThreadsInfo"))
       return eServerPacketType_jThreadsInfo;
+    if (PACKET_STARTS_WITH("jTrace:buffer:read:"))
+      return eServerPacketType_jTraceBufferRead;
+    if (PACKET_STARTS_WITH("jTrace:conf:read:"))
+      return eServerPacketType_jTraceConfigRead;
+    if (PACKET_STARTS_WITH("jTrace:meta:read:"))
+      return eServerPacketType_jTraceMetaRead;
     break;
 
   case 'v':
Index: source/Utility/StringExtractor.cpp
===================================================================
--- source/Utility/StringExtractor.cpp
+++ source/Utility/StringExtractor.cpp
@@ -280,6 +280,15 @@
   return result;
 }
 
+bool StringExtractor::Consume_front(const llvm::StringRef &str) {
+  llvm::StringRef S = GetStringRef();
+  if (!S.startswith(str))
+    return false;
+  else
+    m_index += str.size();
+  return true;
+}
+
 size_t StringExtractor::GetHexBytes(llvm::MutableArrayRef<uint8_t> dest,
                                     uint8_t fail_fill_value) {
   size_t bytes_extracted = 0;
Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
===================================================================
--- source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -175,6 +175,21 @@
 
   Error DisableWatchpoint(Watchpoint *wp, bool notify = true) override;
 
+  lldb::user_id_t StartTrace(const TraceOptions &options,
+                             Error &error) override;
+
+  Error StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) override;
+
+  Error GetData(lldb::user_id_t uid, lldb::tid_t thread_id,
+                llvm::MutableArrayRef<uint8_t> &buffer,
+                size_t offset = 0) override;
+
+  Error GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
+                    llvm::MutableArrayRef<uint8_t> &buffer,
+                    size_t offset = 0) override;
+
+  Error GetTraceConfig(lldb::user_id_t uid, TraceOptions &options) override;
+
   Error GetWatchpointSupportInfo(uint32_t &num) override;
 
   Error GetWatchpointSupportInfo(uint32_t &num, bool &after) override;
@@ -407,6 +422,10 @@
   std::map<uint64_t, uint32_t> m_thread_id_to_used_usec_map;
   uint64_t m_last_signals_version = 0;
 
+  Error GetTraceData(StreamString &packet, lldb::user_id_t uid,
+                     lldb::tid_t thread_id,
+                     llvm::MutableArrayRef<uint8_t> &buffer, size_t offset);
+
   static bool NewThreadNotifyBreakpointHit(void *baton,
                                            StoppointCallbackContext *context,
                                            lldb::user_id_t break_id,
Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
===================================================================
--- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -65,6 +65,7 @@
 #include "lldb/Target/ThreadPlanCallFunction.h"
 #include "lldb/Utility/CleanUp.h"
 #include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/StreamGDBRemote.h"
 #include "lldb/Utility/StreamString.h"
 
 // Project includes
@@ -1236,6 +1237,181 @@
   return error;
 }
 
+lldb::user_id_t ProcessGDBRemote::StartTrace(const TraceOptions &options,
+                                             Error &error) {
+
+  StreamString packet;
+  Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+  lldb::user_id_t ret_uid = LLDB_INVALID_UID;
+
+  packet.PutCString("JTrace:start:");
+  packet.Printf("type:%" PRIx32 ";", options.getType());
+  packet.Printf("buffersize:%" PRIx64 ";", options.getTraceBufferSize());
+  packet.Printf("metabuffersize:%" PRIx64 ";", options.getMetaDataBufferSize());
+
+  if (options.getThreadID() != LLDB_INVALID_THREAD_ID)
+    packet.Printf("threadid:%" PRIx64 ";", options.getThreadID());
+
+  StructuredData::DictionarySP custom_params = options.getTraceParams();
+  if (custom_params) {
+    packet.Printf("jparams:");
+    custom_params->Dump(packet, false);
+    packet.PutCString(";");
+  }
+  StreamGDBRemote escaped_packet;
+  escaped_packet.PutEscapedBytes(packet.GetData(), packet.GetSize());
+
+  StringExtractorGDBRemote response;
+  if (m_gdb_comm.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;
+}
+
+Error ProcessGDBRemote::StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) {
+  Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+  StringExtractorGDBRemote response;
+  Error error;
+
+  StreamString packet;
+  packet.PutCString("JTrace:stop:");
+  packet.Printf("traceid:%" PRIx64 ";", uid);
+
+  if (thread_id != LLDB_INVALID_THREAD_ID)
+    packet.Printf("threadid:%" PRIx64 ";", thread_id);
+
+  if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response,
+                                              true) ==
+      GDBRemoteCommunication::PacketResult::Success) {
+    if (!response.IsNormalResponse()) {
+      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'",
+                                   packet.GetData());
+  }
+  return error;
+}
+
+Error ProcessGDBRemote::GetTraceData(StreamString &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));
+  Error error;
+
+  packet.Printf("traceid:%" PRIx64 ";", uid);
+  packet.Printf("offset:%" PRIx64 ";", offset);
+  packet.Printf("buffersize:%" PRIx64 ";", buffer.size());
+
+  if (thread_id != LLDB_INVALID_THREAD_ID)
+    packet.Printf("threadid:%" PRIx64 ";", thread_id);
+
+  StringExtractorGDBRemote response;
+  if (m_gdb_comm.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;
+}
+
+Error ProcessGDBRemote::GetData(lldb::user_id_t uid, lldb::tid_t thread_id,
+                                llvm::MutableArrayRef<uint8_t> &buffer,
+                                size_t offset) {
+
+  StreamString packet;
+  packet.PutCString("jTrace:buffer:read:");
+  return GetTraceData(packet, uid, thread_id, buffer, offset);
+}
+
+Error ProcessGDBRemote::GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
+                                    llvm::MutableArrayRef<uint8_t> &buffer,
+                                    size_t offset) {
+  StreamString packet;
+  packet.PutCString("jTrace:meta:read:");
+  return GetTraceData(packet, uid, thread_id, buffer, offset);
+}
+
+Error ProcessGDBRemote::GetTraceConfig(lldb::user_id_t uid,
+                                       TraceOptions &options) {
+  Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+  StringExtractorGDBRemote response;
+  Error error;
+
+  StreamString packet;
+  packet.PutCString("jTrace:conf:read:");
+  packet.Printf("traceid:%" PRIx64 ";", uid);
+
+  if (options.getThreadID() != LLDB_INVALID_THREAD_ID)
+    packet.Printf("threadid:%" PRIx64 ";", options.getThreadID());
+
+  if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response,
+                                              true) ==
+      GDBRemoteCommunication::PacketResult::Success) {
+    if (response.IsNormalResponse()) {
+      llvm::StringRef name, value;
+      StructuredData::ObjectSP json_object;
+      while (response.GetNameColonValue(name, value)) {
+        uint64_t extracted_value;
+        value.getAsInteger(16, extracted_value);
+
+        if (name.equals("buffersize")) {
+          options.setTraceBufferSize(extracted_value);
+        } else if (name.equals("metabuffersize")) {
+          options.setMetaDataBufferSize(extracted_value);
+        } else if (name.equals("type")) {
+          options.setType(static_cast<lldb::TraceType>(extracted_value));
+        } else if (name.equals("jparams")) {
+          auto json_object = StructuredData::ParseJSON(value.data());
+          if (!json_object ||
+              json_object->GetType() != StructuredData::Type::eTypeDictionary) {
+            error.SetErrorString("Invalid Configuration obtained");
+            break;
+          }
+          options.setTraceParams(
+              std::static_pointer_cast<StructuredData::Dictionary>(
+                  json_object));
+        } else {
+          error.SetErrorString("Invalid Configuration obtained");
+          break;
+        }
+      }
+    } else {
+      error.SetError(response.GetError(), eErrorTypeGeneric);
+    }
+  } else {
+    LLDB_LOG(log, "failed to send packet");
+    error.SetErrorStringWithFormat("failed to send packet: '%s'",
+                                   packet.GetData());
+  }
+  return error;
+}
+
 void ProcessGDBRemote::DidExit() {
   // When we exit, disconnect from the GDB server communications
   m_gdb_comm.Disconnect();
Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
===================================================================
--- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -189,6 +189,14 @@
 
   PacketResult Handle_QSaveRegisterState(StringExtractorGDBRemote &packet);
 
+  PacketResult Handle_JTrace_start(StringExtractorGDBRemote &packet);
+
+  PacketResult Handle_jTrace_read(StringExtractorGDBRemote &packet);
+
+  PacketResult Handle_JTrace_stop(StringExtractorGDBRemote &packet);
+
+  PacketResult Handle_jTrace_conf_read(StringExtractorGDBRemote &packet);
+
   PacketResult Handle_QRestoreRegisterState(StringExtractorGDBRemote &packet);
 
   PacketResult Handle_vAttach(StringExtractorGDBRemote &packet);
Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
===================================================================
--- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -183,6 +183,22 @@
       StringExtractorGDBRemote::eServerPacketType_QPassSignals,
       &GDBRemoteCommunicationServerLLGS::Handle_QPassSignals);
 
+  RegisterMemberFunctionHandler(
+      StringExtractorGDBRemote::eServerPacketType_JTrace_Start,
+      &GDBRemoteCommunicationServerLLGS::Handle_JTrace_start);
+  RegisterMemberFunctionHandler(
+      StringExtractorGDBRemote::eServerPacketType_jTraceBufferRead,
+      &GDBRemoteCommunicationServerLLGS::Handle_jTrace_read);
+  RegisterMemberFunctionHandler(
+      StringExtractorGDBRemote::eServerPacketType_jTraceMetaRead,
+      &GDBRemoteCommunicationServerLLGS::Handle_jTrace_read);
+  RegisterMemberFunctionHandler(
+      StringExtractorGDBRemote::eServerPacketType_JTrace_Stop,
+      &GDBRemoteCommunicationServerLLGS::Handle_JTrace_stop);
+  RegisterMemberFunctionHandler(
+      StringExtractorGDBRemote::eServerPacketType_jTraceConfigRead,
+      &GDBRemoteCommunicationServerLLGS::Handle_jTrace_conf_read);
+
   RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_k,
                         [this](StringExtractorGDBRemote packet, Error &error,
                                bool &interrupt, bool &quit) {
@@ -1083,6 +1099,284 @@
 }
 
 GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_JTrace_start(
+    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.Consume_front("JTrace:start:"))
+    return SendIllFormedResponse(packet, "JTrace:start: 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();
+  bool error_encountered = false;
+
+  llvm::StringRef name, value;
+  StructuredData::ObjectSP json_object;
+
+  while (packet.GetNameColonValue(name, value)) {
+    uint64_t extracted_value;
+    value.getAsInteger(16, extracted_value);
+
+    if (name.equals("type"))
+      type = extracted_value;
+
+    else if (name.equals("threadid"))
+      tid = extracted_value;
+
+    else if (name.equals("buffersize"))
+      buffersize = extracted_value;
+
+    else if (name.equals("metabuffersize"))
+      metabuffersize = extracted_value;
+
+    else if (name.equals("jparams")) {
+      json_object = StructuredData::ParseJSON(value.data());
+    }
+
+    else {
+      error_encountered = true;
+      break;
+    }
+  }
+
+  if (!json_object ||
+      json_object->GetType() != StructuredData::Type::eTypeDictionary)
+    error_encountered = true;
+
+  if (error_encountered || buffersize == std::numeric_limits<uint64_t>::max() ||
+      type != lldb::TraceType::eTraceTypeProcessorTrace ||
+      packet.GetBytesLeft()) {
+    LLDB_LOG(log,
+             "Ill formed packet error_encountered = {0}  buffersize = {1} type "
+             "= {2} packet empty = { 3 } ",
+             error_encountered, buffersize, type, packet.Empty());
+    return SendIllFormedResponse(packet, "JTrace:start: Ill formed packet ");
+  }
+
+  options.setMetaDataBufferSize(metabuffersize);
+  options.setTraceBufferSize(buffersize);
+  options.setType(static_cast<lldb::TraceType>(type));
+  options.setThreadID(tid);
+  options.setTraceParams(
+      std::static_pointer_cast<StructuredData::Dictionary>(json_object));
+
+  Error error;
+  lldb::user_id_t uid = LLDB_INVALID_UID;
+  uid = m_debugged_process_sp->StartTrace(options, error);
+
+  if (error.Fail())
+    return SendErrorResponse(error.GetError());
+
+  StreamGDBRemote response;
+  response.Printf("%" PRIx64, uid);
+  return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_JTrace_stop(
+    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.Consume_front("JTrace:stop:"))
+    return SendIllFormedResponse(packet, "JTrace:stop: Ill formed packet ");
+
+  lldb::user_id_t uid = LLDB_INVALID_UID;
+  lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+  bool error_encountered = false;
+
+  llvm::StringRef name, value;
+  while (packet.GetNameColonValue(name, value)) {
+    uint64_t extracted_value;
+    if (!value.getAsInteger(16, extracted_value)) {
+      if (name.equals("threadid"))
+        tid = extracted_value;
+
+      else if (name.equals("traceid"))
+        uid = extracted_value;
+
+      else {
+        error_encountered = true;
+        break;
+      }
+    }
+
+    else {
+      error_encountered = true;
+      break;
+    }
+  }
+
+  if (error_encountered || uid == LLDB_INVALID_UID || packet.GetBytesLeft())
+    return SendIllFormedResponse(packet, "JTrace:stop: Ill formed packet ");
+
+  Error error = m_debugged_process_sp->StopTrace(uid, tid);
+
+  if (error.Fail())
+    return SendErrorResponse(error.GetError());
+
+  return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jTrace_conf_read(
+    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.Consume_front("jTrace:conf:read:"))
+    return SendIllFormedResponse(packet, "jTrace: Ill formed packet ");
+
+  lldb::user_id_t uid = LLDB_INVALID_UID;
+  lldb::tid_t threadid = LLDB_INVALID_THREAD_ID;
+  bool error_encountered = false;
+
+  llvm::StringRef name, value;
+  while (packet.GetNameColonValue(name, value)) {
+    uint64_t extracted_value;
+
+    if (!value.getAsInteger(16, extracted_value)) {
+      if (name.equals("threadid"))
+        threadid = extracted_value;
+
+      else if (name.equals("traceid"))
+        uid = extracted_value;
+
+      else {
+        error_encountered = true;
+        break;
+      }
+    } else {
+      error_encountered = true;
+      break;
+    }
+  }
+
+  if (error_encountered || uid == LLDB_INVALID_UID || packet.GetBytesLeft())
+    return SendIllFormedResponse(packet, "jTrace: Ill formed packet ");
+
+  TraceOptions options;
+  StreamGDBRemote response;
+
+  options.setThreadID(threadid);
+  Error error = m_debugged_process_sp->GetTraceConfig(uid, options);
+
+  if (error.Fail())
+    return SendErrorResponse(error.GetError());
+
+  response.Printf("type:%" PRIx32 ";", options.getType());
+  response.Printf("buffersize:%" PRIx64 ";", options.getTraceBufferSize());
+  response.Printf("metabuffersize:%" PRIx64 ";",
+                  options.getMetaDataBufferSize());
+
+  const StructuredData::DictionarySP custom_params = options.getTraceParams();
+  if (custom_params) {
+    response.Printf("jparams:");
+    custom_params->Dump(response, false);
+    response.PutChar(';');
+  }
+  StreamGDBRemote escaped_response;
+  escaped_response.PutEscapedBytes(response.GetData(), response.GetSize());
+  return SendPacketNoLock(escaped_response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jTrace_read(
+    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.Consume_front("jTrace:buffer:read:"))
+    tracetype = BufferData;
+  else if (packet.Consume_front("jTrace:meta:read:"))
+    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();
+  bool error_encountered = false;
+  llvm::StringRef name, value;
+
+  while (packet.GetNameColonValue(name, value)) {
+    uint64_t extracted_value;
+
+    if (!value.getAsInteger(16, extracted_value)) {
+      if (name.equals("buffersize"))
+        byte_count = extracted_value;
+
+      else if (name.equals("threadid"))
+        tid = extracted_value;
+
+      else if (name.equals("offset"))
+        offset = extracted_value;
+
+      else if (name.equals("traceid"))
+        uid = extracted_value;
+
+      else {
+        error_encountered = true;
+        break;
+      }
+    } else {
+      error_encountered = true;
+      break;
+    }
+  }
+
+  if (error_encountered || uid == LLDB_INVALID_UID || packet.GetBytesLeft() ||
+      byte_count == std::numeric_limits<size_t>::max() ||
+      offset == std::numeric_limits<size_t>::max())
+    return SendIllFormedResponse(packet, "jTrace: Ill formed packet ");
+
+  // Allocate the response buffer.
+  std::vector<uint8_t> buffer(byte_count, '\0');
+  if (buffer.empty())
+    return SendErrorResponse(0x78);
+
+  StreamGDBRemote response;
+  Error error;
+  llvm::MutableArrayRef<uint8_t> buf(buffer);
+
+  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.
Index: source/API/SBTrace.cpp
===================================================================
--- source/API/SBTrace.cpp
+++ source/API/SBTrace.cpp
@@ -25,37 +25,37 @@
 
 size_t SBTrace::GetTraceData(SBError &error, void *buf, size_t size,
                              size_t offset, lldb::tid_t thread_id) {
-  size_t bytes_read = 0;
   ProcessSP process_sp(GetSP());
   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+  llvm::MutableArrayRef<uint8_t> buffer(static_cast<uint8_t *>(buf), size);
   error.Clear();
 
   if (!process_sp) {
     error.SetErrorString("invalid process");
   } else {
-    bytes_read = process_sp->GetData(GetTraceUID(), thread_id, error.ref(), buf,
-                                     size, offset);
-    LLDB_LOG(log, "SBTrace::bytes_read - %" PRIx64, bytes_read);
+    error.SetError(
+        process_sp->GetData(GetTraceUID(), thread_id, buffer, offset));
+    LLDB_LOG(log, "SBTrace::bytes_read - {0}", buffer.size());
   }
-  return bytes_read;
+  return buffer.size();
 }
 
 size_t SBTrace::GetMetaData(SBError &error, void *buf, size_t size,
                             size_t offset, lldb::tid_t thread_id) {
-  size_t bytes_read = 0;
   ProcessSP process_sp(GetSP());
   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+  llvm::MutableArrayRef<uint8_t> buffer(static_cast<uint8_t *>(buf), size);
   error.Clear();
 
   if (!process_sp) {
     error.SetErrorString("invalid process");
   } else {
 
-    bytes_read = process_sp->GetMetaData(GetTraceUID(), thread_id, error.ref(),
-                                         buf, size, offset);
-    LLDB_LOG(log, "SBTrace::bytes_read - %" PRIx64, bytes_read);
+    error.SetError(
+        process_sp->GetMetaData(GetTraceUID(), thread_id, buffer, offset));
+    LLDB_LOG(log, "SBTrace::bytes_read - {0}", buffer.size());
   }
-  return bytes_read;
+  return buffer.size();
 }
 
 void SBTrace::StopTrace(SBError &error, lldb::tid_t thread_id) {
@@ -66,7 +66,7 @@
     error.SetErrorString("invalid process");
     return;
   }
-  process_sp->StopTrace(GetTraceUID(), thread_id, error.ref());
+  error.SetError(process_sp->StopTrace(GetTraceUID(), thread_id));
 }
 
 void SBTrace::GetTraceConfig(SBTraceOptions &options, SBError &error) {
@@ -76,8 +76,8 @@
   if (!process_sp) {
     error.SetErrorString("invalid process");
   } else {
-    process_sp->GetTraceConfig(GetTraceUID(), error.ref(),
-                               options.m_traceoptions_sp);
+    error.SetError(process_sp->GetTraceConfig(GetTraceUID(),
+                                              *(options.m_traceoptions_sp)));
   }
 }
 
Index: source/API/SBProcess.cpp
===================================================================
--- source/API/SBProcess.cpp
+++ source/API/SBProcess.cpp
@@ -363,10 +363,9 @@
   if (!process_sp) {
     error.SetErrorString("invalid process");
   } else {
-
-    uid = process_sp->StartTrace(options.m_traceoptions_sp, error.ref());
+    uid = process_sp->StartTrace(*(options.m_traceoptions_sp), error.ref());
     trace_instance.SetTraceUID(uid);
-    LLDB_LOG(log, "SBProcess::returned uid - %" PRIx64, uid);
+    LLDB_LOG(log, "SBProcess::returned uid - {0}", uid);
   }
   return trace_instance;
 }
Index: include/lldb/Utility/StringExtractor.h
===================================================================
--- include/lldb/Utility/StringExtractor.h
+++ include/lldb/Utility/StringExtractor.h
@@ -111,6 +111,8 @@
 
   size_t GetHexByteStringTerminatedBy(std::string &str, char terminator);
 
+  bool Consume_front(const llvm::StringRef &str);
+
   const char *Peek() {
     if (m_index < m_packet.size())
       return m_packet.c_str() + m_index;
Index: include/lldb/Target/Process.h
===================================================================
--- include/lldb/Target/Process.h
+++ include/lldb/Target/Process.h
@@ -2780,7 +2780,7 @@
   /// GetTraceConfig should supply the actual used trace
   /// configuration.
   //------------------------------------------------------------------
-  virtual lldb::user_id_t StartTrace(lldb::TraceOptionsSP &options,
+  virtual lldb::user_id_t StartTrace(const TraceOptions &options,
                                      Error &error) {
     error.SetErrorString("Not implemented");
     return LLDB_INVALID_UID;
@@ -2795,9 +2795,8 @@
   /// In the other case that tracing on an individual thread needs
   /// to be stopped a thread_id can be supplied.
   //------------------------------------------------------------------
-  virtual void StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id,
-                         Error &error) {
-    error.SetErrorString("Not implemented");
+  virtual Error StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) {
+    return Error("Not implemented");
   }
 
   //------------------------------------------------------------------
@@ -2808,21 +2807,19 @@
   /// may not. The thread_id should be used to select a particular
   /// thread for trace extraction.
   //------------------------------------------------------------------
-  virtual size_t GetData(lldb::user_id_t uid, lldb::tid_t thread_id,
-                         Error &error, void *buf, size_t size,
-                         size_t offset = 0) {
-    error.SetErrorString("Not implemented");
-    return 0;
+  virtual Error GetData(lldb::user_id_t uid, lldb::tid_t thread_id,
+                        llvm::MutableArrayRef<uint8_t> &buffer,
+                        size_t offset = 0) {
+    return Error("Not implemented");
   }
 
   //------------------------------------------------------------------
   /// Similar API as above except for obtaining meta data
   //------------------------------------------------------------------
-  virtual size_t GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
-                             Error &error, void *buf, size_t size,
-                             size_t offset = 0) {
-    error.SetErrorString("Not implemented");
-    return 0;
+  virtual Error GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
+                            llvm::MutableArrayRef<uint8_t> &buffer,
+                            size_t offset = 0) {
+    return Error("Not implemented");
   }
 
   //------------------------------------------------------------------
@@ -2834,10 +2831,8 @@
   /// configuration used by a specific thread. The thread_id specified
   /// should also match the uid otherwise an error will be returned.
   //------------------------------------------------------------------
-  virtual void GetTraceConfig(lldb::user_id_t uid, Error &error,
-                              lldb::TraceOptionsSP &options) {
-    error.SetErrorString("Not implemented");
-    return;
+  virtual Error GetTraceConfig(lldb::user_id_t uid, TraceOptions &options) {
+    return Error("Not implemented");
   }
 
 protected:
Index: include/lldb/Host/common/NativeProcessProtocol.h
===================================================================
--- include/lldb/Host/common/NativeProcessProtocol.h
+++ include/lldb/Host/common/NativeProcessProtocol.h
@@ -10,6 +10,7 @@
 #ifndef liblldb_NativeProcessProtocol_h_
 #define liblldb_NativeProcessProtocol_h_
 
+#include "lldb/Core/TraceOptions.h"
 #include "lldb/Host/MainLoop.h"
 #include "lldb/Utility/Error.h"
 #include "lldb/lldb-private-forward.h"
@@ -308,6 +309,109 @@
   static Error Attach(lldb::pid_t pid, NativeDelegate &native_delegate,
                       MainLoop &mainloop, NativeProcessProtocolSP &process_sp);
 
+  //------------------------------------------------------------------
+  /// StartTracing API for starting a tracing instance with the
+  /// TraceOptions on a specific thread.
+  ///
+  /// @param[in] thread
+  ///     The thread to start tracing on, in case whole process needs
+  ///     to be traced use INVALID_THREAD_ID.
+  ///
+  /// @param[in] config
+  ///     The configuration to use when starting tracing.
+  ///
+  /// @param[out] error
+  ///     Error indicates what went wrong.
+  ///
+  /// @return
+  ///     The API returns a user_id which can be used to get trace
+  ///     data, trace configuration or stopping the trace instance.
+  ///     The user_id is a key to identify and operate with a tracing
+  ///     instance. It may refer to the complete process or a single
+  ///     thread.
+  //------------------------------------------------------------------
+  virtual lldb::user_id_t StartTrace(const TraceOptions &config, Error &error) {
+    error.SetErrorString("Not implemented");
+    return LLDB_INVALID_UID;
+  }
+
+  //------------------------------------------------------------------
+  /// StopTracing API as the name suggests stops a tracing instance.
+  ///
+  /// @param[in] uid
+  ///     The user id of the trace intended to be stopped. Now a
+  ///     user_id may map to multiple threads in which case this API
+  ///     could be used to stop the tracing for a specific thread by
+  ///     supplying its thread id.
+  ///
+  /// @param[in] thread
+  ///     Thread is needed when the complete process is being traced
+  ///     and the user wishes to stop tracing on a particular thread.
+  ///
+  /// @return
+  ///     Error indicating what went wrong.
+  //------------------------------------------------------------------
+  virtual Error StopTrace(lldb::user_id_t uid,
+                          lldb::tid_t thread = LLDB_INVALID_THREAD_ID) {
+    return Error("Not implemented");
+  }
+
+  //------------------------------------------------------------------
+  /// This API provides the trace data collected in the form of raw
+  /// data.
+  ///
+  /// @param[in] uid thread
+  ///     The uid and thread provide the context for the trace
+  ///     instance.
+  ///
+  /// @param[in] buf buf_size
+  ///     The buf and buf_size provide the destination buffer
+  ///     where the trace data would be read to.
+  ///
+  /// @param[in] offset
+  ///     There is possibility to read partially the trace data from
+  ///     a specified offset where in such cases the buffer provided
+  ///     may be smaller than the internal trace collection container.
+  ///
+  /// @return
+  ///     The size of the data actually read.
+  //------------------------------------------------------------------
+  virtual Error GetData(lldb::user_id_t uid, lldb::tid_t thread,
+                        llvm::MutableArrayRef<uint8_t> &buffer,
+                        size_t offset = 0) {
+    return Error("Not implemented");
+  }
+
+  //------------------------------------------------------------------
+  /// Similar API as above except it aims to provide any extra data
+  /// useful for decoding the actual trace data.
+  //------------------------------------------------------------------
+  virtual Error GetMetaData(lldb::user_id_t uid, lldb::tid_t thread,
+                            llvm::MutableArrayRef<uint8_t> &buffer,
+                            size_t offset = 0) {
+    return Error("Not implemented");
+  }
+
+  //------------------------------------------------------------------
+  /// API to query the TraceOptions for a given user id
+  ///
+  /// @param[in] uid
+  ///     The user id of the tracing instance.
+  ///
+  /// @param[in] threadid
+  ///     The thread id of the tracing instance, in case configuration
+  ///     for a specific thread is needed.
+  ///
+  /// @param[out] error
+  ///     Error indicates what went wrong.
+  ///
+  /// @param[out] config
+  ///     The actual configuration being used for tracing.
+  //------------------------------------------------------------------
+  virtual Error GetTraceConfig(lldb::user_id_t uid, TraceOptions &config) {
+    return Error("Not implemented");
+  }
+
 protected:
   lldb::pid_t m_pid;
 
Index: include/lldb/Core/TraceOptions.h
===================================================================
--- include/lldb/Core/TraceOptions.h
+++ include/lldb/Core/TraceOptions.h
@@ -18,8 +18,7 @@
 namespace lldb_private {
 class TraceOptions {
 public:
-  TraceOptions()
-      : m_trace_params(new StructuredData::Dictionary()) {}
+  TraceOptions() : m_trace_params(new StructuredData::Dictionary()) {}
 
   const StructuredData::DictionarySP &getTraceParams() const {
     return m_trace_params;
@@ -43,7 +42,7 @@
 
   void setThreadID(lldb::tid_t thread_id) { m_thread_id = thread_id; }
 
-  lldb::tid_t getThreadID() { return m_thread_id; }
+  lldb::tid_t getThreadID() const { return m_thread_id; }
 
 private:
   lldb::TraceType m_type;
Index: include/lldb/API/SBTrace.h
===================================================================
--- include/lldb/API/SBTrace.h
+++ include/lldb/API/SBTrace.h
@@ -40,7 +40,7 @@
   ///
   /// @param[in] thread_id
   ///     Tracing could be started for the complete process or a
-  ///     single thread, in the first case the uid obtained would
+  ///     single thread, in the first case the traceid obtained would
   ///     map to all the threads existing within the process and the
   ///     ones spawning later. The thread_id parameter can be used in
   ///     such a scenario to select the trace data for a specific
@@ -68,16 +68,17 @@
   ///     An error explaining what went wrong.
   ///
   /// @param[in] thread_id
-  ///     The user id could map to a tracing instance for a thread
+  ///     The trace id could map to a tracing instance for a thread
   ///     or could also map to a group of threads being traced with
   ///     the same trace options. A thread_id is normally optional
   ///     except in the case of tracing a complete process and tracing
   ///     needs to switched off on a particular thread.
   ///     A situation could occur where initially a thread (lets say
-  ///     thread A) is being individually traced with a particular uid
-  ///     and then tracing is started on the complete process, in this
-  ///     case thread A will continue without any change. All newly
-  ///     spawned threads would be traced with the uid of the process.
+  ///     thread A) is being individually traced with a particular
+  ///     trace id and then tracing is started on the complete
+  ///     process, in this case thread A will continue without any
+  ///     change. All newly spawned threads would be traced with the
+  ///     trace id of the process.
   ///     Now if the StopTrace API is called for the whole process,
   ///     thread A will not be stopped and must be stopped separately.
   //------------------------------------------------------------------
Index: docs/lldb-gdb-remote.txt
===================================================================
--- docs/lldb-gdb-remote.txt
+++ docs/lldb-gdb-remote.txt
@@ -209,6 +209,161 @@
 read packet: OK
 
 //----------------------------------------------------------------------
+// JTrace:start:
+//
+// BRIEF
+//  Packet for starting trace of type lldb::TraceType. The following
+//  parameters (mandatory and optional) should be appended to the packet
+//  although there is no specific order imposed. The parameters need to
+//  formatted as a semi-colon seperated list of "Name:Value" pairs.
+//  Different tracing types could require different custom parameters.
+//  Such custom tracing parameters if needed should be collectively
+//  specified in a JSON dictionary and the dictionary can be appended
+//  to this packet (as Value corresponding to "jparams"). Since sending
+//  JSON data over gdb-remote protocol has certain limitations, binary
+//  escaping convention is used for JSON data.
+//
+//  Following is the list of parameters -
+//
+//  Name            Value (Hex Encoded 64-bit integer)      (O)Optional/
+//                  (except jparams which should be a       (M)Mandatory
+//                  JSON dictionary)
+//  ==========      ====================================================
+//
+//  type            The type of trace to start (see          M
+//                  lldb-enumerations for TraceType)
+//
+//  buffersize      The size of the buffer to allocate       M
+//                  for trace gathering.
+//
+//  threadid        The id of the thread to start tracing    O
+//                  on.
+//
+//  metabuffersize  The size of buffer to hold meta data     O
+//                  used for decoding the trace data.
+//
+//  jparams         Any parameters that are specific to      O
+//                  certain trace technologies should be
+//                  collectively specified as a JSON
+//                  dictionary
+//  ==========      ====================================================
+//
+//  Each tracing instance is identified by a trace id which is returned
+//  as the reply to this packet. In case the tracing failed to begin an
+//  error code is returned instead.
+//----------------------------------------------------------------------
+
+send packet: JTrace:start:type:<type>;buffersize:<buffersize>;
+read packet: <trace id>/E<error code>
+
+//----------------------------------------------------------------------
+// JTrace:stop:
+//
+// BRIEF
+//  Stop tracing instance with trace id <trace id>, of course trace
+//  needs to be started before.
+//
+//  Following is the list of parameters -
+//
+//  Name            Value (Hex Encoded 64-bit integer)      (O)Optional/
+//                                                          (M)Mandatory
+//  ==========      ====================================================
+//
+//  traceid         The trace id of the tracing instance    M
+//
+//  threadid        The id of the thread to stop tracing    O
+//                  on. Since <trace id> could map to
+//                  multiple trace instances (in case it
+//                  maps to the complete process), the
+//                  threadid of a particular thread could
+//                  be appended as "threadid:<thread id>;"
+//                  to stop tracing on that thread.
+//  ==========      ====================================================
+//
+//  An OK response is sent in case of success else an error code is
+//  returned.
+//----------------------------------------------------------------------
+
+send packet: JTrace:stop:traceid:<trace id>;
+read packet: <OK response>/E<error code>
+
+//----------------------------------------------------------------------
+// jTrace:buffer:read:
+//
+// BRIEF
+//  Packet for reading the trace for tracing instance <trace id>, i.e the
+//  id obtained from StartTrace API.
+//
+//  Following is the list of parameters -
+//
+//  Name            Value (Hex Encoded 64-bit integer)      (O)Optional/
+//                                                          (M)Mandatory
+//  ==========      ====================================================
+//  traceid         The trace id of the tracing instance    M
+//
+//  offset          The offset to start reading the data    M
+//                  from.
+//
+//  buffersize      The size of the data intended to read.  M
+//
+//  threadid        The id of the thread to retrieve data   O
+//                  from.
+//  ==========      ====================================================
+//
+//  The trace data is sent as raw binary data if the read was successful
+//  else an error code is sent.
+//----------------------------------------------------------------------
+
+send packet: jTrace:buffer:read:traceid:<trace id>;offset:<byteoffset>;buffersize:<byte_count>;
+read packet: <binary trace data>/E<error code>
+
+//----------------------------------------------------------------------
+// jTrace:meta:read:traceid:<trace id>;
+//
+// BRIEF
+//  Similar Packet as above except it reads meta data.
+//----------------------------------------------------------------------
+
+/----------------------------------------------------------------------
+// jTrace:conf:read:
+//
+// BRIEF
+//  Request the trace configuration for the tracing instance with id
+//  <trace id>.
+//
+//  Following is the list of parameters -
+//
+//  Name            Value (Hex Encoded 64-bit integer)      (O)Optional/
+//                                                          (M)Mandatory
+//  ==========      ====================================================
+//  traceid         The trace id of the tracing instance    M
+//
+//  threadid        The id of the thread to obtain trace    O
+//                  configuration from. Since <trace id>
+//                  could map to multiple trace instances
+//                  (in case it maps to the complete
+//                  process), the threadid of a particular
+//                  thread could be appended as
+//                  "threadid:<thread id>;" to obtain the
+//                  trace configuration of that thread.
+//  ==========      ====================================================
+//
+//  The numerical values are Hex Encoded 64-bit integers (including the
+//  values obtained in the response).
+//  In the response packet the trace configuration is sent as text,
+//  formatted as "Name:Value" pair seperated by a semi colon (in the
+//  case of custom parameters the value should be a JSON Structure with
+//  Name as "jparams"). Since sending JSON data over gdb-remote protocol
+//  has certain limitations, binary escaping convention is used for JSON
+//  data.
+//  In case the trace instance with the <trace id> was not found, an
+//  error code is returned.
+//----------------------------------------------------------------------
+
+send packet: jTrace:conf:read:traceid:<trace id>;
+read packet: conf1:<conf1>;conf2:<conf2>;jparams:{"paramName":paramValue}];/E<error code>
+
+//----------------------------------------------------------------------
 // "qRegisterInfo<hex-reg-id>"
 //
 // BRIEF
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to