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
IntelPTError(int libipt_error_code,lldb::addr_t address)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
log(llvm::raw_ostream & OS) const29 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
IntelPTInstruction(llvm::Error err)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
IsError() const47 bool IntelPTInstruction::IsError() const { return (bool)m_error; }
48
GetLoadAddress() const49 lldb::addr_t IntelPTInstruction::GetLoadAddress() const { return m_pt_insn.ip; }
50
GetTimestampCounter() const51 Optional<uint64_t> IntelPTInstruction::GetTimestampCounter() const {
52 return m_timestamp;
53 }
54
ToError() const55 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 }
GetRawTraceSize() const64 size_t DecodedThread::GetRawTraceSize() const { return m_raw_trace_size; }
65
66 TraceInstructionControlFlowType
GetControlFlowType(lldb::addr_t next_load_address) const67 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
GetInstructions() const97 ArrayRef<IntelPTInstruction> DecodedThread::GetInstructions() const {
98 return makeArrayRef(m_instructions);
99 }
100
DecodedThread(ThreadSP thread_sp,Error error)101 DecodedThread::DecodedThread(ThreadSP thread_sp, Error error)
102 : m_thread_sp(thread_sp) {
103 m_instructions.emplace_back(std::move(error));
104 }
105
DecodedThread(ThreadSP thread_sp,std::vector<IntelPTInstruction> && instructions,size_t raw_trace_size)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
GetCursor()116 lldb::TraceCursorUP DecodedThread::GetCursor() {
117 return std::make_unique<TraceCursorIntelPT>(m_thread_sp, shared_from_this());
118 }
119