2011-03-03 121 views
29

這個問題在接受採訪時問了我。gcc -g:會發生什麼

他們問我如何生成一個可以調試的核心轉儲文件。 然後我說-g國旗在gcc我們可以做到。

然後他們問我,-g標誌對編譯器做了什麼。

我說(可能是一個錯誤的答案),它會打開核心文件中的所有可用於調試的符號。

誰能告訴我它究竟做了什麼?

+2

可能值得一提的是,如果要生成進程的核心轉儲,可以將其PID傳遞給gcore命令。 – atx 2011-03-11 11:23:46

回答

35

這是正確的,但不完整。 -g請求編譯器和鏈接器在可執行文件本身中生成並保留符號信息。

如果程序發生後崩潰併產生一個核心文件(這表明在實際的代碼中的一些問題),或者故意OS命令它被迫核心(例如kill -SIGQUITPID),或在程序調用一個轉儲內核的函數(例如abort) - 其中沒有一個實際上是由於使用-g引起的 - 那麼調試器將知道如何從可執行文件讀取該「-g」符號信息並將其與核心進行交叉引用。這意味着您可以在堆棧框架中查看變量和函數的正確名稱,獲取行號並在您執行可執行文件時查看源代碼。

無論何時調試,該符號信息都很有用 - 無論您是以核心還是僅以可執行文件開始。它甚至可以幫助產生更好的命令,如pstack

每維克多在評論請求

UPDATE ...

符號信息列出了從源代碼標識符(通常只需要任何name mangling後),(虛擬)內存地址/偏移,在其中他們會加載到進程內存中,類型(例如數據與代碼)。例如...

$ cat ok.cc 
int g_my_num; 
namespace NS { int ns_my_num = 2; } 
int f() { return g_my_num + NS::ns_my_num; } 
int main() { return f(); } 

$ g++ -g ok.cc -o ok # compile ok executable with symbol info 

$ nm ok # show mangled identifiers 
00000000004017c8 d _DYNAMIC 
0000000000401960 d _GLOBAL_OFFSET_TABLE_ 
0000000000400478 R _IO_stdin_used 
       w _ITM_deregisterTMCloneTable 
       w _ITM_registerTMCloneTable 
       w _Jv_RegisterClasses 
000000000040037c T _Z1fv      # this is f() 
0000000000401798 D _ZN2NS9ns_my_numE   # this is NS::ns_my_num 
00000000004017a8 d __CTOR_END__ 
00000000004017a0 d __CTOR_LIST__ 
00000000004017b8 d __DTOR_END__ 
00000000004017b0 d __DTOR_LIST__ 
0000000000400540 r __FRAME_END__ 
00000000004017c0 d __JCR_END__ 
00000000004017c0 d __JCR_LIST__ 
00000000004017c8 d __TMC_END__ 
00000000004017c8 d __TMC_LIST__ 
0000000000401980 A __bss_start 
0000000000401788 D __data_start 
0000000000400440 t __do_global_ctors_aux 
00000000004002e0 t __do_global_dtors_aux 
0000000000401790 d __dso_handle 
0000000000000000 a __fini_array_end 
0000000000000000 a __fini_array_start 
       w __gmon_start__ 
0000000000000000 a __init_array_end 
0000000000000000 a __init_array_start 
00000000004003a0 T __libc_csu_fini 
00000000004003b0 T __libc_csu_init 
       U __libc_start_main 
0000000000000000 a __preinit_array_end 
0000000000000000 a __preinit_array_start 
0000000000401980 A _edata 
0000000000401994 A _end 
0000000000400494 T _fini 
000000000040047c T _init 
0000000000400220 T _start 
000000000040024c t call_gmon_start 
0000000000401980 b completed.6118 
0000000000401788 W data_start 
0000000000400270 t deregister_tm_clones 
0000000000401988 b dtor_idx.6120 
0000000000401994 A end 
0000000000400350 t frame_dummy 
0000000000401990 B g_my_num     # our global g_my_num 
0000000000400390 T main      # the int main() function 
00000000004002a0 t register_tm_clones 

$ nm ok | c++filt   # c++filt "unmangles" identifiers... 
00000000004017c8 d _DYNAMIC 
0000000000401960 d _GLOBAL_OFFSET_TABLE_ 
0000000000400478 R _IO_stdin_used 
       w _ITM_deregisterTMCloneTable 
       w _ITM_registerTMCloneTable 
       w _Jv_RegisterClasses 
