wallace updated this revision to Diff 426546.
wallace added a comment.

update test


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D124648/new/

https://reviews.llvm.org/D124648

Files:
  lldb/docs/lldb-gdb-remote.txt
  lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
  lldb/source/Plugins/Process/Linux/CMakeLists.txt
  lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
  lldb/source/Plugins/Process/Linux/IntelPTCollector.h
  lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.cpp
  lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.h
  lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
  lldb/source/Plugins/Process/Linux/Perf.cpp
  lldb/source/Plugins/Process/Linux/Perf.h
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionSaver.cpp
  lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
  lldb/unittests/Process/Linux/CMakeLists.txt
  lldb/unittests/Process/Linux/IntelPTCollectorTests.cpp
  lldb/unittests/Process/Linux/PerfTests.cpp

Index: lldb/unittests/Process/Linux/PerfTests.cpp
===================================================================
--- lldb/unittests/Process/Linux/PerfTests.cpp
+++ lldb/unittests/Process/Linux/PerfTests.cpp
@@ -86,4 +86,135 @@
             (SLEEP_NANOS + acceptable_overhead).count());
 }
 
+size_t ReadCylicBufferWrapper(void *buf, size_t buf_size, void *cyc_buf,
+                              size_t cyc_buf_size, size_t cyc_start,
+                              size_t offset) {
+  llvm::MutableArrayRef<uint8_t> dst(reinterpret_cast<uint8_t *>(buf),
+                                     buf_size);
+  llvm::ArrayRef<uint8_t> src(reinterpret_cast<uint8_t *>(cyc_buf),
+                              cyc_buf_size);
+  ReadCyclicBuffer(dst, src, cyc_start, offset);
+  return dst.size();
+}
+
+TEST(CyclicBuffer, EdgeCases) {
+  size_t bytes_read;
+  uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
+
+  // We will always leave the last bytes untouched
+  // so that string comparisons work.
+  char smaller_buffer[4] = {};
+
+  // empty buffer to read into
+  bytes_read = ReadCylicBufferWrapper(smaller_buffer, 0, cyclic_buffer,
+                                      sizeof(cyclic_buffer), 3, 0);
+  ASSERT_EQ(0u, bytes_read);
+
+  // empty cyclic buffer
+  bytes_read = ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer),
+                                      cyclic_buffer, 0, 3, 0);
+  ASSERT_EQ(0u, bytes_read);
+
+  // bigger offset
+  bytes_read =
+      ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer),
+                             cyclic_buffer, sizeof(cyclic_buffer), 3, 6);
+  ASSERT_EQ(0u, bytes_read);
+
+  // wrong offset
+  bytes_read =
+      ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer),
+                             cyclic_buffer, sizeof(cyclic_buffer), 3, 7);
+  ASSERT_EQ(0u, bytes_read);
+
+  // wrong start
+  bytes_read =
+      ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer),
+                             cyclic_buffer, sizeof(cyclic_buffer), 3, 7);
+  ASSERT_EQ(0u, bytes_read);
+}
+
+TEST(CyclicBuffer, EqualSizeBuffer) {
+  size_t bytes_read = 0;
+  uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
+
+  char cyclic[] = "cyclic";
+  for (size_t i = 0; i < sizeof(cyclic); i++) {
+    // We will always leave the last bytes untouched
+    // so that string comparisons work.
+    char equal_size_buffer[7] = {};
+    bytes_read =
+        ReadCylicBufferWrapper(equal_size_buffer, sizeof(cyclic_buffer),
+                               cyclic_buffer, sizeof(cyclic_buffer), 3, i);
+    ASSERT_EQ((sizeof(cyclic) - i - 1), bytes_read);
+    ASSERT_STREQ(equal_size_buffer, (cyclic + i));
+  }
+}
+
+TEST(CyclicBuffer, SmallerSizeBuffer) {
+  size_t bytes_read;
+  uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
+
+  // We will always leave the last bytes untouched
+  // so that string comparisons work.
+  char smaller_buffer[4] = {};
+  bytes_read =
+      ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
+                             cyclic_buffer, sizeof(cyclic_buffer), 3, 0);
+  ASSERT_EQ(3u, bytes_read);
+  ASSERT_STREQ(smaller_buffer, "cyc");
+
+  bytes_read =
+      ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
+                             cyclic_buffer, sizeof(cyclic_buffer), 3, 1);
+  ASSERT_EQ(3u, bytes_read);
+  ASSERT_STREQ(smaller_buffer, "ycl");
+
+  bytes_read =
+      ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
+                             cyclic_buffer, sizeof(cyclic_buffer), 3, 2);
+  ASSERT_EQ(3u, bytes_read);
+  ASSERT_STREQ(smaller_buffer, "cli");
+
+  bytes_read =
+      ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
+                             cyclic_buffer, sizeof(cyclic_buffer), 3, 3);
+  ASSERT_EQ(3u, bytes_read);
+  ASSERT_STREQ(smaller_buffer, "lic");
+
+  {
+    char smaller_buffer[4] = {};
+    bytes_read =
+        ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
+                               cyclic_buffer, sizeof(cyclic_buffer), 3, 4);
+    ASSERT_EQ(2u, bytes_read);
+    ASSERT_STREQ(smaller_buffer, "ic");
+  }
+  {
+    char smaller_buffer[4] = {};
+    bytes_read =
+        ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
+                               cyclic_buffer, sizeof(cyclic_buffer), 3, 5);
+    ASSERT_EQ(1u, bytes_read);
+    ASSERT_STREQ(smaller_buffer, "c");
+  }
+}
+
+TEST(CyclicBuffer, BiggerSizeBuffer) {
+  size_t bytes_read = 0;
+  uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
+
+  char cyclic[] = "cyclic";
+  for (size_t i = 0; i < sizeof(cyclic); i++) {
+    // We will always leave the last bytes untouched
+    // so that string comparisons work.
+    char bigger_buffer[10] = {};
+    bytes_read =
+        ReadCylicBufferWrapper(bigger_buffer, (sizeof(bigger_buffer) - 1),
+                               cyclic_buffer, sizeof(cyclic_buffer), 3, i);
+    ASSERT_EQ((sizeof(cyclic) - i - 1), bytes_read);
+    ASSERT_STREQ(bigger_buffer, (cyclic + i));
+  }
+}
+
 #endif // __x86_64__
