Gcc -g: что произойдет

Этот вопрос был задан мне в интервью.

они спросили меня, как создать файл дампа ядра, с которым я могу отлаживать. то я сказал, что с флагом -g в gcc мы можем это сделать.

то они спросили меня, что именно делает этот флаг -g для компилятора.

Я сказал (вероятно, неверный ответ), что он откроет все символы в основном файле, которые можно использовать для отладки.

может кто-нибудь сказать мне, что именно он делает?

Ответ 1

Такой правильный, но неполный. -g запрашивает, чтобы компилятор и компоновщик генерировали и сохраняли информацию о символе в самом исполняемом файле.

Если программа случится с последующим сбоем и создаст файл ядра (что говорит о некоторой проблеме в фактическом коде) или преднамеренная команда ОС заставила его занять ядро ​​(например, kill -SIGQUIT pid), или программа вызывает функцию, которая (например, abort) - ни один из которых фактически не вызван использованием -g - тогда отладчик будет знать, как читать что "-g" символьная информация из исполняемого файла и перекрестная ссылка на него с ядром. Это означает, что вы можете видеть правильные имена переменных и функций в ваших кадрах стека, получать номера строк и видеть исходный код при шаге в исполняемом файле.

Эта информация символа полезна всякий раз, когда отладка - независимо от того, начинаете ли вы с ядра или только с исполняемого файла. Это даже помогает улучшить вывод команд, таких как pstack.

ОБНОВЛЕНИЕ на запрос Виктора в комментариях...

Информация о символах перечисляет идентификаторы из исходного кода (обычно только после того, как требуется любое 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 будет документировать эти вещи....

Ответ 2

Флаг -g сообщает компилятору генерировать отладочную информацию. Это не влияет на то, будет ли генерироваться основной файл. В большинстве UNIX-подобных систем, которые можно настроить с помощью команды ulimit.

Ответ 3

Флаг gcc -g сообщает gcc генерировать и вставлять отладочную информацию. ulimit -c используется для включения генерации основного файла. Вы можете иметь любой из них без другого.

Ответ 4

файл ядра генерируется при ошибке сегментации или таких исключениях. gdb source.cc core - это один из способов взглянуть на основной файл. Backtrace и исследование каждого кадра - это начало при просмотре ядра. -g добавляет отладочные символы в двоичном формате.

Ответ 5

-g добавляет информацию об отладке (имена переменных, номера строк и т.д.) в исполняемый файл. Это часть того, что вам нужно сделать, чтобы иметь возможность понять основной файл.

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

Ответ 6

core dump является одним из действий по умолчанию процесса, когда этот процесс принимает сигналы, например. в стандартных сигналах "SIGQUIT", "SIGILL", "SIGABRT", "SIGFPE", "SIGSEGV". Однако большинство оболочек подавляют создание основного файла, просто потому, что файлы ядра имеют большой размер, и это может занять некоторое время или много времени.

чтобы включить генерацию ядра, "ulimit" - это утилита, которую вы можете использовать для установки ограничения файла файла оболочки или его дочернего процесса.

флаги компилятора "-g" или что-то еще, что касается только компилятора. логически говоря, это не имеет никакого отношения к дампу ядра.

Ответ 7

Если вы не установите флаг -g, не можете вызвать список в gdb, чтобы указать, как выглядит исходный код. он покажет "Таблица символов не загружена. Используйте команду" файл ".

Кроме того, если вы вводите info func или info-кадр, данные locals в gdb, без -g, он не будет отображать возвращаемый тип данных и его аргументы, в основном отсутствие перевода команды в переменную (отображение из таблицы символов).