首页
社区
课程
招聘
[原创]窥探Proot原理
发表于: 2025-3-5 21:07 29441

[原创]窥探Proot原理

2025-3-5 21:07
29441

引导视频(大佬的视频):

57aK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2T1K9h3I4A6j5X3W2D9K9g2)9J5k6h3y4G2L8g2)9J5c8Y4k6A6k6r3g2G2i4K6u0r3b7W2j5I4c8@1Z5@1L8e0q4x3y4K6c8x3i4K6u0r3i4K6y4r3N6X3c8Q4y4h3k6K6L8%4g2J5j5$3g2Q4x3@1b7%4y4e0x3$3y4$3t1J5y4o6q4U0k6r3c8U0x3o6f1H3k6o6x3I4x3$3x3$3y4r3u0V1y4e0M7H3j5$3j5K6z5b7`.`.

编译教程:

98fK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5%4y4V1L8W2)9J5k6h3&6W2N6q4)9J5c8V1c8W2L8X3&6&6i4K6g2X3b7$3S2W2L8W2)9#2k6W2)9J5c8X3q4J5N6r3W2U0L8r3g2Q4x3V1k6V1k6i4c8S2K9h3I4K6i4K6u0r3x3e0x3%4x3o6f1#2y4U0b7J5

源码地址:

911K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6H3M7X3!0G2N6q4)9J5k6r3#2W2i4K6u0r3M7s2u0G2L8%4b7`.

跟踪进程行为:允许一个进程(跟踪者,tracer)观察和控制另一个进程(被跟踪者,tracee)的执行。

读写内存和寄存器:可以修改被跟踪进程的内存和寄存器状态。

拦截信号和系统调用:在系统调用(syscall)或信号(如 SIGTRAP)触发时暂停被跟踪进程,供跟踪者处理。

通过 ptrace(request, pid, addr, data) 发送请求,常见 request 参数包括:

PTRACE_TRACEME
被跟踪进程主动声明自己被父进程跟踪(常用于子进程)。

PTRACE_ATTACH
跟踪者附加到正在运行的进程(需权限)。

PTRACE_DETACH
解除跟踪,恢复被跟踪进程执行。

PTRACE_PEEKTEXT/PTRACE_POKETEXT
读/写被跟踪进程的内存。

PTRACE_GETREGS/PTRACE_SETREGS
读/写被跟踪进程的寄存器(如 eax, ebx 等)。

PTRACE_SYSCALL
使被跟踪进程在下一个系统调用入口和退出时暂停(用于拦截系统调用)。

PTRACE_CONT
恢复被跟踪进程的执行。

拦截系统调用:通过 PTRACE_SYSCALL,跟踪者可以在被跟踪进程执行系统调用前(入口)和系统调用后(退出)获取控制权。

修改参数/返回值

在入口阶段:可修改系统调用的参数(通过寄存器,如 eax 存储系统调用号,ebx, ecx 等存储参数)。

在退出阶段:可修改系统调用的返回值(如模拟成功或失败)。

开发涉及到的关键API都是直接参考官方文档:

ec1K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0j5h3^5%4i4K6u0W2L8%4u0Y4i4K6u0r3L8r3W2F1N6i4S2Q4x3V1k6E0j5h3&6Q4x3X3c8H3j5h3N6W2M7#2)9J5c8X3#2S2L8U0u0Q4x3V1k6H3N6s2u0S2j5$3g2Q4x3X3f1J5i4K6u0W2K9s2c8E0L8l9`.`.

基础理论 到这了 ! 我们来进行实践:

成功的在安卓实现了 使用ptrace 对 主进程的openat的系统函数进行监控

首先还是从main开始分析:

在这个代码中一来就出现不认识的结构体 Tracee

那么我们先了解这个结构体

观察上面的结构体 ,我用ai做了翻译,很清楚的知道 Tracee 这个结构体就是被观测的进程。

我们不关注它的内存管理,我们只关心 它主要的运行逻辑。

好,那么接下来就是创建的一个 Tracee get_tracee(NULL, 0, true)这个方法

看看:

在tracee.h 存在该方法的定义:

ok,不做深入,进行下一步 parse_config这个方法

这里根据参数进行初始化,也就是对proot 后面输入的参数 进行 对应的初始化

后面启动进程:

launch_process

这里创建了 一个子进程 并且 开启了seccomp

我们看看 :enable_syscall_filtering

这里就是设置 设置seccomp过滤器 的地方

完成后就开始 主进程就开始循环处理了

event_loop()

我们跟进 handle_ptracee_event 看看它是如何处理ptrace的调用的?

然后就是对 tracee的处理handle_tracee_event

接着就是系统调用的处理了!

translate_syscall

这里面就有处理 syscall 的函数

这里就对 syscall的函数进行的修改

到这里 就基本搞清楚 proot的实现流程 与我们实现的小 demo 是基本差不多的(假的)

先进行小小的整理一下:

分主进程 与 子进程, proot 对子进程进行 attach 主进程来对 信号进行处理 以及仿真

设置 seccomp 对 ptrace的速度进行优化

那我们接下来 对 proot进行移植到安卓上!

这里使用的环境: Uabntu 22 android Studio Clion

参考实现的文章:3a2K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5%4y4V1L8W2)9J5k6h3&6W2N6q4)9J5c8V1c8W2L8X3&6&6i4K6g2X3b7$3S2W2L8W2)9#2k6W2)9J5c8X3q4J5N6r3W2U0L8r3g2Q4x3V1k6V1k6i4c8S2K9h3I4K6i4K6u0r3x3e0x3%4x3o6f1#2y4U0b7J5

我首先按照教程 ,在clion上实现 然后照猫画虎 移植到 android

cmakelist:

依赖文件 就按照 官网的把源代码下载下来。

后面我的github 会上传源码 这里就完成了proot的移植了(这里我在linux 上 编译arm64成功)

17eK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6&6N6$3H3J5x3o6l9J5x3o6b7J5x3g2)9J5c8W2)9J5k6p5q4F1k6s2u0G2K9h3c8d9k6i4k6W2M7Y4y4W2i4K6u0r3N6s2u0W2k6g2)9J5c8X3#2S2K9h3&6Q4x3V1k6b7M7X3!0G2N6q4)9J5y4f1f1%4i4K6t1#2b7V1y4Q4x3U0f1&6y4W2)9J5y4f1f1^5i4K6t1#2b7f1k6Q4x3U0f1&6x3b7`.`.

对于子进程干了那些事?

声明可跟踪性:通过 ptrace(PTRACE_TRACEME) 将当前进程标记为可被跟踪。

同步状态:通过 SIGSTOP 暂停自身,确保 tracer 能够捕获初始状态。

性能优化:启用 seccomp 模式(如果未禁用)。

执行目标程序:调用 execvp 替换当前进程为目标程序。

我们主要的侧重点 应该放在 event_loop()这个循环里面干的事!

这个event_loop() 到底干了什么:

在主事件循环 中,就设计到 处理 进程的syscall调用,以及对ptrace的仿真。

下面对他进行 模块化分析 方便后续满足自己项目的需要

设想一个ptrace函数触发

那么会出现在 event_loop() 的这个部分进行判断

会判断这里是不是有tracee->as_ptracee.ptracer 存在

那么一开始 在前面 我也没看到对这个设置的代码 猜测 在系统调用的处理handle_tracee_event

首先会调用 translate_syscall_enter 这个函数

确实存在对ptrace的处理

后面的处理

处理就是将ptrace的 中断调用号变成 0 ? 大概就是设置成无效吧

当然 这是处理前

还有函数调用后呢

translate_syscall_exit(Tracee *tracee) 呐,这个就是了

跟进translate_ptrace_exit

这段代码就非常长了 ,显然就是在模拟ptrace了

这里确实与之前 猜测的一样

这个代码 就设置 上了as_ptracee.ptracer 就对上了 event_loop

这里就可以 进入 handle_ptracee_event

这个函数也是处理ptrace的事件 只不过 是proot仿真的 仅对我们跟踪的函数有效

到这里 proot 对ptrace 的仿真就到这里了

说白了 自己维护一个假的ptrace 给 子进程用 。

我打算将proot 能用的部分拆分下来 供自己实现项目 奈何功力不足 但是柳暗花明又一村,我发现我之前看不懂的abyss项目的 demo代码 就是 魔改的proot ,天助我也。

b12K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6A6L8$3k6G2L8h3!0Q4x3V1k6S2j5Y4W2K6M7H3`.`.

发现差不多的 在循环部分 处理好tracee 进行 attach 其他地方差不多的

到这里就是 我对proot理论部分的学习了 接下来 开始 自己 的 svc hook框架搭建

上面的代码分析仅仅是我个人的观点,难免会有疏漏之处。望大佬勿喷,但欢迎指正。

https://bbs.kanxue.com/thread-275511.htm

https://bbs.kanxue.com/thread-273160.htm

12fK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2U0L8X3u0D9L8$3N6K6i4K6u0W2j5$3!0E0i4K6u0r3j5Y4g2F1L8X3g2J5i4K6u0r3M7q4)9J5c8U0p5@1z5o6M7H3y4e0R3%4i4K6u0W2K9s2c8E0L8l9`.`.

0c0K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2U0L8X3u0D9L8$3N6K6i4K6u0W2j5$3!0E0i4K6u0r3j5Y4g2F1L8X3g2J5i4K6u0r3M7q4)9J5c8U0p5@1z5o6M7@1y4o6x3&6i4K6u0W2K9s2c8E0L8l9`.`.

66bK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6Y4L8$3!0Y4L8r3g2Q4x3V1k6K6j5h3&6V1j5X3!0^5k6h3c8Q4x3X3c8S2M7r3W2Q4x3V1k6@1M7X3g2W2i4K6u0r3L8h3q4A6L8W2)9J5c8Y4y4S2L8X3c8T1L8%4S2W2k6q4)9#2k6X3q4H3K9g2)9J5c8Y4y4S2L8X3c8T1L8%4R3J5

104K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2U0L8X3u0D9L8$3N6K6i4K6u0W2j5$3!0E0i4K6u0r3L8i4W2K6K9%4V1H3x3o6N6Q4x3V1k6H3i4K6u0r3x3e0p5H3y4o6M7&6y4o6y4Q4x3X3g2Z5N6r3#2D9

de1K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2L8r3I4W2j5i4k6W2M7$3N6Q4x3X3g2@1L8%4m8Q4x3V1k6S2M7Y4c8A6j5$3I4W2i4K6u0r3b7h3&6V1M7X3!0A6k6q4)9J5k6q4y4W2j5$3y4G2L8i4m8Q4x3U0y4X3x3o6c8U0k6X3b7H3y4X3g2S2x3K6M7@1k6e0u0W2z5e0x3K6y4X3g2W2j5K6b7#2x3r3q4X3j5h3b7K6x3R3`.`.

#include <string>
#include <unistd.h>
#include <android/log.h>
#include <linux/ptrace.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/reg.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <fcntl.h>
#include <linux/filter.h>
#include <linux/seccomp.h>
#include <linux/elf.h>
#include "Syscall_arm64.h"
 
#define LOG_TAG "NDK_LOG"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
 
void test();
 
void ptrace_attach_pid(int pid);
void install_seccomp_filter(){
    struct sock_filter filter[] = {
            BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))),
            BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_openat, 0, 1),
            BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRACE),
            BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
    };
 
    struct sock_fprog prog = {
            .len = (unsigned short) (sizeof(filter) / sizeof(filter[0])),
            .filter = filter,
    };
    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
        LOGD("prctl(PR_SET_NO_NEW_PRIVS)");
    }
    if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) == -1) {
        LOGD("when setting seccomp filter");
    }
}
void test() {
    LOGD("test begin ...");
    int mainPid = getpid();
    int childPid = fork();
    switch (childPid) {
        case -1:
            LOGE("fork fail");
            break;
        case 0:
            LOGD("子进程 逻辑 %d", childPid);
            LOGD("mainPid=%d", mainPid);
            ptrace_attach_pid(mainPid);
            break;
        default:
            LOGD("主进程 逻辑 %d", mainPid);
            install_seccomp_filter();
            kill(getpid(), SIGSTOP);
            kill(getpid(), SIGCONT);
            LOGD("waitpid");
            break;
    }
    LOGD("test end ...");
 
}
 
