Depends on D89408. This diff finally implements trace decoding! The current interface is $ trace load /path/to/trace/session/file.json $ thread trace dump instructions thread #1: tid = 3842849, total instructions = 22 [ 0] 0x40052d [ 1] 0x40052d ... [19] 0x400521 $ # simply enter, which is a repeat command [20] 0x40052d [21] 0x400529 ... This doesn't do any disassembly, which will be done in the next diff. Changes: - Added an IntelPTDecoder class, that is a wrapper for libipt, which is the actual library that performs the decoding. - Added TraceThreadDecoder class that decodes traces and memoizes the result to avoid repeating the decoding step. - Added a DecodedThread class, which represents the output from decoding and that for the time being only stores the list of reconstructed instructions. Later it'll contain the function call hierarchy, which will enable reconstructing backtraces. - Added basic APIs for accessing the trace in Trace.h: - GetInstructionCount, which counts the number of instructions traced for a given thread - IsTraceFailed, which returns an Error if decoding a thread failed - ForEachInstruction, which iterates on the instructions traced for a given thread, concealing the internal storage of threads, as plug-ins can decide to generate the instructions on the fly or to store them all in a vector, like I do. - DumpTraceInstructions was updated to print the instructions or show an error message if decoding was impossible. - Tests included Differential Revision: https://reviews.llvm.org/D89283
147 lines
4.7 KiB
C++
147 lines
4.7 KiB
C++
//===-- DecodedThread.h -----------------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
|
|
#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
|
|
|
|
#include <vector>
|
|
|
|
#include "llvm/Support/Errc.h"
|
|
#include "llvm/Support/Error.h"
|
|
|
|
#include "lldb/Target/Trace.h"
|
|
|
|
#include "intel-pt.h"
|
|
|
|
namespace lldb_private {
|
|
namespace trace_intel_pt {
|
|
|
|
/// Class for representing a libipt decoding error.
|
|
class IntelPTError : public llvm::ErrorInfo<IntelPTError> {
|
|
public:
|
|
static char ID;
|
|
|
|
/// \param[in] libipt_error_code
|
|
/// Negative number returned by libipt when decoding the trace and
|
|
/// signaling errors.
|
|
///
|
|
/// \param[in] address
|
|
/// Optional instruction address. When decoding an individual instruction,
|
|
/// its address might be available in the \a pt_insn object, and should be
|
|
/// passed to this constructor. Other errors don't have an associated
|
|
/// address.
|
|
IntelPTError(int libipt_error_code,
|
|
lldb::addr_t address = LLDB_INVALID_ADDRESS);
|
|
|
|
std::error_code convertToErrorCode() const override {
|
|
return llvm::errc::not_supported;
|
|
}
|
|
|
|
void log(llvm::raw_ostream &OS) const override;
|
|
|
|
private:
|
|
int m_libipt_error_code;
|
|
lldb::addr_t m_address;
|
|
};
|
|
|
|
/// \class IntelPTInstruction
|
|
/// An instruction obtained from decoding a trace. It is either an actual
|
|
/// instruction or an error indicating a gap in the trace.
|
|
///
|
|
/// Gaps in the trace can come in a few flavors:
|
|
/// - tracing gaps (e.g. tracing was paused and then resumed)
|
|
/// - tracing errors (e.g. buffer overflow)
|
|
/// - decoding errors (e.g. some memory region couldn't be decoded)
|
|
/// As mentioned, any gap is represented as an error in this class.
|
|
class IntelPTInstruction {
|
|
public:
|
|
IntelPTInstruction(const pt_insn &pt_insn) : m_pt_insn(pt_insn) {}
|
|
|
|
/// Error constructor
|
|
///
|
|
/// libipt errors should use the underlying \a IntelPTError class.
|
|
IntelPTInstruction(llvm::Error err) {
|
|
llvm::handleAllErrors(std::move(err),
|
|
[&](std::unique_ptr<llvm::ErrorInfoBase> info) {
|
|
m_error = std::move(info);
|
|
});
|
|
}
|
|
|
|
/// Check if this object represents an error (i.e. a gap).
|
|
///
|
|
/// \return
|
|
/// Whether this object represents an error.
|
|
bool IsError() const;
|
|
|
|
/// \return
|
|
/// The instruction pointer address, or an \a llvm::Error if it is an
|
|
/// error.
|
|
llvm::Expected<lldb::addr_t> GetLoadAddress() const;
|
|
|
|
/// \return
|
|
/// An \a llvm::Error object if this class corresponds to an Error, or an
|
|
/// \a llvm::Error::success otherwise.
|
|
llvm::Error ToError() const;
|
|
|
|
IntelPTInstruction(IntelPTInstruction &&other) = default;
|
|
|
|
private:
|
|
IntelPTInstruction(const IntelPTInstruction &other) = delete;
|
|
const IntelPTInstruction &operator=(const IntelPTInstruction &other) = delete;
|
|
|
|
pt_insn m_pt_insn;
|
|
std::unique_ptr<llvm::ErrorInfoBase> m_error;
|
|
};
|
|
|
|
/// \class DecodedThread
|
|
/// Class holding the instructions and function call hierarchy obtained from
|
|
/// decoding a trace, as well as a position cursor used when reverse debugging
|
|
/// the trace.
|
|
///
|
|
/// Each decoded thread contains a cursor to the current position the user is
|
|
/// stopped at. See \a Trace::GetCursorPosition for more information.
|
|
class DecodedThread {
|
|
public:
|
|
DecodedThread(std::vector<IntelPTInstruction> &&instructions)
|
|
: m_instructions(std::move(instructions)), m_position(GetLastPosition()) {
|
|
}
|
|
|
|
/// Get the instructions from the decoded trace. Some of them might indicate
|
|
/// errors (i.e. gaps) in the trace.
|
|
///
|
|
/// \return
|
|
/// The instructions of the trace.
|
|
llvm::ArrayRef<IntelPTInstruction> GetInstructions() const;
|
|
|
|
/// \return
|
|
/// The current position of the cursor of this trace, or 0 if there are no
|
|
/// instructions.
|
|
size_t GetCursorPosition() const;
|
|
|
|
/// Change the position of the cursor of this trace. If this value is to high,
|
|
/// the new position will be set as the last instruction of the trace.
|
|
///
|
|
/// \return
|
|
/// The effective new position.
|
|
size_t SetCursorPosition(size_t new_position);
|
|
/// \}
|
|
|
|
private:
|
|
/// \return
|
|
/// The index of the last element of the trace, or 0 if empty.
|
|
size_t GetLastPosition() const;
|
|
|
|
std::vector<IntelPTInstruction> m_instructions;
|
|
size_t m_position;
|
|
};
|
|
|
|
} // namespace trace_intel_pt
|
|
} // namespace lldb_private
|
|
|
|
#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
|