aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/Trace/intel-pt
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Trace/intel-pt')
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp133
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h69
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp74
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/DecodedThread.h72
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp134
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.h69
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp100
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h50
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp333
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h121
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h27
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td72
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp50
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h28
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/forward-declarations.h20
15 files changed, 1121 insertions, 231 deletions
diff --git a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp
index e1758dfcfc41..5650af657c5e 100644
--- a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp
@@ -8,7 +8,10 @@
#include "CommandObjectTraceStartIntelPT.h"
+#include "TraceIntelPT.h"
+#include "TraceIntelPTConstants.h"
#include "lldb/Host/OptionParser.h"
+#include "lldb/Target/Process.h"
#include "lldb/Target/Trace.h"
using namespace lldb;
@@ -16,10 +19,12 @@ using namespace lldb_private;
using namespace lldb_private::trace_intel_pt;
using namespace llvm;
+// CommandObjectThreadTraceStartIntelPT
+
#define LLDB_OPTIONS_thread_trace_start_intel_pt
#include "TraceIntelPTCommandOptions.inc"
-Status CommandObjectTraceStartIntelPT::CommandOptions::SetOptionValue(
+Status CommandObjectThreadTraceStartIntelPT::CommandOptions::SetOptionValue(
uint32_t option_idx, llvm::StringRef option_arg,
ExecutionContext *execution_context) {
Status error;
@@ -27,23 +32,27 @@ Status CommandObjectTraceStartIntelPT::CommandOptions::SetOptionValue(
switch (short_option) {
case 's': {
- int32_t size_in_kb;
- if (option_arg.empty() || option_arg.getAsInteger(0, size_in_kb) ||
- size_in_kb < 0)
+ int64_t thread_buffer_size;
+ if (option_arg.empty() || option_arg.getAsInteger(0, thread_buffer_size) ||
+ thread_buffer_size < 0)
error.SetErrorStringWithFormat("invalid integer value for option '%s'",
option_arg.str().c_str());
else
- m_size_in_kb = size_in_kb;
+ m_thread_buffer_size = thread_buffer_size;
+ break;
+ }
+ case 't': {
+ m_enable_tsc = true;
break;
}
- case 'c': {
- int32_t custom_config;
- if (option_arg.empty() || option_arg.getAsInteger(0, custom_config) ||
- custom_config < 0)
+ case 'p': {
+ int64_t psb_period;
+ if (option_arg.empty() || option_arg.getAsInteger(0, psb_period) ||
+ psb_period < 0)
error.SetErrorStringWithFormat("invalid integer value for option '%s'",
option_arg.str().c_str());
else
- m_custom_config = custom_config;
+ m_psb_period = psb_period;
break;
}
default:
@@ -52,22 +61,104 @@ Status CommandObjectTraceStartIntelPT::CommandOptions::SetOptionValue(
return error;
}
-void CommandObjectTraceStartIntelPT::CommandOptions::OptionParsingStarting(
- ExecutionContext *execution_context) {
- m_size_in_kb = 4;
- m_custom_config = 0;
+void CommandObjectThreadTraceStartIntelPT::CommandOptions::
+ OptionParsingStarting(ExecutionContext *execution_context) {
+ m_thread_buffer_size = kDefaultThreadBufferSize;
+ m_enable_tsc = kDefaultEnableTscValue;
+ m_psb_period = kDefaultPsbPeriod;
}
llvm::ArrayRef<OptionDefinition>
-CommandObjectTraceStartIntelPT::CommandOptions::GetDefinitions() {
+CommandObjectThreadTraceStartIntelPT::CommandOptions::GetDefinitions() {
return llvm::makeArrayRef(g_thread_trace_start_intel_pt_options);
}
-bool CommandObjectTraceStartIntelPT::HandleOneThread(
- lldb::tid_t tid, CommandReturnObject &result) {
- result.AppendMessageWithFormat(
- "would trace tid %" PRIu64 " with size_in_kb %zu and custom_config %d\n",
- tid, m_options.m_size_in_kb, m_options.m_custom_config);
- result.SetStatus(eReturnStatusSuccessFinishResult);
+bool CommandObjectThreadTraceStartIntelPT::DoExecuteOnThreads(
+ Args &command, CommandReturnObject &result,
+ llvm::ArrayRef<lldb::tid_t> tids) {
+ if (Error err = m_trace.Start(tids, m_options.m_thread_buffer_size,
+ m_options.m_enable_tsc, m_options.m_psb_period))
+ result.SetError(Status(std::move(err)));
+ else
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+
+ return result.Succeeded();
+}
+
+/// CommandObjectProcessTraceStartIntelPT
+
+#define LLDB_OPTIONS_process_trace_start_intel_pt
+#include "TraceIntelPTCommandOptions.inc"
+
+Status CommandObjectProcessTraceStartIntelPT::CommandOptions::SetOptionValue(
+ uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option) {
+ case 's': {
+ int64_t thread_buffer_size;
+ if (option_arg.empty() || option_arg.getAsInteger(0, thread_buffer_size) ||
+ thread_buffer_size < 0)
+ error.SetErrorStringWithFormat("invalid integer value for option '%s'",
+ option_arg.str().c_str());
+ else
+ m_thread_buffer_size = thread_buffer_size;
+ break;
+ }
+ case 'l': {
+ int64_t process_buffer_size_limit;
+ if (option_arg.empty() ||
+ option_arg.getAsInteger(0, process_buffer_size_limit) ||
+ process_buffer_size_limit < 0)
+ error.SetErrorStringWithFormat("invalid integer value for option '%s'",
+ option_arg.str().c_str());
+ else
+ m_process_buffer_size_limit = process_buffer_size_limit;
+ break;
+ }
+ case 't': {
+ m_enable_tsc = true;
+ break;
+ }
+ case 'p': {
+ int64_t psb_period;
+ if (option_arg.empty() || option_arg.getAsInteger(0, psb_period) ||
+ psb_period < 0)
+ error.SetErrorStringWithFormat("invalid integer value for option '%s'",
+ option_arg.str().c_str());
+ else
+ m_psb_period = psb_period;
+ break;
+ }
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+ return error;
+}
+
+void CommandObjectProcessTraceStartIntelPT::CommandOptions::
+ OptionParsingStarting(ExecutionContext *execution_context) {
+ m_thread_buffer_size = kDefaultThreadBufferSize;
+ m_process_buffer_size_limit = kDefaultProcessBufferSizeLimit;
+ m_enable_tsc = kDefaultEnableTscValue;
+ m_psb_period = kDefaultPsbPeriod;
+}
+
+llvm::ArrayRef<OptionDefinition>
+CommandObjectProcessTraceStartIntelPT::CommandOptions::GetDefinitions() {
+ return llvm::makeArrayRef(g_process_trace_start_intel_pt_options);
+}
+
+bool CommandObjectProcessTraceStartIntelPT::DoExecute(
+ Args &command, CommandReturnObject &result) {
+ if (Error err = m_trace.Start(m_options.m_thread_buffer_size,
+ m_options.m_process_buffer_size_limit,
+ m_options.m_enable_tsc, m_options.m_psb_period))
+ result.SetError(Status(std::move(err)));
+ else
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+
return result.Succeeded();
}
diff --git a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h
index 265569c553fa..2f3d53a86406 100644
--- a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h
+++ b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h
@@ -9,21 +9,21 @@
#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_COMMANDOBJECTTRACESTARTINTELPT_H
#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_COMMANDOBJECTTRACESTARTINTELPT_H
-#include "../../../../source/Commands/CommandObjectThreadUtil.h"
+#include "../../../../source/Commands/CommandObjectTrace.h"
+#include "TraceIntelPT.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
namespace lldb_private {
namespace trace_intel_pt {
-class CommandObjectTraceStartIntelPT : public CommandObjectIterateOverThreads {
+class CommandObjectThreadTraceStartIntelPT
+ : public CommandObjectMultipleThreads {
public:
class CommandOptions : public Options {
public:
CommandOptions() : Options() { OptionParsingStarting(nullptr); }
- ~CommandOptions() override = default;
-
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
ExecutionContext *execution_context) override;
@@ -31,31 +31,76 @@ public:
llvm::ArrayRef<OptionDefinition> GetDefinitions() override;
- size_t m_size_in_kb;
- uint32_t m_custom_config;
+ size_t m_thread_buffer_size;
+ bool m_enable_tsc;
+ llvm::Optional<size_t> m_psb_period;
};
- CommandObjectTraceStartIntelPT(CommandInterpreter &interpreter)
- : CommandObjectIterateOverThreads(
+ CommandObjectThreadTraceStartIntelPT(TraceIntelPT &trace,
+ CommandInterpreter &interpreter)
+ : CommandObjectMultipleThreads(
interpreter, "thread trace start",
"Start tracing one or more threads with intel-pt. "
"Defaults to the current thread. Thread indices can be "
"specified as arguments.\n Use the thread-index \"all\" to trace "
- "all threads.",
+ "all threads including future threads.",
"thread trace start [<thread-index> <thread-index> ...] "
"[<intel-pt-options>]",
lldb::eCommandRequiresProcess | lldb::eCommandTryTargetAPILock |
lldb::eCommandProcessMustBeLaunched |
lldb::eCommandProcessMustBePaused),
- m_options() {}
+ m_trace(trace), m_options() {}
+
+ Options *GetOptions() override { return &m_options; }
+
+protected:
+ bool DoExecuteOnThreads(Args &command, CommandReturnObject &result,
+ llvm::ArrayRef<lldb::tid_t> tids) override;
+
+ TraceIntelPT &m_trace;
+ CommandOptions m_options;
+};
+
+class CommandObjectProcessTraceStartIntelPT : public CommandObjectParsed {
+public:
+ class CommandOptions : public Options {
+ public:
+ CommandOptions() : Options() { OptionParsingStarting(nullptr); }
- ~CommandObjectTraceStartIntelPT() override = default;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override;
+
+ void OptionParsingStarting(ExecutionContext *execution_context) override;
+
+ llvm::ArrayRef<OptionDefinition> GetDefinitions() override;
+
+ size_t m_thread_buffer_size;
+ size_t m_process_buffer_size_limit;
+ bool m_enable_tsc;
+ llvm::Optional<size_t> m_psb_period;
+ };
+
+ CommandObjectProcessTraceStartIntelPT(TraceIntelPT &trace,
+ CommandInterpreter &interpreter)
+ : CommandObjectParsed(
+ interpreter, "process trace start",
+ "Start tracing this process with intel-pt, including future "
+ "threads. "
+ "This is implemented by tracing each thread independently. "
+ "Threads traced with the \"thread trace start\" command are left "
+ "unaffected ant not retraced.",
+ "process trace start [<intel-pt-options>]",
+ lldb::eCommandRequiresProcess | lldb::eCommandTryTargetAPILock |
+ lldb::eCommandProcessMustBeLaunched |
+ lldb::eCommandProcessMustBePaused),
+ m_trace(trace), m_options() {}
Options *GetOptions() override { return &m_options; }
protected:
- bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override;
+ bool DoExecute(Args &command, CommandReturnObject &result) override;
+ TraceIntelPT &m_trace;
CommandOptions m_options;
};
diff --git a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
index 6b8b06564052..4822a786c68c 100644
--- a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
@@ -8,8 +8,13 @@
#include "DecodedThread.h"
+#include <intel-pt.h>
+#include <memory>
+
+#include "TraceCursorIntelPT.h"
#include "lldb/Utility/StreamString.h"
+using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::trace_intel_pt;
using namespace llvm;
@@ -30,12 +35,21 @@ void IntelPTError::log(llvm::raw_ostream &OS) const {
OS << "error: " << libipt_error_message;
}
+IntelPTInstruction::IntelPTInstruction(llvm::Error err) {
+ llvm::handleAllErrors(std::move(err),
+ [&](std::unique_ptr<llvm::ErrorInfoBase> info) {
+ m_error = std::move(info);
+ });
+ m_pt_insn.ip = LLDB_INVALID_ADDRESS;
+ m_pt_insn.iclass = ptic_error;
+}
+
bool IntelPTInstruction::IsError() const { return (bool)m_error; }
-Expected<lldb::addr_t> IntelPTInstruction::GetLoadAddress() const {
- if (IsError())
- return ToError();
- return m_pt_insn.ip;
+lldb::addr_t IntelPTInstruction::GetLoadAddress() const { return m_pt_insn.ip; }
+
+Optional<uint64_t> IntelPTInstruction::GetTimestampCounter() const {
+ return m_timestamp;
}
Error IntelPTInstruction::ToError() const {
@@ -47,18 +61,58 @@ Error IntelPTInstruction::ToError() const {
return make_error<StringError>(m_error->message(),
m_error->convertToErrorCode());
}
+size_t DecodedThread::GetRawTraceSize() const { return m_raw_trace_size; }
+
+TraceInstructionControlFlowType
+IntelPTInstruction::GetControlFlowType(lldb::addr_t next_load_address) const {
+ if (IsError())
+ return (TraceInstructionControlFlowType)0;
-size_t DecodedThread::GetLastPosition() const {
- return m_instructions.empty() ? 0 : m_instructions.size() - 1;
+ TraceInstructionControlFlowType mask =
+ eTraceInstructionControlFlowTypeInstruction;
+
+ switch (m_pt_insn.iclass) {
+ case ptic_cond_jump:
+ case ptic_jump:
+ case ptic_far_jump:
+ mask |= eTraceInstructionControlFlowTypeBranch;
+ if (m_pt_insn.ip + m_pt_insn.size != next_load_address)
+ mask |= eTraceInstructionControlFlowTypeTakenBranch;
+ break;
+ case ptic_return:
+ case ptic_far_return:
+ mask |= eTraceInstructionControlFlowTypeReturn;
+ break;
+ case ptic_call:
+ case ptic_far_call:
+ mask |= eTraceInstructionControlFlowTypeCall;
+ break;
+ default:
+ break;
+ }
+
+ return mask;
}
ArrayRef<IntelPTInstruction> DecodedThread::GetInstructions() const {
return makeArrayRef(m_instructions);
}
-size_t DecodedThread::GetCursorPosition() const { return m_position; }
+DecodedThread::DecodedThread(ThreadSP thread_sp, Error error)
+ : m_thread_sp(thread_sp) {
+ m_instructions.emplace_back(std::move(error));
+}
+
+DecodedThread::DecodedThread(ThreadSP thread_sp,
+ std::vector<IntelPTInstruction> &&instructions,
+ size_t raw_trace_size)
+ : m_thread_sp(thread_sp), m_instructions(std::move(instructions)),
+ m_raw_trace_size(raw_trace_size) {
+ if (m_instructions.empty())
+ m_instructions.emplace_back(
+ createStringError(inconvertibleErrorCode(), "empty trace"));
+}
-size_t DecodedThread::SetCursorPosition(size_t new_position) {
- m_position = std::min(new_position, GetLastPosition());
- return m_position;
+lldb::TraceCursorUP DecodedThread::GetCursor() {
+ return std::make_unique<TraceCursorIntelPT>(m_thread_sp, shared_from_this());
}
diff --git a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
index 3c7e030414cb..592c402cd0e5 100644
--- a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
+++ b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
@@ -15,6 +15,7 @@
#include "llvm/Support/Error.h"
#include "lldb/Target/Trace.h"
+#include "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
#include "intel-pt.h"
@@ -60,17 +61,15 @@ private:
/// As mentioned, any gap is represented as an error in this class.
class IntelPTInstruction {
public:
+ IntelPTInstruction(const pt_insn &pt_insn, uint64_t timestamp)
+ : m_pt_insn(pt_insn), m_timestamp(timestamp) {}
+
IntelPTInstruction(const pt_insn &pt_insn) : m_pt_insn(pt_insn) {}
/// Error constructor
///
/// libipt errors should use the underlying \a IntelPTError class.
- IntelPTInstruction(llvm::Error err) {
- llvm::handleAllErrors(std::move(err),
- [&](std::unique_ptr<llvm::ErrorInfoBase> info) {
- m_error = std::move(info);
- });
- }
+ IntelPTInstruction(llvm::Error err);
/// Check if this object represents an error (i.e. a gap).
///
@@ -79,15 +78,34 @@ public:
bool IsError() const;
/// \return
- /// The instruction pointer address, or an \a llvm::Error if it is an
- /// error.
- llvm::Expected<lldb::addr_t> GetLoadAddress() const;
+ /// The instruction pointer address, or \a LLDB_INVALID_ADDRESS if it is
+ /// an error.
+ lldb::addr_t GetLoadAddress() const;
/// \return
/// An \a llvm::Error object if this class corresponds to an Error, or an
/// \a llvm::Error::success otherwise.
llvm::Error ToError() const;
+ /// Get the timestamp associated with the current instruction. The timestamp
+ /// is similar to what a rdtsc instruction would return.
+ ///
+ /// \return
+ /// The timestamp or \b llvm::None if not available.
+ llvm::Optional<uint64_t> GetTimestampCounter() const;
+
+ /// Get the \a lldb::TraceInstructionControlFlowType categories of the
+ /// instruction.
+ ///
+ /// \param[in] next_load_address
+ /// The address of the next instruction in the trace or \b
+ /// LLDB_INVALID_ADDRESS if not available.
+ ///
+ /// \return
+ /// The control flow categories, or \b 0 if the instruction is an error.
+ lldb::TraceInstructionControlFlowType
+ GetControlFlowType(lldb::addr_t next_load_address) const;
+
IntelPTInstruction(IntelPTInstruction &&other) = default;
private:
@@ -95,6 +113,7 @@ private:
const IntelPTInstruction &operator=(const IntelPTInstruction &other) = delete;
pt_insn m_pt_insn;
+ llvm::Optional<uint64_t> m_timestamp;
std::unique_ptr<llvm::ErrorInfoBase> m_error;
};
@@ -105,11 +124,15 @@ private:
///
/// Each decoded thread contains a cursor to the current position the user is
/// stopped at. See \a Trace::GetCursorPosition for more information.
-class DecodedThread {
+class DecodedThread : public std::enable_shared_from_this<DecodedThread> {
public:
- DecodedThread(std::vector<IntelPTInstruction> &&instructions)
- : m_instructions(std::move(instructions)), m_position(GetLastPosition()) {
- }
+ DecodedThread(lldb::ThreadSP thread_sp,
+ std::vector<IntelPTInstruction> &&instructions,
+ size_t raw_trace_size);
+
+ /// Constructor with a single error signaling a complete failure of the
+ /// decoding process.
+ DecodedThread(lldb::ThreadSP thread_sp, llvm::Error error);
/// Get the instructions from the decoded trace. Some of them might indicate
/// errors (i.e. gaps) in the trace.
@@ -118,28 +141,23 @@ public:
/// The instructions of the trace.
llvm::ArrayRef<IntelPTInstruction> GetInstructions() const;
- /// \return
- /// The current position of the cursor of this trace, or 0 if there are no
- /// instructions.
- size_t GetCursorPosition() const;
+ /// Get a new cursor for the decoded thread.
+ lldb::TraceCursorUP GetCursor();
- /// Change the position of the cursor of this trace. If this value is to high,
- /// the new position will be set as the last instruction of the trace.
+ /// Get the size in bytes of the corresponding Intel PT raw trace
///
/// \return
- /// The effective new position.
- size_t SetCursorPosition(size_t new_position);
- /// \}
+ /// The size of the trace.
+ size_t GetRawTraceSize() const;
private:
- /// \return
- /// The index of the last element of the trace, or 0 if empty.
- size_t GetLastPosition() const;
-
+ lldb::ThreadSP m_thread_sp;
std::vector<IntelPTInstruction> m_instructions;
- size_t m_position;
+ size_t m_raw_trace_size;
};
+using DecodedThreadSP = std::shared_ptr<DecodedThread>;
+
} // namespace trace_intel_pt
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp b/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp
index b6e8ae808632..3827881454c7 100644
--- a/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp
@@ -1,5 +1,4 @@
-//===-- IntelPTDecoder.cpp --------------------------------------*- C++ -*-===//
-//
+//===-- IntelPTDecoder.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
@@ -10,10 +9,13 @@
#include "llvm/Support/MemoryBuffer.h"
+#include "../common/ThreadPostMortemTrace.h"
+#include "DecodedThread.h"
+#include "TraceIntelPT.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
#include "lldb/Target/Target.h"
-#include "lldb/Target/ThreadTrace.h"
+#include "lldb/Utility/StringExtractor.h"
using namespace lldb;
using namespace lldb_private;
@@ -85,7 +87,7 @@ static int ProcessPTEvents(pt_insn_decoder &decoder, int errcode) {
return errcode;
}
return 0;
-};
+}
/// Decode all the instructions from a configured decoder.
/// The decoding flow is based on
@@ -135,7 +137,23 @@ DecodeInstructions(pt_insn_decoder &decoder) {
break;
}
- instructions.emplace_back(insn);
+ uint64_t time;
+ int time_error = pt_insn_time(&decoder, &time, nullptr, nullptr);
+ if (time_error == -pte_invalid) {
+ // This happens if we invoke the pt_insn_time method incorrectly,
+ // but the instruction is good though.
+ instructions.emplace_back(
+ make_error<IntelPTError>(time_error, insn.ip));
+ instructions.emplace_back(insn);
+ break;
+ }
+ if (time_error == -pte_no_time) {
+ // We simply don't have time information, i.e. None of TSC, MTC or CYC
+ // was enabled.
+ instructions.emplace_back(insn);
+ } else {
+ instructions.emplace_back(insn, time);
+ }
}
}
@@ -158,39 +176,26 @@ static int ReadProcessMemory(uint8_t *buffer, size_t size,
return bytes_read;
}
-static std::vector<IntelPTInstruction> makeInstructionListFromError(Error err) {
- std::vector<IntelPTInstruction> instructions;
- instructions.emplace_back(std::move(err));
- return instructions;
-}
-
-static std::vector<IntelPTInstruction>
-CreateDecoderAndDecode(Process &process, const pt_cpu &pt_cpu,
- const FileSpec &trace_file) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> trace_or_error =
- MemoryBuffer::getFile(trace_file.GetPath());
- if (std::error_code err = trace_or_error.getError())
- return makeInstructionListFromError(errorCodeToError(err));
-
- MemoryBuffer &trace = **trace_or_error;
+static Expected<std::vector<IntelPTInstruction>>
+DecodeInMemoryTrace(Process &process, TraceIntelPT &trace_intel_pt,
+ MutableArrayRef<uint8_t> buffer) {
+ Expected<pt_cpu> cpu_info = trace_intel_pt.GetCPUInfo();
+ if (!cpu_info)
+ return cpu_info.takeError();
pt_config config;
pt_config_init(&config);
- config.cpu = pt_cpu;
+ config.cpu = *cpu_info;
if (int errcode = pt_cpu_errata(&config.errata, &config.cpu))
- return makeInstructionListFromError(make_error<IntelPTError>(errcode));
+ return make_error<IntelPTError>(errcode);
- // The libipt library does not modify the trace buffer, hence the following
- // cast is safe.
- config.begin =
- reinterpret_cast<uint8_t *>(const_cast<char *>(trace.getBufferStart()));
- config.end =
- reinterpret_cast<uint8_t *>(const_cast<char *>(trace.getBufferEnd()));
+ config.begin = buffer.data();
+ config.end = buffer.data() + buffer.size();
pt_insn_decoder *decoder = pt_insn_alloc_decoder(&config);
if (!decoder)
- return makeInstructionListFromError(make_error<IntelPTError>(-pte_nomem));
+ return make_error<IntelPTError>(-pte_nomem);
pt_image *image = pt_insn_get_image(decoder);
@@ -204,12 +209,71 @@ CreateDecoderAndDecode(Process &process, const pt_cpu &pt_cpu,
return instructions;
}
-const DecodedThread &ThreadTraceDecoder::Decode() {
- if (!m_decoded_thread.hasValue()) {
- m_decoded_thread = DecodedThread(
- CreateDecoderAndDecode(*m_trace_thread->GetProcess(), m_pt_cpu,
- m_trace_thread->GetTraceFile()));
- }
+static Expected<std::vector<IntelPTInstruction>>
+DecodeTraceFile(Process &process, TraceIntelPT &trace_intel_pt,
+ const FileSpec &trace_file, size_t &raw_trace_size) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> trace_or_error =
+ MemoryBuffer::getFile(trace_file.GetPath());
+ if (std::error_code err = trace_or_error.getError())
+ return errorCodeToError(err);
+
+ 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());
+ raw_trace_size = trace_data.size();
+ return DecodeInMemoryTrace(process, trace_intel_pt, trace_data);
+}
+
+static Expected<std::vector<IntelPTInstruction>>
+DecodeLiveThread(Thread &thread, TraceIntelPT &trace, size_t &raw_trace_size) {
+ Expected<std::vector<uint8_t>> buffer =
+ trace.GetLiveThreadBuffer(thread.GetID());
+ if (!buffer)
+ return buffer.takeError();
+ raw_trace_size = buffer->size();
+ if (Expected<pt_cpu> cpu_info = trace.GetCPUInfo())
+ return DecodeInMemoryTrace(*thread.GetProcess(), trace,
+ MutableArrayRef<uint8_t>(*buffer));
+ else
+ return cpu_info.takeError();
+}
+DecodedThreadSP ThreadDecoder::Decode() {
+ if (!m_decoded_thread.hasValue())
+ m_decoded_thread = DoDecode();
return *m_decoded_thread;
}
+
+PostMortemThreadDecoder::PostMortemThreadDecoder(
+ const lldb::ThreadPostMortemTraceSP &trace_thread, TraceIntelPT &trace)
+ : m_trace_thread(trace_thread), m_trace(trace) {}
+
+DecodedThreadSP PostMortemThreadDecoder::DoDecode() {
+ size_t raw_trace_size = 0;
+ if (Expected<std::vector<IntelPTInstruction>> instructions =
+ DecodeTraceFile(*m_trace_thread->GetProcess(), m_trace,
+ m_trace_thread->GetTraceFile(), raw_trace_size))
+ return std::make_shared<DecodedThread>(m_trace_thread->shared_from_this(),
+ std::move(*instructions),
+ raw_trace_size);
+ else
+ return std::make_shared<DecodedThread>(m_trace_thread->shared_from_this(),
+ instructions.takeError());
+}
+
+LiveThreadDecoder::LiveThreadDecoder(Thread &thread, TraceIntelPT &trace)
+ : m_thread_sp(thread.shared_from_this()), m_trace(trace) {}
+
+DecodedThreadSP LiveThreadDecoder::DoDecode() {
+ size_t raw_trace_size = 0;
+ if (Expected<std::vector<IntelPTInstruction>> instructions =
+ DecodeLiveThread(*m_thread_sp, m_trace, raw_trace_size))
+ return std::make_shared<DecodedThread>(
+ m_thread_sp, std::move(*instructions), raw_trace_size);
+ else
+ return std::make_shared<DecodedThread>(m_thread_sp,
+ instructions.takeError());
+}
diff --git a/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.h b/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.h
index 2e67f9bf6da7..e969db579e52 100644
--- a/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.h
+++ b/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.h
@@ -12,38 +12,73 @@
#include "intel-pt.h"
#include "DecodedThread.h"
+#include "forward-declarations.h"
#include "lldb/Target/Process.h"
#include "lldb/Utility/FileSpec.h"
namespace lldb_private {
namespace trace_intel_pt {
-/// \a lldb_private::ThreadTrace decoder that stores the output from decoding,
-/// avoiding recomputations, as decoding is expensive.
-class ThreadTraceDecoder {
+/// Base class that handles the decoding of a thread and caches the result.
+class ThreadDecoder {
public:
- /// \param[in] trace_thread
- /// The thread whose trace file will be decoded.
+ virtual ~ThreadDecoder() = default;
+
+ ThreadDecoder() = default;
+
+ /// Decode the thread and store the result internally, to avoid
+ /// recomputations.
///
- /// \param[in] pt_cpu
- /// The libipt cpu used when recording the trace.
- ThreadTraceDecoder(const std::shared_ptr<ThreadTrace> &trace_thread,
- const pt_cpu &pt_cpu)
- : m_trace_thread(trace_thread), m_pt_cpu(pt_cpu), m_decoded_thread() {}
+ /// \return
+ /// A \a DecodedThread instance.
+ DecodedThreadSP Decode();
- /// Decode the thread and store the result internally.
+ ThreadDecoder(const ThreadDecoder &other) = delete;
+ ThreadDecoder &operator=(const ThreadDecoder &other) = delete;
+
+protected:
+ /// Decode the thread.
///
/// \return
/// A \a DecodedThread instance.
- const DecodedThread &Decode();
+ 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:
- ThreadTraceDecoder(const ThreadTraceDecoder &other) = delete;
- ThreadTraceDecoder &operator=(const ThreadTraceDecoder &other) = delete;
+ DecodedThreadSP DoDecode() override;
- std::shared_ptr<ThreadTrace> m_trace_thread;
- pt_cpu m_pt_cpu;
- llvm::Optional<DecodedThread> m_decoded_thread;
+ lldb::ThreadSP m_thread_sp;
+ TraceIntelPT &m_trace;
};
} // namespace trace_intel_pt
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
new file mode 100644
index 000000000000..edefdd0d3486
--- /dev/null
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
@@ -0,0 +1,100 @@
+//===-- TraceCursorIntelPT.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 "TraceCursorIntelPT.h"
+#include "DecodedThread.h"
+#include "TraceIntelPT.h"
+
+#include <cstdlib>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::trace_intel_pt;
+using namespace llvm;
+
+TraceCursorIntelPT::TraceCursorIntelPT(ThreadSP thread_sp,
+ DecodedThreadSP decoded_thread_sp)
+ : TraceCursor(thread_sp), m_decoded_thread_sp(decoded_thread_sp) {
+ assert(!m_decoded_thread_sp->GetInstructions().empty() &&
+ "a trace should have at least one instruction or error");
+ m_pos = m_decoded_thread_sp->GetInstructions().size() - 1;
+}
+
+size_t TraceCursorIntelPT::GetInternalInstructionSize() {
+ return m_decoded_thread_sp->GetInstructions().size();
+}
+
+bool TraceCursorIntelPT::Next() {
+ auto canMoveOne = [&]() {
+ if (IsForwards())
+ return m_pos + 1 < GetInternalInstructionSize();
+ return m_pos > 0;
+ };
+
+ size_t initial_pos = m_pos;
+
+ while (canMoveOne()) {
+ m_pos += IsForwards() ? 1 : -1;
+ if (!m_ignore_errors && IsError())
+ return true;
+ if (GetInstructionControlFlowType() & m_granularity)
+ return true;
+ }
+
+ // Didn't find any matching instructions
+ m_pos = initial_pos;
+ return false;
+}
+
+size_t TraceCursorIntelPT::Seek(int64_t offset, SeekType origin) {
+ int64_t last_index = GetInternalInstructionSize() - 1;
+
+ auto fitPosToBounds = [&](int64_t raw_pos) -> int64_t {
+ return std::min(std::max((int64_t)0, raw_pos), last_index);
+ };
+
+ switch (origin) {
+ case TraceCursor::SeekType::Set:
+ m_pos = fitPosToBounds(offset);
+ return m_pos;
+ case TraceCursor::SeekType::End:
+ m_pos = fitPosToBounds(offset + last_index);
+ return last_index - m_pos;
+ case TraceCursor::SeekType::Current:
+ int64_t new_pos = fitPosToBounds(offset + m_pos);
+ int64_t dist = m_pos - new_pos;
+ m_pos = new_pos;
+ return std::abs(dist);
+ }
+}
+
+bool TraceCursorIntelPT::IsError() {
+ return m_decoded_thread_sp->GetInstructions()[m_pos].IsError();
+}
+
+Error TraceCursorIntelPT::GetError() {
+ return m_decoded_thread_sp->GetInstructions()[m_pos].ToError();
+}
+
+lldb::addr_t TraceCursorIntelPT::GetLoadAddress() {
+ return m_decoded_thread_sp->GetInstructions()[m_pos].GetLoadAddress();
+}
+
+Optional<uint64_t> TraceCursorIntelPT::GetTimestampCounter() {
+ return m_decoded_thread_sp->GetInstructions()[m_pos].GetTimestampCounter();
+}
+
+TraceInstructionControlFlowType
+TraceCursorIntelPT::GetInstructionControlFlowType() {
+ lldb::addr_t next_load_address =
+ m_pos + 1 < GetInternalInstructionSize()
+ ? m_decoded_thread_sp->GetInstructions()[m_pos + 1].GetLoadAddress()
+ : LLDB_INVALID_ADDRESS;
+ return m_decoded_thread_sp->GetInstructions()[m_pos].GetControlFlowType(
+ next_load_address);
+}
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
new file mode 100644
index 000000000000..29d3792bb489
--- /dev/null
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
@@ -0,0 +1,50 @@
+//===-- TraceCursorIntelPT.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 LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACECURSORINTELPT_H
+#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACECURSORINTELPT_H
+
+#include "IntelPTDecoder.h"
+#include "TraceIntelPTSessionFileParser.h"
+
+namespace lldb_private {
+namespace trace_intel_pt {
+
+class TraceCursorIntelPT : public TraceCursor {
+public:
+ TraceCursorIntelPT(lldb::ThreadSP thread_sp,
+ DecodedThreadSP decoded_thread_sp);
+
+ size_t Seek(int64_t offset, SeekType origin) override;
+
+ virtual bool Next() override;
+
+ llvm::Error GetError() override;
+
+ lldb::addr_t GetLoadAddress() override;
+
+ llvm::Optional<uint64_t> GetTimestampCounter() override;
+
+ lldb::TraceInstructionControlFlowType
+ GetInstructionControlFlowType() override;
+
+ bool IsError() override;
+
+private:
+ size_t GetInternalInstructionSize();
+
+ /// Storage of the actual instructions
+ DecodedThreadSP m_decoded_thread_sp;
+ /// Internal instruction index currently pointing at.
+ size_t m_pos;
+};
+
+} // namespace trace_intel_pt
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACECURSORINTELPT_H
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
index 63a8b2dff4a7..c12bcd3523e3 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
@@ -8,12 +8,14 @@
#include "TraceIntelPT.h"
+#include "../common/ThreadPostMortemTrace.h"
#include "CommandObjectTraceStartIntelPT.h"
+#include "DecodedThread.h"
+#include "TraceIntelPTConstants.h"
#include "TraceIntelPTSessionFileParser.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
-#include "lldb/Target/ThreadTrace.h"
using namespace lldb;
using namespace lldb_private;
@@ -22,18 +24,27 @@ using namespace llvm;
LLDB_PLUGIN_DEFINE(TraceIntelPT)
-CommandObjectSP GetStartCommand(CommandInterpreter &interpreter) {
- return CommandObjectSP(new CommandObjectTraceStartIntelPT(interpreter));
+lldb::CommandObjectSP
+TraceIntelPT::GetProcessTraceStartCommand(CommandInterpreter &interpreter) {
+ return CommandObjectSP(
+ new CommandObjectProcessTraceStartIntelPT(*this, interpreter));
+}
+
+lldb::CommandObjectSP
+TraceIntelPT::GetThreadTraceStartCommand(CommandInterpreter &interpreter) {
+ return CommandObjectSP(
+ new CommandObjectThreadTraceStartIntelPT(*this, interpreter));
}
void TraceIntelPT::Initialize() {
- PluginManager::RegisterPlugin(
- GetPluginNameStatic(), "Intel Processor Trace", CreateInstance,
- TraceIntelPTSessionFileParser::GetSchema(), GetStartCommand);
+ PluginManager::RegisterPlugin(GetPluginNameStatic(), "Intel Processor Trace",
+ CreateInstanceForSessionFile,
+ CreateInstanceForLiveProcess,
+ TraceIntelPTSessionFileParser::GetSchema());
}
void TraceIntelPT::Terminate() {
- PluginManager::UnregisterPlugin(CreateInstance);
+ PluginManager::UnregisterPlugin(CreateInstanceForSessionFile);
}
ConstString TraceIntelPT::GetPluginNameStatic() {
@@ -55,60 +66,278 @@ uint32_t TraceIntelPT::GetPluginVersion() { return 1; }
void TraceIntelPT::Dump(Stream *s) const {}
-Expected<TraceSP>
-TraceIntelPT::CreateInstance(const json::Value &trace_session_file,
- StringRef session_file_dir, Debugger &debugger) {
+Expected<TraceSP> TraceIntelPT::CreateInstanceForSessionFile(
+ const json::Value &trace_session_file, StringRef session_file_dir,
+ Debugger &debugger) {
return TraceIntelPTSessionFileParser(debugger, trace_session_file,
session_file_dir)
.Parse();
}
+Expected<TraceSP> TraceIntelPT::CreateInstanceForLiveProcess(Process &process) {
+ TraceSP instance(new TraceIntelPT(process));
+ process.GetTarget().SetTrace(instance);
+ return instance;
+}
+
TraceIntelPT::TraceIntelPT(
- const pt_cpu &pt_cpu,
- const std::vector<std::shared_ptr<ThreadTrace>> &traced_threads)
- : m_pt_cpu(pt_cpu) {
- for (const std::shared_ptr<ThreadTrace> &thread : traced_threads)
- m_trace_threads.emplace(
- std::piecewise_construct,
- std::forward_as_tuple(thread->GetProcess()->GetID(), thread->GetID()),
- std::forward_as_tuple(thread, pt_cpu));
-}
-
-const DecodedThread *TraceIntelPT::Decode(const Thread &thread) {
- auto it = m_trace_threads.find(
- std::make_pair(thread.GetProcess()->GetID(), thread.GetID()));
- if (it == m_trace_threads.end())
- return nullptr;
- return &it->second.Decode();
-}
-
-size_t TraceIntelPT::GetCursorPosition(const Thread &thread) {
- const DecodedThread *decoded_thread = Decode(thread);
- if (!decoded_thread)
- return 0;
- return decoded_thread->GetCursorPosition();
-}
-
-void TraceIntelPT::TraverseInstructions(
- const Thread &thread, size_t position, TraceDirection direction,
- std::function<bool(size_t index, Expected<lldb::addr_t> load_addr)>
- callback) {
- const DecodedThread *decoded_thread = Decode(thread);
- if (!decoded_thread)
- return;
+ 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.get(), std::make_unique<PostMortemThreadDecoder>(thread, *this));
+}
+
+DecodedThreadSP TraceIntelPT::Decode(Thread &thread) {
+ RefreshLiveProcessState();
+ if (m_live_refresh_error.hasValue())
+ return std::make_shared<DecodedThread>(
+ thread.shared_from_this(),
+ createStringError(inconvertibleErrorCode(), *m_live_refresh_error));
+
+ auto it = m_thread_decoders.find(&thread);
+ if (it == m_thread_decoders.end())
+ return std::make_shared<DecodedThread>(
+ thread.shared_from_this(),
+ createStringError(inconvertibleErrorCode(), "thread not traced"));
+ return it->second->Decode();
+}
- ArrayRef<IntelPTInstruction> instructions = decoded_thread->GetInstructions();
+lldb::TraceCursorUP TraceIntelPT::GetCursor(Thread &thread) {
+ return Decode(thread)->GetCursor();
+}
- ssize_t delta = direction == TraceDirection::Forwards ? 1 : -1;
- for (ssize_t i = position; i < (ssize_t)instructions.size() && i >= 0;
- i += delta)
- if (!callback(i, instructions[i].GetLoadAddress()))
- break;
+void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose) {
+ Optional<size_t> raw_size = GetRawTraceSize(thread);
+ s.Printf("\nthread #%u: tid = %" PRIu64, thread.GetIndexID(), thread.GetID());
+ if (!raw_size) {
+ s.Printf(", not traced\n");
+ return;
+ }
+ s.Printf("\n Raw trace size: %zu bytes\n", *raw_size);
+ return;
}
-size_t TraceIntelPT::GetInstructionCount(const Thread &thread) {
- if (const DecodedThread *decoded_thread = Decode(thread))
- return decoded_thread->GetInstructions().size();
+Optional<size_t> TraceIntelPT::GetRawTraceSize(Thread &thread) {
+ if (IsTraced(thread))
+ return Decode(thread)->GetRawTraceSize();
else
- return 0;
+ return None;
+}
+
+Expected<pt_cpu> TraceIntelPT::GetCPUInfoForLiveProcess() {
+ Expected<std::vector<uint8_t>> cpu_info = GetLiveProcessBinaryData("cpuInfo");
+ if (!cpu_info)
+ return cpu_info.takeError();
+
+ int64_t cpu_family = -1;
+ int64_t model = -1;
+ int64_t stepping = -1;
+ std::string vendor_id;
+
+ StringRef rest(reinterpret_cast<const char *>(cpu_info->data()),
+ cpu_info->size());
+ while (!rest.empty()) {
+ StringRef line;
+ std::tie(line, rest) = rest.split('\n');
+
+ SmallVector<StringRef, 2> columns;
+ line.split(columns, StringRef(":"), -1, false);
+
+ if (columns.size() < 2)
+ continue; // continue searching
+
+ columns[1] = columns[1].trim(" ");
+ if (columns[0].contains("cpu family") &&
+ columns[1].getAsInteger(10, cpu_family))
+ continue;
+
+ else if (columns[0].contains("model") && columns[1].getAsInteger(10, model))
+ continue;
+
+ else if (columns[0].contains("stepping") &&
+ columns[1].getAsInteger(10, stepping))
+ continue;
+
+ else if (columns[0].contains("vendor_id")) {
+ vendor_id = columns[1].str();
+ if (!vendor_id.empty())
+ continue;
+ }
+
+ if ((cpu_family != -1) && (model != -1) && (stepping != -1) &&
+ (!vendor_id.empty())) {
+ return pt_cpu{vendor_id == "GenuineIntel" ? pcv_intel : pcv_unknown,
+ static_cast<uint16_t>(cpu_family),
+ static_cast<uint8_t>(model),
+ static_cast<uint8_t>(stepping)};
+ }
+ }
+ return createStringError(inconvertibleErrorCode(),
+ "Failed parsing the target's /proc/cpuinfo file");
+}
+
+Expected<pt_cpu> TraceIntelPT::GetCPUInfo() {
+ if (!m_cpu_info) {
+ if (llvm::Expected<pt_cpu> cpu_info = GetCPUInfoForLiveProcess())
+ m_cpu_info = *cpu_info;
+ else
+ return cpu_info.takeError();
+ }
+ return *m_cpu_info;
+}
+
+void TraceIntelPT::DoRefreshLiveProcessState(
+ Expected<TraceGetStateResponse> state) {
+ m_thread_decoders.clear();
+
+ if (!state) {
+ m_live_refresh_error = toString(state.takeError());
+ return;
+ }
+
+ for (const TraceThreadState &thread_state : state->tracedThreads) {
+ Thread &thread =
+ *m_live_process->GetThreadList().FindThreadByID(thread_state.tid);
+ m_thread_decoders.emplace(
+ &thread, std::make_unique<LiveThreadDecoder>(thread, *this));
+ }
+}
+
+bool TraceIntelPT::IsTraced(const Thread &thread) {
+ RefreshLiveProcessState();
+ return m_thread_decoders.count(&thread);
+}
+
+// The information here should match the description of the intel-pt section
+// of the jLLDBTraceStart packet in the lldb/docs/lldb-gdb-remote.txt
+// documentation file. Similarly, it should match the CLI help messages of the
+// TraceIntelPTOptions.td file.
+const char *TraceIntelPT::GetStartConfigurationHelp() {
+ return R"(Parameters:
+
+ Note: If a parameter is not specified, a default value will be used.
+
+ - int threadBufferSize (defaults to 4096 bytes):
+ [process and thread tracing]
+ Trace size in bytes per thread. It must be a power of 2 greater
+ than or equal to 4096 (2^12). The trace is circular keeping the
+ the most recent data.
+
+ - boolean enableTsc (default to false):
+ [process and thread tracing]
+ Whether to use enable TSC timestamps or not. This is supported on
+ all devices that support intel-pt.
+
+ - psbPeriod (defaults to null):
+ [process and thread tracing]
+ This value defines the period in which PSB packets will be generated.
+ A PSB packet is a synchronization packet that contains a TSC
+ timestamp and the current absolute instruction pointer.
+
+ This parameter can only be used if
+
+ /sys/bus/event_source/devices/intel_pt/caps/psb_cyc
+
+ is 1. Otherwise, the PSB period will be defined by the processor.
+
+ If supported, valid values for this period can be found in
+
+ /sys/bus/event_source/devices/intel_pt/caps/psb_periods
+
+ which contains a hexadecimal number, whose bits represent
+ valid values e.g. if bit 2 is set, then value 2 is valid.
+
+ The psb_period value is converted to the approximate number of
+ raw trace bytes between PSB packets as:
+
+ 2 ^ (value + 11)
+
+ e.g. value 3 means 16KiB between PSB packets. Defaults to 0 if
+ supported.
+
+ - int processBufferSizeLimit (defaults to 500 MB):
+ [process tracing only]
+ Maximum total trace size per process in bytes. This limit applies
+ to the sum of the sizes of all thread traces of this process,
+ excluding the ones created explicitly with "thread tracing".
+ Whenever a thread is attempted to be traced due to this command
+ and the limit would be reached, the process is stopped with a
+ "processor trace" reason, so that the user can retrace the process
+ if needed.)";
+}
+
+Error TraceIntelPT::Start(size_t thread_buffer_size,
+ size_t total_buffer_size_limit, bool enable_tsc,
+ Optional<size_t> psb_period) {
+ TraceIntelPTStartRequest request;
+ request.threadBufferSize = thread_buffer_size;
+ request.processBufferSizeLimit = total_buffer_size_limit;
+ request.enableTsc = enable_tsc;
+ request.psbPeriod = psb_period.map([](size_t val) { return (int64_t)val; });
+ request.type = GetPluginName().AsCString();
+ return Trace::Start(toJSON(request));
+}
+
+Error TraceIntelPT::Start(StructuredData::ObjectSP configuration) {
+ size_t thread_buffer_size = kDefaultThreadBufferSize;
+ size_t process_buffer_size_limit = kDefaultProcessBufferSizeLimit;
+ bool enable_tsc = kDefaultEnableTscValue;
+ Optional<size_t> psb_period = kDefaultPsbPeriod;
+
+ if (configuration) {
+ if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
+ dict->GetValueForKeyAsInteger("threadBufferSize", thread_buffer_size);
+ dict->GetValueForKeyAsInteger("processBufferSizeLimit",
+ process_buffer_size_limit);
+ dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);
+ dict->GetValueForKeyAsInteger("psbPeriod", psb_period);
+ } else {
+ return createStringError(inconvertibleErrorCode(),
+ "configuration object is not a dictionary");
+ }
+ }
+
+ return Start(thread_buffer_size, process_buffer_size_limit, enable_tsc,
+ psb_period);
+}
+
+llvm::Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
+ size_t thread_buffer_size, bool enable_tsc,
+ Optional<size_t> psb_period) {
+ TraceIntelPTStartRequest request;
+ request.threadBufferSize = thread_buffer_size;
+ request.enableTsc = enable_tsc;
+ request.psbPeriod = psb_period.map([](size_t val) { return (int64_t)val; });
+ request.type = GetPluginName().AsCString();
+ request.tids.emplace();
+ for (lldb::tid_t tid : tids)
+ request.tids->push_back(tid);
+ return Trace::Start(toJSON(request));
+}
+
+Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
+ StructuredData::ObjectSP configuration) {
+ size_t thread_buffer_size = kDefaultThreadBufferSize;
+ bool enable_tsc = kDefaultEnableTscValue;
+ Optional<size_t> psb_period = kDefaultPsbPeriod;
+
+ if (configuration) {
+ if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
+ dict->GetValueForKeyAsInteger("threadBufferSize", thread_buffer_size);
+ dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);
+ dict->GetValueForKeyAsInteger("psbPeriod", psb_period);
+ } else {
+ return createStringError(inconvertibleErrorCode(),
+ "configuration object is not a dictionary");
+ }
+ }
+
+ 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");
}
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
index 5058e6fd32f2..e3b247112ae1 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
@@ -45,49 +45,134 @@ public:
/// \return
/// A trace instance or an error in case of failures.
static llvm::Expected<lldb::TraceSP>
- CreateInstance(const llvm::json::Value &trace_session_file,
- llvm::StringRef session_file_dir, Debugger &debugger);
+ CreateInstanceForSessionFile(const llvm::json::Value &trace_session_file,
+ llvm::StringRef session_file_dir,
+ Debugger &debugger);
+
+ static llvm::Expected<lldb::TraceSP>
+ CreateInstanceForLiveProcess(Process &process);
static ConstString GetPluginNameStatic();
uint32_t GetPluginVersion() override;
/// \}
+ lldb::CommandObjectSP
+ GetProcessTraceStartCommand(CommandInterpreter &interpreter) override;
+
+ lldb::CommandObjectSP
+ GetThreadTraceStartCommand(CommandInterpreter &interpreter) override;
+
llvm::StringRef GetSchema() override;
- void TraverseInstructions(
- const Thread &thread, size_t position, TraceDirection direction,
- std::function<bool(size_t index, llvm::Expected<lldb::addr_t> load_addr)>
- callback) override;
+ lldb::TraceCursorUP GetCursor(Thread &thread) override;
+
+ void DumpTraceInfo(Thread &thread, Stream &s, bool verbose) override;
+
+ llvm::Optional<size_t> GetRawTraceSize(Thread &thread);
+
+ void DoRefreshLiveProcessState(
+ llvm::Expected<TraceGetStateResponse> state) override;
+
+ bool IsTraced(const Thread &thread) override;
+
+ const char *GetStartConfigurationHelp() override;
+
+ /// Start tracing a live process.
+ ///
+ /// \param[in] thread_buffer_size
+ /// Trace size per thread in bytes.
+ ///
+ /// \param[in] total_buffer_size_limit
+ /// Maximum total trace size per process in bytes.
+ /// More information in TraceIntelPT::GetStartConfigurationHelp().
+ ///
+ /// \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 llvm::Error::success if the operation was successful, or
+ /// \a llvm::Error otherwise.
+ llvm::Error Start(size_t thread_buffer_size, size_t total_buffer_size_limit,
+ bool enable_tsc, llvm::Optional<size_t> psb_period);
+
+ /// \copydoc Trace::Start
+ llvm::Error Start(StructuredData::ObjectSP configuration =
+ StructuredData::ObjectSP()) override;
- size_t GetInstructionCount(const Thread &thread) override;
+ /// Start tracing live threads.
+ ///
+ /// \param[in] tids
+ /// Threads to trace.
+ ///
+ /// \param[in] thread_buffer_size
+ /// Trace size per thread 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 llvm::Error::success if the operation was successful, or
+ /// \a llvm::Error otherwise.
+ llvm::Error Start(llvm::ArrayRef<lldb::tid_t> tids, size_t thread_buffer_size,
+ bool enable_tsc, llvm::Optional<size_t> psb_period);
+
+ /// \copydoc Trace::Start
+ llvm::Error Start(llvm::ArrayRef<lldb::tid_t> tids,
+ 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);
- size_t GetCursorPosition(const Thread &thread) override;
+ llvm::Expected<pt_cpu> GetCPUInfo();
private:
friend class TraceIntelPTSessionFileParser;
+ llvm::Expected<pt_cpu> GetCPUInfoForLiveProcess();
+
/// \param[in] trace_threads
/// ThreadTrace instances, which are not live-processes and whose trace
/// files are fixed.
- TraceIntelPT(const pt_cpu &pt_cpu,
- const std::vector<std::shared_ptr<ThreadTrace>> &traced_threads);
+ TraceIntelPT(
+ const pt_cpu &cpu_info,
+ const std::vector<lldb::ThreadPostMortemTraceSP> &traced_threads);
+
+ /// Constructor for live processes
+ TraceIntelPT(Process &live_process)
+ : Trace(live_process), m_thread_decoders(){};
/// Decode the trace of the given thread that, i.e. recontruct the traced
- /// instructions. That trace must be managed by this class.
+ /// instructions.
///
/// \param[in] thread
/// If \a thread is a \a ThreadTrace, then its internal trace file will be
/// decoded. Live threads are not currently supported.
///
/// \return
- /// A \a DecodedThread instance if decoding was successful, or a \b
- /// nullptr if the thread's trace is not managed by this class.
- const DecodedThread *Decode(const Thread &thread);
-
- pt_cpu m_pt_cpu;
- std::map<std::pair<lldb::pid_t, lldb::tid_t>, ThreadTraceDecoder>
- m_trace_threads;
+ /// A \a DecodedThread shared pointer with the decoded instructions. Any
+ /// errors are embedded in the instruction list.
+ DecodedThreadSP Decode(Thread &thread);
+
+ /// It is provided by either a session file or a live process' "cpuInfo"
+ /// binary data.
+ llvm::Optional<pt_cpu> m_cpu_info;
+ std::map<const Thread *, std::unique_ptr<ThreadDecoder>> m_thread_decoders;
+ /// Error gotten after a failed live process update, if any.
+ llvm::Optional<std::string> m_live_refresh_error;
};
} // namespace trace_intel_pt
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h
new file mode 100644
index 000000000000..c2bc1b57b2bd
--- /dev/null
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h
@@ -0,0 +1,27 @@
+//===-- TraceIntelPTConstants.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 LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_CONSTANTS_H
+#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_CONSTANTS_H
+
+#include <cstddef>
+
+#include <llvm/ADT/Optional.h>
+
+namespace lldb_private {
+namespace trace_intel_pt {
+
+const size_t kDefaultThreadBufferSize = 4 * 1024; // 4KB
+const size_t kDefaultProcessBufferSizeLimit = 5 * 1024 * 1024; // 500MB
+const bool kDefaultEnableTscValue = false;
+const llvm::Optional<size_t> kDefaultPsbPeriod = llvm::None;
+
+} // namespace trace_intel_pt
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_CONSTANTS_H
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
index 6ffe949dbe7b..9e8cab1ee5c4 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
@@ -1,16 +1,74 @@
include "../../../../source/Commands/OptionsBase.td"
+// The information of the start commands here should match the description of
+// the intel-pt section of the jLLDBTraceStart packet in the
+// lldb/docs/lldb-gdb-remote.txt documentation file. Similarly, it should match
+// the API help message of TraceIntelPT::GetStartConfigurationHelp().
+
let Command = "thread trace start intel pt" in {
def thread_trace_start_intel_pt_size: Option<"size", "s">,
Group<1>,
Arg<"Value">,
- Desc<"The size of the trace in KB. The kernel rounds it down to the nearest"
- " multiple of 4. Defaults to 4.">;
- def thread_trace_start_intel_pt_custom_config: Option<"custom-config", "c">,
+ Desc<"Trace size in bytes per thread. It must be a power of 2 greater "
+ "than or equal to 4096 (2^12). The trace is circular keeping "
+ "the most recent data. Defaults to 4096 bytes.">;
+ def thread_trace_start_intel_pt_tsc: Option<"tsc", "t">,
+ Group<1>,
+ Desc<"Enable the use of TSC timestamps. This is supported on all devices "
+ "that support intel-pt.">;
+ def thread_trace_start_intel_pt_psb_period: Option<"psb-period", "p">,
+ Group<1>,
+ Arg<"Value">,
+ Desc<"This value defines the period in which PSB packets will be "
+ "generated. A PSB packet is a synchronization packet that contains a "
+ "TSC timestamp and the current absolute instruction pointer. "
+ "This parameter can only be used if "
+ "/sys/bus/event_source/devices/intel_pt/caps/psb_cyc is 1. Otherwise, "
+ "the PSB period will be defined by the processor. If supported, valid "
+ "values for this period can be found in "
+ "/sys/bus/event_source/devices/intel_pt/caps/psb_periods which "
+ "contains a hexadecimal number, whose bits represent valid values "
+ "e.g. if bit 2 is set, then value 2 is valid. The psb_period value is "
+ "converted to the approximate number of raw trace bytes between PSB "
+ "packets as: 2 ^ (value + 11), e.g. value 3 means 16KiB between PSB "
+ "packets. Defaults to 0 if supported.">;
+}
+
+let Command = "process trace start intel pt" in {
+ def process_trace_start_intel_pt_thread_size: Option<"thread-size", "s">,
+ Group<1>,
+ Arg<"Value">,
+ Desc<"Trace size in bytes per thread. It must be a power of 2 greater "
+ "than or equal to 4096 (2^12). The trace is circular keeping "
+ "the most recent data. Defaults to 4096 bytes.">;
+ def process_trace_start_intel_pt_process_size_limit: Option<"total-size-limit", "l">,
+ Group<1>,
+ Arg<"Value">,
+ Desc<"Maximum total trace size per process in bytes. This limit applies to "
+ "the sum of the sizes of all thread traces of this process, excluding "
+ "the ones created with the \"thread trace start\" command. "
+ "Whenever a thread is attempted to be traced due to this command and "
+ "the limit would be reached, the process is stopped with a "
+ "\"processor trace\" reason, so that the user can retrace the process "
+ "if needed. Defaults to 500MB.">;
+ def process_trace_start_intel_pt_tsc: Option<"tsc", "t">,
+ Group<1>,
+ Desc<"Enable the use of TSC timestamps. This is supported on all devices "
+ "that support intel-pt.">;
+ def process_trace_start_intel_pt_psb_period: Option<"psb-period", "p">,
Group<1>,
Arg<"Value">,
- Desc<"Low level bitmask configuration for the kernel based on the values "
- "in `grep -H /sys/bus/event_source/devices/intel_pt/format/*`. "
- "See https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/perf-intel-pt.txt"
- " for more information. Defaults to 0.">;
+ Desc<"This value defines the period in which PSB packets will be "
+ "generated. A PSB packet is a synchronization packet that contains a "
+ "TSC timestamp and the current absolute instruction pointer. "
+ "This parameter can only be used if "
+ "/sys/bus/event_source/devices/intel_pt/caps/psb_cyc is 1. Otherwise, "
+ "the PSB period will be defined by the processor. If supported, valid "
+ "values for this period can be found in "
+ "/sys/bus/event_source/devices/intel_pt/caps/psb_periods which "
+ "contains a hexadecimal number, whose bits represent valid values "
+ "e.g. if bit 2 is set, then value 2 is valid. The psb_period value is "
+ "converted to the approximate number of raw trace bytes between PSB "
+ "packets as: 2 ^ (value + 11), e.g. value 3 means 16KiB between PSB "
+ "packets. Defaults to 0 if supported.">;
}
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp
index beef5c3968ea..5af7c269d0cb 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp
@@ -8,11 +8,11 @@
#include "TraceIntelPTSessionFileParser.h"
+#include "../common/ThreadPostMortemTrace.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadList.h"
-#include "lldb/Target/ThreadTrace.h"
using namespace lldb;
using namespace lldb_private;
@@ -24,7 +24,7 @@ StringRef TraceIntelPTSessionFileParser::GetSchema() {
if (schema.empty()) {
schema = TraceSessionFileParser::BuildSchema(R"({
"type": "intel-pt",
- "pt_cpu": {
+ "cpuInfo": {
"vendor": "intel" | "unknown",
"family": integer,
"model": integer,
@@ -35,21 +35,22 @@ StringRef TraceIntelPTSessionFileParser::GetSchema() {
return schema;
}
-pt_cpu TraceIntelPTSessionFileParser::ParsePTCPU(const JSONPTCPU &pt_cpu) {
- return {pt_cpu.vendor.compare("intel") == 0 ? pcv_intel : pcv_unknown,
- static_cast<uint16_t>(pt_cpu.family),
- static_cast<uint8_t>(pt_cpu.model),
- static_cast<uint8_t>(pt_cpu.stepping)};
+pt_cpu TraceIntelPTSessionFileParser::ParsePTCPU(
+ const JSONTraceIntelPTCPUInfo &cpu_info) {
+ return {cpu_info.vendor.compare("intel") == 0 ? pcv_intel : pcv_unknown,
+ static_cast<uint16_t>(cpu_info.family),
+ static_cast<uint8_t>(cpu_info.model),
+ static_cast<uint8_t>(cpu_info.stepping)};
}
TraceSP TraceIntelPTSessionFileParser::CreateTraceIntelPTInstance(
- const pt_cpu &pt_cpu, std::vector<ParsedProcess> &parsed_processes) {
- std::vector<ThreadTraceSP> threads;
+ const pt_cpu &cpu_info, std::vector<ParsedProcess> &parsed_processes) {
+ std::vector<ThreadPostMortemTraceSP> threads;
for (const ParsedProcess &parsed_process : parsed_processes)
threads.insert(threads.end(), parsed_process.threads.begin(),
parsed_process.threads.end());
- TraceSP trace_instance(new TraceIntelPT(pt_cpu, threads));
+ TraceSP trace_instance(new TraceIntelPT(cpu_info, threads));
for (const ParsedProcess &parsed_process : parsed_processes)
parsed_process.target_sp->SetTrace(trace_instance);
@@ -64,7 +65,7 @@ Expected<TraceSP> TraceIntelPTSessionFileParser::Parse() {
if (Expected<std::vector<ParsedProcess>> parsed_processes =
ParseCommonSessionFile(session))
- return CreateTraceIntelPTInstance(ParsePTCPU(session.trace.pt_cpu),
+ return CreateTraceIntelPTInstance(ParsePTCPU(session.trace.cpuInfo),
*parsed_processes);
else
return parsed_processes.takeError();
@@ -73,25 +74,34 @@ Expected<TraceSP> TraceIntelPTSessionFileParser::Parse() {
namespace llvm {
namespace json {
-bool fromJSON(const Value &value,
- TraceIntelPTSessionFileParser::JSONPTCPU &pt_cpu, Path path) {
- ObjectMapper o(value, path);
- return o && o.map("vendor", pt_cpu.vendor) &&
- o.map("family", pt_cpu.family) && o.map("model", pt_cpu.model) &&
- o.map("stepping", pt_cpu.stepping);
-}
-
bool fromJSON(
const Value &value,
TraceIntelPTSessionFileParser::JSONTraceIntelPTSettings &plugin_settings,
Path path) {
ObjectMapper o(value, path);
- return o && o.map("pt_cpu", plugin_settings.pt_cpu) &&
+ return o && o.map("cpuInfo", plugin_settings.cpuInfo) &&
fromJSON(
value,
(TraceSessionFileParser::JSONTracePluginSettings &)plugin_settings,
path);
}
+bool fromJSON(const json::Value &value,
+ TraceIntelPTSessionFileParser::JSONTraceIntelPTCPUInfo &cpu_info,
+ Path path) {
+ ObjectMapper o(value, path);
+ return o && o.map("vendor", cpu_info.vendor) &&
+ o.map("family", cpu_info.family) && o.map("model", cpu_info.model) &&
+ o.map("stepping", cpu_info.stepping);
+}
+
+Value toJSON(
+ const TraceIntelPTSessionFileParser::JSONTraceIntelPTCPUInfo &cpu_info) {
+ return Value(Object{{"family", cpu_info.family},
+ {"model", cpu_info.model},
+ {"stepping", cpu_info.stepping},
+ {"vendor", cpu_info.vendor}});
+}
+
} // namespace json
} // namespace llvm
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h
index 6a896de09d00..b2667a882222 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h
@@ -10,7 +10,8 @@
#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPTSESSIONFILEPARSER_H
#include "TraceIntelPT.h"
-#include "lldb/Target/TraceSessionFileParser.h"
+
+#include "../common/TraceSessionFileParser.h"
namespace lldb_private {
namespace trace_intel_pt {
@@ -19,16 +20,16 @@ class TraceIntelPT;
class TraceIntelPTSessionFileParser : public TraceSessionFileParser {
public:
- struct JSONPTCPU {
- std::string vendor;
+ struct JSONTraceIntelPTCPUInfo {
int64_t family;
int64_t model;
int64_t stepping;
+ std::string vendor;
};
struct JSONTraceIntelPTSettings
: TraceSessionFileParser::JSONTracePluginSettings {
- JSONPTCPU pt_cpu;
+ JSONTraceIntelPTCPUInfo cpuInfo;
};
/// See \a TraceSessionFileParser::TraceSessionFileParser for the description
@@ -52,11 +53,11 @@ public:
llvm::Expected<lldb::TraceSP> Parse();
lldb::TraceSP
- CreateTraceIntelPTInstance(const pt_cpu &pt_cpu,
+ CreateTraceIntelPTInstance(const pt_cpu &cpu_info,
std::vector<ParsedProcess> &parsed_processes);
private:
- pt_cpu ParsePTCPU(const JSONPTCPU &pt_cpu);
+ static pt_cpu ParsePTCPU(const JSONTraceIntelPTCPUInfo &cpu_info);
const llvm::json::Value &m_trace_session_file;
};
@@ -67,17 +68,20 @@ private:
namespace llvm {
namespace json {
-bool fromJSON(
- const Value &value,
- lldb_private::trace_intel_pt::TraceIntelPTSessionFileParser::JSONPTCPU
- &pt_cpu,
- Path path);
-
bool fromJSON(const Value &value,
lldb_private::trace_intel_pt::TraceIntelPTSessionFileParser::
JSONTraceIntelPTSettings &plugin_settings,
Path path);
+bool fromJSON(const llvm::json::Value &value,
+ lldb_private::trace_intel_pt::TraceIntelPTSessionFileParser::
+ JSONTraceIntelPTCPUInfo &packet,
+ llvm::json::Path path);
+
+llvm::json::Value
+toJSON(const lldb_private::trace_intel_pt::TraceIntelPTSessionFileParser::
+ JSONTraceIntelPTCPUInfo &packet);
+
} // namespace json
} // namespace llvm
diff --git a/lldb/source/Plugins/Trace/intel-pt/forward-declarations.h b/lldb/source/Plugins/Trace/intel-pt/forward-declarations.h
new file mode 100644
index 000000000000..3c5f811acc10
--- /dev/null
+++ b/lldb/source/Plugins/Trace/intel-pt/forward-declarations.h
@@ -0,0 +1,20 @@
+//===-- forward-declarations.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 LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_FORWARD_DECLARATIONS_H
+#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_FORWARD_DECLARATIONS_H
+
+namespace lldb_private {
+namespace trace_intel_pt {
+
+class TraceIntelPT;
+class ThreadDecoder;
+
+} // namespace trace_intel_pt
+} // namespace lldb_private
+#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_FORWARD_DECLARATIONS_H