void ptrace_attach_pid(int pid) {
    int status;
 
    if(ptrace(PTRACE_ATTACH,pid,0,0) == -1){
        LOGE("ptrace attach fail");
    }
    //设置 ptrace 选项
    const unsigned long default_ptrace_options = (
            PTRACE_O_TRACESYSGOOD |   //当被跟踪的进程产生一个系统调用时,会发送 SIGTRAP 信号,并且 siginfo 结构中的 si_code 会被设置为 SYS_SECCOMP。
            PTRACE_O_TRACEFORK | //允许跟踪进程的创建和克隆事件
            PTRACE_O_TRACEVFORK |  //允许跟踪进程的创建和克隆事件
            PTRACE_O_TRACEVFORKDONE |  //允许跟踪进程的创建和克隆事件
            PTRACE_O_TRACECLONE |  //允许跟踪进程的创建和克隆事件
            PTRACE_O_TRACEEXEC |  //允许跟踪进程的创建和克隆事件
            PTRACE_O_TRACEEXIT );  //当被跟踪的进程退出时,会触发跟踪事件
    int state;
    state = ptrace(PTRACE_SETOPTIONS, pid, 0, default_ptrace_options | PTRACE_O_TRACESECCOMP);  //这个选项特别重要,它允许跟踪 seccomp 过滤器触发的事件。当被跟踪的进程因为 seccomp 规则而触发一个 SIGSYS 信号时,会发送一个 SIGTRAP 信号,并且 siginfo 结构中的 si_code 会被设置为 SYS_SECCOMP。
    if(state == -1){
        LOGE("PTRACE_SETOPTIONS failed");
    }
    waitpid(pid, &status, 0);
    if ( WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP){
 
        while (1){
            struct user_regs_struct regs;
            struct iovec io;
            io.iov_base = &regs;
            io.iov_len = sizeof(regs);
            ptrace(PTRACE_CONT, pid, 0, 0);
            waitpid(pid, &status, 0);
            ptrace(PTRACE_GETREGSET, pid, (void*)NT_PRSTATUS, &io);
            if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8)) ){
                LOGD("seccomp svc 中断调用号 : %lx",regs.regs[8]);
                LOGD("seccomp svc 寄存器0内容: %lx",regs.regs[0]);
                LOGD("seccomp svc 寄存器1内容: %lx",regs.regs[1]);
                LOGD("seccomp svc 寄存器2内容: %lx",regs.regs[2]);
                LOGD("seccomp svc 路径内容: %s",regs.regs[1]);
            }
            if (WIFEXITED(status)){
                break;
            }
 
        }
    }
 
 
}
#include <string>
#include <unistd.h>
#include <android/log.h>
#include <linux/ptrace.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/reg.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <fcntl.h>
#include <linux/filter.h>
#include <linux/seccomp.h>
#include <linux/elf.h>
#include "Syscall_arm64.h"
 
#define LOG_TAG "NDK_LOG"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
 
void test();
 
void ptrace_attach_pid(int pid);
void install_seccomp_filter(){
    struct sock_filter filter[] = {
            BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))),
            BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_openat, 0, 1),
            BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRACE),
            BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
    };
 
    struct sock_fprog prog = {
            .len = (unsigned short) (sizeof(filter) / sizeof(filter[0])),
            .filter = filter,
    };
    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
        LOGD("prctl(PR_SET_NO_NEW_PRIVS)");
    }
    if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) == -1) {
        LOGD("when setting seccomp filter");
    }
}
void test() {
    LOGD("test begin ...");
    int mainPid = getpid();
    int childPid = fork();
    switch (childPid) {
        case -1:
            LOGE("fork fail");
            break;
        case 0:
            LOGD("子进程 逻辑 %d", childPid);
            LOGD("mainPid=%d", mainPid);
            ptrace_attach_pid(mainPid);
            break;
        default:
            LOGD("主进程 逻辑 %d", mainPid);
            install_seccomp_filter();
            kill(getpid(), SIGSTOP);
            kill(getpid(), SIGCONT);
            LOGD("waitpid");
            break;
    }
    LOGD("test end ...");
 
}
 
void ptrace_attach_pid(int pid) {
    int status;
 
    if(ptrace(PTRACE_ATTACH,pid,0,0) == -1){
        LOGE("ptrace attach fail");
    }
    //设置 ptrace 选项
    const unsigned long default_ptrace_options = (
            PTRACE_O_TRACESYSGOOD |   //当被跟踪的进程产生一个系统调用时,会发送 SIGTRAP 信号,并且 siginfo 结构中的 si_code 会被设置为 SYS_SECCOMP。
            PTRACE_O_TRACEFORK | //允许跟踪进程的创建和克隆事件
            PTRACE_O_TRACEVFORK |  //允许跟踪进程的创建和克隆事件
            PTRACE_O_TRACEVFORKDONE |  //允许跟踪进程的创建和克隆事件
            PTRACE_O_TRACECLONE |  //允许跟踪进程的创建和克隆事件
            PTRACE_O_TRACEEXEC |  //允许跟踪进程的创建和克隆事件
            PTRACE_O_TRACEEXIT );  //当被跟踪的进程退出时,会触发跟踪事件
    int state;
    state = ptrace(PTRACE_SETOPTIONS, pid, 0, default_ptrace_options | PTRACE_O_TRACESECCOMP);  //这个选项特别重要,它允许跟踪 seccomp 过滤器触发的事件。当被跟踪的进程因为 seccomp 规则而触发一个 SIGSYS 信号时,会发送一个 SIGTRAP 信号,并且 siginfo 结构中的 si_code 会被设置为 SYS_SECCOMP。
    if(state == -1){
        LOGE("PTRACE_SETOPTIONS failed");
    }
    waitpid(pid, &status, 0);
    if ( WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP){
 
        while (1){
            struct user_regs_struct regs;
            struct iovec io;
            io.iov_base = &regs;
            io.iov_len = sizeof(regs);
            ptrace(PTRACE_CONT, pid, 0, 0);
            waitpid(pid, &status, 0);
            ptrace(PTRACE_GETREGSET, pid, (void*)NT_PRSTATUS, &io);
            if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8)) ){
                LOGD("seccomp svc 中断调用号 : %lx",regs.regs[8]);
                LOGD("seccomp svc 寄存器0内容: %lx",regs.regs[0]);
                LOGD("seccomp svc 寄存器1内容: %lx",regs.regs[1]);
                LOGD("seccomp svc 寄存器2内容: %lx",regs.regs[2]);
                LOGD("seccomp svc 路径内容: %s",regs.regs[1]);
            }
            if (WIFEXITED(status)){
                break;
            }
 
        }
    }
 
 
}
/* 主函数:程序入口点
 * @argc 参数数量
 * @argv 参数值数组
 * @return 程序退出状态 */
int main(int argc, char *const argv[])
{
    Tracee *tracee;   // 被跟踪进程的上下文对象
    int status;       // 操作状态返回值
 
    /* 配置内存分配器 - 启用内存泄漏报告 */
    talloc_enable_leak_report();
 
    /* TALLOC 2.0+ 版本需要将日志输出到标准错误 */
#if defined(TALLOC_VERSION_MAJOR) && TALLOC_VERSION_MAJOR >= 2
    talloc_set_log_stderr();
#endif
 
    /* 预创建第一个被跟踪进程(初始pid设为0) */
    tracee = get_tracee(NULL, 0, true);
    if (tracee == NULL)
        goto error;
    tracee->pid = getpid();  // 设置实际进程ID
 
    /* 解析配置参数 */
    status = parse_config(tracee, argc, argv);
    if (status < 0)
        goto error;
 
    /* 启动被跟踪进程 */
    status = launch_process(tracee, &argv[status]);
    if (status < 0) {
        print_execve_help(tracee, tracee->exe, status); // 执行失败时显示帮助
        goto error;
    }
 
    /* 进入事件循环跟踪进程及其子进程 */
    exit(event_loop());  // 事件循环返回时退出程序
 
/* 错误处理模块 */
error:
    TALLOC_FREE(tracee);  // 释放跟踪对象内存
 
    /* 根据错误状态退出 */
    if (exit_failure) {
        fprintf(stderr, "致命错误:请查看 `%s --help`.\n", basename(argv[0]));
        exit(EXIT_FAILURE);
    }
    else
        exit(EXIT_SUCCESS);
}
/* 主函数:程序入口点
 * @argc 参数数量
 * @argv 参数值数组
 * @return 程序退出状态 */
int main(int argc, char *const argv[])
{
    Tracee *tracee;   // 被跟踪进程的上下文对象
    int status;       // 操作状态返回值
 
    /* 配置内存分配器 - 启用内存泄漏报告 */
    talloc_enable_leak_report();
 
    /* TALLOC 2.0+ 版本需要将日志输出到标准错误 */
#if defined(TALLOC_VERSION_MAJOR) && TALLOC_VERSION_MAJOR >= 2
    talloc_set_log_stderr();
#endif
 
    /* 预创建第一个被跟踪进程(初始pid设为0) */
    tracee = get_tracee(NULL, 0, true);
    if (tracee == NULL)
        goto error;
    tracee->pid = getpid();  // 设置实际进程ID
 
    /* 解析配置参数 */
    status = parse_config(tracee, argc, argv);
    if (status < 0)
        goto error;
 
    /* 启动被跟踪进程 */
    status = launch_process(tracee, &argv[status]);
    if (status < 0) {
        print_execve_help(tracee, tracee->exe, status); // 执行失败时显示帮助
        goto error;
    }
 
    /* 进入事件循环跟踪进程及其子进程 */
    exit(event_loop());  // 事件循环返回时退出程序
 
/* 错误处理模块 */
error:
    TALLOC_FREE(tracee);  // 释放跟踪对象内存
 
    /* 根据错误状态退出 */
    if (exit_failure) {
        fprintf(stderr, "致命错误:请查看 `%s --help`.\n", basename(argv[0]));
        exit(EXIT_FAILURE);
    }
    else
        exit(EXIT_SUCCESS);
}
typedef struct tracee {
    /**********************************************************************
     * 私有资源 (Private resources)                                       *
     **********************************************************************/
 
    /* 所有被跟踪进程(tracee)列表的链接。 */
    LIST_ENTRY(tracee) link;
 
    /* 进程标识符。 */
    pid_t pid;
 
    /* 当前是否正在运行? */
    bool running;
 
    /* 该被跟踪进程的父进程,若不存在则为NULL。 */
    struct tracee *parent;
 
    /* 是否为“克隆”进程(即与其创建者共享同一个父进程)。 */
    bool clone;
 
    /* ptrace模拟支持(跟踪器端)。 */
    struct {
        size_t nb_ptracees;              // 被ptrace跟踪的进程数量
        LIST_HEAD(zombies, tracee) zombies; // 僵尸进程列表
 
        struct direct_ptracees *direct_ptracees; // 直接跟踪的进程
 
        pid_t wait_pid;       // 等待的进程ID
        word_t wait_options;  // 等待选项
 
        /* 等待状态: */
        enum {
            DOESNT_WAIT = 0,   // 不等待
            WAITS_IN_KERNEL,   // 在内核中等待
            WAITS_IN_PROOT     // 在PRoot中等待
        } waits_in;
    } as_ptracer;
 
    /* ptrace模拟支持(被跟踪进程端)。 */
    struct {
        struct tracee *ptracer;  // 对应的跟踪器
 
        struct {
            #define STRUCT_EVENT struct { int value; bool pending; }
            STRUCT_EVENT proot;    // PRoot相关事件
            STRUCT_EVENT ptracer;  // 跟踪器相关事件
        } event4;
 
        bool tracing_started;            // 是否已启动跟踪
        bool ignore_loader_syscalls;      // 是否忽略加载器系统调用
        bool ignore_syscalls;            // 是否忽略所有系统调用
        word_t options;                   // ptrace选项
        bool is_zombie;                  // 是否为僵尸进程
    } as_ptracee;
 
    /* 当前状态:
     *        0: 进入系统调用(syscall入口)
     *        1: 系统调用正常退出(无错误)
     *   -errno: 系统调用错误退出(错误号为errno) */
    int status;
 
#define IS_IN_SYSENTER(tracee) ((tracee)->status == 0)        // 是否在系统调用入口
#define IS_IN_SYSEXIT(tracee) (!IS_IN_SYSENTER(tracee))        // 是否在系统调用退出
#define IS_IN_SYSEXIT2(tracee, sysnum) (IS_IN_SYSEXIT(tracee) \
                     &&***INAL) == sysnum) // 是否在指定系统调用的退出阶段
 
    /* 该被跟踪进程的重启方式。 */
    enum __ptrace_request restart_how;
 
    /* 被跟踪进程的通用寄存器值(多版本存储)。 */
    struct user_regs_struct _regs[NB_REG_VERSION];
    bool _regs_were_changed;           // 寄存器是否被修改
    bool restore_original_regs;        // 是否恢复原始寄存器值
 
    /* SIGSTOP信号的特殊处理状态。 */
    enum {
        SIGSTOP_IGNORED = 0,  // 忽略SIGSTOP(当父进程已知时)
        SIGSTOP_ALLOWED,       // 允许SIGSTOP(当父进程已知时)
        SIGSTOP_PENDING,       // 阻塞SIGSTOP直到父进程未知
    } sigstop;
 
    /* 用于临时动态内存分配的上下文。 */
    TALLOC_CTX *ctx;
 
    /* 用于存储生命周期内动态内存分配的上下文(进程释放时自动回收)。 */
    TALLOC_CTX *life_context;
 
    /* 注:可将"ctx"重命名为"event_span","life_context"重命名为"life_span"。 */
 
    /* 在绑定路径初始化时指定最终组件的类型(由bind_path()定义,build_glue()使用)。 */
    mode_t glue_type;
 
    /* 在子重配置期间,新配置相对于该被跟踪进程的文件系统命名空间。@paths保存其$PATH环境变量以模拟execvp(3)行为。 */
    struct {
        struct tracee *tracee;  // 关联的被跟踪进程
        const char *paths;      // 环境变量PATH值
    } reconf;
 
    /* 由PRoot在实际系统调用后插入的未请求的系统调用链。 */
    struct {
        struct chained_syscalls *syscalls;  // 链式系统调用
        bool force_final_result;            // 是否强制最终结果
        word_t final_result;                // 强制设置的最终结果
    } chain;
 
    /* 在execve系统调用入口生成,并在退出时使用的加载信息。 */
    struct load_info *load_info;
 
    /* 加载进程的当前状态。 */
    struct {
        enum {
            LOADING_STEP_NONE = 0,  // 未在加载
            LOADING_STEP_OPEN,      // 打开文件阶段
            LOADING_STEP_MMAP,      // 内存映射阶段
            LOADING_STEP_CLOSE      // 关闭文件阶段
        } step;
 
        struct load_info *info;  // 加载信息指针
        size_t index;            // 当前步骤索引
    } loading;
 
    /**********************************************************************
     * 私有但可继承的资源                                                 *
     **********************************************************************/
 
    /* 详细级别。 */
    int verbose;
 
    /* 该被跟踪进程的seccomp加速状态。 */
    enum { DISABLED = 0, DISABLING, ENABLED } seccomp;
 
    /* 确保在seccomp下始终触发系统调用退出阶段。 */
    bool sysexit_pending;
 
    /**********************************************************************
     * 共享或私有资源(取决于CLONE_FS/VM标志)                            *
     **********************************************************************/
 
    /* 文件系统命名空间相关信息。 */
    FileSystemNameSpace *fs;
 
    /* 虚拟堆(通过常规内存映射模拟)。 */
    Heap *heap;
 
    /**********************************************************************
     * 共享资源(直到该进程调用execve())                                  *
     **********************************************************************/
    /* 可执行文件路径(类似/proc/self/exe)。 */
    char *exe;
 
    /**********************************************************************
     * 共享或私有资源(取决于配置或重配置)                               *
     **********************************************************************/
 
 
    /* 模拟器(QEMU)命令行参数。 */
    char **qemu;
 
 
    /* 宿主机与客户机根文件系统之间的粘合路径。 */
    const char *glue;
  /* 为此跟踪对象启用的扩展列表。*/ struct extensions *extensions;
 
