Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,28 @@
include_directories(.)
include_directories(../POSIX)
include_directories(../Utility)
add_lldb_library(lldbPluginProcessLinux PLUGIN
NativeProcessLinux.cpp
NativeRegisterContextLinux.cpp
NativeRegisterContextLinux_arm.cpp
NativeRegisterContextLinux_arm64.cpp
NativeRegisterContextLinux_mips64.cpp
NativeRegisterContextLinux_ppc64le.cpp
NativeRegisterContextLinux_s390x.cpp
NativeRegisterContextLinux_x86_64.cpp
NativeThreadLinux.cpp
ProcessorTrace.cpp
SingleStepCheck.cpp
LINK_LIBS
lldbCore
lldbHost
lldbSymbol
lldbTarget
lldbUtility
lldbPluginProcessPOSIX
lldbPluginProcessUtility
LINK_COMPONENTS
Support
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,287 @@
//===-- NativeProcessLinux.h ---------------------------------- -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_NativeProcessLinux_H_
#define liblldb_NativeProcessLinux_H_
#include <csignal>
#include <unordered_set>
#include "lldb/Host/Debug.h"
#include "lldb/Host/HostThread.h"
#include "lldb/Host/linux/Support.h"
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/lldb-types.h"
#include "NativeThreadLinux.h"
#include "ProcessorTrace.h"
#include "lldb/Host/common/NativeProcessProtocol.h"
namespace lldb_private {
class Status;
class Scalar;
namespace process_linux {
/// @class NativeProcessLinux
/// @brief Manages communication with the inferior (debugee) process.
///
/// Upon construction, this class prepares and launches an inferior process for
/// debugging.
///
/// Changes in the inferior process state are broadcasted.
class NativeProcessLinux : public NativeProcessProtocol {
public:
class Factory : public NativeProcessProtocol::Factory {
public:
llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate,
MainLoop &mainloop) const override;
llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
Attach(lldb::pid_t pid, NativeDelegate &native_delegate,
MainLoop &mainloop) const override;
};
// ---------------------------------------------------------------------
// NativeProcessProtocol Interface
// ---------------------------------------------------------------------
Status Resume(const ResumeActionList &resume_actions) override;
Status Halt() override;
Status Detach() override;
Status Signal(int signo) override;
Status Interrupt() override;
Status Kill() override;
Status GetMemoryRegionInfo(lldb::addr_t load_addr,
MemoryRegionInfo &range_info) override;
Status ReadMemory(lldb::addr_t addr, void *buf, size_t size,
size_t &bytes_read) override;
Status ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size,
size_t &bytes_read) override;
Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
size_t &bytes_written) override;
Status AllocateMemory(size_t size, uint32_t permissions,
lldb::addr_t &addr) override;
Status DeallocateMemory(lldb::addr_t addr) override;
lldb::addr_t GetSharedLibraryInfoAddress() override;
size_t UpdateThreads() override;
const ArchSpec &GetArchitecture() const override { return m_arch; }
Status SetBreakpoint(lldb::addr_t addr, uint32_t size,
bool hardware) override;
Status RemoveBreakpoint(lldb::addr_t addr, bool hardware = false) override;
void DoStopIDBumped(uint32_t newBumpId) override;
Status GetLoadedModuleFileSpec(const char *module_path,
FileSpec &file_spec) override;
Status GetFileLoadAddress(const llvm::StringRef &file_name,
lldb::addr_t &load_addr) override;
NativeThreadLinux *GetThreadByID(lldb::tid_t id);
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
GetAuxvData() const override {
return getProcFile(GetID(), "auxv");
}
lldb::user_id_t StartTrace(const TraceOptions &config,
Status &error) override;
Status StopTrace(lldb::user_id_t traceid,
lldb::tid_t thread) override;
Status GetData(lldb::user_id_t traceid, lldb::tid_t thread,
llvm::MutableArrayRef<uint8_t> &buffer,
size_t offset = 0) override;
Status GetMetaData(lldb::user_id_t traceid, lldb::tid_t thread,
llvm::MutableArrayRef<uint8_t> &buffer,
size_t offset = 0) override;
Status GetTraceConfig(lldb::user_id_t traceid, TraceOptions &config) override;
// ---------------------------------------------------------------------
// Interface used by NativeRegisterContext-derived classes.
// ---------------------------------------------------------------------
static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr,
void *data = nullptr, size_t data_size = 0,
long *result = nullptr);
bool SupportHardwareSingleStepping() const;
protected:
// ---------------------------------------------------------------------
// NativeProcessProtocol protected interface
// ---------------------------------------------------------------------
Status
GetSoftwareBreakpointTrapOpcode(size_t trap_opcode_size_hint,
size_t &actual_opcode_size,
const uint8_t *&trap_opcode_bytes) override;
private:
MainLoop::SignalHandleUP m_sigchld_handle;
ArchSpec m_arch;
LazyBool m_supports_mem_region = eLazyBoolCalculate;
std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache;
lldb::tid_t m_pending_notification_tid = LLDB_INVALID_THREAD_ID;
// List of thread ids stepping with a breakpoint with the address of
// the relevan breakpoint
std::map<lldb::tid_t, lldb::addr_t> m_threads_stepping_with_breakpoint;
// ---------------------------------------------------------------------
// Private Instance Methods
// ---------------------------------------------------------------------
NativeProcessLinux(::pid_t pid, int terminal_fd, NativeDelegate &delegate,
const ArchSpec &arch, MainLoop &mainloop,
llvm::ArrayRef<::pid_t> tids);
// Returns a list of process threads that we have attached to.
static llvm::Expected<std::vector<::pid_t>> Attach(::pid_t pid);
static Status SetDefaultPtraceOpts(const lldb::pid_t);
void MonitorCallback(lldb::pid_t pid, bool exited, WaitStatus status);
void WaitForNewThread(::pid_t tid);
void MonitorSIGTRAP(const siginfo_t &info, NativeThreadLinux &thread);
void MonitorTrace(NativeThreadLinux &thread);
void MonitorBreakpoint(NativeThreadLinux &thread);
void MonitorWatchpoint(NativeThreadLinux &thread, uint32_t wp_index);
void MonitorSignal(const siginfo_t &info, NativeThreadLinux &thread,
bool exited);
Status SetupSoftwareSingleStepping(NativeThreadLinux &thread);
#if 0
static ::ProcessMessage::CrashReason
GetCrashReasonForSIGSEGV(const siginfo_t *info);
static ::ProcessMessage::CrashReason
GetCrashReasonForSIGILL(const siginfo_t *info);
static ::ProcessMessage::CrashReason
GetCrashReasonForSIGFPE(const siginfo_t *info);
static ::ProcessMessage::CrashReason
GetCrashReasonForSIGBUS(const siginfo_t *info);
#endif
bool HasThreadNoLock(lldb::tid_t thread_id);
bool StopTrackingThread(lldb::tid_t thread_id);
NativeThreadLinux &AddThread(lldb::tid_t thread_id);
Status GetSoftwareBreakpointPCOffset(uint32_t &actual_opcode_size);
Status FixupBreakpointPCAsNeeded(NativeThreadLinux &thread);
/// Writes a siginfo_t structure corresponding to the given thread ID to the
/// memory region pointed to by @p siginfo.
Status GetSignalInfo(lldb::tid_t tid, void *siginfo);
/// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG)
/// corresponding to the given thread ID to the memory pointed to by @p
/// message.
Status GetEventMessage(lldb::tid_t tid, unsigned long *message);
void NotifyThreadDeath(lldb::tid_t tid);
Status Detach(lldb::tid_t tid);
// This method is requests a stop on all threads which are still running. It
// sets up a
// deferred delegate notification, which will fire once threads report as
// stopped. The
// triggerring_tid will be set as the current thread (main stop reason).
void StopRunningThreads(lldb::tid_t triggering_tid);
// Notify the delegate if all threads have stopped.
void SignalIfAllThreadsStopped();
// Resume the given thread, optionally passing it the given signal. The type
// of resume
// operation (continue, single-step) depends on the state parameter.
Status ResumeThread(NativeThreadLinux &thread, lldb::StateType state,
int signo);
void ThreadWasCreated(NativeThreadLinux &thread);
void SigchldHandler();
Status PopulateMemoryRegionCache();
lldb::user_id_t StartTraceGroup(const TraceOptions &config,
Status &error);
// This function is intended to be used to stop tracing
// on a thread that exited.
Status StopTracingForThread(lldb::tid_t thread);
// The below function as the name suggests, looks up a ProcessorTrace
// instance from the m_processor_trace_monitor map. In the case of
// process tracing where the traceid passed would map to the complete
// process, it is mandatory to provide a threadid to obtain a trace
// instance (since ProcessorTrace is tied to a thread). In the other
// scenario that an individual thread is being traced, just the traceid
// is sufficient to obtain the actual ProcessorTrace instance.
llvm::Expected<ProcessorTraceMonitor &>
LookupProcessorTraceInstance(lldb::user_id_t traceid, lldb::tid_t thread);
// Stops tracing on individual threads being traced. Not intended
// to be used to stop tracing on complete process.
Status StopProcessorTracingOnThread(lldb::user_id_t traceid,
lldb::tid_t thread);
// Intended to stop tracing on complete process.
// Should not be used for stopping trace on
// individual threads.
void StopProcessorTracingOnProcess();
llvm::DenseMap<lldb::tid_t, ProcessorTraceMonitorUP>
m_processor_trace_monitor;
// Set for tracking threads being traced under
// same process user id.
llvm::DenseSet<lldb::tid_t> m_pt_traced_thread_group;
lldb::user_id_t m_pt_proces_trace_id = LLDB_INVALID_UID;
TraceOptions m_pt_process_trace_config;
};
} // namespace process_linux
} // namespace lldb_private
#endif // #ifndef liblldb_NativeProcessLinux_H_

