Почему GDB непредсказуемо перепрыгивает между строками и печатает переменные как «<value optimized out>»? - PullRequest
83 голосов
/ 28 августа 2009

Кто-нибудь может объяснить это поведение 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?

Ответы [ 8 ]

113 голосов
/ 30 августа 2009

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

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

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

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

74 голосов
/ 31 августа 2009

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

38 голосов
/ 28 августа 2009

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

volatile int found = 0;
11 голосов
/ 28 августа 2009

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

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

6 голосов
/ 28 августа 2009

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

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" никогда не хранится нигде.

4 голосов
/ 29 августа 2009

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

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

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

(gdb) p $eax
(gdb) set $eax = 0 
4 голосов
/ 28 августа 2009

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

0 голосов
/ 23 декабря 2015

Я использую QtCreator с GDB.

Добавление

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

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

...