如何知道系统调用是否返回错误?

问题描述 投票:0回答:1

我尝试使用

strace
在 C 中重现
ptrace
行为。

我想检查系统调用是否返回错误(以及什么错误1),但我不知道该怎么做?

这是我尝试重现的

strace
的输出示例:

execve("./exit", ["./exit"], 0x7ffff059f250 /* 62 vars */) = 0
read(42, NULL, 0)                       = -1 EBADF (Bad file descriptor)
exit(0)                                 = ?
+++ exited with 0 +++

我尝试将系统调用2的返回值与-1进行比较,但它们不相等。

我在GLIBC系统调用的实现(

sysdeps/unix/sysv/linux/syscall.c
)中看到使用了
INTERNAL_SYSCALL_ERROR_P
宏,这似乎是GLIBC内部使用的宏。我发现了这个宏的两个实现:

  • 第一个,在
    sysdeps/unix/sysv/linux/sysdep.h
#define INTERNAL_SYSCALL_ERROR_P(val) ((unsigned long int)(val) > -4096UL)
  • 第二个,在
    sysdeps/unix/sysv/linux/x86_64/x32/times.c
#define INTERNAL_SYSCALL_ERROR_P(val) ((unsigned long long int)(val) >= -4095LL)

由于第一个位于与系统直接相关的标头中(与第二个不同),我倾向于说这是

syscall
使用的标头。但我不知道它们是否是仿制药,所以我是否可以使用它。

1要恢复 errno 代码,反转系统调用返回值 (

-rax
) 似乎可行。

2使用

ptrace(PTRACE_GETREGS, ...)
,我们可以获得子寄存器,并将它们存储在
struct user_regs_struct
中(在
sys/user.h
中定义)。访问该结构的
rax
成员,我们得到了系统调用的返回值。

c system-calls strace ptrace
1个回答
0
投票

我想我找到了解决方案。

syscall
好像没有设置进位标志。
否则,就像我们在
syscall
手册
上看到的那样,如果
rax
为负数(低于0),则表明存在错误。
由于
rax
中的
struct user_regs_struct
是无符号的,我们只需将其转换为有符号的,我们就可以知道系统调用是否返回并出错,以及什么错误(
-rax
获取 errno 代码)。

int main(int argc, const char *argv[])
{
    struct user_regs_struct regs;

    // strace logic ...
    if ((long long)regs.rax < 0)
        printf(" = -1 %s (%s)\n", strerrorname_np((int)-regs.rax), strerror((int)-regs.rax));
    else
        printf(" = %llu\n", regs.rax);
    // ...
}
© www.soinside.com 2019 - 2024. All rights reserved.