1 //===-- DecodedThread.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 "DecodedThread.h"
10 
11 #include <intel-pt.h>
12 #include <memory>
13 
14 #include "TraceCursorIntelPT.h"
15 #include "lldb/Utility/StreamString.h"
16 
17 using namespace lldb;
18 using namespace lldb_private;
19 using namespace lldb_private::trace_intel_pt;
20 using namespace llvm;
21 
22 char IntelPTError::ID;
23 
24 IntelPTError::IntelPTError(int libipt_error_code, lldb::addr_t address)
25     : m_libipt_error_code(libipt_error_code), m_address(address) {
26   assert(libipt_error_code < 0);
27 }
28 
29 void IntelPTError::log(llvm::raw_ostream &OS) const {
30   const char *libipt_error_message = pt_errstr(pt_errcode(m_libipt_error_code));
31   if (m_address != LLDB_INVALID_ADDRESS && m_address > 0) {
32     write_hex(OS, m_address, HexPrintStyle::PrefixLower, 18);
33     OS << "    ";
34   }
35   OS << "error: " << libipt_error_message;
36 }
37 
38 IntelPTInstruction::IntelPTInstruction(llvm::Error err) {
39   llvm::handleAllErrors(std::move(err),
40                         [&](std::unique_ptr<llvm::ErrorInfoBase> info) {
41                           m_error = std::move(info);
42                         });
43   m_pt_insn.ip = LLDB_INVALID_ADDRESS;
44   m_pt_insn.iclass = ptic_error;
45 }
46 
47 bool IntelPTInstruction::IsError() const { return (bool)m_error; }
48 
49 lldb::addr_t IntelPTInstruction::GetLoadAddress() const { return m_pt_insn.ip; }
50 
51 size_t IntelPTInstruction::GetNonErrorMemoryUsage() { return sizeof(IntelPTInstruction); }
52 
53 Optional<uint64_t> IntelPTInstruction::GetTimestampCounter() const {
54   return m_timestamp;
55 }
56 
57 Error IntelPTInstruction::ToError() const {
58   if (!IsError())
59     return Error::success();
60 
61   if (m_error->isA<IntelPTError>())
62     return make_error<IntelPTError>(static_cast<IntelPTError &>(*m_error));
63   return make_error<StringError>(m_error->message(),
64                                  m_error->convertToErrorCode());
65 }
66 size_t DecodedThread::GetRawTraceSize() const { return m_raw_trace_size; }
67 
68 TraceInstructionControlFlowType
69 IntelPTInstruction::GetControlFlowType(lldb::addr_t next_load_address) const {
70   if (IsError())
71     return (TraceInstructionControlFlowType)0;
72 
73   TraceInstructionControlFlowType mask =
74       eTraceInstructionControlFlowTypeInstruction;
75 
76   switch (m_pt_insn.iclass) {
77   case ptic_cond_jump:
78   case ptic_jump:
79   case ptic_far_jump:
80     mask |= eTraceInstructionControlFlowTypeBranch;
81     if (m_pt_insn.ip + m_pt_insn.size != next_load_address)
82       mask |= eTraceInstructionControlFlowTypeTakenBranch;
83     break;
84   case ptic_return:
85   case ptic_far_return:
86     mask |= eTraceInstructionControlFlowTypeReturn;
87     break;
88   case ptic_call:
89   case ptic_far_call:
90     mask |= eTraceInstructionControlFlowTypeCall;
91     break;
92   default:
93     break;
94   }
95 
96   return mask;
97 }
98 
99 ArrayRef<IntelPTInstruction> DecodedThread::GetInstructions() const {
100   return makeArrayRef(m_instructions);
101 }
102 
103 DecodedThread::DecodedThread(ThreadSP thread_sp, Error error)
104     : m_thread_sp(thread_sp) {
105   m_instructions.emplace_back(std::move(error));
106 }
107 
108 DecodedThread::DecodedThread(ThreadSP thread_sp,
109                              std::vector<IntelPTInstruction> &&instructions,
110                              size_t raw_trace_size)
111     : m_thread_sp(thread_sp), m_instructions(std::move(instructions)),
112       m_raw_trace_size(raw_trace_size) {
113   if (m_instructions.empty())
114     m_instructions.emplace_back(
115         createStringError(inconvertibleErrorCode(), "empty trace"));
116 }
117 
118 lldb::TraceCursorUP DecodedThread::GetCursor() {
119   return std::make_unique<TraceCursorIntelPT>(m_thread_sp, shared_from_this());
120 }
121 
122 size_t DecodedThread::CalculateApproximateMemoryUsage() const {
123   return m_raw_trace_size
124     + IntelPTInstruction::GetNonErrorMemoryUsage() * m_instructions.size()
125     + sizeof(DecodedThread);
126 }
127