Skip to content
1 change: 1 addition & 0 deletions lldb/source/Plugins/Process/Linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ add_lldb_library(lldbPluginProcessLinux
NativeRegisterContextLinux.cpp
NativeRegisterContextLinux_arm.cpp
NativeRegisterContextLinux_arm64.cpp
NativeRegisterContextLinux_arm64dbreg.cpp
NativeRegisterContextLinux_loongarch64.cpp
NativeRegisterContextLinux_ppc64le.cpp
NativeRegisterContextLinux_riscv64.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,19 @@
#include <elf.h>
#include <sys/uio.h>

#if defined(__arm64__) || defined(__aarch64__)
#include "NativeRegisterContextLinux_arm64dbreg.h"
#include "lldb/Host/linux/Ptrace.h"
#include <asm/ptrace.h>
#endif

#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(m_fpr))

#ifndef PTRACE_GETVFPREGS
#define PTRACE_GETVFPREGS 27
#define PTRACE_SETVFPREGS 28
#endif
#ifndef PTRACE_GETHBPREGS
#if defined(__arm__) && !defined(PTRACE_GETHBPREGS)
#define PTRACE_GETHBPREGS 29
#define PTRACE_SETHBPREGS 30
#endif
Expand Down Expand Up @@ -342,7 +348,8 @@ NativeRegisterContextLinux_arm::SetHardwareBreakpoint(lldb::addr_t addr,
m_hbr_regs[bp_index].control = control_value;

// PTRACE call to set corresponding hardware breakpoint register.
error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index);
error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK,
bp_index);

if (error.Fail()) {
m_hbr_regs[bp_index].address = 0;
Expand Down Expand Up @@ -375,7 +382,8 @@ bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) {
m_hbr_regs[hw_idx].address = 0;

// PTRACE call to clear corresponding hardware breakpoint register.
error = WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx);
error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK,
hw_idx);