View File

@@ -0,0 +1,196 @@
//===-- NativeRegisterContextLinux.cpp --------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "NativeRegisterContextLinux.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Host/common/NativeProcessProtocol.h"
#include "lldb/Host/common/NativeThreadProtocol.h"
#include "lldb/Host/linux/Ptrace.h"
#include "Plugins/Process/Linux/NativeProcessLinux.h"
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
using namespace lldb_private;
using namespace lldb_private::process_linux;
NativeRegisterContextLinux::NativeRegisterContextLinux(
NativeThreadProtocol &native_thread,
RegisterInfoInterface *reg_info_interface_p)
: NativeRegisterContextRegisterInfo(native_thread, reg_info_interface_p) {}
lldb::ByteOrder NativeRegisterContextLinux::GetByteOrder() const {
return m_thread.GetProcess().GetByteOrder();
}
Status NativeRegisterContextLinux::ReadRegisterRaw(uint32_t reg_index,
RegisterValue &reg_value) {
const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index);
if (!reg_info)
return Status("register %" PRIu32 " not found", reg_index);
return DoReadRegisterValue(reg_info->byte_offset, reg_info->name,
reg_info->byte_size, reg_value);
}
Status
NativeRegisterContextLinux::WriteRegisterRaw(uint32_t reg_index,
const RegisterValue &reg_value) {
uint32_t reg_to_write = reg_index;
RegisterValue value_to_write = reg_value;
// Check if this is a subregister of a full register.
const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index);
if (reg_info->invalidate_regs &&
(reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) {
Status error;
RegisterValue full_value;
uint32_t full_reg = reg_info->invalidate_regs[0];
const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
// Read the full register.
error = ReadRegister(full_reg_info, full_value);
if (error.Fail())
return error;
lldb::ByteOrder byte_order = GetByteOrder();
uint8_t dst[RegisterValue::kMaxRegisterByteSize];
// Get the bytes for the full register.
const uint32_t dest_size = full_value.GetAsMemoryData(
full_reg_info, dst, sizeof(dst), byte_order, error);
if (error.Success() && dest_size) {
uint8_t src[RegisterValue::kMaxRegisterByteSize];
// Get the bytes for the source data.
const uint32_t src_size = reg_value.GetAsMemoryData(
reg_info, src, sizeof(src), byte_order, error);
if (error.Success() && src_size && (src_size < dest_size)) {
// Copy the src bytes to the destination.
memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size);
// Set this full register as the value to write.
value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
value_to_write.SetType(full_reg_info);
reg_to_write = full_reg;
}
}
}
const RegisterInfo *const register_to_write_info_p =
GetRegisterInfoAtIndex(reg_to_write);
assert(register_to_write_info_p &&
"register to write does not have valid RegisterInfo");
if (!register_to_write_info_p)
return Status("NativeRegisterContextLinux::%s failed to get RegisterInfo "
"for write register index %" PRIu32,
__FUNCTION__, reg_to_write);
return DoWriteRegisterValue(reg_info->byte_offset, reg_info->name, reg_value);
}
Status NativeRegisterContextLinux::ReadGPR() {
void *buf = GetGPRBuffer();
if (!buf)
return Status("GPR buffer is NULL");
size_t buf_size = GetGPRSize();
return DoReadGPR(buf, buf_size);
}
Status NativeRegisterContextLinux::WriteGPR() {
void *buf = GetGPRBuffer();
if (!buf)
return Status("GPR buffer is NULL");
size_t buf_size = GetGPRSize();
return DoWriteGPR(buf, buf_size);
}
Status NativeRegisterContextLinux::ReadFPR() {
void *buf = GetFPRBuffer();
if (!buf)
return Status("FPR buffer is NULL");
size_t buf_size = GetFPRSize();
return DoReadFPR(buf, buf_size);
}
Status NativeRegisterContextLinux::WriteFPR() {
void *buf = GetFPRBuffer();
if (!buf)
return Status("FPR buffer is NULL");
size_t buf_size = GetFPRSize();
return DoWriteFPR(buf, buf_size);
}
Status NativeRegisterContextLinux::ReadRegisterSet(void *buf, size_t buf_size,
unsigned int regset) {
return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(),
static_cast<void *>(&regset), buf,
buf_size);
}
Status NativeRegisterContextLinux::WriteRegisterSet(void *buf, size_t buf_size,
unsigned int regset) {
return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
static_cast<void *>(&regset), buf,
buf_size);
}
Status NativeRegisterContextLinux::DoReadRegisterValue(uint32_t offset,
const char *reg_name,
uint32_t size,
RegisterValue &value) {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS));
long data;
Status error = NativeProcessLinux::PtraceWrapper(
PTRACE_PEEKUSER, m_thread.GetID(), reinterpret_cast<void *>(offset),
nullptr, 0, &data);
if (error.Success())
// First cast to an unsigned of the same size to avoid sign extension.
value.SetUInt(static_cast<unsigned long>(data), size);
LLDB_LOG(log, "{0}: {1:x}", reg_name, data);
return error;
}
Status NativeRegisterContextLinux::DoWriteRegisterValue(
uint32_t offset, const char *reg_name, const RegisterValue &value) {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS));
void *buf = reinterpret_cast<void *>(value.GetAsUInt64());
LLDB_LOG(log, "{0}: {1}", reg_name, buf);
return NativeProcessLinux::PtraceWrapper(
PTRACE_POKEUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), buf);
}
Status NativeRegisterContextLinux::DoReadGPR(void *buf, size_t buf_size) {
return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(),
nullptr, buf, buf_size);
}
Status NativeRegisterContextLinux::DoWriteGPR(void *buf, size_t buf_size) {
return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_thread.GetID(),
nullptr, buf, buf_size);
}
Status NativeRegisterContextLinux::DoReadFPR(void *buf, size_t buf_size) {
return NativeProcessLinux::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(),
nullptr, buf, buf_size);
}
Status NativeRegisterContextLinux::DoWriteFPR(void *buf, size_t buf_size) {
return NativeProcessLinux::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(),
nullptr, buf, buf_size);
}

View File

