【问题标题】:ptrace system call returns -1 with errno=0ptrace 系统调用返回 -1 且 errno=0
【发布时间】:2020-06-28 22:15:22
【问题描述】:

我正在尝试使用 ptrace 做一些非常基本的事情,但我的行为非常奇怪。

unsigned long start=strtoul(start_text,NULL,16);

long start_data; 
 if ((start_data = ptrace(PTRACE_PEEKTEXT,child_pid,(void*)start,NULL))<0){
      free_memory(vars,registers,size);
      exit(1);
}
    

start_text是另一个程序中有效位置的字符串,start的值是正确的,child_pid的值也是正确的。

出于某种原因,对于 start 的某些值,调用可以正常工作,但对于某些值,它会失败。

我试图了解是什么原因造成的,所以我写了这个:

ptrace(PTRACE_PEEKTEXT,child_pid,(void*)start,NULL);
printf("%d",errno);

但errno 每次都是 0。

谁能解释一下导致问题的原因?

【问题讨论】:

  • ptrace 总是会在出错时设置 errno —— 但 PTRACE_PEEKTEXT 可能会返回一个负值(如果读取的值为负数)而不会出错。要检测 PEEKTEXT 的错误,您需要在 ptrace 调用之前设置 errno = 0 并在之后检查。

标签: c system-calls


【解决方案1】:

来自 Linux 的 ptrace 手册页:

由于返回的值 成功的 PTRACE_PEEK* 请求可能为 -1,调用者必须在调用之前清除 errno,并且 然后检查它以确定是否发生错误。

也就是说,您正在读取的值可能恰好是 -1,或者在您的情况下,可能是某个其他负数(即设置了高位的 64 位值)。

因此与大多数其他系统调用函数不同,您无法通过测试返回值是否为负来检查是否成功。你应该这样做

errno = 0;
start_data = ptrace(PTRACE_PEEKTEXT,child_pid,(void*)start,NULL));
if (errno != 0) {
    // handle error
}

请注意首先设置errno = 0 的重要性。与其他系统调用一样,如果ptrace 成功,它可能会保留errno 的值不变。因此,除非您首先清除 errno,否则您将无法判断之后的非零值是否表示 ptrace 失败,或者 ptrace 是否成功并且该值是从先前失败的调用中遗留下来的。

(我的手册页版本表明ptrace 库包装器实际上可能在成功时将errno 设置为零,但没有明确说明具体时间,因此最好不要依赖这种行为。)

【讨论】:

  • Nitpick:系统调用本身没有errno 的概念,而ptrace 系统调用会像其他任何一样报告错误。这个问题纯粹是 libc 包装器的结果。
猜你喜欢
  • 2015-10-15
  • 2012-10-07
  • 1970-01-01
  • 1970-01-01
  • 2012-02-23
  • 2012-08-14
  • 2023-04-06
  • 2011-06-09
  • 1970-01-01
相关资源
最近更新 更多