c-为什么qemu有时比ptrace计数更多,有时计数更少



我希望在每次执行指令后将寄存器与qemu生成的寄存器转储进行比较。因此,我编写了一个程序,它使用ptrace迭代程序的每个执行指令,并能够在每个指令之后转储寄存器。我简化了程序,使其仅适用于/bin/ls,并且它只计算执行的指令数,而不是转储寄存器。

SPOILER:qemu和ptrace的指令数不匹配,相差几千条指令。

这是我写的代码:

#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;
}

运行这段代码可以得到492611条已执行的指令。我知道这些指令中的大多数都来自于动态链接器。如果我在每条指令之后转储寄存器,则/bin/ls的第一个寄存器转储将准备就绪。

现在我想用qemu在每条指令之后转储寄存器。我使用以下命令单步执行来自/bin/ls的每条指令,并在进入每个转换块之前转储寄存器状态。我禁用了qemu的转换块链接,以便在每条实际指令之前转储寄存器。

qemu-x86_64-单步-D日志文件-D nochain,cpu/bin/ls

查看日志文件,每条指令的寄存器转储由20行组成,例如:

RAX=0000000000000000 RBX=0000000000000000 RCX=0000000000000000 RDX=0000000000000000
RSI=0000000000000000 RDI=0000000000000000 RBP=0000000000000000 RSP=0000004000805180
R8 =0000000000000000 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000000
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=0000004000807100 RFL=00000202 [-------] CPL=3 II=0 A20=1 SMM=0 HLT=0
ES =0000 0000000000000000 00000000 00000000
CS =0033 0000000000000000 ffffffff 00effb00 DPL=3 CS64 [-RA]
SS =002b 0000000000000000 ffffffff 00cff300 DPL=3 DS   [-WA]
DS =0000 0000000000000000 00000000 00000000
FS =0000 0000000000000000 00000000 00000000
GS =0000 0000000000000000 00000000 00000000
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT=     0000004000837000 0000007f
IDT=     0000004000836000 000001ff
CR0=80010001 CR2=0000000000000000 CR3=0000000000000000 CR4=00000220
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000000 CCD=0000000000000000 CCO=EFLAGS  
EFER=0000000000000500

我用计算了日志文件的行数

wc-l日志文件

这给了我9.873.540行,导致9.873.540/20=493.677条指令的寄存器转储。

因此,对于/bin/ls,qemu比我的ptrace程序多计算1.066条指令。我也做了同样的事情;return null";程序和打印数字0-9的程序。结果如下:

returnnull:
qemu counts 105.351 instructions vs ptrace counts 109.308 -> qemu counts 3.957 instructions less than ptrace
printf 0-9:
qemu counts 2.188.344 instructions vs ptrace counts 2.194.793 -> qemu counts 6.449 instructions less than ptrace

为什么qemu和ptrace不计算完全相同的指令。为什么qemu有时比ptrace计数更多,有时计数更少?我能做些什么来获得相同指令的寄存器转储并且能够比较这些?

如果您在使用ptrace单步执行、执行一些基本文本处理并运行diff -u(确保也关闭ASLR,例如在setarch linux64 -R ...下运行(时确实转储了指令地址,那么您应该能够自己回答这个问题。

一种可能性可能是,当内核与qemu加载程序时,由于不同的入口点状态(auxv等(,不同的代码实际上在启动序列中执行(在动态链接器中或通过__libc_start_main或等效程序到达的东西中(。减少这种情况的一个快速方法是使用静态链接进行测试。如果这消除了差异,那可能是唯一的原因;如果它只是改变了它,那么可能有多种原因。

相关内容

  • 没有找到相关文章

最新更新