系统调用如何存储在pt_regs中?

时间:2015-10-13 13:33:53

标签: c linux system-calls

include/asm/ptrace.h:
struct pt_regs {
     long ebx;
     long ecx;
     long edx;
     long esi;
     long edi;
     long ebp;
     long eax;
     int xds;
     int xes;
     long orig_eax;
     long eip;
     int xcs;
     long eflags;
     long esp;
     int xss;
};

我想知道在给定pt_regs结构的情况下我是如何查看/访问系统调用的?

2 个答案:

答案 0 :(得分:4)

ptrace允许跟踪器运行跟踪程序(tracee),但在每次进入和退出系统调用时自动停止(暂停)。 ptrace(PTRACE_GETREGS, pid, &regs, &regs)允许跟踪器在进入时获取系统调用的参数,并从系统调用中获取结果值,以及struct user_regs_struct regs;头文件中定义的<sys/user.h>。 (指定指向addrdata指针的指针可避免使用特殊套接字SPARC系统。有关背景,请参阅上面的手册页。)

系统调用参数在寄存器中,但它取决于使用哪个寄存器的体系结构。有关详细信息,请参阅man 2 syscall

C库为struct user_regs_struct中的<sys/user.h>定义当前安装的体系结构。对于与体系结构无关的代码,您需要找到一个可以为您抽象细节的库,或者自己编写一个垫片。 (这并不困难;只是有15个架构需要支持,并收集每个架构的详细信息,并测试它们,并将它们全部组合到#if defined() .. #elif defined() .. #else #error ...#endif`序列是很多工作,细节是绝对正确的。所以直截了当的努力。)

例如,在i386上,系统调用号(请参阅/usr/include/bits/syscall.h)位于eax寄存器中,返回值也位于eax中。每个系统调用最多可以提供六个参数;从第一个开始,它们存储在ebxecxedxesiediebp寄存器中,按顺序从左到右。 (Linux内核不支持系统调用的浮点参数,因此基本上所有的syscall参数都被提升为long,这与i386上的指针大小相同。用户空间虚拟内存也是平的,即指针是只是简单的32位地址,并且不包含段寄存器引用。)

作为一个详细的例子,让我们考虑在进入时停止tracee以说出read系统调用的情况。 Linux中的此系统调用使用与POSIX.1 read()函数相同的接口,除了在发生错误时设置errno而不是返回-1,它将返回-errornumber;即-EAGAIN-EINTR等。

跟踪器通知(通过wait()waitpid())tracee停止,并使用上述ptrace(PTRACE_GETREGS,pid,&regs,&regs)调用获取寄存器。文件描述符在regs.ebx中,指向缓冲区的指针在regs.ecx中,要写入的字节数在regs.edx中。

如果跟踪器继续并等待tracee在所述系统调用的退出处停止,regs.eax将包含结果值。如果为零,则描述符的另一端已关闭(关闭)连接。如果是正数,则是读取缓冲区的字节数。如果是负数,则为错误编号(存储在errno否定。 (是的,Linux中的errno值保证是小的正(非零)整数。)

答案 1 :(得分:2)

在x86上,系统调用参数在(ebx,ecx,edx,esi,edi,ebp)中,如果我没记错的话,系统调用号应该在orig_eax中。

如果要在用户空间中查看或访问它们,请检查ptrace(2),也可以使用strace(1)source。