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

comments addressed


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D86670

Files:
  lldb/include/lldb/Target/Target.h
  lldb/include/lldb/Target/Trace.h
  lldb/source/Commands/CommandObjectTrace.cpp
  lldb/source/Commands/Options.td
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
  lldb/source/Target/Target.cpp
  lldb/source/Target/Trace.cpp
  lldb/source/Target/TraceSettingsParser.cpp
  lldb/test/API/commands/trace/TestTraceDump.py
  lldb/test/API/commands/trace/intelpt-trace/trace2.json

Index: lldb/test/API/commands/trace/intelpt-trace/trace2.json
===================================================================
--- /dev/null
+++ lldb/test/API/commands/trace/intelpt-trace/trace2.json
@@ -0,0 +1,53 @@
+{
+  "trace": {
+    "type": "intel-pt",
+    "pt_cpu": {
+      "vendor": "intel",
+      "family": 6,
+      "model": 79,
+      "stepping": 1
+    }
+  },
+  "processes": [
+    {
+      "pid": 1,
+      "triple": "x86_64-*-linux",
+      "threads": [
+        {
+          "tid": 11,
+          "traceFile": "3842849.trace"
+        }
+      ],
+      "modules": [
+        {
+          "file": "a.out",
+          "systemPath": "a.out",
+          "loadAddress": "0x0000000000400000",
+          "uuid": "6AA9A4E2-6F28-2F33-377D-59FECE874C71-5B41261A"
+        }
+      ]
+    },
+    {
+      "pid": 2,
+      "triple": "x86_64-*-linux",
+      "threads": [
+        {
+          "tid": 21,
+          "traceFile": "3842849.trace"
+        },
+        {
+          "tid": 22,
+          "traceFile": "3842849.trace"
+        }
+      ],
+      "modules": [
+        {
+          "file": "a.out",
+          "systemPath": "a.out",
+          "loadAddress": "0x0000000000400000",
+          "uuid": "6AA9A4E2-6F28-2F33-377D-59FECE874C71-5B41261A"
+        }
+      ]
+    }
+  ]
+}
Index: lldb/test/API/commands/trace/TestTraceDump.py
===================================================================
--- /dev/null
+++ lldb/test/API/commands/trace/TestTraceDump.py
@@ -0,0 +1,49 @@
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+from lldbsuite.test.decorators import *
+
+class TestTraceDump(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def setUp(self):
+        TestBase.setUp(self)
+        if 'intel-pt' not in configuration.enabled_plugins:
+            self.skipTest("The intel-pt test plugin is not enabled")
+        self.src_dir = self.getSourceDir()
+
+    def testDumpMissingTrace(self):
+        self.expect("target create " + os.path.join(self.src_dir, 'intelpt-trace', 'a.out'))
+        self.expect("trace dump", substrs=["error: no trace data in this target"])
+
+    def testDumpTrace(self):
+        self.expect("trace load " + os.path.join(self.src_dir, "intelpt-trace", "trace2.json"))
+
+        # An invalid thread id should show an error message
+        self.expect("trace dump -t 5678", substrs=['error: the thread id "5678" does not exist in this target'])
+
+        # Only the specified thread should be printed
+        self.expect("trace dump -t 22", substrs=["Trace files"],
+          patterns=["pid: '2', tid: '22', trace file: .*/test/API/commands/trace/intelpt-trace/3842849.trace",
+                    "Modules:\n  uuid: 6AA9A4E2-6F28-2F33-377D-59FECE874C71-5B41261A, load address: 0x0000000000400000, file: .*intelpt-trace/a.out"])
+
+        # Verbose should output the entire JSON settings besides the thread specific information
+        self.expect("trace dump -t 22 -v",
+          substrs=["Settings", "3842849.trace", "intel-pt", "Settings directory"],
+          patterns=["pid: '2', tid: '22', trace file: .*/test/API/commands/trace/intelpt-trace/3842849.trace"])
+
+        # In this case all threads should be printed
+        self.expect("trace dump", substrs=["Trace files"],
+          patterns=["pid: '2', tid: '21', trace file: .*/test/API/commands/trace/intelpt-trace/3842849.trace",
+            "pid: '2', tid: '22', trace file: .*/test/API/commands/trace/intelpt-trace/3842849.trace"])
+
+        self.expect("trace dump -t 21 -t 22", substrs=["Trace files"],
+          patterns=["pid: '2', tid: '21', trace file: .*/test/API/commands/trace/intelpt-trace/3842849.trace",
+            "pid: '2', tid: '22', trace file: .*/test/API/commands/trace/intelpt-trace/3842849.trace"])
+
+        # We switch targets and check the threads of this target
+        self.dbg.SetSelectedTarget(self.dbg.FindTargetWithProcessID(1))
+        self.expect("trace dump", substrs=["Trace files"],
+          patterns=["pid: '1', tid: '11', trace file: .*/test/API/commands/trace/intelpt-trace/3842849.trace"])
Index: lldb/source/Target/TraceSettingsParser.cpp
===================================================================
--- lldb/source/Target/TraceSettingsParser.cpp
+++ lldb/source/Target/TraceSettingsParser.cpp
@@ -166,10 +166,12 @@
     return err;
   }
 
