1 //===-- TraceCursorIntelPT.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 "TraceCursorIntelPT.h" 10 #include "DecodedThread.h" 11 #include "TraceIntelPT.h" 12 13 #include <cstdlib> 14 15 using namespace lldb; 16 using namespace lldb_private; 17 using namespace lldb_private::trace_intel_pt; 18 using namespace llvm; 19 20 TraceCursorIntelPT::TraceCursorIntelPT(ThreadSP thread_sp, 21 DecodedThreadSP decoded_thread_sp) 22 : TraceCursor(thread_sp), m_decoded_thread_sp(decoded_thread_sp) { 23 assert(m_decoded_thread_sp->GetInstructionsCount() > 0 && 24 "a trace should have at least one instruction or error"); 25 m_pos = m_decoded_thread_sp->GetInstructionsCount() - 1; 26 m_tsc_range = m_decoded_thread_sp->CalculateTscRange(m_pos); 27 } 28 29 size_t TraceCursorIntelPT::GetInternalInstructionSize() { 30 return m_decoded_thread_sp->GetInstructionsCount(); 31 } 32 33 bool TraceCursorIntelPT::Next() { 34 auto canMoveOne = [&]() { 35 if (IsForwards()) 36 return m_pos + 1 < GetInternalInstructionSize(); 37 return m_pos > 0; 38 }; 39 40 size_t initial_pos = m_pos; 41 42 while (canMoveOne()) { 43 m_pos += IsForwards() ? 1 : -1; 44 45 if (m_tsc_range && !m_tsc_range->InRange(m_pos)) 46 m_tsc_range = IsForwards() ? m_tsc_range->Next() : m_tsc_range->Prev(); 47 48 if (!m_ignore_errors && IsError()) 49 return true; 50 if (GetInstructionControlFlowType() & m_granularity) 51 return true; 52 } 53 54 // Didn't find any matching instructions 55 m_pos = initial_pos; 56 return false; 57 } 58 59 size_t TraceCursorIntelPT::Seek(int64_t offset, SeekType origin) { 60 int64_t last_index = GetInternalInstructionSize() - 1; 61 62 auto fitPosToBounds = [&](int64_t raw_pos) -> int64_t { 63 return std::min(std::max((int64_t)0, raw_pos), last_index); 64 }; 65 66 auto FindDistanceAndSetPos = [&]() -> int64_t { 67 switch (origin) { 68 case TraceCursor::SeekType::Set: 69 m_pos = fitPosToBounds(offset); 70 return m_pos; 71 case TraceCursor::SeekType::End: 72 m_pos = fitPosToBounds(offset + last_index); 73 return last_index - m_pos; 74 case TraceCursor::SeekType::Current: 75 int64_t new_pos = fitPosToBounds(offset + m_pos); 76 int64_t dist = m_pos - new_pos; 77 m_pos = new_pos; 78 return std::abs(dist); 79 } 80 }; 81 82 int64_t dist = FindDistanceAndSetPos(); 83 m_tsc_range = m_decoded_thread_sp->CalculateTscRange(m_pos); 84 return dist; 85 } 86 87 bool TraceCursorIntelPT::IsError() { 88 return m_decoded_thread_sp->IsInstructionAnError(m_pos); 89 } 90 91 const char *TraceCursorIntelPT::GetError() { 92 return m_decoded_thread_sp->GetErrorByInstructionIndex(m_pos); 93 } 94 95 lldb::addr_t TraceCursorIntelPT::GetLoadAddress() { 96 return m_decoded_thread_sp->GetInstructionLoadAddress(m_pos); 97 } 98 99 Optional<uint64_t> 100 TraceCursorIntelPT::GetCounter(lldb::TraceCounter counter_type) { 101 switch (counter_type) { 102 case lldb::eTraceCounterTSC: 103 if (m_tsc_range) 104 return m_tsc_range->GetTsc(); 105 else 106 return llvm::None; 107 } 108 } 109 110 TraceInstructionControlFlowType 111 TraceCursorIntelPT::GetInstructionControlFlowType() { 112 return m_decoded_thread_sp->GetInstructionControlFlowType(m_pos); 113 } 114