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   Seek(0, SeekType::End);
24 }
25 
26 int64_t TraceCursorIntelPT::GetItemsCount() const {
27   return m_decoded_thread_sp->GetInstructionsCount();
28 }
29 
30 void TraceCursorIntelPT::CalculateTscRange() {
31   // If we failed, then we look for the exact range
32   if (!m_tsc_range || !m_tsc_range->InRange(m_pos))
33     m_tsc_range = m_decoded_thread_sp->CalculateTscRange(
34         m_pos, /*hit_range=*/m_tsc_range);
35 }
36 
37 void TraceCursorIntelPT::Next() {
38   m_pos += IsForwards() ? 1 : -1;
39 
40   // We try to go to a neighbor tsc range that might contain the current pos
41   if (m_tsc_range && !m_tsc_range->InRange(m_pos))
42     m_tsc_range = IsForwards() ? m_tsc_range->Next() : m_tsc_range->Prev();
43 
44   // If we failed, this call will fix it
45   CalculateTscRange();
46 }
47 
48 bool TraceCursorIntelPT::Seek(int64_t offset, SeekType origin) {
49   switch (origin) {
50   case TraceCursor::SeekType::Beginning:
51     m_pos = offset;
52     break;
53   case TraceCursor::SeekType::End:
54     m_pos = GetItemsCount() - 1 + offset;
55     break;
56   case TraceCursor::SeekType::Current:
57     m_pos += offset;
58   }
59   CalculateTscRange();
60 
61   return HasValue();
62 }
63 
64 bool TraceCursorIntelPT::HasValue() const {
65   return m_pos >= 0 && m_pos < GetItemsCount();
66 }
67 
68 bool TraceCursorIntelPT::IsError() {
69   return m_decoded_thread_sp->IsInstructionAnError(m_pos);
70 }
71 
72 const char *TraceCursorIntelPT::GetError() {
73   return m_decoded_thread_sp->GetErrorByInstructionIndex(m_pos);
74 }
75 
76 lldb::addr_t TraceCursorIntelPT::GetLoadAddress() {
77   return m_decoded_thread_sp->GetInstructionLoadAddress(m_pos);
78 }
79 
80 Optional<uint64_t>
81 TraceCursorIntelPT::GetCounter(lldb::TraceCounter counter_type) {
82   switch (counter_type) {
83   case lldb::eTraceCounterTSC:
84     if (m_tsc_range)
85       return m_tsc_range->GetTsc();
86     else
87       return llvm::None;
88   }
89 }
90 
91 lldb::TraceEvents TraceCursorIntelPT::GetEvents() {
92   return m_decoded_thread_sp->GetEvents(m_pos);
93 }
94 
95 TraceInstructionControlFlowType
96 TraceCursorIntelPT::GetInstructionControlFlowType() {
97   return m_decoded_thread_sp->GetInstructionControlFlowType(m_pos);
98 }
99 
100 bool TraceCursorIntelPT::GoToId(user_id_t id) {
101   if (!HasId(id))
102     return false;
103   m_pos = id;
104   m_tsc_range = m_decoded_thread_sp->CalculateTscRange(m_pos, m_tsc_range);
105 
106   return true;
107 }
108 
109 bool TraceCursorIntelPT::HasId(lldb::user_id_t id) const {
110   return id < m_decoded_thread_sp->GetInstructionsCount();
111 }
112 
113 user_id_t TraceCursorIntelPT::GetId() const { return m_pos; }
114