Публикация продолжает цикл статей по обзору инструментария, предназначенного для исследования аварийных дампов памяти системы и приложений, и в данной статье, в качестве инструмента изучения мы будем рассматривать отладчик широкого применения под названием WinDbg. Для начала, не лишним будет обмолвиться о том, что отладчик WinDbg является, пожалуй, самым функциональным многоцелевым отладчиком для операционных систем Microsoft Windows. В значительной степени это заслуга того, что WinDbg самый "древний" отладчик и разрабатывается уже достаточно давно, ориентировочно со времен появления первых версий системы Windows NT. WinDbg по праву занимает достойное место в арсенале специалистов по исследованию кода, поскольку ни один другой отладчик, за всю историю существования операционных систем Windows, не может похвастаться столь продолжительным жизненным циклом. Конечно же, во многом это обусловлено и тем фактом, что разрабатывает WinDbg сама корпорация Microsoft, то есть WinDbg является "родным", нативным отладчиком для Windows. WinDbg (Windows DeBuGger) - мощный многофункциональный отладчик, который позволяет отлаживать приложения и драйвера пользовательского режима (user mode) а так же непосредственно модули/драйвера режима ядра (kernel mode).
Отладчик - программа, разработанная для помощи в обнаружении ошибок в программном обеспечении.
WinDbg объединяет в себе широкий спектр функционала, огромное количество внутренних и внешних команд, макросов и расширений, количество которых достаточно велико, что позволяет существенно расширить функционал отладчика. К основным функциям отладчика относятся пошаговое выполнение исследуемого кода, установка точек останова, просмотр переменных, трассировка стека вызова, просмотр областей памяти, исследование аварийных дампов системы и многое другое. Отладчик позволяет отлаживать как современный 64-битный код, так и уходящий уже в прошлое 32-битный. Что касается именно дампов и разрядности, то Вы можете отлаживать 64-разрядный дамп на 32-разрядной системе и наоборот. К недостаткам WinDbg можно отнести не удобный для большинства интерфейс, требующий дополнительной настройки, некоторые проблемы с отладкой в исходных текстах и знаменитую глючность. :) Основным предназначением отладчика WinDbg, как Вы уже догадались, является интерактивная отладка целевого кода.
!analyze -v
и прочие), без углубленной отладки дампа системы с учетом параметров и специфики конкретной STOP-ошибки.Подготовка
К глубокому сожалению, отладчик WinDbg не входит в состав дистрибутива операционной системы и, с определенного времени, не доступен в качестве отдельного продукта, а поставляется исключительно в составе пакета отладки Debugging Tools for Windows. Соответственно, для начала нам потребуется установить Debugging Tools for Windows. После окончания процедуры установки, которая детально описана в статье, мы готовы будем продолжить.
Первый запуск WinDbg
Теперь самое время запустить WinDbg. Действие это можно выполнить как из меню "Пуск", так и из командной строки. При первом запуске отладчика открывается главное окно пока еще не настроенной программы, имеющее примерно такой вот вид:
Глядя на скриншот можно понять, что при первом запуске WinDbg пользователь получает совершенно аскетичное рабочее окружение (workspace) отладчика с исключительно простым интерфейсом. Да, возможно многим интерфейс покажется совсем уж минималистичным, однако не спешите делать какие-либо выводы, поскольку на самом деле не все так плохо и рабочее окружение легко настраивается и доводится до уровня известных конкурентных продуктов. Нас же в данный момент подобный доводка не интересует, поскольку перед нами стоит задача получить подробную информации о сбое за как можно более краткий промежуток времени.
Настройка символов в WinDbg
Отладочные символы — информация, позволяющая использовать "символические" (понятные человеку) данные о бинарном файле, такие как имена процедур, функций и переменных, используемых автором в исходном коде.
Я бы настоятельно рекомендовал настраивать отладчик на работу с отладочными символами, особенно в ситуации с 32-битным кодом. В сети я встречал мнение, что WinDbg не нужны отладочные символы для вычисления сбойного драйвера/модуля, в контексте которого произошел сбой, но применительно к 32-битному коду часто наблюдал ситуацию, когда разбор стека отладчиком заканчивается совершенно парадоксальными результатами, совершенно далекими от истины. Особенно часто подобное проявляется в ситуации, когда отсутствуют символы для стороннего драйвера/модуля, находящегося в стеке момента сбоя и разбор стека отладчиком в этом случае затруднен. К тому же, при настроенных символах мы получаем дополнительную информацию по сбою и можем более детально проанализировать, к примеру, стек вызовов момента сбоя на уровне процедур и функций.
Настроить отладчик на работу с отладочным символам можно несколькими способами. Первый, самый простой и традиционный, заключается в указании составного пути к символам в настройках отладчика WinDbg: srv*c:\symbols*http://msdl.microsoft.com/download/symbols. Для настройки отладочных символов выберем в меню пункт File - Symbol File Path ... и просто вставим указанное выше значение в поле ввода, затем нажмем клавишу ОК.
Теперь при запуске процесса отладки, отладчик WinDbg сначала произведет поиск символов для модулей, участвующих в процессе отладки, в локальной папке c:\symbols, если там символов не будет обнаружено, то WinDbg попытается загрузить их из сети Интернет с сайта http://msdl.microsoft.com/download/symbols и закешировать (сохранить) в ту же папку c:\symbols. Отладчик WinDbg загружает символы только по мере необходимости и только к модулям, которые обнаруживаются в процессе анализа дампа. Причем директорию c:\symbols руками создавать не требуется, поскольку отладчик создаст её сам на стадии кеширования символов (в случае наличия у него соответствующих разрешений, конечно же).
Для того, чтобы не настраивать путь поиска символов каждый раз после запуска WinDbg, необходимо сохранить рабочее окружение отладчика. Для этого зайдите в меню "File" и выберите пункт "Save Workspace".
Еще один способ конфигурирования отладочных символов заключается в прописывании переменной окружения с именем _NT_SYMBOL_PATH
.
Анализ аварийного дампа системы
Первый сценарий, рассматриваемый нами в статье, подразумевает изучение системного (при останове системы) аварийного дампа памяти. Перво-наперво нам необходимо выполнить загрузку файла дампа в отладчик, для этого выбираем пункт меню File - Open Crash Dump..., после чего откроется окно выбора файла, в нем мы указываем местоположение аварийного дампа, выбираем сам файл и нажимаем кнопку ОК. Следствием данного действия является изменение интерфейса отладчика Windbg: открывается дочернее информационное окно вывода, которое предназначается для отображения логики работы отладчика и в нижней части окна появится командная строка.
Ничего Вам не напомнило? Интерфейс по структуре своей сильно похож на привычную консоль, имеется строка ввода и область (поле) вывода. Вероятно, разработчики стремились максимально совместить графический интерфейс с привычной для многих специалистов консолью. Как мы видим по скриншоту, сразу после загрузки аварийного дампа отладчик автоматически выполняет предварительный анализ. Стоит дождаться окончания этого процесса. Активность отладчика завершается, когда в информационное окно выводится сокращенный вывод анализа, в финальной части которого пользователь может наблюдать строку Followup: MachineOwner. Например:
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 |
Microsoft (R) Windows Debugger Version 6.12.0002.633 AMD64 Copyright (c) Microsoft Corporation. All rights reserved. Loading Dump File [C:\Users\user\Downloads\Mini052615-01.dmp] Mini Kernel Dump File: Only registers and stack trace are available Symbol search path is: srv*c:\symbols*http://msdl.microsoft.com/download/symbols Executable search path is: Windows XP Kernel Version 2600 (Service Pack 3) MP (2 procs) Free x86 compatible Product: WinNt, suite: TerminalServer SingleUserTS Built by: 2600.xpsp_sp3_qfe.120411-1615 Machine Name: Kernel base = 0x804d7000 PsLoadedModuleList = 0x8055d720 Debug session time: Tue May 26 13:07:26.828 2015 (UTC + 3:00) System Uptime: 0 days 0:02:45.552 Loading Kernel Symbols ............................................................... ................................................................ ............ Loading User Symbols Loading unloaded module list ............ ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* Use !analyze -v to get detailed debugging information. BugCheck 19, {20, 89d0c370, 89d0c3a0, a060001} Unable to load image RtkHDAud.sys, Win32 error 0n2 *** WARNING: Unable to verify timestamp for RtkHDAud.sys *** ERROR: Module load completed but symbols could not be loaded for RtkHDAud.sys Probably caused by : portcls.sys ( portcls!PcDispatchProperty+150 ) Followup: MachineOwner --------- |
В нижней части окна Command командная строка с подсказкой kd> станет активной. Этот факт сигнализирует нам о том, что возможен ввод пользовательских команд. На скриншоте выше я выделил красным цветом важную для нас строку Probably caused by:
, которая в переводе на русский язык означает "Вероятно вызван:", и которой отладчик сообщает нам о предполагаемом виновнике сбоя. Тем не менее, результат предварительного анализа можно получить не во всех сценариях, в вашем случае он может и отсутствовать. Почему имеет место быть такая расплывчатая формулировка "вероятно.."? Меня тоже всегда это удивляло. Вероятно, так уж устроена архитектура x86, что не возможно сделать точное заключение о причине сбоя, поскольку источником может быть аппаратная часть, что не всегда очевидно из анализа структур дампа, но это лишь моё предположение. К тому же, отладчик WinDbg проводит быстрый анализ дампа, выводя имя источника проблемы просто на основе исследования соответствующих структур внутри дампа, что, предположительно, тоже может не являться достаточным условием для точного предположения о виновнике сбоя. В нашем случае отладчик посчитал, что предполагаемым виновником является драйвер режима ядра portcls.sys
. И все, виновник найден? Но что-то по самому сбою на экране отладки у нас довольно мало информации, не думаю, что дотошному исследователю её будет достаточно. Как Вы могли уже заметить по приведенному выше выводу информационного окна, в нижней части его присутствует строка Use !analyze -v to get detailed debugging information, которая явно указывает нам на то, что есть возможность произвести более глубокий анализ проблемы и для этого можно выполнить команду !analyze -v
(при этом на странице присутствует активная, кликабельная ссылка). Сейчас мы еще раз, но более детально, проанализируем аварийный дамп, для чего можно либо щелкнуть по ссылке, либо ввести в командной строке:
!analyze –v
Это команда расширения WinDbg, которая выполняет ряд программных скриптов, предназначенных для анализа отдельных аспектов содержащейся в дампе информации. Ко всему прочему, присутствует опция -v
, которая задает режим подробного вывода. В результате, в информационном окне можно увидеть намного больше информации, нежели в предоставленном нам ранее стандартном анализе.
На всякий случай приведу скриншот расширенного анализа:
Ну и теперь посмотрим весь текстовый вывод анализатора при расширенном анализе:
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 |
******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* BAD_POOL_HEADER (19) The pool is already corrupt at the time of the current request. This may or may not be due to the caller. The internal pool links must be walked to figure out a possible cause of the problem, and then special pool applied to the suspect tags or the driver verifier to a suspect driver. Arguments: Arg1: 00000020, a pool block header size is corrupt. Arg2: 89d0c370, The pool entry we were looking for within the page. Arg3: 89d0c3a0, The next pool entry. Arg4: 0a060001, (reserved) Debugging Details: ------------------ Unable to load image RtkHDAud.sys, Win32 error 0n2 *** WARNING: Unable to verify timestamp for RtkHDAud.sys *** ERROR: Module load completed but symbols could not be loaded for RtkHDAud.sys BUGCHECK_STR: 0x19_20 POOL_ADDRESS: 89d0c370 CUSTOMER_CRASH_COUNT: 1 DEFAULT_BUCKET_ID: DRIVER_FAULT PROCESS_NAME: LouderIt.exe LAST_CONTROL_TRANSFER: from 8054b583 to 804f9f5f STACK_TEXT: b261f810 8054b583 00000019 00000020 89d0c370 nt!KeBugCheckEx+0x1b b261f860 8054b95f 89d0c378 00000000 b261f888 nt!ExFreePoolWithTag+0x2a3 b261f870 b3f79996 89d0c378 00000003 89f5e2f0 nt!ExFreePool+0xf b261f888 b3f799cf 89f5e2f0 8a9a97d8 e2527230 portcls!PcDispatchProperty+0x150 b261f8b0 b618fea8 00000004 8abb9330 8abb9328 portcls!PropertyItemPropertyHandler+0x2b b261f914 b618fed9 89f5e2f0 00000003 e2527230 ks!KspPropertyHandler+0x602 b261f938 b3f776a9 89f5e2f0 00000003 e2527208 ks!KsPropertyHandler+0x19 b261f94c b3f79ab3 89f5e2f0 00000003 e2527208 portcls!PcHandlePropertyWithTable+0x1b b261f980 b3f7774d 8a9a97c0 8a89a710 89f5e2f0 portcls!CPortFilterWaveCyclic::DeviceIoControl+0xb2 b261f99c b618ff1f 8a89a710 89f5e2f0 b261f9c4 portcls!DispatchDeviceIoControl+0x49 b261f9ac b3f778c0 8a89a710 89f5e2f0 8a89a7c8 ks!KsDispatchIrp+0x126 b261f9c4 b3f77881 8a89a710 89f5e2f0 b261f9f8 portcls!KsoDispatchIrp+0x43 b261f9d4 b3e04121 8a89a710 89f5e2f0 00000000 portcls!PcDispatchIrp+0x5f WARNING: Stack unwind information not available. Following frames may be wrong. b261f9f8 804ef1a9 8a89a710 00000004 89f5e2f0 RtkHDAud+0x424121 b261fa08 b26f0774 00000000 00000000 89f5e2f0 nt!IopfCallDriver+0x31 b261fa58 b26f218e 89f5e2f0 8abb9330 e3f24218 sysaudio!ForwardIrpNode+0x1b2 b261faac b618ff95 8a84ef08 89f5e2f0 b261faf8 sysaudio!CFilterInstance::FilterDispatchIoControl+0x14c b261fabc 804ef1a9 8a84ef08 89f5e2f0 89f5e2f0 ks!DispatchDeviceIoControl+0x28 b261facc b6190ba8 b2595aa0 b261fb3c 00000028 nt!IopfCallDriver+0x31 b261faf8 b258c6ce 8a976cb0 00000000 002f0003 ks!KsSynchronousIoControlDevice+0xbd b261fb5c b258dff2 8a976cb0 0000000d 00000010 wdmaud!kmxlAudioNodeProperty+0xb8 b261fb98 b258df7e 8aaf6e88 89e9fbd8 e3f134d8 wdmaud!kmxlHandleGetUnsigned+0xd3 b261fbc8 b258de58 89e9fbd8 8aaf6e88 8ac15300 wdmaud!kmxlGetControlDetailsHandler+0x200 b261fc18 b258dcbb 8a0133a8 89e9e000 8aaf6e88 wdmaud!Dispatch_GetControlDetails+0xfa b261fc40 804ef1a9 00000018 89e9e000 806e7410 wdmaud!SoundDispatch+0x424 b261fc50 8057f9a0 8a01343c 8a957250 8a0133a8 nt!IopfCallDriver+0x31 b261fc64 8058082f 8a875960 8a0133a8 8a957250 nt!IopSynchronousServiceTail+0x70 b261fd00 80579292 000000c0 00000224 00000000 nt!IopXxxControlFile+0x5c5 b261fd34 8054168c 000000c0 00000224 00000000 nt!NtDeviceIoControlFile+0x2a b261fd34 7c90e514 000000c0 00000224 00000000 nt!KiFastCallEntry+0xfc 0012fd58 00000000 00000000 00000000 00000000 0x7c90e514 STACK_COMMAND: kb FOLLOWUP_IP: portcls!PcDispatchProperty+150 b3f79996 8bc7 mov eax,edi SYMBOL_STACK_INDEX: 3 SYMBOL_NAME: portcls!PcDispatchProperty+150 FOLLOWUP_NAME: MachineOwner MODULE_NAME: portcls IMAGE_NAME: portcls.sys DEBUG_FLR_IMAGE_TIMESTAMP: 48025ccc FAILURE_BUCKET_ID: 0x19_20_portcls!PcDispatchProperty+150 BUCKET_ID: 0x19_20_portcls!PcDispatchProperty+150 Followup: MachineOwner --------- |
Небольшое лирическое отступление: на самом деле это полезность этой команды сильно недооценена, поскольку именно она, помимо анализа, позволяет увидеть достаточно важные для самостоятельного исследования структуры:
- Символическое имя STOP-ошибки (BugCheck), в нашем случае это
BAD_POOL_HEADER
; - Краткое описание сбоя, которое помогает исследователю выстроить алгоритм для самостоятельного анализа в зависимости от специфики конкретной ошибки;
- Четыре входных аргумента (параметра) функции
KeBugCheckEx
: Arg1, Arg2, Arg3, Arg4. Именно значения этих параметров позволяют посредством анализа соответствующих структур углубляться в проблему; - Стек вызовов. Помогает увидеть цепочку вызовов потока, что позволяет анализировать все стадии выполнения;
Для анализа стека вызовов момента падения нам пригодятся отладочные символы, поскольку полнота отображения информации о стеке вызовов в момент падения (для 32-битного кода) сильно зависит от наличия правильных отладочных символов всех причастных компонентов.
Но, вернемся к автоматизированному анализу. Он дает нам о сбое достаточно большое количество информации. Во-первых, мы можем видеть саму сбойную инструкцию. Во-вторых, мы может видеть имя функции, в рамках которой выполнялась сбойная инструкция в момент падения. В-третьих, мы можем видеть весь стек вызовов потока, в контексте которого произошел сбой, по данному стеку мы можем делать выводы о последовательности вызовов функций.
Каждая запись стека вызовов (STACK_TEXT) формируется по стандартному шаблону вида
имя_модуля!имя_функции+смещение
, где имя_модуля - имя исполняемого файла, код которого содержит функцию, имя_функции - наименование функции, смещение - количество байт (в шестнадцатеричной системе) от точки входа функции до инструкции, следующей за инструкцией, вызвавшей следующую функцию, одним словом - точка возврата из вышестоящей функции. В ряде ситуаций имя функции может быть недоступно, тогда адрес отображается в форматеимя_модуля+смещение
.
Многие начинающие исследователи (к каковым отношусь и я :) безоговорочно доверяют выводу трассировки стека, полученному при помощи команды !analyze
, при этом совершенно упуская из виду тот факт, что WinDbg является всего-лишь инструментом, опирающимся в своих процедурах анализа на данные из файла дампа. Иногда информация, необходимая для корректной трассировки стека попросту отсутствует, и это может привести к неправильной трассировке стека и, соответственно, выводу в отчет некорректной информации. Иногда (но не всегда) признаком неправильного разбора стека могут являться сообщения "Following frames may be wrong", а так же иные признаки, такие как присутствие в стеке функций, абсолютно не относящихся к проблеме, неправильные адреса и прочее. В нашем случае нам повезло и виновником действительно оказался драйвер, на который указывал отладчик, однако будьте внимательны, поскольку в запутанном деле анализа дампов памяти системы часто имеются нюансы.
Для многих далеко не все поля, которые можно видеть в информационном окне, окажутся понятными. Поэтому, попробую привести краткую собственную интерпретацию значений:
BUGCHECK_STR | BugCheck код или, по-другому, код STOP-ошибки в сокращенном формате. Собственный классификатор Microsoft для описания сбоев. Поле описывает код возникшего исключения в нескольких возможных форматах: 0xXXXXXXXX , 0xXX либо DD.DD.DDDD XXXXX . Чаще можно встретить сокращенную форму записи, в нашем случае это 0x19_20 . Первая половина четко указывает нам на STOP 0x00000019, а вот что означает вторая? |
POOL_ADDRESS | Адрес блока памяти, в котором находится страница, содержащая сбойную инструкцию. |
CUSTOMER_CRASH_COUNT | Поле отображается только в минидампах и показывает, сколько раз система упала с идентичной ошибкой после первого аналогичного случая. Вместо того, чтобы каждый раз создавать идентичный дамп, просто увеличивается данный счетчик. |
DEFAULT_BUCKET_ID | Поле отражает основную категорию сбоев, к которой принадлежит текущий сбой. В данном случае значение DRIVER_FAULT говорит о сбое в драйвере. Вероятно, где-то имеется каталог возможных категорий. |
PROCESS_NAME | Поле указывает на имя процесса, в рамках которого возник сбой. Другими словами это процесс, который выполнялся процессором (было выделено процессорное время) во время сбоя. Крайне редко рассматривается в качестве причины ошибки, потому как процесс был текущим, то есть просто выполнялся процессором в момент сбоя. |
LAST_CONTROL_TRANSFER | Поле показывает последний вызов в стеке. В нашем случае код по адресу 8054b583 вызвал функцию по адресу 804f9f5f . Для определения функции можно посмотреть данные адреса командой ln address . |
STACK_TEXT | Поле отражает карту стека в момент сбоя. Первое поле - EBP (фрейм), второе поле - адрес возврата, третье поле - первый передаваемый параметр, четвертое поле - второй передаваемый параметр, пятое поле - третий передаваемый параметр. Последнее поле - имя модуля и вызываемого метода внутри него в формате модуль!функция+смещение . |
STACK_COMMAND | Поле указывает на команду, применяемую для отображения стека вызовов. В нашем случае это kb , то есть отображение стека вызовов с первыми тремя параметрами, переданными каждой функции. Помните описание поля STACK_TEXT? Начиная с третьего поля там - это первый, второй и третий передаваемые параметры. |
FOLLOWUP_IP | Поле описывает участок кода, где возникла ошибка. Первое значение поля указывает на сбойную инструкцию в формате модуль!функция+смещение , во втором значении следует адрес, машинный код команды и сама дизассемблированная команда в мнемонике языка ассемблер, при выполнении которой и произошел сбой. |
SYMBOL_STACK_INDEX | |
SYMBOL_NAME | Описывает символическое имя инструкции, вызвавшей сбой. Символическое имя представляет собой смещение до сбойной инструкции в формате модуль!функция+смещение . В нашем случае это portcls!PcDispatchProperty+150 . |
FOLLOWUP_NAME | Вероятно (!) говорит об имени следующего выполняемого отладчиком набора команд. Значение MachineOwner может указывать на то, что после выполнения команды ожидается пользовательский ввод. |
MODULE_NAME | Имя модуля в таблице объектов ядра. Если анализатору удалось обнаружить проблемный драйвер, имя отображается в полях MODULE_NAME и IMAGE_NAME. |
IMAGE_NAME | Имя исполняемого образа, файла. Если анализатору удалось обнаружить проблемный драйвер, имя отображается в полях MODULE_NAME и IMAGE_NAME. |
DEBUG_FLR_IMAGE_TIMESTAMP | Вероятно (!) время, прошедшее с момента загрузки исполняемого образа в память. |
FAILURE_BUCKET_ID | Вероятно (!) некий классификатор сбоя. Группирует в себе код сбоя (BUGCHECK_STR), символическое имя ошибки, имя сбойного модуля/образа (IMAGE_NAME) и, если применимо, наименование функции со смещением (SYMBOL_NAME). |
BUCKET_ID | Вероятно (!) некий классификатор сбоя. Группирует в себе код сбоя (BUGCHECK_STR), символическое имя ошибки, имя сбойного модуля/образа (IMAGE_NAME) и, если применимо, наименование функции со смещением (SYMBOL_NAME). |
Кстати, символы могут быть не корректны. Большая величина смещения, отсутствие наименования функции после имени модуля, может говорить о том, что с символами что-то не так: либо они отсутствуют вовсе, либо они некорректны. Напротив, если смещение небольшое и присутствуют имена функций, то можно утверждать что символы корректны.
Соответственно, на основании расширенного вывода специалист может сделать намного больше предположений относительно природы сбоя. Собственно, когда виновник сбоя локализован, можно переходить к определению принадлежности сбойного модуля.
Анализ аварийного дампа приложения
Второй основной сценарий, в котором может применяться отладчик WinDbg с точки зрения анализа различного вида дампов - это изучение дампа памяти сбойного приложения (процесса). Полученный при помощи специализированных средств (Диспетчер задач Windows, Отчеты об ошибках Windows (WER), внешние отладчики cdb,...) дамп памяти глючащего приложения, можно так же с успехом проанализировать в отладчике. При этом, общий сценарий исследования и поиска причин меняется несущественно, в него, всего-лишь, добавляется дополнительная команда !dlls
. Эта команда позволяет создать отчет о загруженных непосредственно до записи дампа в адресное пространство процесса библиотеках, что дает возможность получить зачастую достаточно важную дополнительную информацию об адресном пространстве изучаемой программы. Синтаксис команды таков:
!dlls
Затем, выполняем уже изученную нами по предыдущему разделу команду:
!analyze –v
WinDbg не видит символы
При отсутствии сконфигурированного пути поиска символов и отсутствии в локальном кеше отладочных символов необходимых модулей/драйверов, отладчик WinDbg предупреждает нам об этом посредством сообщений об ошибках. Вот примерно такой текст мы можем наблюдать в информационном окне, когда Windbg не видит символы:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
Symbol search path is: *** Invalid *** **************************************************************************** * Symbol loading may be unreliable without a symbol search path. * * Use .symfix to have the debugger choose a symbol path. * * After setting your symbol path, use .reload to refresh symbol locations. * **************************************************************************** Executable search path is: ********************************************************************* * Symbols can not be loaded because symbol path is not initialized. * * * * The Symbol Path can be set by: * * using the _NT_SYMBOL_PATH environment variable. * * using the -y argument when starting the debugger. * * using .sympath and .sympath+ * ********************************************************************* Unable to load image ntoskrnl.exe, Win32 error 0n2 *** WARNING: Unable to verify timestamp for ntoskrnl.exe *** ERROR: Module load completed but symbols could not be loaded for ntoskrnl.exe Windows XP Kernel Version 2600 (Service Pack 3) MP (2 procs) Free x86 compatible Product: WinNt, suite: TerminalServer SingleUserTS Machine Name: Kernel base = 0x804d7000 PsLoadedModuleList = 0x8055d720 Debug session time: Tue May 26 13:07:26.828 2015 (UTC + 3:00) System Uptime: 0 days 0:02:45.552 |
Как я уже говорил выше, при отсутствии отладочных символов WinDbg может провести анализ дампа, однако качество анализа в этом случае предугадать довольно сложно. Поэтому, в большинстве случаев без символов нам не обойтись, поскольку вывод может быть совершенно не информативен! К счастью, у WinDbg имеется возможность импортировать символы прямо во время работы, и если у Вас, по каким то причинам символы не подключились на этапе старта отладчика, то можно исправить настройку в любой момент. Для этого в отладчике WinDbg присутствуют следующие команды:
.symfix
.reload
Если есть подключение к сети Интернет, мы должны увидеть что-то вроде такого:
1 2 3 4 5 6 7 |
Loading Kernel Symbols ............................................................... ................................................................ ............ Loading User Symbols Loading unloaded module list ............ |
Команда .symfix просто (добавляет) подставляет в переменную пути строку srv*, что предписывает отладчику WinDbg в случае необходимости подключаться к серверу символов Microsoft по адресу http://msdl.microsoft.com/download/symbols
и искать символы там. Команда также позволяет задавать путь к локальному кешу символов, и если локальный путь не задан, то по умолчанию используется поддиректория sym по пути инсталляции дистрибутива отладки. А команда .reload производит перечисление всех загруженных в адресное пространство процесса модулей и пытается найти ассоциированные файлы символов (в локальном хранилище, а так же на серверах Microsoft) для каждого из этих модулей. В случае же отсутствия подключения к сети Интернет, проблема приобретает совершенно другой вид и нам потребуется вручную скачивать символы к необходимым модулям, но это уже совершенно другая история. Ну и не лишним будет еще раз напомнить о том, что для того, что бы сохранить данные настройки в рабочем окружении (workspace) отладчика, необходимо выбрать меню "File" и далее пункт "Save Workspace".