jj10306 created this revision.
jj10306 added a reviewer: wallace.
Herald added a project: All.
jj10306 requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

Add trace load functionality to SBDebugger via the `LoadTraceFromFile` method.
Update intelpt test case class to have `testTraceLoad` method so we can take 
advantage of
the testApiAndSB decorator to test both the CLI and SB without duplicating code.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D128107

Files:
  lldb/bindings/interface/SBDebugger.i
  lldb/include/lldb/API/SBDebugger.h
  lldb/include/lldb/API/SBTrace.h
  lldb/include/lldb/Target/Trace.h
  lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
  lldb/source/API/SBDebugger.cpp
  lldb/source/API/SBTrace.cpp
  lldb/source/Commands/CommandObjectTrace.cpp
  lldb/source/Target/Trace.cpp
  lldb/test/API/commands/trace/TestTraceLoad.py

Index: lldb/test/API/commands/trace/TestTraceLoad.py
===================================================================
--- lldb/test/API/commands/trace/TestTraceLoad.py
+++ lldb/test/API/commands/trace/TestTraceLoad.py
@@ -9,10 +9,11 @@
     mydir = TestBase.compute_mydir(__file__)
     NO_DEBUG_INFO_TESTCASE = True
 
+    @testSBAPIAndCommands
     def testLoadMultiCoreTrace(self):
         src_dir = self.getSourceDir()
         trace_definition_file = os.path.join(src_dir, "intelpt-multi-core-trace", "trace.json")
