C语言 什么可以使GDB拒绝崩溃



我很困惑。我正在用C编写一个编译器(出于爱好),并在amd64 Linux 2.6.32上使用GCC 4.6.1编译,使用GDB 7.3。标志是"-Wall -Wextra - 0 -g",除了通常的-I和诸如此类的。我有一个函数,其目的是报告解析错误,定义如下:

void cerror_at (struct lex *lex, struct token *tok, const char *fmt, ...)

除了可变之外,没有什么奇怪的。问题是GDB不会在此中断。我已经尝试了我能想到的每一种方法(函数中的断点,函数内部,在它被调用之前,你命名它),但是只要我的程序在函数内部,我就会得到像"警告:删除断点0错误"这样的消息,GDB只是让程序完成。它再也没有什么问题了(我已经修复了我试图找到的错误,一切都正常运行),但我无法进入函数。你知道是什么原因导致的吗?

编辑:更多信息!GDB将断点设置为0x403057。该函数从0x403025开始。看看这部分反汇编:

0x0000000000403053 <+46>:   test   %al,%al
0x0000000000403055 <+48>:   je     0x403077 <cerror_at+82>

此时,它跳到0x403077(超过断点)。我已经验证了将断点放置在"je"之前的地址,以及位于0x403077(跳转的目标)或之后的地址,但不在两者之间(GDB试图放置它的地方)。为什么GDB将断点放在函数的中间?甚至GDB也告诉我,函数的地址实际上是0x403025。

也许我只是笨,但我遇到的调试器拒绝中断的最常见原因是最简单的。

  1. 我试图调试的代码与调试器中的代码不完全匹配。
  2. 我忘记编译带有调试选项的库了。

在遇到类似这样的调试错误时,即使您认为这不是问题,也要确保检查这两个选项。

这听起来像是GDB中的一个bug。特别是,Error removing breakpoint 0是非常可疑的(它是一个自动插入的断点GDB;用户插入的断点为正数)。

您可能应该尝试创建一个简化的测试用例,并在这里提交一个bug。

正如在注释中提到的,您应该尝试理解编译生成的机器代码:

在GDB中,您可以看到disassemble cerror_at的实际功能代码它应该给出类似于(x86_64):

(gdb) disassemble dive
Dump of assembler code for function dive:
   0x0000000000400504 <+0>: push   %rbp
   0x0000000000400505 <+1>: mov    %rsp,%rbp
   0x0000000000400508 <+4>: sub    $0x10,%rsp
   0x000000000040050c <+8>: mov    %edi,-0x4(%rbp)
   0x000000000040050f <+11>:    mov    -0x4(%rbp),%eax
   0x0000000000400512 <+14>:    add    $0x1,%eax
   0x0000000000400515 <+17>:    mov    %eax,%edi
   0x0000000000400517 <+19>:    callq  0x400504 <dive>
   0x000000000040051c <+24>:    leaveq
   0x000000000040051d <+25>:    retq   
End of assembler dump.

然后检查子例程是否被调用:在函数调用之前中断执行几条指令,然后:

   (gdb) x/5i $p
=> 0x400539 <main+27>:  mov    $0x1,%esi
   0x40053e <main+32>:  mov    %rax,%rdi
   0x400541 <main+35>:  callq  0x400408 <fwrite@plt>
   0x400546 <main+40>:  mov    $0x1,%edi
-->0x40054b <main+45>:  callq  0x400504 <dive> <------

与其他CPU体系结构的输出应该略有不同,但是您应该能够看到指向函数地址的分支指令。

,

您可以在之前执行maint info breakpoint,此时您看到Error removing breakpoint 0以了解breakpoint 0的设置位置,这可能有助于了解它的问题所在。

根据你最近的编辑,我打赌这是一个编译器错误。具体来说,我敢打赌DWARF调试信息的生成存在问题,GDB使用DWARF调试信息来映射目标代码中的地址和源代码中的文件/过程/行号。

你可以尝试-gdwarf-4, -gdwarf-3,甚至-gdwarf-2,看看它是否有任何不同。

如果你能把它简化成一个简单的测试用例,我怀疑gcc开发人员会接受它作为一个bug。

当然,这也可能是GDB中的错误。但考虑到这种行为,我认为这不太可能。

最新更新