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() { 39 m_pt_insn.ip = LLDB_INVALID_ADDRESS; 40 m_pt_insn.iclass = ptic_error; 41 m_is_error = true; 42 } 43 44 bool IntelPTInstruction::IsError() const { return m_is_error; } 45 46 lldb::addr_t IntelPTInstruction::GetLoadAddress() const { return m_pt_insn.ip; } 47 48 size_t IntelPTInstruction::GetMemoryUsage() { 49 return sizeof(IntelPTInstruction); 50 } 51 52 Optional<uint64_t> IntelPTInstruction::GetTimestampCounter() const { 53 return m_timestamp; 54 } 55 56 Optional<size_t> DecodedThread::GetRawTraceSize() const { 57 return m_raw_trace_size; 58 } 59 60 TraceInstructionControlFlowType 61 IntelPTInstruction::GetControlFlowType(lldb::addr_t next_load_address) const { 62 if (IsError()) 63 return (TraceInstructionControlFlowType)0; 64 65 TraceInstructionControlFlowType mask = 66 eTraceInstructionControlFlowTypeInstruction; 67 68 switch (m_pt_insn.iclass) { 69 case ptic_cond_jump: 70 case ptic_jump: 71 case ptic_far_jump: 72 mask |= eTraceInstructionControlFlowTypeBranch; 73 if (m_pt_insn.ip + m_pt_insn.size != next_load_address) 74 mask |= eTraceInstructionControlFlowTypeTakenBranch; 75 break; 76 case ptic_return: 77 case ptic_far_return: 78 mask |= eTraceInstructionControlFlowTypeReturn; 79 break; 80 case ptic_call: 81 case ptic_far_call: 82 mask |= eTraceInstructionControlFlowTypeCall; 83 break; 84 default: 85 break; 86 } 87 88 return mask; 89 } 90 91 ThreadSP DecodedThread::GetThread() { return m_thread_sp; } 92 93 void DecodedThread::AppendError(llvm::Error &&error) { 94 m_errors.try_emplace(m_instructions.size(), toString(std::move(error))); 95 m_instructions.emplace_back(); 96 } 97 98 ArrayRef<IntelPTInstruction> DecodedThread::GetInstructions() const { 99 return makeArrayRef(m_instructions); 100 } 101 102 const char *DecodedThread::GetErrorByInstructionIndex(uint64_t idx) { 103 auto it = m_errors.find(idx); 104 if (it == m_errors.end()) 105 return nullptr; 106 107 return it->second.c_str(); 108 } 109 110 DecodedThread::DecodedThread(ThreadSP thread_sp) : m_thread_sp(thread_sp) {} 111 112 DecodedThread::DecodedThread(ThreadSP thread_sp, Error &&error) 113 : m_thread_sp(thread_sp) { 114 AppendError(std::move(error)); 115 } 116 117 void DecodedThread::SetRawTraceSize(size_t size) { m_raw_trace_size = size; } 118 119 lldb::TraceCursorUP DecodedThread::GetCursor() { 120 // We insert a fake error signaling an empty trace if needed becasue the 121 // TraceCursor requires non-empty traces. 122 if (m_instructions.empty()) 123 AppendError(createStringError(inconvertibleErrorCode(), "empty trace")); 124 return std::make_unique<TraceCursorIntelPT>(m_thread_sp, shared_from_this()); 125 } 126 127 size_t DecodedThread::CalculateApproximateMemoryUsage() const { 128 return m_raw_trace_size.getValueOr(0) + 129 IntelPTInstruction::GetMemoryUsage() * m_instructions.size() + 130 m_errors.getMemorySize(); 131 } 132