这个问题在接受我的采访时被问到了。
他们问我如何生成我可以调试的核心转储文件。
然后我说-g
gcc
中的-g
标志就可以了。
然后他们问我{{1}}标志对编译器的确切作用。
我说(可能是一个错误的答案)它会打开核心文件中可用于调试的所有符号。
谁能告诉我它究竟做了什么?
答案 0 :(得分:48)
这是正确的,但不完整。 -g
请求编译器和链接器在可执行文件中生成并保留源级调试/符号信息。
如果 ...
kill -SIGQUIT
pid )或abort
) ...-其中没有一个实际上是由使用-g
引起的 - 然后调试器将知道如何从可执行文件中读取“-g
”符号信息并交叉引用它核心。这意味着你可以在堆栈框架中看到变量和函数的正确名称,获取行号并在可执行文件中徘徊时查看源代码。
调试信息在调试时非常有用 - 无论是从核心开始还是仅从可执行文件开始。它甚至可以帮助从pstack
等命令产生更好的输出。
请注意,您的环境可能还有其他设置来控制是否生成核心(它们可能很大,并且没有一般方法可以知道是否/何时可以删除它们,因此并不总是需要它们)。例如,在UNIX / LINUX shell上,它通常是ulimit -c
。
您可能还有兴趣阅读DWARF Wikipedia - 一种常用的调试信息格式,用于对可执行文件/库对象中的嵌入式调试/符号信息进行编码(例如,在UNIX和Linux上)。 / p>
根据评论中的Victor请求更新......
符号信息列出源代码中的标识符(通常仅在需要任何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
(代表“TEXT” - 用于只读非零内存内容,无论它实际上是文本还是其他数据或可执行文件码),g_my_num
B
是一个全局隐式归零内存,而NS::ns_my_num
为D
,因为可执行文件必须明确提供值2
才能占用该内存。 man/info-page for nm
进一步记录了这些事情......
答案 1 :(得分:9)
-g标志告诉编译器生成调试信息。它对是否生成核心文件没有影响。在大多数类似unix的系统上,可以使用ulimit命令进行设置。
答案 2 :(得分:5)
gcc -g标志告诉gcc生成并嵌入调试信息。 ulimit -c
用于启用核心文件生成。你可以没有其中任何一个。
答案 3 :(得分:3)
-g
将调试信息(变量名,行号等)添加到可执行文件中。这是您需要做的一部分,以便能够理解核心文件。
http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html#Debugging-Options
答案 4 :(得分:1)
在Segmentation Fault上生成核心文件或此类异常。 gdb source.cc core
是查看核心文件的一种方法。回溯和调查每一帧是开始研究核心。 -g
在二进制文件中添加调试符号。
答案 5 :(得分:1)
核心转储是进程的默认操作之一,当此进程接收到信号时,例如在标准信号“SIGQUIT”,“SIGILL”,“SIGABRT”,“SIGFPE”,“SIGSEGV”中。但是,大多数shell都会抑制核心文件的创建,因为核心文件往往很大,可能需要一些时间或大量时间。
为了启用核心生成,“ulimit”是可用于设置shell或其子进程的文件限制的实用程序。
编译器标记“-g”或仅与编译器有关的任何内容。从逻辑上讲,它与核心转储无关。
答案 6 :(得分:1)
如果你没有放-g标志,就不能在gdb中调用列表列出源代码的样子。它将显示"没有加载符号表。使用"文件" 。命令"
此外,如果你键入info func或info frame,在gdb中输入信息本地,没有-g它将不显示返回数据类型及其参数,基本上没有指令转换为变量(从符号表映射)。