+  for (auto target_sp : m_targets)
+    target_sp->SetTrace(m_trace.shared_from_this());
+
   m_trace.m_settings = *raw_settings.getAsObject();
   m_trace.m_settings_dir = m_settings_dir;
   m_trace.m_thread_to_trace_file_map = m_thread_to_trace_file_map;
-  m_trace.m_targets = m_targets;
 
   return llvm::Error::success();
 }
Index: lldb/source/Target/Trace.cpp
===================================================================
--- lldb/source/Target/Trace.cpp
+++ lldb/source/Target/Trace.cpp
@@ -13,6 +13,7 @@
 #include "llvm/Support/Format.h"
 
 #include "lldb/Core/PluginManager.h"
+#include "lldb/Target/Target.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -85,11 +86,7 @@
 llvm::Error Trace::ParseSettings(Debugger &debugger,
                                  const llvm::json::Value &settings,
                                  llvm::StringRef settings_dir) {
-  if (llvm::Error err =
-          CreateParser()->ParseSettings(debugger, settings, settings_dir))
-    return err;
-
-  return llvm::Error::success();
+  return CreateParser()->ParseSettings(debugger, settings, settings_dir);
 }
 
 llvm::StringRef Trace::GetSchema() { return CreateParser()->GetSchema(); }
Index: lldb/source/Target/Target.cpp
===================================================================
--- lldb/source/Target/Target.cpp
+++ lldb/source/Target/Target.cpp
@@ -2965,6 +2965,31 @@
   return error;
 }
 
