В началоИзучаем параметры gcc → Опции, относящиеся к отладке.
Gentoo-doc HOME Пред.: Параметры, относящиеся к вызову функцийВ началоУровень выше: Изучаем параметры gccСлед.: Опции, управляющие стадиями компиляции.

3. Опции, относящиеся к отладке.

Каждый иногда нуждается в отладке его или её кода. Когда это время приходит, обычно вы запускаете 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След.: Опции, управляющие стадиями компиляции.
В началоИзучаем параметры gcc → Опции, относящиеся к отладке.