我很困惑。我正在用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。
也许我只是笨,但我遇到的调试器拒绝中断的最常见原因是最简单的。
- 我试图调试的代码与调试器中的代码不完全匹配。
- 我忘记编译带有调试选项的库了。
在遇到类似这样的调试错误时,即使您认为这不是问题,也要确保检查这两个选项。
这听起来像是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中的错误。但考虑到这种行为,我认为这不太可能。