+void Target::SetTrace(const lldb::TraceSP &trace_sp) { m_trace_sp = trace_sp; }
+
+lldb::TraceSP &Target::GetTrace() { return m_trace_sp; }
+
+void Target::DumpTrace(Stream &s, TraceDumpOptions &options) {
+  if (!m_trace_sp) {
+    s << "error: no trace data in this target";
+    return;
+  }
+  if (!m_process_sp) {
+    s << "error: no process in this target";
+    return;
+  }
+  options.process = m_process_sp.get();
+  ThreadSP thread_sp;
+  for (lldb::tid_t tid : options.tids) {
+    if (!m_process_sp->GetThreadList().FindThreadByID(tid)) {
+      s.Printf("error: the thread id \"%" PRIu64
+               "\" does not exist in this target",
+               tid);
+    }
+  }
+  m_trace_sp->Dump(s, options);
+}
+
 Status Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) {
   auto state = eStateInvalid;
   auto process_sp = GetProcessSP();
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
@@ -18,7 +18,8 @@
 
 class TraceIntelPT : public lldb_private::Trace {
 public:
-  void Dump(lldb_private::Stream *s) const override;
+  void Dump(lldb_private::Stream &s,
+            const lldb_private::TraceDumpOptions &options) const override;
 
   ~TraceIntelPT() override = default;
 
@@ -43,6 +44,11 @@
   std::unique_ptr<lldb_private::TraceSettingsParser> CreateParser() override;
 
 private:
+  void DumpJSONSettings(lldb_private::Stream &s) const;
+
+  void DumpTraceFiles(lldb_private::Stream &s,
+                      const lldb_private::TraceDumpOptions &options) const;
+
   friend class TraceIntelPTSettingsParser;
   pt_cpu m_pt_cpu;
 };
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
@@ -8,8 +8,16 @@
 
 #include "TraceIntelPT.h"
 
+#include <cassert>
+
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+
 #include "TraceIntelPTSettingsParser.h"
+#include "lldb/Core/Module.h"
 #include "lldb/Core/PluginManager.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/SectionLoadList.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -44,7 +52,98 @@
 
 uint32_t TraceIntelPT::GetPluginVersion() { return 1; }
 
-void TraceIntelPT::Dump(lldb_private::Stream *s) const {}
+void DumpImages(Stream &s, const TraceDumpOptions &options) {
+  s << "\n\nModules:";
+  s.IndentMore();
+
+  Target &target = options.process->GetTarget();
+  const ModuleList &modules = target.GetImages();
+
+  for (size_t i = 0; i < modules.GetSize(); i++) {
+    const ModuleSP module = modules.GetModuleAtIndex(i);
+    s << "\n";
+    s.Indent();
+    if (module->GetUUID().IsValid()) {
+      s << "uuid: ";
+      module->GetUUID().Dump(&s);
+      s << ", ";
+    }
+
+    if (ObjectFile *objfile = module->GetObjectFile()) {
+      Address base_addr(objfile->GetBaseAddress());
+      if (base_addr.IsValid()) {
+        s << "load address: ";
+        if (!target.GetSectionLoadList().IsEmpty()) {
+          lldb::addr_t load_addr = base_addr.GetLoadAddress(&target);
+          if (load_addr == LLDB_INVALID_ADDRESS) {
+            base_addr.Dump(&s, &target, Address::DumpStyleModuleWithFileAddress,
+                           Address::DumpStyleFileAddress);
+          } else {
+            // Show the load address of the image
+            s.Printf("0x%" PRIx64, load_addr);
+          }
+        } else {
+          // The address was valid, but the image isn't loaded, output the
+          // address in an appropriate format
+          base_addr.Dump(&s, &target, Address::DumpStyleFileAddress);
+        }
+        s << ", ";
+      }
+    }
+    s << "file: ";
+    module->GetFileSpec().Dump(s.AsRawOstream());
+  }
+
+  s.IndentLess();
+}
+
+void TraceIntelPT::DumpJSONSettings(Stream &s) const {
+  s << "Settings:\n";
+  std::string str;
+  llvm::raw_string_ostream OS(str);
+  json::Object obj = m_settings;
+  OS << llvm::formatv("{0:2}", json::Value(std::move(obj)));
+  OS.flush();
+  s << OS.str();
+
+  s << "\n\nSettings directory:\n";
+  s.IndentMore();
+  s.Indent();
+  s << m_settings_dir << "\n\n";
+  s.IndentLess();
+}
+
+void TraceIntelPT::DumpTraceFiles(Stream &s,
+                                  const TraceDumpOptions &options) const {
+  s << "Trace files:";
+
+  lldb::pid_t pid = options.process->GetID();
+  const auto &process_it = m_thread_to_trace_file_map.find(pid);
+  if (process_it == m_thread_to_trace_file_map.end())
+    return;
+
+  s.IndentMore();
+  for (const auto &thread_trace_file : process_it->second) {
+    lldb::tid_t tid = thread_trace_file.first;
+    if (options.tids.empty() || options.tids.count(tid)) {
+      s << "\n";
+      s.Indent();
+      s.Printf("pid: '%" PRIu64 "', tid: '%" PRIu64 "', trace file: ", pid,
+               tid);
+      s << thread_trace_file.second;
+    }
+  }
+  s.IndentLess();
+}
+
+void TraceIntelPT::Dump(Stream &s, const TraceDumpOptions &options) const {
+  assert(options.process != nullptr && "The process field must be specified");
+  if (options.verbose)
+    DumpJSONSettings(s);
+
+  DumpTraceFiles(s, options);
+  DumpImages(s, options);
+}
 
 lldb::TraceSP TraceIntelPT::CreateInstance() {
   return lldb::TraceSP(new TraceIntelPT());
Index: lldb/source/Commands/Options.td
===================================================================
--- lldb/source/Commands/Options.td
+++ lldb/source/Commands/Options.td
@@ -1188,6 +1188,8 @@
 let Command = "trace dump" in {
   def trace_dump_verbose : Option<"verbose", "v">, Group<1>,
     Desc<"Show verbose trace information.">;
+  def trace_dump_thread_id : Option<"thread-id", "t">, Group<1>,
+    Arg<"ThreadID">, Desc<"The thread id to dump trace information of. Can be repeated multiple times to dump the information of several threads.">;
 }
 
 let Command = "trace schema" in {
Index: lldb/source/Commands/CommandObjectTrace.cpp
===================================================================
--- lldb/source/Commands/CommandObjectTrace.cpp
+++ lldb/source/Commands/CommandObjectTrace.cpp
@@ -147,7 +147,16 @@
 
       switch (short_option) {
       case 'v': {
-        m_verbose = true;
+        m_dump_options.verbose = true;
+        break;
+      }
+      case 't': {
+        lldb::tid_t tid;
+        if (option_arg.empty() || option_arg.getAsInteger(0, tid))
+          error.SetErrorStringWithFormat("invalid thread id string '%s'",
+                                         option_arg.str().c_str());
+        else
+          m_dump_options.tids.insert(tid);
         break;
       }
       default:
@@ -157,20 +166,21 @@
     }
 
     void OptionParsingStarting(ExecutionContext *execution_context) override {
-      m_verbose = false;
+      m_dump_options = TraceDumpOptions();
     }
 
     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
       return llvm::makeArrayRef(g_trace_dump_options);
     }
 
-    bool m_verbose; // Enable verbose logging for debugging purposes.
+    TraceDumpOptions m_dump_options;
   };
 
   CommandObjectTraceDump(CommandInterpreter &interpreter)
-      : CommandObjectParsed(interpreter, "trace dump",
-                            "Dump the loaded processor trace data.",
-                            "trace dump"),
+      : CommandObjectParsed(
+            interpreter, "trace dump",
+            "Dump the loaded processor trace data in the current target.",
+            "trace dump", eCommandRequiresTarget),
         m_options() {}
 
   ~CommandObjectTraceDump() override = default;
@@ -180,8 +190,11 @@
 protected:
   bool DoExecute(Args &command, CommandReturnObject &result) override {
     Status error;
-    // TODO: fill in the dumping code here!
+    Target &target = GetSelectedTarget();
+    target.DumpTrace(result.GetOutputStream(), m_options.m_dump_options);
+
     if (error.Success()) {
+      result.AppendMessage("\n");
       result.SetStatus(eReturnStatusSuccessFinishResult);
     } else {
       result.AppendErrorWithFormat("%s\n", error.AsCString());
Index: lldb/include/lldb/Target/Trace.h
===================================================================
--- lldb/include/lldb/Target/Trace.h
+++ lldb/include/lldb/Target/Trace.h
@@ -18,6 +18,17 @@
 
 namespace lldb_private {
 
+/// Helper class that holds the configuration of a Dump action.
+///
+/// The \a process field must be set before invoking \a Trace::Dump.
+///
+/// If \a tids is empty, then all threads of the given process are considered.
+struct TraceDumpOptions {
+  Process *process = nullptr;
+  std::set<lldb::tid_t> tids;
+  bool verbose = false;
+};
+
 /// \class Trace Trace.h "lldb/Target/Trace.h"
 /// A plug-in interface definition class for trace information.
 ///
@@ -33,17 +44,21 @@
 /// Processor trace information can also be fetched through the process
 /// interfaces during a live debug session if your process supports gathering
 /// this information.
-class Trace : public PluginInterface {
+class Trace : public PluginInterface,
+              public std::enable_shared_from_this<Trace> {
 public:
   /// Dump the trace data that this plug-in has access to.
   ///
   /// This function will dump all of the trace data for all threads in a user
-  /// readable format. Options for dumping can be added as this API is iterated
-  /// on.
+  /// readable format.
   ///
   /// \param[in] s
   ///     A stream object to dump the information to.
-  virtual void Dump(Stream *s) const = 0;
+  ///
+  /// \param[in] options
+  ///   The trace dump options. See \a TraceDumpOptions for more information.
+  virtual void Dump(lldb_private::Stream &s,
+                    const TraceDumpOptions &options) const = 0;
 
   /// Find a trace plug-in using JSON data.
   ///
@@ -135,7 +150,6 @@
 
   std::map<lldb::pid_t, std::map<lldb::tid_t, lldb_private::FileSpec>>
       m_thread_to_trace_file_map;
-  std::vector<lldb::TargetSP> m_targets;
 };
 
 } // namespace lldb_private
Index: lldb/include/lldb/Target/Target.h
===================================================================
--- lldb/include/lldb/Target/Target.h
+++ lldb/include/lldb/Target/Target.h
@@ -29,6 +29,7 @@
 #include "lldb/Target/PathMappingList.h"
 #include "lldb/Target/SectionLoadHistory.h"
 #include "lldb/Target/ThreadSpec.h"
+#include "lldb/Target/Trace.h"
 #include "lldb/Utility/ArchSpec.h"
 #include "lldb/Utility/Broadcaster.h"
 #include "lldb/Utility/LLDBAssert.h"
@@ -210,7 +211,7 @@
   bool GetInjectLocalVariables(ExecutionContext *exe_ctx) const;
 
   void SetInjectLocalVariables(ExecutionContext *exe_ctx, bool b);
-  
+
   void SetRequireHardwareBreakpoints(bool b);
 
   bool GetRequireHardwareBreakpoints() const;
@@ -1105,6 +1106,29 @@
 
   void ClearAllLoadedSections();
 
+  /// Set the \a Trace object containing processor trace information of this
+  /// target.
+  ///
+  /// \param[in] trace_sp
+  ///   The trace object.
+  void SetTrace(const lldb::TraceSP &trace_sp);
+
+  /// Get the \a Trace object containing processor trace information of this
+  /// target.
+  ///
+  /// \return
+  ///   The trace object. It might be undefined.
+  lldb::TraceSP &GetTrace();
+
+  /// Dump the \a Trace information.
+  ///
+  /// \param[in] s
+  ///   The stream object where the information is printed.
+  ///
+  /// \param[in] options
+  ///   The trace dump options. See \a TraceDumpOptions for more information.
+  void DumpTrace(Stream &s, lldb_private::TraceDumpOptions &options);
+
   // Since expressions results can persist beyond the lifetime of a process,
   // and the const expression results are available after a process is gone, we
   // provide a way for expressions to be evaluated from the Target itself. If
@@ -1394,6 +1418,9 @@
   bool m_suppress_stop_hooks;
   bool m_is_dummy_target;
   unsigned m_next_persistent_variable_index = 0;
+  /// An optional \a lldb_private::Trace object containing processor trace
+  /// information of this target.
+  lldb::TraceSP m_trace_sp;
   /// Stores the frame recognizers of this target.
   lldb::StackFrameRecognizerManagerUP m_frame_recognizer_manager_up;
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to