這個問題在接受採訪時問了我。gcc -g:會發生什麼
他們問我如何生成一個可以調試的核心轉儲文件。 然後我說-g
國旗在gcc
我們可以做到。
然後他們問我,-g
標誌對編譯器做了什麼。
我說(可能是一個錯誤的答案),它會打開核心文件中的所有可用於調試的符號。
誰能告訴我它究竟做了什麼?
這個問題在接受採訪時問了我。gcc -g:會發生什麼
他們問我如何生成一個可以調試的核心轉儲文件。 然後我說-g
國旗在gcc
我們可以做到。
然後他們問我,-g
標誌對編譯器做了什麼。
我說(可能是一個錯誤的答案),它會打開核心文件中的所有可用於調試的符號。
誰能告訴我它究竟做了什麼?
這是正確的,但不完整。 -g
請求編譯器和鏈接器在可執行文件本身中生成並保留符號信息。
如果程序發生後崩潰併產生一個核心文件(這表明在實際的代碼中的一些問題),或者故意OS命令它被迫核心(例如kill -SIGQUIT
PID),或在程序調用一個轉儲內核的函數(例如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_num
是B
是一個全球性的具有隱含零編出內存,而NS::ns_my_num
是D
作爲可執行有明確規定值2
佔據該內存。 nm
的man/info-page將記錄這些東西......
注意:'strip'實用程序執行反向操作,即它帶一個帶有調試符號的庫並將其去掉。 – 2011-03-03 10:34:56
什麼是符號信息?你能爲我提供更多的ELIF嗎? – 2016-03-02 05:08:47
@VictorLin:我不知道ELIF是什麼...... – 2016-03-02 05:24:26
-g標誌告訴編譯器生成調試信息。它不會影響核心文件是否會生成。在大多數類Unix系統上,可以使用ulimit命令進行設置。
但我想知道調試信息到底是什麼。我知道你已經知道了,我需要的東西超出了這個範圍。 – Vijay 2011-03-03 10:09:08
@wvwvwv Beyound,它很複雜 - 一個徹底的描述需要幾十頁。您可以從查看DWARF(http://dwarfstd.org/Download.php)標準開始,該標準是嵌入在可執行文件(大多數* nixes)中的調試符號的規範。 -g指示編譯器/鏈接器生成並將這些結構嵌入到可執行文件中。下一步可能是瞭解調試器如何使用此調試信息。 – nos 2011-03-03 10:15:06
簡而言之,它添加了關於符號名稱(函數,局部和全局變量等)的信息以及有關類型,源文件名和行號的信息。它也可以通過自動定義的宏在不同的頭文件中(例如STL和assert宏的定義)進行調試。它可能也會爲內聯函數生成特殊輸出,因此可以加入內聯函數/方法。 – Axel 2011-03-03 10:23:43
gcc -g標誌告訴gcc生成並嵌入調試信息。 ulimit -c
用於啓用核心文件生成。你可以沒有其他任何一個。
核心文件在分割錯誤或類似的異常上產生。 gdb source.cc core
是查看核心文件的一種方法。追蹤和調查每一幀是研究核心的開始。 -g
在二進制文件中添加了調試符號。
-g
向可執行文件添加調試信息(變量名稱,行號等)。這是你需要做的能夠理解核心文件的一部分。
http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html#Debugging-Options
核心轉儲的process's默認動作之一,當該過程接收信號,例如在標準信號「SIGQUIT」,「SIGILL」,「SIGABRT」,「SIGFPE」,「SIGSEGV」中。但是,大多數shell會壓制核心文件的創建,只是因爲核心文件往往很大,而且可能需要一些時間或很多時間。
爲了啓用核心生成,「ulimit」是您可以用來設置shell或其子進程的文件限制的實用程序。
編譯器標誌「-g」或任何只與編譯器有關的東西。從邏輯上講,它與核心轉儲無關。
如果你沒有使用-g標誌,就不能在gdb中調用列表來列出源代碼的外觀。它會顯示「沒有符號表被加載,使用」文件「命令。」
此外,如果您輸入info func或info frame,gdb中的info locals,則不使用-g,它不會顯示返回數據類型及其參數,基本上沒有將指令轉換爲變量(從符號表映射)。
可能值得一提的是,如果要生成進程的核心轉儲,可以將其PID傳遞給gcore命令。 – atx 2011-03-11 11:23:46