xref: /llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp (revision 059f39d2f44503862cb9c752c28a3a77275b0e51)
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