1 //===-- DecodedThread.cpp -------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "DecodedThread.h" 10 11 #include <intel-pt.h> 12 #include <memory> 13 14 #include "TraceCursorIntelPT.h" 15 #include "lldb/Utility/StreamString.h" 16 17 using namespace lldb; 18 using namespace lldb_private; 19 using namespace lldb_private::trace_intel_pt; 20 using namespace llvm; 21 22 char IntelPTError::ID; 23 24 IntelPTError::IntelPTError(int libipt_error_code, lldb::addr_t address) 25 : m_libipt_error_code(libipt_error_code), m_address(address) { 26 assert(libipt_error_code < 0); 27 } 28 29 void IntelPTError::log(llvm::raw_ostream &OS) const { 30 const char *libipt_error_message = pt_errstr(pt_errcode(m_libipt_error_code)); 31 if (m_address != LLDB_INVALID_ADDRESS && m_address > 0) { 32 write_hex(OS, m_address, HexPrintStyle::PrefixLower, 18); 33 OS << " "; 34 } 35 OS << "error: " << libipt_error_message; 36 } 37 38 IntelPTInstruction::IntelPTInstruction(llvm::Error err) { 39 llvm::handleAllErrors(std::move(err), 40 [&](std::unique_ptr<llvm::ErrorInfoBase> info) { 41 m_error = std::move(info); 42 }); 43 m_pt_insn.ip = LLDB_INVALID_ADDRESS; 44 m_pt_insn.iclass = ptic_error; 45 } 46 47 bool IntelPTInstruction::IsError() const { return (bool)m_error; } 48 49 lldb::addr_t IntelPTInstruction::GetLoadAddress() const { return m_pt_insn.ip; } 50 51 size_t IntelPTInstruction::GetNonErrorMemoryUsage() { return sizeof(IntelPTInstruction); } 52 53 Optional<uint64_t> IntelPTInstruction::GetTimestampCounter() const { 54 return m_timestamp; 55 } 56 57 Error IntelPTInstruction::ToError() const { 58 if (!IsError()) 59 return Error::success(); 60 61 if (m_error->isA<IntelPTError>()) 62 return make_error<IntelPTError>(static_cast<IntelPTError &>(*m_error)); 63 return make_error<StringError>(m_error->message(), 64 m_error->convertToErrorCode()); 65 } 66 size_t DecodedThread::GetRawTraceSize() const { return m_raw_trace_size; } 67 68 TraceInstructionControlFlowType 69 IntelPTInstruction::GetControlFlowType(lldb::addr_t next_load_address) const { 70 if (IsError()) 71 return (TraceInstructionControlFlowType)0; 72 73 TraceInstructionControlFlowType mask = 74 eTraceInstructionControlFlowTypeInstruction; 75 76 switch (m_pt_insn.iclass) { 77 case ptic_cond_jump: 78 case ptic_jump: 79 case ptic_far_jump: 80 mask |= eTraceInstructionControlFlowTypeBranch; 81 if (m_pt_insn.ip + m_pt_insn.size != next_load_address) 82 mask |= eTraceInstructionControlFlowTypeTakenBranch; 83 break; 84 case ptic_return: 85 case ptic_far_return: 86 mask |= eTraceInstructionControlFlowTypeReturn; 87 break; 88 case ptic_call: 89 case ptic_far_call: 90 mask |= eTraceInstructionControlFlowTypeCall; 91 break; 92 default: 93 break; 94 } 95 96 return mask; 97 } 98 99 ArrayRef<IntelPTInstruction> DecodedThread::GetInstructions() const { 100 return makeArrayRef(m_instructions); 101 } 102 103 DecodedThread::DecodedThread(ThreadSP thread_sp, Error error) 104 : m_thread_sp(thread_sp) { 105 m_instructions.emplace_back(std::move(error)); 106 } 107 108 DecodedThread::DecodedThread(ThreadSP thread_sp, 109 std::vector<IntelPTInstruction> &&instructions, 110 size_t raw_trace_size) 111 : m_thread_sp(thread_sp), m_instructions(std::move(instructions)), 112 m_raw_trace_size(raw_trace_size) { 113 if (m_instructions.empty()) 114 m_instructions.emplace_back( 115 createStringError(inconvertibleErrorCode(), "empty trace")); 116 } 117 118 lldb::TraceCursorUP DecodedThread::GetCursor() { 119 return std::make_unique<TraceCursorIntelPT>(m_thread_sp, shared_from_this()); 120 } 121 122 size_t DecodedThread::CalculateApproximateMemoryUsage() const { 123 return m_raw_trace_size 124 + IntelPTInstruction::GetNonErrorMemoryUsage() * m_instructions.size() 125 + sizeof(DecodedThread); 126 } 127