if (error.Fail()) {
m_hbr_regs[hw_idx].control = tempControl;
Expand Down Expand Up @@ -435,7 +443,8 @@ Status NativeRegisterContextLinux_arm::ClearAllHardwareBreakpoints() {
m_hbr_regs[i].address = 0;

// Ptrace call to update hardware debug registers
error = WriteHardwareDebugRegs(eDREGTypeBREAK, i);
error =
WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK, i);

if (error.Fail()) {
m_hbr_regs[i].control = tempControl;
Expand Down Expand Up @@ -555,7 +564,8 @@ uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint(
m_hwp_regs[wp_index].control = control_value;

// PTRACE call to set corresponding watchpoint register.
error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH,
wp_index);

if (error.Fail()) {
m_hwp_regs[wp_index].address = 0;
Expand Down Expand Up @@ -590,7 +600,8 @@ bool NativeRegisterContextLinux_arm::ClearHardwareWatchpoint(
m_hwp_regs[wp_index].address = 0;

// Ptrace call to update hardware debug registers
error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH,
wp_index);

if (error.Fail()) {
m_hwp_regs[wp_index].control = tempControl;
Expand Down Expand Up @@ -623,7 +634,8 @@ Status NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() {
m_hwp_regs[i].address = 0;

// Ptrace call to update hardware debug registers
error = WriteHardwareDebugRegs(eDREGTypeWATCH, i);
error =
WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH, i);

if (error.Fail()) {
m_hwp_regs[i].control = tempControl;
Expand Down Expand Up @@ -723,6 +735,7 @@ Status NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
return Status();
}

#ifdef __arm__
unsigned int cap_val;

error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(),
Expand All @@ -737,16 +750,21 @@ Status NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
m_refresh_hwdebug_info = false;

return error;
#else // __aarch64__
return arm64::ReadHardwareDebugInfo(m_thread.GetID(), m_max_hwp_supported,
m_max_hbp_supported);
#endif // ifdef __arm__
}

Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType,
int hwb_index) {
Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(
NativeRegisterContextDBReg::DREGType hwbType, int hwb_index) {
Status error;

#ifdef __arm__
lldb::addr_t *addr_buf;
uint32_t *ctrl_buf;

if (hwbType == eDREGTypeWATCH) {
if (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH) {
addr_buf = &m_hwp_regs[hwb_index].address;
ctrl_buf = &m_hwp_regs[hwb_index].control;

Expand Down Expand Up @@ -781,6 +799,17 @@ Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType,
}

return error;
#else // __aarch64__
uint32_t max_supported =
(hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH)
? m_max_hwp_supported
: m_max_hbp_supported;
auto &regs = (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH)
? m_hwp_regs
: m_hbr_regs;
return arm64::WriteHardwareDebugRegs(hwbType, m_thread.GetID(), max_supported,
regs);
#endif // ifdef __arm__
}

uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#define lldb_NativeRegisterContextLinux_arm_h

#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h"
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
#include "Plugins/Process/Utility/lldb-arm-register-enums.h"

Expand Down Expand Up @@ -74,9 +75,6 @@ class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux {

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;
Expand All @@ -102,17 +100,10 @@ class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux {
uint32_t m_gpr_arm[k_num_gpr_registers_arm];
RegisterInfoPOSIX_arm::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.
};

struct DREG m_hbr_regs[16]; // Arm native linux hardware breakpoints
struct DREG m_hwp_regs[16]; // Arm native linux hardware watchpoints
std::array<NativeRegisterContextDBReg::DREG, 16>
m_hbr_regs; // Arm native linux hardware breakpoints
std::array<NativeRegisterContextDBReg::DREG, 16>
m_hwp_regs; // Arm native linux hardware watchpoints

uint32_t m_max_hwp_supported;
uint32_t m_max_hbp_supported;
Expand All @@ -124,7 +115,8 @@ class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux {

Status ReadHardwareDebugInfo();

Status WriteHardwareDebugRegs(int hwbType, int hwb_index);
Status WriteHardwareDebugRegs(NativeRegisterContextDBReg::DREGType hwbType,
int hwb_index);

uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@

#if defined(__arm64__) || defined(__aarch64__)

#include "NativeRegisterContextLinux_arm.h"
#include "NativeRegisterContextLinux_arm64.h"
#include "NativeRegisterContextLinux_arm.h"
#include "NativeRegisterContextLinux_arm64dbreg.h"

#include "lldb/Host/HostInfo.h"
#include "lldb/Host/common/NativeProcessProtocol.h"
Expand Down Expand Up @@ -1146,68 +1147,23 @@ llvm::Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() {

::pid_t tid = m_thread.GetID();

int regset = NT_ARM_HW_WATCH;
struct iovec ioVec;
struct user_hwdebug_state dreg_state;
Status error;

ioVec.iov_base = &dreg_state;
ioVec.iov_len = sizeof(dreg_state);
error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
&ioVec, ioVec.iov_len);

Status error = arm64::ReadHardwareDebugInfo(tid, m_max_hwp_supported,
m_max_hbp_supported);
if (error.Fail())
return error.ToError();

m_max_hwp_supported = dreg_state.dbg_info & 0xff;

regset = NT_ARM_HW_BREAK;
error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
&ioVec, ioVec.iov_len);

if (error.Fail())
return error.ToError();

m_max_hbp_supported = dreg_state.dbg_info & 0xff;
m_refresh_hwdebug_info = false;

return llvm::Error::success();
}

llvm::Error
NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(DREGType hwbType) {
struct iovec ioVec;
struct user_hwdebug_state dreg_state;
int regset;

memset(&dreg_state, 0, sizeof(dreg_state));
ioVec.iov_base = &dreg_state;

switch (hwbType) {
case eDREGTypeWATCH:
regset = NT_ARM_HW_WATCH;
ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) +
(sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported);

for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
}
break;
case eDREGTypeBREAK:
regset = NT_ARM_HW_BREAK;
ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) +
(sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported);

for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
dreg_state.dbg_regs[i].addr = m_hbp_regs[i].address;
dreg_state.dbg_regs[i].ctrl = m_hbp_regs[i].control;
}
break;
}

return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
&regset, &ioVec, ioVec.iov_len)
uint32_t max_supported =
(hwbType == eDREGTypeWATCH) ? m_max_hwp_supported : m_max_hbp_supported;
auto &regs = (hwbType == eDREGTypeWATCH) ? m_hwp_regs : m_hbp_regs;
return arm64::WriteHardwareDebugRegs(hwbType, m_thread.GetID(), max_supported,
regs)
.ToError();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//===-- NativeRegisterContextLinux_arm64dbreg.cpp -------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#if defined(__arm64__) || defined(__aarch64__)