@@ -0,0 +1,85 @@
//===-- NativeRegisterContextLinux.h ----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef lldb_NativeRegisterContextLinux_h
#define lldb_NativeRegisterContextLinux_h
#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
#include "lldb/Host/common/NativeThreadProtocol.h"
namespace lldb_private {
namespace process_linux {
class NativeRegisterContextLinux : public NativeRegisterContextRegisterInfo {
public:
NativeRegisterContextLinux(NativeThreadProtocol &native_thread,
RegisterInfoInterface *reg_info_interface_p);
// This function is implemented in the NativeRegisterContextLinux_* subclasses
// to create a new instance of the host specific NativeRegisterContextLinux.
// The implementations can't collide as only one NativeRegisterContextLinux_*
// variant should be compiled into the final executable.
static std::unique_ptr<NativeRegisterContextLinux>
CreateHostNativeRegisterContextLinux(const ArchSpec &target_arch,
NativeThreadProtocol &native_thread);
protected:
lldb::ByteOrder GetByteOrder() const;
virtual Status ReadRegisterRaw(uint32_t reg_index, RegisterValue &reg_value);
virtual Status WriteRegisterRaw(uint32_t reg_index,
const RegisterValue &reg_value);
virtual Status ReadRegisterSet(void *buf, size_t buf_size,
unsigned int regset);
virtual Status WriteRegisterSet(void *buf, size_t buf_size,
unsigned int regset);
virtual Status ReadGPR();
virtual Status WriteGPR();
virtual Status ReadFPR();
virtual Status WriteFPR();
virtual void *GetGPRBuffer() { return nullptr; }
virtual size_t GetGPRSize() {
return GetRegisterInfoInterface().GetGPRSize();
}
virtual void *GetFPRBuffer() { return nullptr; }
virtual size_t GetFPRSize() { return 0; }
// The Do*** functions are executed on the privileged thread and can perform
// ptrace
// operations directly.
virtual Status DoReadRegisterValue(uint32_t offset, const char *reg_name,
uint32_t size, RegisterValue &value);
virtual Status DoWriteRegisterValue(uint32_t offset, const char *reg_name,
const RegisterValue &value);
virtual Status DoReadGPR(void *buf, size_t buf_size);
virtual Status DoWriteGPR(void *buf, size_t buf_size);
virtual Status DoReadFPR(void *buf, size_t buf_size);
virtual Status DoWriteFPR(void *buf, size_t buf_size);
};
} // namespace process_linux
} // namespace lldb_private
#endif // #ifndef lldb_NativeRegisterContextLinux_h

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,169 @@
//===-- NativeRegisterContextLinux_arm.h ---------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
#ifndef lldb_NativeRegisterContextLinux_arm_h
#define lldb_NativeRegisterContextLinux_arm_h
#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
#include "Plugins/Process/Utility/lldb-arm-register-enums.h"
namespace lldb_private {
namespace process_linux {
class NativeProcessLinux;
class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux {
public:
NativeRegisterContextLinux_arm(const ArchSpec &target_arch,
NativeThreadProtocol &native_thread);
uint32_t GetRegisterSetCount() const override;
const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
uint32_t GetUserRegisterCount() const override;
Status ReadRegister(const RegisterInfo *reg_info,
RegisterValue &reg_value) override;
Status WriteRegister(const RegisterInfo *reg_info,
const RegisterValue &reg_value) override;
Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
//------------------------------------------------------------------
// Hardware breakpoints/watchpoint mangement functions
//------------------------------------------------------------------
uint32_t NumSupportedHardwareBreakpoints() override;
uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
bool ClearHardwareBreakpoint(uint32_t hw_idx) override;
Status ClearAllHardwareBreakpoints() override;
Status GetHardwareBreakHitIndex(uint32_t &bp_index,
lldb::addr_t trap_addr) override;
uint32_t NumSupportedHardwareWatchpoints() override;
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
uint32_t watch_flags) override;
bool ClearHardwareWatchpoint(uint32_t hw_index) override;
Status ClearAllHardwareWatchpoints() override;
Status GetWatchpointHitIndex(uint32_t &wp_index,
lldb::addr_t trap_addr) override;
lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override;
lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
uint32_t GetWatchpointSize(uint32_t wp_index);
bool WatchpointIsEnabled(uint32_t wp_index);
// Debug register type select
enum DREGType { eDREGTypeWATCH = 0, eDREGTypeBREAK };
protected:
Status DoReadRegisterValue(uint32_t offset, const char *reg_name,
uint32_t size, RegisterValue &value) override;
Status DoWriteRegisterValue(uint32_t offset, const char *reg_name,
const RegisterValue &value) override;
Status DoReadGPR(void *buf, size_t buf_size) override;
Status DoWriteGPR(void *buf, size_t buf_size) override;
Status DoReadFPR(void *buf, size_t buf_size) override;
Status DoWriteFPR(void *buf, size_t buf_size) override;
void *GetGPRBuffer() override { return &m_gpr_arm; }
void *GetFPRBuffer() override { return &m_fpr; }
size_t GetFPRSize() override { return sizeof(m_fpr); }
private:
struct RegInfo {
uint32_t num_registers;
uint32_t num_gpr_registers;
uint32_t num_fpr_registers;
uint32_t last_gpr;
uint32_t first_fpr;
uint32_t last_fpr;
uint32_t first_fpr_v;
uint32_t last_fpr_v;
uint32_t gpr_flags;
};
struct QReg {
uint8_t bytes[16];
};
struct FPU {
union {
uint32_t s[32];
uint64_t d[32];
QReg q[16]; // the 128-bit NEON registers
} floats;
uint32_t fpscr;
};
uint32_t m_gpr_arm[k_num_gpr_registers_arm];
RegInfo m_reg_info;
FPU m_fpr;
// Debug register info for hardware breakpoints and watchpoints management.
struct DREG {
lldb::addr_t address; // Breakpoint/watchpoint address value.
lldb::addr_t hit_addr; // Address at which last watchpoint trigger exception
// occurred.
lldb::addr_t real_addr; // Address value that should cause target to stop.
uint32_t control; // Breakpoint/watchpoint control value.
uint32_t refcount; // Serves as enable/disable and refernce counter.
};
struct DREG m_hbr_regs[16]; // Arm native linux hardware breakpoints
struct DREG m_hwp_regs[16]; // Arm native linux hardware watchpoints
uint32_t m_max_hwp_supported;
uint32_t m_max_hbp_supported;
bool m_refresh_hwdebug_info;
bool IsGPR(unsigned reg) const;
bool IsFPR(unsigned reg) const;
Status ReadHardwareDebugInfo();
Status WriteHardwareDebugRegs(int hwbType, int hwb_index);
uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const;
};
} // namespace process_linux
} // namespace lldb_private
#endif // #ifndef lldb_NativeRegisterContextLinux_arm_h
#endif // defined(__arm__) || defined(__arm64__) || defined(__aarch64__)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,169 @@
//===-- NativeRegisterContextLinux_arm64.h ---------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#if defined(__arm64__) || defined(__aarch64__)
#ifndef lldb_NativeRegisterContextLinux_arm64_h
#define lldb_NativeRegisterContextLinux_arm64_h
#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
#include "Plugins/Process/Utility/lldb-arm64-register-enums.h"
namespace lldb_private {
namespace process_linux {
class NativeProcessLinux;
class NativeRegisterContextLinux_arm64 : public NativeRegisterContextLinux {
public:
NativeRegisterContextLinux_arm64(const ArchSpec &target_arch,
NativeThreadProtocol &native_thread);
uint32_t GetRegisterSetCount() const override;
uint32_t GetUserRegisterCount() const override;
const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
Status ReadRegister(const RegisterInfo *reg_info,
RegisterValue &reg_value) override;
Status WriteRegister(const RegisterInfo *reg_info,
const RegisterValue &reg_value) override;
Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
//------------------------------------------------------------------
// Hardware breakpoints/watchpoint mangement functions
//------------------------------------------------------------------
uint32_t NumSupportedHardwareBreakpoints() override;
uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
bool ClearHardwareBreakpoint(uint32_t hw_idx) override;
Status ClearAllHardwareBreakpoints() override;
Status GetHardwareBreakHitIndex(uint32_t &bp_index,
lldb::addr_t trap_addr) override;
uint32_t NumSupportedHardwareWatchpoints() override;
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
uint32_t watch_flags) override;
bool ClearHardwareWatchpoint(uint32_t hw_index) override;
Status ClearAllHardwareWatchpoints() override;
Status GetWatchpointHitIndex(uint32_t &wp_index,
lldb::addr_t trap_addr) override;
lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override;
lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
uint32_t GetWatchpointSize(uint32_t wp_index);
bool WatchpointIsEnabled(uint32_t wp_index);
// Debug register type select
enum DREGType { eDREGTypeWATCH = 0, eDREGTypeBREAK };
protected:
Status DoReadRegisterValue(uint32_t offset, const char *reg_name,
uint32_t size, RegisterValue &value) override;
Status DoWriteRegisterValue(uint32_t offset, const char *reg_name,
const RegisterValue &value) override;
Status DoReadGPR(void *buf, size_t buf_size) override;
Status DoWriteGPR(void *buf, size_t buf_size) override;
Status DoReadFPR(void *buf, size_t buf_size) override;
Status DoWriteFPR(void *buf, size_t buf_size) override;
void *GetGPRBuffer() override { return &m_gpr_arm64; }
void *GetFPRBuffer() override { return &m_fpr; }
size_t GetFPRSize() override { return sizeof(m_fpr); }
private:
struct RegInfo {
uint32_t num_registers;
uint32_t num_gpr_registers;
uint32_t num_fpr_registers;
uint32_t last_gpr;
uint32_t first_fpr;
uint32_t last_fpr;
uint32_t first_fpr_v;
uint32_t last_fpr_v;
uint32_t gpr_flags;
};
// based on RegisterContextDarwin_arm64.h
struct VReg {
uint8_t bytes[16];
};
// based on RegisterContextDarwin_arm64.h
struct FPU {
VReg v[32];
uint32_t fpsr;
uint32_t fpcr;
};
uint64_t m_gpr_arm64[k_num_gpr_registers_arm64]; // 64-bit general purpose
// registers.
RegInfo m_reg_info;
FPU m_fpr; // floating-point registers including extended register sets.
// Debug register info for hardware breakpoints and watchpoints management.
struct DREG {
lldb::addr_t address; // Breakpoint/watchpoint address value.
lldb::addr_t hit_addr; // Address at which last watchpoint trigger exception
// occurred.
lldb::addr_t real_addr; // Address value that should cause target to stop.
uint32_t control; // Breakpoint/watchpoint control value.
uint32_t refcount; // Serves as enable/disable and refernce counter.
};
struct DREG m_hbr_regs[16]; // Arm native linux hardware breakpoints
struct DREG m_hwp_regs[16]; // Arm native linux hardware watchpoints
uint32_t m_max_hwp_supported;
uint32_t m_max_hbp_supported;
bool m_refresh_hwdebug_info;
bool IsGPR(unsigned reg) const;
bool IsFPR(unsigned reg) const;
Status ReadHardwareDebugInfo();
Status WriteHardwareDebugRegs(int hwbType);
uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const;
};
} // namespace process_linux
} // namespace lldb_private
#endif // #ifndef lldb_NativeRegisterContextLinux_arm64_h
#endif // defined (__arm64__) || defined (__aarch64__)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,140 @@
//===-- NativeRegisterContextLinux_mips64.h ---------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#if defined(__mips__)
#ifndef lldb_NativeRegisterContextLinux_mips64_h
#define lldb_NativeRegisterContextLinux_mips64_h
#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
#include "Plugins/Process/Utility/RegisterContext_mips.h"
#include "Plugins/Process/Utility/lldb-mips-linux-register-enums.h"
#include <sys/uio.h>
#define MAX_NUM_WP 8
namespace lldb_private {
namespace process_linux {
class NativeProcessLinux;
class NativeRegisterContextLinux_mips64 : public NativeRegisterContextLinux {
public:
NativeRegisterContextLinux_mips64(const ArchSpec &target_arch,
NativeThreadProtocol &native_thread);
uint32_t GetRegisterSetCount() const override;
lldb::addr_t GetPCfromBreakpointLocation(
lldb::addr_t fail_value = LLDB_INVALID_ADDRESS) override;
lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override;
const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
Status ReadRegister(const RegisterInfo *reg_info,
RegisterValue &reg_value) override;
Status WriteRegister(const RegisterInfo *reg_info,
const RegisterValue &reg_value) override;
Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
Status ReadCP1();
Status WriteCP1();
uint8_t *ReturnFPOffset(uint8_t reg_index, uint32_t byte_offset);
Status IsWatchpointHit(uint32_t wp_index, bool &is_hit) override;
Status GetWatchpointHitIndex(uint32_t &wp_index,
lldb::addr_t trap_addr) override;
Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override;
bool ClearHardwareWatchpoint(uint32_t wp_index) override;
Status ClearAllHardwareWatchpoints() override;
Status SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size,
uint32_t watch_flags,
uint32_t wp_index);
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
uint32_t watch_flags) override;
lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
uint32_t NumSupportedHardwareWatchpoints() override;
static bool IsMSAAvailable();
protected:
Status Read_SR_Config(uint32_t offset, const char *reg_name, uint32_t size,
RegisterValue &value);
Status ReadRegisterRaw(uint32_t reg_index, RegisterValue &value) override;
Status WriteRegisterRaw(uint32_t reg_index,
const RegisterValue &value) override;
Status DoReadWatchPointRegisterValue(lldb::tid_t tid, void *watch_readback);
Status DoWriteWatchPointRegisterValue(lldb::tid_t tid, void *watch_readback);
bool IsFR0();
bool IsFRE();
bool IsFPR(uint32_t reg_index) const;
bool IsMSA(uint32_t reg_index) const;
void *GetGPRBuffer() override { return &m_gpr; }
void *GetFPRBuffer() override { return &m_fpr; }
size_t GetFPRSize() override { return sizeof(FPR_linux_mips); }
private:
// Info about register ranges.
struct RegInfo {
uint32_t num_registers;
uint32_t num_gpr_registers;
uint32_t num_fpr_registers;
uint32_t last_gpr;
uint32_t first_fpr;
uint32_t last_fpr;
uint32_t first_msa;
uint32_t last_msa;
};
RegInfo m_reg_info;
GPR_linux_mips m_gpr;
FPR_linux_mips m_fpr;
MSA_linux_mips m_msa;
lldb::addr_t hw_addr_map[MAX_NUM_WP];
struct iovec m_iovec;
};
} // namespace process_linux
} // namespace lldb_private
#endif // #ifndef lldb_NativeRegisterContextLinux_mips64_h
#endif // defined (__mips__)