-        self.expect("trace load -v " + trace_definition_file, substrs=["intel-pt"])
+        self.traceLoad(traceSessionFilePath=trace_definition_file, substrs=["intel-pt"])
         self.expect("thread trace dump instructions 2 -t",
           substrs=["19521: [tsc=0x008fb5211c143fd8] error: expected tracing enabled event",
                    "m.out`foo() + 65 at multi_thread.cpp:12:21",
@@ -21,10 +22,11 @@
           substrs=["67910: [tsc=0x008fb5211bfdf270] 0x0000000000400bd7    addl   $0x1, -0x4(%rbp)",
                    "m.out`bar() + 26 at multi_thread.cpp:20:6"])
 
+    @testSBAPIAndCommands
     def testLoadMultiCoreTraceWithStringNumbers(self):
         src_dir = self.getSourceDir()
         trace_definition_file = os.path.join(src_dir, "intelpt-multi-core-trace", "trace_with_string_numbers.json")
-        self.expect("trace load -v " + trace_definition_file, substrs=["intel-pt"])
+        self.traceLoad(traceSessionFilePath=trace_definition_file, substrs=["intel-pt"])
         self.expect("thread trace dump instructions 2 -t",
           substrs=["19521: [tsc=0x008fb5211c143fd8] error: expected tracing enabled event",
                    "m.out`foo() + 65 at multi_thread.cpp:12:21",
@@ -33,10 +35,11 @@
           substrs=["67910: [tsc=0x008fb5211bfdf270] 0x0000000000400bd7    addl   $0x1, -0x4(%rbp)",
                    "m.out`bar() + 26 at multi_thread.cpp:20:6"])
 
+    @testSBAPIAndCommands
     def testLoadMultiCoreTraceWithMissingThreads(self):
         src_dir = self.getSourceDir()
         trace_definition_file = os.path.join(src_dir, "intelpt-multi-core-trace", "trace_missing_threads.json")
-        self.expect("trace load -v " + trace_definition_file, substrs=["intel-pt"])
+        self.traceLoad(traceSessionFilePath=trace_definition_file, substrs=["intel-pt"])
         self.expect("thread trace dump instructions 3 -t",
           substrs=["19521: [tsc=0x008fb5211c143fd8] error: expected tracing enabled event",
                    "m.out`foo() + 65 at multi_thread.cpp:12:21",
@@ -45,10 +48,11 @@
           substrs=["67910: [tsc=0x008fb5211bfdf270] 0x0000000000400bd7    addl   $0x1, -0x4(%rbp)",
                    "m.out`bar() + 26 at multi_thread.cpp:20:6"])
 
+    @testSBAPIAndCommands
     def testLoadTrace(self):
         src_dir = self.getSourceDir()
         trace_definition_file = os.path.join(src_dir, "intelpt-trace", "trace.json")
-        self.expect("trace load -v " + trace_definition_file, substrs=["intel-pt"])
+        self.traceLoad(traceSessionFilePath=trace_definition_file, substrs=["intel-pt"])
 
         target = self.dbg.GetSelectedTarget()
         process = target.GetProcess()
@@ -90,11 +94,12 @@
   Errors:
     Number of TSC decoding errors: 0'''])
 
+    @testSBAPIAndCommands
     def testLoadInvalidTraces(self):
         src_dir = self.getSourceDir()
+        trace_definition_file = os.path.join(src_dir, "intelpt-trace", "trace_bad.json")
         # We test first an invalid type
-        self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad.json"), error=True,
-          substrs=['''error: expected object at traceSession.processes[0]
+        self.traceLoad(traceSessionFilePath=trace_definition_file, error=True, substrs=['''error: expected object at traceSession.processes[0]
 
 Context:
 {
Index: lldb/source/Target/Trace.cpp
===================================================================
--- lldb/source/Target/Trace.cpp
+++ lldb/source/Target/Trace.cpp
@@ -89,6 +89,30 @@
       plugin_name.data());
 }
 
+llvm::Expected<lldb::TraceSP>
+Trace::LoadPostMortemTraceFromFile(Debugger &debugger,
+                                   llvm::StringRef trace_session_file_path) {
+
+  FileSpec json_file(trace_session_file_path);
+
+  auto buffer_or_error = llvm::MemoryBuffer::getFile(json_file.GetPath());
+  if (!buffer_or_error) {
+    return llvm::createStringError(
+        std::errc::invalid_argument, "could not open input file: %s - %s.",
+        json_file.GetPath().c_str(),
+        buffer_or_error.getError().message().c_str());
+  }
+
+  llvm::Expected<json::Value> session_file =
+      json::parse(buffer_or_error.get()->getBuffer().str());
+  if (!session_file) {
+    return session_file.takeError();
+  }
+
+  return Trace::FindPluginForPostMortemProcess(
+      debugger, *session_file, json_file.GetDirectory().AsCString());
+}
+
 Expected<lldb::TraceSP>
 Trace::FindPluginForPostMortemProcess(Debugger &debugger,
                                       const json::Value &trace_session_file,
Index: lldb/source/Commands/CommandObjectTrace.cpp
===================================================================
--- lldb/source/Commands/CommandObjectTrace.cpp
+++ lldb/source/Commands/CommandObjectTrace.cpp
@@ -85,41 +85,24 @@
     if (command.size() != 1) {
       result.AppendError(
           "a single path to a JSON file containing a trace session"
-          "is required");
+          " is required");
       return false;
     }
 
-    auto end_with_failure = [&result](llvm::Error err) -> bool {
-      result.AppendErrorWithFormat("%s\n",
-                                   llvm::toString(std::move(err)).c_str());
-      return false;
-    };
-
-    FileSpec json_file(command[0].ref());
+    llvm::Expected<lldb::TraceSP> trace_or_err =
+        Trace::LoadPostMortemTraceFromFile(GetDebugger(), command[0].ref());
 
-    auto buffer_or_error = llvm::MemoryBuffer::getFile(json_file.GetPath());
-    if (!buffer_or_error) {
-      return end_with_failure(llvm::createStringError(
-          std::errc::invalid_argument, "could not open input file: %s - %s.",
-          json_file.GetPath().c_str(),
-          buffer_or_error.getError().message().c_str()));
+    if (!trace_or_err) {
+      result.AppendErrorWithFormat(
+          "%s\n", llvm::toString(trace_or_err.takeError()).c_str());
+      return false;
     }
 
-    llvm::Expected<json::Value> session_file =
-        json::parse(buffer_or_error.get()->getBuffer().str());
-    if (!session_file)
-      return end_with_failure(session_file.takeError());
-
-    if (Expected<lldb::TraceSP> traceOrErr =
-            Trace::FindPluginForPostMortemProcess(
-                GetDebugger(), *session_file,
-                json_file.GetDirectory().AsCString())) {
-      lldb::TraceSP trace_sp = traceOrErr.get();
-      if (m_options.m_verbose && trace_sp)
-        result.AppendMessageWithFormatv("loading trace with plugin {0}\n",
-                                        trace_sp->GetPluginName());
-    } else
-      return end_with_failure(traceOrErr.takeError());
+    lldb::TraceSP trace_sp = trace_or_err.get();
+    if (m_options.m_verbose && trace_sp) {
+      result.AppendMessageWithFormatv("loading trace with plugin {0}\n",
+                                      trace_sp->GetPluginName());
+    }
 
     result.SetStatus(eReturnStatusSuccessFinishResult);
     return true;
Index: lldb/source/API/SBTrace.cpp
===================================================================
--- lldb/source/API/SBTrace.cpp
+++ lldb/source/API/SBTrace.cpp
@@ -9,6 +9,7 @@
 #include "lldb/Target/Process.h"
 #include "lldb/Utility/Instrumentation.h"
 
+#include "lldb/API/SBDebugger.h"
 #include "lldb/API/SBStructuredData.h"
 #include "lldb/API/SBThread.h"
 #include "lldb/API/SBTrace.h"
@@ -26,6 +27,21 @@
   LLDB_INSTRUMENT_VA(this, trace_sp);
 }
 
+SBTrace SBTrace::LoadTraceFromFile(SBError &error, SBDebugger &debugger,
+                                   const char *trace_session_file_path) {
+
+  llvm::Expected<lldb::TraceSP> trace_or_err =
+      Trace::LoadPostMortemTraceFromFile(debugger.ref(),
+                                         trace_session_file_path);
+
+  if (!trace_or_err) {
+    error.SetErrorString(llvm::toString(trace_or_err.takeError()).c_str());
+    return SBTrace();
+  }
+
+  return SBTrace(trace_or_err.get());
+}
+
 const char *SBTrace::GetStartConfigurationHelp() {
   LLDB_INSTRUMENT_VA(this);
   return m_opaque_sp ? m_opaque_sp->GetStartConfigurationHelp() : nullptr;
Index: lldb/source/API/SBDebugger.cpp
===================================================================
--- lldb/source/API/SBDebugger.cpp
+++ lldb/source/API/SBDebugger.cpp
@@ -27,6 +27,7 @@
 #include "lldb/API/SBStructuredData.h"
 #include "lldb/API/SBTarget.h"
 #include "lldb/API/SBThread.h"
+#include "lldb/API/SBTrace.h"
 #include "lldb/API/SBTypeCategory.h"
 #include "lldb/API/SBTypeFilter.h"
 #include "lldb/API/SBTypeFormat.h"
@@ -1633,3 +1634,8 @@
     return m_opaque_sp->SetLoggingCallback(log_callback, baton);
   }
 }
+
+SBTrace SBDebugger::LoadTraceFromFile(SBError &error,
+                                      const char *trace_file_path) {
+  return SBTrace::LoadTraceFromFile(error, *this, trace_file_path);
+}
Index: lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
+++ lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
@@ -133,3 +133,12 @@
             if thread is not None:
                 command += " " + str(thread.GetIndexID())
             self.expect(command, error=error, substrs=substrs)
+
+    def traceLoad(self, traceSessionFilePath="trace.json", error=False, substrs=None):
+        if self.USE_SB_API:
+            loadTraceError = lldb.SBError()
+            _trace = self.dbg.LoadTraceFromFile(loadTraceError, traceSessionFilePath)
+            self.assertSBError(loadTraceError, error)
+        else:
+            command = f"trace load -v {traceSessionFilePath}"
+            self.expect(command, error=error, substrs=substrs)
Index: lldb/include/lldb/Target/Trace.h
===================================================================
--- lldb/include/lldb/Target/Trace.h
+++ lldb/include/lldb/Target/Trace.h
@@ -137,6 +137,24 @@
   static llvm::Expected<llvm::StringRef>
   FindPluginSchema(llvm::StringRef plugin_name);
 
+  /// Load trace from trace session file and create Targets based on the
+  /// contents of the file.
+  ///
+  /// \param[in] debugger
+  ///     The debugger instance where new Targets will be created as part of the
+  ///     JSON data parsing.
+  ///
+  /// \param[in] trace_session_file_path
+  ///     The full or partial path of the trace session file describing the
+  ///     trace session.
+  ///
+  /// \return
+  ///     A \a TraceSP instance, or an \a llvm::Error if loading the trace
+  ///     from file fails.
+  static llvm::Expected<lldb::TraceSP>
+  LoadPostMortemTraceFromFile(Debugger &debugger,
+                              llvm::StringRef trace_session_file_path);
+
   /// Get the command handle for the "process trace start" command.
   virtual lldb::CommandObjectSP
   GetProcessTraceStartCommand(CommandInterpreter &interpreter) = 0;
Index: lldb/include/lldb/API/SBTrace.h
===================================================================
--- lldb/include/lldb/API/SBTrace.h
+++ lldb/include/lldb/API/SBTrace.h
@@ -12,8 +12,6 @@
 #include "lldb/API/SBDefines.h"
 #include "lldb/API/SBError.h"
 
-class TraceImpl;
-
 namespace lldb {
 
 class LLDB_API SBTrace {
@@ -23,6 +21,27 @@
 
   SBTrace(const lldb::TraceSP &trace_sp);
 
+  /// Load trace from trace session file and create Targets based on the
+  /// contents of the file.
+  ///
+  /// \param[out] error
+  ///   An error if the trace could not be created.
+  ///
+  /// \param[in] debugger
+  ///     The debugger instance where new Targets will be created as part of the
+  ///     JSON data parsing.
+  ///
+  /// \param[in] trace_session_file_path
+  ///     The full or partial path of the trace session file describing the
+  ///     trace session.  static SBTrace LoadTraceFromFile(SBDebugger &debugger,
+  ///     const char *trace_session_file_path);
+  ///
+  /// \return
+  ///     A \a TraceSP instance, or an \a llvm::Error if loading the trace
+  ///     from file fails.
+  static SBTrace LoadTraceFromFile(SBError &error, SBDebugger &debugger,
+                                   const char *trace_session_file_path);
+
   /// \return
   ///     A description of the parameters to use for the \a SBTrace::Start
   ///     method, or \b null if the object is invalid.
Index: lldb/include/lldb/API/SBDebugger.h
===================================================================
--- lldb/include/lldb/API/SBDebugger.h
+++ lldb/include/lldb/API/SBDebugger.h
@@ -391,6 +391,17 @@
 
   SBError RunREPL(lldb::LanguageType language, const char *repl_options);
 
+  /// Load trace from trace session file and create Targets based on the
+  /// contents of the file.
+  ///
+  /// \param[out] error
+  ///   An error if the trace could not be created.
+  ///
+  /// \param[in] trace_session_file_path
+  ///     The full or partial path of the trace session file describing the
+  ///     trace session.
+  SBTrace LoadTraceFromFile(SBError &error, const char *trace_file_path);
+
 private:
   friend class SBCommandInterpreter;
   friend class SBInputReader;
@@ -398,6 +409,7 @@
   friend class SBProcess;
   friend class SBSourceManager;
   friend class SBTarget;
+  friend class SBTrace;
 
   lldb::SBTarget FindTargetWithLLDBProcess(const lldb::ProcessSP &processSP);
 
Index: lldb/bindings/interface/SBDebugger.i
===================================================================
--- lldb/bindings/interface/SBDebugger.i
+++ lldb/bindings/interface/SBDebugger.i
@@ -542,6 +542,8 @@
     lldb::SBError
     RunREPL (lldb::LanguageType language, const char *repl_options);
 
+    SBTrace LoadTraceFromFile(SBError &error, const char *trace_file_path);
+
 #ifdef SWIGPYTHON
     %pythoncode%{
     def __iter__(self):
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to