You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用ptrace为地址范围设置监视点/断点?父子共享内存技术求助

父子进程共享内存的预读取修改方案

一、无需硬件断点的更优解决方案

硬件断点本身受限于CPU寄存器数量(x86架构最多4个),且权限配置麻烦,更可靠的是用以下两种方案实现需求:

1. 内存保护+信号拦截

核心思路:把共享内存设为只读,子进程读取时触发SIGSEGV信号,父进程捕获信号后修改内存,再恢复权限让子进程继续执行。

简化代码示例:

#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <stdio.h>
#include <signal.h>

int main() {
    // 创建匿名共享内存页
    void* shmem = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    // 初始设置为只读
    mprotect(shmem, 4096, PROT_READ);

    pid_t pid = fork();
    if (pid == 0) {
        // 子进程:主动让父进程跟踪自己
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        // 尝试读取共享内存,触发SIGSEGV
        int val = *(int*)shmem;
        printf("子进程读取到:%d\n", val);
        munmap(shmem, 4096);
        return 0;
    } else {
        int status;
        // 等待子进程触发信号
        waitpid(pid, &status, 0);
        if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGSEGV) {
            // 父进程修改共享内存内容
            *(int*)shmem = 12345;
            // 恢复内存可读可写权限
            mprotect(shmem, 4096, PROT_READ | PROT_WRITE);
            // 让子进程继续执行
            ptrace(PTRACE_CONT, pid, NULL, NULL);
            // 等待子进程结束
            waitpid(pid, &status, 0);
        }
        munmap(shmem, 4096);
        return 0;
    }
}

2. 显式同步机制(最简单可靠)

如果子进程的读取时机可控,直接用信号量、互斥锁或管道做同步,完全不需要依赖断点或内存保护:

信号量实现示例:

#include <semaphore.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>

typedef struct {
    sem_t sem;
    int value;
} SharedData;

int main() {
    // 创建包含信号量的共享内存
    SharedData* shmem = mmap(NULL, sizeof(SharedData), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    // 初始化信号量,初始值0(子进程等待父进程信号)
    sem_init(&shmem->sem, 1, 0);

    pid_t pid = fork();
    if (pid == 0) {
        // 子进程:等待父进程通知
        sem_wait(&shmem->sem);
        printf("子进程读取到:%d\n", shmem->value);
        sem_destroy(&shmem->sem);
        munmap(shmem, sizeof(SharedData));
        return 0;
    } else {
        // 父进程:先修改共享内存内容
        shmem->value = 9876;
        // 通知子进程可以读取
        sem_post(&shmem->sem);
        wait(NULL);
        munmap(shmem, sizeof(SharedData));
        return 0;
    }
}

二、硬件断点的问题修复(如果坚持使用)

1. 权限问题解决

硬件断点需要进程拥有CAP_SYS_PTRACE权限,可通过以下方式配置:

  • 给程序添加权限:sudo setcap cap_sys_ptrace+ep ./your_program
  • 临时关闭系统ptrace限制(不推荐,不安全):echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope

2. 永久断点实现

硬件断点触发后CPU调试寄存器会自动重置,要实现永久断点,需在信号处理后重新写入寄存器:

伪代码逻辑:

// 父进程捕获子进程的SIGTRAP信号
waitpid(pid, &status, 0);
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
    // 修改共享内存内容
    *(int*)shmem = 54321;
    // 重新设置硬件断点
    struct user_regs_struct regs;
    ptrace(PTRACE_GETREGS, pid, NULL, &regs);
    regs.dr0 = (unsigned long)shmem; // 设置断点地址
    regs.dr7 = (1 << 0); // 启用dr0的读断点
    ptrace(PTRACE_SETREGS, pid, NULL, &regs);
    // 让子进程继续执行
    ptrace(PTRACE_CONT, pid, NULL, NULL);
}

注意:这种方式依然受限于CPU最多4个硬件断点的限制,不适合多地址监控场景。

内容的提问来源于stack exchange,提问作者Maray97

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 13:07:42