View File

@@ -0,0 +1,149 @@
//===-- NativeRegisterContextLinux_ppc64le.h --------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// This implementation is related to the OpenPOWER ABI for Power Architecture
// 64-bit ELF V2 ABI
#if defined(__powerpc64__)
#ifndef lldb_NativeRegisterContextLinux_ppc64le_h
#define lldb_NativeRegisterContextLinux_ppc64le_h
#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h"
#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT
#include "RegisterInfos_ppc64le.h"
#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT
namespace lldb_private {
namespace process_linux {
class NativeProcessLinux;
class NativeRegisterContextLinux_ppc64le : public NativeRegisterContextLinux {
public:
NativeRegisterContextLinux_ppc64le(const ArchSpec &target_arch,
NativeThreadProtocol &native_thread);
uint32_t GetRegisterSetCount() const override;
uint32_t GetUserRegisterCount() const override;
const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
Status ReadRegister(const RegisterInfo *reg_info,
RegisterValue &reg_value) override;
Status WriteRegister(const RegisterInfo *reg_info,
const RegisterValue &reg_value) override;
Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
//------------------------------------------------------------------
// Hardware watchpoint mangement functions
//------------------------------------------------------------------
uint32_t NumSupportedHardwareWatchpoints() override;
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
uint32_t watch_flags) override;
bool ClearHardwareWatchpoint(uint32_t hw_index) override;
Status GetWatchpointHitIndex(uint32_t &wp_index,
lldb::addr_t trap_addr) override;
lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override;
lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
uint32_t GetWatchpointSize(uint32_t wp_index);
bool WatchpointIsEnabled(uint32_t wp_index);
protected:
Status DoReadGPR(void *buf, size_t buf_size) override;
Status DoWriteGPR(void *buf, size_t buf_size) override;
Status DoReadFPR(void *buf, size_t buf_size) override;
Status DoWriteFPR(void *buf, size_t buf_size) override;
bool IsVMX(unsigned reg);
bool IsVSX(unsigned reg);
Status ReadVMX();
Status WriteVMX();
Status ReadVSX();
Status WriteVSX();
void *GetGPRBuffer() override { return &m_gpr_ppc64le; }
void *GetFPRBuffer() override { return &m_fpr_ppc64le; }
size_t GetFPRSize() override { return sizeof(m_fpr_ppc64le); }
private:
GPR m_gpr_ppc64le; // 64-bit general purpose registers.
FPR m_fpr_ppc64le; // floating-point registers including extended register.
VMX m_vmx_ppc64le; // VMX registers.
VSX m_vsx_ppc64le; // Last lower bytes from first VSX registers.
bool IsGPR(unsigned reg) const;
bool IsFPR(unsigned reg) const;
bool IsVMX(unsigned reg) const;
bool IsVSX(unsigned reg) const;
uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const;
uint32_t CalculateVmxOffset(const RegisterInfo *reg_info) const;
uint32_t CalculateVsxOffset(const RegisterInfo *reg_info) const;
Status ReadHardwareDebugInfo();
Status WriteHardwareDebugRegs();
// Debug register info for hardware watchpoints management.
struct DREG {
lldb::addr_t address; // Breakpoint/watchpoint address value.
lldb::addr_t hit_addr; // Address at which last watchpoint trigger
// exception occurred.
lldb::addr_t real_addr; // Address value that should cause target to stop.
uint32_t control; // Breakpoint/watchpoint control value.
uint32_t refcount; // Serves as enable/disable and reference counter.
long slot; // Saves the value returned from PTRACE_SETHWDEBUG.
int mode; // Defines if watchpoint is read/write/access.
};
std::array<DREG, 4> m_hwp_regs;
// 16 is just a maximum value, query hardware for actual watchpoint count
uint32_t m_max_hwp_supported = 16;
uint32_t m_max_hbp_supported = 16;
bool m_refresh_hwdebug_info = true;
};
} // namespace process_linux
} // namespace lldb_private
#endif // #ifndef lldb_NativeRegisterContextLinux_ppc64le_h
#endif // defined(__powerpc64__)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,115 @@
//===-- NativeRegisterContextLinux_s390x.h ----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#if defined(__s390x__) && defined(__linux__)
#ifndef lldb_NativeRegisterContextLinux_s390x_h
#define lldb_NativeRegisterContextLinux_s390x_h
#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
#include "Plugins/Process/Utility/RegisterContext_s390x.h"
#include "Plugins/Process/Utility/lldb-s390x-register-enums.h"
namespace lldb_private {
namespace process_linux {
class NativeProcessLinux;
class NativeRegisterContextLinux_s390x : public NativeRegisterContextLinux {
public:
NativeRegisterContextLinux_s390x(const ArchSpec &target_arch,
NativeThreadProtocol &native_thread);
uint32_t GetRegisterSetCount() const override;
const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
uint32_t GetUserRegisterCount() const override;
Status ReadRegister(const RegisterInfo *reg_info,
RegisterValue &reg_value) override;
Status WriteRegister(const RegisterInfo *reg_info,
const RegisterValue &reg_value) override;
Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
Status IsWatchpointHit(uint32_t wp_index, bool &is_hit) override;
Status GetWatchpointHitIndex(uint32_t &wp_index,
lldb::addr_t trap_addr) override;
Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override;
bool ClearHardwareWatchpoint(uint32_t wp_index) override;
Status ClearAllHardwareWatchpoints() override;
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
uint32_t watch_flags) override;
lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
uint32_t NumSupportedHardwareWatchpoints() override;
protected:
Status DoReadRegisterValue(uint32_t offset, const char *reg_name,
uint32_t size, RegisterValue &value) override;
Status DoWriteRegisterValue(uint32_t offset, const char *reg_name,
const RegisterValue &value) override;
Status DoReadGPR(void *buf, size_t buf_size) override;
Status DoWriteGPR(void *buf, size_t buf_size) override;
Status DoReadFPR(void *buf, size_t buf_size) override;
Status DoWriteFPR(void *buf, size_t buf_size) override;
private:
// Info about register ranges.
struct RegInfo {
uint32_t num_registers;
uint32_t num_gpr_registers;
uint32_t num_fpr_registers;
uint32_t last_gpr;
uint32_t first_fpr;
uint32_t last_fpr;
};
// Private member variables.
RegInfo m_reg_info;
lldb::addr_t m_watchpoint_addr;
// Private member methods.
bool IsRegisterSetAvailable(uint32_t set_index) const;
bool IsGPR(uint32_t reg_index) const;
bool IsFPR(uint32_t reg_index) const;
Status PeekUserArea(uint32_t offset, void *buf, size_t buf_size);
Status PokeUserArea(uint32_t offset, const void *buf, size_t buf_size);
Status DoReadRegisterSet(uint32_t regset, void *buf, size_t buf_size);
Status DoWriteRegisterSet(uint32_t regset, const void *buf, size_t buf_size);
};
} // namespace process_linux
} // namespace lldb_private
#endif // #ifndef lldb_NativeRegisterContextLinux_s390x_h
#endif // defined(__s390x__) && defined(__linux__)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,149 @@
//===-- NativeRegisterContextLinux_x86_64.h ---------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#if defined(__i386__) || defined(__x86_64__)
#ifndef lldb_NativeRegisterContextLinux_x86_64_h
#define lldb_NativeRegisterContextLinux_x86_64_h
#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
#include "Plugins/Process/Utility/RegisterContext_x86.h"
#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
#include <sys/uio.h>
namespace lldb_private {
namespace process_linux {
class NativeProcessLinux;
class NativeRegisterContextLinux_x86_64 : public NativeRegisterContextLinux {
public:
NativeRegisterContextLinux_x86_64(const ArchSpec &target_arch,
NativeThreadProtocol &native_thread);
uint32_t GetRegisterSetCount() const override;
const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
uint32_t GetUserRegisterCount() const override;
Status ReadRegister(const RegisterInfo *reg_info,
RegisterValue &reg_value) override;
Status WriteRegister(const RegisterInfo *reg_info,
const RegisterValue &reg_value) override;
Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
Status IsWatchpointHit(uint32_t wp_index, bool &is_hit) override;
Status GetWatchpointHitIndex(uint32_t &wp_index,
lldb::addr_t trap_addr) override;
Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override;
bool ClearHardwareWatchpoint(uint32_t wp_index) override;
Status ClearAllHardwareWatchpoints() override;
Status SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size,
uint32_t watch_flags,
uint32_t wp_index);
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
uint32_t watch_flags) override;
lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
uint32_t NumSupportedHardwareWatchpoints() override;
protected:
void *GetGPRBuffer() override { return &m_gpr_x86_64; }
void *GetFPRBuffer() override;
size_t GetFPRSize() override;
Status ReadFPR() override;
Status WriteFPR() override;
private:
// Private member types.
enum class XStateType { Invalid, FXSAVE, XSAVE };
enum class RegSet { gpr, fpu, avx, mpx };
// Info about register ranges.
struct RegInfo {
uint32_t num_registers;
uint32_t num_gpr_registers;
uint32_t num_fpr_registers;
uint32_t num_avx_registers;
uint32_t num_mpx_registers;
uint32_t last_gpr;
uint32_t first_fpr;
uint32_t last_fpr;
uint32_t first_st;
uint32_t last_st;
uint32_t first_mm;
uint32_t last_mm;
uint32_t first_xmm;
uint32_t last_xmm;
uint32_t first_ymm;
uint32_t last_ymm;
uint32_t first_mpxr;
uint32_t last_mpxr;
uint32_t first_mpxc;
uint32_t last_mpxc;
uint32_t first_dr;
uint32_t gpr_flags;
};
// Private member variables.
mutable XStateType m_xstate_type;
FPR m_fpr; // Extended States Area, named FPR for historical reasons.
struct iovec m_iovec;
YMM m_ymm_set;
MPX m_mpx_set;
RegInfo m_reg_info;
uint64_t m_gpr_x86_64[k_num_gpr_registers_x86_64];
uint32_t m_fctrl_offset_in_userarea;
// Private member methods.
bool IsCPUFeatureAvailable(RegSet feature_code) const;
bool IsRegisterSetAvailable(uint32_t set_index) const;
bool IsGPR(uint32_t reg_index) const;
bool IsFPR(uint32_t reg_index) const;
bool CopyXSTATEtoYMM(uint32_t reg_index, lldb::ByteOrder byte_order);
bool CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order);
bool IsAVX(uint32_t reg_index) const;
bool CopyXSTATEtoMPX(uint32_t reg);
bool CopyMPXtoXSTATE(uint32_t reg);
bool IsMPX(uint32_t reg_index) const;
void UpdateXSTATEforWrite(uint32_t reg_index);
};
} // namespace process_linux
} // namespace lldb_private
#endif // #ifndef lldb_NativeRegisterContextLinux_x86_64_h
#endif // defined(__i386__) || defined(__x86_64__)

