Может ли кто-нибудь объяснить такое поведение 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
?
Ответы:
Чтобы отладить оптимизированный код, изучите ассемблер / машинный язык.
Используйте режим GDB TUI. Моя копия GDB включает его, когда я набираю минус и Enter. Затем введите Cx 2 (то есть удерживайте Control и нажмите X, отпустите оба и нажмите 2). Это поместит его в разделенный исходный код и дисплей разборки. Затем используйте
stepi
иnexti
для перемещения по одной машинной инструкции за раз. Используйте Cx o для переключения между окнами TUI.Загрузите PDF-файл о машинном языке вашего процессора и соглашениях о вызове функций. Вы быстро научитесь распознавать, что делается с аргументами функции и возвращаемыми значениями.
Вы можете отобразить значение регистра, используя команду GDB, например
p $eax
источник
Перекомпилируйте без оптимизаций (-O0 на gcc).
источник
Объявить найденное как «изменчивое». Это должно сказать компилятору НЕ оптимизировать его.
volatile int found = 0;
источник
Компилятор начнет делать очень умные вещи с включенной оптимизацией. Отладчик будет показывать, что код много прыгает вперед и назад из-за оптимизированного способа хранения переменных в регистрах. Вероятно, это причина, по которой вы не можете установить свою переменную (или в некоторых случаях увидеть ее значение), поскольку она была разумно распределена между регистрами для скорости, вместо того, чтобы иметь прямую ячейку памяти, к которой может получить доступ отладчик.
Скомпилировать без оптимизаций?
источник
Как правило, логические значения, которые используются в ветвях сразу после того, как они вычисляются таким образом, на самом деле никогда не сохраняются в переменных. Вместо этого компилятор просто выполняет ответвления непосредственно от кодов условий, которые были установлены в предыдущем сравнении. Например,
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» на самом деле нигде не сохраняется.
источник
Вы практически не можете установить значение found. Отладка оптимизированных программ редко стоит проблем, компилятор может переупорядочить код таким образом, чтобы он никоим образом не соответствовал исходному коду (кроме получения того же результата), тем самым беспредельно запутывая отладчиков.
источник
При отладке оптимизированных программ (что может потребоваться, если ошибка не обнаруживается в отладочных сборках), вам часто приходится разбираться в сгенерированном компиляторе сборки.
В вашем конкретном случае возвращаемое значение
cpnd_find_exact_ckptinfo
будет храниться в регистре, который используется на вашей платформе для возвращаемых значений. Оix86
, это было бы%eax
. Вклx86_64
:%rax
и т. Д. Вам может потребоваться поискать в Google «соглашение о вызове процедуры [ваш процессор]», если не указано иное.Вы можете проверить этот регистр
GDB
и настроить его. Напримерix86
:(gdb) p $eax (gdb) set $eax = 0
источник
Я использую QtCreator с gdb.
Добавление
Хорошо работает для меня
источник