首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在gdb中为open(2)SysCall返回-1设置断点?

如何在gdb中为open(2)SysCall返回-1设置断点?
EN

Stack Overflow用户
提问于 2018-02-20 03:04:41
回答 2查看 0关注 0票数 0

操作系统:GNU/Linux

发行版:opensuse 13.1

ARCH:x86-64

GDB版本:7.6.50.20130731-CVS

程序语言:主要是C语言,包含少量的程序集

想象一下,我有一个相当大的程序,有时无法打开一个文件。 是否可以在GDB中设置断点,以便在open(2)系统调用返回-1之后停止?

当然,我可以通过源代码grep来查找所有open(2)调用并缩小错误open()调用,但也许有更好的方法。

我试图使用“catch系统调用打开”,然后“条件N,如果$ rax == - 1”,但显然它没有被击中。

是否有可能在GDB中调用系统调用(例如open(2))和从系统调用返回(例如open(2))?

EN

Stack Overflow用户

发布于 2018-02-20 11:30:05

在gdb中设置断点是否可能使其在open(2)SysCall返回-1之后停止?

我认为这个问题的提出是错误的。

当然,我可以通过源代码实现grep,并找到所有open(2)调用。

这是你的困惑的一部分:当你在C程序中调用open时,你实际上并没有执行open(2)系统调用。 而是从你的libc调用一个open(3)“stub”,并且这个stub将为你执行open(2)系统调用。

如果你想在存根即将返回-1时设置一个断点,那很简单。

例子:

代码语言:javascript
复制
/* t.c */
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
  int fd = open("/no/such/file", O_RDONLY);
  return fd == -1 ? 0 : 1;
}

$ gcc -g t.c; gdb -q ./a.out
(gdb) start
Temporary breakpoint 1 at 0x4004fc: file t.c, line 6.
Starting program: /tmp/a.out

Temporary breakpoint 1, main () at t.c:6
6     int fd = open("/no/such/file", O_RDONLY);
(gdb) s
open64 () at ../sysdeps/unix/syscall-template.S:82
82  ../sysdeps/unix/syscall-template.S: No such file or directory.

这里我们已经到了glibc系统调用存根。让我们拆开它:

代码语言:javascript
复制
(gdb) disas
Dump of assembler code for function open64:
=> 0x00007ffff7b01d00 <+0>: cmpl   $0x0,0x2d74ad(%rip)        # 0x7ffff7dd91b4 <__libc_multiple_threads>
   0x00007ffff7b01d07 <+7>: jne    0x7ffff7b01d19 <open64+25>
   0x00007ffff7b01d09 <+0>: mov    $0x2,%eax
   0x00007ffff7b01d0e <+5>: syscall
   0x00007ffff7b01d10 <+7>: cmp    $0xfffffffffffff001,%rax
   0x00007ffff7b01d16 <+13>:    jae    0x7ffff7b01d49 <open64+73>
   0x00007ffff7b01d18 <+15>:    retq
   0x00007ffff7b01d19 <+25>:    sub    $0x8,%rsp
   0x00007ffff7b01d1d <+29>:    callq  0x7ffff7b1d050 <__libc_enable_asynccancel>
   0x00007ffff7b01d22 <+34>:    mov    %rax,(%rsp)
   0x00007ffff7b01d26 <+38>:    mov    $0x2,%eax
   0x00007ffff7b01d2b <+43>:    syscall
   0x00007ffff7b01d2d <+45>:    mov    (%rsp),%rdi
   0x00007ffff7b01d31 <+49>:    mov    %rax,%rdx
   0x00007ffff7b01d34 <+52>:    callq  0x7ffff7b1d0b0 <__libc_disable_asynccancel>
   0x00007ffff7b01d39 <+57>:    mov    %rdx,%rax
   0x00007ffff7b01d3c <+60>:    add    $0x8,%rsp
   0x00007ffff7b01d40 <+64>:    cmp    $0xfffffffffffff001,%rax
   0x00007ffff7b01d46 <+70>:    jae    0x7ffff7b01d49 <open64+73>
   0x00007ffff7b01d48 <+72>:    retq
   0x00007ffff7b01d49 <+73>:    mov    0x2d10d0(%rip),%rcx        # 0x7ffff7dd2e20
   0x00007ffff7b01d50 <+80>:    xor    %edx,%edx
   0x00007ffff7b01d52 <+82>:    sub    %rax,%rdx
   0x00007ffff7b01d55 <+85>:    mov    %edx,%fs:(%rcx)
   0x00007ffff7b01d58 <+88>:    or     $0xffffffffffffffff,%rax
   0x00007ffff7b01d5c <+92>:    jmp    0x7ffff7b01d48 <open64+72>
End of assembler dump.

在这里你可以看到存根的行为有所不同,这取决于程序是否有多个线程。 这与异步取消有关。

有两个系统调用指令,在一般情况下,我们需要在每个指令之后设置一个断点(但请参见下文)。

但是这个例子是单线程的,所以我可以设置一个条件断点:

代码语言:javascript
复制
(gdb) b *0x00007ffff7b01d10 if $rax < 0
Breakpoint 2 at 0x7ffff7b01d10: file ../sysdeps/unix/syscall-template.S, line 82.
(gdb) c
Continuing.

Breakpoint 2, 0x00007ffff7b01d10 in __open_nocancel () at ../sysdeps/unix/syscall-template.S:82
82  in ../sysdeps/unix/syscall-template.S
(gdb) p $rax
$1 = -2

open(2)系统调用返回-2,该存根将转换为将errno设置为ENOENT(在此系统上为2)并返回-1。

如果open(2)成功,则$ rax <0的条件将为false,并且GDB将继续执行。

这正是GDB在寻找其中一个失败的系统调用时通常需要的行为。

票数 0
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/-100004155

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档