View File

@@ -0,0 +1,451 @@
//===-- NativeThreadLinux.cpp --------------------------------- -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "NativeThreadLinux.h"
#include <signal.h>
#include <sstream>
#include "NativeProcessLinux.h"
#include "NativeRegisterContextLinux.h"
#include "SingleStepCheck.h"
#include "lldb/Core/State.h"
#include "lldb/Host/HostNativeThread.h"
#include "lldb/Host/linux/Ptrace.h"
#include "lldb/Host/linux/Support.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/Log.h"
#include "lldb/lldb-enumerations.h"
#include "llvm/ADT/SmallString.h"
#include "Plugins/Process/POSIX/CrashReason.h"
#include <sys/syscall.h>
// Try to define a macro to encapsulate the tgkill syscall
#define tgkill(pid, tid, sig) \
syscall(__NR_tgkill, static_cast<::pid_t>(pid), static_cast<::pid_t>(tid), \
sig)
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_linux;
namespace {
void LogThreadStopInfo(Log &log, const ThreadStopInfo &stop_info,
const char *const header) {
switch (stop_info.reason) {
case eStopReasonNone:
log.Printf("%s: %s no stop reason", __FUNCTION__, header);
return;
case eStopReasonTrace:
log.Printf("%s: %s trace, stopping signal 0x%" PRIx32, __FUNCTION__, header,
stop_info.details.signal.signo);
return;
case eStopReasonBreakpoint:
log.Printf("%s: %s breakpoint, stopping signal 0x%" PRIx32, __FUNCTION__,
header, stop_info.details.signal.signo);
return;
case eStopReasonWatchpoint:
log.Printf("%s: %s watchpoint, stopping signal 0x%" PRIx32, __FUNCTION__,
header, stop_info.details.signal.signo);
return;
case eStopReasonSignal:
log.Printf("%s: %s signal 0x%02" PRIx32, __FUNCTION__, header,
stop_info.details.signal.signo);
return;
case eStopReasonException:
log.Printf("%s: %s exception type 0x%02" PRIx64, __FUNCTION__, header,
stop_info.details.exception.type);
return;
case eStopReasonExec:
log.Printf("%s: %s exec, stopping signal 0x%" PRIx32, __FUNCTION__, header,
stop_info.details.signal.signo);
return;
case eStopReasonPlanComplete:
log.Printf("%s: %s plan complete", __FUNCTION__, header);
return;
case eStopReasonThreadExiting:
log.Printf("%s: %s thread exiting", __FUNCTION__, header);
return;
case eStopReasonInstrumentation:
log.Printf("%s: %s instrumentation", __FUNCTION__, header);
return;
default:
log.Printf("%s: %s invalid stop reason %" PRIu32, __FUNCTION__, header,
static_cast<uint32_t>(stop_info.reason));
}
}
}
NativeThreadLinux::NativeThreadLinux(NativeProcessLinux &process,
lldb::tid_t tid)
: NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),
m_stop_info(),
m_reg_context_up(
NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
process.GetArchitecture(), *this)),
m_stop_description() {}
std::string NativeThreadLinux::GetName() {
NativeProcessLinux &process = GetProcess();
auto BufferOrError = getProcFile(process.GetID(), GetID(), "comm");
if (!BufferOrError)
return "";
return BufferOrError.get()->getBuffer().rtrim('\n');
}
lldb::StateType NativeThreadLinux::GetState() { return m_state; }
bool NativeThreadLinux::GetStopReason(ThreadStopInfo &stop_info,
std::string &description) {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
description.clear();
switch (m_state) {
case eStateStopped:
case eStateCrashed:
case eStateExited:
case eStateSuspended:
case eStateUnloaded:
if (log)
LogThreadStopInfo(*log, m_stop_info, "m_stop_info in thread:");
stop_info = m_stop_info;
description = m_stop_description;
if (log)
LogThreadStopInfo(*log, stop_info, "returned stop_info:");
return true;
case eStateInvalid:
case eStateConnected:
case eStateAttaching:
case eStateLaunching:
case eStateRunning:
case eStateStepping:
case eStateDetached:
if (log) {
log->Printf("NativeThreadLinux::%s tid %" PRIu64
" in state %s cannot answer stop reason",
__FUNCTION__, GetID(), StateAsCString(m_state));
}
return false;
}
llvm_unreachable("unhandled StateType!");
}
Status NativeThreadLinux::SetWatchpoint(lldb::addr_t addr, size_t size,
uint32_t watch_flags, bool hardware) {
if (!hardware)
return Status("not implemented");
if (m_state == eStateLaunching)
return Status();
Status error = RemoveWatchpoint(addr);
if (error.Fail())
return error;
uint32_t wp_index =
m_reg_context_up->SetHardwareWatchpoint(addr, size, watch_flags);
if (wp_index == LLDB_INVALID_INDEX32)
return Status("Setting hardware watchpoint failed.");
m_watchpoint_index_map.insert({addr, wp_index});
return Status();
}
Status NativeThreadLinux::RemoveWatchpoint(lldb::addr_t addr) {
auto wp = m_watchpoint_index_map.find(addr);
if (wp == m_watchpoint_index_map.end())
return Status();
uint32_t wp_index = wp->second;
m_watchpoint_index_map.erase(wp);
if (m_reg_context_up->ClearHardwareWatchpoint(wp_index))
return Status();
return Status("Clearing hardware watchpoint failed.");
}
Status NativeThreadLinux::SetHardwareBreakpoint(lldb::addr_t addr,
size_t size) {
if (m_state == eStateLaunching)
return Status();
Status error = RemoveHardwareBreakpoint(addr);
if (error.Fail())
return error;
uint32_t bp_index = m_reg_context_up->SetHardwareBreakpoint(addr, size);
if (bp_index == LLDB_INVALID_INDEX32)
return Status("Setting hardware breakpoint failed.");
m_hw_break_index_map.insert({addr, bp_index});
return Status();
}
Status NativeThreadLinux::RemoveHardwareBreakpoint(lldb::addr_t addr) {
auto bp = m_hw_break_index_map.find(addr);
if (bp == m_hw_break_index_map.end())
return Status();
uint32_t bp_index = bp->second;
if (m_reg_context_up->ClearHardwareBreakpoint(bp_index)) {
m_hw_break_index_map.erase(bp);
return Status();
}
return Status("Clearing hardware breakpoint failed.");
}
Status NativeThreadLinux::Resume(uint32_t signo) {
const StateType new_state = StateType::eStateRunning;
MaybeLogStateChange(new_state);
m_state = new_state;
m_stop_info.reason = StopReason::eStopReasonNone;
m_stop_description.clear();
// If watchpoints have been set, but none on this thread,
// then this is a new thread. So set all existing watchpoints.
if (m_watchpoint_index_map.empty()) {
NativeProcessLinux &process = GetProcess();
const auto &watchpoint_map = process.GetWatchpointMap();
m_reg_context_up->ClearAllHardwareWatchpoints();
for (const auto &pair : watchpoint_map) {
const auto &wp = pair.second;
SetWatchpoint(wp.m_addr, wp.m_size, wp.m_watch_flags, wp.m_hardware);
}
}
// Set all active hardware breakpoint on all threads.
if (m_hw_break_index_map.empty()) {
NativeProcessLinux &process = GetProcess();
const auto &hw_breakpoint_map = process.GetHardwareBreakpointMap();
m_reg_context_up->ClearAllHardwareBreakpoints();
for (const auto &pair : hw_breakpoint_map) {
const auto &bp = pair.second;
SetHardwareBreakpoint(bp.m_addr, bp.m_size);
}
}
intptr_t data = 0;
if (signo != LLDB_INVALID_SIGNAL_NUMBER)
data = signo;
return NativeProcessLinux::PtraceWrapper(PTRACE_CONT, GetID(), nullptr,
reinterpret_cast<void *>(data));
}
Status NativeThreadLinux::SingleStep(uint32_t signo) {
const StateType new_state = StateType::eStateStepping;
MaybeLogStateChange(new_state);
m_state = new_state;
m_stop_info.reason = StopReason::eStopReasonNone;
if(!m_step_workaround) {
// If we already hava a workaround inplace, don't reset it. Otherwise, the
// destructor of the existing instance will run after the new instance has
// fetched the cpu mask, and the thread will end up with the wrong mask.
m_step_workaround = SingleStepWorkaround::Get(m_tid);
}
intptr_t data = 0;
if (signo != LLDB_INVALID_SIGNAL_NUMBER)
data = signo;
// If hardware single-stepping is not supported, we just do a continue. The
// breakpoint on the
// next instruction has been setup in NativeProcessLinux::Resume.
return NativeProcessLinux::PtraceWrapper(
GetProcess().SupportHardwareSingleStepping() ? PTRACE_SINGLESTEP
: PTRACE_CONT,
m_tid, nullptr, reinterpret_cast<void *>(data));
}
void NativeThreadLinux::SetStoppedBySignal(uint32_t signo,
const siginfo_t *info) {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
if (log)
log->Printf("NativeThreadLinux::%s called with signal 0x%02" PRIx32,
__FUNCTION__, signo);
SetStopped();
m_stop_info.reason = StopReason::eStopReasonSignal;
m_stop_info.details.signal.signo = signo;
m_stop_description.clear();
if (info) {
switch (signo) {
case SIGSEGV:
case SIGBUS:
case SIGFPE:
case SIGILL:
// In case of MIPS64 target, SI_KERNEL is generated for invalid 64bit
// address.
const auto reason =
(info->si_signo == SIGBUS && info->si_code == SI_KERNEL)
? CrashReason::eInvalidAddress
: GetCrashReason(*info);
m_stop_description = GetCrashReasonString(reason, *info);
break;
}
}
}
bool NativeThreadLinux::IsStopped(int *signo) {
if (!StateIsStoppedState(m_state, false))
return false;
// If we are stopped by a signal, return the signo.
if (signo && m_state == StateType::eStateStopped &&
m_stop_info.reason == StopReason::eStopReasonSignal) {
*signo = m_stop_info.details.signal.signo;
}
// Regardless, we are stopped.
return true;
}
void NativeThreadLinux::SetStopped() {
if (m_state == StateType::eStateStepping)
m_step_workaround.reset();
const StateType new_state = StateType::eStateStopped;
MaybeLogStateChange(new_state);
m_state = new_state;
m_stop_description.clear();
}
void NativeThreadLinux::SetStoppedByExec() {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
if (log)
log->Printf("NativeThreadLinux::%s()", __FUNCTION__);
SetStopped();
m_stop_info.reason = StopReason::eStopReasonExec;
m_stop_info.details.signal.signo = SIGSTOP;
}
void NativeThreadLinux::SetStoppedByBreakpoint() {
SetStopped();
m_stop_info.reason = StopReason::eStopReasonBreakpoint;
m_stop_info.details.signal.signo = SIGTRAP;
m_stop_description.clear();
}
void NativeThreadLinux::SetStoppedByWatchpoint(uint32_t wp_index) {
SetStopped();
lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");
std::ostringstream ostr;
ostr << m_reg_context_up->GetWatchpointAddress(wp_index) << " ";
ostr << wp_index;
/*
* MIPS: Last 3bits of the watchpoint address are masked by the kernel. For
* example:
* 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is set at
* 'm', then
* watch exception is generated even when 'n' is read/written. To handle this
* case,
* find the base address of the load/store instruction and append it in the
* stop-info
* packet.
*/
ostr << " " << m_reg_context_up->GetWatchpointHitAddress(wp_index);
m_stop_description = ostr.str();
m_stop_info.reason = StopReason::eStopReasonWatchpoint;
m_stop_info.details.signal.signo = SIGTRAP;
}
bool NativeThreadLinux::IsStoppedAtBreakpoint() {
return GetState() == StateType::eStateStopped &&
m_stop_info.reason == StopReason::eStopReasonBreakpoint;
}
bool NativeThreadLinux::IsStoppedAtWatchpoint() {
return GetState() == StateType::eStateStopped &&
m_stop_info.reason == StopReason::eStopReasonWatchpoint;
}
void NativeThreadLinux::SetStoppedByTrace() {
SetStopped();
m_stop_info.reason = StopReason::eStopReasonTrace;
m_stop_info.details.signal.signo = SIGTRAP;
}
void NativeThreadLinux::SetStoppedWithNoReason() {
SetStopped();
m_stop_info.reason = StopReason::eStopReasonNone;
m_stop_info.details.signal.signo = 0;
}
void NativeThreadLinux::SetExited() {
const StateType new_state = StateType::eStateExited;
MaybeLogStateChange(new_state);
m_state = new_state;
m_stop_info.reason = StopReason::eStopReasonThreadExiting;
}
Status NativeThreadLinux::RequestStop() {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
NativeProcessLinux &process = GetProcess();
lldb::pid_t pid = process.GetID();
lldb::tid_t tid = GetID();
if (log)
log->Printf("NativeThreadLinux::%s requesting thread stop(pid: %" PRIu64
", tid: %" PRIu64 ")",
__FUNCTION__, pid, tid);
Status err;
errno = 0;
if (::tgkill(pid, tid, SIGSTOP) != 0) {
err.SetErrorToErrno();
if (log)
log->Printf("NativeThreadLinux::%s tgkill(%" PRIu64 ", %" PRIu64
", SIGSTOP) failed: %s",
__FUNCTION__, pid, tid, err.AsCString());
}
return err;
}
void NativeThreadLinux::MaybeLogStateChange(lldb::StateType new_state) {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
// If we're not logging, we're done.
if (!log)
return;
// If this is a state change to the same state, we're done.
lldb::StateType old_state = m_state;
if (new_state == old_state)
return;
LLDB_LOG(log, "pid={0}, tid={1}: changing from state {2} to {3}",
m_process.GetID(), GetID(), old_state, new_state);
}
NativeProcessLinux &NativeThreadLinux::GetProcess() {
return static_cast<NativeProcessLinux &>(m_process);
}

