簡體   English   中英

gcc -g:會發生什么

[英]gcc -g :what will happen

我在接受采訪時問了這個問題。

他們問我如何生成我可以調試的核心轉儲文件。 然后我說用gcc -g標志我們可以做到。

然后他們問我-g標志對編譯器的確切作用。

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

任何人都可以告訴我它到底是做什么的?

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

如果 ...

  • 程序碰巧崩潰並生成一個核心文件(這表明實際代碼中存在一些問題),或者
  • 故意操作系統命令強制它進行核心操作(例如kill -SIGQUIT pid ),或者
  • 程序調用轉儲核心的函數(例如abort

...-其中沒有一個實際上是由使用-g引起的 - 然后調試器將知道如何從可執行文件中讀取“ -g ”符號信息並將其與核心進行交叉引用。 這意味着您可以在堆棧框架中查看變量和函數的正確名稱,獲取行號並在可執行文件中徘徊時查看源代碼。

調試時,調試信息非常有用 - 無論是以核心還是僅從可執行文件開始。 它甚至可以幫助從pstack命令中獲得更好的輸出。

請注意,您的環境可能有其他設置來控制是否生成核心(它們可能很大,並且沒有一般方法可以知道是否/何時可以刪除它們,因此並不總是需要它們)。 例如,在UNIX / LINUX shell上,它通常是ulimit -c

您可能還有興趣閱讀DWARF Wikipedia - 一種常用的調試信息格式,用於編碼可執行文件/庫對象中的嵌入式調試/符號信息(例如,在UNIX和Linux上)。

根據Victor的評論請求更新......

符號信息列出源代碼中的標識符(通常僅在需要任何名稱修改之后),它們將被加載到進程存儲器中的(虛擬)存儲器地址/偏移量,類型(例如數據與代碼)。 例如...

$ 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 (代表“TEXT” - 用於只讀非零內存內容,無論它實際上是文本還是其他數據或可執行代碼),
  • g_my_numB是一個具有隱式零值內存的全局內存,而
  • NS::ns_my_numD因為可執行文件必須顯式提供值2來占用該內存。

nmman / info- pages進一步記錄了這些東西......

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

gcc -g標志告訴gcc生成並嵌入調試信息。 ulimit -c用於啟用核心文件生成。 沒有另一個,你可以擁有其中任何一個。

-g將調試信息(變量名,行號等)添加到可執行文件中。 這是您需要做的事情的一部分,以便能夠理解核心文件。

http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html#Debugging-Options

當該過程接收到信號時,核心轉儲是過程的默認動作之一,例如標准信號“SIGQUIT”,“SIGILL”,“SIGABRT”,“SIGFPE”,“SIGSEGV”。 但是,大多數shell都會抑制核心文件的創建,因為核心文件往往很大,可能需要一些時間或大量時間。

為了啟用核心生成,“ulimit”是可用於設置shell或其子進程的文件限制的實用程序。

編譯器標志“-g”或僅與編譯器有關的任何內容。 從邏輯上講,它與核心轉儲無關。

如果你沒有放-g標志,就不能在gdb中調用列表來列出源代碼的樣子。 它將顯示“沒有加載符號表。使用”file“命令。”

此外,如果你鍵入info func或info frame,gdb中的信息本地,沒有-g它將不顯示返回數據類型及其參數,基本上沒有指令轉換為變量(從符號表映射)。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM