Почему GDB непредсказуемо скачет между строками и печатает переменные как "<значение оптимизировано>"?

Может ли кто-нибудь объяснить это поведение gdb?

900         memset(&new_ckpt_info,'\0',sizeof(CKPT_INFO));
(gdb)
**903         prev_offset   = cp_node->offset;**
(gdb)
**905         m_CPND_CKPTINFO_READ(ckpt_info,(char *)cb->shm_addr.ckpt_addr+sizeof(CKPT_** HDR),i_offset);
(gdb)
**903         prev_offset   = cp_node->offset;**
(gdb)
**905         m_CPND_CKPTINFO_READ(ckpt_info,(char *)cb->shm_addr.ckpt_addr+sizeof(CKPT_ HDR),i_offset);**
(gdb)
**908         bitmap_offset  = client_hdl/32;**
(gdb)
**910         bitmap_value = cpnd_client_bitmap_set(client_hdl%32);**
(gdb)
**908         bitmap_offset  = client_hdl/32;**
(gdb)
**910         bitmap_value = cpnd_client_bitmap_set(client_hdl%32);**
(gdb)
**908         bitmap_offset  = client_hdl/32;**
(gdb)
**910         bitmap_value = cpnd_client_bitmap_set(client_hdl%32);**
(gdb)
913         found = cpnd_find_exact_ckptinfo(cb , &ckpt_info , bitmap_offset , &offset , &prev_offset);
(gdb)
916         if(!found)
(gdb) p found
$1 = <value optimized out>
(gdb) set found=0
Left operand of assignment is not an lvalue.

Почему после выполнения строки 903 он снова выполняет то же самое для 905 908 910?

Другая вещь found - это переменная типа bool, поэтому почему она показывает value optimized out? Я также не могу установить значение found.

Это, по-видимому, оптимизация компилятора (в данном случае его -O2); как я могу установить значение found?

Ответ 1

Чтобы отладить оптимизированный код, изучите язык сборки/машины.

Используйте режим TUI GDB. Моя копия GDB позволяет это, когда я набираю минус и Enter. Затем введите C-x 2 (удерживая нажатой клавишу Control и нажмите X, отпустите оба и затем нажмите 2). Это поместит его в разделительный источник и демонстрационный дисплей. Затем используйте stepi и nexti для перемещения одной машинной команды за раз. Используйте C-x o для переключения между окнами TUI.

Загрузите PDF файл о вашем языке машинного процессора и соглашениях о вызовах функций. Вы быстро научитесь распознавать, что делается с аргументами функции и возвращаемыми значениями.

Вы можете отобразить значение регистра с помощью команды GDB, например p $eax

Ответ 2

Перекомпилируйте без оптимизации (-O0 на gcc).

Ответ 3

Объявить найденным как "volatile". Это должно сказать компилятору НЕ оптимизировать его.

volatile int found = 0;

Ответ 4

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

Скомпилировать без оптимизаций?

Ответ 5

Обычно логические значения, которые используются в ветвях сразу после их вычисления, как никогда, никогда не сохраняются в переменных. Вместо этого компилятор просто веткится непосредственно из кодов условий, которые были установлены из предыдущего сравнения. Например,

int a = SomeFunction();
bool result = --a >= 0; // use subtraction as example computation
if ( result ) 
{
   foo(); 
}
else
{
   bar();
}
return;

Обычно компилируется что-то вроде:

call .SomeFunction  ; calls to SomeFunction(), which stores its return value in eax
sub eax, 1 ; subtract 1 from eax and store in eax, set S (sign) flag if result is negative
jl ELSEBLOCK ; GOTO label "ELSEBLOCK" if S flag is set
call .foo ; this is the "if" black, call foo()
j FINISH ; GOTO FINISH; skip over the "else" block
ELSEBLOCK: ; label this location to the assembler
call .bar
FINISH: ; both paths end up here
ret ; return

Обратите внимание, что "bool" никогда не хранится нигде.

Ответ 6

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

Ответ 7

При отладке оптимизированных программ (которые могут потребоваться, если ошибка не отображается в отладочных сборках), вам часто приходится разбираться в компиляторе сборки.

В вашем конкретном случае возвращаемое значение cpnd_find_exact_ckptinfo будет храниться в регистре, который используется на вашей платформе для возвращаемых значений. На ix86 это будет %eax. В x86_64: %rax и т.д. Возможно, вам понадобится Google для процедуры "[ваш процессор], вызывающей соглашение", если это не указано выше.

Вы можете проверить этот регистр в GDB, и вы можете его установить. Например. на ix86:

(gdb) p $eax
(gdb) set $eax = 0 

Ответ 8

Im, использующий QtCreator с gdb.

Добавление

QMAKE_CXXFLAGS += -O0
QMAKE_CXXFLAGS -= -O1
QMAKE_CXXFLAGS -= -O2
QMAKE_CXXFLAGS -= -O3

Хорошо работает для меня