xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
1*e8d8bef9SDimitry Andric //===-- DecodedThread.h -----------------------------------------*- C++ -*-===//
2*e8d8bef9SDimitry Andric //
3*e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*e8d8bef9SDimitry Andric //
7*e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
8*e8d8bef9SDimitry Andric 
9*e8d8bef9SDimitry Andric #ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
10*e8d8bef9SDimitry Andric #define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
11*e8d8bef9SDimitry Andric 
12*e8d8bef9SDimitry Andric #include <vector>
13*e8d8bef9SDimitry Andric 
14*e8d8bef9SDimitry Andric #include "llvm/Support/Errc.h"
15*e8d8bef9SDimitry Andric #include "llvm/Support/Error.h"
16*e8d8bef9SDimitry Andric 
17*e8d8bef9SDimitry Andric #include "lldb/Target/Trace.h"
18*e8d8bef9SDimitry Andric 
19*e8d8bef9SDimitry Andric #include "intel-pt.h"
20*e8d8bef9SDimitry Andric 
21*e8d8bef9SDimitry Andric namespace lldb_private {
22*e8d8bef9SDimitry Andric namespace trace_intel_pt {
23*e8d8bef9SDimitry Andric 
24*e8d8bef9SDimitry Andric /// Class for representing a libipt decoding error.
25*e8d8bef9SDimitry Andric class IntelPTError : public llvm::ErrorInfo<IntelPTError> {
26*e8d8bef9SDimitry Andric public:
27*e8d8bef9SDimitry Andric   static char ID;
28*e8d8bef9SDimitry Andric 
29*e8d8bef9SDimitry Andric   /// \param[in] libipt_error_code
30*e8d8bef9SDimitry Andric   ///     Negative number returned by libipt when decoding the trace and
31*e8d8bef9SDimitry Andric   ///     signaling errors.
32*e8d8bef9SDimitry Andric   ///
33*e8d8bef9SDimitry Andric   /// \param[in] address
34*e8d8bef9SDimitry Andric   ///     Optional instruction address. When decoding an individual instruction,
35*e8d8bef9SDimitry Andric   ///     its address might be available in the \a pt_insn object, and should be
36*e8d8bef9SDimitry Andric   ///     passed to this constructor. Other errors don't have an associated
37*e8d8bef9SDimitry Andric   ///     address.
38*e8d8bef9SDimitry Andric   IntelPTError(int libipt_error_code,
39*e8d8bef9SDimitry Andric                lldb::addr_t address = LLDB_INVALID_ADDRESS);
40*e8d8bef9SDimitry Andric 
41*e8d8bef9SDimitry Andric   std::error_code convertToErrorCode() const override {
42*e8d8bef9SDimitry Andric     return llvm::errc::not_supported;
43*e8d8bef9SDimitry Andric   }
44*e8d8bef9SDimitry Andric 
45*e8d8bef9SDimitry Andric   void log(llvm::raw_ostream &OS) const override;
46*e8d8bef9SDimitry Andric 
47*e8d8bef9SDimitry Andric private:
48*e8d8bef9SDimitry Andric   int m_libipt_error_code;
49*e8d8bef9SDimitry Andric   lldb::addr_t m_address;
50*e8d8bef9SDimitry Andric };
51*e8d8bef9SDimitry Andric 
52*e8d8bef9SDimitry Andric /// \class IntelPTInstruction
53*e8d8bef9SDimitry Andric /// An instruction obtained from decoding a trace. It is either an actual
54*e8d8bef9SDimitry Andric /// instruction or an error indicating a gap in the trace.
55*e8d8bef9SDimitry Andric ///
56*e8d8bef9SDimitry Andric /// Gaps in the trace can come in a few flavors:
57*e8d8bef9SDimitry Andric ///   - tracing gaps (e.g. tracing was paused and then resumed)
58*e8d8bef9SDimitry Andric ///   - tracing errors (e.g. buffer overflow)
59*e8d8bef9SDimitry Andric ///   - decoding errors (e.g. some memory region couldn't be decoded)
60*e8d8bef9SDimitry Andric /// As mentioned, any gap is represented as an error in this class.
61*e8d8bef9SDimitry Andric class IntelPTInstruction {
62*e8d8bef9SDimitry Andric public:
63*e8d8bef9SDimitry Andric   IntelPTInstruction(const pt_insn &pt_insn) : m_pt_insn(pt_insn) {}
64*e8d8bef9SDimitry Andric 
65*e8d8bef9SDimitry Andric   /// Error constructor
66*e8d8bef9SDimitry Andric   ///
67*e8d8bef9SDimitry Andric   /// libipt errors should use the underlying \a IntelPTError class.
68*e8d8bef9SDimitry Andric   IntelPTInstruction(llvm::Error err) {
69*e8d8bef9SDimitry Andric     llvm::handleAllErrors(std::move(err),
70*e8d8bef9SDimitry Andric                           [&](std::unique_ptr<llvm::ErrorInfoBase> info) {
71*e8d8bef9SDimitry Andric                             m_error = std::move(info);
72*e8d8bef9SDimitry Andric                           });
73*e8d8bef9SDimitry Andric   }
74*e8d8bef9SDimitry Andric 
75*e8d8bef9SDimitry Andric   /// Check if this object represents an error (i.e. a gap).
76*e8d8bef9SDimitry Andric   ///
77*e8d8bef9SDimitry Andric   /// \return
78*e8d8bef9SDimitry Andric   ///     Whether this object represents an error.
79*e8d8bef9SDimitry Andric   bool IsError() const;
80*e8d8bef9SDimitry Andric 
81*e8d8bef9SDimitry Andric   /// \return
82*e8d8bef9SDimitry Andric   ///     The instruction pointer address, or an \a llvm::Error if it is an
83*e8d8bef9SDimitry Andric   ///     error.
84*e8d8bef9SDimitry Andric   llvm::Expected<lldb::addr_t> GetLoadAddress() const;
85*e8d8bef9SDimitry Andric 
86*e8d8bef9SDimitry Andric   /// \return
87*e8d8bef9SDimitry Andric   ///     An \a llvm::Error object if this class corresponds to an Error, or an
88*e8d8bef9SDimitry Andric   ///     \a llvm::Error::success otherwise.
89*e8d8bef9SDimitry Andric   llvm::Error ToError() const;
90*e8d8bef9SDimitry Andric 
91*e8d8bef9SDimitry Andric   IntelPTInstruction(IntelPTInstruction &&other) = default;
92*e8d8bef9SDimitry Andric 
93*e8d8bef9SDimitry Andric private:
94*e8d8bef9SDimitry Andric   IntelPTInstruction(const IntelPTInstruction &other) = delete;
95*e8d8bef9SDimitry Andric   const IntelPTInstruction &operator=(const IntelPTInstruction &other) = delete;
96*e8d8bef9SDimitry Andric 
97*e8d8bef9SDimitry Andric   pt_insn m_pt_insn;
98*e8d8bef9SDimitry Andric   std::unique_ptr<llvm::ErrorInfoBase> m_error;
99*e8d8bef9SDimitry Andric };
100*e8d8bef9SDimitry Andric 
101*e8d8bef9SDimitry Andric /// \class DecodedThread
102*e8d8bef9SDimitry Andric /// Class holding the instructions and function call hierarchy obtained from
103*e8d8bef9SDimitry Andric /// decoding a trace, as well as a position cursor used when reverse debugging
104*e8d8bef9SDimitry Andric /// the trace.
105*e8d8bef9SDimitry Andric ///
106*e8d8bef9SDimitry Andric /// Each decoded thread contains a cursor to the current position the user is
107*e8d8bef9SDimitry Andric /// stopped at. See \a Trace::GetCursorPosition for more information.
108*e8d8bef9SDimitry Andric class DecodedThread {
109*e8d8bef9SDimitry Andric public:
110*e8d8bef9SDimitry Andric   DecodedThread(std::vector<IntelPTInstruction> &&instructions)
111*e8d8bef9SDimitry Andric       : m_instructions(std::move(instructions)), m_position(GetLastPosition()) {
112*e8d8bef9SDimitry Andric   }
113*e8d8bef9SDimitry Andric 
114*e8d8bef9SDimitry Andric   /// Get the instructions from the decoded trace. Some of them might indicate
115*e8d8bef9SDimitry Andric   /// errors (i.e. gaps) in the trace.
116*e8d8bef9SDimitry Andric   ///
117*e8d8bef9SDimitry Andric   /// \return
118*e8d8bef9SDimitry Andric   ///   The instructions of the trace.
119*e8d8bef9SDimitry Andric   llvm::ArrayRef<IntelPTInstruction> GetInstructions() const;
120*e8d8bef9SDimitry Andric 
121*e8d8bef9SDimitry Andric   /// \return
122*e8d8bef9SDimitry Andric   ///   The current position of the cursor of this trace, or 0 if there are no
123*e8d8bef9SDimitry Andric   ///   instructions.
124*e8d8bef9SDimitry Andric   size_t GetCursorPosition() const;
125*e8d8bef9SDimitry Andric 
126*e8d8bef9SDimitry Andric   /// Change the position of the cursor of this trace. If this value is to high,
127*e8d8bef9SDimitry Andric   /// the new position will be set as the last instruction of the trace.
128*e8d8bef9SDimitry Andric   ///
129*e8d8bef9SDimitry Andric   /// \return
130*e8d8bef9SDimitry Andric   ///     The effective new position.
131*e8d8bef9SDimitry Andric   size_t SetCursorPosition(size_t new_position);
132*e8d8bef9SDimitry Andric   /// \}
133*e8d8bef9SDimitry Andric 
134*e8d8bef9SDimitry Andric private:
135*e8d8bef9SDimitry Andric   /// \return
136*e8d8bef9SDimitry Andric   ///     The index of the last element of the trace, or 0 if empty.
137*e8d8bef9SDimitry Andric   size_t GetLastPosition() const;
138*e8d8bef9SDimitry Andric 
139*e8d8bef9SDimitry Andric   std::vector<IntelPTInstruction> m_instructions;
140*e8d8bef9SDimitry Andric   size_t m_position;
141*e8d8bef9SDimitry Andric };
142*e8d8bef9SDimitry Andric 
143*e8d8bef9SDimitry Andric } // namespace trace_intel_pt
144*e8d8bef9SDimitry Andric } // namespace lldb_private
145*e8d8bef9SDimitry Andric 
146*e8d8bef9SDimitry Andric #endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
147