Почему Minidumps не дают хорошие столы вызовов?

Я использовал minidumps во многих игровых проектах на протяжении многих лет, и у них, похоже, 50% вероятность наличия действительного стека вызовов. Что я могу сделать, чтобы у них были лучшие стеки вызовов?

Я попытался поместить последнюю dbghelp.dll в каталог exe. Кажется, это помогает.

Лучше ли Visual Studio 2008 или 2010? (Я все еще на VS 2005).

Используемый мной код выглядит как этот пример.

Ответ 1

Одна вещь, которую вы можете сделать для повышения точности стеков вызовов, найденных в дампах, - использовать отладчик, отличный от Visual Studio, - в частности, использовать WinDbg или другой инструмент, который использует механизм отладки "Отладчик Windows", найденный в dbgeng.dll(в отличие от механизма отладки Visual Studio Debugger, который использует Visual Studio).

По нашему опыту, WinDbg на 100% надежна в создании хороших стеков вызовов с тех же дампов, где Visual Studio создает непригодные или дико неточные стеки вызовов. Из того, что я могу сказать, в случаях, когда необработанное исключение является источником сбоя, WinDbg автоматически выполняет сложный процесс восстановления/восстановления стоп-кары исключений, но Visual Studio не делает (или не может?). Два отладчика используют различные эвристики для интерпретации стеков

WinDbg может быть пугающим сначала, поэтому здесь мое краткое руководство о том, как упростить или даже не использовать его напрямую.

Простое Mortal Guide для извлечения хороших вызовов

Они упорядочены с "самой быстрой/простой" до "самой медленной/самой загадочной для интерпретации".

  • Самый простой вариант: используйте DbgDiag из Microsoft

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

    • Запустите приложение "DebugDiag Analysis"
    • Установите флажок "CrashHangAnalysis" на главной странице
    • Перетащите свой свалку в панель "Файлы данных" на главной странице
    • Нажмите "Начать анализ"


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

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

    Примечание. Chrome не будет загружать или открывать файлы .mhtml по соображениям безопасности, поэтому вы должны открывать в Internet Explorer или Microsoft Edge, чтобы он мог использоваться. Это раздражает, и я подал запрос с командой DebugDiag ([email protected]), чтобы изменить формат на обычный HTML

  • Средняя опция: установите WinDbg в качестве альтернативного механизма отладки для Visual Studio

    • Установите Visual Studio, если он еще не установлен. Это необходимо сделать до следующего шага.
    • Установите Набор драйверов для Windows (WDK)
    • Запустите Visual Studio и (эта часть важна!) используйте новую опцию "Файл → Открыть → Сбой дампа...", чтобы открыть дамп. Это приведет к отладке дампа сбоя с помощью отладчика Windows (если вы вместо этого перетащите дамп в Visual Studio или используйте стандартный параметр "Файл → Открыть → Файл..." ), чтобы открыть дамп, он отладит его используя старый механизм отладки Visual Studio... так что будьте осторожны, чтобы использовать правильный вариант).
    • Теперь вы должны иметь возможность видеть правильный стек вызовов и перемещаться по нему с помощью графического интерфейса Visual Studio, хотя некоторые вещи работают по-другому (окна часов требуют использования незнакомого синтаксиса WinDbg, идентификаторы потоков разные и т.д.). Примечание. Пользовательский интерфейс Visual Studio может быть очень вялым, особенно если задействовано много потоков, а окна "потоки" или "параллельные стеки" открыты.
  • вариант Hardcore: используйте WinDbg напрямую

    • Запустить WinDbg.exe
    • Перетащите ваш дамп в окно WinDbg
    • Введите !analyze -v и нажмите Enter. Через некоторое время WinDbg выплюнет стек аварийного вызова, а также его оценку того, что является источником проблемы. Если вы анализируете тупик, вы можете попробовать !analyze -v -hang, и WinDbg часто покажет вам связанную цепочку зависимостей.


    На этом этапе у вас может быть вся информация, которая вам нужна!Однако, если вы хотите проверить состояние процесса в отладчике Visual Studio, вы можете выполнить следующие дополнительные шаги:

    • Открытие дампа сбоя в Visual Studio
    • Щелкните правой кнопкой мыши в окне вызова и выберите "Перейти к разборке"
    • Вставьте шестнадцатеричный адрес из верхней строки выходного вызова WinDbg в строку "Адрес" окна "Разборка" и нажмите "Enter". Теперь вы находитесь в месте аварии, глядя на разобранный код.
    • Щелкните правой кнопкой мыши в окне разборки и выберите "Перейти к исходному коду", чтобы перейти к исходному коду местоположения. Теперь вы смотрите на исходный код на месте сбоя.

Примечание. Все вышеперечисленное требует наличия правильных путей сервера символов, иначе вы не сможете разрешить символы в столах вызовов. Я рекомендую установить переменную среды _ NT_SYMBOL_PATH, чтобы она автоматически была доступна для Visual Studio, WinDbg и DebugDiag.

Ответ 2

