Как подключить дамп памяти
"…в отделе программ весь пол был усеян дырочками от перфокарт и какие-то мужики ползали по раскатанной по полу 20-метровой распечатке аварийного дампа памяти с целью обнаружения ошибки в распределителе памяти ОС-360. К президенту подошел начальник отдела и сообщил, что есть надежда сделать это еще к обеду"
Ю.Антонов "Юность Гейтса"
Дамп памяти (memory dump, также называемый "корой" [от английского core –— сердцевина], crash- или аварийным дампом), сброшенный системой при возникновении критической ошибки –— не самое убедительное средство для выявления причин катастрофы, но ничего другого в руках администратора зачастую просто не бывает. Последний вздох операционной системы, похожий на дурно пахнущую навозную кучу, из которой высовывается чей-то наполовину разложившийся труп, мгновенным снимком запечатленный в момент неустранимого сбоя –— вот что такое дамп памяти во время крушения системы! Копание в нем вряд ли доставит вам удовольствие. Не исключено, что истинного виновника краха системы вообще не удастся найти. Допустим, некий некорректно работающий драйвер вторгся в область памяти, принадлежащую другому драйверу, и наглым образом затер критические структуры данных, сделав из чисел "винегрет". К тому моменту, когда драйвер-жертва пойдет вразнос, драйвер-хищник может быть вообще выгружен из системы, и определить его причастность к крушению системы по одному лишь дампу практически нереально.
Тем не менее, полностью игнорировать факт существования дампа, право же, не стоит. В конце концов, до возникновения инактивных отладчиков ошибки в программах приходилось искать именно так. Избалованность современных программистов визуальными средствами анализа, увы, не добавляет им уверенности в тех ситуациях, когда неумолимая энтропия оставляет их со своими проблемами один на один. Но довольно лирики. Переходим к делу, расписывая каждое действие по шагам.
Первым делом, необходимо войти в конфигурацию системы Пуск à Настройка à Панель управления à Система
(Start à Settings à Control Panel à System) и убедиться, что настройки дампа соответствуют предъявляемым к ним требованиям Дополнительно à Загрузка и восстановление à Отказ системы (Startup/Shutdown à Recovery) в Windows 2000 RUS и Windows NT 4.0 ENG соответственно). Операционная система Windows 2000 поддерживает три разновидности дампов памяти: малый дамп памяти (small memory dump), дамп памяти ядра (kernel memory dump) и полный дамп памяти (complete dump memory). Для изменения настроек дампа вы должны иметь права администратора.
Малый дамп памяти занимает всего лишь 64 Кбайта (а отнюдь не 2 Мбайта, как утверждает контекстная помощь) и включает в себя:
q копию "голубого экрана смерти";
q перечень загруженных драйверов;
q контекст обрушившегося процесса со всеми его потоками;
q первые 16 Кбайт содержимого ядерного стека "обрушившегося" потока.
Разочаровывающие малоинформативные сведения! Непосредственный анализ дампа дает нам лишь адрес возникновения ошибки и имя драйвера, к которому этот адрес принадлежит. При условии, что конфигурация системы не была изменена после возникновения сбоя, мы можем загрузить отладчик и дизассемблировать подозреваемый драйвер, но это мало что даст. Ведь содержимое сегмента данных на момент возникновения сбоя нам неизвестно, более того —? мы не можем утверждать, что видим те же самые машинные команды, что вызвали сбой. Поэтому малый дамп памяти полезен лишь тем администраторам, которым достаточно одного лишь имени нестабильного драйвера. Как показывает практика, в подавляющем большинстве случаев этой информации оказывается вполне достаточно. Разработчикам драйвера отсылается гневный "бан-рапорт" (вместе с дампом!), а сам драйвер тем временем заменяется другим –— более новым и надежным.
По умолчанию малый дамп памяти записывается в каталог %SystemRoot%\Minidump, где ему присваивается имя Mini, дата записи дампа и порядковый номер сбоя на данный день. Например Mini110701-69.dmp –— 69 дамп системы от 07 ноября 2001 года (не пугайтесь! это просто я отлаживал драйвера).
Дамп памяти ядра содержит намного более полную информацию о сбое и включает в себя всю память, выделенную ядром и его компонентами (драйверами, уровнем абстракции от оборудования и т. д.), а также копию "голубого экрана смерти". Размер дампа памяти ядра зависит от количества установленных драйверов и варьируется от системы к системе. Контекстная помощь утверждает, что эта величина составляет от 50 до 800 Мбайт. Ну, на счет 800 Мбайт авторы явно "загнули", и объем в 50–—100 Мбайт выглядит более вероятным (техническая документация на систему сообщает, что ориентировочный размер дампа ядра составляет треть объема физической оперативной памяти, установленной на системе). Это наилучший компромисс между накладными расходами на дисковое пространство, скорости сброса дампа и информативностью последнего. Весь "джентльменский" минимум информации –— в вашем распоряжении. Практически все типовые ошибки драйверов и прочих ядерных компонентов могут быть локализованы с точностью до байта, включая и те, что вызваны физическим сбоем аппаратуры (правда, для этого вы должны иметь некоторый "патологоанатомический" опыт исследования "трупных" дампов системы). По умолчанию дамп памяти ядра записывается в файл %SystemRoot%\Memory.dmp, затирая или не затирая (в зависимости от текущих настроек системы) предыдущий дамп.
Полный дамп памяти включает в себя все содержимое физической памяти компьютера, занятое как прикладными, так и компонентами ядра системы. Полный дамп памяти оказывается особенно полезным при отладке ASPI/SPTI-приложений, которые в силу своей специфики могут "уронить" ядро даже с прикладного уровня.
Несмотря на довольно большой размер, равный размеру оперативной памяти, полный дамп остается наиболее любимым дампом всех системных программистов (системные же администраторы в своей массе предпочитают малый дамп). Это не покажется удивительным, если вспомнить, что объемы жестких дисков давно перевалили за отметку 100 Гбайт, а оплата труда системных программистов за последние несколько лет даже несколько возросла. Лучше иметь невостребованный полный дамп под рукой, чем кусать локти при его отсутствии. По умолчанию полный дамп памяти записывается в файл %SystemRoot%\Memory.dmp, затирая или не затирая (в зависимости от текущих настроек системы) предыдущий дамп.
Выбрав предпочтительный тип дампа, давайте совершим учебный "падение" системы, отрабатывая методику его анализа в "полевых" условиях. Для этого нам понадобится:
q комплект разработчика драйверов (Driver Development Kit или сокращенно DDK), бесплатно распространяемый фирмой Microsoft и содержащий в себе подробную техническую документацию по ядру системы; несколько компиляторов Си/Си++ и ассемблера, а также достаточно "продвинутые" средства анализа дампа памяти;
q драйвер W2K_KILL.SYS или любой другой драйвер-убийца операционной системы, например BDOS.EXE от Марка Русиновича, позволяющий получить дамп в любое удобное для нас время, не дожидаясь возникновения критической ошибки (бесплатную копию программы можно скачать с адреса http://www.sysinternals.com);
q файлы символьных идентификаторов (symbol files), необходимые отладчикам ядра для его нормального функционирования и делающие дизассемблерный код более наглядным. Файлы символьных идентификаторов входят в состав "зеленого" набора MSDN, но, в принципе, без них можно и обойтись, однако переменная окружения _NT_SYMBOL_PATH по любому должна быть определена, иначе отладчик i386kd.exe работать не будет;
q одна или несколько книжек, описывающих архитектуру ядра системы.
Очень хороша в этом смысле книга " Внутреннее устройство Windows 2000" Марка Руссиновича и Дэвида Соломона, интересная как системным программистам, так и администраторам.
Итак, установив DDK на свой компьютер и завершив все приложения, запускаем драйвер-убийцу и… под "скрипящий" звук записывающегося дампа, система немедленно выбрасывает "голубой экран смерти" (BSOD — Blue Screen Of Death), свидетельствующий о возникновении неустранимого сбоя системы с краткой информацией о нем, кратко информирующий нас о причинах сбоя (см. рис. 3.4 xx).
*** STOP: 0x0000001E (0xC0000005, 0xBE80B000, 0x00000000, 0x00000000)
KMODE_EXEPTION_NOT_HALTED
*** Address 0xBE80B000 base at 0xBE80A000, Date Stamp 389db915 – w2k_kill.sys
Beginning dump of physical memory
Dumping physical memory to disk: 69
Рис.унок 3.4. "Голубой экран смерти" (BSOD – Blue Screen Of Death), свидетельствующий о возникновении неустранимого сбоя системы с краткой информацией о нем
Для большинства администраторов "голубой экран смерти" означает лишь одно –— системе "поплохело" настолько, что она предпочла смерть позору неустойчивого функционирования. Что же до таинственных надписей, сопровождающих эти экраны, то они остаются сплошной загадкой. Но только не для настоящих профессионалов!
Мы начнем с левого верхнего угла экрана и, зигзагами спускаясь вниз, трассируем все надписи по порядку.
q *** STOP: — буквально означает "останов [системы]" и не несет в себе никакой дополнительной информации;
q 0x0000001E — представляет собой код Bug Check, содержащий категорию сбоя. Расшифровку кодов Bug Check можно найти в DDK. В данном случае это 0x1E –— KMODE_EXEPTION_NOT_HALTED, о чем и свидетельствует символьное имя расположенное строкой ниже. Краткое объяснение некоторых, наиболее популярных кодов Bug Check приведено в таблице 3.1.
Определение рейтинга популярности кодов Bug Check осуществлялось путем подсчета упоминаний о них в конференциях Интернет (спасибо старику Googl'у). Полноту фирменной документации она, разумеется, не заменяет, но некоторое представление о целесообразности скачивания 70 Мбайт DDK все-таки дает;
q "арабская вязь" в круглых скобках –— это четыре Bug Check-параметра, физический смысл которых зависит от конкретного кода Bug Check и вне его контекста теряет всякий смысл; применительно к KMODE_EXEPTION_NOT_HALTED –— первый Bug Check-параметр содержит номер возбужденного исключения. Судя по таблице 3.1, это –— STATUS_ACCESS_VIOLATION –— доступ к запрещенному адресу памяти –— и четвертый Bug Check-параметр указывает какой именно. В данном случае он равен нулю, следовательно, некоторая машинная инструкция попыталась совершить обращение по null-pointer, соответствующему инициализированному указателю, ссылающемуся на невыделенный регион памяти. Ее адрес содержится во втором Bug Check-параметре. Третий Bug Check-параметр в данном конкретном случае не определен;
q *** Address 0xBE80B00 –— это и есть тот адрес, по которому произошел сбой. В данном случае он идентичен второму Bug Check-параметру, однако так бывает далеко не всегда (коды Bug Check собственно и не подряжались хранить чьи-либо адреса).
q base at 0xBE80A00 –— содержит базовый адрес загрузки модуля-нарушителя системного порядка, по которому легко установить "паспортные" данные самого этого модуля.
Внимание!
Далеко не во всех случаях правильное определение базового адреса вообще возможно.
Воспользовавшись любым подходящим отладчиком (например, Soft-Ice от Нумега или i386kd от Microsoft), введем команду, распечатывающую перечень загруженных драйверов с их краткими характеристиками (в i386kd это осуществляется командой !drivers).
Как одним из вариантов, можно воспользоваться утилитой drivers.exe, входящей в NTDDK. но, какой бы вы путь не избрали, результат будет приблизительно следующим:
kd> !drivers!drivers
Loaded System Driver Summary
Base Code Size Data Size Driver Name Creation Time
80400000 142dc0 (1291 kb) 4d680 (309 kb) ntoskrnl.exe Wed Dec 08 02:41:11 1999
80062000 cc20 ( 51 kb) 32c0 ( 12 kb) hal.dll Wed Nov 03 04:14:22 1999
f4010000 1760 ( 5 kb) 1000 ( 4 kb) BOOTVID.DLL Thu Nov 04 04:24:33 1999
bffd8000 21ee0 ( 135 kb) 59a0 ( 22 kb) ACPI.sys Thu Nov 11 04:06:04 1999
be193000 16f60 ( 91 kb) ccc0 ( 51 kb) kmixer.sys Wed Nov 10 09:52:30 1999
bddb4000 355e0 ( 213 kb) 10ac0 ( 66 kb) ATMFD.DLL Fri Nov 12 06:48:40 1999
be80a000 200 ( 0 kb) a00 ( 2 kb) w2k_kill.sys Mon Aug 28 02:40:12 2000
TOTAL: 835ca0 (8407 kb) 326180 (3224 kb) ( 0 kb 0 kb)
Обратите внимание на выделенную полужирным черным цветом строку с именем w2k_kill.sys, найденную по ее базовому адресу 0xBE80A00. Это и есть тот самый драйвер, который нам нужен! А впрочем, этого можно и не делать, поскольку имя "неправильного" драйвера и без того присутствует на "голубом экране смерти";
q две нижние строки отражают прогресс "сброса" дампа на диск, развлекая администратора чередой быстро меняющихся циферок на это время.
Таблица 3.1. Физический смысл наиболее популярных кодов Bug Check с краткими пояснениями
Категория |
Описание |
|
hex-код |
Символьное имя |
|
0x0A |
IRQL_NOT_LESS_OR_EQUAL |
Драйвер попытался обратиться к странице памяти на уровне DISPATCH_LEVEL или более высоком, что и привело к краху, поскольку менеджер виртуальной памяти работает на более низком уровне; источником сбоя может быть и BIOS, и драйвер, и системный сервис (особенно этим грешат вирусные сканеры и FM-тюнеры); как вариант –— проверьте кабельные терминаторы на SCSI-накопителях и Master/Slayer на IDE, отключите кэширование памяти в BIOS; если и это не поможет, обратитесь к четырем параметрам кода Bug Check, содержащим ссылку на память, к которой осуществлялся доступ, уровень IRQ (Interrupt ReQuest), тип доступа (чтение/запись) и адрес машинной инструкции драйвера |
0x1E: |
KMODE_EXCEPTION_NOT_HANDLED |
Компонент ядра возбудил исключение и "забыл" его обработать; номер исключения содержится в первом Bug Check-параметре; обычно он принимает одно из следующих значений: 0x80000003 (STATUS_BREAKPOINT): встретилась программная точка останова –— отладочный рудимент, по небрежности не удаленный разработчиком драйвера; (0xC0000005) STATUS_ACCESS_ VIOLATION: доступ к запрещенному адресу (четвертый Bug Check-параметр уточняет к какому) –— ошибка разработчика; (0xC000021A) STATUS_SYSTEM_ PROCESS_TERMINATED: сбой процессов CSRSS и/или Winlogon, источником которого могут быть как компоненты ядра, так и пользовательские приложения; обычно это происходит при заражении машины вирусом или нарушении целостности системных файлов; (0xC0000221) STATUS_IMAGE_ CHECSUM_MISMATCH: целостность одного из системных файлов оказалась нарушена; второй Bug Check-параметр содержит адрес машинной команды, возбудившей исключение |
0x24 |
NTFS_FILE_SYSTEM |
Проблема с драйвером NTFS.SYS, обычно возникающая вследствие физического разрушения диска, реже –— при остром недостатке физической оперативной памяти |
0x2E |
DATA_BUS_ERROR |
Драйвер обратился по несуществующему физическому адресу; если только это не ошибка драйвера; оперативная память и/или кэш-память процессора (видеопамять) неисправны или же работают на запредельных тактовых частотах |
0x35 |
NO_MORE_IRP_STACK_LOCATIONS |
Драйвер более высокого уровня обратился к драйверу более низкого уровня посредством IoCallDriver-интерфейса, однако свободного пространства в стеке IRP (I/O Request Packet) не оказалось и передать весь IRP-пакет целиком не удалось; это гибельная ситуация, не имеющая прямых решений; попытайтесь удалить один или несколько наименее нужных драйверов, быть может тогда система заработает |
0x3F |
NO_MORE_SYSTEM_PTES |
Результат сильной фрагментации таблицы страниц PTE (Page Table Entry), приводящей к невозможности выделения затребованного драйвером блока памяти; обычно это характерно для аудио- или видеодрайверов, манипулирующих огромными блоками памяти и к тому же не всегда их вовремя освобождающих; для решения проблемы попробуйте увеличить количество PTE (до 50 000 максимум) в следующей ветке реестра: HLLM\SYSTEM\CurrentControlSet\ Control\SessionManager\ Memory Management\SystemPages |
0x50 |
PAGE_FAULT_IN_NONPAGED_AREA |
Обращение к несуществующей странице памяти, вызванное либо неисправностью оборудования (как правило –— оперативной, видео или кэш-памяти), либо некорректно спроектированным сервисом (этим грешат многие антивирусы, в том числе Касперский и Доктор Веб), либо разрушениями NTFS-тома (запустите программу chkdsk.exe с ключами /f и /r), также попробуйте запретить кэширование памяти в BIOS |
0x58 |
FTDISK_INTERNAL_ERROR |
Сбой RAID-массива, –— при попытке загрузки с основного диска система обнаружила, что он поврежден, тогда она обратилась к его зеркалу, но таблицы разделов не оказалось и там. |
0x76 |
PROCESS_HAS_LOCKED_PAGES |
Драйвер не смог освободить залоченные [Y94] [n2k95] страницы после завершения операции ввода-вывода; для определения имени дефективного драйвера следует обратиться к ветке HKLM\SYSTEM\CurrentControlSet\ Control\Session Manager\ Memory Management, и установить параметр TrackLockedPages типа DWORD в значение 1, потом перезагрузить систему, после чего та будет сохранять трассируемый стек и, если нехороший драйвер вновь начнет чудить, возникнет BSOD с кодом Bug Check: 0xCB, позволяющим определить виновника |
0x77 |
KERNEL_STACK_INPAGE_ERROR |
Страница данных памяти ядра по техническим причинам недоступна, если первый код Bug Check не равен нулю, то он может принимать одно из следующих значений: (0xC000009A) STATUS_INSUFFICIENT_RESOURCES –— недостаточно системных ресурсов; (0xC000009C) STATUS_DEVICE_DATA_ ERROR –— ошибка чтения с диска (bad-сектор?); (0xC000009D) STATUS_DEVICE_NOT_ CONNECTED –— система не видит привод (неисправность контроллера, плохой контакт шлейфа); (0xC000016A) STATUS_DISK_ OPERATION_FAILED –— ошибка чтения диска (bad-сектор или неисправный контроллер); (0xC0000185) STATUS_IO_DEVICE_ ERROR –— неправильное "термирование" SCSI-привода или конфликт IRQ IDE-приводов; нулевое же значение первого кода Bug Check указывает на неизвестную аппаратную проблему; такое сообщение может появляться и при заражении системы вирусами, и при разрушении диска старыми "докторами", и при отказе RAM –— войдите в консоль восстановления и запустите программу chkdsk.exe с ключом /r |
0x7A |
KERNEL_DATA_INPAGE_ERROR### |
Страница данных памяти ядра по техническим причинам недоступна, второй Bug Check-параметр содержит статус обмена, четвертый –— виртуальный страничный адрес, загрузить который не удалось; возможные причины сбоя — те же дефектные сектора, попавшие в файл-подкачки pagefile.sys, сбои дискового контроллера, ну и вирусы, наконец |
0x7B |
INACCESSIBLE_BOOT_DEVICE |
Загрузочное устройство недоступно, –— таблица разделов повреждена или не соответствует файлу boot.ini; также такое сообщение появляется при замене материнской платы с интегрированным IDE-контроллером (или замене SCSI-контроллера), поскольку всякий контроллер требует "своих" драйверов и при подключении жесткого диска с установленной Windows NT на компьютер, оснащенный несовместимым оборудованием, операционная система просто откажется грузиться и ее необходимо будет переустановить (опытные администраторы могут переустановить непосредственно сами дисковые драйвера, загрузившись с консоли восстановления); также не помешает проверить общую исправность оборудования и наличие вирусов на диске |
0x7F |
UNEXPECTED_KERNEL_MODE_TRAP |
Исключение процессора, необработанное операционной системой; обычно возникает вследствие неисправности оборудования (как правило –— разгона CPU), его несовместимости с установленными драйверами или алгоритмическими ошибками в самих драйверах; проверьте исправность оборудования и удалите все посторонние драйвера; первый Bug Check-параметр содержит номер исключения и может принимать следующие значения: 0x00 –— попытка деления на нуль; 0x01 –— исключение системного отладчика; 0x03 –— исключение точки останова; 0x04 –— переполнение; 0x05 –— генерируется инструкцией BOUND; 0x06 –— неверный опкод; 0x07 –— двойной отказ (Double Fault); описание остальных исключений содержится в документации на процессоры Intel и AMD |
0xC2 |
BAD_POOL_CALLER |
Текущий поток вызвал некорректный pool-request, что обычно происходит по причине алгоритмической ошибки, допущенной разработчиком драйвера; однако, судя по всему, и сама система не остается без ошибок, поскольку для устранения этого "голубого экрана смерти" Microsoft рекомендует установить SP2 |
0xCB |
DRIVER_LEFT_LOCKED_PAGES_IN_ PROCESS |
После завершения процедуры ввода/вывода, драйвер не может освободить заблокированные страницы (см. PROCESS_HAS_LOCKED_PAGES); первый Bug Check-параметр содержит вызываемый, а второй Bug Check-параметр, вызывающий адрес; последний, четвертый параметр указывает на UNICODE-строку с именем драйвера |
0xD1 |
DRIVER_IRQL_NOT_LESS_OR_EQUAL |
То же самое, что и IRQL_NOT_LESS_OR_EQUAL |
0xE2 |
MANUALLY_INITIATED_CRAS |
Сбой системы, спровоцированный вручную, путем нажатия "горячей" комбинации клавиш <Ctrl>+<Scroll Loock>, при условии, что параметр CrashOnCtrlScroll реестра HKLM\System\CurrentControlSet\ Services\i8042prt\Parameters содержит ненулевое значение |
0x7A |
KERNEL_DATA_INPAGE_ERROR |
Страница данных памяти ядра по техническим причинам недоступна, второй Bug Check-параметр содержит статус обмена, четвертый –— виртуальный страничный адрес, загрузить который не удалось; возможные причины сбоя — те же дефектные сектора, попавшие в файл pagefile.sys, сбои дискового контроллера, ну и вирусы, наконец |