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->GetInstructions().empty() &&
24          "a trace should have at least one instruction or error");
25   m_pos = m_decoded_thread_sp->GetInstructions().size() - 1;
26 }
27 
28 size_t TraceCursorIntelPT::GetInternalInstructionSize() {
29   return m_decoded_thread_sp->GetInstructions().size();
30 }
31 
32 bool TraceCursorIntelPT::Next() {
33   auto canMoveOne = [&]() {
34     if (IsForwards())
35       return m_pos + 1 < GetInternalInstructionSize();
36     return m_pos > 0;
37   };
38 
39   size_t initial_pos = m_pos;
40 
41   while (canMoveOne()) {
42     m_pos += IsForwards() ? 1 : -1;
43     if (!m_ignore_errors && IsError())
44       return true;
45     if (GetInstructionControlFlowType() & m_granularity)
46       return true;
47   }
48 
49   // Didn't find any matching instructions
50   m_pos = initial_pos;
51   return false;
52 }
53 
54 size_t TraceCursorIntelPT::Seek(int64_t offset, SeekType origin) {
55   int64_t last_index = GetInternalInstructionSize() - 1;
56 
57   auto fitPosToBounds = [&](int64_t raw_pos) -> int64_t {
58     return std::min(std::max((int64_t)0, raw_pos), last_index);
59   };
60 
61   switch (origin) {
62   case TraceCursor::SeekType::Set:
63     m_pos = fitPosToBounds(offset);
64     return m_pos;
65   case TraceCursor::SeekType::End:
66     m_pos = fitPosToBounds(offset + last_index);
67     return last_index - m_pos;
68   case TraceCursor::SeekType::Current:
69     int64_t new_pos = fitPosToBounds(offset + m_pos);
70     int64_t dist = m_pos - new_pos;
71     m_pos = new_pos;
72     return std::abs(dist);
73   }
74 }
75 
76 bool TraceCursorIntelPT::IsError() {
77   return m_decoded_thread_sp->GetInstructions()[m_pos].IsError();
78 }
79 
80 Error TraceCursorIntelPT::GetError() {
81   return m_decoded_thread_sp->GetInstructions()[m_pos].ToError();
82 }
83 
84 lldb::addr_t TraceCursorIntelPT::GetLoadAddress() {
85   return m_decoded_thread_sp->GetInstructions()[m_pos].GetLoadAddress();
86 }
87 
88 Optional<uint64_t> TraceCursorIntelPT::GetTimestampCounter() {
89   return m_decoded_thread_sp->GetInstructions()[m_pos].GetTimestampCounter();
90 }
91 
92 TraceInstructionControlFlowType
93 TraceCursorIntelPT::GetInstructionControlFlowType() {
94   lldb::addr_t next_load_address =
95       m_pos + 1 < GetInternalInstructionSize()
96           ? m_decoded_thread_sp->GetInstructions()[m_pos + 1].GetLoadAddress()
97           : LLDB_INVALID_ADDRESS;
98   return m_decoded_thread_sp->GetInstructions()[m_pos].GetControlFlowType(
99       next_load_address);
100 }
101