compel: remove hardware breakpoint usage

Hardware breakpoints were originally intended to speed up the resume process
by stopping the process at a specific point in the pie code. However, it
turned out that they don't provide a significant speedup and, in some cases,
can even slow it down. This is especially critical for hosts with a large
number of CPUs.

Hardware Breakpoint Restore Performance Benchmark
==================================================

System: Linux 6.17.0-1007-gcp x86_64
CPU:    INTEL(R) XEON(R) PLATINUM 8581C CPU @ 2.10GHz
Virt:   google
CRIU:   Version: 4.2
Iterations per data point: 5

Threads         With BP (us) Without BP (us)     Diff (%)
--------        ------------ ---------------     --------
>>> Benchmarking with 1 thread(s)...
1                        391             326        19.9%
>>> Benchmarking with 10 thread(s)...
10                      1098             695        58.0%
>>> Benchmarking with 50 thread(s)...
50                      3772            2344        60.9%
>>> Benchmarking with 100 thread(s)...
100                     6740            4504        49.6%
>>> Benchmarking with 500 thread(s)...
500                    31382           19982        57.1%
>>> Benchmarking with 1000 thread(s)...
1000                   58617           40568        44.5%

Notes:
  'With BP'    = hardware breakpoints enabled (current default)
  'Without BP' = CRIU_FAULT=130 (FI_NO_BREAKPOINTS, uses PTRACE_SYSCALL)
  Positive diff% means breakpoints are slower

Signed-off-by: Andrei Vagin <avagin@google.com>
This commit is contained in:
Andrei Vagin 2026-03-09 00:19:15 +00:00 committed by Andrei Vagin
parent 869d481cf2
commit 7daebbe469
34 changed files with 34 additions and 496 deletions

View file

@ -1,42 +0,0 @@
#ifndef __COMPEL_BREAKPOINTS_H__
#define __COMPEL_BREAKPOINTS_H__
#define ARCH_SI_TRAP TRAP_BRKPT
#include <sys/types.h>
#include <stdbool.h>
struct hwbp_cap {
char arch;
char bp_count;
};
/* copied from `linux/arch/arm64/include/asm/hw_breakpoint.h` */
/* Lengths */
#define ARM_BREAKPOINT_LEN_1 0x1
#define ARM_BREAKPOINT_LEN_2 0x3
#define ARM_BREAKPOINT_LEN_3 0x7
#define ARM_BREAKPOINT_LEN_4 0xf
#define ARM_BREAKPOINT_LEN_5 0x1f
#define ARM_BREAKPOINT_LEN_6 0x3f
#define ARM_BREAKPOINT_LEN_7 0x7f
#define ARM_BREAKPOINT_LEN_8 0xff
/* Privilege Levels */
#define AARCH64_BREAKPOINT_EL1 1
#define AARCH64_BREAKPOINT_EL0 2
/* Breakpoint */
#define ARM_BREAKPOINT_EXECUTE 0
/* Watchpoints */
#define ARM_BREAKPOINT_LOAD 1
#define ARM_BREAKPOINT_STORE 2
#define AARCH64_ESR_ACCESS_MASK (1 << 6)
#define DISABLE_HBP 0
#define ENABLE_HBP 1
int ptrace_set_breakpoint(pid_t pid, void *addr);
int ptrace_flush_breakpoints(pid_t pid);
#endif

View file

