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

84

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

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

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

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

Арпит
источник
8
при отладке обычно рекомендуется компилировать с параметром -O0, поскольку оптимизация приводит к такого рода проблемам.
LiraNuna

Ответы:

115

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

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

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

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

Зан Рысь
источник
У меня все еще есть проблема с "оптимизацией", и значение переменной не отображается в других окнах, но, тем не менее, это отличная информация, спасибо!
Том Брито
16
@TomBrito: Оптимизировано означает, что переменная отсутствует в памяти. Вероятно, он находится только в регистре ЦП, что означает, что вам нужно прочитать разборку и распечатать значения регистров, чтобы найти ее.
Zan Lynx
@Zan Lynx: Я не уверен, что согласен с вашим анализом. Символы DWARF содержат достаточно информации для извлечения значений из регистров. Возможно, здесь имеется в виду, что компилятор определил, что переменная может быть безопасно отброшена, когда выполнение достигнет текущей строки. В этом случае хранилище, в котором находится переменная, вероятно, было повторно использовано для чего-то другого. Я думаю, вы правы, что обычно это происходит только в том случае, если переменная была зарегистрирована.
Ян Ни-Льюис,
@ IanNi-Lewis: Я не знаю, какую версию DWARF вы используете, но по моему опыту GDB не может распечатать переменную, которая была сохранена в регистре.
Zan Lynx
Я уверен, ты прав. Мой опыт работы с DWARF связан с написанием собственного парсера, а не с использованием gdb, поэтому я действительно не знаю, на что способен gdb.
Ян Ни-Льюис,
75

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

Д'Набр
источник
17
Даже -O0 может создавать оптимизированный код (пытаясь бороться с этим прямо сейчас), хотя я не уверен, почему.
Крис Грегг
@ChrisGregg У меня такая же проблема! Вы узнали, в чем проблема?
Paolo M
1
@paolom похоже, что это может быть проблема clang, поэтому, к сожалению, я компилировал с g ++ для целей отладки.
Крис Грегг
Часто это не решение, особенно если у вас есть дамп ядра из производственной среды и / или вы не можете воспроизвести проблему в среде разработки.
smbear
39

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

BenB
источник
1
Даже когда я объявляю некоторые переменные "volatile" в отладчике gdb, он показывает их как оптимизированную переменную! Есть ли что-то еще в этом?
M.Rez 08
11

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

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

Kjfletch
источник
6

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

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

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

Crashworks
источник
4

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

нет
источник
4

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

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

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

Занятые русские
источник
0

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

Добавление

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

Haselnussstrauch
источник