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