首页 > 解决方案 > qemu 跟踪哪些指令?

问题描述

我编写了以下一段代码,它逐步执行/bin/ls并计算其指令:

#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/user.h>
#include <sys/reg.h>    
#include <sys/syscall.h>

int main()
{   
    pid_t child;
    child = fork(); //create child
    
    if(child == 0) {
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        char* child_argv[] = {"/bin/ls", NULL};
        execv("/bin/ls", child_argv);
    }
    else {
        int status;
        long long ins_count = 0;
        while(1)
        {
            //stop tracing if child terminated successfully
            wait(&status);
            if(WIFEXITED(status))
                break;

                ins_count++;
                ptrace(PTRACE_SINGLESTEP, child, NULL, NULL);
        }

    printf("\n%lld Instructions executed.\n", ins_count);

    }
    
    return 0;
}

运行这段代码可以让我执行大约 500.000 条指令。据我所知,这些指令中的大部分应该来自动态链接器。当我使用带有qemu-x86_64 -singlestep -D log -d in_asm /bin/ ls 的 QEMU 跟踪 /bin/ ls 时,我执行了大约 17.000 条指令。我必须调整什么才能在 QEMU 所做的相同点开始和停止计数?(又名。计算相同的指令)。

我用 QEMU 跟踪了一个“返回 null”程序,它产生了 7840 条指令,而我的代码给了我 109025,因此 QEMU 似乎跟踪的比主代码多,但比我的代码少。

我的目标是稍后比较这些指令,这就是为什么我想迭代像 QEMU 这样的指令。

标签: clinuxqemuinstructionsptrace

解决方案


QEMU 的“in_asm”日志不是执行指令的日志。每次翻译指令时(即 QEMU 生成与其对应的主机代码位时),它都会记录下来。然后缓存该翻译,如果客户循环并再次执行相同的指令,QEMU 将简单地重新使用相同的翻译,因此它不会被 in_asm 记录。因此,预计“in_asm 报告的指令要少得多”。

通过 -d 选项记录每条执行的指令有点棘手——你需要查看“cpu”和“exec”跟踪,使用 -d 的“nochain”子选项来禁用 QEMU 优化,否则会导致一些块没有被记录,使用'-singlestep'强制每个块执行一条指令,并且还考虑了一些我们打印执行跟踪然后实际上不执行指令的极端情况。这是因为 -d 选项并非旨在让用户自省其程序的行为——它是一个调试选项,旨在允许调试 QEMU 和来宾程序一起执行的操作,因此它打印的信息是需要对 QEMU 内部有一点了解才能正确解释。

您可能会发现编写 QEMU“插件”更简单:https ://qemu.readthedocs.io/en/latest/devel/tcg-plugins.html - 这是一个 API,旨在相当简单地编写类似的工具“计数指令执行”。如果您很幸运,那么其中一个示例插件甚至可能足以满足您的目的。


推荐阅读