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<size_t> DecodedThread::GetRawTraceSize() const { 53 return m_raw_trace_size; 54 } 55 56 TraceInstructionControlFlowType 57 IntelPTInstruction::GetControlFlowType(lldb::addr_t next_load_address) const { 58 if (IsError()) 59 return (TraceInstructionControlFlowType)0; 60 61 TraceInstructionControlFlowType mask = 62 eTraceInstructionControlFlowTypeInstruction; 63 64 switch (m_pt_insn.iclass) { 65 case ptic_cond_jump: 66 case ptic_jump: 67 case ptic_far_jump: 68 mask |= eTraceInstructionControlFlowTypeBranch; 69 if (m_pt_insn.ip + m_pt_insn.size != next_load_address) 70 mask |= eTraceInstructionControlFlowTypeTakenBranch; 71 break; 72 case ptic_return: 73 case ptic_far_return: 74 mask |= eTraceInstructionControlFlowTypeReturn; 75 break; 76 case ptic_call: 77 case ptic_far_call: 78 mask |= eTraceInstructionControlFlowTypeCall; 79 break; 80 default: 81 break; 82 } 83 84 return mask; 85 } 86 87 ThreadSP DecodedThread::GetThread() { return m_thread_sp; } 88 89 void DecodedThread::RecordTscForLastInstruction(uint64_t tsc) { 90 if (!m_last_tsc || *m_last_tsc != tsc) { 91 // In case the first instructions are errors or did not have a TSC, we'll 92 // get a first valid TSC not in position 0. We can safely force these error 93 // instructions to use the first valid TSC, so that all the trace has TSCs. 94 size_t start_index = 95 m_instruction_timestamps.empty() ? 0 : m_instructions.size() - 1; 96 m_instruction_timestamps.emplace(start_index, tsc); 97 m_last_tsc = tsc; 98 } 99 } 100 101 void DecodedThread::AppendInstruction(const pt_insn &insn) { 102 m_instructions.emplace_back(insn); 103 } 104 105 void DecodedThread::AppendInstruction(const pt_insn &insn, uint64_t tsc) { 106 AppendInstruction(insn); 107 RecordTscForLastInstruction(tsc); 108 } 109 110 void DecodedThread::AppendError(llvm::Error &&error) { 111 m_errors.try_emplace(m_instructions.size(), toString(std::move(error))); 112 m_instructions.emplace_back(); 113 } 114 115 void DecodedThread::AppendError(llvm::Error &&error, uint64_t tsc) { 116 AppendError(std::move(error)); 117 RecordTscForLastInstruction(tsc); 118 } 119 120 void DecodedThread::LibiptErrors::RecordError(int libipt_error_code) { 121 libipt_errors[pt_errstr(pt_errcode(libipt_error_code))]++; 122 total_count++; 123 } 124 125 void DecodedThread::RecordTscError(int libipt_error_code) { 126 m_tsc_errors.RecordError(libipt_error_code); 127 } 128 129 const DecodedThread::LibiptErrors &DecodedThread::GetTscErrors() const { 130 return m_tsc_errors; 131 } 132 133 ArrayRef<IntelPTInstruction> DecodedThread::GetInstructions() const { 134 return makeArrayRef(m_instructions); 135 } 136 137 Optional<DecodedThread::TscRange> 138 DecodedThread::CalculateTscRange(size_t insn_index) const { 139 auto it = m_instruction_timestamps.upper_bound(insn_index); 140 if (it == m_instruction_timestamps.begin()) 141 return None; 142 143 return TscRange(--it, *this); 144 } 145 146 bool DecodedThread::IsInstructionAnError(size_t insn_idx) const { 147 return m_instructions[insn_idx].IsError(); 148 } 149 150 const char *DecodedThread::GetErrorByInstructionIndex(size_t insn_idx) { 151 auto it = m_errors.find(insn_idx); 152 if (it == m_errors.end()) 153 return nullptr; 154 155 return it->second.c_str(); 156 } 157 158 DecodedThread::DecodedThread(ThreadSP thread_sp) : m_thread_sp(thread_sp) {} 159 160 DecodedThread::DecodedThread(ThreadSP thread_sp, Error &&error) 161 : m_thread_sp(thread_sp) { 162 AppendError(std::move(error)); 163 } 164 165 void DecodedThread::SetRawTraceSize(size_t size) { m_raw_trace_size = size; } 166 167 lldb::TraceCursorUP DecodedThread::GetCursor() { 168 // We insert a fake error signaling an empty trace if needed becasue the 169 // TraceCursor requires non-empty traces. 170 if (m_instructions.empty()) 171 AppendError(createStringError(inconvertibleErrorCode(), "empty trace")); 172 return std::make_unique<TraceCursorIntelPT>(m_thread_sp, shared_from_this()); 173 } 174 175 size_t DecodedThread::CalculateApproximateMemoryUsage() const { 176 return IntelPTInstruction::GetMemoryUsage() * m_instructions.size() + 177 m_errors.getMemorySize(); 178 } 179 180 DecodedThread::TscRange::TscRange(std::map<size_t, uint64_t>::const_iterator it, 181 const DecodedThread &decoded_thread) 182 : m_it(it), m_decoded_thread(&decoded_thread) { 183 auto next_it = m_it; 184 ++next_it; 185 m_end_index = (next_it == m_decoded_thread->m_instruction_timestamps.end()) 186 ? m_decoded_thread->GetInstructions().size() - 1 187 : next_it->first - 1; 188 } 189 190 size_t DecodedThread::TscRange::GetTsc() const { return m_it->second; } 191 192 size_t DecodedThread::TscRange::GetStartInstructionIndex() const { 193 return m_it->first; 194 } 195 196 size_t DecodedThread::TscRange::GetEndInstructionIndex() const { 197 return m_end_index; 198 } 199 200 bool DecodedThread::TscRange::InRange(size_t insn_index) { 201 return GetStartInstructionIndex() <= insn_index && 202 insn_index <= GetEndInstructionIndex(); 203 } 204 205 Optional<DecodedThread::TscRange> DecodedThread::TscRange::Next() { 206 auto next_it = m_it; 207 ++next_it; 208 if (next_it == m_decoded_thread->m_instruction_timestamps.end()) 209 return None; 210 return TscRange(next_it, *m_decoded_thread); 211 } 212 213 Optional<DecodedThread::TscRange> DecodedThread::TscRange::Prev() { 214 if (m_it == m_decoded_thread->m_instruction_timestamps.begin()) 215 return None; 216 auto prev_it = m_it; 217 --prev_it; 218 return TscRange(prev_it, *m_decoded_thread); 219 } 220