Честно говоря, до определенного времени как то не задавался вопросом о причинах падения приложений, какова же настоящая природа этого явления? Всегда приходилось решать подобные инциденты с глючащим программным обеспечением на уровне дилетанта: изучать записи в журнале событий, силясь найти описания идентификаторов ошибок в сети, пытаться просто "в тупую" переустановить сбойное программное обеспечение, различные сопутствующие компоненты. Время от времени случались настолько непонятные инциденты, что в итоге все заканчивалось переустановкой системы "с нуля". В какой то момент времени мне это всё порядком поднадоело, и результатом изучения вопроса явились сначала короткие заметки, которые через определенное время были доработаны и доведены до уровня статьи.
В данном посте мы будем рассматривать анализ ошибок приложения, то есть диагностику внештатных ситуаций, при которых код пользовательского режима ведет себя неординарно, что приводит к тому, что приложения аварийно завершаются ("падают") либо перестают отвечать на запросы операционной системы ("зависают"). Стоит отметить, что в отличии от системного фатального сбоя в модуле ядра (синий экран смерти, BSOD), падение некритического для системы пользовательского процесса не должно сказываться на стабильности работы системы в целом. На пользовательском уровне всё устроено несколько иначе, во время выполнения кода программы может возникнуть ситуация, когда состояние данных, устройств ввода-вывода, или системы в целом делает последующие вычисления в соответствии с базовым алгоритмом бессмысленными или вовсе невозможными.
Примерами таких ситуаций могут быть:
- Доступ к области памяти, помеченной как "недоступная". В данном случае программа не получает необходимые данные и дальнейшие вычисления не имеют смысла.
- Исчерпание памяти. Если в какой-то определенный момент времени система не сможет выделить программе область памяти необходимого размера, то программа не сможет нормально функционировать.
- Целочисленное деление на ноль. Результата у подобной операции быть не может, поэтому дальнейшие вычисления смысла не имеют.
- Ошибка получения данных с внешнего устройства. Если данные не получены, то дальнейшие действия над ним так же бессмысленны.
Подобные ситуации генерируют системные события, которые носят название "исключение".
Почему исключение имеет такое витиеватое и довольно запутанное определение? Потому как само определение исключения довольно непростое: исключение может быть как реакцией на ошибку, так и необходимостью выполнить определенные действия перед тем как продолжить дальнейшее исполнение [прерванного] кода.
Исключения могут быть двух видов:
- Уровня операционной системы: к подобным исключениям относятся исключения, возникающие в коде, который использует структурную обработку исключений (Structured Exception Handling, SEH), то есть встроенный в операционную систему Windows механизм обработки программных и аппаратных исключений. Структурная обработка исключений - механизм, который позволяет приложениям самим получать управление в случае возникновения исключительной ситуации (примеры описаны выше) и обрабатывать их собственными силами, не привлекая операционную систему.
- Уровня языка программирования/фреймворка: к подобным исключениям относятся исключения, возникающие в программах, написанных на каких-либо языках программирования (напр.: C++ либо .NET). Подобные программы используют собственные механизмы обработки исключений на уровне приложения, однако все они все-равно базируются на системной структурной обработке исключений (SEH).
Исключения уровня операционной системы, в свою очередь, по источнику проблемы, могут быть двух типов:
- Аппаратное - специальный тип прерывания процессора, генерируемого в ответ на определенное событие. Относятся: Invalid memory access, Integer devide by zero и прч.
- Программное - явный вызов WinAPI-функции RaiseException кодом приложения или модуля ядра ОС. Относятся: любые виды исключительных состояний, описанные разработчиком ПО.
Обработкой исключений в системе занимается специализированный код ядра системы (размещенный в ntdll.dll), называемый иначе системным обработчиком исключений или кодом диспетчеризации исключений. Он предоставляет системные механизмы обработки исключений, так называемые "внутренние обработчики исключений". Если программа сама не предоставляет обработчика для какого-либо исключения, то исключение попадает на системный обработчик исключений и, в зависимости от настроек, возможны следующие действия: запуск отладчика для изучения, принудительное закрытие виновного процесса с целью предотвращения дальнейших проблем, создание дампа памяти приложения, создание отчета о сбое и прч. В данной заметке мы будем проводить анализ ошибок приложения пользовательского режима с помощью специализированных средств adplus и cdb.
С точки зрения пользователя ошибка приложения выглядит как информационное окно с сообщением о том, что прекращена работа программы "...". Вид окна в операционной системе Windows 7 приобрел такой вот незамысловатый вид:
Помимо того, что сообщение об ошибке приложения выводится на экран с целью информирования пользователя о том, что что-то пошло не так, детали ошибки приложения фиксируются в специальном системном журнале - журнале событий системы. Сюда попадают записи, которые содержат минимальную информацию относительно сбоя, понятно что информации, представленной в них, зачастую просто недостаточно. Поэтому, во-первых очень сложно сделать выводы только лишь на основании нескольких строк, описывающих сбой в журнале событий, во-вторых, для сторонних библиотек DLL сложно предоставить детальное описание события. Беря во внимание всё вышеперечисленное, в большинстве случаев для точной диагностики потребуются иные, специализированные средства анализа ошибок приложения.
Одним из подобных средств анализа ошибок приложения является отладчик. Если во время возникновения ошибки отладчик подключен (приаттачен, прилинкован) к процессу, в котором возникла проблема, то детали сбоя могут быть собраны (зафиксированы). Собираемая отладчиком информация [о сбое] являются более подробной, нежели информация из журнала событий, то есть предоставляет значительно больше данных для анализа/изучения. Большинство пользователей представляют себе отладчик в виде полноценного графического интерфейса с огромным количеством информации о регистрах, коде, процессах, процедура, стеке и прочем, однако бывают и достаточно простые отладчики, которые работают в текстовом режиме и ориентированы на определенные специфические задачи, такие как сбор информации, логгирование событий, расстановка точек останова, запись дампа памяти.
Подобный отладчик может сформировать понятный пользователю лог-файл, который описывает поведение процесса во времени. Дополнительно, он может сформировать дамп памяти приложения для дальнейшего изучения последнего.
После сбора информации о сбое, можно её проанализировать с помощью техник, аналогичных используемым при анализе BSOD, потому как у нас на руках будет полноценный дамп приложения. Аварийный дамп системы или дамп упавшего/зависшего приложения - для отладчика разницы никакой нет. А вот мы сможет уже знакомым нам способом провести анализ ошибки приложения и выяснить причину сбоя.
Для анализа ошибок приложений Microsoft предоставляет несколько утилит в составе комплекта Debugging Tools for Windows, это:
- Adplus - утилита, автоматизирующая действия отладчика Microsoft CDB с целью установки точек останова, создания дампов памяти и лог-файлов одного или множества процессов.
- CDB - упрощенный консольный отладчик пользовательского режима (user-mode).
Microsoft рекомендует использовать ADPlus для анализа следующих видов процессов:
- Процессы, которые перестали отвечать на запросы, "виснут".
- Процессы, которые показывают 100% загрузку процессора на одноядерном процессоре, 50% ЦПУ на двухядерном процессоре, 25% ЦПУ на четырехядерном процессоре, и так далее.
- Процессы, которые неожиданно "падают" или "закрываются".
Microsoft не рекомендует использовать ADPlus в следующих случаях:
- Процессы, которые не запускаются, то есть закрываются прямо на этапе запуска.
- DLL или программы, которые порождают большое количество EH-исключений Microsoft Visual C++.
Настройка среды отладки
- Установка Debugging Tools for Windows. Как мы уже упоминали, ADPlus содержится в составе комплекта Debugging Tools for Windows. Для установки самой свежей и актуальной для моей системы версии Debugging Tools for Windows, я использую полный комплект Windows SDK (Software Developers Kit). Подробнее о процессе установки можно почитать Установка Debugging Tools for Windows.
- Создание рабочей директории ADplus. Именно по этому пути у нас будут складываться логи, скрипты и дампы. Создадим рабочую директорию для утилиты adplus.exe. Для этих целей я лично предпочитаю использовать каталог хранения временных файлов, заданный системной переменной
%TEMP%
. На моей системе он почти всегда имеет имяC:\TEMP
. Исходя из этого создадим директориюc:\temp\adplus
. Каждый раз при запуске ADPlus, отладочная информация будет складываться в новый уникальный подкаталог и каждый файл, создаваемый в этом подкаталоге будет иметь уникальное имя.
Отладка сбойного приложения
1. Определение имени образа или идентификатора сбойного процесса. В начале, чтобы правильно указать за каким именно процессом будет следить adplus, нам необходимо определить либо имя образа проблемного процесса либо PID. Для этих целей, на вскидку, приходит на ум два способа. Можно использовать Диспетчер задач, предварительно в меню "Вид" - "Выбрать столбцы" - включить чекбокс "ИД процесса (PID)":
либо использовать консольную команду tasklist без опций:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
Microsoft Windows [Version 6.1.7601] (c) Корпорация Майкрософт (Microsoft Corp.), 2009. Все права защищены. C:\Users\admin>tasklist Имя образа PID Имя сессии № сеанса Память ========================= ======== ================ =========== ============ System Idle Process 0 Services 0 24 КБ System 4 Services 0 304 КБ smss.exe 316 Services 0 1 196 КБ csrss.exe 436 Services 0 4 808 КБ wininit.exe 492 Services 0 4 668 КБ services.exe 548 Services 0 11 356 КБ lsass.exe 572 Services 0 13 132 КБ lsm.exe 580 Services 0 5 048 КБ svchost.exe 720 Services 0 10 104 КБ svchost.exe 800 Services 0 10 916 КБ svchost.exe 904 Services 0 20 008 КБ svchost.exe 940 Services 0 17 904 КБ svchost.exe 968 Services 0 37 356 КБ UMVPFSrv.exe 1008 Services 0 4 964 КБ svchost.exe 540 Services 0 7 256 КБ svchost.exe 576 Services 0 18 232 КБ svchost.exe 1056 Services 0 16 600 КБ spoolsv.exe 1324 Services 0 13 368 КБ svchost.exe 1356 Services 0 14 228 КБ armsvc.exe 1484 Services 0 4 072 КБ pbeagent.exe 1504 Services 0 57 628 КБ svchost.exe 1528 Services 0 11 992 КБ HeciServer.exe 1560 Services 0 5 808 КБ Jhi_service.exe 1600 Services 0 4 476 КБ svchost.exe 1720 Services 0 15 032 КБ ss_conn_service.exe 1744 Services 0 4 620 КБ svchost.exe 1788 Services 0 6 248 КБ TeamViewer_Service.exe 1824 Services 0 13 796 КБ ViakaraokeSrv.exe 1880 Services 0 4 696 КБ vmnat.exe 1908 Services 0 4 836 КБ vmware-authd.exe 1972 Services 0 15 372 КБ vmnetdhcp.exe 1188 Services 0 4 192 КБ vmware-usbarbitrator64.ex 1440 Services 0 7 956 КБ svchost.exe 2624 Services 0 5 656 КБ WmiApSrv.exe 2988 Services 0 6 524 КБ IAStorDataMgrSvc.exe 3660 Services 0 20 720 КБ LMS.exe 4032 Services 0 5 520 КБ UNS.exe 3156 Services 0 12 052 КБ csrss.exe 3964 Console 2 42 868 КБ winlogon.exe 3120 Console 2 7 520 КБ taskhost.exe 2604 Console 2 10 288 КБ dwm.exe 3164 Console 2 42 156 КБ explorer.exe 4356 Console 2 80 696 КБ igfxtray.exe 2840 Console 2 7 208 КБ hkcmd.exe 4236 Console 2 7 284 КБ igfxpers.exe 4208 Console 2 8 024 КБ MSOSYNC.EXE 3504 Console 2 14 364 КБ MusicManager.exe 3268 Console 2 18 740 КБ YandexDisk.exe 652 Console 2 83 048 КБ iusb3mon.exe 3092 Console 2 5 644 КБ KiesTrayAgent.exe 3448 Console 2 11 256 КБ YandexDiskStarter.exe 1932 Console 2 4 024 КБ YandexDiskStarter.exe 3548 Console 2 4 240 КБ wuauclt.exe 1300 Console 2 7 012 КБ wmpnetwk.exe 1988 Services 0 11 092 КБ chrome.exe 4980 Console 2 182 048 КБ chrome.exe 2692 Console 2 86 528 КБ chrome.exe 916 Console 2 26 216 КБ chrome.exe 3704 Console 2 101 208 КБ chrome.exe 2304 Console 2 45 112 КБ chrome.exe 4628 Console 2 48 692 КБ chrome.exe 2904 Console 2 41 568 КБ chrome.exe 2944 Console 2 34 620 КБ chrome.exe 5128 Console 2 58 868 КБ chrome.exe 5272 Console 2 46 176 КБ chrome.exe 5384 Console 2 47 400 КБ chrome.exe 5464 Console 2 50 012 КБ chrome.exe 5528 Console 2 50 460 КБ chrome.exe 5652 Console 2 75 760 КБ chrome.exe 5708 Console 2 80 528 КБ chrome.exe 5744 Console 2 67 280 КБ chrome.exe 5824 Console 2 72 544 КБ chrome.exe 5920 Console 2 54 972 КБ chrome.exe 6012 Console 2 64 400 КБ chrome.exe 6020 Console 2 50 840 КБ chrome.exe 5584 Console 2 51 316 КБ chrome.exe 1964 Console 2 31 520 КБ chrome.exe 1376 Console 2 72 892 КБ chrome.exe 2648 Console 2 62 488 КБ chrome.exe 6224 Console 2 62 016 КБ chrome.exe 6400 Console 2 110 724 КБ IAStorIcon.exe 6628 Console 2 22 532 КБ chrome.exe 6548 Console 2 142 744 КБ chrome.exe 3996 Console 2 82 440 КБ Snagit32.exe 4156 Console 2 152 520 КБ TscHelp.exe 680 Console 2 4 488 КБ SnagPriv.exe 2964 Console 2 6 220 КБ wisptis.exe 6972 Console 2 7 656 КБ SnagitEditor.exe 4516 Console 2 105 892 КБ EXCEL.EXE 5100 Console 2 32 448 КБ OSPPSVC.EXE 3520 Services 0 11 160 КБ OSE.EXE 3416 Services 0 8 116 КБ cmd.exe 4656 Console 2 3 044 КБ conhost.exe 6388 Console 2 5 932 КБ tasklist.exe 1184 Console 2 5 964 КБ WmiPrvSE.exe 2284 Services 0 6 556 КБ |
и в выведенном длинном списке, в колонке "Имя образа" найти имя, либо в колонке "PID" найти идентификатор того процесса, который вы хотите отладить. В нашем случае завис Excel, поэтому имя образа будет excel.exe, а идентификатор будет равен значению 5100.
2. Линковка (присоединение) отладчика к сбойному приложению.
Запустите интерпретатор командной строку (cmd) и войдите в директорию установки Windows Debugging Tools (по-умолчанию это C:\Program Files\Debugging Tools for Windows (x64)):
1 2 3 4 5 6 |
Microsoft Windows [Version 6.1.7601] (c) Корпорация Майкрософт (Microsoft Corp.), 2009. Все права защищены. C:\Users\admin>cd c:\program files\debugging tools for windows (x64) c:\Program Files\Debugging Tools for Windows (x64)> |
Теперь сделаем небольшое отступление с целью понять режимы работы утилиты ADPlus:
- Режим "Завис" (Hang). Используется для диагностики зависших процессов, процессов, создающих 100% нагрузку на процессор и других проблем, которые не приводят к падению. Когда Вы используете утилиту ADPlus в режиме "hang", то должны дождаться пока процесс или группа процессов перестанут отвечать. Вот после этого Вы и должны запустить утилиту. По сути, в режиме "hang" утилита ADPlus всего-лишь создает полный дамп памяти приложения. Поэтому, в данном режиме ADPlus удобно использовать для простой операции создания дампа памяти нормально функционирующего приложения, с целью последующего изучения. На время пока память процесса скидывается в файл, процесс останавливается. После сброса дампа памяти на диск, процесс возобновляется методом неразрушающего (ненавязчивого, non-invasive) присоединения/отсоединения отладчика.
- Режим "Упал" (Crash). Используется для диагностики исключений, которые приводят к ошибкам, по которым запускается Dr. Watson, или любым другим типам ошибок, которые приводят к немедленному закрытию программы или сервиса. Когда Вы используете утилиту ADPlus в режиме "crash", то должны запустить ADPlus до момента падения. Когда утилита ADPlus запускается в этом режиме, то отладчик cdb присоединяется к каждому приложению, описанному в командной строке запуска ADPlus, и висит на нем до момента падения исследуемого приложения, либо до вмешательства пользователя. В данном режиме обрабатываются следующие типы исключений: Invalid Handle, Illegal Instruction, Integer Divide by Zero, Floating Point Divide by Zero, Integer Overflow, Invalid Lock Sequence, Access Violation, Stack Overflow, C++ EH Exception, Unknown Exception. Режим "crash" использует метод разрушающего (навязчивого, invasive) присоединения отладчика к процессу, поэтому имеются некоторые ограничения, например процесс завершается когда отладчик отсоединяется от него.
И так, вернемся к процессу отладки. Мы переместились в рабочую директорию средств отладки. Напомню, что в нашем случае мы имеет дело в "падающим" приложением, приложение Excel аварийно завершается. Поэтому, мы будем использовать режим "crash" утилиты adplus. Для того, чтобы начать отладку падающего процесса, мы привяжемся к идентификатору сбойного приложения, выполнив команду:
adplus.exe -crash -p 5100 -o c:\temp\adplus -NoDumpOnFirst
Если же Вы знаете имя образа сбойного процесса, то команда у нас слегка изменится:
adplus.exe -crash -pn excel.exe -o c:\temp\adplus -NoDumpOnFirst
для того, чтобы опции командной строки были более понятными, приведем краткий синтаксис:
Параметр | Описание |
---|---|
-crash -hang |
Режим работы отладчика |
-p <ID процесса> | Задает идентификатор процесса, к которому будет прилинкован отладчик. |
-pn <имя образа> | Задает имя образа процесса, к которому будет прилинкован отладчик. |
-sc <запускаемое приложение> | Задает имя запускаемого внешнего приложения и его параметров. |
-y <путь к символам> | Задает путь к каталогу локальных отладочных символов. |
-mss <каталог локального кеша символов> | Указывает каталог для локального кеша символов, получаемых с сервера символов Microsoft. Сюда скачиваются необходимые файлы символов. Обычно C:\Symbols . |
-o <целевой каталог> | Рабочая директория отладчика. В неё он складывает логи и дампы. |
-c <файл конфигурации> | Задает файл конфигурации ADPlus. Начиная с версии 6.0+ ADPlus может использовать расширенную конфигурацию во внешнем файле. |
-dbg <отладчик> | Задает отладчик, который будет использован: cdb, windbg, ntsd. По-умолчанию стоит cdb. |
-quiet | Подавляет весь графический вывод ADPlus. Говорит о том, что не стоит использовать диалоговые окна. Полезен при удаленном запуске утилиты. |
-notify <имя компьютера|имя пользователя> | Если запущен в режиме -crash, извещает пользователя или станцию посредством сервиса Windows Messenger о падении приложения. |
-NoDumpOnFirst | Предписывает отладчику не создавать дамп при возникновении исключения первого шанса. |
Если всё прошло нормально, в виде иконки в трее, в режиме свернутого окна запускается отладчик cdb. В трее иконка cdb выглядит так:
В большинстве случаев нет необходимости взаимодействовать с рабочим окном cdb, поэтому рекомендую просто оставить его минимизированным. В случае же, если Вам потребуется, по каким-либо причинам, отключить отладчик от исследуемого процесса, просто разверните окно cdb и нажмите комбинацию клавиш CTRL+C.
Вот так выглядит рабочее окно cdb при попытке его развернуть:
Немного об алгоритме работы консольного отладчика CDB и отладчиков в целом. Когда отладчик прилинкован к приложению, то он видит все виды возникающих исключений ДО логики самой программы.
Отладчик уведомляется о каждом исключении дважды (перед обработчиком приложения и после обработчика приложения):
- Первый шанс [обработать исключение] (first chance exception), не фатальное. В случае возникновения исключения, прилинкованный к приложению отладчик уведомляется до уведомления приложения (или до возможности приложения обработать исключение), отсюда и название! Исключения первого шанса называют не фатальным потому, что при первом уведомлении об исключении есть шанс, что оно впоследствии будет обработано самим приложением, то есть не станет причиной падения (закрытия) приложения. Отладчик может обрабатывать исключение первого шанса, однако в большинстве случаев отладчик сконфигурирован таким образом, чтобы не реагировать на исключение первого шанса и продолжить выполнение кода программы, в этом случае программа увидит исключение в штатном режиме.
- Второй шанс [обработать исключение] (second chance exception), фатальное. После того, как отладчик передает исключение обработчику приложения, то приложение имеет два варианта - обработать исключение, либо не обрабатывать его. Если программа сама обрабатывает исключение собственным обработчиком исключений (exception handler), то исключение не вызывает "падения" приложения и не становится исключением второго шанса. Если же программа самостоятельно не обрабатывает исключение, то есть не имеет сконфигурированного обработчика [данного типа] исключения, то отладчик получает второй шанс на обработку этого же исключения. Интерактивный отладчик в этот момент всплывает окном интерфейса, в нашем же случае с консольным отладчиком CDB ничего подобного не происходит, а просто создается запись в лог-файле и дамп приложения. Фатальным исключение второго шанса называют потому, что в случае, когда оно не обрабатывается приложением, системный обработчик (читать: система) просто закрывает приложение, то есть считается, что приложение "упало".
В обычном режиме, то есть в ситуации когда отладчик отсутствует вовсе, приложение "падает", а пользователь видит на экране ошибку приложения с заветной надписью вида "прекращена работа приложения..".
ADPlus детектирует исключения первого шанса (не фатальные) для всех типов исключений, за исключением неизвестных типов и SEH исключений? ADPlus детектирует исключение второго шанса (фатальные) для всех типов исключений, включая SEH и неизвестные исключения.
Окончание мониторинга и запись результатов
В различных режимах ADPlus/CDB действуют по-разному, то есть заканчивают мониторинг на разных стадиях:
- Режим "Crash". В этом режиме отладчик cdb висит запущенным до момента падения наблюдаемого приложения и выходит сразу после закрытия (падения) приложения. Создаются логи и дамп.
- Режим "Hang". В этом режиме отладчик cdb создает логи и дамп сразу после запуска и завершает работу.
В процессе работы отладчика cdb в заданной рабочей директории (в нашем случае это c:\temp\adplus) создается новый подкаталог, который имеет уникальное имя. В этот подкаталог помещается серия носящих уникальные имена текстовых и лог-файлов.
Файл | Назначение |
---|---|
Adplus_log_****_YYYY-MM-DD_HH-MM-SS-***.log | Весь вывод, который сгенерировал отладчик cdb. |
ADPlust_report.txt | Параметры запуска Adplus. Если Вы захотите посмотреть, с какими параметрами запускался сеанс Adplus, сколлекционировавший логи и дампы, то вам как раз сюда. |
DebuggerScript.txt | Скрипт, сгенерированный утилитой Adplus и запущенный в отладчике cdb в начале процесса отладки. |
FULLDUMP_****Mode_***.***__****_YYYY-MM-DD-HH-MM-SS-***_****.dmp | Дамп памяти приложения. |
На этом этап сбора информации у нас завершается, и мы переходим непосредственно к анализу ошибок приложения.
Анализ результатов
К моменту завершения работы adplus/cdb, у нас на руках оказываются лог-файлы отчетов и дамп(ы) памяти приложения. Анализ результатов работы слегка разнится для файлов, полученных в разных режимах работы adplus: crash и hang. По большому счету, нам было бы вполне достаточно одного лишь дампа для того, чтобы начать процесс анализа памяти приложения в момент падения/зависания, но для чего же нам тогда было использовать специальные средства, ведь для простого создания дампа мы могли бы использовать хорошо известные традиционные средства?. Правильно, в ситуации с adplus/cdb разработчики пошли чуть дальше, и в режиме "crash" предоставляют в лог-файле достаточно подробную хронологию возникающих в процессе работы приложения проблем.
Анализ результатов режима Hang
У нас на руках имеется дамп памяти приложения, при этом, в лог-файлы adplus/cdb никакой специфической информации о "подвисании" приложения не попадает, поскольку отладчик и не может ничего нам сообщить, ведь зависший процесс не производит никакой активности и не генерирует никаких исключений, он просто "висит". Но нам то и дампа памяти подвисшего процесса вполне достаточно. Теперь мы можем перейти к его анализу при помощи отладчика WinDbg.
Анализ результатов режима Crash
Здесь все значительно интереснее. Дело в том, что cdb в момент возникновения исключений первого и второго шансов записывает некоторую отладочную информацию в файл Adplus_log_****_YYYY-MM-DD_HH-MM-SS-***.log. А именно, мы имеем возможность наблюдать стек выполнения момента возникновения исключения для исключений первого и второго шанса. Вот наглядный пример стека:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
Call stack below --- # Child-SP RetAddr : Args to Child : Call Site 00 00000000`002b82c8 000007fe`e10fbbfa : 00000000`00000000 000007fe`e10af324 00000000`123e0518 00000000`00000000 : wwlib!FMain+0x23e36f 01 00000000`002b82d0 000007fe`e177d4ea : 00000000`00000000 00000000`00000000 00000000`00000001 00000000`00000000 : wwlib!FMain+0x89bd2 02 00000000`002b8340 000007fe`e177dba7 : 00000000`13728400 00000000`00000000 00000000`00000001 00000000`00000004 : wwlib!DllGetClassObject+0x45c58a 03 00000000`002b8400 000007fe`e113f3c5 : 00000000`00000000 00000000`00000001 00000000`002b86f0 00000000`00000000 : wwlib!DllGetClassObject+0x45cc47 04 00000000`002b84a0 000007fe`e113e5a2 : 00000000`002b86f0 00000000`00000000 00000000`002b86f0 00000000`002b86f0 : wwlib!FMain+0xcd39d 05 00000000`002b85b0 000007fe`e13232ac : 00000000`00000001 00000000`0000000a 00000000`00000001 00000000`00000000 : wwlib!FMain+0xcc57a 06 00000000`002bd3f0 000007fe`e1cdbdfa : 00000000`00000000 00000000`13728400 00000000`00000001 00000000`00000001 : wwlib!DllGetClassObject+0x234c 07 00000000`002bd750 000007fe`e1322422 : 00000000`13728400 00000000`056e0748 00000000`00000000 00000000`00352402 : wwlib!GetAllocCounters+0x19e5b2 08 00000000`002bd7d0 00000001`3fe0318b : 00000000`00000001 00000000`0548e050 00000000`00000000 00000000`00352002 : wwlib!DllGetClassObject+0x14c2 09 00000000`002bd920 00000001`3fe01e73 : 00000000`0cffffff 00000000`12776870 00000000`00000000 00000000`0cffffff : OUTLOOK!FOutlookIsDeepSyncing+0x29197 0a 00000000`002bde20 00000001`3fdee2b8 : 00000000`03454800 00000000`0548e020 00000000`03454800 00000000`00000018 : OUTLOOK!FOutlookIsDeepSyncing+0x27e7f 0b 00000000`002bde50 00000001`3fded9e3 : 00000000`00000000 00000000`00000000 00000000`034548b0 00000001`3fcf59dc : OUTLOOK!FOutlookIsDeepSyncing+0x142c4 0c 00000000`002be520 00000001`400b1198 : 00000000`034548b0 00000000`0cffffff 00000000`0885fc00 00000000`00000000 : OUTLOOK!FOutlookIsDeepSyncing+0x139ef 0d 00000000`002be5d0 00000001`400ab91d : 00000000`00000000 00000000`00000000 00000000`0af59000 00000000`00000000 : OUTLOOK!FAllowStoreToSend+0x3596c 0e 00000000`002be600 00000001`400ab78b : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`002be6d0 : OUTLOOK!FAllowStoreToSend+0x300f1 0f 00000000`002be650 00000001`400ab74e : 00000000`00000000 00000001`405b7b0f 00000000`00000000 00000000`00000001 : OUTLOOK!FAllowStoreToSend+0x2ff5f 10 00000000`002be680 00000001`400ab4b8 : 00000000`0d9c73e8 00000000`00000001 00000000`0d9c73e8 00000000`00000001 : OUTLOOK!FAllowStoreToSend+0x2ff22 11 00000000`002be6b0 00000001`400ab3c9 : 00000000`0d9c73e8 00000000`00000000 00000000`00000000 00000000`00000000 : OUTLOOK!FAllowStoreToSend+0x2fc8c 12 00000000`002be730 00000001`400ab03a : 00000000`0af59000 00000000`002be7e0 00000000`00000000 00000000`00000001 : OUTLOOK!FAllowStoreToSend+0x2fb9d 13 00000000`002be7b0 00000001`400aaf4d : 00000000`ffffffff 00000000`00000000 00000000`00000000 00000001`402f4f60 : OUTLOOK!FAllowStoreToSend+0x2f80e 14 00000000`002be7e0 00000001`400a161b : 00000000`0d9c7340 00000000`0d9c7340 00000000`0548e000 00000000`007f0000 : OUTLOOK!FAllowStoreToSend+0x2f721 15 00000000`002be830 00000001`400a0d69 : 00000000`12779038 00000000`00000000 00000000`0d9c7340 00000000`08855460 : OUTLOOK!FAllowStoreToSend+0x25def 16 00000000`002be8b0 00000001`40182d52 : 00000000`00010003 00000000`0548e000 00000000`00000000 00000000`002bea60 : OUTLOOK!FAllowStoreToSend+0x2553d 17 00000000`002be970 00000001`3fe21688 : 00000000`00000000 00000000`00000001 00000000`00000000 000007fe`00000000 : OUTLOOK!HrMsgDownloadedNotification+0x7e0e 18 00000000`002be9b0 00000001`3fe2084a : 00000000`0548e000 00000001`40196607 00000000`12779038 00000001`3fce701d : OUTLOOK!FOutlookIsDeepSyncing+0x47694 19 00000000`002beab0 00000001`40172024 : 00000000`0548e008 00000000`001202d8 00000000`00000000 ffffffff`fffffffe : OUTLOOK!FOutlookIsDeepSyncing+0x46856 1a 00000000`002beaf0 00000001`4062d0e2 : 00000000`0d534788 00000000`00000000 00000000`0548e5e0 00000000`00000000 : OUTLOOK!HrGetOABURL+0x5584 1b 00000000`002beb70 00000001`40a2cdcc : 00000000`20000108 00000000`0d5341e8 00000000`00000001 00000000`00000000 : OUTLOOK!ReleaseResObjStreams+0x3b3ee 1c 00000000`002bed40 00000001`40a47ef4 : 00000000`00000000 00000000`0d5341e0 00000000`001a020c 00000000`00000000 : OUTLOOK!HrImportRules+0x15d46c 1d 00000000`002bee50 00000001`4096e191 : 00000000`037a3800 00000000`002bf070 00000000`002bf070 00000000`00000000 : OUTLOOK!HrImportRules+0x178594 1e 00000000`002bef50 00000001`3fea13fa : 00000000`037a3800 00000000`00000001 00000000`002bf070 00000860`00000000 : OUTLOOK!HrImportRules+0x9e831 1f 00000000`002bef90 00000001`40964ef7 : 00000000`037a3800 00000000`037a3800 00000007`00000049 00000042`00000086 : OUTLOOK!FOutlookIsDeepSyncing+0xc7406 20 00000000`002beff0 00000001`403e2460 : 00000000`037a3800 00000000`037a3800 00000000`037a3800 00000000`002bf064 : OUTLOOK!HrImportRules+0x95597 21 00000000`002bf030 00000001`3fcf6332 : 00000001`403e220c 00000000`00000042 00000042`00000086 00000000`002bf450 : OUTLOOK!HrShowRenFFDialog2+0xe864 22 00000000`002bf0a0 00000001`3fd84f71 : 00000000`037a3800 00000000`00000203 00000000`00000001 00000000`00000001 : OUTLOOK!StdCoCreateInstance+0x3b56 23 00000000`002bf150 00000001`3fcf5b10 : 00000000`00000000 00000000`00420086 00000000`00000001 00000000`00000203 : OUTLOOK!GetOutlookSafeModeState+0x5f439 24 00000000`002bf190 00000001`40b0e847 : 00000001`412153f0 00000000`001a020c 00000000`00000000 00000000`77016840 : OUTLOOK!StdCoCreateInstance+0x3334 25 00000000`002bf240 00000000`77019bd1 : 00000001`3fcf59dc 00000000`00000001 00000000`00000001 00000000`00000000 : OUTLOOK!PushSavedKeyToCicero+0x29fcf 26 00000000`002bf280 00000000`77013bfc : 00000000`001a020c 00000001`3fcf59dc 00000000`00000203 00000000`00000001 : USER32!TranslateMessageEx+0x2a1 27 00000000`002bf340 00000000`77013b78 : 00000000`002bf5b0 00000000`00420086 00000000`00000203 00000000`00000000 : USER32!CallWindowProcW+0x9c 28 00000000`002bf390 000007fe`fc7e6205 : 00000000`00000001 00000000`77016bad 00000000`0004042a 00000000`00000407 : USER32!CallWindowProcW+0x18 29 00000000`002bf3d0 000007fe`fc7e6990 : 00000000`00000001 00000000`7701791a 00000000`001a020c 00000000`77019aa6 : Comctl32!CreateUpDownControl+0x254d 2a 00000000`002bf410 000007fe`fc7e6758 : 00000000`00000000 00000000`001a020c 00000000`00000000 00000001`3fcf749d : Comctl32!DefSubclassProc+0x2b4 2b 00000000`002bf490 000007fe`fc7e6990 : 00000000`002bf5b0 00000000`00000002 00000000`00000203 00000000`77019aa6 : Comctl32!DefSubclassProc+0x7c 2c 00000000`002bf4e0 000007fe`fc7e6867 : 00000000`00000000 00000000`001a020c 00000000`001202d8 00000000`77019aa6 : Comctl32!DefSubclassProc+0x2b4 2d 00000000`002bf560 00000000`77019bd1 : ffffffff`fffffffe 00000000`002bf7a0 ffffffff`fffffffe 00000000`00000000 : Comctl32!DefSubclassProc+0x18b 2e 00000000`002bf600 00000000`770198da : 00000000`002bf7a0 000007fe`fc7e6780 00000000`00000000 00000000`00ca3660 : USER32!TranslateMessageEx+0x2a1 2f 00000000`002bf6c0 000007fe`f0920f02 : ffffffff`fffffffe 00000000`002bf7a0 000007fe`fc7e6780 00000000`00000001 : USER32!TranslateMessage+0x1ea 30 00000000`002bf740 00000001`3fdd6140 : 00000000`00000000 00000000`00000000 00000000`00000002 00000000`00000001 : mso!Ordinal4166+0x2e 31 00000000`002bf770 00000001`3fdd5e34 : 00000001`411f9b60 00000001`411f9b60 00000001`00000000 00000000`00000001 : OUTLOOK!FFolderSupportsUnicode+0x11eac 32 00000000`002bf810 00000001`3fce4112 : 00000000`00000001 00000001`3fce0000 00000000`00000000 00000000`00886630 : OUTLOOK!FFolderSupportsUnicode+0x11ba0 33 00000000`002bf840 00000001`40b19ea7 : 00000000`00000000 00000000`00000000 00000000`00000000 00000001`40e57000 : OUTLOOK+0x4112 34 00000000`002bf880 00000000`775f59dd : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : OUTLOOK!PushSavedKeyToCicero+0x3562f 35 00000000`002bf930 00000000`7772a631 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0xd 36 00000000`002bf960 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21 Creating c:\temp\adplus\20151113_141236_Crash_Mode\MINIDUMP_FirstChance_av_AccessViolation_OUTLOOK.EXE__176c_2015-11-13_14-12-54-612_1304.dmp - mini user dump Dump successfully written (1304.1404): Access violation - code c0000005 (!!! second chance !!!) SecondChance_av_AccessViolation |
Сделать выводы можно на основе визуального осмотра стека на предмет используемых процедур и функций. Конечно, это требуется некоторых знаний, и если Вы затрудняетесь с визуальным разбором стека исполнения, то Вы можете проанализировать полученных дамп при помощи WinDbg. Соответственно, при подключенных отладочных символах мы имеем возможность сделать выводу по характеру сбоя уже до непосредственного анализа дампа в таких средствах, как WinDbg. Это то и является достаточно большим плюсом в сценарии анализа ошибок приложения при помощи adplus и cdb.