diff --git a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h --- a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h +++ b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h @@ -10,6 +10,7 @@ #define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H #include +#include #include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" @@ -39,6 +40,10 @@ IntelPTError(int libipt_error_code, lldb::addr_t address = LLDB_INVALID_ADDRESS); + // /// \param[in] string_error + // /// StringError to copy from + // IntelPTError(StringError string_error); + std::error_code convertToErrorCode() const override { return llvm::errc::not_supported; } @@ -69,7 +74,7 @@ /// Error constructor /// /// libipt errors should use the underlying \a IntelPTError class. - IntelPTInstruction(llvm::Error err); + IntelPTInstruction(llvm::Error &err); /// Check if this object represents an error (i.e. a gap). /// @@ -82,13 +87,8 @@ /// an error. lldb::addr_t GetLoadAddress() const; - /// Get the size in bytes of a non-error instance of this class - static size_t GetNonErrorMemoryUsage(); - - /// \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 size in bytes of an instance of this class + static size_t GetMemoryUsage(); /// Get the timestamp associated with the current instruction. The timestamp /// is similar to what a rdtsc instruction would return. @@ -119,7 +119,7 @@ // IntelPTInstruction::GetNonErrorMemoryUsage() if needed. pt_insn m_pt_insn; llvm::Optional m_timestamp; - std::unique_ptr m_error; + bool is_error; }; /// \class DecodedThread @@ -139,13 +139,39 @@ /// 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. + /// Get the instructions from the decoded trace. /// /// \return /// The instructions of the trace. llvm::ArrayRef GetInstructions() const; + /// Get the error associated with a given instruction index. + /// + /// \return + /// The error or \a llvm::Error::success if the given index + /// points to a valid instruction. + llvm::Error GetErrorByInstructionIndex(uint64_t ins_idx); + + /// Append a successfully decoded instruction. + template + void AppendInstruction(Ts... __args) { + m_instructions.emplace_back(std::move(IntelPTInstruction(__args...))); + } + + /// Append a decoding error (i.e. an instruction that failed to be decoded). + template + void AppendError(Ts... __args) { + llvm::Error err = llvm::make_error(__args...); + m_instructions.emplace_back(err); + handleAllErrors( + std::move(err), + [&](std::unique_ptr info) { + m_errors.insert(std::pair>( + m_instructions.size(), std::move(info) + )); + }); + } + /// Get a new cursor for the decoded thread. lldb::TraceCursorUP GetCursor(); @@ -164,6 +190,7 @@ /// to update \a CalculateApproximateMemoryUsage() accordingly. lldb::ThreadSP m_thread_sp; std::vector m_instructions; + llvm::DenseMap> m_errors; size_t m_raw_trace_size; }; diff --git a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp --- a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp +++ b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp @@ -10,6 +10,8 @@ #include #include +#include +#include #include "TraceCursorIntelPT.h" #include "lldb/Utility/StreamString.h" @@ -35,34 +37,24 @@ OS << "error: " << libipt_error_message; } -IntelPTInstruction::IntelPTInstruction(llvm::Error err) { - llvm::handleAllErrors(std::move(err), - [&](std::unique_ptr info) { - m_error = std::move(info); - }); +IntelPTInstruction::IntelPTInstruction(Error &err) { m_pt_insn.ip = LLDB_INVALID_ADDRESS; m_pt_insn.iclass = ptic_error; + is_error = true; } -bool IntelPTInstruction::IsError() const { return (bool)m_error; } +bool IntelPTInstruction::IsError() const { return is_error; } lldb::addr_t IntelPTInstruction::GetLoadAddress() const { return m_pt_insn.ip; } -size_t IntelPTInstruction::GetNonErrorMemoryUsage() { return sizeof(IntelPTInstruction); } +size_t IntelPTInstruction::GetMemoryUsage() { + return sizeof(IntelPTInstruction); +} Optional IntelPTInstruction::GetTimestampCounter() const { return m_timestamp; } -Error IntelPTInstruction::ToError() const { - if (!IsError()) - return Error::success(); - - if (m_error->isA()) - return make_error(static_cast(*m_error)); - return make_error(m_error->message(), - m_error->convertToErrorCode()); -} size_t DecodedThread::GetRawTraceSize() const { return m_raw_trace_size; } TraceInstructionControlFlowType @@ -100,9 +92,21 @@ return makeArrayRef(m_instructions); } +Error DecodedThread::GetErrorByInstructionIndex(uint64_t idx) { + auto it = m_errors.find(idx); + if (it == m_errors.end()) + return Error::success(); + + auto &err = it->second; + if (err->isA()) + return make_error(static_cast(*err)); + + return make_error(err->message(), err->convertToErrorCode()); +} + DecodedThread::DecodedThread(ThreadSP thread_sp, Error error) : m_thread_sp(thread_sp) { - m_instructions.emplace_back(std::move(error)); + m_instructions.emplace_back(error); } DecodedThread::DecodedThread(ThreadSP thread_sp, @@ -111,8 +115,7 @@ : 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")); + AppendError(inconvertibleErrorCode(), "empty trace"); } lldb::TraceCursorUP DecodedThread::GetCursor() { @@ -121,6 +124,7 @@ size_t DecodedThread::CalculateApproximateMemoryUsage() const { return m_raw_trace_size - + IntelPTInstruction::GetNonErrorMemoryUsage() * m_instructions.size() - + sizeof(DecodedThread); + + sizeof(IntelPTInstruction) * (m_instructions.size() - m_errors.size()) + + m_errors.getMemorySize(); + // + sizeof(DecodedThread); } diff --git a/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp b/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp --- a/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp +++ b/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp @@ -9,6 +9,7 @@ #include "llvm/Support/MemoryBuffer.h" +#include #include "../common/ThreadPostMortemTrace.h" #include "DecodedThread.h" #include "TraceIntelPT.h" @@ -104,9 +105,12 @@ /// /// \return /// The decoded instructions. -static std::vector -DecodeInstructions(pt_insn_decoder &decoder) { - std::vector instructions; +static DecodedThreadSP DecodeInstructions(pt_insn_decoder &decoder, + const ThreadSP &thread_sp, + const size_t raw_trace_size) { + DecodedThreadSP decoded_thread = + std::make_shared(DecodedThread( + thread_sp, std::vector(), raw_trace_size)); while (true) { int errcode = FindNextSynchronizationPoint(decoder); @@ -114,7 +118,7 @@ break; if (errcode < 0) { - instructions.emplace_back(make_error(errcode)); + decoded_thread->AppendError(errcode); break; } @@ -123,17 +127,17 @@ while (true) { errcode = ProcessPTEvents(decoder, errcode); if (errcode < 0) { - instructions.emplace_back(make_error(errcode)); + decoded_thread->AppendError(errcode); break; } - pt_insn insn; + pt_insn insn; errcode = pt_insn_next(&decoder, &insn, sizeof(insn)); if (errcode == -pte_eos) break; if (errcode < 0) { - instructions.emplace_back(make_error(errcode, insn.ip)); + decoded_thread->AppendError(errcode, insn.ip); break; } @@ -142,22 +146,22 @@ 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(time_error, insn.ip)); - instructions.emplace_back(insn); + decoded_thread->AppendError(time_error, insn.ip); + decoded_thread->AppendInstruction(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); + decoded_thread->AppendInstruction(insn); } else { - instructions.emplace_back(insn, time); + decoded_thread->AppendInstruction(insn, time); } } } - return instructions; + return decoded_thread; } /// Callback used by libipt for reading the process memory. @@ -176,8 +180,9 @@ return bytes_read; } -static Expected> -DecodeInMemoryTrace(Process &process, TraceIntelPT &trace_intel_pt, +static Expected +DecodeInMemoryTrace(const ThreadSP &thread_sp, Process &process, + TraceIntelPT &trace_intel_pt, MutableArrayRef buffer) { Expected cpu_info = trace_intel_pt.GetCPUInfo(); if (!cpu_info) @@ -203,77 +208,72 @@ assert(errcode == 0); (void)errcode; - std::vector instructions = DecodeInstructions(*decoder); + DecodedThreadSP decoded_thread = + DecodeInstructions(*decoder, thread_sp, buffer.size()); pt_insn_free_decoder(decoder); - return instructions; + return decoded_thread; } +// --------------------------- -static Expected> -DecodeTraceFile(Process &process, TraceIntelPT &trace_intel_pt, - const FileSpec &trace_file, size_t &raw_trace_size) { - ErrorOr> 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 trace_data( - // The libipt library does not modify the trace buffer, hence the - // following cast is safe. - reinterpret_cast(const_cast(trace.getBufferStart())), - trace.getBufferSize()); - raw_trace_size = trace_data.size(); - return DecodeInMemoryTrace(process, trace_intel_pt, trace_data); +DecodedThreadSP ThreadDecoder::Decode() { + if (!m_decoded_thread.hasValue()) + m_decoded_thread = DoDecode(); + return *m_decoded_thread; } -static Expected> -DecodeLiveThread(Thread &thread, TraceIntelPT &trace, size_t &raw_trace_size) { +// LiveThreadDecoder ==================== + +LiveThreadDecoder::LiveThreadDecoder(Thread &thread, TraceIntelPT &trace) + : m_thread_sp(thread.shared_from_this()), m_trace(trace) {} + +DecodedThreadSP LiveThreadDecoder::DoDecode() { Expected> buffer = - trace.GetLiveThreadBuffer(thread.GetID()); + m_trace.GetLiveThreadBuffer(m_thread_sp->GetID()); + if (!buffer) - return buffer.takeError(); - raw_trace_size = buffer->size(); - if (Expected cpu_info = trace.GetCPUInfo()) - return DecodeInMemoryTrace(*thread.GetProcess(), trace, - MutableArrayRef(*buffer)); + return DecodedThread(m_thread_sp, buffer.takeError()).shared_from_this(); + + if (Expected cpu_info = m_trace.GetCPUInfo()) + if (Expected dtsp = + DecodeInMemoryTrace(m_thread_sp, *m_thread_sp->GetProcess(), + m_trace, MutableArrayRef(*buffer))) + return *dtsp; + else + return DecodedThread(m_thread_sp, dtsp.takeError()).shared_from_this(); else - return cpu_info.takeError(); + return DecodedThread(m_thread_sp, cpu_info.takeError()).shared_from_this(); } -DecodedThreadSP ThreadDecoder::Decode() { - if (!m_decoded_thread.hasValue()) - m_decoded_thread = DoDecode(); - return *m_decoded_thread; -} +// PostMortemThreadDecoder ======================= 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> instructions = - DecodeTraceFile(*m_trace_thread->GetProcess(), m_trace, - m_trace_thread->GetTraceFile(), raw_trace_size)) - return std::make_shared(m_trace_thread->shared_from_this(), - std::move(*instructions), - raw_trace_size); - else - return std::make_shared(m_trace_thread->shared_from_this(), - instructions.takeError()); -} +static Expected DecodeTraceFile(const ThreadSP &thread_sp, + Process &process, + TraceIntelPT &trace_intel_pt, + const FileSpec &trace_file) { + ErrorOr> trace_or_error = + MemoryBuffer::getFile(trace_file.GetPath()); + if (std::error_code err = trace_or_error.getError()) + return errorCodeToError(err); -LiveThreadDecoder::LiveThreadDecoder(Thread &thread, TraceIntelPT &trace) - : m_thread_sp(thread.shared_from_this()), m_trace(trace) {} + MemoryBuffer &trace = **trace_or_error; + MutableArrayRef trace_data( + // The libipt library does not modify the trace buffer, hence the + // following cast is safe. + reinterpret_cast(const_cast(trace.getBufferStart())), + trace.getBufferSize()); + return DecodeInMemoryTrace(thread_sp, process, trace_intel_pt, trace_data); +} -DecodedThreadSP LiveThreadDecoder::DoDecode() { - size_t raw_trace_size = 0; - if (Expected> instructions = - DecodeLiveThread(*m_thread_sp, m_trace, raw_trace_size)) - return std::make_shared( - m_thread_sp, std::move(*instructions), raw_trace_size); +DecodedThreadSP PostMortemThreadDecoder::DoDecode() { + if (Expected dtsp = + DecodeTraceFile(m_trace_thread, *m_trace_thread->GetProcess(), + m_trace, m_trace_thread->GetTraceFile())) + return *dtsp; else - return std::make_shared(m_thread_sp, - instructions.takeError()); + return DecodedThread(m_trace_thread, dtsp.takeError()).shared_from_this(); } diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp --- a/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp +++ b/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp @@ -78,7 +78,7 @@ } Error TraceCursorIntelPT::GetError() { - return m_decoded_thread_sp->GetInstructions()[m_pos].ToError(); + return m_decoded_thread_sp->GetErrorByInstructionIndex(m_pos); } lldb::addr_t TraceCursorIntelPT::GetLoadAddress() {