[Lldb-commits] [lldb] e0cfe20 - [trace][intel pt] Create a common accessor for live and postmortem data

Walter Erquinigo via lldb-commits lldb-commits at lists.llvm.org
Thu Apr 7 16:06:56 PDT 2022


Author: Walter Erquinigo
Date: 2022-04-07T15:58:44-07:00
New Revision: e0cfe20ad2fb8c7aab3d6e82c42649eacf595d9f

URL: https://github.com/llvm/llvm-project/commit/e0cfe20ad2fb8c7aab3d6e82c42649eacf595d9f
DIFF: https://github.com/llvm/llvm-project/commit/e0cfe20ad2fb8c7aab3d6e82c42649eacf595d9f.diff

LOG: [trace][intel pt] Create a common accessor for live and postmortem data

Some parts of the code have to distinguish between live and postmortem threads
to figure out how to get some data, e.g. thread trace buffers. This makes the
code less generic and more error prone. An example of that is that we have
two different decoders: LiveThreadDecoder and PostMortemThreadDecoder. They
exist because getting the trace bufer is different for each case.

The problem doesn't stop there. Soon we'll have even more kinds of data, like
the context switch trace, whose fetching will be different for live and post-
mortem processes.

As a way to fix this, I'm creating a common API for accessing thread data,
which is able to figure out how to handle the postmortem and live cases on
behalf of the caller. As a result of that, I was able to eliminate the two
decoders and unify them into a simpler one. Not only that, our TraceSave
functionality only worked for live threads, but now it can also work for
postmortem processes, which might be useful now, but it might in the future.

This common API is OnThreadBinaryDataRead. More information in the inline
documentation.

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

Added: 
    

Modified: 
    lldb/include/lldb/Target/Trace.h
    lldb/source/Plugins/Trace/common/TraceSessionSaver.cpp
    lldb/source/Plugins/Trace/common/TraceSessionSaver.h
    lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
    lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h
    lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
    lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.h
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionSaver.cpp
    lldb/source/Target/Trace.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Target/Trace.h b/lldb/include/lldb/Target/Trace.h
index c4ca192a1c263..78575119b680b 100644
--- a/lldb/include/lldb/Target/Trace.h
+++ b/lldb/include/lldb/Target/Trace.h
@@ -233,15 +233,76 @@ class Trace : public PluginInterface,
   ///     \a llvm::Error otherwise.
   llvm::Error Stop();
 
-  /// Get the trace file of the given post mortem thread.
-  llvm::Expected<const FileSpec &> GetPostMortemTraceFile(lldb::tid_t tid);
-
   /// \return
   ///     The stop ID of the live process being traced, or an invalid stop ID
   ///     if the trace is in an error or invalid state.
   uint32_t GetStopID();
 
+  using OnBinaryDataReadCallback =
+      std::function<llvm::Error(llvm::ArrayRef<uint8_t> data)>;
+  /// Fetch binary data associated with a thread, either live or postmortem, and
+  /// pass it to the given callback. The reason of having a callback is to free
+  /// the caller from having to manage the life cycle of the data and to hide
+  /// the 
diff erent data fetching procedures that exist for live and post mortem
+  /// threads.
+  ///
+  /// The fetched data is not persisted after the callback is invoked.
+  ///
+  /// \param[in] tid
+  ///     The tid who owns the data.
+  ///
+  /// \param[in] kind
+  ///     The kind of data to read.
+  ///
+  /// \param[in] callback
+  ///     The callback to be invoked once the data was successfully read. Its
+  ///     return value, which is an \a llvm::Error, is returned by this
+  ///     function.
+  ///
+  /// \return
+  ///     An \a llvm::Error if the data couldn't be fetched, or the return value
+  ///     of the callback, otherwise.
+  llvm::Error OnThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind,
+                                     OnBinaryDataReadCallback callback);
+
 protected:
+  /// Implementation of \a OnThreadBinaryDataRead() for live threads.
+  llvm::Error OnLiveThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind,
+                                         OnBinaryDataReadCallback callback);
+
+  /// Implementation of \a OnThreadBinaryDataRead() for post mortem threads.
+  llvm::Error
+  OnPostMortemThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind,
+                                   OnBinaryDataReadCallback callback);
+
+  /// Get the file path containing data of a postmortem thread given a data
+  /// identifier.
+  ///
+  /// \param[in] tid
+  ///     The thread whose data is requested.
+  ///
+  /// \param[in] kind
+  ///     The kind of data requested.
+  ///
+  /// \return
+  ///     The file spec containing the requested data, or an \a llvm::Error in
+  ///     case of failures.
+  llvm::Expected<FileSpec> GetPostMortemThreadDataFile(lldb::tid_t tid,
+                                                       llvm::StringRef kind);
+
+  /// Associate a given thread with a data file using a data identifier.
+  ///
+  /// \param[in] tid
+  ///     The thread associated with the data file.
+  ///
+  /// \param[in] kind
+  ///     The kind of data being registered.
+  ///
+  /// \param[in] file_spec
+  ///     The path of the data file.
+  void SetPostMortemThreadDataFile(lldb::tid_t tid, llvm::StringRef kind,
+                                   FileSpec file_spec);
+
   /// Get binary data of a live thread given a data identifier.
   ///
   /// \param[in] tid
@@ -315,11 +376,25 @@ class Trace : public PluginInterface,
   uint32_t m_stop_id = LLDB_INVALID_STOP_ID;
   /// Process traced by this object if doing live tracing. Otherwise it's null.
   Process *m_live_process = nullptr;
+
+  /// These data kinds are returned by lldb-server when fetching the state of
+  /// the tracing session. The size in bytes can be used later for fetching the
+  /// data in batches.
+  /// \{
+
   /// tid -> data kind -> size
-  std::map<lldb::tid_t, std::unordered_map<std::string, size_t>>
+  llvm::DenseMap<lldb::tid_t, std::unordered_map<std::string, size_t>>
       m_live_thread_data;
+
   /// data kind -> size
   std::unordered_map<std::string, size_t> m_live_process_data;
+  /// \}
+
+  /// Postmortem traces can specific additional data files, which are
+  /// represented in this variable using a data kind identifier for each file.
+  /// tid -> data kind -> file
+  llvm::DenseMap<lldb::tid_t, std::unordered_map<std::string, FileSpec>>
+      m_postmortem_thread_data;
 };
 
 } // namespace lldb_private