Index: lldb/unittests/Process/Linux/IntelPTCollectorTests.cpp
===================================================================
--- lldb/unittests/Process/Linux/IntelPTCollectorTests.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-//===-- IntelPTCollectorTests.cpp -------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "IntelPTCollector.h"
-#include "llvm/ADT/ArrayRef.h"
-
-
-using namespace lldb_private;
-using namespace process_linux;
-
-size_t ReadCylicBufferWrapper(void *buf, size_t buf_size, void *cyc_buf,
-                              size_t cyc_buf_size, size_t cyc_start,
-                              size_t offset) {
-  llvm::MutableArrayRef<uint8_t> dst(reinterpret_cast<uint8_t *>(buf),
-                                     buf_size);
-  llvm::ArrayRef<uint8_t> src(reinterpret_cast<uint8_t *>(cyc_buf),
-                              cyc_buf_size);
-  IntelPTThreadTrace::ReadCyclicBuffer(dst, src, cyc_start, offset);
-  return dst.size();
-}
-
-TEST(CyclicBuffer, EdgeCases) {
-  size_t bytes_read;
-  uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
-
-  // We will always leave the last bytes untouched
-  // so that string comparisons work.
-  char smaller_buffer[4] = {};
-
-  // empty buffer to read into
-  bytes_read = ReadCylicBufferWrapper(smaller_buffer, 0, cyclic_buffer,
-                                      sizeof(cyclic_buffer), 3, 0);
-  ASSERT_EQ(0u, bytes_read);
-
-  // empty cyclic buffer
-  bytes_read = ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer),
-                                      cyclic_buffer, 0, 3, 0);
-  ASSERT_EQ(0u, bytes_read);
-
-  // bigger offset
-  bytes_read =
-      ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer),
-                             cyclic_buffer, sizeof(cyclic_buffer), 3, 6);
-  ASSERT_EQ(0u, bytes_read);
-
-  // wrong offset
-  bytes_read =
-      ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer),
-                             cyclic_buffer, sizeof(cyclic_buffer), 3, 7);
-  ASSERT_EQ(0u, bytes_read);
-
-  // wrong start
-  bytes_read =
-      ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer),
-                             cyclic_buffer, sizeof(cyclic_buffer), 3, 7);
-  ASSERT_EQ(0u, bytes_read);
-}
-
-TEST(CyclicBuffer, EqualSizeBuffer) {
-  size_t bytes_read = 0;
-  uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
-
-  char cyclic[] = "cyclic";
-  for (size_t i = 0; i < sizeof(cyclic); i++) {
-    // We will always leave the last bytes untouched
-    // so that string comparisons work.
-    char equal_size_buffer[7] = {};
-    bytes_read =
-        ReadCylicBufferWrapper(equal_size_buffer, sizeof(cyclic_buffer),
-                               cyclic_buffer, sizeof(cyclic_buffer), 3, i);
-    ASSERT_EQ((sizeof(cyclic) - i - 1), bytes_read);
-    ASSERT_STREQ(equal_size_buffer, (cyclic + i));
-  }
-}
-
-TEST(CyclicBuffer, SmallerSizeBuffer) {
-  size_t bytes_read;
-  uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
-
-  // We will always leave the last bytes untouched
-  // so that string comparisons work.
-  char smaller_buffer[4] = {};
-  bytes_read =
-      ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
-                             cyclic_buffer, sizeof(cyclic_buffer), 3, 0);
-  ASSERT_EQ(3u, bytes_read);
-  ASSERT_STREQ(smaller_buffer, "cyc");
-
-  bytes_read =
-      ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
-                             cyclic_buffer, sizeof(cyclic_buffer), 3, 1);
-  ASSERT_EQ(3u, bytes_read);
-  ASSERT_STREQ(smaller_buffer, "ycl");
-
-  bytes_read =
-      ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
-                             cyclic_buffer, sizeof(cyclic_buffer), 3, 2);
-  ASSERT_EQ(3u, bytes_read);
-  ASSERT_STREQ(smaller_buffer, "cli");
-
-  bytes_read =
-      ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
-                             cyclic_buffer, sizeof(cyclic_buffer), 3, 3);
-  ASSERT_EQ(3u, bytes_read);
-  ASSERT_STREQ(smaller_buffer, "lic");
-
-  {
-    char smaller_buffer[4] = {};
-    bytes_read =
-        ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
-                               cyclic_buffer, sizeof(cyclic_buffer), 3, 4);
-    ASSERT_EQ(2u, bytes_read);
-    ASSERT_STREQ(smaller_buffer, "ic");
-  }
-  {
-    char smaller_buffer[4] = {};
-    bytes_read =
-        ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
-                               cyclic_buffer, sizeof(cyclic_buffer), 3, 5);
-    ASSERT_EQ(1u, bytes_read);
-    ASSERT_STREQ(smaller_buffer, "c");
-  }
-}
-
-TEST(CyclicBuffer, BiggerSizeBuffer) {
-  size_t bytes_read = 0;
-  uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
-
-  char cyclic[] = "cyclic";
-  for (size_t i = 0; i < sizeof(cyclic); i++) {
-    // We will always leave the last bytes untouched
-    // so that string comparisons work.
-    char bigger_buffer[10] = {};
-    bytes_read =
-        ReadCylicBufferWrapper(bigger_buffer, (sizeof(bigger_buffer) - 1),
-                               cyclic_buffer, sizeof(cyclic_buffer), 3, i);
-    ASSERT_EQ((sizeof(cyclic) - i - 1), bytes_read);
-    ASSERT_STREQ(bigger_buffer, (cyclic + i));
-  }
-}
Index: lldb/unittests/Process/Linux/CMakeLists.txt
===================================================================
--- lldb/unittests/Process/Linux/CMakeLists.txt
+++ lldb/unittests/Process/Linux/CMakeLists.txt
@@ -1,5 +1,4 @@
 add_lldb_unittest(ProcessLinuxTests
-  IntelPTCollectorTests.cpp
   PerfTests.cpp
   ProcfsTests.cpp
 
Index: lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
===================================================================
--- lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
+++ lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
@@ -14,7 +14,7 @@
 namespace lldb_private {
 
 const char *IntelPTDataKinds::kProcFsCpuInfo = "procfsCpuInfo";
-const char *IntelPTDataKinds::kThreadTraceBuffer = "threadTraceBuffer";
+const char *IntelPTDataKinds::kTraceBuffer = "traceBuffer";
 
 bool fromJSON(const json::Value &value, TraceIntelPTStartRequest &packet,
               Path path) {
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionSaver.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionSaver.cpp
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionSaver.cpp
@@ -49,7 +49,7 @@
 
   llvm::Expected<JSONTraceSessionBase> json_session_description =
       TraceSessionSaver::BuildProcessesSection(
-          *live_process, IntelPTDataKinds::kThreadTraceBuffer, directory);
+          *live_process, IntelPTDataKinds::kTraceBuffer, directory);
 
   if (!json_session_description)
     return json_session_description.takeError();
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
@@ -81,8 +81,7 @@
   for (const ThreadPostMortemTraceSP &thread : traced_threads) {
     m_thread_decoders.emplace(thread->GetID(),
                               std::make_unique<ThreadDecoder>(thread, *this));
-    SetPostMortemThreadDataFile(thread->GetID(),
-                                IntelPTDataKinds::kThreadTraceBuffer,
+    SetPostMortemThreadDataFile(thread->GetID(), IntelPTDataKinds::kTraceBuffer,
                                 thread->GetTraceFile());
   }
 }
@@ -373,8 +372,7 @@
 
 Error TraceIntelPT::OnThreadBufferRead(lldb::tid_t tid,
                                        OnBinaryDataReadCallback callback) {
-  return OnThreadBinaryDataRead(tid, IntelPTDataKinds::kThreadTraceBuffer,
-                                callback);
+  return OnThreadBinaryDataRead(tid, IntelPTDataKinds::kTraceBuffer, callback);
 }
 
 TaskTimer &TraceIntelPT::GetTimer() { return m_task_timer; }
Index: lldb/source/Plugins/Process/Linux/Perf.h
===================================================================
--- lldb/source/Plugins/Process/Linux/Perf.h
+++ lldb/source/Plugins/Process/Linux/Perf.h
@@ -74,6 +74,24 @@
 
 } // namespace resource_handle
 
+/// Read data from a cyclic buffer
+///
+/// \param[in] [out] buf
+///     Destination buffer, the buffer will be truncated to written size.
+///
+/// \param[in] src
+///     Source buffer which must be a cyclic buffer.
+///
+/// \param[in] src_cyc_index
+///     The index pointer (start of the valid data in the cyclic
+///     buffer).
+///
+/// \param[in] offset
+///     The offset to begin reading the data in the cyclic buffer.
+void ReadCyclicBuffer(llvm::MutableArrayRef<uint8_t> &dst,
+                      llvm::ArrayRef<uint8_t> src, size_t src_cyc_index,
+                      size_t offset);
+
 /// Thin wrapper of the perf_event_open API.
 ///
 /// Exposes the metadata page and data and aux buffers of a perf event.
Index: lldb/source/Plugins/Process/Linux/Perf.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/Perf.cpp
+++ lldb/source/Plugins/Process/Linux/Perf.cpp
@@ -8,6 +8,7 @@
 
 #include "Perf.h"
 
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
 #include "lldb/Host/linux/Support.h"
 
 #include "llvm/Support/FormatVariadic.h"
@@ -22,6 +23,54 @@
 using namespace process_linux;
 using namespace llvm;
 
+void lldb_private::process_linux::ReadCyclicBuffer(
+    llvm::MutableArrayRef<uint8_t> &dst, llvm::ArrayRef<uint8_t> src,
+    size_t src_cyc_index, size_t offset) {
+
+  Log *log = GetLog(POSIXLog::Trace);
+
+  if (dst.empty() || src.empty()) {
+    dst = dst.drop_back(dst.size());
+    return;
+  }
+
+  if (dst.data() == nullptr || src.data() == nullptr) {
+    dst = dst.drop_back(dst.size());
+    return;
+  }
+
+  if (src_cyc_index > src.size()) {
+    dst = dst.drop_back(dst.size());
+    return;
+  }
+
+  if (offset >= src.size()) {
+    LLDB_LOG(log, "Too Big offset ");
+    dst = dst.drop_back(dst.size());
+    return;
+  }
+
+  llvm::SmallVector<ArrayRef<uint8_t>, 2> parts = {
+      src.slice(src_cyc_index), src.take_front(src_cyc_index)};
+
+  if (offset > parts[0].size()) {
+    parts[1] = parts[1].slice(offset - parts[0].size());
+    parts[0] = parts[0].drop_back(parts[0].size());
+  } else if (offset == parts[0].size()) {
+    parts[0] = parts[0].drop_back(parts[0].size());
+  } else {
+    parts[0] = parts[0].slice(offset);
+  }
+  auto next = dst.begin();
+  auto bytes_left = dst.size();
+  for (auto part : parts) {
+    size_t chunk_size = std::min(part.size(), bytes_left);
+    next = std::copy_n(part.begin(), chunk_size, next);
+    bytes_left -= chunk_size;
+  }
+  dst = dst.drop_back(bytes_left);
+}
+
 Expected<LinuxPerfZeroTscConversion>
 lldb_private::process_linux::LoadPerfTscConversionParameters() {
   lldb::pid_t pid = getpid();
Index: lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -312,7 +312,7 @@
                                        const ArchSpec &arch, MainLoop &mainloop,
                                        llvm::ArrayRef<::pid_t> tids)
     : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch),
