C 如何知道任何库函数(abort)调用是否在源代码中使用了一次以上?
在下面的示例代码中,我们在不同的条件下总共有四个中止调用,但是当我们使用优化标志(-O3)编译时,我们只能看到一个中止调用的调试信息。因此,在这四个中止调用中发生崩溃的地方,gdb总是给出一个包含调试信息的调用C 如何知道任何库函数(abort)调用是否在源代码中使用了一次以上?,c,gcc,gdb,compiler-optimization,abort,C,Gcc,Gdb,Compiler Optimization,Abort,在下面的示例代码中,我们在不同的条件下总共有四个中止调用,但是当我们使用优化标志(-O3)编译时,我们只能看到一个中止调用的调试信息。因此,在这四个中止调用中发生崩溃的地方,gdb总是给出一个包含调试信息的调用 #include <stdio.h> #include <stdlib.h> void level_aa(int a) { if (a == 0) abort(); if (a == 1)
#include <stdio.h>
#include <stdlib.h>
void level_aa(int a)
{
if (a == 0)
abort();
if (a == 1)
abort();
if (a == 2)
abort();
abort();
}
int main(int argc,char *argv[])
{ int D;
D = atoi(argv[1]);
printf(" Value = %d", D);
level_aa(D);
return 0;
}
#包括
#包括
空层_aa(内部a)
{
如果(a==0)
中止();
如果(a==1)
中止();
如果(a==2)
中止();
中止();
}
int main(int argc,char*argv[])
{int D;
D=atoi(argv[1]);
printf(“值=%d”,d);
aa(D)级;
返回0;
}
将上面的代码与优化标志(-O3)混合,并使用gdb运行
>gcc -g -O3 abort_crash.c -o abort
>gdb ./abort
(gdb)run 1
(gdb) bt
#0 0x00007ffff7ab2945 in *__GI_raise (sig=<optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1 0x00007ffff7ab3f21 in *__GI_abort () at abort.c:92
#2 0x0000000000400634 in level_aa (a=<optimized out>) at abort_crash.c:13
#3 main (argc=<optimized out>, argv=<optimized out>) at abort_crash.c:20
(gdb)
gcc-g-O3中止\u崩溃.c-o中止
>gdb./abort
(gdb)运行1
(gdb)英国电信
#在../nptl/sysdeps/unix/sysv/linux/raise.c:64处0 0x00007ffff7ab2945 in*u GI_raise(sig=)
#1 0x00007FF7AB3F21 in*\uuu GI\u abort()位于abort.c:92
#2 0x0000000000400634在中止时处于级别_aa(a=)c:13
#3主(argc=,argv=)在中止时崩溃。c:20
(gdb)
如果我们观察第2帧(#2),碰撞实际上发生在第9行,但gdb显示的是第13行。我可以理解,这是源代码优化的结果。因为如果它被多次使用,那么gdb backtrace中显示的行号可能不正确。是否可以通过不查看源来知道中止调用是否被多次使用?如果我们知道呼叫被多次使用,并且经过优化,那么我们可以打印一条警告消息。我们是工具提供商(内部使用gdb),除了用户的转储文件外,我们看不到用户的源代码
非常感谢你的帮助 不,这是不可能的。特别是在您给出的示例中,所有路径都会导致调用
abort
,GCC很可能会放弃对a
的所有检查,只生成一个调用abort
据我所知,DWARF中的行表信息(将地址映射到源文件和行号)没有任何工具可以使行号成为特定的地址映射,并以某个DWARF表达式为条件。因此,据我所知,单个地址只能代表一个源行,因此GCC必须为每个地址选择一个行号
在您的示例中,GCC选择了第13行,这似乎是一个明智的选择,因为前面所有检查a
的代码都是多余的
要获得更具体的回溯,唯一的方法是编译而不进行优化,或者使用比GDB更强大的工具。如果你看不到源代码,行号有什么用?我们只是工具提供商,正在验证内核转储的回溯,我们应该确保回溯是正确的。但在这种情况下,由于源代码的优化,我们无法获得准确的行号,因此我们希望向用户打印一条警告消息。相关:特别是abort通常声明为no_return,因此gcc知道,如果执行了先前的abort,则不会调用第13行中的catch all abort,因此整个if。。。确实可以从编译器中删除。