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 = 27 m_decoded_thread_sp->CalculateTscRange(m_pos, /*hint_range*/ None); 28 } 29 30 size_t TraceCursorIntelPT::GetInternalInstructionSize() { 31 return m_decoded_thread_sp->GetInstructionsCount(); 32 } 33 34 bool TraceCursorIntelPT::Next() { 35 auto canMoveOne = [&]() { 36 if (IsForwards()) 37 return m_pos + 1 < GetInternalInstructionSize(); 38 return m_pos > 0; 39 }; 40 41 size_t initial_pos = m_pos; 42 43 while (canMoveOne()) { 44 m_pos += IsForwards() ? 1 : -1; 45 46 if (m_tsc_range && !m_tsc_range->InRange(m_pos)) 47 m_tsc_range = IsForwards() ? m_tsc_range->Next() : m_tsc_range->Prev(); 48 49 if (!m_ignore_errors && IsError()) 50 return true; 51 if (GetInstructionControlFlowType() & m_granularity) 52 return true; 53 } 54 55 // Didn't find any matching instructions 56 m_pos = initial_pos; 57 return false; 58 } 59 60 uint64_t TraceCursorIntelPT::Seek(int64_t offset, SeekType origin) { 61 int64_t last_index = GetInternalInstructionSize() - 1; 62 63 auto fitPosToBounds = [&](int64_t raw_pos) -> int64_t { 64 return std::min(std::max((int64_t)0, raw_pos), last_index); 65 }; 66 67 auto FindDistanceAndSetPos = [&]() -> int64_t { 68 switch (origin) { 69 case TraceCursor::SeekType::Beginning: 70 m_pos = fitPosToBounds(offset); 71 return m_pos; 72 case TraceCursor::SeekType::End: 73 m_pos = fitPosToBounds(offset + last_index); 74 return last_index - m_pos; 75 case TraceCursor::SeekType::Current: 76 int64_t new_pos = fitPosToBounds(offset + m_pos); 77 int64_t dist = m_pos - new_pos; 78 m_pos = new_pos; 79 return std::abs(dist); 80 } 81 }; 82 83 int64_t dist = FindDistanceAndSetPos(); 84 m_tsc_range = m_decoded_thread_sp->CalculateTscRange(m_pos, m_tsc_range); 85 return dist; 86 } 87 88 bool TraceCursorIntelPT::IsError() { 89 return m_decoded_thread_sp->IsInstructionAnError(m_pos); 90 } 91 92 const char *TraceCursorIntelPT::GetError() { 93 return m_decoded_thread_sp->GetErrorByInstructionIndex(m_pos); 94 } 95 96 lldb::addr_t TraceCursorIntelPT::GetLoadAddress() { 97 return m_decoded_thread_sp->GetInstructionLoadAddress(m_pos); 98 } 99 100 Optional<uint64_t> 101 TraceCursorIntelPT::GetCounter(lldb::TraceCounter counter_type) { 102 switch (counter_type) { 103 case lldb::eTraceCounterTSC: 104 if (m_tsc_range) 105 return m_tsc_range->GetTsc(); 106 else 107 return llvm::None; 108 } 109 } 110 111 lldb::TraceEvents TraceCursorIntelPT::GetEvents() { 112 return m_decoded_thread_sp->GetEvents(m_pos); 113 } 114 115 TraceInstructionControlFlowType 116 TraceCursorIntelPT::GetInstructionControlFlowType() { 117 return m_decoded_thread_sp->GetInstructionControlFlowType(m_pos); 118 } 119 120 bool TraceCursorIntelPT::GoToId(user_id_t id) { 121 if (m_decoded_thread_sp->GetInstructionsCount() <= id) 122 return false; 123 m_pos = id; 124 m_tsc_range = m_decoded_thread_sp->CalculateTscRange(m_pos, m_tsc_range); 125 126 return true; 127 } 128 129 user_id_t TraceCursorIntelPT::GetId() const { return m_pos; } 130