xref: /freebsd/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp (revision 848ee2a3a8b47c9905fc51fefcf60eb371edbb98)
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 Optional<uint64_t> IntelPTInstruction::GetTimestampCounter() const {
52   return m_timestamp;
53 }
54 
55 Error IntelPTInstruction::ToError() const {
56   if (!IsError())
57     return Error::success();
58 
59   if (m_error->isA<IntelPTError>())
60     return make_error<IntelPTError>(static_cast<IntelPTError &>(*m_error));
61   return make_error<StringError>(m_error->message(),
62                                  m_error->convertToErrorCode());
63 }
64 size_t DecodedThread::GetRawTraceSize() const { return m_raw_trace_size; }
65 
66 TraceInstructionControlFlowType
67 IntelPTInstruction::GetControlFlowType(lldb::addr_t next_load_address) const {
68   if (IsError())
69     return (TraceInstructionControlFlowType)0;
70 
71   TraceInstructionControlFlowType mask =
72       eTraceInstructionControlFlowTypeInstruction;
73 
74   switch (m_pt_insn.iclass) {
75   case ptic_cond_jump:
76   case ptic_jump:
77   case ptic_far_jump:
78     mask |= eTraceInstructionControlFlowTypeBranch;
79     if (m_pt_insn.ip + m_pt_insn.size != next_load_address)
80       mask |= eTraceInstructionControlFlowTypeTakenBranch;
81     break;
82   case ptic_return:
83   case ptic_far_return:
84     mask |= eTraceInstructionControlFlowTypeReturn;
85     break;
86   case ptic_call:
87   case ptic_far_call:
88     mask |= eTraceInstructionControlFlowTypeCall;
89     break;
90   default:
91     break;
92   }
93 
94   return mask;
95 }
96 
97 ArrayRef<IntelPTInstruction> DecodedThread::GetInstructions() const {
98   return makeArrayRef(m_instructions);
99 }
100 
101 DecodedThread::DecodedThread(ThreadSP thread_sp, Error error)
102     : m_thread_sp(thread_sp) {
103   m_instructions.emplace_back(std::move(error));
104 }
105 
106 DecodedThread::DecodedThread(ThreadSP thread_sp,
107                              std::vector<IntelPTInstruction> &&instructions,
108                              size_t raw_trace_size)
109     : m_thread_sp(thread_sp), m_instructions(std::move(instructions)),
110       m_raw_trace_size(raw_trace_size) {
111   if (m_instructions.empty())
112     m_instructions.emplace_back(
113         createStringError(inconvertibleErrorCode(), "empty trace"));
114 }
115 
116 lldb::TraceCursorUP DecodedThread::GetCursor() {
117   return std::make_unique<TraceCursorIntelPT>(m_thread_sp, shared_from_this());
118 }
119