Что не хватает в вашем стеке? У вас есть куча адресов, которые не разрешают действительные имена функций (т.е. 0x8732ae00 вместо CFoo: Bar())? Если это так, то вам нужно поместить ваши .PDB, где ваш отладчик может их найти, или настроить сервер символов и установить "Символ Пути" в контекстном меню правой кнопки мыши на панели "Модули" .

Мы сохраняем каждый .PDB из каждого двоичного файла каждый раз, когда кто-то проверяет в новом списке изменений Perforce, так что, когда свалка возвращается от кого-либо из офиса или любого клиента в розницу, у нас есть .PDB, соответствующий версии игра, в которой они бежали. С установленным сервером символов и путями все, что мне нужно сделать, это просто дважды щелкнуть файл .mdmp, и он работает каждый раз.

Или у вас есть стек вызовов, который, как представляется, имеет только одну функцию? Например, 0x8538cf00 без чего-либо еще над ним в стеке? Если это так, то ваша авария на самом деле является поврежденной. Если обратные адреса в backchain были перезаписаны, естественно, отладчик не сможет их разрешить.

Иногда также вы обнаружите, что поток, который на самом деле испускает minidump, не тот, который выбросил исключение, вызвавшее крах. Посмотрите в окне Threads, чтобы увидеть, есть ли в нем один из других потоков.

Если вы отлаживаете сборку "Release", то есть скомпилируете все флаги оптимизации, вам придется жить с тем, что отладчик будет иметь проблемы с поиском локальных переменных и некоторых других данных, Это связано с тем, что включение оптимизаций означает, что компилятор может хранить данные в регистрах, сворачивать вычисления и, как правило, делать множество вещей, которые не позволяют записывать данные в стек. Если это ваша проблема, вам нужно открыть окно разборки и преследовать данные вручную или перестроить двоичный файл отладки и воспроизвести проблему, где вы можете посмотреть на нее.

Ответ 3

Отключите оптимизацию указателя фрейма, если вам нужны дампы стека. Указатели рамки используются для явного определения фреймов стек. Без них отладчик должен определить местоположение каждого кадра.

Ответ 4

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

Получение хороших символов (включая файлы PE) имеет решающее значение для ходьбы в стеке. Более подробную информацию можно найти здесь: https://randomascii.wordpress.com/2013/03/09/symbols-the-microsoft-way/

Я нахожу, что Visual Studio обычно надежна при отображении стеков вызовов. Он автоматически отображает соответствующий стек вызовов из записи об исключениях и упрощает изменение потоков, чтобы вы могли видеть стеки вызовов всех потоков. Иногда он пытается "скрыть" детали, которые, по его мнению, могут вас смутить - хорошо это или плохо, зависит от вашего уровня мастерства.

Windbg по умолчанию показывает стек вызовов кода, который записывал дамп сбоя, а не стек сбоев вызовов. Windbg требует, чтобы вы вышли ".ecxr" или "! Anal -v", чтобы увидеть стек сбоя. Я нахожу это раздражающим. Windbg также требует большей конфигурации, чтобы быть полезным.

Два отладчика имеют разные эвристические методы стекирования. Эти эвристики необходимы, например, если вы вызываете или возвращаете нулевой адрес, так как нет никакой информации для разговора по этому адресу. Для "чистых" сбоев, когда команда с отказом находится в нормальном коде, эти эвристики менее важны.

За последние десять лет стековая ходьба почти наверняка улучшилась. VS 2015 Community Edition очень способна и бесплатна, поэтому вы можете попробовать ее.

Если вы используете windbg, вы можете попробовать несколько экспериментов:

!vc7fpo - toggles some of the windbg heuristics.
!stackdbg d, 7, f - turns on windbg stack walk
k1 - walks one level of the stack, spitting diagnostics as controlled by !stackdbg
dds esp - dumps the raw contents of the stack, doing a symbol lookup on each pointer

Если вы переходите на VS 2015 и все еще имеете проблемы, вполне вероятно, что сбои в ходу стека специфичны для сбоев, которые вы видите. Если переполнение буфера перебрасывает стек перед сбоем, то стек вызовов будет безвозвратно поврежден. В вашем вопросе слишком мало информации о том, какие неудачи вы видите, чтобы дать окончательный диагноз. Я считаю, что отображения стека обоих отладчиков достаточно надежны, но я также обычно понимаю, почему они иногда терпят неудачу, и когда это произойдет, я все еще могу извлечь нужную мне информацию.

Ответ 5

Я не использую minidumps, а вместо этого сбрасываю стек "вручную" в файл журнала (см. www.ddj.com/cpp/185300443 и Как записывать стеки с помощью Windows x64).

Я сталкиваюсь с аналогичным поведением, как и вы: иногда существует допустимый стек вызовов, иногда его нет. В незначительном числе случаев стек может быть действительно поврежден. Возможно, в 1/3 всех случаев установленный обработчик Exception вообще не вызывается! Я предполагаю, что это как-то проблема обработки структурированных исключений Windows.