View File

@@ -0,0 +1,119 @@
//===-- NativeThreadLinux.h ----------------------------------- -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_NativeThreadLinux_H_
#define liblldb_NativeThreadLinux_H_
#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
#include "Plugins/Process/Linux/SingleStepCheck.h"
#include "lldb/Host/common/NativeThreadProtocol.h"
#include "lldb/lldb-private-forward.h"
#include <csignal>
#include <map>
#include <memory>
#include <string>
namespace lldb_private {
namespace process_linux {
class NativeProcessLinux;
class NativeThreadLinux : public NativeThreadProtocol {
friend class NativeProcessLinux;
public:
NativeThreadLinux(NativeProcessLinux &process, lldb::tid_t tid);
// ---------------------------------------------------------------------
// NativeThreadProtocol Interface
// ---------------------------------------------------------------------
std::string GetName() override;
lldb::StateType GetState() override;
bool GetStopReason(ThreadStopInfo &stop_info,
std::string &description) override;
NativeRegisterContextLinux &GetRegisterContext() override {
return *m_reg_context_up;
}
Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags,
bool hardware) override;
Status RemoveWatchpoint(lldb::addr_t addr) override;
Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
Status RemoveHardwareBreakpoint(lldb::addr_t addr) override;
private:
// ---------------------------------------------------------------------
// Interface for friend classes
// ---------------------------------------------------------------------
/// Resumes the thread. If @p signo is anything but
/// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
Status Resume(uint32_t signo);
/// Single steps the thread. If @p signo is anything but
/// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
Status SingleStep(uint32_t signo);
void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr);
/// Return true if the thread is stopped.
/// If stopped by a signal, indicate the signo in the signo argument.
/// Otherwise, return LLDB_INVALID_SIGNAL_NUMBER.
bool IsStopped(int *signo);
void SetStoppedByExec();
void SetStoppedByBreakpoint();
void SetStoppedByWatchpoint(uint32_t wp_index);
bool IsStoppedAtBreakpoint();
bool IsStoppedAtWatchpoint();
void SetStoppedByTrace();
void SetStoppedWithNoReason();
void SetExited();
Status RequestStop();
// ---------------------------------------------------------------------
// Private interface
// ---------------------------------------------------------------------
void MaybeLogStateChange(lldb::StateType new_state);
NativeProcessLinux &GetProcess();
void SetStopped();
// ---------------------------------------------------------------------
// Member Variables
// ---------------------------------------------------------------------
lldb::StateType m_state;
ThreadStopInfo m_stop_info;
std::unique_ptr<NativeRegisterContextLinux> m_reg_context_up;
std::string m_stop_description;
using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>;
WatchpointIndexMap m_watchpoint_index_map;
WatchpointIndexMap m_hw_break_index_map;
std::unique_ptr<SingleStepWorkaround> m_step_workaround;
};
} // namespace process_linux
} // namespace lldb_private
#endif // #ifndef liblldb_NativeThreadLinux_H_