@ -12,7 +12,6 @@
#include "errno.h"
#include "infect.h"
#include "infect-priv.h"
#include "asm/breakpoints.h"
#include "asm/gcs-types.h"
#include <linux/prctl.h>
@ -255,114 +254,6 @@ unsigned long compel_task_size(void)
return task_size;
}
static struct hwbp_cap *ptrace_get_hwbp_cap(pid_t pid)
{
static struct hwbp_cap info;
static int available = -1;
if (available == -1) {
unsigned int val;
struct iovec iovec = {
.iov_base = &val,
.iov_len = sizeof(val),
};
if (ptrace(PTRACE_GETREGSET, pid, NT_ARM_HW_BREAK, &iovec) < 0)
available = 0;
else {
info.arch = (char)((val >> 8) & 0xff);
info.bp_count = (char)(val & 0xff);
available = (info.arch != 0);
}
}
return available == 1 ? &info : NULL;
}
int ptrace_set_breakpoint(pid_t pid, void *addr)
{
k_rtsigset_t block;
struct hwbp_cap *info = ptrace_get_hwbp_cap(pid);
struct user_hwdebug_state regs = {};
unsigned int ctrl = 0;
struct iovec iovec;
if (info == NULL || info->bp_count == 0)
return 0;
/*
* The struct is copied from `arch/arm64/include/asm/hw_breakpoint.h` in
* linux kernel:
* struct arch_hw_breakpoint_ctrl {
* __u32 __reserved : 19,
* len : 8,
* type : 2,
* privilege : 2,
* enabled : 1;
* };
*
* The part of `struct arch_hw_breakpoint_ctrl` bits meaning is defined
* in <<ARM Architecture Reference Manual for A-profile architecture>>,
* D13.3.2 DBGBCR<n>_EL1, Debug Breakpoint Control Registers.
*/
ctrl = ARM_BREAKPOINT_LEN_4;
ctrl = (ctrl << 2) | ARM_BREAKPOINT_EXECUTE;
ctrl = (ctrl << 2) | AARCH64_BREAKPOINT_EL0;
ctrl = (ctrl << 1) | ENABLE_HBP;
regs.dbg_regs[0].addr = (__u64)addr;
regs.dbg_regs[0].ctrl = ctrl;
iovec.iov_base = &regs;
iovec.iov_len = (offsetof(struct user_hwdebug_state, dbg_regs) + sizeof(regs.dbg_regs[0]));
if (ptrace(PTRACE_SETREGSET, pid, NT_ARM_HW_BREAK, &iovec))
return -1;
/*
* FIXME(issues/1429): SIGTRAP can't be blocked, otherwise its handler
* will be reset to the default one.
*/
ksigfillset(&block);
ksigdelset(&block, SIGTRAP);
if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), &block)) {
pr_perror("Can't block signals for %d", pid);
return -1;
}
if (ptrace(PTRACE_CONT, pid, NULL, NULL) != 0) {
pr_perror("Unable to restart the stopped tracee process %d", pid);
return -1;
}
return 1;
}
int ptrace_flush_breakpoints(pid_t pid)
{
struct hwbp_cap *info = ptrace_get_hwbp_cap(pid);
struct user_hwdebug_state regs = {};
unsigned int ctrl = 0;
struct iovec iovec;
if (info == NULL || info->bp_count == 0)
return 0;
ctrl = ARM_BREAKPOINT_LEN_4;
ctrl = (ctrl << 2) | ARM_BREAKPOINT_EXECUTE;
ctrl = (ctrl << 2) | AARCH64_BREAKPOINT_EL0;
ctrl = (ctrl << 1) | DISABLE_HBP;
regs.dbg_regs[0].addr = 0ul;
regs.dbg_regs[0].ctrl = ctrl;
iovec.iov_base = &regs;
iovec.iov_len = (offsetof(struct user_hwdebug_state, dbg_regs) + sizeof(regs.dbg_regs[0]));
if (ptrace(PTRACE_SETREGSET, pid, NT_ARM_HW_BREAK, &iovec))
return -1;
return 0;
}
int inject_gcs_cap_token(struct parasite_ctl *ctl, pid_t pid, struct cr_user_gcs *gcs)
{
struct iovec gcs_iov = { .iov_base = gcs, .iov_len = sizeof(*gcs) };

View file

@ -1,15 +0,0 @@
#ifndef __COMPEL_BREAKPOINTS_H__
#define __COMPEL_BREAKPOINTS_H__
#define ARCH_SI_TRAP TRAP_BRKPT
static inline int ptrace_set_breakpoint(pid_t pid, void *addr)
{
return 0;
}
static inline int ptrace_flush_breakpoints(pid_t pid)
{
return 0;
}
#endif

View file

@ -2,6 +2,7 @@
#define UAPI_COMPEL_ASM_TYPES_H__
#include <stdint.h>
#include <signal.h>
#include <sys/mman.h>
#define SIGMAX 64

View file

@ -1,6 +0,0 @@
#ifndef __COMPEL_BREAKPOINTS_H__
#define __COMPEL_BREAKPOINTS_H__
#define ARCH_SI_TRAP TRAP_BRKPT
extern int ptrace_set_breakpoint(pid_t pid, void *addr);
extern int ptrace_flush_breakpoints(pid_t pid);
#endif

View file

@ -2,9 +2,11 @@
#define UAPI_COMPEL_ASM_TYPES_H__
#include <stdint.h>
#include <signal.h>
#define SIGMAX 64
#define SIGMAX_OLD 31
#define ARCH_SI_TRAP TRAP_BRKPT
/*
* From the Linux kernel header arch/loongarch/include/uapi/asm/ptrace.h

View file

@ -174,19 +174,6 @@ int arch_fetch_sas(struct parasite_ctl *ctl, struct rt_sigframe *s)
return err ? err : ret;
}
/*
* TODO: add feature
*/
int ptrace_set_breakpoint(pid_t pid, void *addr)
{
return 0;
}
int ptrace_flush_breakpoints(pid_t pid)
{
return 0;
}
/*
* Refer to Linux kernel arch/loongarch/include/asm/processor.h
*/

View file

@ -1,6 +0,0 @@
#ifndef __COMPEL_BREAKPOINTS_H__
#define __COMPEL_BREAKPOINTS_H__
#define ARCH_SI_TRAP TRAP_BRKPT
extern int ptrace_set_breakpoint(pid_t pid, void *addr);
extern int ptrace_flush_breakpoints(pid_t pid);
#endif

View file

@ -8,6 +8,7 @@
#include <linux/types.h>
#define SIGMAX 64
#define SIGMAX_OLD 31
#define ARCH_SI_TRAP TRAP_BRKPT
/*
* Copied from the Linux kernel header arch/mips/include/asm/ptrace.h

View file

@ -226,16 +226,6 @@ int arch_fetch_sas(struct parasite_ctl *ctl, struct rt_sigframe *s)
return err ? err : ret;
}
int ptrace_set_breakpoint(pid_t pid, void *addr)
{
return 0;
}
int ptrace_flush_breakpoints(pid_t pid)
{
return 0;
}
/*refer to kernel linux-3.10/arch/mips/include/asm/processor.h*/
#define TASK_SIZE32 0x7fff8000UL
#define TASK_SIZE64 0x10000000000UL

View file

@ -1,15 +0,0 @@
#ifndef __COMPEL_BREAKPOINTS_H__
#define __COMPEL_BREAKPOINTS_H__
#define ARCH_SI_TRAP TRAP_BRKPT
static inline int ptrace_set_breakpoint(pid_t pid, void *addr)
{
return 0;
}
static inline int ptrace_flush_breakpoints(pid_t pid)
{
return 0;
}
#endif

View file

@ -1,15 +0,0 @@
#ifndef __COMPEL_BREAKPOINTS_H__
#define __COMPEL_BREAKPOINTS_H__
#define ARCH_SI_TRAP TRAP_BRKPT
static inline int ptrace_set_breakpoint(pid_t pid, void *addr)
{
return 0;
}
static inline int ptrace_flush_breakpoints(pid_t pid)
{
return 0;
}
#endif

View file

@ -1,15 +0,0 @@
#ifndef __COMPEL_BREAKPOINTS_H__
#define __COMPEL_BREAKPOINTS_H__
#define ARCH_SI_TRAP TRAP_BRKPT
static inline int ptrace_set_breakpoint(pid_t pid, void *addr)
{
return 0;
}
static inline int ptrace_flush_breakpoints(pid_t pid)
{
return 0;
}
#endif

View file

@ -9,6 +9,7 @@
#define SIGMAX 64
#define SIGMAX_OLD 31
#define ARCH_SI_TRAP TRAP_BRKPT
/*
* Definitions from /usr/include/asm/ptrace.h:

View file

@ -1,6 +0,0 @@
#ifndef __COMPEL_BREAKPOINTS_H__
#define __COMPEL_BREAKPOINTS_H__
#define ARCH_SI_TRAP SI_KERNEL
extern int ptrace_set_breakpoint(pid_t pid, void *addr);
extern int ptrace_flush_breakpoints(pid_t pid);
#endif

View file

@ -8,6 +8,7 @@
#define SIGMAX 64
#define SIGMAX_OLD 31
#define ARCH_SI_TRAP SI_KERNEL
#define ARCH_HAS_PTRACE_GET_THREAD_AREA

View file

@ -633,70 +633,6 @@ int arch_fetch_sas(struct parasite_ctl *ctl, struct rt_sigframe *s)
return err ? err : ret;
}
/* Copied from the gdb header gdb/nat/x86-dregs.h */
/* Debug registers' indices. */
#define DR_FIRSTADDR 0
#define DR_LASTADDR 3
#define DR_NADDR 4 /* The number of debug address registers. */
#define DR_STATUS 6 /* Index of debug status register (DR6). */
#define DR_CONTROL 7 /* Index of debug control register (DR7). */
#define DR_LOCAL_ENABLE_SHIFT 0 /* Extra shift to the local enable bit. */
#define DR_GLOBAL_ENABLE_SHIFT 1 /* Extra shift to the global enable bit. */
#define DR_ENABLE_SIZE 2 /* Two enable bits per debug register. */
/* Locally enable the break/watchpoint in the I'th debug register. */
#define X86_DR_LOCAL_ENABLE(i) (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (i)))
int ptrace_set_breakpoint(pid_t pid, void *addr)
{
k_rtsigset_t block;
int ret;
/* Set a breakpoint */
if (ptrace(PTRACE_POKEUSER, pid, offsetof(struct user, u_debugreg[DR_FIRSTADDR]), addr)) {
pr_perror("Unable to setup a breakpoint into %d", pid);
return -1;
}
/* Enable the breakpoint */
if (ptrace(PTRACE_POKEUSER, pid, offsetof(struct user, u_debugreg[DR_CONTROL]),
X86_DR_LOCAL_ENABLE(DR_FIRSTADDR))) {
pr_perror("Unable to enable the breakpoint for %d", pid);
return -1;
}
/*
* FIXME(issues/1429): SIGTRAP can't be blocked, otherwise its handler
* will be reset to the default one.
*/
ksigfillset(&block);
ksigdelset(&block, SIGTRAP);
if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), &block)) {
pr_perror("Can't block signals for %d", pid);
return -1;
}
ret = ptrace(PTRACE_CONT, pid, NULL, NULL);
if (ret) {
pr_perror("Unable to restart the stopped tracee process %d", pid);
return -1;
}
return 1;
}
int ptrace_flush_breakpoints(pid_t pid)
{
/* Disable the breakpoint */
if (ptrace(PTRACE_POKEUSER, pid, offsetof(struct user, u_debugreg[DR_CONTROL]), 0)) {
pr_perror("Unable to disable the breakpoint for %d", pid);
return -1;
}
return 0;
}
int ptrace_get_regs(pid_t pid, user_regs_struct_t *regs)
{
struct iovec iov;

View file

@ -19,7 +19,6 @@ struct parasite_ctl {
int rpid; /* Real pid of the victim */
void *remote_map;
void *local_map;
void *sigreturn_addr; /* A place for the breakpoint */
unsigned long map_length;
struct infect_ctx ictx;

View file

@ -41,7 +41,6 @@ struct parasite_init_args {
int32_t h_addr_len;
struct sockaddr_un h_addr;
int32_t log_level;
uint64_t sigreturn_addr;
uint64_t sigframe; /* pointer to sigframe */
futex_t daemon_connected;
#ifdef ARCH_HAS_LONG_PAGES

View file

@ -95,8 +95,6 @@ enum trace_flags {
extern int __must_check compel_stop_on_syscall(int tasks, int sys_nr, int sys_nr_compat);
extern int compel_stop_tasks_on_syscall(int tasks, pid_t *pids, const int sys_nr, const int sys_nr_compat);
extern int __must_check compel_stop_pie(pid_t pid, void *addr, bool no_bp);
extern int __must_check compel_unmap(struct parasite_ctl *ctl, unsigned long addr);
extern int compel_mode_native(struct parasite_ctl *ctl);
@ -139,8 +137,6 @@ extern struct infect_ctx *compel_infect_ctx(struct parasite_ctl *);
#define INFECT_NO_MEMFD (1UL << 0)
/* Make parasite connect() fail */
#define INFECT_FAIL_CONNECT (1UL << 1)
/* No breakpoints in pie tracking */
#define INFECT_NO_BREAKPOINTS (1UL << 2)
/* Can run parasite inside compat tasks */
#define INFECT_COMPATIBLE (1UL << 3)
/* Workaround for ptrace bug on Skylake CPUs with kernels older than v4.14 */

View file

@ -11,8 +11,6 @@
#include <sys/ptrace.h>
#include <stdint.h>
#include <compel/asm/breakpoints.h>
/*
* Some constants for ptrace that might be missing from the
* standard library includes due to being (relatively) new.

View file

@ -153,7 +153,6 @@ static noinline __used unsigned long parasite_init_daemon(void *data)
struct parasite_init_args *args = data;
int ret;
args->sigreturn_addr = (uint64_t)(uintptr_t)fini_sigreturn;
sigframe = (void *)(uintptr_t)args->sigframe;
#ifdef ARCH_HAS_LONG_PAGES
__page_size = args->page_size;

View file

@ -725,7 +725,6 @@ static int parasite_init_daemon(struct parasite_ctl *ctl)
goto err;
}
ctl->sigreturn_addr = (void *)(uintptr_t)args->sigreturn_addr;
ctl->daemonized = true;
pr_info("Parasite %d has been switched to daemon mode\n", pid);
return 0;
@ -1435,9 +1434,10 @@ static int parasite_fini_seized(struct parasite_ctl *ctl)
return -1;
/* Go to sigreturn as closer as we can */
ret = compel_stop_pie(pid, ctl->sigreturn_addr, ctl->ictx.flags & INFECT_NO_BREAKPOINTS);
if (ret < 0)
return ret;
if (ptrace(PTRACE_SYSCALL, pid, NULL, NULL)) {
pr_perror("Unable to restart the %d process", pid);
return -1;
}
if (compel_stop_on_syscall(1, __NR(rt_sigreturn, 0), __NR(rt_sigreturn, 1)))
return -1;
@ -1588,38 +1588,6 @@ err:
return ret;
}
int compel_stop_pie(pid_t pid, void *addr, bool no_bp)
{
int ret;
if (no_bp) {
pr_debug("Force no-breakpoints restore of %d\n", pid);
ret = 0;
} else
ret = ptrace_set_breakpoint(pid, addr);
if (ret < 0)
return ret;
if (ret > 0) {
/*
* PIE will stop on a breakpoint, next
* stop after that will be syscall enter.
*/
return 0;
}
/*
* No breakpoints available -- start tracing it
* in a per-syscall manner.
*/
ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
if (ret) {
pr_perror("Unable to restart the %d process", pid);
return -1;
}
return 0;
}
static bool task_is_trapped(int status, pid_t pid)
{
if (WIFSTOPPED(status) && (WSTOPSIG(status) & ~PTRACE_SYSCALL_TRAP) == SIGTRAP)
@ -1675,22 +1643,19 @@ int compel_stop_on_syscall(int tasks, const int sys_nr, const int sys_nr_compat)
pr_debug("%d was trapped\n", pid);
if ((WSTOPSIG(status) & PTRACE_SYSCALL_TRAP) == 0) {
/*
* On some platforms such as ARM64, it is impossible to
* pass through a breakpoint, so let's clear it right
* after it has been triggered.
*/
if (ptrace_flush_breakpoints(pid)) {
pr_err("Unable to clear breakpoints\n");
return -1;
}
goto goon;
if (!(WSTOPSIG(status) & PTRACE_SYSCALL_TRAP)) {
pr_err("Task %d is in unexpected state: %x\n", pid, status);
return -1;
}
if (trace == TRACE_EXIT) {
trace = TRACE_ENTER;
pr_debug("`- Expecting exit\n");
goto goon;
ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
if (ret) {
pr_perror("ptrace");
return -1;
}
continue;
}
if (trace == TRACE_ENTER)
trace = TRACE_EXIT;
@ -1721,12 +1686,17 @@ int compel_stop_on_syscall(int tasks, const int sys_nr, const int sys_nr_compat)
if (!task_is_trapped(status, pid))
return -1;
if (!(WSTOPSIG(status) & PTRACE_SYSCALL_TRAP)) {
pr_err("Task %d is in unexpected state: %x\n", pid, status);
return -1;
}
pr_debug("%d was stopped\n", pid);
tasks--;
continue;
}
goon:
ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
if (ret) {
pr_perror("ptrace");
return -1;
@ -1785,18 +1755,11 @@ int compel_stop_tasks_on_syscall(int nr_tasks, pid_t *pids, const int sys_nr, co
pr_debug("%d was trapped\n", pid);
if ((WSTOPSIG(status) & PTRACE_SYSCALL_TRAP) == 0) {
/*
* On some platforms such as ARM64, it is impossible to
* pass through a breakpoint, so let's clear it right
* after it has been triggered.
*/
if (ptrace_flush_breakpoints(pid)) {
pr_err("Unable to clear breakpoints\n");
goto err;
}
goto goon;
if (!(WSTOPSIG(status) & PTRACE_SYSCALL_TRAP)) {
pr_err("Task %d is in unexpected state: %x\n", pid, status);
goto err;
}
if (done[i] == SYS_TRAP_ENTER) {
done[i] = SYS_TRAP_EXIT;
continue;
@ -1810,7 +1773,7 @@ int compel_stop_tasks_on_syscall(int nr_tasks, pid_t *pids, const int sys_nr, co
if (is_required_syscall(&regs, pid, sys_nr, sys_nr_compat))
done[i] = SYS_TRAP_ENTER;
goon:
/* Let this task run while updating the others. */
ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
if (ret) {

View file

@ -199,9 +199,6 @@ static inline void _setup_sas(struct rt_sigframe *sigframe, ThreadSasEntry *sas)
int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r);
int restore_nonsigframe_gpregs(UserX86RegsEntry *r);
int ptrace_set_breakpoint(pid_t pid, void *addr);
int ptrace_flush_breakpoints(pid_t pid);
extern int arch_map_vdso(unsigned long map_at, bool compatible);
#endif

View file

@ -1589,16 +1589,6 @@ static int check_overlayfs_maps(void)
return status == 0 ? 0 : -1;
}
static int check_breakpoints(void)
{
if (!kdat.has_breakpoints) {
pr_warn("Hardware breakpoints don't seem to work\n");
return -1;
}
return 0;
}
static int check_pagemap_scan_guard_pages(void)
{
kerndat_warn_about_madv_guards();
@ -1746,7 +1736,6 @@ int cr_check(void)
/*
* Category 4 - optional.
*/
check_breakpoints();
pr_msg("%s\n", ret ? CHECK_MAYBE : CHECK_GOOD);
return ret;
@ -1869,7 +1858,6 @@ static struct feature_list feature_list[] = {
{ "pagemap_scan", check_pagemap_scan },
{ "timer_cr_ids", check_timer_cr_ids },
{ "overlayfs_maps", check_overlayfs_maps },
{ "breakpoints", check_breakpoints },
{ "pagemap_scan_guard_pages", check_pagemap_scan_guard_pages },
{ "binfmt_misc_sandboxing", check_binfmt_misc_sandboxing },
{ NULL, NULL },

View file

@ -1834,7 +1834,6 @@ static int restore_rseq_cs(void)
static int catch_tasks(pid_t *pids, int nr_tasks)
{
struct pstree_item *item;
bool nobp = fault_injected(FI_NO_BREAKPOINTS) || !kdat.has_breakpoints;
int npids = 0;
for_each_pstree_item(item) {
@ -1859,7 +1858,7 @@ static int catch_tasks(pid_t *pids, int nr_tasks)
}
}
for_each_pstree_item(item) {
int status, i, ret;
int status, i;
if (!task_alive(item))
continue;
@ -1872,9 +1871,10 @@ static int catch_tasks(pid_t *pids, int nr_tasks)
return -1;
}
ret = compel_stop_pie(pid, rsti(item)->breakpoint, nobp);
if (ret < 0)
if (ptrace(PTRACE_SYSCALL, pid, NULL, NULL)) {
pr_perror("Unable to resume the %d process", pid);
return -1;
}
}
}
@ -3334,7 +3334,6 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns
goto err;
}
task_args->breakpoint = &rsti(current)->breakpoint;
task_args->fault_strategy = fi_strategy;
sigemptyset(&blockmask);

View file

@ -14,7 +14,6 @@ enum faults {
FI_VDSO_TRAMPOLINES = 127,
FI_CHECK_OPEN_HANDLE = 128,
FI_NO_MEMFD = 129,
FI_NO_BREAKPOINTS = 130,
FI_PARTIAL_PAGES = 131,
FI_HUGE_ANON_SHMEM_ID = 132,
FI_CANNOT_MAP_VDSO = 133,

View file

@ -90,7 +90,6 @@ struct kerndat_s {
bool has_shstk;
bool has_close_range;
bool has_timer_cr_ids;
bool has_breakpoints;
bool has_madv_guard;
bool has_pagemap_scan_guard_pages;
bool has_binfmt_misc_sandboxing;

View file

@ -229,7 +229,6 @@ struct task_restore_args {
unsigned long vdso_rt_size;
struct vdso_maps vdso_maps_rt; /* runtime vdso symbols */
unsigned long vdso_rt_parked_at; /* safe place to keep vdso */
void **breakpoint;
enum faults fault_strategy;
#ifdef ARCH_HAS_LONG_PAGES

View file

@ -85,8 +85,6 @@ struct rst_info {
futex_t shstk_enable;
futex_t shstk_unlock;
void *breakpoint;
struct rst_arch_info arch_info;
};

View file

@ -1736,83 +1736,6 @@ static int kerndat_has_timer_cr_ids(void)
return 0;
}
static void breakpoint_func(void)
{
if (raise(SIGSTOP))
pr_perror("Unable to kill itself with SIGSTOP");
exit(1);
}
/*
* kerndat_breakpoints checks that hardware breakpoints work as they should.
* In some cases, they might not work in virtual machines if the hypervisor
* doesn't virtualize them. For example, they don't work in AMD SEV virtual
* machines if the Debug Virtualization extension isn't supported or isn't
* enabled in SEV_FEATURES.
*/
static int kerndat_breakpoints(void)
{
int status, ret, exit_code = -1;
pid_t pid;
pid = fork();
if (pid == -1) {
pr_perror("fork");
return -1;
}
if (pid == 0) {
if (ptrace(PTRACE_TRACEME, 0, 0, 0)) {
pr_perror("ptrace(PTRACE_TRACEME)");
exit(1);
}
raise(SIGSTOP);
breakpoint_func();
exit(1);
}
if (waitpid(pid, &status, 0) == -1) {
pr_perror("waitpid for initial stop");
goto err;
}
if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP) {
pr_err("Child didn't stop as expected: status=%x\n", status);
goto err;
}
ret = ptrace_set_breakpoint(pid, &breakpoint_func);
if (ret < 0) {
pr_err("Failed to set breakpoint\n");
goto err;
}
if (ret == 0) {
pr_debug("Hardware breakpoints appear to be disabled\n");
goto out;
}
if (waitpid(pid, &status, 0) == -1) {
pr_perror("waitpid for breakpoint trigger");
goto err;
}
if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) {
pr_warn("Hardware breakpoints don't seem to work (status=%x)\n", status);
goto out;
}
kdat.has_breakpoints = true;
out:
exit_code = 0;
err:
if (kill(pid, SIGKILL)) {
pr_perror("Failed to kill the child process");
exit_code = -1;
}
if (waitpid(pid, &status, 0) == -1) {
pr_perror("Failed to wait for the child process");
exit_code = -1;
}
if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGKILL) {
pr_err("The child exited with unexpected code: %x\n", status);
exit_code = -1;
}
return exit_code;
}
static int kerndat_has_madv_guard(void)
{
void *map;
@ -2199,10 +2122,6 @@ int kerndat_init(void)
pr_err("kerndat_has_timer_cr_ids has failed when initializing kerndat.\n");
ret = -1;
}
if (!ret && kerndat_breakpoints()) {
pr_err("kerndat_breakpoints has failed when initializing kerndat.\n");
ret = -1;
}
if (!ret && kerndat_has_madv_guard()) {
pr_err("kerndat_has_madv_guard has failed when initializing kerndat.\n");
ret = -1;

View file

@ -421,8 +421,6 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
ictx->flags |= INFECT_NO_MEMFD;
if (fault_injected(FI_PARASITE_CONNECT))
ictx->flags |= INFECT_FAIL_CONNECT;
if (fault_injected(FI_NO_BREAKPOINTS) || !kdat.has_breakpoints)
ictx->flags |= INFECT_NO_BREAKPOINTS;
if (kdat.compat_cr)
ictx->flags |= INFECT_COMPATIBLE;
if (kdat.x86_has_ptrace_fpu_xsave_bug)

View file

@ -1747,7 +1747,6 @@ __visible long __export_restore_task(struct task_restore_args *args)
n_helpers = args->helpers_n;
zombies = args->zombies;
n_zombies = args->zombies_n;
*args->breakpoint = rst_sigreturn;
#ifdef ARCH_HAS_LONG_PAGES
__page_size = args->page_size;
#endif

View file

@ -15,7 +15,6 @@ if [ $NOBTRFS -eq 1 ] ; then
fi
./test/zdtm.py run -t zdtm/static/env00 --fault 129 -f uns || fail
./test/zdtm.py run -t zdtm/transition/fork --fault 130 -f h || fail
./test/zdtm.py run -t zdtm/static/vdso01 --fault 127 || fail
./test/zdtm.py run -t zdtm/static/vdso-proxy --fault 127 --iters 3 || fail