diff  --git a/lldb/source/Plugins/Trace/common/TraceSessionSaver.cpp b/lldb/source/Plugins/Trace/common/TraceSessionSaver.cpp
index 8c20a3b158cd0..e1d62062b8e79 100644
--- a/lldb/source/Plugins/Trace/common/TraceSessionSaver.cpp
+++ b/lldb/source/Plugins/Trace/common/TraceSessionSaver.cpp
@@ -39,15 +39,12 @@ llvm::Error TraceSessionSaver::WriteSessionToFile(
 }
 
 llvm::Expected<JSONTraceSessionBase> TraceSessionSaver::BuildProcessesSection(
-    Process &live_process,
-    std::function<
-        llvm::Expected<llvm::Optional<std::vector<uint8_t>>>(lldb::tid_t tid)>
-        raw_trace_fetcher,
+    Process &live_process, llvm::StringRef raw_thread_trace_data_kind,
     FileSpec directory) {
 
   JSONTraceSessionBase json_session_description;
   Expected<std::vector<JSONThread>> json_threads =
-      BuildThreadsSection(live_process, raw_trace_fetcher, directory);
+      BuildThreadsSection(live_process, raw_thread_trace_data_kind, directory);
   if (!json_threads)
     return json_threads.takeError();
 
@@ -64,39 +61,41 @@ llvm::Expected<JSONTraceSessionBase> TraceSessionSaver::BuildProcessesSection(
 }
 
 llvm::Expected<std::vector<JSONThread>> TraceSessionSaver::BuildThreadsSection(
-    Process &live_process,
-    std::function<
-        llvm::Expected<llvm::Optional<std::vector<uint8_t>>>(lldb::tid_t tid)>
-        raw_trace_fetcher,
+    Process &live_process, llvm::StringRef raw_thread_trace_data_kind,
     FileSpec directory) {
   std::vector<JSONThread> json_threads;
   for (ThreadSP thread_sp : live_process.Threads()) {
+    TraceSP trace_sp = live_process.GetTarget().GetTrace();
+    lldb::tid_t tid = thread_sp->GetID();
+    if (!trace_sp->IsTraced(tid))
+      continue;
+
     // resolve the directory just in case
     FileSystem::Instance().Resolve(directory);
     FileSpec raw_trace_path = directory;
-    raw_trace_path.AppendPathComponent(std::to_string(thread_sp->GetID()) +
-                                       ".trace");
-    json_threads.push_back(JSONThread{static_cast<int64_t>(thread_sp->GetID()),
+    raw_trace_path.AppendPathComponent(std::to_string(tid) + ".trace");
+    json_threads.push_back(JSONThread{static_cast<int64_t>(tid),
                                       raw_trace_path.GetPath().c_str()});
 
-    llvm::Expected<llvm::Optional<std::vector<uint8_t>>> raw_trace =
-        raw_trace_fetcher(thread_sp->GetID());
-
-    if (!raw_trace)
-      return raw_trace.takeError();
-    if (!raw_trace.get())
-      continue;
-
-    std::basic_fstream<char> raw_trace_fs = std::fstream(
-        raw_trace_path.GetPath().c_str(), std::ios::out | std::ios::binary);
-    raw_trace_fs.write(reinterpret_cast<const char *>(&raw_trace.get()->at(0)),
-                       raw_trace.get()->size() * sizeof(uint8_t));
-    raw_trace_fs.close();
-    if (!raw_trace_fs) {
-      return createStringError(inconvertibleErrorCode(),
-                               formatv("couldn't write to the file {0}",
-                                       raw_trace_path.GetPath().c_str()));
-    }
+    llvm::Error err =
+        live_process.GetTarget().GetTrace()->OnThreadBinaryDataRead(
+            tid, raw_thread_trace_data_kind,
+            [&](llvm::ArrayRef<uint8_t> data) -> llvm::Error {
+              std::basic_fstream<char> raw_trace_fs =
+                  std::fstream(raw_trace_path.GetPath().c_str(),
+                               std::ios::out | std::ios::binary);
+              raw_trace_fs.write(reinterpret_cast<const char *>(&data[0]),
+                                 data.size() * sizeof(uint8_t));
+              raw_trace_fs.close();
+              if (!raw_trace_fs)
+                return createStringError(
+                    inconvertibleErrorCode(),
+                    formatv("couldn't write to the file {0}",
+                            raw_trace_path.GetPath().c_str()));
+              return Error::success();
+            });
+    if (err)
+      return std::move(err);
   }
   return json_threads;
 }

diff  --git a/lldb/source/Plugins/Trace/common/TraceSessionSaver.h b/lldb/source/Plugins/Trace/common/TraceSessionSaver.h
index 9a1a75c167dc2..c490fd747ffc2 100644
--- a/lldb/source/Plugins/Trace/common/TraceSessionSaver.h
+++ b/lldb/source/Plugins/Trace/common/TraceSessionSaver.h
@@ -39,11 +39,8 @@ class TraceSessionSaver {
   /// \param[in] live_process
   ///     The process being traced.
   ///
-  /// \param[in] raw_trace_fetcher
-  ///     Callback function that receives a thread ID and returns its raw trace.
-  ///     This callback should return \a None if the thread is not being traced.
-  ///     Otherwise, it should return the raw trace in bytes or an
-  ///     \a llvm::Error in case of failures.
+  /// \param[in] raw_thread_trace_data_kind
+  ///     Identifier for the data kind of the raw trace for each thread.
   ///
   /// \param[in] directory
   ///     The directory where files will be saved when building the processes
@@ -51,12 +48,10 @@ class TraceSessionSaver {
   ///
   /// \return
   ///     The processes section or \a llvm::Error in case of failures.
-  static llvm::Expected<JSONTraceSessionBase> BuildProcessesSection(
-      Process &live_process,
-      std::function<
-          llvm::Expected<llvm::Optional<std::vector<uint8_t>>>(lldb::tid_t tid)>
-          raw_trace_fetcher,
-      FileSpec directory);
+  static llvm::Expected<JSONTraceSessionBase>
+  BuildProcessesSection(Process &live_process,
+                        llvm::StringRef raw_thread_trace_data_kind,
+                        FileSpec directory);
 
   /// Build the threads sub-section of the trace session description file.
   /// For each traced thread, its raw trace is also written to the file
@@ -65,11 +60,8 @@ class TraceSessionSaver {
   /// \param[in] live_process
   ///     The process being traced.
   ///
-  /// \param[in] raw_trace_fetcher
-  ///     Callback function that receives a thread ID and returns its raw trace.
-  ///     This callback should return \a None if the thread is not being traced.
-  ///     Otherwise, it should return the raw trace in bytes or an
-  ///     \a llvm::Error in case of failures.
+  /// \param[in] raw_thread_trace_data_kind
+  ///     Identifier for the data kind of the raw trace for each thread.
   ///
   /// \param[in] directory
   ///     The directory where files will be saved when building the threads
@@ -77,12 +69,10 @@ class TraceSessionSaver {
   ///
   /// \return
   ///     The threads section or \a llvm::Error in case of failures.
-  static llvm::Expected<std::vector<JSONThread>> BuildThreadsSection(
-      Process &live_process,
-      std::function<
-          llvm::Expected<llvm::Optional<std::vector<uint8_t>>>(lldb::tid_t tid)>
-          raw_trace_fetcher,
-      FileSpec directory);
+  static llvm::Expected<std::vector<JSONThread>>
+  BuildThreadsSection(Process &live_process,
+                      llvm::StringRef raw_thread_trace_data_kind,
+                      FileSpec directory);
 
   /// Build modules sub-section of the trace's session. The original modules
   /// will be copied over to the \a <directory/modules> folder. Invalid modules

diff  --git a/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp b/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
index 713795cb7264b..1d9e8ce991117 100644
--- a/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
@@ -255,7 +255,7 @@ using PtInsnDecoderUP =
 static Expected<PtInsnDecoderUP>
 CreateInstructionDecoder(DecodedThread &decoded_thread,
                          TraceIntelPT &trace_intel_pt,
-                         MutableArrayRef<uint8_t> buffer) {
+                         ArrayRef<uint8_t> buffer) {
   Expected<pt_cpu> cpu_info = trace_intel_pt.GetCPUInfo();
   if (!cpu_info)
     return cpu_info.takeError();
@@ -268,8 +268,10 @@ CreateInstructionDecoder(DecodedThread &decoded_thread,
   if (IsLibiptError(status = pt_cpu_errata(&config.errata, &config.cpu)))
     return make_error<IntelPTError>(status);
 
-  config.begin = buffer.data();
-  config.end = buffer.data() + buffer.size();
+  // The libipt library does not modify the trace buffer, hence the
+  // following casts are safe.
+  config.begin = const_cast<uint8_t *>(buffer.data());
+  config.end = const_cast<uint8_t *>(buffer.data() + buffer.size());
 
   pt_insn_decoder *decoder_ptr = pt_insn_alloc_decoder(&config);
   if (!decoder_ptr)
@@ -285,9 +287,11 @@ CreateInstructionDecoder(DecodedThread &decoded_thread,
   return decoder_up;
 }
 
-void lldb_private::trace_intel_pt::DecodeTrace(
-    DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt,
-    MutableArrayRef<uint8_t> buffer) {
+void lldb_private::trace_intel_pt::DecodeTrace(DecodedThread &decoded_thread,
+                                               TraceIntelPT &trace_intel_pt,
+                                               ArrayRef<uint8_t> buffer) {
+  decoded_thread.SetRawTraceSize(buffer.size());
+
   Expected<PtInsnDecoderUP> decoder_up =
       CreateInstructionDecoder(decoded_thread, trace_intel_pt, buffer);
   if (!decoder_up)

diff  --git a/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h b/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h
index c8c33b6a2eefc..21e7bf3085eda 100644
--- a/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h
+++ b/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h
@@ -21,7 +21,7 @@ namespace trace_intel_pt {
 /// instructions and errors in \p decoded_thread. It uses the low level libipt
 /// library underneath.
 void DecodeTrace(DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt,
-                 llvm::MutableArrayRef<uint8_t> buffer);
+                 llvm::ArrayRef<uint8_t> buffer);
 
 } // namespace trace_intel_pt
 } // namespace lldb_private

diff  --git a/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp b/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
index 2e6d13b2fa6e2..1ffa4d197c853 100644
--- a/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
@@ -20,7 +20,8 @@ using namespace lldb_private;
 using namespace lldb_private::trace_intel_pt;
 using namespace llvm;
 
-// ThreadDecoder ====================
+ThreadDecoder::ThreadDecoder(const ThreadSP &thread_sp, TraceIntelPT &trace)
+    : m_thread_sp(thread_sp), m_trace(trace) {}
 
 DecodedThreadSP ThreadDecoder::Decode() {
   if (!m_decoded_thread.hasValue())
@@ -28,52 +29,16 @@ DecodedThreadSP ThreadDecoder::Decode() {
   return *m_decoded_thread;
 }
 
-// LiveThreadDecoder ====================
-
-LiveThreadDecoder::LiveThreadDecoder(Thread &thread, TraceIntelPT &trace)
-    : m_thread_sp(thread.shared_from_this()), m_trace(trace) {}
-
-DecodedThreadSP LiveThreadDecoder::DoDecode() {
+DecodedThreadSP ThreadDecoder::DoDecode() {
   DecodedThreadSP decoded_thread_sp =
       std::make_shared<DecodedThread>(m_thread_sp);
 
-  Expected<std::vector<uint8_t>> buffer =
-      m_trace.GetLiveThreadBuffer(m_thread_sp->GetID());
-  if (!buffer) {
-    decoded_thread_sp->AppendError(buffer.takeError());
-    return decoded_thread_sp;
-  }
-
-  decoded_thread_sp->SetRawTraceSize(buffer->size());
-  DecodeTrace(*decoded_thread_sp, m_trace, MutableArrayRef<uint8_t>(*buffer));
-  return decoded_thread_sp;
-}
-
-// PostMortemThreadDecoder =======================
-
-PostMortemThreadDecoder::PostMortemThreadDecoder(
-    const lldb::ThreadPostMortemTraceSP &trace_thread, TraceIntelPT &trace)
-    : m_trace_thread(trace_thread), m_trace(trace) {}
-
-DecodedThreadSP PostMortemThreadDecoder::DoDecode() {
-  DecodedThreadSP decoded_thread_sp =
-      std::make_shared<DecodedThread>(m_trace_thread);
-
-  ErrorOr<std::unique_ptr<MemoryBuffer>> trace_or_error =
-      MemoryBuffer::getFile(m_trace_thread->GetTraceFile().GetPath());
-  if (std::error_code err = trace_or_error.getError()) {
-    decoded_thread_sp->AppendError(errorCodeToError(err));
-    return decoded_thread_sp;
-  }
-
-  MemoryBuffer &trace = **trace_or_error;
-  MutableArrayRef<uint8_t> trace_data(
-      // The libipt library does not modify the trace buffer, hence the
-      // following cast is safe.
-      reinterpret_cast<uint8_t *>(const_cast<char *>(trace.getBufferStart())),
-      trace.getBufferSize());
-  decoded_thread_sp->SetRawTraceSize(trace_data.size());
-
-  DecodeTrace(*decoded_thread_sp, m_trace, trace_data);
+  Error err = m_trace.OnThreadBufferRead(
+      m_thread_sp->GetID(), [&](llvm::ArrayRef<uint8_t> data) {
+        DecodeTrace(*decoded_thread_sp, m_trace, data);
+        return Error::success();
+      });
+  if (err)
+    decoded_thread_sp->AppendError(std::move(err));
   return decoded_thread_sp;
 }

diff  --git a/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.h b/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.h
index b487667c34b1c..06bb958a3e721 100644
--- a/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.h
+++ b/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.h
@@ -19,12 +19,15 @@
 namespace lldb_private {
 namespace trace_intel_pt {
 
-/// Base class that handles the decoding of a thread and caches the result.
+/// Class that handles the decoding of a thread and caches the result.
 class ThreadDecoder {
 public:
-  virtual ~ThreadDecoder() = default;
-
-  ThreadDecoder() = default;
+  /// \param[in] thread_sp
+  ///     The thread whose trace buffer will be decoded.
+  ///
+  /// \param[in] trace
+  ///     The main Trace object who owns this decoder and its data.
+  ThreadDecoder(const lldb::ThreadSP &thread_sp, TraceIntelPT &trace);
 
   /// Decode the thread and store the result internally, to avoid
   /// recomputations.
@@ -36,49 +39,12 @@ class ThreadDecoder {
   ThreadDecoder(const ThreadDecoder &other) = delete;
   ThreadDecoder &operator=(const ThreadDecoder &other) = delete;
 
-protected:
-  /// Decode the thread.
-  ///
-  /// \return
-  ///     A \a DecodedThread instance.
-  virtual DecodedThreadSP DoDecode() = 0;
-
-  llvm::Optional<DecodedThreadSP> m_decoded_thread;
-};
-
-/// Decoder implementation for \a lldb_private::ThreadPostMortemTrace, which are
-/// non-live processes that come trace session files.
-class PostMortemThreadDecoder : public ThreadDecoder {
-public:
-  /// \param[in] trace_thread
-  ///     The thread whose trace file will be decoded.
-  ///
-  /// \param[in] trace
-  ///     The main Trace object who owns this decoder and its data.
-  PostMortemThreadDecoder(const lldb::ThreadPostMortemTraceSP &trace_thread,
-                          TraceIntelPT &trace);
-
 private:
-  DecodedThreadSP DoDecode() override;
-
-  lldb::ThreadPostMortemTraceSP m_trace_thread;
-  TraceIntelPT &m_trace;
-};
-
-class LiveThreadDecoder : public ThreadDecoder {
-public:
-  /// \param[in] thread
-  ///     The thread whose traces will be decoded.
-  ///
-  /// \param[in] trace
-  ///     The main Trace object who owns this decoder and its data.
-  LiveThreadDecoder(Thread &thread, TraceIntelPT &trace);
-
-private:
-  DecodedThreadSP DoDecode() override;
+  DecodedThreadSP DoDecode();
 
   lldb::ThreadSP m_thread_sp;
   TraceIntelPT &m_trace;
+  llvm::Optional<DecodedThreadSP> m_decoded_thread;
 };
 
 } // namespace trace_intel_pt

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
index 8c4468a72b2db..325bcb9acc163 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
@@ -78,10 +78,12 @@ TraceIntelPT::TraceIntelPT(
     const pt_cpu &cpu_info,
     const std::vector<ThreadPostMortemTraceSP> &traced_threads)
     : m_cpu_info(cpu_info) {
-  for (const ThreadPostMortemTraceSP &thread : traced_threads)
-    m_thread_decoders.emplace(
-        thread->GetID(),
-        std::make_unique<PostMortemThreadDecoder>(thread, *this));
+  for (const ThreadPostMortemTraceSP &thread : traced_threads) {
+    m_thread_decoders.emplace(thread->GetID(),
+                              std::make_unique<ThreadDecoder>(thread, *this));
+    SetPostMortemThreadDataFile(thread->GetID(), "threadTraceBuffer",
+                                thread->GetTraceFile());
+  }
 }
 
 DecodedThreadSP TraceIntelPT::Decode(Thread &thread) {
@@ -213,10 +215,10 @@ void TraceIntelPT::DoRefreshLiveProcessState(
   }
 
   for (const TraceThreadState &thread_state : state->tracedThreads) {
-    Thread &thread =
-        *m_live_process->GetThreadList().FindThreadByID(thread_state.tid);
+    ThreadSP thread_sp =
+        m_live_process->GetThreadList().FindThreadByID(thread_state.tid);
     m_thread_decoders.emplace(
-        thread_state.tid, std::make_unique<LiveThreadDecoder>(thread, *this));
+        thread_state.tid, std::make_unique<ThreadDecoder>(thread_sp, *this));
   }
 }
 
@@ -352,7 +354,7 @@ Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
   return Start(tids, thread_buffer_size, enable_tsc, psb_period);
 }
 
-Expected<std::vector<uint8_t>>
-TraceIntelPT::GetLiveThreadBuffer(lldb::tid_t tid) {
-  return Trace::GetLiveThreadBinaryData(tid, "threadTraceBuffer");
+Error TraceIntelPT::OnThreadBufferRead(lldb::tid_t tid,
+                                       OnBinaryDataReadCallback callback) {
+  return OnThreadBinaryDataRead(tid, "threadTraceBuffer", callback);
 }

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
index a8d51f4fa5e7a..3b93374029d0b 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
@@ -137,8 +137,9 @@ class TraceIntelPT : public Trace {
                     StructuredData::ObjectSP configuration =
                         StructuredData::ObjectSP()) override;
 
-  /// Get the thread buffer content for a live thread
-  llvm::Expected<std::vector<uint8_t>> GetLiveThreadBuffer(lldb::tid_t tid);
+  /// See \a Trace::OnThreadBinaryDataRead().
+  llvm::Error OnThreadBufferRead(lldb::tid_t tid,
+                                 OnBinaryDataReadCallback callback);
 
   llvm::Expected<pt_cpu> GetCPUInfo();
 

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionSaver.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionSaver.cpp
index a8d03db1c25c9..241d9c52d0627 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionSaver.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionSaver.cpp
@@ -48,15 +48,8 @@ llvm::Error TraceIntelPTSessionSaver::SaveToDisk(TraceIntelPT &trace_ipt,
     return json_intel_pt_trace.takeError();
 
   llvm::Expected<JSONTraceSessionBase> json_session_description =
-      TraceSessionSaver::BuildProcessesSection(
-          *live_process,
-          [&](lldb::tid_t tid)
-              -> llvm::Expected<llvm::Optional<std::vector<uint8_t>>> {
-            if (!trace_ipt.IsTraced(tid))
-              return None;
-            return trace_ipt.GetLiveThreadBuffer(tid);
-          },
-          directory);
+      TraceSessionSaver::BuildProcessesSection(*live_process,
+                                               "threadTraceBuffer", directory);
 
   if (!json_session_description)
     return json_session_description.takeError();

diff  --git a/lldb/source/Target/Trace.cpp b/lldb/source/Target/Trace.cpp
index 7f9ae54455cb1..b33d5afb3b34c 100644
--- a/lldb/source/Target/Trace.cpp
+++ b/lldb/source/Target/Trace.cpp
@@ -215,3 +215,64 @@ uint32_t Trace::GetStopID() {
   RefreshLiveProcessState();
   return m_stop_id;
 }
+
+llvm::Expected<FileSpec>
+Trace::GetPostMortemThreadDataFile(lldb::tid_t tid, llvm::StringRef kind) {
+  auto NotFoundError = [&]() {
+    return createStringError(
+        inconvertibleErrorCode(),
+        formatv("The thread with tid={0} doesn't have the tracing data {1}",
+                tid, kind));
+  };
+
+  auto it = m_postmortem_thread_data.find(tid);
+  if (it == m_postmortem_thread_data.end())
+    return NotFoundError();
+
+  std::unordered_map<std::string, FileSpec> &data_kind_to_file_spec_map =
+      it->second;
+  auto it2 = data_kind_to_file_spec_map.find(kind.str());
+  if (it2 == data_kind_to_file_spec_map.end())
+    return NotFoundError();
+  return it2->second;
+}
+
+void Trace::SetPostMortemThreadDataFile(lldb::tid_t tid, llvm::StringRef kind,
+                                        FileSpec file_spec) {
+  m_postmortem_thread_data[tid][kind.str()] = file_spec;
+}
+
+llvm::Error
+Trace::OnLiveThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind,
+                                  OnBinaryDataReadCallback callback) {
+  Expected<std::vector<uint8_t>> data = GetLiveThreadBinaryData(tid, kind);
+  if (!data)
+    return data.takeError();
+  return callback(*data);
+}
+
+llvm::Error
+Trace::OnPostMortemThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind,
+                                        OnBinaryDataReadCallback callback) {
+  Expected<FileSpec> file = GetPostMortemThreadDataFile(tid, kind);
+  if (!file)
+    return file.takeError();
+  ErrorOr<std::unique_ptr<MemoryBuffer>> trace_or_error =
+      MemoryBuffer::getFile(file->GetPath());
+  if (std::error_code err = trace_or_error.getError())
+    return errorCodeToError(err);
+
+  MemoryBuffer &data = **trace_or_error;
+  ArrayRef<uint8_t> array_ref(
+      reinterpret_cast<const uint8_t *>(data.getBufferStart()),
+      data.getBufferSize());
+  return callback(array_ref);
+}
+
+llvm::Error Trace::OnThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind,
+                                          OnBinaryDataReadCallback callback) {
+  if (m_live_process)
+    return OnLiveThreadBinaryDataRead(tid, kind, callback);
+  else
+    return OnPostMortemThreadBinaryDataRead(tid, kind, callback);
+}


        


More information about the lldb-commits mailing list