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结构的情况下我是如何查看/访问系统调用的?
答案 0 :(得分:4)
ptrace允许跟踪器运行跟踪程序(tracee),但在每次进入和退出系统调用时自动停止(暂停)。 ptrace(PTRACE_GETREGS, pid, ®s, ®s)
允许跟踪器在进入时获取系统调用的参数,并从系统调用中获取结果值,以及struct user_regs_struct regs;
头文件中定义的<sys/user.h>
。 (指定指向addr
和data
指针的指针可避免使用特殊套接字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
中。每个系统调用最多可以提供六个参数;从第一个开始,它们存储在ebx
,ecx
,edx
,esi
,edi
和ebp
寄存器中,按顺序从左到右。 (Linux内核不支持系统调用的浮点参数,因此基本上所有的syscall参数都被提升为long
,这与i386上的指针大小相同。用户空间虚拟内存也是平的,即指针是只是简单的32位地址,并且不包含段寄存器引用。)
作为一个详细的例子,让我们考虑在进入时停止tracee以说出read
系统调用的情况。 Linux中的此系统调用使用与POSIX.1 read()
函数相同的接口,除了在发生错误时设置errno
而不是返回-1,它将返回-errornumber
;即-EAGAIN
,-EINTR
等。
跟踪器通知(通过wait()
或waitpid()
)tracee停止,并使用上述ptrace(PTRACE_GETREGS,pid,®s,®s)
调用获取寄存器。文件描述符在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。