000000000040037c T f() 
0000000000401798 D NS::ns_my_num 
00000000004017a8 d __CTOR_END__ 
00000000004017a0 d __CTOR_LIST__ 
00000000004017b8 d __DTOR_END__ 
00000000004017b0 d __DTOR_LIST__ 
0000000000400540 r __FRAME_END__ 
00000000004017c0 d __JCR_END__ 
00000000004017c0 d __JCR_LIST__ 
00000000004017c8 d __TMC_END__ 
00000000004017c8 d __TMC_LIST__ 
0000000000401980 A __bss_start 
0000000000401788 D __data_start 
0000000000400440 t __do_global_ctors_aux 
00000000004002e0 t __do_global_dtors_aux 
0000000000401790 d __dso_handle 
0000000000000000 a __fini_array_end 
0000000000000000 a __fini_array_start 
       w __gmon_start__ 
0000000000000000 a __init_array_end 
0000000000000000 a __init_array_start 
00000000004003a0 T __libc_csu_fini 
00000000004003b0 T __libc_csu_init 
       U __libc_start_main 
0000000000000000 a __preinit_array_end 
0000000000000000 a __preinit_array_start 
0000000000401980 A _edata 
0000000000401994 A _end 
0000000000400494 T _fini 
000000000040047c T _init 
0000000000400220 T _start 
000000000040024c t call_gmon_start 
0000000000401980 b completed.6118 
0000000000401788 W data_start 
0000000000400270 t deregister_tm_clones 
0000000000401988 b dtor_idx.6120 
0000000000401994 A end 
0000000000400350 t frame_dummy 
0000000000401990 B g_my_num 
0000000000400390 T main 
00000000004002a0 t register_tm_clones 

請注意,我們的功能f()main()T型,g_my_numB是一個全球性的具有隱含零編出內存,而NS::ns_my_numD作爲可執行有明確規定值2佔據該內存。 nm的man/info-page將記錄這些東西......

+4

注意:'strip'實用程序執行反向操作,即它帶一個帶有調試符號的庫並將其去掉。 – 2011-03-03 10:34:56

+0

什麼是符號信息?你能爲我提供更多的ELIF嗎? – 2016-03-02 05:08:47

+0

@VictorLin:我不知道ELIF是什麼...... – 2016-03-02 05:24:26

8

-g標誌告訴編譯器生成調試信息。它不會影響核心文件是否會生成。在大多數類Unix系統上,可以使用ulimit命令進行設置。

+0

但我想知道調試信息到底是什麼。我知道你已經知道了,我需要的東西超出了這個範圍。 – Vijay 2011-03-03 10:09:08

+0

@wvwvwv Beyound,它很複雜 - 一個徹底的描述需要幾十頁。您可以從查看DWARF(http://dwarfstd.org/Download.php)標準開始,該標準是嵌入在可執行文件(大多數* nixes)中的調試符號的規範。 -g指示編譯器/鏈接器生成並將這些結構嵌入到可執行文件中。下一步可能是瞭解調試器如何使用此調試信息。 – nos 2011-03-03 10:15:06

+0

簡而言之,它添加了關於符號名稱(函數,局部和全局變量等)的信息以及有關類型,源文件名和行號的信息。它也可以通過自動定義的宏在不同的頭文件中(例如STL和assert宏的定義)進行調試。它可能也會爲內聯函數生成特殊輸出,因此可以加入內聯函數/方法。 – Axel 2011-03-03 10:23:43

4

gcc -g標誌告訴gcc生成並嵌入調試信息。 ulimit -c用於啓用核心文件生成。你可以沒有其他任何一個。

1

核心文件在分割錯誤或類似的異常上產生。 gdb source.cc core是查看核心文件的一種方法。追蹤和調查每一幀是研究核心的開始。 -g在二進制文件中添加了調試符號。

1

核心轉儲的process's默認動作之一,當該過程接收信號,例如在標準信號「SIGQUIT」,「SIGILL」,「SIGABRT」,「SIGFPE」,「SIGSEGV」中。但是,大多數shell會壓制核心文件的創建,只是因爲核心文件往往很大,而且可能需要一些時間或很多時間。

爲了啓用核心生成,「ulimit」是您可以用來設置shell或其子進程的文件限制的實用程序。

編譯器標誌「-g」或任何只與編譯器有關的東西。從邏輯上講,它與核心轉儲無關。

0

如果你沒有使用-g標誌,就不能在gdb中調用列表來列出源代碼的外觀。它會顯示「沒有符號表被加載,使用」文件「命令。」

此外,如果您輸入info func或info frame,gdb中的info locals,則不使用-g,它不會顯示返回數據類型及其參數,基本上沒有將指令轉換爲變量(從符號表映射)。