/**********************************************************************
 * 共享但只读的资源                                                  *
 **********************************************************************/
/* 在混合模式下,宿主机LD_LIBRARY_PATH会在"客户机->宿主机"转换期间被保存,
 * 以便在"宿主机->客户机"转换时恢复(仅当宿主机的LD_LIBRARY_PATH未发生变化时)。*/
const char *host_ldso_paths;
const char *guest_ldso_paths;
/* 用于诊断目的 */
const char *tool_name;
} Tracee;
typedef struct tracee {
    /**********************************************************************
     * 私有资源 (Private resources)                                       *
     **********************************************************************/
 
    /* 所有被跟踪进程(tracee)列表的链接。 */
    LIST_ENTRY(tracee) link;
 
    /* 进程标识符。 */
    pid_t pid;
 
    /* 当前是否正在运行? */
    bool running;
 
    /* 该被跟踪进程的父进程,若不存在则为NULL。 */
    struct tracee *parent;
 
    /* 是否为“克隆”进程(即与其创建者共享同一个父进程)。 */
    bool clone;
 
    /* ptrace模拟支持(跟踪器端)。 */
    struct {
        size_t nb_ptracees;              // 被ptrace跟踪的进程数量
        LIST_HEAD(zombies, tracee) zombies; // 僵尸进程列表
 
        struct direct_ptracees *direct_ptracees; // 直接跟踪的进程
 
        pid_t wait_pid;       // 等待的进程ID
        word_t wait_options;  // 等待选项
 
        /* 等待状态: */
        enum {
            DOESNT_WAIT = 0,   // 不等待
            WAITS_IN_KERNEL,   // 在内核中等待
            WAITS_IN_PROOT     // 在PRoot中等待
        } waits_in;
    } as_ptracer;
 
    /* ptrace模拟支持(被跟踪进程端)。 */
    struct {
        struct tracee *ptracer;  // 对应的跟踪器
 
        struct {
            #define STRUCT_EVENT struct { int value; bool pending; }
            STRUCT_EVENT proot;    // PRoot相关事件
            STRUCT_EVENT ptracer;  // 跟踪器相关事件
        } event4;
 
        bool tracing_started;            // 是否已启动跟踪
        bool ignore_loader_syscalls;      // 是否忽略加载器系统调用
        bool ignore_syscalls;            // 是否忽略所有系统调用
        word_t options;                   // ptrace选项
        bool is_zombie;                  // 是否为僵尸进程
    } as_ptracee;
 
    /* 当前状态:
     *        0: 进入系统调用(syscall入口)
     *        1: 系统调用正常退出(无错误)
     *   -errno: 系统调用错误退出(错误号为errno) */
    int status;
 
#define IS_IN_SYSENTER(tracee) ((tracee)->status == 0)        // 是否在系统调用入口
#define IS_IN_SYSEXIT(tracee) (!IS_IN_SYSENTER(tracee))        // 是否在系统调用退出
#define IS_IN_SYSEXIT2(tracee, sysnum) (IS_IN_SYSEXIT(tracee) \
                     &&***INAL) == sysnum) // 是否在指定系统调用的退出阶段
 
    /* 该被跟踪进程的重启方式。 */
    enum __ptrace_request restart_how;
 
    /* 被跟踪进程的通用寄存器值(多版本存储)。 */
    struct user_regs_struct _regs[NB_REG_VERSION];
    bool _regs_were_changed;           // 寄存器是否被修改
    bool restore_original_regs;        // 是否恢复原始寄存器值
 
    /* SIGSTOP信号的特殊处理状态。 */
    enum {
        SIGSTOP_IGNORED = 0,  // 忽略SIGSTOP(当父进程已知时)
        SIGSTOP_ALLOWED,       // 允许SIGSTOP(当父进程已知时)
        SIGSTOP_PENDING,       // 阻塞SIGSTOP直到父进程未知
    } sigstop;
 
    /* 用于临时动态内存分配的上下文。 */
    TALLOC_CTX *ctx;
 
    /* 用于存储生命周期内动态内存分配的上下文(进程释放时自动回收)。 */
    TALLOC_CTX *life_context;
 
    /* 注:可将"ctx"重命名为"event_span","life_context"重命名为"life_span"。 */
 
    /* 在绑定路径初始化时指定最终组件的类型(由bind_path()定义,build_glue()使用)。 */
    mode_t glue_type;
 
    /* 在子重配置期间,新配置相对于该被跟踪进程的文件系统命名空间。@paths保存其$PATH环境变量以模拟execvp(3)行为。 */
    struct {
        struct tracee *tracee;  // 关联的被跟踪进程
        const char *paths;      // 环境变量PATH值
    } reconf;
 
    /* 由PRoot在实际系统调用后插入的未请求的系统调用链。 */
    struct {
        struct chained_syscalls *syscalls;  // 链式系统调用
        bool force_final_result;            // 是否强制最终结果
        word_t final_result;                // 强制设置的最终结果
    } chain;
 
    /* 在execve系统调用入口生成,并在退出时使用的加载信息。 */
    struct load_info *load_info;
 
    /* 加载进程的当前状态。 */
    struct {
        enum {
            LOADING_STEP_NONE = 0,  // 未在加载
            LOADING_STEP_OPEN,      // 打开文件阶段
            LOADING_STEP_MMAP,      // 内存映射阶段
            LOADING_STEP_CLOSE      // 关闭文件阶段
        } step;
 
        struct load_info *info;  // 加载信息指针
        size_t index;            // 当前步骤索引
    } loading;
 
    /**********************************************************************
     * 私有但可继承的资源                                                 *
     **********************************************************************/
 
    /* 详细级别。 */
    int verbose;
 
    /* 该被跟踪进程的seccomp加速状态。 */
    enum { DISABLED = 0, DISABLING, ENABLED } seccomp;
 
    /* 确保在seccomp下始终触发系统调用退出阶段。 */
    bool sysexit_pending;
 
    /**********************************************************************
     * 共享或私有资源(取决于CLONE_FS/VM标志)                            *
     **********************************************************************/
 
    /* 文件系统命名空间相关信息。 */
    FileSystemNameSpace *fs;
 
    /* 虚拟堆(通过常规内存映射模拟)。 */
    Heap *heap;
 
    /**********************************************************************
     * 共享资源(直到该进程调用execve())                                  *
     **********************************************************************/
    /* 可执行文件路径(类似/proc/self/exe)。 */
    char *exe;
 
    /**********************************************************************
     * 共享或私有资源(取决于配置或重配置)                               *
     **********************************************************************/
 
 
    /* 模拟器(QEMU)命令行参数。 */
    char **qemu;
 
 
    /* 宿主机与客户机根文件系统之间的粘合路径。 */
    const char *glue;
  /* 为此跟踪对象启用的扩展列表。*/ struct extensions *extensions;
 
/**********************************************************************
 * 共享但只读的资源                                                  *
 **********************************************************************/
/* 在混合模式下,宿主机LD_LIBRARY_PATH会在"客户机->宿主机"转换期间被保存,
 * 以便在"宿主机->客户机"转换时恢复(仅当宿主机的LD_LIBRARY_PATH未发生变化时)。*/
const char *host_ldso_paths;
const char *guest_ldso_paths;
/* 用于诊断目的 */
const char *tool_name;
} Tracee;
/* 根据给定的进程ID查找或创建对应的Tracee结构体 */
Tracee *get_tracee(const Tracee *current_tracee, pid_t pid, bool create)
{
    Tracee *tracee;
 
    /* 如果当前正在追踪的进程就是要找的进程
     * 则直接返回当前Tracee对象,避免重置内存收集器。
     * 因为调用者可能持有子分配数据的指针 */
    if (current_tracee != NULL && current_tracee->pid == pid)
        return (Tracee *)current_tracee;
 
    /* 遍历tracees链表寻找匹配PID的Tracee对象 */
    LIST_FOREACH(tracee, &tracees, link) {
        if (tracee->pid == pid) {
            /* 释放旧的内存上下文并创建新的内存分配器
             * 使用talloc内存管理库进行内存管理 */
            TALLOC_FREE(tracee->ctx);
            tracee->ctx = talloc_new(tracee);
 
            return tracee;
        }
    }
 
    /* 如果没有找到且允许创建,则新建Tracee对象
     * 否则返回NULL */
    return (create ? new_tracee(pid) : NULL);
}
/* 根据给定的进程ID查找或创建对应的Tracee结构体 */
Tracee *get_tracee(const Tracee *current_tracee, pid_t pid, bool create)
{
    Tracee *tracee;
 
    /* 如果当前正在追踪的进程就是要找的进程
     * 则直接返回当前Tracee对象,避免重置内存收集器。
     * 因为调用者可能持有子分配数据的指针 */
    if (current_tracee != NULL && current_tracee->pid == pid)
        return (Tracee *)current_tracee;
 
    /* 遍历tracees链表寻找匹配PID的Tracee对象 */
    LIST_FOREACH(tracee, &tracees, link) {
        if (tracee->pid == pid) {
            /* 释放旧的内存上下文并创建新的内存分配器
             * 使用talloc内存管理库进行内存管理 */
            TALLOC_FREE(tracee->ctx);
            tracee->ctx = talloc_new(tracee);
 
            return tracee;
        }
    }
 
    /* 如果没有找到且允许创建,则新建Tracee对象
     * 否则返回NULL */
    return (create ? new_tracee(pid) : NULL);
}
/**
 
根据存储在@argv[]中的命令行参数配置@tracee。该函数返回@argv[]中要启动的命令的索引,若发生错误则返回-1。
*/
static int parse_config(Tracee *tracee, size_t argc, char *const argv[])
{
option_handler_t handler = NULL; // 当前选项的处理函数
const Option *options; // CLI选项列表
const Cli *cli = NULL; // 当前使用的CLI工具(CARE或PRoot)
size_t argc_offset; // 命令在argv中的起始位置
size_t i, j, k; // 循环计数器
int status; // 操作状态码
 
/* 检查是否为自解压CARE归档 */
if (get_care_cli != NULL) {
// 尝试从"/proc/self/exe"提取归档(当前可执行文件是否为CARE自解压包?)
status = extract_archive_from_file("/proc/self/exe");
if (status == 0) { // 成功提取则退出
exit_failure = 0; // 标记正常退出
return -1;
}
 
 /* 检查工具名是否为"care"(如"care-3.4") */
 if (strncasecmp(basename(argv[0]), "care", strlen("care")) == 0)
     cli = get_care_cli(tracee->ctx); // 获取CARE的CLI配置
}
 
/* 默认使用PRoot CLI */
if (cli == NULL)
cli = get_proot_cli(tracee->ctx); // 获取PRoot的CLI配置
tracee->tool_name = cli->name; // 设置工具名称(如"proot")
 
/* 参数不足时打印用法 */
if (argc == 1) {
print_usage(tracee, cli, false); // 显示帮助信息
return -1;
}
 
/* 遍历所有参数进行解析 */
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
 
复制
 /* 处理短选项的值(如 -o value,此时handler已指向处理函数) */
 if (handler != NULL) {
     status = handler(tracee, cli, arg); // 调用之前设置的处理器
     if (status < 0) return -1;     // 错误则退出
     handler = NULL;                // 重置处理器
     continue;
 }
 
 /* 遇到非选项参数(如命令),停止解析 */
 if (arg[0] != '-') break;
 
 /* 遍历所有支持的选项 */
 options = cli->options;             // 获取当前CLI的选项列表
 for (j = 0; options[j].class != NULL; j++) { // 遍历每个选项类别
     const Option *option = &options[j];
 
     /* 检查所有选项别名(如 -v 和 --verbose) */
     for (k = 0; ; k++) {            // 遍历选项的多个别名
         const Argument *argument = &option->arguments[k];
         size_t length;
 
         /* 无更多别名时跳出循环 */
         if (!argument->name) break;
 
         length = strlen(argument->name);
         if (strncmp(arg, argument->name, length) != 0)
             continue;              // 不匹配则跳过
 
         /* 处理选项与值的分隔符(如 -I/usr 或 -I /usr) */
         if (strlen(arg) > length && arg[length] != argument->separator) {
             print_error_separator(tracee, argument); // 分隔符错误(如 -I=usr)
             return -1;
         }
 
         /* 无值的选项(如 --help) */
         if (!argument->value) {
             status = option->handler(tracee, cli, NULL); // 调用处理函数
             if (status < 0) return -1;
             goto known_option;      // 跳转到后续处理
         }
 
         /* 合并值的选项(如 -I/usr,分隔符为'/') */
         if (argument->separator == arg[length]) {
             status = option->handler(tracee, cli, &arg[length + 1]); // 提取值
             if (status < 0) return -1;
             goto known_option;
         }
 
         /* 分隔符必须为空格的情况(如 -I /usr) */
         if (argument->separator != ' ') {
             print_error_separator(tracee, argument);
             return -1;
         }
 
         /* 短选项需要后续参数作为值(如 -o value) */
         handler = option->handler; // 设置处理器,等待下一个参数
         goto known_option;
     }
 }
 
 /* 未知选项处理 */
 note(tracee, ERROR, USER, "unknown option '%s'.", arg);
 return -1;
known_option:
/* 检查是否缺少选项值(如 -o 后无参数) */
if (handler != NULL && i == argc - 1) {
note(tracee, ERROR, USER, "missing value for option '%s'.", arg);
return -1;
}
}
argc_offset = i; // 记录命令起始位置(如 argv[3] 是命令名)
 
