В начало → Изучаем параметры gcc → Опции, относящиеся к отладке. |
Каждый иногда нуждается в отладке его или её кода. Когда это время приходит, обычно вы запускаете gdb, ставите точки останова там и тут, анализируете бэктрейсы, и так далее, чтобы выявить расположение нарушающего работу кода. А что получаете на самом деле? Если вы не используете опции отладки, вы просто получаете адрес, указывающий на регистр EIP.
Вот в чем проблема, в действительности вы не хотите адрес. Вы хотите, чтобы gdb или другой отладчик просто показал требуемые строки. Но gdb не может этого сделать без определенного вида помощи. Эта помощь, называемая отладкой с приписываемыми форматами записи (Debugging With Attributed Record Formats — DWARF), помогает вам выполнять отладку на уровне исходного кода.
Как это сделать? Используйте -g при компиляции в объектный код, то есть:
$
gcc -o -g test test.c
Что такого добавляет gcc, что отладчик может сопоставлять адрес с исходным кодом? Вам нужна dwarfdump [7] чтобы узнать это. Это утилита находится внутри тарболла libdwarf или в RPM, так что вы не найдете её в виде отдельного пакета. Скомпилируйте её сами или просто установите из репозитория вашего дистрибутива; оба варианта должны сработать. В этой части статьи я использую версию 20060614 RPM.
Используя readelf, вы можете отметить, что в неотлаженной версии первого листинга существует 28 разделов:
$
readelf -S ./non-optimized
Но в отлаженной версий есть 36 разделов. Новые разделы:
* debug_arranges
* debug_pubnames
* debug_info
* debug_abbrev
* debug_line
* debug_frame
* debug_str
* debug_loc
Вам не нужно копаться во всех этих разделах; для быстрого изучения, будет достаточно рассмотреть .debug_line. Команда, которая вам нужна:
$
/path/to/dwarfdump -l
Вот пример того, что вы получите:
.debug_line: line number info for a single cu Source lines (from CU-DIE at .debug_info offset 11): [row,column] //
Интерпретация этих сообщений довольно простая. Возьмите первую запись (идущую за строкой
line number 3 in file non-optimized.c is located in address 0x8048384.
gdb дает ту же информацию:
$
gdb non-optimized-debugging
(gdb) l *0x8048384 0x8048384 is in main (./non-optimized.c:3).
readelf также предоставляет похожую информацию, используя --debug-info:
$
readelf --debug-dump=line
Line Number Statements: Extended opcode 2: set Address to 0x8048384 Special opcode 7: advance Address by 0 to 0x8048384 and Line by 2 to 3 Advance PC by constant 17 to 0x8048395 Special opcode 7: advance Address by 0 to 0x8048395 and Line by 2 to 5 ....
И readelf, и dwarfdump могут анализировать информацию отладки, так что вы вольны выбирать сами.
Что вы должны понимать, так это то, что исходный код сам по себе не встроен в объектный файл. На самом деле, отладчик должен проверять отдельный файл исходного кода. Запись в колонке
$
gcc -O2 -ggdb -o debug-optimized listing-one.c
$
readelf --debug-dump=line debug-optimized
.. Special opcode 107: advance Address by 7 to 0x80483aa and Line by 4 to 11 ...
Но что говорит gdb?
$
gdb debug-optimized
(gdb) l *0x80483aa 0x80483aa is in main (./non-optimized.c:11). ... 11 printf("acc = %lu\n",acc); ... (gdb) disassemble main ... 0x080483aa : add $0x6,%edx 0x080483ad : cmp $0x1388,%eax ...
Здесь вы видите полное расхождение. Изучая одну информацию об отладке, вы будете ожидать, что указанный адрес содержит что-то вроде инструкции CALL. Но в действительности, вы получите инструкции ADD и CMP, что больше похоже на конструкцию цикла. Это побочный эффект действий оптимизации — в этом случае меняется порядок инструкций. Так что возьмите себе за правило не смешивать опции -g (или её варианты) c -O.
В начало → Изучаем параметры gcc → Опции, относящиеся к отладке. |