2013-03-31 33 views
4

我們有一個非常大的項目(約200,000個文件)如何使用gdb找到全局變量的析構函數調用?

當項目退出時,它崩潰在一個全局變量的解構。

但我們無法找到變量定義的位置。

有沒有人知道如何找到全局變量的位置?

+1

grep比gdb更有用。 – Cairnarvon

+0

如果您使用IDE,它可以顯示變量的定義位置。如果沒有,嘗試在某個IDE(KDevelop,Code :: Blocks等)中創建一個項目並詢問它。 – Aneri

回答

9

但是我們找不到變量定義在哪裏。

大概你想找出哪個全局變量引起的麻煩。如果您知道它是哪一個,則可以使用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() 

在這一點上,你知道你的全球的一個「標準:: basic_string的< ...>」的對象是造成麻煩,但你不知道哪一個。

這將是微不足道的發現:只是去幀#4和打印this,對不對?

(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 

問題:問題變量是baz。最後:

(gdb) info var baz 
All variables matching regular expression "baz": 

File foo.cc: 
std::string baz; 
1

您可以在每個目標文件上使用nm -C(並將grep的結果輸入到正在搜索的析構函數中)。

也許命令gdb可能會有所幫助。

你甚至可以考慮自定義你的GCC例如與MELT(用於擴展GCC的領域特定語言)進行導航或重構(即,在MELT中創建GCC擴展以幫助您)。對於像你這樣的大項目來說,定製編譯器(以及學習MELT)是值得的(至少幫助開發團隊,例如通過爲你的編碼規則定製GEL和MELT等)。

+0

但是爲了擴展GCC,即使使用MELT,您也需要了解一些GCC內部信息(並學習MELT語言),這意味着一些工作(或者轉包)。 –

0

對於這樣大的軟件項目我肯定也會建議你開始使用Doxygen。 每次都會爲您節省運行grepnm -c的麻煩。

相關問題