View File

@@ -0,0 +1,395 @@
//===-- ProcessorTrace.cpp ------------------------------------ -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include <fstream>
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MathExtras.h"
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#include "ProcessorTrace.h"
#include "lldb/Host/linux/Support.h"
#include <sys/syscall.h>
using namespace lldb;
using namespace lldb_private;
using namespace process_linux;
using namespace llvm;
lldb::user_id_t ProcessorTraceMonitor::m_trace_num = 1;
Status ProcessorTraceMonitor::GetTraceConfig(TraceOptions &config) const {
#ifndef PERF_ATTR_SIZE_VER5
llvm_unreachable("perf event not supported");
#else
Status error;
config.setType(lldb::TraceType::eTraceTypeProcessorTrace);
config.setMetaDataBufferSize(m_mmap_meta->data_size);
config.setTraceBufferSize(m_mmap_meta->aux_size);
error = GetCPUType(config);
return error;
#endif
}
Status ProcessorTraceMonitor::StartTrace(lldb::pid_t pid, lldb::tid_t tid,
const TraceOptions &config) {
#ifndef PERF_ATTR_SIZE_VER5
llvm_unreachable("perf event not supported");
#else
Status error;
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
LLDB_LOG(log, "called thread id {0}", tid);
uint64_t page_size = getpagesize();
uint64_t bufsize = config.getTraceBufferSize();
uint64_t metabufsize = config.getMetaDataBufferSize();
uint64_t numpages = static_cast<uint64_t>(
llvm::PowerOf2Floor((bufsize + page_size - 1) / page_size));
numpages = std::max<uint64_t>(1, numpages);
bufsize = page_size * numpages;
numpages = static_cast<uint64_t>(
llvm::PowerOf2Floor((metabufsize + page_size - 1) / page_size));
metabufsize = page_size * numpages;
perf_event_attr attr;
memset(&attr, 0, sizeof(attr));
attr.size = sizeof(attr);
attr.exclude_kernel = 1;
attr.sample_type = PERF_SAMPLE_TIME;
attr.sample_id_all = 1;
attr.exclude_hv = 1;
attr.exclude_idle = 1;
attr.mmap = 1;
int intel_pt_type = 0;
auto ret = llvm::MemoryBuffer::getFileAsStream(
"/sys/bus/event_source/devices/intel_pt/type");
if (!ret) {
LLDB_LOG(log, "failed to open Config file");
return ret.getError();
}
StringRef rest = ret.get()->getBuffer();
if (rest.empty() || rest.trim().getAsInteger(10, intel_pt_type)) {
LLDB_LOG(log, "failed to read Config file");
error.SetErrorString("invalid file");
return error;
}
rest.trim().getAsInteger(10, intel_pt_type);
LLDB_LOG(log, "intel pt type {0}", intel_pt_type);
attr.type = intel_pt_type;
LLDB_LOG(log, "meta buffer size {0}", metabufsize);
LLDB_LOG(log, "buffer size {0} ", bufsize);
if (error.Fail()) {
LLDB_LOG(log, "Status in custom config");
return error;
}
errno = 0;
auto fd =
syscall(SYS_perf_event_open, &attr, static_cast<::tid_t>(tid), -1, -1, 0);
if (fd == -1) {
LLDB_LOG(log, "syscall error {0}", errno);
error.SetErrorString("perf event syscall Failed");
return error;
}
m_fd = std::unique_ptr<int, file_close>(new int(fd), file_close());
errno = 0;
auto base =
mmap(NULL, (metabufsize + page_size), PROT_WRITE, MAP_SHARED, fd, 0);
if (base == MAP_FAILED) {
LLDB_LOG(log, "mmap base error {0}", errno);
error.SetErrorString("Meta buffer allocation failed");
return error;
}
m_mmap_meta = std::unique_ptr<perf_event_mmap_page, munmap_delete>(
reinterpret_cast<perf_event_mmap_page *>(base),
munmap_delete(metabufsize + page_size));
m_mmap_meta->aux_offset = m_mmap_meta->data_offset + m_mmap_meta->data_size;
m_mmap_meta->aux_size = bufsize;
errno = 0;
auto mmap_aux = mmap(NULL, bufsize, PROT_READ, MAP_SHARED, fd,
static_cast<long int>(m_mmap_meta->aux_offset));
if (mmap_aux == MAP_FAILED) {
LLDB_LOG(log, "second mmap done {0}", errno);
error.SetErrorString("Trace buffer allocation failed");
return error;
}
m_mmap_aux = std::unique_ptr<uint8_t, munmap_delete>(
reinterpret_cast<uint8_t *>(mmap_aux), munmap_delete(bufsize));
return error;
#endif
}
llvm::MutableArrayRef<uint8_t> ProcessorTraceMonitor::GetDataBuffer() {
#ifndef PERF_ATTR_SIZE_VER5
llvm_unreachable("perf event not supported");
#else
return MutableArrayRef<uint8_t>(
(reinterpret_cast<uint8_t *>(m_mmap_meta.get()) +
m_mmap_meta->data_offset),
m_mmap_meta->data_size);
#endif
}
llvm::MutableArrayRef<uint8_t> ProcessorTraceMonitor::GetAuxBuffer() {
#ifndef PERF_ATTR_SIZE_VER5
llvm_unreachable("perf event not supported");
#else
return MutableArrayRef<uint8_t>(m_mmap_aux.get(), m_mmap_meta->aux_size);
#endif
}
Status ProcessorTraceMonitor::GetCPUType(TraceOptions &config) {
Status error;
uint64_t cpu_family = -1;
uint64_t model = -1;
uint64_t stepping = -1;
std::string vendor_id;
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
auto BufferOrError = getProcFile("cpuinfo");
if (!BufferOrError)
return BufferOrError.getError();
LLDB_LOG(log, "GetCPUType Function");
StringRef Rest = BufferOrError.get()->getBuffer();
while (!Rest.empty()) {
StringRef Line;
std::tie(Line, Rest) = Rest.split('\n');
SmallVector<StringRef, 2> columns;
Line.split(columns, StringRef(":"), -1, false);
if (columns.size() < 2)
continue; // continue searching
columns[1] = columns[1].trim(" ");
if (columns[0].contains("cpu family") &&
columns[1].getAsInteger(10, cpu_family))
continue;
else if (columns[0].contains("model") && columns[1].getAsInteger(10, model))
continue;
else if (columns[0].contains("stepping") &&
columns[1].getAsInteger(10, stepping))
continue;
else if (columns[0].contains("vendor_id")) {
vendor_id = columns[1].str();
if (!vendor_id.empty())
continue;
}
LLDB_LOG(log, "{0}:{1}:{2}:{3}", cpu_family, model, stepping, vendor_id);
if ((cpu_family != static_cast<uint64_t>(-1)) &&
(model != static_cast<uint64_t>(-1)) &&
(stepping != static_cast<uint64_t>(-1)) && (!vendor_id.empty())) {
auto params_dict = std::make_shared<StructuredData::Dictionary>();
params_dict->AddIntegerItem("cpu_family", cpu_family);
params_dict->AddIntegerItem("cpu_model", model);
params_dict->AddIntegerItem("cpu_stepping", stepping);
params_dict->AddStringItem("cpu_vendor", vendor_id);
llvm::StringRef intel_custom_params_key("intel-pt");
auto intel_custom_params = std::make_shared<StructuredData::Dictionary>();
intel_custom_params->AddItem(
intel_custom_params_key,
StructuredData::ObjectSP(std::move(params_dict)));
config.setTraceParams(intel_custom_params);
return error; // we are done
}
}
error.SetErrorString("cpu info not found");
return error;
}
llvm::Expected<ProcessorTraceMonitorUP>
ProcessorTraceMonitor::Create(lldb::pid_t pid, lldb::tid_t tid,
const TraceOptions &config,
bool useProcessSettings) {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
Status error;
if (tid == LLDB_INVALID_THREAD_ID) {
error.SetErrorString("thread not specified");
return error.ToError();
}
ProcessorTraceMonitorUP pt_monitor_up(new ProcessorTraceMonitor);
error = pt_monitor_up->StartTrace(pid, tid, config);
if (error.Fail())
return error.ToError();
pt_monitor_up->SetThreadID(tid);
if (useProcessSettings) {
pt_monitor_up->SetTraceID(0);
} else {
pt_monitor_up->SetTraceID(m_trace_num++);
LLDB_LOG(log, "Trace ID {0}", m_trace_num);
}
return std::move(pt_monitor_up);
}
Status
ProcessorTraceMonitor::ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer,
size_t offset) {
#ifndef PERF_ATTR_SIZE_VER5
llvm_unreachable("perf event not supported");
#else
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
Status error;
uint64_t head = m_mmap_meta->aux_head;
LLDB_LOG(log, "Aux size -{0} , Head - {1}", m_mmap_meta->aux_size, head);
/**
* When configured as ring buffer, the aux buffer keeps wrapping around
* the buffer and its not possible to detect how many times the buffer
* wrapped. Initially the buffer is filled with zeros,as shown below
* so in order to get complete buffer we first copy firstpartsize, followed
* by any left over part from beginning to aux_head
*
* aux_offset [d,d,d,d,d,d,d,d,0,0,0,0,0,0,0,0,0,0,0] aux_size
* aux_head->||<- firstpartsize ->|
*
* */
ReadCyclicBuffer(buffer, GetAuxBuffer(), static_cast<size_t>(head), offset);
LLDB_LOG(log, "ReadCyclic BUffer Done");
return error;
#endif
}
Status
ProcessorTraceMonitor::ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer,
size_t offset) {
#ifndef PERF_ATTR_SIZE_VER5
llvm_unreachable("perf event not supported");
#else
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
uint64_t bytes_remaining = buffer.size();
Status error;
uint64_t head = m_mmap_meta->data_head;
/*
* The data buffer and aux buffer have different implementations
* with respect to their definition of head pointer. In the case
* of Aux data buffer the head always wraps around the aux buffer
* and we don't need to care about it, whereas the data_head keeps
* increasing and needs to be wrapped by modulus operator
*/
LLDB_LOG(log, "bytes_remaining - {0}", bytes_remaining);
auto data_buffer = GetDataBuffer();
if (head > data_buffer.size()) {
head = head % data_buffer.size();
LLDB_LOG(log, "Data size -{0} Head - {1}", m_mmap_meta->data_size, head);
ReadCyclicBuffer(buffer, data_buffer, static_cast<size_t>(head), offset);
bytes_remaining -= buffer.size();
} else {
LLDB_LOG(log, "Head - {0}", head);
if (offset >= head) {
LLDB_LOG(log, "Invalid Offset ");
error.SetErrorString("invalid offset");
buffer = buffer.slice(buffer.size());
return error;
}
auto data = data_buffer.slice(offset, (head - offset));
auto remaining = std::copy(data.begin(), data.end(), buffer.begin());
bytes_remaining -= (remaining - buffer.begin());
}
buffer = buffer.drop_back(bytes_remaining);
return error;
#endif
}
void ProcessorTraceMonitor::ReadCyclicBuffer(
llvm::MutableArrayRef<uint8_t> &dst, llvm::MutableArrayRef<uint8_t> src,
size_t src_cyc_index, size_t offset) {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
if (dst.empty() || src.empty()) {
dst = dst.drop_back(dst.size());
return;
}
if (dst.data() == nullptr || src.data() == nullptr) {
dst = dst.drop_back(dst.size());
return;
}
if (src_cyc_index > src.size()) {
dst = dst.drop_back(dst.size());
return;
}
if (offset >= src.size()) {
LLDB_LOG(log, "Too Big offset ");
dst = dst.drop_back(dst.size());
return;
}
llvm::SmallVector<MutableArrayRef<uint8_t>, 2> parts = {
src.slice(src_cyc_index), src.take_front(src_cyc_index)};
if (offset > parts[0].size()) {
parts[1] = parts[1].slice(offset - parts[0].size());
parts[0] = parts[0].drop_back(parts[0].size());
} else if (offset == parts[0].size()) {
parts[0] = parts[0].drop_back(parts[0].size());
} else {
parts[0] = parts[0].slice(offset);
}
auto next = dst.begin();
auto bytes_left = dst.size();
for (auto part : parts) {
size_t chunk_size = std::min(part.size(), bytes_left);
next = std::copy_n(part.begin(), chunk_size, next);
bytes_left -= chunk_size;
}
dst = dst.drop_back(bytes_left);
}

Some files were not shown because too many files have changed in this diff Show More