我怎样才能find一个全局variables的析构函数调用使用gdb?

我们有一个很大的项目(大约20万个文件)

当项目退出时,它会崩溃在一个全局variables的解构。

但是我们无法findvariables定义的位置。

有谁知道如何find全局variables的位置?

但是我们无法找到变量定义的位置。

据推测,你想找出哪个全局变量造成麻烦。 如果你知道它是哪一个,你可以使用grep或者GDB info variable foobar来找到它。

我们来看一个例子。

 cat foo.cc #include <stdio.h> #include <string> using std::string; string foo("foo"); string bar("bar"); string baz("baz"); // It is not valid to call this function with a global string. void invalid_with_global(string *str) { printf("str: %s @%p)\n", str->c_str(), str); printf("before dtor\n"); str->~string(); printf("after dtor\n"); } int main() { invalid_with_global(&baz); } g++ -g foo.cc && gdb -q ./a.out Reading symbols from /tmp/a.out...done. (gdb) r Starting program: /tmp/a.out str: baz @0x601088) before dtor after dtor *** glibc detected *** /tmp/a.out: double free or corruption (fasttop): 0x0000000000602070 *** ======= Backtrace: ========= /lib/x86_64-linux-gnu/libc.so.6(+0x7eb96)[0x7ffff7583b96] /usr/lib/x86_64-linux-gnu/libstdc++.so.6(_ZNSsD1Ev+0x23)[0x7ffff7b78c13] /lib/x86_64-linux-gnu/libc.so.6(+0x3b901)[0x7ffff7540901] /lib/x86_64-linux-gnu/libc.so.6(+0x3b985)[0x7ffff7540985] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf4)[0x7ffff7526774] /tmp/a.out[0x4007f9] ======= Memory map: ======== 00400000-00401000 r-xp 00000000 ca:01 147024 /tmp/a.out 00600000-00601000 r--p 00000000 ca:01 147024 /tmp/a.out 00601000-00602000 rw-p 00001000 ca:01 147024 /tmp/a.out 00602000-00623000 rw-p 00000000 00:00 0 [heap] 7ffff7209000-7ffff7304000 r-xp 00000000 ca:01 881564 /lib/x86_64-linux-gnu/libm-2.15.so 7ffff7304000-7ffff7503000 ---p 000fb000 ca:01 881564 /lib/x86_64-linux-gnu/libm-2.15.so 7ffff7503000-7ffff7504000 r--p 000fa000 ca:01 881564 /lib/x86_64-linux-gnu/libm-2.15.so 7ffff7504000-7ffff7505000 rw-p 000fb000 ca:01 881564 /lib/x86_64-linux-gnu/libm-2.15.so 7ffff7505000-7ffff76ba000 r-xp 00000000 ca:01 881572 /lib/x86_64-linux-gnu/libc-2.15.so 7ffff76ba000-7ffff78b9000 ---p 001b5000 ca:01 881572 /lib/x86_64-linux-gnu/libc-2.15.so 7ffff78b9000-7ffff78bd000 r--p 001b4000 ca:01 881572 /lib/x86_64-linux-gnu/libc-2.15.so 7ffff78bd000-7ffff78bf000 rw-p 001b8000 ca:01 881572 /lib/x86_64-linux-gnu/libc-2.15.so 7ffff78bf000-7ffff78c4000 rw-p 00000000 00:00 0 7ffff78c4000-7ffff78d9000 r-xp 00000000 ca:01 881501 /lib/x86_64-linux-gnu/libgcc_s.so.1 7ffff78d9000-7ffff7ad8000 ---p 00015000 ca:01 881501 /lib/x86_64-linux-gnu/libgcc_s.so.1 7ffff7ad8000-7ffff7ad9000 r--p 00014000 ca:01 881501 /lib/x86_64-linux-gnu/libgcc_s.so.1 7ffff7ad9000-7ffff7ada000 rw-p 00015000 ca:01 881501 /lib/x86_64-linux-gnu/libgcc_s.so.1 7ffff7ada000-7ffff7bbc000 r-xp 00000000 ca:01 1096828 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16 7ffff7bbc000-7ffff7dbb000 ---p 000e2000 ca:01 1096828 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16 7ffff7dbb000-7ffff7dc3000 r--p 000e1000 ca:01 1096828 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16 7ffff7dc3000-7ffff7dc5000 rw-p 000e9000 ca:01 1096828 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16 7ffff7dc5000-7ffff7dda000 rw-p 00000000 00:00 0 7ffff7dda000-7ffff7dfc000 r-xp 00000000 ca:01 881673 /lib/x86_64-linux-gnu/ld-2.15.so 7ffff7fd8000-7ffff7fdd000 rw-p 00000000 00:00 0 7ffff7ff7000-7ffff7ffb000 rw-p 00000000 00:00 0 7ffff7ffb000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso] 7ffff7ffc000-7ffff7ffd000 r--p 00022000 ca:01 881673 /lib/x86_64-linux-gnu/ld-2.15.so 7ffff7ffd000-7ffff7fff000 rw-p 00023000 ca:01 881673 /lib/x86_64-linux-gnu/ld-2.15.so 7ffffffdd000-7ffffffff000 rw-p 00000000 00:00 0 [stack] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] Program received signal SIGABRT, Aborted. 0x00007ffff753b425 in __GI_raise (sig=<optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 64 ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory. (gdb) bt #0 0x00007ffff753b425 in __GI_raise (sig=<optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 #1 0x00007ffff753eb8b in __GI_abort () at abort.c:91 #2 0x00007ffff757939e in __libc_message (do_abort=2, fmt=0x7ffff7683008 "*** glibc detected *** %s: %s: 0x%s ***\n") at ../sysdeps/unix/sysv/linux/libc_fatal.c:201 #3 0x00007ffff7583b96 in malloc_printerr (action=3, str=0x7ffff76831f8 "double free or corruption (fasttop)", ptr=<optimized out>) at malloc.c:5007 #4 0x00007ffff7b78c13 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 #5 0x00007ffff7540901 in __run_exit_handlers (status=0, listp=0x7ffff78bd688 <__exit_funcs>, run_list_atexit=true) at exit.c:78 #6 0x00007ffff7540985 in __GI_exit (status=<optimized out>) at exit.c:100 #7 0x00007ffff7526774 in __libc_start_main (main=0x400904 <main()>, argc=1, ubp_av=0x7fffffffd828, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffd818) at libc-start.c:258 #8 0x00000000004007f9 in _start () 