/* 通过钩子函数进行初始化阶段配置 /
#define HOOK_CONFIG(callback)
do {
if (cli->callback != NULL) {
status = cli->callback(tracee, cli, argc, argv, i);
if (status < 0) return -1;
i = status; / 可能调整参数索引 */
}
} while (0)
 
HOOK_CONFIG(pre_initialize_bindings); // 绑定初始化前处理
 
/* 解析用户绑定的路径(如 -b /host:/guest) */
status = initialize_bindings(tracee);
if (status < 0) return -1;
 
HOOK_CONFIG(post_initialize_bindings); // 绑定初始化后处理
HOOK_CONFIG(pre_initialize_cwd); // 工作目录初始化前处理
 
/* 设置当前工作目录 */
status = initialize_cwd(tracee);
if (status < 0) return -1;
 
HOOK_CONFIG(post_initialize_cwd); // 工作目录初始化后处理
HOOK_CONFIG(pre_initialize_exe); // 可执行文件初始化前处理
 
/* 解析目标可执行文件路径 */
status = initialize_exe(tracee, argv[argc_offset]);
if (status < 0) return -1;
 
HOOK_CONFIG(post_initialize_exe); // 可执行文件初始化后处理
#undef HOOK_CONFIG
 
print_config(tracee, &argv[argc_offset]); // 打印最终配置信息
 
return argc_offset; // 返回命令的argv起始索引(如 argv[3])
}
/**
 
根据存储在@argv[]中的命令行参数配置@tracee。该函数返回@argv[]中要启动的命令的索引,若发生错误则返回-1。
*/
static int parse_config(Tracee *tracee, size_t argc, char *const argv[])
{
option_handler_t handler = NULL; // 当前选项的处理函数
const Option *options; // CLI选项列表
const Cli *cli = NULL; // 当前使用的CLI工具(CARE或PRoot)
size_t argc_offset; // 命令在argv中的起始位置
size_t i, j, k; // 循环计数器
int status; // 操作状态码
 
/* 检查是否为自解压CARE归档 */
if (get_care_cli != NULL) {
// 尝试从"/proc/self/exe"提取归档(当前可执行文件是否为CARE自解压包?)
status = extract_archive_from_file("/proc/self/exe");
if (status == 0) { // 成功提取则退出
exit_failure = 0; // 标记正常退出
return -1;
}
 
 /* 检查工具名是否为"care"(如"care-3.4") */
 if (strncasecmp(basename(argv[0]), "care", strlen("care")) == 0)
     cli = get_care_cli(tracee->ctx); // 获取CARE的CLI配置
}
 
/* 默认使用PRoot CLI */
if (cli == NULL)
cli = get_proot_cli(tracee->ctx); // 获取PRoot的CLI配置
tracee->tool_name = cli->name; // 设置工具名称(如"proot")
 
/* 参数不足时打印用法 */
if (argc == 1) {
print_usage(tracee, cli, false); // 显示帮助信息
return -1;
}
 
/* 遍历所有参数进行解析 */
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
 
复制
 /* 处理短选项的值(如 -o value,此时handler已指向处理函数) */
 if (handler != NULL) {
     status = handler(tracee, cli, arg); // 调用之前设置的处理器
     if (status < 0) return -1;     // 错误则退出
     handler = NULL;                // 重置处理器
     continue;
 }
 
 /* 遇到非选项参数(如命令),停止解析 */
 if (arg[0] != '-') break;
 
 /* 遍历所有支持的选项 */
 options = cli->options;             // 获取当前CLI的选项列表
 for (j = 0; options[j].class != NULL; j++) { // 遍历每个选项类别
     const Option *option = &options[j];
 
     /* 检查所有选项别名(如 -v 和 --verbose) */
     for (k = 0; ; k++) {            // 遍历选项的多个别名
         const Argument *argument = &option->arguments[k];
         size_t length;
 
         /* 无更多别名时跳出循环 */
         if (!argument->name) break;
 
         length = strlen(argument->name);
         if (strncmp(arg, argument->name, length) != 0)
             continue;              // 不匹配则跳过
 
         /* 处理选项与值的分隔符(如 -I/usr 或 -I /usr) */
         if (strlen(arg) > length && arg[length] != argument->separator) {
             print_error_separator(tracee, argument); // 分隔符错误(如 -I=usr)
             return -1;
         }
 
         /* 无值的选项(如 --help) */
         if (!argument->value) {
             status = option->handler(tracee, cli, NULL); // 调用处理函数
             if (status < 0) return -1;
             goto known_option;      // 跳转到后续处理
         }
 
         /* 合并值的选项(如 -I/usr,分隔符为'/') */
         if (argument->separator == arg[length]) {
             status = option->handler(tracee, cli, &arg[length + 1]); // 提取值
             if (status < 0) return -1;
             goto known_option;
         }
 
         /* 分隔符必须为空格的情况(如 -I /usr) */
         if (argument->separator != ' ') {
             print_error_separator(tracee, argument);
             return -1;
         }
 
         /* 短选项需要后续参数作为值(如 -o value) */
         handler = option->handler; // 设置处理器,等待下一个参数
         goto known_option;
     }
 }
 
 /* 未知选项处理 */
 note(tracee, ERROR, USER, "unknown option '%s'.", arg);
 return -1;
known_option:
/* 检查是否缺少选项值(如 -o 后无参数) */
if (handler != NULL && i == argc - 1) {
note(tracee, ERROR, USER, "missing value for option '%s'.", arg);
return -1;
}
}
argc_offset = i; // 记录命令起始位置(如 argv[3] 是命令名)
 
/* 通过钩子函数进行初始化阶段配置 /
#define HOOK_CONFIG(callback)
do {
if (cli->callback != NULL) {
status = cli->callback(tracee, cli, argc, argv, i);
if (status < 0) return -1;
i = status; / 可能调整参数索引 */
}
} while (0)
 
HOOK_CONFIG(pre_initialize_bindings); // 绑定初始化前处理
 
/* 解析用户绑定的路径(如 -b /host:/guest) */
status = initialize_bindings(tracee);
if (status < 0) return -1;
 
HOOK_CONFIG(post_initialize_bindings); // 绑定初始化后处理
HOOK_CONFIG(pre_initialize_cwd); // 工作目录初始化前处理
 
/* 设置当前工作目录 */
status = initialize_cwd(tracee);
if (status < 0) return -1;
 
HOOK_CONFIG(post_initialize_cwd); // 工作目录初始化后处理
HOOK_CONFIG(pre_initialize_exe); // 可执行文件初始化前处理
 
/* 解析目标可执行文件路径 */
status = initialize_exe(tracee, argv[argc_offset]);
if (status < 0) return -1;
 
HOOK_CONFIG(post_initialize_exe); // 可执行文件初始化后处理
#undef HOOK_CONFIG
 
print_config(tracee, &argv[argc_offset]); // 打印最终配置信息
 
return argc_offset; // 返回命令的argv起始索引(如 argv[3])
}
/**
 * 启动 @tracee->exe 并使用给定的 @argv[] 参数。此函数在发生错误时返回 -errno,否则返回 0。
 */
int launch_process(Tracee *tracee, char *const argv[])
{
    char *const default_argv[] = { "-", NULL };
    long status;
    pid_t pid;
 
    /* Warn about open file descriptors. They won't be
     * translated until they are closed. */
    if (tracee->verbose > 0)
        list_open_fd(tracee);
 
    pid = fork();
    switch(pid) {
    case -1:
        note(tracee, ERROR, SYSTEM, "fork()");
        return -errno;
 
    case 0: /* child */
        /* Declare myself as ptraceable before executing the
         * requested program. */
        status = ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        if (status < 0) {
            note(tracee, ERROR, SYSTEM, "ptrace(TRACEME)");
            return -errno;
        }
 
        /* Synchronize with the tracer's event loop.  Without
         * this trick the tracer only sees the "return" from
         * the next execve(2) so PRoot wouldn't handle the
         * interpreter/runner.  I also verified that strace
         * does the same thing. */
        kill(getpid(), SIGSTOP);
 
        /* Improve performance by using seccomp mode 2, unless
         * this support is explicitly disabled.  */
        if (getenv("PROOT_NO_SECCOMP") == NULL)
            (void) enable_syscall_filtering(tracee);
 
        /* Now process is ptraced, so the current rootfs is already the
         * guest rootfs.  Note: Valgrind can't handle execve(2) on
         * "foreign" binaries (ENOEXEC) but can handle execvp(3) on such
         * binaries.  */
        execvp(tracee->exe, argv[0] != NULL ? argv : default_argv);
        return -errno;
 
    default: /* parent */
        /* We know the pid of the first tracee now.  */
        tracee->pid = pid;
        return 0;
    }
 
    /* Never reached.  */
    return -ENOSYS;
}
/**
 * 启动 @tracee->exe 并使用给定的 @argv[] 参数。此函数在发生错误时返回 -errno,否则返回 0。
 */
int launch_process(Tracee *tracee, char *const argv[])
{
    char *const default_argv[] = { "-", NULL };
    long status;
    pid_t pid;
 
    /* Warn about open file descriptors. They won't be
     * translated until they are closed. */
    if (tracee->verbose > 0)
        list_open_fd(tracee);
 
    pid = fork();
    switch(pid) {
    case -1:
        note(tracee, ERROR, SYSTEM, "fork()");
        return -errno;
 
    case 0: /* child */
        /* Declare myself as ptraceable before executing the
         * requested program. */
        status = ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        if (status < 0) {
            note(tracee, ERROR, SYSTEM, "ptrace(TRACEME)");
            return -errno;
        }
 
        /* Synchronize with the tracer's event loop.  Without
         * this trick the tracer only sees the "return" from
         * the next execve(2) so PRoot wouldn't handle the
         * interpreter/runner.  I also verified that strace
         * does the same thing. */
        kill(getpid(), SIGSTOP);
 
        /* Improve performance by using seccomp mode 2, unless
         * this support is explicitly disabled.  */
        if (getenv("PROOT_NO_SECCOMP") == NULL)
            (void) enable_syscall_filtering(tracee);
 
        /* Now process is ptraced, so the current rootfs is already the
         * guest rootfs.  Note: Valgrind can't handle execve(2) on
         * "foreign" binaries (ENOEXEC) but can handle execvp(3) on such
         * binaries.  */
        execvp(tracee->exe, argv[0] != NULL ? argv : default_argv);
        return -errno;
 
    default: /* parent */
        /* We know the pid of the first tracee now.  */
        tracee->pid = pid;
        return 0;
    }
 
    /* Never reached.  */
    return -ENOSYS;
}
/**
 * 通知内核仅跟踪由PRoot及其扩展处理的系统调用。
 * 该过滤器将对给定的@tracee及其所有未来子进程生效。
 * 如果发生错误,该函数返回-errno,否则返回0。
 */