#include "NativeRegisterContextLinux_arm64dbreg.h"
#include "lldb/Host/linux/Ptrace.h"

#include <asm/ptrace.h>
// System includes - They have to be included after framework includes because
// they define some macros which collide with variable names in other modules
#include <sys/uio.h>
// NT_PRSTATUS and NT_FPREGSET definition
#include <elf.h>

using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_linux;

static Status ReadHardwareDebugInfoHelper(int regset, ::pid_t tid,
uint32_t &max_supported) {
struct iovec ioVec;
struct user_hwdebug_state dreg_state;
Status error;

ioVec.iov_base = &dreg_state;
ioVec.iov_len = sizeof(dreg_state);
error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
&ioVec, ioVec.iov_len);

if (error.Fail())
return error;

max_supported = dreg_state.dbg_info & 0xff;
return error;
}

Status lldb_private::process_linux::arm64::ReadHardwareDebugInfo(
::pid_t tid, uint32_t &max_hwp_supported, uint32_t &max_hbp_supported) {
Status error =
ReadHardwareDebugInfoHelper(NT_ARM_HW_WATCH, tid, max_hwp_supported);

if (error.Fail())
return error;

return ReadHardwareDebugInfoHelper(NT_ARM_HW_BREAK, tid, max_hbp_supported);
}

Status lldb_private::process_linux::arm64::WriteHardwareDebugRegs(
int hwbType, ::pid_t tid, uint32_t max_supported,
const std::array<NativeRegisterContextDBReg::DREG, 16> &regs) {
int regset = hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH
? NT_ARM_HW_WATCH
: NT_ARM_HW_BREAK;

struct user_hwdebug_state dreg_state;
memset(&dreg_state, 0, sizeof(dreg_state));
for (uint32_t i = 0; i < max_supported; i++) {
dreg_state.dbg_regs[i].addr = regs[i].address;
dreg_state.dbg_regs[i].ctrl = regs[i].control;
}

struct iovec ioVec;
ioVec.iov_base = &dreg_state;
ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) +
(sizeof(dreg_state.dbg_regs[0]) * max_supported);

return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset,
&ioVec, ioVec.iov_len);
}

#endif // defined (__arm64__) || defined (__aarch64__)
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//===-- NativeRegisterContextLinux_arm64dbreg.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
//
//===----------------------------------------------------------------------===//

// When debugging 32-bit processes, Arm64 lldb-server should use 64-bit ptrace
// interfaces. 32-bit ptrace interfaces should only be used by 32-bit server.
// These functions are split out to be reused in both 32-bit and 64-bit register
// context for 64-bit server.

#include "Plugins/Process/Linux/NativeProcessLinux.h"
#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h"
#include "lldb/Utility/Status.h"

namespace lldb_private {
namespace process_linux {
namespace arm64 {

Status ReadHardwareDebugInfo(::pid_t tid, uint32_t &max_hwp_supported,
uint32_t &max_hbp_supported);

Status WriteHardwareDebugRegs(
int hwbType, ::pid_t tid, uint32_t max_supported,
const std::array<NativeRegisterContextDBReg::DREG, 16> &regs);

} // namespace arm64
} // namespace process_linux
} // namespace lldb_private
Loading
Loading