C 如何知道任何库函数(abort)调用是否在源代码中使用了一次以上?

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)

在下面的示例代码中,我们在不同的条件下总共有四个中止调用,但是当我们使用优化标志(-O3)编译时,我们只能看到一个中止调用的调试信息。因此,在这四个中止调用中发生崩溃的地方,gdb总是给出一个包含调试信息的调用

#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。。。确实可以从编译器中删除。