int enable_syscall_filtering(const Tracee *tracee)
{
    FilteredSysnum *filtered_sysnums = NULL; // 被过滤的系统调用号列表
    Extension *extension;                     // 扩展模块指针
    int status;                              // 操作状态码
 
    // 断言确保tracee及其上下文不为空
    assert(tracee != NULL && tracee->ctx != NULL);
 
    /* 将PRoot需要的系统调用号添加到过滤列表。
     * TODO: 仅在需要路径转换时添加 */
    status = merge_filtered_sysnums(tracee->ctx, &filtered_sysnums, proot_sysnums);
    if (status < 0)
        return status;
 
    /* 将扩展模块需要的系统调用号合并到过滤列表 */
    if (tracee->extensions != NULL) {
        // 遍历所有扩展模块
        LIST_FOREACH(extension, tracee->extensions, link) {
            if (extension->filtered_sysnums == NULL)
                continue;
 
            // 合并当前扩展的过滤列表
            status = merge_filtered_sysnums(tracee->ctx, &filtered_sysnums,
                            extension->filtered_sysnums);
            if (status < 0)
                return status;
        }
    }
 
    // 设置seccomp过滤器
    status = set_seccomp_filters(filtered_sysnums);
    if (status < 0)
        return status;
 
    return 0; // 成功返回0
}
/**
 * 通知内核仅跟踪由PRoot及其扩展处理的系统调用。
 * 该过滤器将对给定的@tracee及其所有未来子进程生效。
 * 如果发生错误,该函数返回-errno,否则返回0。
 */
int enable_syscall_filtering(const Tracee *tracee)
{
    FilteredSysnum *filtered_sysnums = NULL; // 被过滤的系统调用号列表
    Extension *extension;                     // 扩展模块指针
    int status;                              // 操作状态码
 
    // 断言确保tracee及其上下文不为空
    assert(tracee != NULL && tracee->ctx != NULL);
 
    /* 将PRoot需要的系统调用号添加到过滤列表。
     * TODO: 仅在需要路径转换时添加 */
    status = merge_filtered_sysnums(tracee->ctx, &filtered_sysnums, proot_sysnums);
    if (status < 0)
        return status;
 
    /* 将扩展模块需要的系统调用号合并到过滤列表 */
    if (tracee->extensions != NULL) {
        // 遍历所有扩展模块
        LIST_FOREACH(extension, tracee->extensions, link) {
            if (extension->filtered_sysnums == NULL)
                continue;
 
            // 合并当前扩展的过滤列表
            status = merge_filtered_sysnums(tracee->ctx, &filtered_sysnums,
                            extension->filtered_sysnums);
            if (status < 0)
                return status;
        }
    }
 
    // 设置seccomp过滤器
    status = set_seccomp_filters(filtered_sysnums);
    if (status < 0)
        return status;
 
    return 0; // 成功返回0
}
/**
 * 等待并处理来自所有被跟踪进程(tracees)的事件。本函数返回最后一个终止程序的退出状态。
 */
int event_loop()
{
    struct sigaction signal_action;
    long status;
    int signum;
 
    /* 退出时杀死所有被跟踪进程 */
    status = atexit(kill_all_tracees);
    if (status != 0)
        note(NULL, WARNING, INTERNAL, "atexit() 失败");
 
    /* 信号处理函数被调用时会阻塞所有信号。
     * 使用 SIGINFO 标识进程信号来源,RESTART 标识无缝重启 waitpid(2) */
    bzero(&signal_action, sizeof(signal_action));
    signal_action.sa_flags = SA_SIGINFO | SA_RESTART;
    status = sigfillset(&signal_action.sa_mask);
    if (status < 0)
        note(NULL, WARNING, SYSTEM, "sigfillset() 错误");
 
    /* 遍历所有可能的信号并配置处理方式 */
    for (signum = 0; signum < SIGRTMAX; signum++) {
        switch (signum) {
        case SIGQUIT:  // 终止请求信号
        case SIGILL:   // 非法指令
        case SIGABRT:  // 异常中止
        case SIGFPE:   // 算术错误
        case SIGSEGV:  // 段错误
            /* 在异常终止信号时杀死所有被跟踪进程,确保无残留 */
            signal_action.sa_sigaction = kill_all_tracees2;
            break;
 
        case SIGUSR1:  // 用户自定义信号1
        case SIGUSR2:  // 用户自定义信号2
            /* 调试用:在 stderr 打印完整 talloc 内存层级 */
            signal_action.sa_sigaction = print_talloc_hierarchy;
            break;
 
        case SIGCHLD:   // 子进程状态变化
        case SIGCONT:   // 继续执行
        case SIGSTOP:   // 停止进程
        case SIGTSTP:   // 终端停止请求
        case SIGTTIN:   // 后台读终端
        case SIGTTOU:   // 后台写终端
            /* 保留与终端和作业控制相关信号的默认行为 */
            continue;
 
        default:
            /* 忽略其他信号(如终止信号 SIGINT/^C) */
            signal_action.sa_sigaction = (void *)SIG_IGN;
            break;
        }
 
        /* 注册信号处理函数 */
        status = sigaction(signum, &signal_action, NULL);
        if (status < 0 && errno != EINVAL)
            note(NULL, WARNING, SYSTEM, "sigaction(%d) 错误", signum);
    }
 
    /* 主事件循环 */
    while (1) {
        int tracee_status;  // 被跟踪进程状态
        Tracee *tracee;      // 被跟踪进程对象
        int signal;          // 接收到的信号
        pid_t pid;           // 进程ID
 
        /* 等待任意被跟踪进程的状态变化 */
        pid = waitpid(-1, &tracee_status, __WALL);
        if (pid < 0) {
            if (errno != ECHILD) {  // 无子进程时正常退出
                note(NULL, ERROR, SYSTEM, "waitpid() 错误");
                return EXIT_FAILURE;
            }
            break// 所有子进程已退出,结束循环
        }
 
        /* 获取对应被跟踪进程的信息 */
        tracee = get_tracee(NULL, pid, true);
        assert(tracee != NULL);
 
        tracee->running = false// 标记为停止状态
 
        /* 通知扩展模块处理新状态 */
        status = notify_extensions(tracee, NEW_STATUS, tracee_status, 0);
        if (status != 0)
            continue;
 
        /* 处理来自 ptrace 的事件 */
        if (tracee->as_ptracee.ptracer != NULL) {
            bool keep_stopped = handle_ptracee_event(tracee, tracee_status);
            if (keep_stopped)
                continue// 需要保持停止状态,不重启进程
        }
 
        /* 处理事件并获取需传递的信号 */
        signal = handle_tracee_event(tracee, tracee_status);
        /* 重启被跟踪进程(可能附带信号) */
        (void) restart_tracee(tracee, signal);
    }
 
    return last_exit_status;  // 返回最后一个退出状态码
}
/**
 * 等待并处理来自所有被跟踪进程(tracees)的事件。本函数返回最后一个终止程序的退出状态。
 */
int event_loop()
{
    struct sigaction signal_action;
    long status;
    int signum;
 
    /* 退出时杀死所有被跟踪进程 */
    status = atexit(kill_all_tracees);
    if (status != 0)
        note(NULL, WARNING, INTERNAL, "atexit() 失败");
 
    /* 信号处理函数被调用时会阻塞所有信号。
     * 使用 SIGINFO 标识进程信号来源,RESTART 标识无缝重启 waitpid(2) */
    bzero(&signal_action, sizeof(signal_action));
    signal_action.sa_flags = SA_SIGINFO | SA_RESTART;
    status = sigfillset(&signal_action.sa_mask);
    if (status < 0)
        note(NULL, WARNING, SYSTEM, "sigfillset() 错误");
 
    /* 遍历所有可能的信号并配置处理方式 */
    for (signum = 0; signum < SIGRTMAX; signum++) {
        switch (signum) {
        case SIGQUIT:  // 终止请求信号
        case SIGILL:   // 非法指令
        case SIGABRT:  // 异常中止
        case SIGFPE:   // 算术错误
        case SIGSEGV:  // 段错误
            /* 在异常终止信号时杀死所有被跟踪进程,确保无残留 */
            signal_action.sa_sigaction = kill_all_tracees2;
            break;
 
        case SIGUSR1:  // 用户自定义信号1
        case SIGUSR2:  // 用户自定义信号2
            /* 调试用:在 stderr 打印完整 talloc 内存层级 */
            signal_action.sa_sigaction = print_talloc_hierarchy;
            break;
 
        case SIGCHLD:   // 子进程状态变化
        case SIGCONT:   // 继续执行
        case SIGSTOP:   // 停止进程
        case SIGTSTP:   // 终端停止请求
        case SIGTTIN:   // 后台读终端
        case SIGTTOU:   // 后台写终端
            /* 保留与终端和作业控制相关信号的默认行为 */
            continue;
 
        default:
            /* 忽略其他信号(如终止信号 SIGINT/^C) */
            signal_action.sa_sigaction = (void *)SIG_IGN;
            break;
        }
 
        /* 注册信号处理函数 */
        status = sigaction(signum, &signal_action, NULL);
        if (status < 0 && errno != EINVAL)
            note(NULL, WARNING, SYSTEM, "sigaction(%d) 错误", signum);
    }
 
    /* 主事件循环 */
    while (1) {
        int tracee_status;  // 被跟踪进程状态
        Tracee *tracee;      // 被跟踪进程对象
        int signal;          // 接收到的信号
        pid_t pid;           // 进程ID
 
        /* 等待任意被跟踪进程的状态变化 */
        pid = waitpid(-1, &tracee_status, __WALL);
        if (pid < 0) {
            if (errno != ECHILD) {  // 无子进程时正常退出
                note(NULL, ERROR, SYSTEM, "waitpid() 错误");
                return EXIT_FAILURE;
            }
            break// 所有子进程已退出,结束循环
        }
 
        /* 获取对应被跟踪进程的信息 */
        tracee = get_tracee(NULL, pid, true);
        assert(tracee != NULL);
 
        tracee->running = false// 标记为停止状态
 
        /* 通知扩展模块处理新状态 */
        status = notify_extensions(tracee, NEW_STATUS, tracee_status, 0);
        if (status != 0)
            continue;
 
        /* 处理来自 ptrace 的事件 */
        if (tracee->as_ptracee.ptracer != NULL) {
            bool keep_stopped = handle_ptracee_event(tracee, tracee_status);
            if (keep_stopped)
                continue// 需要保持停止状态,不重启进程
        }
 
        /* 处理事件并获取需传递的信号 */
        signal = handle_tracee_event(tracee, tracee_status);
        /* 重启被跟踪进程(可能附带信号) */
        (void) restart_tracee(tracee, signal);
    }
 
    return last_exit_status;  // 返回最后一个退出状态码
}
/**
 * 对于给定的被跟踪进程 @ptracee,如果其跟踪者(ptracer)正在等待当前 @event,
 * 则将事件传递给跟踪者;否则将 @ptracee 置为“等待跟踪者”状态。
 * 返回值表示是否应保持 @ptracee 的停止状态。
 */