-      m_main_loop(mainloop), m_intel_pt_collector(pid) {
+      m_main_loop(mainloop) {
   if (m_terminal_fd != -1) {
     Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
     assert(status.Success());
Index: lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.h
@@ -0,0 +1,96 @@
+//===-- IntelPTSingleBufferTrace.h ---------------------------- -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_IntelPTSingleBufferTrace_H_
+#define liblldb_IntelPTSingleBufferTrace_H_
+
+#include "Perf.h"
+
+#include "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
+#include "lldb/lldb-types.h"
+
+#include "llvm/Support/Error.h"
+
+#include <memory>
+
+namespace lldb_private {
+namespace process_linux {
+
+llvm::Expected<uint32_t> GetIntelPTOSEventType();
+
+class IntelPTTrace;
+class IntelPTSingleBufferTrace;
+
+using IntelPTThreadTraceUP = std::unique_ptr<IntelPTTrace>;
+using IntelPTSingleBufferTraceUP = std::unique_ptr<IntelPTSingleBufferTrace>;
+
+/// This class wraps a single perf event collecting intel pt data in a single
+/// buffer.
+class IntelPTSingleBufferTrace {
+public:
+  /// Start tracing using a single Intel PT trace buffer.
+  ///
+  /// \param[in] request
+  ///     Intel PT configuration parameters.
+  ///
+  /// \param[in] tid
+  ///     The tid of the thread to be traced.
+  ///
+  /// \return
+  ///   A \a IntelPTSingleBufferTrace instance if tracing was successful, or
+  ///   an \a llvm::Error otherwise.
+  static llvm::Expected<IntelPTSingleBufferTraceUP>
+  Start(const TraceIntelPTStartRequest &request, lldb::tid_t tid);
+
+  /// \return
+  ///    The bytes requested by a jLLDBTraceGetBinaryData packet that was routed
+  ///    to this trace instace.
+  llvm::Expected<std::vector<uint8_t>>
+  GetBinaryData(const TraceGetBinaryDataRequest &request) const;
+
+  /// Read the trace buffer managed by this trace instance.
+  ///
+  /// \param[in] offset
+  ///     Offset of the data to read.
+  ///
+  /// \param[in] size
+  ///     Number of bytes to read.
+  ///
+  /// \return
+  ///     A vector with the requested binary data. The vector will have the
+  ///     size of the requested \a size. Non-available positions will be
+  ///     filled with zeroes.
+  llvm::Expected<std::vector<uint8_t>> GetTraceBuffer(size_t offset,
+                                                      size_t size) const;
+
+  /// \return
+  ///   The total the size in bytes used by the trace buffer managed by this
+  ///   trace instance.
+  size_t GetTraceBufferSize() const;
+
+private:
+  /// Construct new \a IntelPTSingleBufferThreadTrace. Users are supposed to
+  /// create instances of this class via the \a Start() method and not invoke
+  /// this one directly.
+  ///
+  /// \param[in] perf_event
+  ///   perf event configured for IntelPT.
+  ///
+  /// \param[in] tid
+  ///   The thread being traced.
+  IntelPTSingleBufferTrace(PerfEvent &&perf_event, lldb::tid_t tid)
+      : m_perf_event(std::move(perf_event)) {}
+
+  /// perf event configured for IntelPT.
+  PerfEvent m_perf_event;
+};
+
+} // namespace process_linux
+} // namespace lldb_private
+
+#endif // liblldb_IntelPTSingleBufferTrace_H_
Index: lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.cpp
@@ -0,0 +1,302 @@
+//===-- IntelPTSingleBufferTrace.cpp --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "IntelPTSingleBufferTrace.h"
+
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
+
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#include <sstream>
+
+#include <linux/perf_event.h>
+#include <sys/ioctl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace process_linux;
+using namespace llvm;
+
+const char *kOSEventIntelPTTypeFile =
+    "/sys/bus/event_source/devices/intel_pt/type";
+
+const char *kPSBPeriodCapFile =
+    "/sys/bus/event_source/devices/intel_pt/caps/psb_cyc";
+
+const char *kPSBPeriodValidValuesFile =
+    "/sys/bus/event_source/devices/intel_pt/caps/psb_periods";
+
+const char *kPSBPeriodBitOffsetFile =
+    "/sys/bus/event_source/devices/intel_pt/format/psb_period";
+
+const char *kTSCBitOffsetFile =
+    "/sys/bus/event_source/devices/intel_pt/format/tsc";
+
+enum IntelPTConfigFileType {
+  Hex = 0,
+  // 0 or 1
+  ZeroOne,
+  Decimal,
+  // a bit index file always starts with the prefix config: following by an int,
+  // which represents the offset of the perf_event_attr.config value where to
+  // store a given configuration.
+  BitOffset
+};
+
+static Expected<uint32_t> ReadIntelPTConfigFile(const char *file,
+                                                IntelPTConfigFileType type) {
+  ErrorOr<std::unique_ptr<MemoryBuffer>> stream =
+      MemoryBuffer::getFileAsStream(file);
+
+  if (!stream)
+    return createStringError(inconvertibleErrorCode(),
+                             "Can't open the file '%s'", file);
+
+  uint32_t value = 0;
+  StringRef text_buffer = stream.get()->getBuffer();
+
+  if (type == BitOffset) {
+    const char *prefix = "config:";
+    if (!text_buffer.startswith(prefix))
+      return createStringError(inconvertibleErrorCode(),
+                               "The file '%s' contents doesn't start with '%s'",
+                               file, prefix);
+    text_buffer = text_buffer.substr(strlen(prefix));
+  }
+
+  auto getRadix = [&]() {
+    switch (type) {
+    case Hex:
+      return 16;
+    case ZeroOne:
+    case Decimal:
+    case BitOffset:
+      return 10;
+    }
+    llvm_unreachable("Fully covered switch above!");
+  };
+
+  auto createError = [&](const char *expected_value_message) {
+    return createStringError(
+        inconvertibleErrorCode(),
+        "The file '%s' has an invalid value. It should be %s.", file,
+        expected_value_message);
+  };
+
+  if (text_buffer.trim().consumeInteger(getRadix(), value) ||
+      (type == ZeroOne && value != 0 && value != 1)) {
+    switch (type) {
+    case Hex:
+      return createError("an unsigned hexadecimal int");
+    case ZeroOne:
+      return createError("0 or 1");
+    case Decimal:
+    case BitOffset:
+      return createError("an unsigned decimal int");
+    }
+  }
+  return value;
+}
+
+/// Return the Linux perf event type for Intel PT.
+Expected<uint32_t> process_linux::GetIntelPTOSEventType() {
+  return ReadIntelPTConfigFile(kOSEventIntelPTTypeFile,
+                               IntelPTConfigFileType::Decimal);
+}
+
+static Error CheckPsbPeriod(size_t psb_period) {
+  Expected<uint32_t> cap =
+      ReadIntelPTConfigFile(kPSBPeriodCapFile, IntelPTConfigFileType::ZeroOne);
+  if (!cap)
+    return cap.takeError();
+  if (*cap == 0)
+    return createStringError(inconvertibleErrorCode(),
+                             "psb_period is unsupported in the system.");
+
+  Expected<uint32_t> valid_values = ReadIntelPTConfigFile(
+      kPSBPeriodValidValuesFile, IntelPTConfigFileType::Hex);
+  if (!valid_values)
+    return valid_values.takeError();
+
+  if (valid_values.get() & (1 << psb_period))
+    return Error::success();
+
+  std::ostringstream error;
+  // 0 is always a valid value
+  error << "Invalid psb_period. Valid values are: 0";
+  uint32_t mask = valid_values.get();
+  while (mask) {
+    int index = __builtin_ctz(mask);
+    if (index > 0)
+      error << ", " << index;
+    // clear the lowest bit
+    mask &= mask - 1;
+  }
+  error << ".";
+  return createStringError(inconvertibleErrorCode(), error.str().c_str());
+}
+
+static Expected<uint64_t>
+GeneratePerfEventConfigValue(bool enable_tsc, Optional<size_t> psb_period) {
+  uint64_t config = 0;
+  // tsc is always supported
+  if (enable_tsc) {
+    if (Expected<uint32_t> offset = ReadIntelPTConfigFile(
+            kTSCBitOffsetFile, IntelPTConfigFileType::BitOffset))
+      config |= 1 << *offset;
+    else
+      return offset.takeError();
+  }
+  if (psb_period) {
+    if (Error error = CheckPsbPeriod(*psb_period))
+      return std::move(error);
+
+    if (Expected<uint32_t> offset = ReadIntelPTConfigFile(
+            kPSBPeriodBitOffsetFile, IntelPTConfigFileType::BitOffset))
+      config |= *psb_period << *offset;
+    else
+      return offset.takeError();
+  }
+  return config;
+}
+
+/// Create a \a perf_event_attr configured for
+/// an IntelPT event.
+///
+/// \return
+///   A \a perf_event_attr if successful,
+///   or an \a llvm::Error otherwise.
+static Expected<perf_event_attr>
+CreateIntelPTPerfEventConfiguration(bool enable_tsc,
+                                    llvm::Optional<size_t> psb_period) {
+#ifndef PERF_ATTR_SIZE_VER5
+  return llvm_unreachable("Intel PT Linux perf event not supported");
+#else
+  perf_event_attr attr;
+  memset(&attr, 0, sizeof(attr));
+  attr.size = sizeof(attr);
+  attr.exclude_kernel = 1;
+  attr.sample_type = PERF_SAMPLE_TIME;
+  attr.sample_id_all = 1;
+  attr.exclude_hv = 1;
+  attr.exclude_idle = 1;
+  attr.mmap = 1;
+
+  if (Expected<uint64_t> config_value =
+          GeneratePerfEventConfigValue(enable_tsc, psb_period))
+    attr.config = *config_value;
+  else
+    return config_value.takeError();
+
+  if (Expected<uint32_t> intel_pt_type = GetIntelPTOSEventType())
+    attr.type = *intel_pt_type;
+  else
+    return intel_pt_type.takeError();
+
+  return attr;
+#endif
+}
+
+size_t IntelPTSingleBufferTrace::GetTraceBufferSize() const {
+  return m_perf_event.GetAuxBuffer().size();
+}
+
+Expected<std::vector<uint8_t>>
+IntelPTSingleBufferTrace::GetTraceBuffer(size_t offset, size_t size) const {
+  auto fd = m_perf_event.GetFd();
+  perf_event_mmap_page &mmap_metadata = m_perf_event.GetMetadataPage();
+  // Disable the perf event to force a flush out of the CPU's internal buffer.
+  // Besides, we can guarantee that the CPU won't override any data as we are
+  // reading the buffer.
+  //
+  // The Intel documentation says:
+  //
+  // Packets are first buffered internally and then written out asynchronously.
+  // To collect packet output for postprocessing, a collector needs first to
+  // ensure that all packet data has been flushed from internal buffers.
+  // Software can ensure this by stopping packet generation by clearing
+  // IA32_RTIT_CTL.TraceEn (see “Disabling Packet Generation” in
+  // Section 35.2.7.2).
+  //
+  // This is achieved by the PERF_EVENT_IOC_DISABLE ioctl request, as mentioned
+  // in the man page of perf_event_open.
+  ioctl(fd, PERF_EVENT_IOC_DISABLE);
+
+  Log *log = GetLog(POSIXLog::Trace);
+  Status error;
+  uint64_t head = mmap_metadata.aux_head;
+
+  LLDB_LOG(log, "Aux size -{0} , Head - {1}", mmap_metadata.aux_size, head);
+
+  /**
+   * When configured as ring buffer, the aux buffer keeps wrapping around
+   * the buffer and its not possible to detect how many times the buffer
+   * wrapped. Initially the buffer is filled with zeros,as shown below
+   * so in order to get complete buffer we first copy firstpartsize, followed
+   * by any left over part from beginning to aux_head
+   *
+   * aux_offset [d,d,d,d,d,d,d,d,0,0,0,0,0,0,0,0,0,0,0] aux_size
+   *                 aux_head->||<- firstpartsize  ->|
+   *
+   * */
+
+  std::vector<uint8_t> data(size, 0);
+  MutableArrayRef<uint8_t> buffer(data);
+  ReadCyclicBuffer(buffer, m_perf_event.GetAuxBuffer(),
+                   static_cast<size_t>(head), offset);
+
+  // Reenable tracing now we have read the buffer
+  ioctl(fd, PERF_EVENT_IOC_ENABLE);
+  return data;
+}
+
+Expected<IntelPTSingleBufferTraceUP>
+IntelPTSingleBufferTrace::Start(const TraceIntelPTStartRequest &request,
+                                lldb::tid_t tid) {
+  Log *log = GetLog(POSIXLog::Trace);
+
+  LLDB_LOG(log, "Will start tracing thread id {0}", tid);
+
+  if (__builtin_popcount(request.trace_buffer_size) != 1 ||
+      request.trace_buffer_size < 4096) {
+    return createStringError(
+        inconvertibleErrorCode(),
+        "The trace buffer size must be a power of 2 greater than or equal to "
+        "4096 (2^12) bytes. It was %" PRIu64 ".",
+        request.trace_buffer_size);
+  }
+  uint64_t page_size = getpagesize();
+  uint64_t buffer_numpages = static_cast<uint64_t>(llvm::PowerOf2Floor(
+      (request.trace_buffer_size + page_size - 1) / page_size));
+
+  Expected<perf_event_attr> attr = CreateIntelPTPerfEventConfiguration(
+      request.enable_tsc, request.psb_period.map([](int value) {
+        return static_cast<uint64_t>(value);
+      }));
+  if (!attr)
+    return attr.takeError();
+
+  LLDB_LOG(log, "Will create trace buffer of size {0}",
+           request.trace_buffer_size);
+
+  if (Expected<PerfEvent> perf_event = PerfEvent::Init(*attr, tid)) {
+    if (Error mmap_err = perf_event->MmapMetadataAndBuffers(buffer_numpages,
+                                                            buffer_numpages)) {
+      return std::move(mmap_err);
+    }
+    return IntelPTSingleBufferTraceUP(
+        new IntelPTSingleBufferTrace(std::move(*perf_event), tid));
+  } else {
+    return perf_event.takeError();
+  }
+}
Index: lldb/source/Plugins/Process/Linux/IntelPTCollector.h
===================================================================
--- lldb/source/Plugins/Process/Linux/IntelPTCollector.h
+++ lldb/source/Plugins/Process/Linux/IntelPTCollector.h
@@ -11,6 +11,8 @@
 
 #include "Perf.h"
 
+#include "IntelPTSingleBufferTrace.h"
+
 #include "lldb/Utility/Status.h"
 #include "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
 #include "lldb/lldb-types.h"
@@ -23,120 +25,10 @@
 
 namespace process_linux {
 
-/// This class keeps track of one tracing instance of
-/// Intel(R) Processor Trace on Linux OS at thread level.
-///
-/// The kernel interface for us is the perf_event_open.
-class IntelPTThreadTrace;
-typedef std::unique_ptr<IntelPTThreadTrace> IntelPTThreadTraceUP;
-
-class IntelPTThreadTrace {
-public:
-  /// Create a new \a IntelPTThreadTrace and start tracing the thread.
-  ///
-  /// \param[in] pid
-  ///     The pid of the process whose thread will be traced.
-  ///
-  /// \param[in] tid
-  ///     The tid of the thread to be traced.
-  ///
-  /// \param[in] buffer_size
-  ///     Size of the thread buffer in bytes.
-  ///
-  /// \param[in] enable_tsc
-  ///     Whether to use enable TSC timestamps or not.
-  ///     More information in TraceIntelPT::GetStartConfigurationHelp().
-  ///
-  /// \param[in] psb_period
-  ///     This value defines the period in which PSB packets will be generated.
-  ///     More information in TraceIntelPT::GetStartConfigurationHelp().
-  ///
-  /// \return
-  ///   A \a IntelPTThreadTrace instance if tracing was successful, or
-  ///   an \a llvm::Error otherwise.
-  static llvm::Expected<IntelPTThreadTraceUP>
-  Create(lldb::pid_t pid, lldb::tid_t tid, size_t buffer_size, bool enable_tsc,
-         llvm::Optional<size_t> psb_period);
-
-  /// Create a \a perf_event_attr configured for
-  /// an IntelPT event.
-  ///
-  /// \return
-  ///   A \a perf_event_attr if successful,
-  ///   or an \a llvm::Error otherwise.
-  static llvm::Expected<perf_event_attr>
-  CreateIntelPTPerfEventConfiguration(bool enable_tsc,
-                                      llvm::Optional<size_t> psb_period);
-
-  /// Read the trace buffer of the currently traced thread.
-  ///
-  /// \param[in] offset
-  ///     Offset of the data to read.
-  ///
-  /// \param[in] size
-  ///     Number of bytes to read.
-  ///
-  /// \return
-  ///     A vector with the requested binary data. The vector will have the
-  ///     size of the requested \a size. Non-available positions will be
-  ///     filled with zeroes.
-  llvm::Expected<std::vector<uint8_t>> GetIntelPTBuffer(size_t offset,
-                                                        size_t size) const;
-
-  Status ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer,
-                          size_t offset = 0) const;
-
-  Status ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer,
-                           size_t offset = 0) const;
-
-  /// Get the size in bytes of the aux section of the thread or process traced
-  /// by this object.
-  size_t GetTraceBufferSize() const;
-
-  /// Read data from a cyclic buffer
-  ///
-  /// \param[in] [out] buf
-  ///     Destination buffer, the buffer will be truncated to written size.
-  ///
-  /// \param[in] src
-  ///     Source buffer which must be a cyclic buffer.
-  ///
-  /// \param[in] src_cyc_index
-  ///     The index pointer (start of the valid data in the cyclic
-  ///     buffer).
-  ///
-  /// \param[in] offset
-  ///     The offset to begin reading the data in the cyclic buffer.
-  static void ReadCyclicBuffer(llvm::MutableArrayRef<uint8_t> &dst,
-                               llvm::ArrayRef<uint8_t> src,
-                               size_t src_cyc_index, size_t offset);
-
-  /// Return the thread-specific part of the jLLDBTraceGetState packet.
-  TraceThreadState GetState() const;
-
-private:
-  /// Construct new \a IntelPTThreadTrace. Users are supposed to create
-  /// instances of this class via the \a Create() method and not invoke this one
-  /// directly.
-  ///
-  /// \param[in] perf_event
-  ///   perf event configured for IntelPT.
-  ///
-  /// \param[in] tid
-  ///   The thread being traced.
-  IntelPTThreadTrace(PerfEvent &&perf_event, lldb::tid_t tid)
-      : m_perf_event(std::move(perf_event)), m_tid(tid) {}
-
-  /// perf event configured for IntelPT.
-  PerfEvent m_perf_event;
-  /// The thread being traced.
-  lldb::tid_t m_tid;
-};
-
 /// Manages a list of thread traces.
 class IntelPTThreadTraceCollection {
 public:
-  IntelPTThreadTraceCollection(lldb::pid_t pid) : m_pid(pid) {}
+  IntelPTThreadTraceCollection() {}
 
   /// Dispose of all traces
   void Clear();
@@ -147,7 +39,7 @@
 
   std::vector<TraceThreadState> GetThreadStates() const;
 
-  llvm::Expected<const IntelPTThreadTrace &>
+  llvm::Expected<const IntelPTSingleBufferTrace &>
   GetTracedThread(lldb::tid_t tid) const;
 
   llvm::Error TraceStart(lldb::tid_t tid,
@@ -156,8 +48,7 @@
   llvm::Error TraceStop(lldb::tid_t tid);
 
 private:
-  lldb::pid_t m_pid;
-  llvm::DenseMap<lldb::tid_t, IntelPTThreadTraceUP> m_thread_traces;
+  llvm::DenseMap<lldb::tid_t, IntelPTSingleBufferTraceUP> m_thread_traces;
   /// Total actual thread buffer size in bytes
   size_t m_total_buffer_size = 0;
 };
@@ -165,8 +56,8 @@
 /// Manages a "process trace" instance.
 class IntelPTProcessTrace {
 public:
-  IntelPTProcessTrace(lldb::pid_t pid, const TraceIntelPTStartRequest &request)
-      : m_thread_traces(pid), m_tracing_params(request) {}
+  IntelPTProcessTrace(const TraceIntelPTStartRequest &request)
+      : m_tracing_params(request) {}
 
   bool TracesThread(lldb::tid_t tid) const;
 
@@ -185,7 +76,7 @@
 /// Main class that manages intel-pt process and thread tracing.
 class IntelPTCollector {
 public:
-  IntelPTCollector(lldb::pid_t pid);
+  IntelPTCollector();
 
   static bool IsSupported();
 
@@ -222,14 +113,13 @@
   llvm::Error TraceStart(lldb::tid_t tid,
                          const TraceIntelPTStartRequest &request);
 
-  llvm::Expected<const IntelPTThreadTrace &>
+  llvm::Expected<const IntelPTSingleBufferTrace &>
   GetTracedThread(lldb::tid_t tid) const;
 
   bool IsProcessTracingEnabled() const;
 
   void ClearProcessTracing();
 
-  lldb::pid_t m_pid;
   /// Threads traced due to "thread tracing"
   IntelPTThreadTraceCollection m_thread_traces;
   /// Threads traced due to "process tracing". Only one active "process tracing"
Index: lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
+++ lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
@@ -32,394 +32,6 @@
 using namespace process_linux;
 using namespace llvm;
 
-const char *kOSEventIntelPTTypeFile =
-    "/sys/bus/event_source/devices/intel_pt/type";
-
-const char *kPSBPeriodCapFile =
-    "/sys/bus/event_source/devices/intel_pt/caps/psb_cyc";
-
-const char *kPSBPeriodValidValuesFile =
-    "/sys/bus/event_source/devices/intel_pt/caps/psb_periods";
-
-const char *kTSCBitOffsetFile =
-    "/sys/bus/event_source/devices/intel_pt/format/tsc";
-
-const char *kPSBPeriodBitOffsetFile =
-    "/sys/bus/event_source/devices/intel_pt/format/psb_period";
-
-enum IntelPTConfigFileType {
-  Hex = 0,
-  // 0 or 1
-  ZeroOne,
-  Decimal,
-  // a bit index file always starts with the prefix config: following by an int,
-  // which represents the offset of the perf_event_attr.config value where to
-  // store a given configuration.
-  BitOffset
-};
-
-static Expected<uint32_t> ReadIntelPTConfigFile(const char *file,
-                                                IntelPTConfigFileType type) {
-  ErrorOr<std::unique_ptr<MemoryBuffer>> stream =
-      MemoryBuffer::getFileAsStream(file);
-
-  if (!stream)
-    return createStringError(inconvertibleErrorCode(),
-                             "Can't open the file '%s'", file);
-
-  uint32_t value = 0;
-  StringRef text_buffer = stream.get()->getBuffer();
-
-  if (type == BitOffset) {
-    const char *prefix = "config:";
-    if (!text_buffer.startswith(prefix))
-      return createStringError(inconvertibleErrorCode(),
-                               "The file '%s' contents doesn't start with '%s'",
-                               file, prefix);
-    text_buffer = text_buffer.substr(strlen(prefix));
-  }
-
-  auto getRadix = [&]() {
-    switch (type) {
-    case Hex:
-      return 16;
-    case ZeroOne:
-    case Decimal:
-    case BitOffset:
-      return 10;
-    }
-    llvm_unreachable("Fully covered switch above!");
-  };
-
-  auto createError = [&](const char *expected_value_message) {
-    return createStringError(
-        inconvertibleErrorCode(),
-        "The file '%s' has an invalid value. It should be %s.", file,
-        expected_value_message);
-  };
-
-  if (text_buffer.trim().consumeInteger(getRadix(), value) ||
-      (type == ZeroOne && value != 0 && value != 1)) {
-    switch (type) {
-    case Hex:
-      return createError("an unsigned hexadecimal int");
-    case ZeroOne:
-      return createError("0 or 1");
-    case Decimal:
-    case BitOffset:
-      return createError("an unsigned decimal int");
-    }
-  }
-  return value;
-}
-
-/// Return the Linux perf event type for Intel PT.
-static Expected<uint32_t> GetOSEventType() {
-  return ReadIntelPTConfigFile(kOSEventIntelPTTypeFile,
-                               IntelPTConfigFileType::Decimal);
-}
-
-static Error CheckPsbPeriod(size_t psb_period) {
-  Expected<uint32_t> cap =
-      ReadIntelPTConfigFile(kPSBPeriodCapFile, IntelPTConfigFileType::ZeroOne);
-  if (!cap)
-    return cap.takeError();
-  if (*cap == 0)
-    return createStringError(inconvertibleErrorCode(),
-                             "psb_period is unsupported in the system.");
-
-  Expected<uint32_t> valid_values = ReadIntelPTConfigFile(
-      kPSBPeriodValidValuesFile, IntelPTConfigFileType::Hex);
-  if (!valid_values)
-    return valid_values.takeError();
-
-  if (valid_values.get() & (1 << psb_period))
-    return Error::success();
-
-  std::ostringstream error;
-  // 0 is always a valid value
-  error << "Invalid psb_period. Valid values are: 0";
-  uint32_t mask = valid_values.get();
-  while (mask) {
-    int index = __builtin_ctz(mask);
-    if (index > 0)
-      error << ", " << index;
-    // clear the lowest bit
-    mask &= mask - 1;
-  }
-  error << ".";
-  return createStringError(inconvertibleErrorCode(), error.str().c_str());
-}
-
-size_t IntelPTThreadTrace::GetTraceBufferSize() const {
-#ifndef PERF_ATTR_SIZE_VER5
-  llvm_unreachable("Intel PT Linux perf event not supported");
-#else
-  return m_perf_event.GetAuxBuffer().size();
-#endif
-}
-
-static Expected<uint64_t>
-GeneratePerfEventConfigValue(bool enable_tsc, Optional<size_t> psb_period) {
-  uint64_t config = 0;
-  // tsc is always supported
-  if (enable_tsc) {
-    if (Expected<uint32_t> offset = ReadIntelPTConfigFile(
-            kTSCBitOffsetFile, IntelPTConfigFileType::BitOffset))
-      config |= 1 << *offset;
-    else
-      return offset.takeError();
-  }
-  if (psb_period) {
-    if (Error error = CheckPsbPeriod(*psb_period))
-      return std::move(error);
-
-    if (Expected<uint32_t> offset = ReadIntelPTConfigFile(
-            kPSBPeriodBitOffsetFile, IntelPTConfigFileType::BitOffset))
-      config |= *psb_period << *offset;
-    else
-      return offset.takeError();
-  }
-  return config;
-}
-
-llvm::Expected<perf_event_attr>
-IntelPTThreadTrace::CreateIntelPTPerfEventConfiguration(
-    bool enable_tsc, Optional<size_t> psb_period) {
-  perf_event_attr attr;
-  memset(&attr, 0, sizeof(attr));
-  attr.size = sizeof(attr);
-  attr.exclude_kernel = 1;
-  attr.sample_type = PERF_SAMPLE_TIME;
-  attr.sample_id_all = 1;
-  attr.exclude_hv = 1;
-  attr.exclude_idle = 1;
-  attr.mmap = 1;
-
-  if (Expected<uint64_t> config_value =
-          GeneratePerfEventConfigValue(enable_tsc, psb_period)) {
-    attr.config = *config_value;
-  } else {
-    return config_value.takeError();
-  }
-
-  if (Expected<uint32_t> intel_pt_type = GetOSEventType()) {
-    attr.type = *intel_pt_type;
-  } else {
-    return intel_pt_type.takeError();
-  }
-
-  return attr;
-}
-
-llvm::Expected<IntelPTThreadTraceUP>
-IntelPTThreadTrace::Create(lldb::pid_t pid, lldb::tid_t tid, size_t buffer_size,
-                           bool enable_tsc, Optional<size_t> psb_period) {
-#ifndef PERF_ATTR_SIZE_VER5
-  llvm_unreachable("Intel PT Linux perf event not supported");
-#else
-  Log *log = GetLog(POSIXLog::Ptrace);
-
-  LLDB_LOG(log, "called thread id {0}", tid);
-
-  if (__builtin_popcount(buffer_size) != 1 || buffer_size < 4096) {
-    return createStringError(
-        inconvertibleErrorCode(),
-        "The trace buffer size must be a power of 2 greater than or equal to "
-        "4096 (2^12) bytes. It was %" PRIu64 ".",
-        buffer_size);
-  }
-  uint64_t page_size = getpagesize();
-  uint64_t buffer_numpages = static_cast<uint64_t>(
-      llvm::PowerOf2Floor((buffer_size + page_size - 1) / page_size));
-
-  Expected<perf_event_attr> attr =
-      IntelPTThreadTrace::CreateIntelPTPerfEventConfiguration(enable_tsc,
-                                                              psb_period);
-  if (!attr)
-    return attr.takeError();
-
-  LLDB_LOG(log, "buffer size {0} ", buffer_size);
-
-  if (Expected<PerfEvent> perf_event = PerfEvent::Init(*attr, tid)) {
-    if (Error mmap_err = perf_event->MmapMetadataAndBuffers(buffer_numpages,
-                                                            buffer_numpages)) {
-      return std::move(mmap_err);
-    }
-    return IntelPTThreadTraceUP(
-        new IntelPTThreadTrace(std::move(*perf_event), tid));
-  } else {
-    return perf_event.takeError();
-  }
-#endif
-}
-
-Expected<std::vector<uint8_t>>
-IntelPTThreadTrace::GetIntelPTBuffer(size_t offset, size_t size) const {
-  std::vector<uint8_t> data(size, 0);
-  MutableArrayRef<uint8_t> buffer_ref(data);
-  Status error = ReadPerfTraceAux(buffer_ref, 0);
-  if (error.Fail())
-    return error.ToError();
-  return data;
-}
-
-Status
-IntelPTThreadTrace::ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer,
-                                     size_t offset) const {
-#ifndef PERF_ATTR_SIZE_VER5
-  llvm_unreachable("perf event not supported");
-#else
-  auto fd = m_perf_event.GetFd();
-  perf_event_mmap_page &mmap_metadata = m_perf_event.GetMetadataPage();
-  // Disable the perf event to force a flush out of the CPU's internal buffer.
-  // Besides, we can guarantee that the CPU won't override any data as we are
-  // reading the buffer.
-  //
-  // The Intel documentation says:
-  //
-  // Packets are first buffered internally and then written out asynchronously.
-  // To collect packet output for postprocessing, a collector needs first to
-  // ensure that all packet data has been flushed from internal buffers.
-  // Software can ensure this by stopping packet generation by clearing
-  // IA32_RTIT_CTL.TraceEn (see “Disabling Packet Generation” in
-  // Section 35.2.7.2).
-  //
-  // This is achieved by the PERF_EVENT_IOC_DISABLE ioctl request, as mentioned
-  // in the man page of perf_event_open.
-  ioctl(fd, PERF_EVENT_IOC_DISABLE);
-
-  Log *log = GetLog(POSIXLog::Ptrace);
-  Status error;
-  uint64_t head = mmap_metadata.aux_head;
-
-  LLDB_LOG(log, "Aux size -{0} , Head - {1}", mmap_metadata.aux_size, head);
-
-  /**
-   * When configured as ring buffer, the aux buffer keeps wrapping around
-   * the buffer and its not possible to detect how many times the buffer
-   * wrapped. Initially the buffer is filled with zeros,as shown below
-   * so in order to get complete buffer we first copy firstpartsize, followed
-   * by any left over part from beginning to aux_head
-   *
-   * aux_offset [d,d,d,d,d,d,d,d,0,0,0,0,0,0,0,0,0,0,0] aux_size
-   *                 aux_head->||<- firstpartsize  ->|
-   *
-   * */
-
-  ReadCyclicBuffer(buffer, m_perf_event.GetAuxBuffer(),
-                   static_cast<size_t>(head), offset);
-  LLDB_LOG(log, "ReadCyclic Buffer Done");
-
-  // Reenable tracing now we have read the buffer
-  ioctl(fd, PERF_EVENT_IOC_ENABLE);
-  return error;
-#endif
-}
-
-Status
-IntelPTThreadTrace::ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer,
-                                      size_t offset) const {
-#ifndef PERF_ATTR_SIZE_VER5
-  llvm_unreachable("perf event not supported");
-#else
-  Log *log = GetLog(POSIXLog::Ptrace);
-  uint64_t bytes_remaining = buffer.size();
-  Status error;
-
-  perf_event_mmap_page &mmap_metadata = m_perf_event.GetMetadataPage();
-  uint64_t head = mmap_metadata.data_head;
-
-  /*
-   * The data buffer and aux buffer have different implementations
-   * with respect to their definition of head pointer. In the case
-   * of Aux data buffer the head always wraps around the aux buffer
-   * and we don't need to care about it, whereas the data_head keeps
-   * increasing and needs to be wrapped by modulus operator
-   */
-
-  LLDB_LOG(log, "bytes_remaining - {0}", bytes_remaining);
-
-  auto data_buffer = m_perf_event.GetDataBuffer();
-
-  if (head > data_buffer.size()) {
-    head = head % data_buffer.size();
-    LLDB_LOG(log, "Data size -{0} Head - {1}", mmap_metadata.data_size, head);
-
-    ReadCyclicBuffer(buffer, data_buffer, static_cast<size_t>(head), offset);
-    bytes_remaining -= buffer.size();
-  } else {
-    LLDB_LOG(log, "Head - {0}", head);
-    if (offset >= head) {
-      LLDB_LOG(log, "Invalid Offset ");
-      error.SetErrorString("invalid offset");
-      buffer = buffer.slice(buffer.size());
-      return error;
-    }
-
-    auto data = data_buffer.slice(offset, (head - offset));
-    auto remaining = std::copy(data.begin(), data.end(), buffer.begin());
-    bytes_remaining -= (remaining - buffer.begin());
-  }
-  buffer = buffer.drop_back(bytes_remaining);
-  return error;
-#endif
-}
-
-void IntelPTThreadTrace::ReadCyclicBuffer(llvm::MutableArrayRef<uint8_t> &dst,
-                                          llvm::ArrayRef<uint8_t> src,
-                                          size_t src_cyc_index, size_t offset) {
-
-  Log *log = GetLog(POSIXLog::Ptrace);
-
-  if (dst.empty() || src.empty()) {
-    dst = dst.drop_back(dst.size());
-    return;
-  }
-
-  if (dst.data() == nullptr || src.data() == nullptr) {
-    dst = dst.drop_back(dst.size());
-    return;
-  }
-
-  if (src_cyc_index > src.size()) {
-    dst = dst.drop_back(dst.size());
-    return;
-  }
-
-  if (offset >= src.size()) {
-    LLDB_LOG(log, "Too Big offset ");
-    dst = dst.drop_back(dst.size());
-    return;
-  }
-
-  llvm::SmallVector<ArrayRef<uint8_t>, 2> parts = {
-      src.slice(src_cyc_index), src.take_front(src_cyc_index)};
-
-  if (offset > parts[0].size()) {
-    parts[1] = parts[1].slice(offset - parts[0].size());
-    parts[0] = parts[0].drop_back(parts[0].size());
-  } else if (offset == parts[0].size()) {
-    parts[0] = parts[0].drop_back(parts[0].size());
-  } else {
-    parts[0] = parts[0].slice(offset);
-  }
-  auto next = dst.begin();
-  auto bytes_left = dst.size();
-  for (auto part : parts) {
-    size_t chunk_size = std::min(part.size(), bytes_left);
-    next = std::copy_n(part.begin(), chunk_size, next);
-    bytes_left -= chunk_size;
-  }
-  dst = dst.drop_back(bytes_left);
-}
-
-TraceThreadState IntelPTThreadTrace::GetState() const {
-  return {static_cast<int64_t>(m_tid),
-          {TraceBinaryData{IntelPTDataKinds::kThreadTraceBuffer,
-                           static_cast<int64_t>(GetTraceBufferSize())}}};
-}
-
 /// IntelPTThreadTraceCollection
 
 bool IntelPTThreadTraceCollection::TracesThread(lldb::tid_t tid) const {
@@ -442,9 +54,8 @@
     return createStringError(inconvertibleErrorCode(),
                              "Thread %" PRIu64 " already traced", tid);
 
-  Expected<IntelPTThreadTraceUP> trace_up = IntelPTThreadTrace::Create(
-      m_pid, tid, request.trace_buffer_size, request.enable_tsc,
-      request.psb_period.map([](int64_t period) { return (size_t)period; }));
+  Expected<IntelPTSingleBufferTraceUP> trace_up =
+      IntelPTSingleBufferTrace::Start(request, tid);
   if (!trace_up)
     return trace_up.takeError();
 
@@ -461,11 +72,14 @@
 IntelPTThreadTraceCollection::GetThreadStates() const {
   std::vector<TraceThreadState> states;
   for (const auto &it : m_thread_traces)
-    states.push_back(it.second->GetState());
+    states.push_back({static_cast<int64_t>(it.first),
+                      {TraceBinaryData{IntelPTDataKinds::kTraceBuffer,
+                                       static_cast<int64_t>(
+                                           it.second->GetTraceBufferSize())}}});
   return states;
 }
 
-Expected<const IntelPTThreadTrace &>
+Expected<const IntelPTSingleBufferTrace &>
 IntelPTThreadTraceCollection::GetTracedThread(lldb::tid_t tid) const {
   auto it = m_thread_traces.find(tid);
   if (it == m_thread_traces.end())
@@ -510,8 +124,7 @@
 
 /// IntelPTCollector
 
-IntelPTCollector::IntelPTCollector(lldb::pid_t pid)
-    : m_pid(pid), m_thread_traces(pid) {
+IntelPTCollector::IntelPTCollector() {
   if (Expected<LinuxPerfZeroTscConversion> tsc_conversion =
           LoadPerfTscConversionParameters())
     m_tsc_conversion =
@@ -553,7 +166,7 @@
       return createStringError(inconvertibleErrorCode(),
                                "Per-core tracing is not supported.");
     }
-    m_process_trace = IntelPTProcessTrace(m_pid, request);
+    m_process_trace = IntelPTProcessTrace(request);
 
     Error error = Error::success();
     for (lldb::tid_t tid : process_threads)
@@ -604,7 +217,7 @@
   return toJSON(state);
 }
 
-Expected<const IntelPTThreadTrace &>
+Expected<const IntelPTSingleBufferTrace &>
 IntelPTCollector::GetTracedThread(lldb::tid_t tid) const {
   if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid))
     return m_process_trace->GetThreadTraces().GetTracedThread(tid);
@@ -613,10 +226,10 @@
 
 Expected<std::vector<uint8_t>>
 IntelPTCollector::GetBinaryData(const TraceGetBinaryDataRequest &request) const {
-  if (request.kind == IntelPTDataKinds::kThreadTraceBuffer) {
-    if (Expected<const IntelPTThreadTrace &> trace =
+  if (request.kind == IntelPTDataKinds::kTraceBuffer) {
+    if (Expected<const IntelPTSingleBufferTrace &> trace =
             GetTracedThread(*request.tid))
-      return trace->GetIntelPTBuffer(request.offset, request.size);
+      return trace->GetTraceBuffer(request.offset, request.size);
     else
       return trace.takeError();
   } else if (request.kind == IntelPTDataKinds::kProcFsCpuInfo) {
@@ -630,12 +243,12 @@
 void IntelPTCollector::ClearProcessTracing() { m_process_trace = None; }
 
 bool IntelPTCollector::IsSupported() {
-  Expected<uint32_t> intel_pt_type = GetOSEventType();
-  if (!intel_pt_type) {
+  if (Expected<uint32_t> intel_pt_type = GetIntelPTOSEventType()) {
+    return true;
+  } else {
     llvm::consumeError(intel_pt_type.takeError());
     return false;
   }
-  return true;
 }
 
 bool IntelPTCollector::IsProcessTracingEnabled() const {
Index: lldb/source/Plugins/Process/Linux/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/Process/Linux/CMakeLists.txt
+++ lldb/source/Plugins/Process/Linux/CMakeLists.txt
@@ -1,5 +1,6 @@
 add_lldb_library(lldbPluginProcessLinux
   IntelPTCollector.cpp
+  IntelPTSingleBufferTrace.cpp
   NativeProcessLinux.cpp
   NativeRegisterContextLinux.cpp
   NativeRegisterContextLinux_arm.cpp
Index: lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
===================================================================
--- lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
+++ lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
@@ -21,7 +21,7 @@
 // List of data kinds used by jLLDBGetState and jLLDBGetBinaryData.
 struct IntelPTDataKinds {
   static const char *kProcFsCpuInfo;
-  static const char *kThreadTraceBuffer;
+  static const char *kTraceBuffer;
 };
 
 /// jLLDBTraceStart gdb-remote packet
Index: lldb/docs/lldb-gdb-remote.txt
===================================================================
--- lldb/docs/lldb-gdb-remote.txt
+++ lldb/docs/lldb-gdb-remote.txt
@@ -495,7 +495,7 @@
 // INTEL PT
 //
 //  Binary data kinds:
-//    - threadTraceBuffer: trace buffer for a thread.
+//    - traceBuffer: trace buffer for a thread or a core.
 //    - procfsCpuInfo: contents of the /proc/cpuinfo file.
 //
 //  Counter info kinds:
@@ -550,7 +550,7 @@
 // INTEL PT
 //
 //  Binary data kinds:
-//    - threadTraceBuffer: trace buffer for a thread.
+//    - traceBuffer: trace buffer for a thread or a core.
 //    - procfsCpuInfo: contents of the /proc/cpuinfo file.
 //----------------------------------------------------------------------
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to