[Lldb-commits] [lldb] 50f9367 - Add LoadTraceFromFile to SBDebugger and SBTrace
Jakob Johnson via lldb-commits
lldb-commits at lists.llvm.org
Mon Jun 20 12:06:10 PDT 2022
Author: Jakob Johnson
Date: 2022-06-20T11:54:47-07:00
New Revision: 50f9367960725b450a9ef779d73e32a35031ee70
URL: https://github.com/llvm/llvm-project/commit/50f9367960725b450a9ef779d73e32a35031ee70
DIFF: https://github.com/llvm/llvm-project/commit/50f9367960725b450a9ef779d73e32a35031ee70.diff
LOG: Add LoadTraceFromFile to SBDebugger and SBTrace
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.
Differential Revision: https://reviews.llvm.org/D128107
Added:
Modified:
lldb/bindings/interface/SBDebugger.i
lldb/include/lldb/API/SBDebugger.h
lldb/include/lldb/API/SBFileSpec.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
Removed:
################################################################################
diff --git a/lldb/bindings/interface/SBDebugger.i b/lldb/bindings/interface/SBDebugger.i
index 2239f049c6514..5d51a6ac20d2f 100644
--- a/lldb/bindings/interface/SBDebugger.i
+++ b/lldb/bindings/interface/SBDebugger.i
@@ -542,6 +542,8 @@ Example: ::
lldb::SBError
RunREPL (lldb::LanguageType language, const char *repl_options);
+ SBTrace LoadTraceFromFile(SBError &error, const SBFileSpec &trace_description_file);
+
#ifdef SWIGPYTHON
%pythoncode%{
def __iter__(self):
diff --git a/lldb/include/lldb/API/SBDebugger.h b/lldb/include/lldb/API/SBDebugger.h
index 6a23077175b92..b9a9b593d0ad4 100644
--- a/lldb/include/lldb/API/SBDebugger.h
+++ b/lldb/include/lldb/API/SBDebugger.h
@@ -391,6 +391,17 @@ class LLDB_API SBDebugger {
SBError RunREPL(lldb::LanguageType language, const char *repl_options);
+ /// Load a trace from a trace description file and create Targets,
+ /// Processes and Threads based on the contents of such file.
+ ///
+ /// \param[out] error
+ /// An error if the trace could not be created.
+ ///
+ /// \param[in] trace_description_file
+ /// The file containing the necessary information to load the trace.
+ SBTrace LoadTraceFromFile(SBError &error,
+ const SBFileSpec &trace_description_file);
+
private:
friend class SBCommandInterpreter;
friend class SBInputReader;
@@ -398,6 +409,7 @@ class LLDB_API SBDebugger {
friend class SBProcess;
friend class SBSourceManager;
friend class SBTarget;
+ friend class SBTrace;
lldb::SBTarget FindTargetWithLLDBProcess(const lldb::ProcessSP &processSP);
diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h
index a2f02ac78208b..a286912f109e5 100644
--- a/lldb/include/lldb/API/SBFileSpec.h
+++ b/lldb/include/lldb/API/SBFileSpec.h
@@ -74,6 +74,7 @@ class LLDB_API SBFileSpec {
friend class SBSourceManager;
friend class SBTarget;
friend class SBThread;
+ friend class SBTrace;
SBFileSpec(const lldb_private::FileSpec &fspec);
diff --git a/lldb/include/lldb/API/SBTrace.h b/lldb/include/lldb/API/SBTrace.h
index 1685caaf4efa3..d5cf30f56637f 100644
--- a/lldb/include/lldb/API/SBTrace.h
+++ b/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,10 @@ class LLDB_API SBTrace {
SBTrace(const lldb::TraceSP &trace_sp);
+ /// See SBDebugger::LoadTraceFromFile.
+ static SBTrace LoadTraceFromFile(SBError &error, SBDebugger &debugger,
+ const SBFileSpec &trace_description_file);
+
/// \return
/// A description of the parameters to use for the \a SBTrace::Start
/// method, or \b null if the object is invalid.
diff --git a/lldb/include/lldb/Target/Trace.h b/lldb/include/lldb/Target/Trace.h
index 2fee3c9274959..216394bdd1847 100644
--- a/lldb/include/lldb/Target/Trace.h
+++ b/lldb/include/lldb/Target/Trace.h
@@ -137,6 +137,23 @@ class Trace : public PluginInterface,
static llvm::Expected<llvm::StringRef>
FindPluginSchema(llvm::StringRef plugin_name);
+ /// Load a trace from a trace description file and create Targets,
+ /// Processes and Threads based on the contents of such file.
+ ///
+ /// \param[in] debugger
+ /// The debugger instance where new Targets will be created as part of the
+ /// JSON data parsing.
+ ///
+ /// \param[in] trace_description_file
+ /// The file containing the necessary information to load the trace.
+ ///
+ /// \return
+ /// A \a TraceSP instance, or an \a llvm::Error if loading the trace
+ /// fails.
+ static llvm::Expected<lldb::TraceSP>
+ LoadPostMortemTraceFromFile(Debugger &debugger,
+ const FileSpec &trace_description_file);
+
/// Get the command handle for the "process trace start" command.
virtual lldb::CommandObjectSP
GetProcessTraceStartCommand(CommandInterpreter &interpreter) = 0;
diff --git a/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
index 501429036c718..436cf6e868570 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
@@ -133,3 +133,13 @@ def traceStopThread(self, thread=None, error=False, substrs=None):
if thread is not None:
command += " " + str(thread.GetIndexID())
self.expect(command, error=error, substrs=substrs)
+
+ def traceLoad(self, traceDescriptionFilePath="trace.json", error=False, substrs=None):
+ if self.USE_SB_API:
+ traceDescriptionFile = lldb.SBFileSpec(traceDescriptionFilePath, True)
+ loadTraceError = lldb.SBError()
+ _trace = self.dbg.LoadTraceFromFile(loadTraceError, traceDescriptionFile)
+ self.assertSBError(loadTraceError, error)
+ else:
+ command = f"trace load -v {traceDescriptionFilePath}"
+ self.expect(command, error=error, substrs=substrs)
diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp
index ea340e3a44792..37469989dc5b5 100644
--- a/lldb/source/API/SBDebugger.cpp
+++ b/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,10 @@ void SBDebugger::SetLoggingCallback(lldb::LogOutputCallback log_callback,
return m_opaque_sp->SetLoggingCallback(log_callback, baton);
}
}
+
+SBTrace
+SBDebugger::LoadTraceFromFile(SBError &error,
+ const SBFileSpec &trace_description_file) {
+ LLDB_INSTRUMENT_VA(this, error, trace_description_file);
+ return SBTrace::LoadTraceFromFile(error, *this, trace_description_file);
+}
diff --git a/lldb/source/API/SBTrace.cpp b/lldb/source/API/SBTrace.cpp
index 64a675e2e16cd..fe90032370733 100644
--- a/lldb/source/API/SBTrace.cpp
+++ b/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"
@@ -19,6 +20,7 @@
using namespace lldb;
using namespace lldb_private;
+using namespace llvm;
SBTrace::SBTrace() { LLDB_INSTRUMENT_VA(this); }
@@ -26,6 +28,21 @@ SBTrace::SBTrace(const lldb::TraceSP &trace_sp) : m_opaque_sp(trace_sp) {
LLDB_INSTRUMENT_VA(this, trace_sp);
}
+SBTrace SBTrace::LoadTraceFromFile(SBError &error, SBDebugger &debugger,
+ const SBFileSpec &trace_description_file) {
+ LLDB_INSTRUMENT_VA(error, debugger, trace_description_file);
+
+ Expected<lldb::TraceSP> trace_or_err = Trace::LoadPostMortemTraceFromFile(
+ debugger.ref(), trace_description_file.ref());
+
+ if (!trace_or_err) {
+ error.SetErrorString(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;
diff --git a/lldb/source/Commands/CommandObjectTrace.cpp b/lldb/source/Commands/CommandObjectTrace.cpp
index 53f1b0a32e607..d69b223c5a707 100644
--- a/lldb/source/Commands/CommandObjectTrace.cpp
+++ b/lldb/source/Commands/CommandObjectTrace.cpp
@@ -85,41 +85,26 @@ class CommandObjectTraceLoad : public CommandObjectParsed {
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;
- };
+ const FileSpec trace_description_file(command[0].ref());
- FileSpec json_file(command[0].ref());
+ llvm::Expected<lldb::TraceSP> trace_or_err =
+ Trace::LoadPostMortemTraceFromFile(GetDebugger(),
+ trace_description_file);
- 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());
+ if (m_options.m_verbose) {
+ result.AppendMessageWithFormatv("loading trace with plugin {0}\n",
+ trace_or_err.get()->GetPluginName());
+ }
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
diff --git a/lldb/source/Target/Trace.cpp b/lldb/source/Target/Trace.cpp
index ac7fd7717621b..6a022a27d0340 100644
--- a/lldb/source/Target/Trace.cpp
+++ b/lldb/source/Target/Trace.cpp
@@ -89,6 +89,30 @@ static Error createInvalidPlugInError(StringRef plugin_name) {
plugin_name.data());
}
+Expected<lldb::TraceSP>
+Trace::LoadPostMortemTraceFromFile(Debugger &debugger,
+ const FileSpec &trace_description_file) {
+
+ auto buffer_or_error =
+ MemoryBuffer::getFile(trace_description_file.GetPath());
+ if (!buffer_or_error) {
+ return createStringError(std::errc::invalid_argument,
+ "could not open input file: %s - %s.",
+ trace_description_file.GetPath().c_str(),
+ buffer_or_error.getError().message().c_str());
+ }
+
+ 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,
+ trace_description_file.GetDirectory().AsCString());
+}
+
Expected<lldb::TraceSP>
Trace::FindPluginForPostMortemProcess(Debugger &debugger,
const json::Value &trace_session_file,
diff --git a/lldb/test/API/commands/trace/TestTraceLoad.py b/lldb/test/API/commands/trace/TestTraceLoad.py
index e5746989ba1c0..80783dbf0ac30 100644
--- a/lldb/test/API/commands/trace/TestTraceLoad.py
+++ b/lldb/test/API/commands/trace/TestTraceLoad.py
@@ -7,10 +7,11 @@
class TestTraceLoad(TraceIntelPTTestCaseBase):
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"])
+ trace_description_file_path = os.path.join(src_dir, "intelpt-multi-core-trace", "trace.json")
+ self.traceLoad(traceDescriptionFilePath=trace_description_file_path, 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",
@@ -19,10 +20,11 @@ def testLoadMultiCoreTrace(self):
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"])
+ trace_description_file_path = os.path.join(src_dir, "intelpt-multi-core-trace", "trace_with_string_numbers.json")
+ self.traceLoad(traceDescriptionFilePath=trace_description_file_path, 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",
@@ -31,10 +33,11 @@ def testLoadMultiCoreTraceWithStringNumbers(self):
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"])
+ trace_description_file_path = os.path.join(src_dir, "intelpt-multi-core-trace", "trace_missing_threads.json")
+ self.traceLoad(traceDescriptionFilePath=trace_description_file_path, 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",
@@ -43,10 +46,11 @@ def testLoadMultiCoreTraceWithMissingThreads(self):
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"])
+ trace_description_file_path = os.path.join(src_dir, "intelpt-trace", "trace.json")
+ self.traceLoad(traceDescriptionFilePath=trace_description_file_path, substrs=["intel-pt"])
target = self.dbg.GetSelectedTarget()
process = target.GetProcess()
@@ -88,11 +92,13 @@ def testLoadTrace(self):
Errors:
Number of TSC decoding errors: 0'''])
+ @testSBAPIAndCommands
def testLoadInvalidTraces(self):
src_dir = self.getSourceDir()
+
# 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]
+ trace_description_file_path = os.path.join(src_dir, "intelpt-trace", "trace_bad.json")
+ expected_substrs = ['''error: expected object at traceSession.processes[0]
Context:
{
@@ -114,15 +120,19 @@ def testLoadInvalidTraces(self):
"family": integer,
"model": integer,
"stepping": integer
- },'''])
+ },''']
+ self.traceLoad(traceDescriptionFilePath=trace_description_file_path, error=True, substrs=expected_substrs)
+
# Now we test a wrong cpu family field in the global session file
- self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad2.json"), error=True,
- substrs=['error: expected uint64_t at traceSession.cpuInfo.family', "Context", "Schema"])
+ trace_description_file_path = os.path.join(src_dir, "intelpt-trace", "trace_bad2.json")
+ expected_substrs = ['error: expected uint64_t at traceSession.cpuInfo.family', "Context", "Schema"]
+ self.traceLoad(traceDescriptionFilePath=trace_description_file_path, error=True, substrs=expected_substrs)
+
# Now we test a missing field in the intel-pt settings
- self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad4.json"), error=True,
- substrs=['''error: missing value at traceSession.cpuInfo.family
+ trace_description_file_path = os.path.join(src_dir, "intelpt-trace", "trace_bad4.json")
+ expected_substrs = ['''error: missing value at traceSession.cpuInfo.family
Context:
{
@@ -133,15 +143,20 @@ def testLoadInvalidTraces(self):
},
"processes": [],
"type": "intel-pt"
-}''', "Schema"])
+}''', "Schema"]
+ self.traceLoad(traceDescriptionFilePath=trace_description_file_path, error=True, substrs=expected_substrs)
+
# Now we test an incorrect load address in the intel-pt settings
- self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad5.json"), error=True,
- substrs=['error: missing value at traceSession.processes[1].pid', "Schema"])
+ trace_description_file_path = os.path.join(src_dir, "intelpt-trace", "trace_bad5.json")
+ expected_substrs = ['error: missing value at traceSession.processes[1].pid', "Schema"]
+ self.traceLoad(traceDescriptionFilePath=trace_description_file_path, error=True, substrs=expected_substrs)
+
# The following wrong schema will have a valid target and an invalid one. In the case of failure,
# no targets should be created.
self.assertEqual(self.dbg.GetNumTargets(), 0)
- self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad3.json"), error=True,
- substrs=['error: missing value at traceSession.processes[1].pid'])
+ trace_description_file_path = os.path.join(src_dir, "intelpt-trace", "trace_bad3.json")
+ expected_substrs = ['error: missing value at traceSession.processes[1].pid']
+ self.traceLoad(traceDescriptionFilePath=trace_description_file_path, error=True, substrs=expected_substrs)
self.assertEqual(self.dbg.GetNumTargets(), 0)
More information about the lldb-commits
mailing list