bool handle_ptracee_event(Tracee *ptracee, int event)
{
    bool handled_by_proot_first = false// 标记事件是否需要由PRoot优先处理
    Tracee *ptracer = PTRACEE.ptracer;    // 获取跟踪者(父进程)
    bool keep_stopped;                    // 返回值:是否保持停止状态
 
    assert(ptracer != NULL);              // 确保跟踪者存在
 
    /* 保存原始事件信息,供PRoot后续处理 */
    PTRACEE.event4.proot.value   = event;  // 存储事件值
    PTRACEE.event4.proot.pending = true;   // 标记事件待处理
 
    /* 默认情况下,保持ptracee停止,直到跟踪者恢复它 */
    keep_stopped = true;
 
    /* 处理因信号停止的事件(WIFSTOPPED) */
    if (WIFSTOPPED(event)) {
        switch ((event & 0xfff00) >> 8) {  // 提取高位信号类型
        case SIGTRAP | 0x80:              // 系统调用退出事件(带syscall-good标志)
            if (PTRACEE.ignore_syscalls || PTRACEE.ignore_loader_syscalls)
                return false;              // 若忽略系统调用,直接返回不保持停止
 
            if ((PTRACEE.options & PTRACE_O_TRACESYSGOOD) == 0)  // 未启用TRACESYSGOOD
                event &= ~(0x80 << 8);     // 清除高位标志
 
            handled_by_proot_first = IS_IN_SYSEXIT(ptracee);  // 系统调用退出阶段由PRoot处理
            break;
 
        // 宏定义:处理特定跟踪事件(FORK/VFORK等)
#define PTRACE_EVENT_VFORKDONE PTRACE_EVENT_VFORK_DONE  // 兼容性定义
#define CASE_FILTER_EVENT(name) \
        case SIGTRAP | PTRACE_EVENT_ ##name << 8:       \
            if ((PTRACEE.options & PTRACE_O_TRACE ##name) == 0) \  // 未启用对应跟踪选项
                return false;                           \
            PTRACEE.tracing_started = true;             \  // 标记跟踪已开始
            handled_by_proot_first = true;               \  // PRoot优先处理
            break;
 
        CASE_FILTER_EVENT(FORK);     // 处理进程fork事件
        CASE_FILTER_EVENT(VFORK);    // 处理vfork事件
        CASE_FILTER_EVENT(VFORKDONE);// 处理vfork完成事件
        CASE_FILTER_EVENT(CLONE);    // 处理clone事件
        CASE_FILTER_EVENT(EXIT);     // 处理进程退出事件
        CASE_FILTER_EVENT(EXEC);     // 处理exec事件
 
        /* 以下代码不可达,触发断言 */
        assert(0);
 
        // 不支持的事件类型(如seccomp)
        case SIGTRAP | PTRACE_EVENT_SECCOMP2 << 8:
        case SIGTRAP | PTRACE_EVENT_SECCOMP << 8:
            return false// 直接返回不处理
 
        default// 其他信号停止事件
            PTRACEE.tracing_started = true// 标记跟踪开始
            break;
        }
    }
    /* 处理进程退出或信号终止事件 */
    else if (WIFEXITED(event) || WIFSIGNALED(event)) {
        PTRACEE.tracing_started = true// 标记跟踪已开始
        keep_stopped = false;            // 进程已终止,无需保持停止
    }
 
    /* 若跟踪尚未开始(如TRACEME后首次事件),直接返回 */
    if (!PTRACEE.tracing_started)
        return false;
 
    /* PRoot优先处理事件(如系统调用退出) */
    if (handled_by_proot_first) {
        int signal = handle_tracee_event(ptracee, PTRACEE.event4.proot.value);
        PTRACEE.event4.proot.value = signal// 更新处理后的信号值
        assert(signal == 0);  // 当前逻辑下信号应为0(如sysexit无需传递信号)
    }
 
    /* 保存处理后的事件信息,供跟踪者使用 */
    PTRACEE.event4.ptracer.value   = event;    // 记录最终事件值
    PTRACEE.event4.ptracer.pending = true;     // 标记事件待跟踪者处理
 
    /* 异步通知跟踪者(发送SIGCHLD模拟内核行为) */
    kill(ptracer->pid, SIGCHLD);
 
    /* 若跟踪者正在等待此ptracee的事件 */
    if ((PTRACER.wait_pid == -1 || PTRACER.wait_pid == ptracee->pid) &&
        EXPECTED_WAIT_CLONE(PTRACER.wait_options, ptracee)) {
        bool restarted;
        int status = update_wait_status(ptracer, ptracee);  // 更新等待状态
        poke_reg(ptracer, SYSARG_RESULT, (word_t) status);  // 修改寄存器返回值
 
        (void) push_regs(ptracer);  // 写回寄存器缓存
 
        /* 重启跟踪者进程 */
        PTRACER.wait_pid = 0;
        restarted = restart_tracee(ptracer, 0);  // 尝试恢复跟踪者执行
        if (!restarted)  // 重启失败则不再保持停止
            keep_stopped = false;
    }
 
    return keep_stopped;  // 返回是否保持ptracee停止
}
 
// 关键逻辑说明:
// 1. 事件分层处理:
//    - 原始事件(如系统调用退出)先由PRoot处理(如模拟执行后清理)
//    - 处理后的事件转发给跟踪者(如GDB),模拟内核的ptrace事件传递
//
// 2. 状态同步机制:
//    - 通过SIGCHLD通知跟踪者有事件待处理
//    - 若跟踪者正在waitpid,直接更新其寄存器状态并唤醒,减少延迟
//
// 3. 停止状态决策:
//    - 进程终止(EXITED/SIGNALED)时必须返回false,防止僵尸进程滞留
//    - 默认保持停止,直到跟踪者显式调用PTRACE_CONT
//
// 潜在问题:
// 1. 事件掩码计算:
//    - `(event & 0xfff00) >> 8` 假设高位存储事件类型,需确保与内核实现一致
//    - 若PTRACE_EVENT_* 的编码方式变化,可能导致错误过滤
//
// 2. 异步竞争条件:
//    - kill()发送SIGCHLD后,跟踪者可能尚未进入waitpid,导致信号丢失
//    - 需依赖内核的ptrace语义保证事件不会丢失
//
// 3. 宏展开风险:
//    - CASE_FILTER_EVENT(EXEC) 展开后依赖PTRACE_O_TRACEEXEC选项的存在
//    - 若PTrace实现不兼容某些选项,需添加条件编译
/**
 * 对于给定的被跟踪进程 @ptracee,如果其跟踪者(ptracer)正在等待当前 @event,
 * 则将事件传递给跟踪者;否则将 @ptracee 置为“等待跟踪者”状态。
 * 返回值表示是否应保持 @ptracee 的停止状态。
 */
bool handle_ptracee_event(Tracee *ptracee, int event)
{
    bool handled_by_proot_first = false// 标记事件是否需要由PRoot优先处理
    Tracee *ptracer = PTRACEE.ptracer;    // 获取跟踪者(父进程)
    bool keep_stopped;                    // 返回值:是否保持停止状态
 
    assert(ptracer != NULL);              // 确保跟踪者存在
 
    /* 保存原始事件信息,供PRoot后续处理 */
    PTRACEE.event4.proot.value   = event;  // 存储事件值
    PTRACEE.event4.proot.pending = true;   // 标记事件待处理
 
    /* 默认情况下,保持ptracee停止,直到跟踪者恢复它 */
    keep_stopped = true;
 
    /* 处理因信号停止的事件(WIFSTOPPED) */
    if (WIFSTOPPED(event)) {
        switch ((event & 0xfff00) >> 8) {  // 提取高位信号类型
        case SIGTRAP | 0x80:              // 系统调用退出事件(带syscall-good标志)
            if (PTRACEE.ignore_syscalls || PTRACEE.ignore_loader_syscalls)
                return false;              // 若忽略系统调用,直接返回不保持停止
 
            if ((PTRACEE.options & PTRACE_O_TRACESYSGOOD) == 0)  // 未启用TRACESYSGOOD
                event &= ~(0x80 << 8);     // 清除高位标志
 
            handled_by_proot_first = IS_IN_SYSEXIT(ptracee);  // 系统调用退出阶段由PRoot处理
            break;
 
        // 宏定义:处理特定跟踪事件(FORK/VFORK等)
#define PTRACE_EVENT_VFORKDONE PTRACE_EVENT_VFORK_DONE  // 兼容性定义
#define CASE_FILTER_EVENT(name) \
        case SIGTRAP | PTRACE_EVENT_ ##name << 8:       \
            if ((PTRACEE.options & PTRACE_O_TRACE ##name) == 0) \  // 未启用对应跟踪选项
                return false;                           \
            PTRACEE.tracing_started = true;             \  // 标记跟踪已开始
            handled_by_proot_first = true;               \  // PRoot优先处理
            break;
 
        CASE_FILTER_EVENT(FORK);     // 处理进程fork事件
        CASE_FILTER_EVENT(VFORK);    // 处理vfork事件
        CASE_FILTER_EVENT(VFORKDONE);// 处理vfork完成事件
        CASE_FILTER_EVENT(CLONE);    // 处理clone事件
        CASE_FILTER_EVENT(EXIT);     // 处理进程退出事件
        CASE_FILTER_EVENT(EXEC);     // 处理exec事件
 
        /* 以下代码不可达,触发断言 */
        assert(0);
 
        // 不支持的事件类型(如seccomp)
        case SIGTRAP | PTRACE_EVENT_SECCOMP2 << 8:
        case SIGTRAP | PTRACE_EVENT_SECCOMP << 8:
            return false// 直接返回不处理
 
        default// 其他信号停止事件
            PTRACEE.tracing_started = true// 标记跟踪开始
            break;
        }
    }
    /* 处理进程退出或信号终止事件 */
    else if (WIFEXITED(event) || WIFSIGNALED(event)) {
        PTRACEE.tracing_started = true// 标记跟踪已开始
        keep_stopped = false;            // 进程已终止,无需保持停止
    }
 
    /* 若跟踪尚未开始(如TRACEME后首次事件),直接返回 */
    if (!PTRACEE.tracing_started)
        return false;
 
    /* PRoot优先处理事件(如系统调用退出) */
    if (handled_by_proot_first) {
        int signal = handle_tracee_event(ptracee, PTRACEE.event4.proot.value);
        PTRACEE.event4.proot.value = signal// 更新处理后的信号值
        assert(signal == 0);  // 当前逻辑下信号应为0(如sysexit无需传递信号)
    }
 
    /* 保存处理后的事件信息,供跟踪者使用 */
    PTRACEE.event4.ptracer.value   = event;    // 记录最终事件值
    PTRACEE.event4.ptracer.pending = true;     // 标记事件待跟踪者处理
 
    /* 异步通知跟踪者(发送SIGCHLD模拟内核行为) */
    kill(ptracer->pid, SIGCHLD);
 
    /* 若跟踪者正在等待此ptracee的事件 */
    if ((PTRACER.wait_pid == -1 || PTRACER.wait_pid == ptracee->pid) &&
        EXPECTED_WAIT_CLONE(PTRACER.wait_options, ptracee)) {
        bool restarted;
        int status = update_wait_status(ptracer, ptracee);  // 更新等待状态
        poke_reg(ptracer, SYSARG_RESULT, (word_t) status);  // 修改寄存器返回值
 
        (void) push_regs(ptracer);  // 写回寄存器缓存
 
        /* 重启跟踪者进程 */
        PTRACER.wait_pid = 0;
        restarted = restart_tracee(ptracer, 0);  // 尝试恢复跟踪者执行
        if (!restarted)  // 重启失败则不再保持停止
            keep_stopped = false;
    }
 
    return keep_stopped;  // 返回是否保持ptracee停止
}
 
// 关键逻辑说明:
// 1. 事件分层处理:
//    - 原始事件(如系统调用退出)先由PRoot处理(如模拟执行后清理)
//    - 处理后的事件转发给跟踪者(如GDB),模拟内核的ptrace事件传递
//
// 2. 状态同步机制:
//    - 通过SIGCHLD通知跟踪者有事件待处理
//    - 若跟踪者正在waitpid,直接更新其寄存器状态并唤醒,减少延迟
//
// 3. 停止状态决策:
//    - 进程终止(EXITED/SIGNALED)时必须返回false,防止僵尸进程滞留
//    - 默认保持停止,直到跟踪者显式调用PTRACE_CONT
//
// 潜在问题:
// 1. 事件掩码计算:
//    - `(event & 0xfff00) >> 8` 假设高位存储事件类型,需确保与内核实现一致
//    - 若PTRACE_EVENT_* 的编码方式变化,可能导致错误过滤
//
// 2. 异步竞争条件:
//    - kill()发送SIGCHLD后,跟踪者可能尚未进入waitpid,导致信号丢失
//    - 需依赖内核的ptrace语义保证事件不会丢失
//
// 3. 宏展开风险:
//    - CASE_FILTER_EVENT(EXEC) 展开后依赖PTRACE_O_TRACEEXEC选项的存在
//    - 若PTrace实现不兼容某些选项,需添加条件编译
/**
 * 处理被跟踪进程(tracee)的当前事件(@tracee_status)。该函数返回用于恢复该进程执行的"计算"信号。
 */
int handle_tracee_event(Tracee *tracee, int tracee_status)
{
    static bool seccomp_detected = false// 静态标志位,检测是否启用seccomp
    pid_t pid = tracee->pid;               // 获取被跟踪进程的PID
    long status;                           // 系统调用状态
    int signal;                            // 要发送的信号
 
 
    /* 如果重启方式未被显式设置(例如在单步调试的ptrace模拟中),
       则自动设置默认值 */
    if (tracee->restart_how == 0) {
        /* 当启用seccomp时,所有事件在非停止模式下重启,但后续可能需要修改。
           检查"sysexit_pending"确保不会因其他事件(如execve退出的PTRACE_EVENT_EXEC)
           清除用于seccomp退出阶段的PTRACE_SYSCALL */
        if (tracee->seccomp == ENABLED && !tracee->sysexit_pending)
            tracee->restart_how = PTRACE_CONT;   // 继续执行
        else
            tracee->restart_how = PTRACE_SYSCALL; // 在下一个系统调用时停止
    }
 
 
    /* 默认不是信号触发的停止 */
    signal = 0;
 
 
    // 处理进程退出状态
    if (WIFEXITED(tracee_status)) {
        last_exit_status = WEXITSTATUS(tracee_status);
        VERBOSE(tracee, 1, "进程 %d:已退出,状态码 %d", pid, last_exit_status);
    }
    // 处理信号终止
    else if (WIFSIGNALED(tracee_status)) {
        check_architecture(tracee);
        VERBOSE(tracee, (int) (last_exit_status != -1),
            "进程 %d:被信号 %d 终止", pid, WTERMSIG(tracee_status));
    }
    // 处理停止状态
    else if (WIFSTOPPED(tracee_status)) {
        /* 不使用WSTOPSIG()提取信号,因为它会清除PTRACE_EVENT_*标志位 */
        signal = (tracee_status & 0xfff00) >> 8;  // 解码信号
 
 
        switch (signal) {
            static bool deliver_sigtrap = false// 静态标志控制SIGTRAP传递
 
 
        case SIGTRAP: {  // 断点/单步异常
            // 默认ptrace监控选项
            const unsigned long default_ptrace_options = (
                PTRACE_O_TRACESYSGOOD   |  // 系统调用时发送SIGTRAP|0x80
                PTRACE_O_TRACEFORK      |  // 跟踪fork
                PTRACE_O_TRACEVFORK     |  // 跟踪vfork
                PTRACE_O_TRACEVFORKDONE |  // vfork完成跟踪
                PTRACE_O_TRACEEXEC      |  // 跟踪exec
                PTRACE_O_TRACECLONE     |  // 跟踪clone
                PTRACE_O_TRACEEXIT);      // 跟踪进程退出
 
 
            /* 区分不同事件类型,自动为新进程设置相同跟踪选项
               只有第一个纯SIGTRAP与跟踪循环相关,其他SIGTRAP携带
               TRACE*FORK/CLONE/EXEC的跟踪信息 */
            if (deliver_sigtrap)
                break// 直接传递该信号
 
 
            deliver_sigtrap = true;
 
 
            /* 尝试启用seccomp模式2... */
            status = ptrace(PTRACE_SETOPTIONS, tracee->pid, NULL,
                    default_ptrace_options | PTRACE_O_TRACESECCOMP);
            if (status < 0) {
                /* ...否则仅使用默认选项 */
                status = ptrace(PTRACE_SETOPTIONS, tracee->pid, NULL,
                        default_ptrace_options);
                if (status < 0) {
                    note(tracee, ERROR, SYSTEM, "ptrace(PTRACE_SETOPTIONS失败)");
                    exit(EXIT_FAILURE);
                }
            }
        }
            /* 继续处理 */
        case SIGTRAP | 0x80:  // 带系统调用标志的SIGTRAP
            signal = 0;
 
 
            /* 当tracee在系统调用进入阶段被释放,但内核仍报告退出阶段时,
               丢弃这个无效的tracee/事件 */
            if (tracee->exe == NULL) {
                tracee->restart_how = PTRACE_CONT;
                return 0;
            }
 
 
            // 根据seccomp状态处理系统调用
            switch (tracee->seccomp) {
            case ENABLED:  // seccomp启用状态
                if (IS_IN_SYSENTER(tracee)) {  // 系统调用进入阶段
                    tracee->restart_how = PTRACE_SYSCALL; // 捕获退出阶段
                    tracee->sysexit_pending = true;       // 标记退出阶段待处理
                }
                else {                          // 系统调用退出阶段
                    tracee->restart_how = PTRACE_CONT;    // 直接继续执行
                    tracee->sysexit_pending = false;      // 清除退出标志
                }
                /* 继续处理 */
            case DISABLED:  // seccomp禁用状态
                translate_syscall(tracee);  // 转换系统调用
 
 
                /* 当前系统调用已禁用seccomp */
                if (tracee->seccomp == DISABLING) {
                    tracee->restart_how = PTRACE_SYSCALL;
                    tracee->seccomp = DISABLED;
                }
 
 
                break;
 
 
            case DISABLING:  // seccomp正在禁用
                /* 前一个系统调用已禁用seccomp,
                   但其进入阶段已处理完成 */
                tracee->seccomp = DISABLED;
                if (IS_IN_SYSENTER(tracee))
                    tracee->status = 1;
                break;
            }
            break;
 
 
        // 处理seccomp事件(模式2或原始模式)
        case SIGTRAP | PTRACE_EVENT_SECCOMP2 << 8:
        case SIGTRAP | PTRACE_EVENT_SECCOMP << 8: {
            unsigned long flags = 0;
 
 
            signal = 0;
 
 
            if (!seccomp_detected) {
                VERBOSE(tracee, 1, "已启用ptrace加速(seccomp模式2)");
                tracee->seccomp = ENABLED;
                seccomp_detected = true;
            }
 
 
            /* 如果该tracee已显式禁用seccomp,使用普通ptrace流程 */
            if (tracee->seccomp != ENABLED)
                break;
 
 
            status = ptrace(PTRACE_GETEVENTMSG, tracee->pid, NULL, &flags);
            if (status < 0)
                break;
 
 
            /* 需要处理系统调用退出阶段时,使用普通ptrace流程 */
            if ((flags & FILTER_SYSEXIT) != 0) {
                tracee->restart_how = PTRACE_SYSCALL;
                break;
            }
 
 
            /* 否则立即处理系统调用进入阶段 */
            tracee->restart_how = PTRACE_CONT;
            translate_syscall(tracee);
 
 
            /* 如果该调用禁用了seccomp,切换回普通流程以确保处理退出阶段 */
            if (tracee->seccomp == DISABLING)
                /* 设置跟踪对象的系统调用重启方式为PTRACE_SYSCALL(在进入和退出时都停止) */
                tracee->restart_how = PTRACE_SYSCALL;
 
/* 标记该跟踪对象的seccomp状态为已禁用 */
                tracee->seccomp = DISABLED;
 
                break; // 退出当前switch分支
 
case DISABLING: // 处理seccomp正在禁用中的状态
    /*
     * 前一个系统调用已禁用seccomp,
     * 但其sysenter阶段(系统调用入口)已被处理。
     */
    tracee->seccomp = DISABLED; // 更新状态为完全禁用
     
    /* 如果当前处于sysenter阶段,设置状态标志为1 */
    if (IS_IN_SYSENTER(tracee))
        tracee->status = 1;
    break;
 
break; // 退出外层switch
 
/* 处理SECCOMP相关ptrace事件 */
case SIGTRAP | PTRACE_EVENT_SECCOMP2 << 8:
case SIGTRAP | PTRACE_EVENT_SECCOMP << 8: {
    unsigned long flags = 0;
    signal = 0; // 重置信号,表示不传递信号给被跟踪进程
 
    /* 首次检测到seccomp时的初始化 */
    if (!seccomp_detected) {
        VERBOSE(tracee, 1, "启用ptrace加速(seccomp模式2)");
        tracee->seccomp = ENABLED; // 启用seccomp跟踪
        seccomp_detected = true;   // 设置全局检测标志
    }
 
    /* 如果该跟踪对象未启用seccomp,走普通ptrace流程 */
    if (tracee->seccomp != ENABLED)
        break;
 
    /* 获取事件消息中的过滤器标志 */
    status = ptrace(PTRACE_GETEVENTMSG, tracee->pid, NULL, &flags);
    if (status < 0)
        break;
 
    /* 当需要处理sysexit(系统调用退出)时,使用常规流程 */
    if ((flags & FILTER_SYSEXIT) != 0) {
        tracee->restart_how = PTRACE_SYSCALL; // 捕获进入和退出
        break;
    }
 
    /* 否则立即处理sysenter阶段 */
    tracee->restart_how = PTRACE_CONT; // 继续执行直到下一个事件
    translate_syscall(tracee);         // 处理系统调用参数/模拟
 
    /* 如果该syscall禁用了seccomp,切回常规路径以确保处理sysexit */
    if (tracee->seccomp == DISABLING)
        tracee->restart_how = PTRACE_SYSCALL;
    break;
}
 
/* 处理vfork事件 */
case SIGTRAP | PTRACE_EVENT_VFORK << 8:
    signal = 0;
    (void) new_child(tracee, CLONE_VFORK); // 创建vfork子进程跟踪对象
    break;
 
/* 处理fork/clone事件 */
case SIGTRAP | PTRACE_EVENT_FORK  << 8:
case SIGTRAP | PTRACE_EVENT_CLONE << 8:
    signal = 0;
    (void) new_child(tracee, 0); // 创建普通子进程跟踪对象
    break;
 
/* 处理其他事件(不执行特殊操作) */
case SIGTRAP | PTRACE_EVENT_VFORK_DONE << 8:
case SIGTRAP | PTRACE_EVENT_EXEC  << 8:
case SIGTRAP | PTRACE_EVENT_EXIT  << 8:
    signal = 0; // 仅清除信号
    break;
 
/* 处理SIGSTOP信号 */
case SIGSTOP:
    /* 当进程镜像未设置时,挂起跟踪直到收到fork/clone通知 */
    if (tracee->exe == NULL) {
        tracee->sigstop = SIGSTOP_PENDING; // 设置挂起状态
        signal = -1; // 阻止信号传递
    }
 
    /* 对每个跟踪对象,首个SIGSTOP仅用于通知跟踪器 */
    if (tracee->sigstop == SIGSTOP_IGNORED) {
        tracee->sigstop = SIGSTOP_ALLOWED; // 标记为已处理
        signal = 0; // 允许后续传递
    }
    break;
 
default:
    /* 其他信号直接传递给被跟踪进程 */
    break;
}
/**
 * 处理被跟踪进程(tracee)的当前事件(@tracee_status)。该函数返回用于恢复该进程执行的"计算"信号。
 */
int handle_tracee_event(Tracee *tracee, int tracee_status)
{
    static bool seccomp_detected = false// 静态标志位,检测是否启用seccomp
    pid_t pid = tracee->pid;               // 获取被跟踪进程的PID
    long status;                           // 系统调用状态
    int signal;                            // 要发送的信号
 
 
    /* 如果重启方式未被显式设置(例如在单步调试的ptrace模拟中),
       则自动设置默认值 */
    if (tracee->restart_how == 0) {
        /* 当启用seccomp时,所有事件在非停止模式下重启,但后续可能需要修改。
           检查"sysexit_pending"确保不会因其他事件(如execve退出的PTRACE_EVENT_EXEC)
           清除用于seccomp退出阶段的PTRACE_SYSCALL */
        if (tracee->seccomp == ENABLED && !tracee->sysexit_pending)
            tracee->restart_how = PTRACE_CONT;   // 继续执行
        else
            tracee->restart_how = PTRACE_SYSCALL; // 在下一个系统调用时停止
    }
 
 
    /* 默认不是信号触发的停止 */
    signal = 0;
 
 
    // 处理进程退出状态
    if (WIFEXITED(tracee_status)) {
        last_exit_status = WEXITSTATUS(tracee_status);
        VERBOSE(tracee, 1, "进程 %d:已退出,状态码 %d", pid, last_exit_status);
    }
    // 处理信号终止
    else if (WIFSIGNALED(tracee_status)) {
        check_architecture(tracee);
        VERBOSE(tracee, (int) (last_exit_status != -1),
            "进程 %d:被信号 %d 终止", pid, WTERMSIG(tracee_status));
    }
    // 处理停止状态
    else if (WIFSTOPPED(tracee_status)) {
        /* 不使用WSTOPSIG()提取信号,因为它会清除PTRACE_EVENT_*标志位 */
        signal = (tracee_status & 0xfff00) >> 8;  // 解码信号
 
 
        switch (signal) {
            static bool deliver_sigtrap = false// 静态标志控制SIGTRAP传递
 
 
        case SIGTRAP: {  // 断点/单步异常
            // 默认ptrace监控选项
            const unsigned long default_ptrace_options = (
                PTRACE_O_TRACESYSGOOD   |  // 系统调用时发送SIGTRAP|0x80
                PTRACE_O_TRACEFORK      |  // 跟踪fork
                PTRACE_O_TRACEVFORK     |  // 跟踪vfork
                PTRACE_O_TRACEVFORKDONE |  // vfork完成跟踪
                PTRACE_O_TRACEEXEC      |  // 跟踪exec
                PTRACE_O_TRACECLONE     |  // 跟踪clone
                PTRACE_O_TRACEEXIT);      // 跟踪进程退出
 
 
            /* 区分不同事件类型,自动为新进程设置相同跟踪选项
               只有第一个纯SIGTRAP与跟踪循环相关,其他SIGTRAP携带
               TRACE*FORK/CLONE/EXEC的跟踪信息 */
            if (deliver_sigtrap)
                break// 直接传递该信号
 
 
            deliver_sigtrap = true;
 
 
            /* 尝试启用seccomp模式2... */
            status = ptrace(PTRACE_SETOPTIONS, tracee->pid, NULL,
                    default_ptrace_options | PTRACE_O_TRACESECCOMP);
            if (status < 0) {
                /* ...否则仅使用默认选项 */
                status = ptrace(PTRACE_SETOPTIONS, tracee->pid, NULL,
                        default_ptrace_options);
                if (status < 0) {
                    note(tracee, ERROR, SYSTEM, "ptrace(PTRACE_SETOPTIONS失败)");
                    exit(EXIT_FAILURE);
                }
            }
        }
            /* 继续处理 */
        case SIGTRAP | 0x80:  // 带系统调用标志的SIGTRAP
            signal = 0;
 
 
            /* 当tracee在系统调用进入阶段被释放,但内核仍报告退出阶段时,
               丢弃这个无效的tracee/事件 */
            if (tracee->exe == NULL) {
                tracee->restart_how = PTRACE_CONT;
                return 0;
            }
 
 
            // 根据seccomp状态处理系统调用
            switch (tracee->seccomp) {
            case ENABLED:  // seccomp启用状态
                if (IS_IN_SYSENTER(tracee)) {  // 系统调用进入阶段
                    tracee->restart_how = PTRACE_SYSCALL; // 捕获退出阶段
                    tracee->sysexit_pending = true;       // 标记退出阶段待处理
                }
                else {                          // 系统调用退出阶段
                    tracee->restart_how = PTRACE_CONT;    // 直接继续执行
                    tracee->sysexit_pending = false;      // 清除退出标志
                }
                /* 继续处理 */
            case DISABLED:  // seccomp禁用状态
                translate_syscall(tracee);  // 转换系统调用
 
 
                /* 当前系统调用已禁用seccomp */
                if (tracee->seccomp == DISABLING) {
                    tracee->restart_how = PTRACE_SYSCALL;
                    tracee->seccomp = DISABLED;
                }
 
 
                break;
 
 
            case DISABLING:  // seccomp正在禁用
                /* 前一个系统调用已禁用seccomp,
                   但其进入阶段已处理完成 */
                tracee->seccomp = DISABLED;
                if (IS_IN_SYSENTER(tracee))
                    tracee->status = 1;
                break;
            }
            break;
 
 
        // 处理seccomp事件(模式2或原始模式)
        case SIGTRAP | PTRACE_EVENT_SECCOMP2 << 8:
        case SIGTRAP | PTRACE_EVENT_SECCOMP << 8: {
            unsigned long flags = 0;
 
 
            signal = 0;
 
 
            if (!seccomp_detected) {
                VERBOSE(tracee, 1, "已启用ptrace加速(seccomp模式2)");
                tracee->seccomp = ENABLED;
                seccomp_detected = true;
            }
 
 
            /* 如果该tracee已显式禁用seccomp,使用普通ptrace流程 */
            if (tracee->seccomp != ENABLED)
                break;
 
 
            status = ptrace(PTRACE_GETEVENTMSG, tracee->pid, NULL, &flags);
            if (status < 0)
                break;
 
 
            /* 需要处理系统调用退出阶段时,使用普通ptrace流程 */
            if ((flags & FILTER_SYSEXIT) != 0) {
                tracee->restart_how = PTRACE_SYSCALL;
                break;
            }
 
 
            /* 否则立即处理系统调用进入阶段 */
            tracee->restart_how = PTRACE_CONT;
            translate_syscall(tracee);
 
 
            /* 如果该调用禁用了seccomp,切换回普通流程以确保处理退出阶段 */
            if (tracee->seccomp == DISABLING)
                /* 设置跟踪对象的系统调用重启方式为PTRACE_SYSCALL(在进入和退出时都停止) */
                tracee->restart_how = PTRACE_SYSCALL;
 
/* 标记该跟踪对象的seccomp状态为已禁用 */
                tracee->seccomp = DISABLED;
 
                break; // 退出当前switch分支
 
case DISABLING: // 处理seccomp正在禁用中的状态
    /*
     * 前一个系统调用已禁用seccomp,
     * 但其sysenter阶段(系统调用入口)已被处理。
     */
    tracee->seccomp = DISABLED; // 更新状态为完全禁用
     
    /* 如果当前处于sysenter阶段,设置状态标志为1 */
    if (IS_IN_SYSENTER(tracee))
        tracee->status = 1;
    break;
 
break; // 退出外层switch
 
/* 处理SECCOMP相关ptrace事件 */
case SIGTRAP | PTRACE_EVENT_SECCOMP2 << 8:
case SIGTRAP | PTRACE_EVENT_SECCOMP << 8: {
    unsigned long flags = 0;
    signal = 0; // 重置信号,表示不传递信号给被跟踪进程
 
    /* 首次检测到seccomp时的初始化 */
    if (!seccomp_detected) {
        VERBOSE(tracee, 1, "启用ptrace加速(seccomp模式2)");
        tracee->seccomp = ENABLED; // 启用seccomp跟踪
        seccomp_detected = true;   // 设置全局检测标志
    }
 
    /* 如果该跟踪对象未启用seccomp,走普通ptrace流程 */
    if (tracee->seccomp != ENABLED)
        break;
 
    /* 获取事件消息中的过滤器标志 */
    status = ptrace(PTRACE_GETEVENTMSG, tracee->pid, NULL, &flags);
    if (status < 0)
        break;
 
    /* 当需要处理sysexit(系统调用退出)时,使用常规流程 */
    if ((flags & FILTER_SYSEXIT) != 0) {
        tracee->restart_how = PTRACE_SYSCALL; // 捕获进入和退出
        break;
    }
 
    /* 否则立即处理sysenter阶段 */
    tracee->restart_how = PTRACE_CONT; // 继续执行直到下一个事件
    translate_syscall(tracee);         // 处理系统调用参数/模拟
 
    /* 如果该syscall禁用了seccomp,切回常规路径以确保处理sysexit */
    if (tracee->seccomp == DISABLING)
        tracee->restart_how = PTRACE_SYSCALL;
    break;
}
 
/* 处理vfork事件 */
case SIGTRAP | PTRACE_EVENT_VFORK << 8:
    signal = 0;
    (void) new_child(tracee, CLONE_VFORK); // 创建vfork子进程跟踪对象
    break;
 
/* 处理fork/clone事件 */
case SIGTRAP | PTRACE_EVENT_FORK  << 8:
case SIGTRAP | PTRACE_EVENT_CLONE << 8:
    signal = 0;
    (void) new_child(tracee, 0); // 创建普通子进程跟踪对象
    break;
 
/* 处理其他事件(不执行特殊操作) */
case SIGTRAP | PTRACE_EVENT_VFORK_DONE << 8:
case SIGTRAP | PTRACE_EVENT_EXEC  << 8:
case SIGTRAP | PTRACE_EVENT_EXIT  << 8:
    signal = 0; // 仅清除信号
    break;
 
/* 处理SIGSTOP信号 */
case SIGSTOP:
    /* 当进程镜像未设置时,挂起跟踪直到收到fork/clone通知 */
    if (tracee->exe == NULL) {
        tracee->sigstop = SIGSTOP_PENDING; // 设置挂起状态
        signal = -1; // 阻止信号传递
    }
 
    /* 对每个跟踪对象,首个SIGSTOP仅用于通知跟踪器 */
    if (tracee->sigstop == SIGSTOP_IGNORED) {
        tracee->sigstop = SIGSTOP_ALLOWED; // 标记为已处理
        signal = 0; // 允许后续传递
    }
    break;
 
default:
    /* 其他信号直接传递给被跟踪进程 */
    break;
}
/**
 * 系统调用翻译核心函数 - 处理系统调用进入/退出阶段的寄存器操作
 * @param tracee 被跟踪进程的上下文信息
 */
void translate_syscall(Tracee *tracee)
{
    const bool is_enter_stage = IS_IN_SYSENTER(tracee); // 判断当前阶段:系统调用入口
    int status;
 
    assert(tracee->exe != NULL); // 确保已加载目标可执行文件
 
    /* 获取当前寄存器状态 */
    status = fetch_regs(tracee);
    if (status < 0)
        return; // 获取失败直接返回
 
    if (is_enter_stage) {
        /* ==== 系统调用入口阶段处理 ==== */
         
        /* 标记本阶段结束时不需要恢复原始寄存器 */
        tracee->restore_original_regs = false;
 
        print_current_regs(tracee, 3, "sysenter start"); // 调试输出:三级详细度的寄存器状态
 
        /* 仅处理真实用户请求的系统调用(非PRoot内部链式调用) */
        if (tracee->chain.syscalls == NULL) {
            save_current_regs(tracee, ORIGINAL);      // 保存原始寄存器快照
            status = translate_syscall_enter(tracee); // 执行系统调用入口翻译
            save_current_regs(tracee, MODIFIED);      // 保存修改后的寄存器状态
        }
        else {
            /* 链式调用处理:通知扩展模块 */
            status = notify_extensions(tracee, SYSCALL_CHAINED_ENTER, 0, 0);
            tracee->restart_how = PTRACE_SYSCALL; // 设置ptrace为完整跟踪模式
        }
 
        /* 错误处理逻辑 */
        if (status < 0) {
            set_sysnum(tracee, PR_void); // 将系统调用号设为无效值
            poke_reg(tracee, SYSARG_RESULT, (word_t) status); // 将错误码写入结果寄存器
            tracee->status = status;    // 记录错误状态
        }
        else
            tracee->status = 1; // 标记正常状态
 
        /* 特殊场景处理:当使用PTRACE_CONT直接继续时恢复栈指针 */
        if (tracee->restart_how == PTRACE_CONT) {
            tracee->status = 0;
            poke_reg(tracee, STACK_POINTER,
                peek_reg(tracee, ORIGINAL, STACK_POINTER)); // 还原原始栈指针
        }
    }
    else {
        /* ==== 系统调用退出阶段处理 ==== */
         
        /* 默认在退出阶段结束时恢复原始寄存器 */
        tracee->restore_original_regs = true;
 
        print_current_regs(tracee, 5, "sysexit start"); // 调试输出:五级详细度
 
        /* 仅处理真实系统调用的退出 */
        if (tracee->chain.syscalls == NULL)
            translate_syscall_exit(tracee); // 执行退出阶段翻译
        else
            (void) notify_extensions(tracee, SYSCALL_CHAINED_EXIT, 0, 0);
 
        tracee->status = 0; // 重置状态
 
        /* 链式调用处理:执行下一个链式系统调用 */
        if (tracee->chain.syscalls != NULL)
            chain_next_syscall(tracee); // 加载下一个系统调用参数
    }
 
    /* 将修改后的寄存器写回被跟踪进程 */
    (void) push_regs(tracee);
 
    /* 阶段结束调试输出 */
    if (is_enter_stage)
        print_current_regs(tracee, 5, "sysenter end");
    else
        print_current_regs(tracee, 4, "sysexit end");
}
/**
 * 系统调用翻译核心函数 - 处理系统调用进入/退出阶段的寄存器操作
 * @param tracee 被跟踪进程的上下文信息
 */
void translate_syscall(Tracee *tracee)
{
    const bool is_enter_stage = IS_IN_SYSENTER(tracee); // 判断当前阶段:系统调用入口
    int status;
 
    assert(tracee->exe != NULL); // 确保已加载目标可执行文件
 
    /* 获取当前寄存器状态 */
    status = fetch_regs(tracee);
    if (status < 0)
        return; // 获取失败直接返回
 
    if (is_enter_stage) {
        /* ==== 系统调用入口阶段处理 ==== */
         
        /* 标记本阶段结束时不需要恢复原始寄存器 */
        tracee->restore_original_regs = false;
 
        print_current_regs(tracee, 3, "sysenter start"); // 调试输出:三级详细度的寄存器状态
 
        /* 仅处理真实用户请求的系统调用(非PRoot内部链式调用) */
        if (tracee->chain.syscalls == NULL) {
            save_current_regs(tracee, ORIGINAL);      // 保存原始寄存器快照
            status = translate_syscall_enter(tracee); // 执行系统调用入口翻译
            save_current_regs(tracee, MODIFIED);      // 保存修改后的寄存器状态
        }
        else {
            /* 链式调用处理:通知扩展模块 */
            status = notify_extensions(tracee, SYSCALL_CHAINED_ENTER, 0, 0);
            tracee->restart_how = PTRACE_SYSCALL; // 设置ptrace为完整跟踪模式
        }
 
        /* 错误处理逻辑 */
        if (status < 0) {
            set_sysnum(tracee, PR_void); // 将系统调用号设为无效值
            poke_reg(tracee, SYSARG_RESULT, (word_t) status); // 将错误码写入结果寄存器
            tracee->status = status;    // 记录错误状态
        }
        else
            tracee->status = 1; // 标记正常状态
 
        /* 特殊场景处理:当使用PTRACE_CONT直接继续时恢复栈指针 */
        if (tracee->restart_how == PTRACE_CONT) {
            tracee->status = 0;

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 15
支持
分享
最新回复 (5)
雪    币: 4866
活跃值: (14803)
能力值: ( LV9,RANK:230 )
在线值:
发帖
回帖
粉丝
2
你搞错了,,,, 你发的那个proot地址是linux用的,不是安卓上用的,442K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6@1k6i4u0E0N6i4S2Q4x3V1k6H3M7X3!0G2N6l9`.`.
这个才是安卓在termux用的,linux的在android上用很多syscall无法拦截,需要兼容的地方非常多.....
2025-3-6 12:26
2
雪    币: 3146
活跃值: (3717)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
3
珍惜Any 你搞错了,,,, 你发的那个proot地址是linux用的,不是安卓上用的,5e5K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6@1k6i4u0E0N6i4S2Q4x3V1k6H3M7X3!0G2N6l9`.`. 这个才是安卓在termux用的,linux的在androi ...
原来如此,好滴好滴,路漫漫其修远兮,多谢珍惜 解惑
2025-3-6 12:37
0
雪    币: 4933
活跃值: (7509)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
不错噢, 有时间再学习学习。
2025-3-7 09:56
0
雪    币: 1842
活跃值: (1150)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
好文章,以后好好研究一下
2025-4-12 17:32
0
游客
登录 | 注册 方可回帖
返回