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