理解覆盖过程映像和 execl 调用

understanding overlaying process image and execl call

我想从头开始构建我自己的调试器,所以我想了解它背后的一些概念。首先,我从简单开始,使用 ptrace 库。但即使在这一点上我也有一些问题,让我 运行 通过这段代码:

int main(int argc, char** argv)
{
    pid_t child_pid;

    if (argc < 2) {
        fprintf(stderr, "Expected a program name as argument\n");
        return -1;
    }

    child_pid = fork();
    if (child_pid == 0)
        run_target(argv[1]);
    else if (child_pid > 0)
        run_debugger(child_pid);
    else {
        perror("fork");
        return -1;
    }

    return 0;
}

这没什么特别的,我正在使用 fork() 创建一个子进程 下一个功能实在是看不懂

void run_target(const char* programname)
{
    procmsg("target started. will run '%s'\n", programname);

    /* Allow tracing of this process */
    if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
        perror("ptrace");
        return;
    }

    /* Replace this process's image with the given program */
    execl(programname, programname, 0);
}

最后一个电话是问题所在。此调用代表了叠加过程的概念 image.I 我没有完全了解正在发生的事情。作者是这样说的:

I've highlighted the part that interests us in this example. Note that the very next thing run_target does after ptrace is invoke the program given to it as an argument with execl. This, as the highlighted part explains, causes the OS kernel to stop the process just before it begins executing the program in execl and send a signal to the parent.
运行 调试器基本上父进程必须跟踪子进程,子进程确认它希望使用 PTRACEME 进行跟踪。但是我不知道那个execl在做什么。我能理解目的和输出,但不知道如何做。我查阅了手册页,但无法解决这个问题。 如果有人能给我一个关于这个 execl 函数发生了什么的清晰解释,我将不胜感激。

我想你同意这一点:概念是调试器必须调试程序 TARGET,只有调用 PTRACE_TRACEME.

才能调试

当然,TARGET 不会在其源代码中使用 PTRACE_TRACEME 参数调用 ptrace。 所以,调试器必须为它做。

最初,调试器分叉。这时我们有两个进程:

  1. 父亲:它叫run_debugger()
  2. Child:调用run_target()

Child 是调试器可以控制的进程,因此它可以使用参数 PTRACE_TRACEME(在 run_target() 中)调用 ptrace。但是这个过程不是TARGET.

因此,下一步是将 child 关联到 TARGET 的“图像”(即我们要调试的程序)。进程映像是程序执行时需要的可执行文件,由4个经典段组成:

  1. 代码(文本段)
  2. 数据
  3. 堆栈

execl 和朋友属于 exec 系列,即用新过程映像替换当前过程映像的函数。据我所知,execl 与其朋友 execv 的参数传递方式不同,但概念是相同的。

所以,你需要知道的是:

exec replaces the currently running program by another program (i..e., TARGET) inside an EXISTING process.

后者使用参数 PTRACE_TRACEME 调用了 ptrace,因此新程序不会忽略调试器将来进行的 ptrace 调用。

如果你的问题是exec systemcall的实现细节,我对它的了解不是很全面,但我可以给一些建议:

  • 正在阅读“The exec-like Functions”一书“Understanding Linux Kernel”
  • 查看源代码 (this question) 会将您定向到 execve 的源代码,这对您来说完全没问题,与 execl.[=67 的概念相同=]
  • 如果您想创建自己的 exec, 也很有用。