在这一点上,你知道你的一个全局的“std :: basic_string <…>”对象正在引起麻烦,但你不知道是哪一个。

找出这个问题是很简单的,只要进入第四帧并打印出来,对不对?

 (gdb) fr 4 #4 0x00007ffff7b78c13 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (gdb) p this No symbol "this" in current context. 

嗯,这样做效果不好,因为我没有安装libstdc++.so.6调试符号(如果引起麻烦的对象是在你自己的源代码中定义的,你不应该有这个麻烦)。

现在,我可以为我的libstdc++.so.6安装调试符号,或者我可以使用我的ABI知识。 在Linux / x86_64上,第一个( this )参数在寄存器%rdi传递。 我不能使用当前的%rdi ,因为它已经被用于别的东西了。 所以,而是我在问题析构函数上设置断点: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() ,然后重新启动。

在一个真正的程序中,析构函数会被调用很多,但是我只会对exit中的调用感兴趣。 所以我在exit时设置了断点,并且只有当这个断点被触发时,我才在析构函数上设置一个新的断点。

 (gdb) b exit (gdb) r Starting program: /tmp/a.out str: baz @0x601088) before dtor after dtor Breakpoint 1, __GI_exit (status=0) at exit.c:100 100 exit.c: No such file or directory. (gdb) b std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() Breakpoint 2 at 0x7ffff7b78bf0 (gdb) c Continuing. Breakpoint 2, 0x00007ffff7b78bf0 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (gdb) bt #0 0x00007ffff7b78bf0 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 #1 0x00007ffff7540901 in __run_exit_handlers (status=0, listp=0x7ffff78bd688 <__exit_funcs>, run_list_atexit=true) at exit.c:78 #2 0x00007ffff7540985 in __GI_exit (status=<optimized out>) at exit.c:100 #3 0x00007ffff7526774 in __libc_start_main (main=0x400904 <main()>, argc=1, ubp_av=0x7fffffffd828, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffd818) at libc-start.c:258 #4 0x00000000004007f9 in _start () (gdb) p/x $rdi $1 = 0x601088 (gdb) c Continuing. *** glibc detected *** /tmp/a.out: double free or corruption (fasttop): 0x0000000000602070 *** ... as before, omitted ... Program received signal SIGABRT, Aborted. 0x00007ffff753b425 in __GI_raise (sig=<optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 64 ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory. 

所以现在我们的地址是“坏”全球: 0x601088 ,你会注意到我打印的值匹配。

最后我们准备回答“哪个变量是? 题:

 (gdb) info sym 0x601088 baz in section .bss of /tmp/a.out 

Voilà:问题变量是baz 。 最后:

 (gdb) info var baz All variables matching regular expression "baz": File foo.cc: std::string baz; 

你可以在每个目标文件上使用nm -C (并将其结果grep到正在搜索的析构函数中)。

也许gdbptype命令可能会有所帮助。

你甚至可以考虑自定义你的海湾合作委员会,例如用MELT (用于扩展海湾合作委员会的领域特定语言)进行导航或重构(例如,在海岸警卫队做一个GCC扩展来帮助你)。 对于像你这样的大型项目来说,定制编译器(以及学习MELT)是值得的(至少帮助开发团队,例如通过使用MELT为你的编码规则定制GCC等)

对于这样的大型软件项目,我肯定也会建议你开始使用Doxygen。 它会为您节省每次运行grepnm -c的麻烦。