Голубые Экраны Смерти (BSOD) носят стихийный характер, появляясь в непредсказуемое время, не связанное ни с какими конкретными действиями пользователя. Приложения начинают выдавать критические ошибки в самых разных местах, причем коды ошибок во всех случаях обычно разные. Попробуем в этом разобраться...
Голубой Экран замечателен тем, что явным образом сигнализирует о наличие серьезной проблемы и дает наводку, куда копать. Зачастую, имя глючного драйвера высвечивается на экране, однако там его может и не быть, или (что еще хуже) может стоять имя совершенно другого драйвера. Получается запутанная цепочка.
К примеру, кривой драйвер от видеокарты имеет тенденцию разрушать структуры графической подсистемы Windows, в результате чего в BSOD'е отображается имя системного драйвера win32k.sys (см.ниже), в котором реализована значительная часть функций USER и GDI, которые тут вовсе не причём. Так что, интерпретация показаний BSOD - это магия, наука, и искусство - вместе взятые.
BSOD, с именем системного драйвера Win32k.sys, пострадавшего из-за другого драйвера:
*** STOP: 0x0000001E (0xC0000005,0xA0016B0E,0x00000001,0x5050585C)
KMODE_EXCEPTION_NOT_HANDLED
*** Address A0016B0E base at A0000000, DateStamp 30430FF7 - Win32k.sys
Beginning dump of phusical memory
Damping phusical memory to disk: 69
Помимо дефектов драйверов, Голубые Экраны Смерти могут вызываться отказами железа (например разогнанным процем), неисправной оперативкой, не до конца воткнутой в слот PCI-картой, плохим БП, вздутых электролитов на материнке и т.п. Поэтому, прежде чем "колоть дрова", необходимо убедиться, что железо полностью исправно.
Дефекты проектирования драйверов разработчиками могут носить самый разный характер - от выпадений в голубой экран, до замедления работы компа и глючного поведения (совсем не связанных с драйвером) прикладных приложений. В пресловутых экранах смерти и нестабильной работе винды в большинстве случаев виноваты драйвера сторонних производителей. Давайте попробуем их обнаружить и удалить из системы, заменив на более свежие и "прямые".
Драва без сертификата - в топку!
Весь комплект инструментария необходимый для разработки драйверов, Microsoft распространяет бесплатно (DDK - Driver Development Kit). Этот комплект (!)позволяет любому заточить "как бы" работающий, "как бы" драйвер! Как только появился DDK, сразу-же огромная армия "пионеров" дружненько взялись за разработку своих драйверов, от которых ничего путного ждать не приходится. Драйвер - это не "Hello World", и правильно написать его не каждому по-зубам!
Во избежание этого беспредела, Microsoft ввела процедуру сертификации драйверов на соответствие предъявляемых им требований, после которой драйверу выдавалась цифровая подпись. И хотя сертификация - всего лишь формальная процедура, не гарантирующая отсутствие фатальных ошибок и дефектов разработки, часть откровенно "пионерских" драйверов она все-таки отсеивает.
В идеале, в системе следует держать только драйвера заверенные цифровой подписью, т.к. она указывает на определенный уровень культуры разработки. Драйвера без цифровой подписи - это хуже, чем кот с кошкой в одном мешке! Встречались экземпляры, в которых обнаруживали зловредные программы, которые вызывали нестабильность системы.
Короче, не будем разводить демагогию, а попробуем ответить на один простой вопрос - как составить список драйверов без цифровой подписи? В этом нам поможет утилита sigverif.exe, входящая в комплект поставки винды.
Запускаем её (Win+R --> sigverif) и жмём "Дополнительно". Во вкладке "Поиск" настраиваем критерии отбора, перемещая радио-кнопку в положение "Искать другие файлы..", после чего в "Параметрах поиска" открываем бокс и выбираем "*.sys". Ниже указываем папку для поиска "C:\WINDOWS", обязательно отметив галочку "включая подпапки":
После нажатия на "ОК" --> "Пуск", на экране появится градусник, отображающий ход прогресса и винт начнет шуршать башками. По завершении будет составлен список драйверов без цифровой подписи.
Некоторые горячие головы предлагают сразу удалить все неподписанные драйвера, но последствия такой операции могут оказаться весьма плачевными и лучше, кликнув правой клавишей мыши на иконку драйвера, найти в "свойствах" имя производителя, по которому можно установить, что за приложение/железка установила этот драйвер и деинсталлировать ее цивилизованным путем, правда, здесь есть одно "но"..
Наличие/отсутствие цифровой подписи само по себе ещё ни о чём не говорит, и даже если мы используем только подписанные драйвера, никаких гарантий стабильности это нам не дает. Вот тут-то мы и переходим ко второй части, а именно - тестированию драйверов в боевых условиях!
Расшифровка кода BSOD
Первое, что нам нужно будет сделать - это перехватить последний вздох системы, в виде дампа памяти на момент краха! Для этого жмём:
[Win+Break --> Дополнительно --> Загрузка и восстановление --> Параметры]
..нужно снять там галочку "Выполнить авто-перезагрузку". С этого момента ваша зубная боль (перезагрузки) превращается в головную. При очередном отказе системы, появляется BSOD с кодом ошибки, и по-ходу в папке WINDOWS возникнет папка Minidump. В ней и находятся необходимые нам файлы! Они нам пригодятся в будущем, а пока - разберёмся с инфой BSOD'а.
Как показывает практика, львиная доля экранов смерти приходится на обращение к несуществующей области памяти, поэтому в качестве примера возьмём эту ошибку STOP 0х0Аh (IRQL_NOT_LESS_OR_EQUAL).
STOP 0x0000000A сообщает, что драйвер пытался обратиться по недопустимому адресу памяти! В этом случае система катапультирует пользователя даже не попращавшись. Ну и зачем было из-за этого ронять систему? Как сказать ей, что "в Багдаде всё спокойно!"? Дай знать об этом и всё..., ан нет - нужно обязательно клеить ласты. Билли в очередной раз доказывает, что создал непрактичную систему. Ну да хай с ним...
STOP 0х0А может быть вызван как программным обеспечением, так и проблемой с оборудованием. Для выявления причин мы должны разобрать этот STOP на мелкие кусочки! Для этих целей обычно используют дебагер, тем не менее, некоторые выводы можно сделать, рассмотрев параметры STOP-сообщения. Дебагер нас не устраивает тем, что его отчёт нужно будет отправлять в Майкрософт и тупо ждать от них ЦУ.
Помимо всех нравоучений (типа проверь железяку, обратись к админу), типичный шаблон экрана смерти выглядит примерно так:
STOP 0x0000000A (0xWWWWWWWW, 0xXXXXXXXX, 0xYYYYYYYY, 0xZZZZZZZZ)
IRQL_NOT_LESS_OR_EQUAL
Найти в сети имя ошибки - не проблема, да и способов решения тоже куча, но это всё только предположения! Имя ошибки ещё ни о чём не говорит, т.к. причин возникновения она не раскрывает. Вся инфа зарыта в скобках, о расшифровки которой большинство справочников дружно умалчивают. Попробую внести ясность в дело...
Значит, область значений после STOP является номером ошибки. Дальше (в скобках) идут параметры:
W - адрес в памяти, по которому выполнено ошибочное обращение
X - IRQL, который использовался для обращения к памяти
Y - тип доступа к памяти: 0 = операция чтения, 1 = операция записи
Z - адрес инструкции, которая затребовала доступ к памяти
Параметр "Z" несёт в себе наиболее значимую и в тоже время, наиболее труднодобываемую порцию инфы. Как видно из таблицы, это "Адрес инструкции". Что это такое и как узнать эту инструкцию? Для этого нужно диззасемблировать дамп памяти, в листинге которого и указывается глючная инструкция. Обычно, это "переходы на метки" в коде программы, типа JNx, FAR и т.д. Для пояснения, дизассемблирую виндовый блокнот:
C:\> debug c:\temp\notepad.exe
-u
13F2:0000 0E PUSH CS
13F2:0001 1F POP DS
13F2:0002 BA0E00 MOV DX,000E
13F2:0005 B409 MOV AH,09
13F2:0007 CD21 INT 21
13F2:0009 B8014C MOV AX,4C01
13F2:000C CD21 INT 21
13F2:000E 54 PUSH SP
13F2:000F 68 DB 68
13F2:0010 69 DB 69
13F2:0011 7320 JNB 0033
13F2:0013 7072 JO 0087
13F2:0015 6F DB 6F
13F2:0016 67 DB 67
13F2:0017 7261 JB 007A
13F2:0019 6D DB 6D
13F2:001A 206361 AND [BP+DI+61],AH
13F2:001D 6E DB 6E
13F2:001E 6E DB 6E
13F2:001F 6F DB 6F
13F2:0020 7420 JZ 0042
13F2:0022 62 DB 62
13F2:0023 65 DB 65
13F2:0024 207275 AND [BP+SI+75],DH
-
Если-бы блокнот уронил систему, то скорей всего в поле BSOD'a (0хZZZZ) стояло-бы значение или 0x00000011, или 0x00000020 (или другой адрес с переходом в коде). Смотрим, на какую строку программного кода указывает переход (на адреса 0033 и 0042 соответственно). Осталось перейти по указанному адресу и исправить баг. Это и есть "Адрес инструкции"!
Хотелось-бы сказать пару слов об отладчиках реального режима, типа Soft-ICE. Он позволяет перехватить ошибки системы, не допуская её краха. Алгоритм такой: ждать ошибку и при возникновении не дать процессу перейти по указанному адресу! Вместо авто-перехода, отладчик предлагает перейти по указанному адресу вручную, что позволяет двумя строчками кода возвратить управление родительскому процессу, тем самым предотвратив BSOD. Есть над чем поработать большому Билли...
Но вернёмся к параметру (Z). Если он указывает на область адресов системных устройств, значит в момент ошибки был запущен драйвер какого-то сус-устройства. Этот драйвер обычно указан на третьей линии STOP экрана. Попробуем расшифровать такую запись:
Stop 0x0000000A (0x0227001d, 0x00000002, 0x00000000, 0x804eba3a)
IRQL_NOT_LESS_OR_EQUAL
...кидаем взор на параметры в скобках (справа-налево) и делаем вывод, что "Ошибка вызвана НЕ системным устройством, при операции чтения ячейки памяти 0227001Dh". Но какое именно устройство-то сглючило? Смотрим, IRQL у нас равен 02h. Но здесь - стоп, ...нужно прояснить некоторые нюансы и дать определение IRQ и IRQL.
Что такое IRQ ?
IRQ - это запрос на обслуживание. Физически, IRQ представляют собой отдельно проложенные линии (проводники), которые предназначены только для передачи запросов прерывания. После получения запроса, процессор обращается к таблице векторов прерываний, которая находится в памяти и содежит список адресов программ-обработчиков. От номера прерывания зависит, какая программа будет запущена. В основном этими программами являются драйвера относящиеся к устройству, которое послало запрос.
Сама таблица находится в ОЗУ и состоит из 256 элементов по 4 байта каждый (адреса от 0х0000h до 0х0400h). Чтобы не было путаницы, у IRQ есть иерархия или приоритеты. Чем меньше номер прерывания, тем выше приоритет и наоборот. Системных IRQ всего 16. Самый высокий приоритет у IRQ 0, а самый низкий у IRQ 15.
Чтоб просмотреть свои прерывания, жмём [Win+R --> msinfo32 --> Ресурсы аппаратуры –-> Прерывания IRQ]:
0 - Системный таймер
1 - Контроллер клавиатуры
2 - Программируемый контроллер прерываний
3 - COM-2
4 - COM-1
5 - Звуковая или сетевая карты или свободен
6 - Контроллер гибких дисков
7 - LPT
8 - CMOS и часы
9 - Звуковая или сетевая карты или свободен
10 - Свободен
11 - USB или SCSI или свободен
12 - PS/2 мышь
13 - Сопроцессор
14 - Контроллер IDE
15 - Дополнительный контроллер IDE
Будем считать, что с IRQ мы разобрались. Переходим к IRQL..
Что такое IRQL ?
IRQL — это некое свойство потока, как-бы приоритет. Оно означает, что потоки с более низким IRQL не смогут вытеснить поток с более высоким IRQL. Повышение IRQL изпользуется для того, чтобы поток с высоким приоритетом имел приимущество перед низким. Например, приоритет планировщика потоков (DPC) выше, чем приоритет пользовательских потоков. Если бы это было не так, тогда потоки могли бы вытеснить планировщик и тем самым «отключить» многозадачность.
В Windows NT применяются 32 уровня IRQL, самый привилегированный из которых - 31:
31 - High
30 - Power fail
29 - IPI
28 - Clock
27 - Profile
26-3 - Диапазон аппаратных прерываний (Devices IRQL/DIRQL)
02 - DPC/DISPATCH
01 - APC
00 - PASSIVE (0)
...к примеру это означает, что планировщик работающий на уровне DPC/DISPATCH может быть прерван аппаратными прерываниями, межпроцессорными прерываниями (IPI) и т.д., но не может быть прерван асинхронными процедурами (APC) и обычными потоками, работающими на уровне PASSIVE.
Также IRQL помогает отслеживать и выявлять логические ошибки при проектировании ОС. Легендарная ошибка IRQL_NOT_LESS_OR_EQUAL означает следующую ситуацию... Драйвер с IRQL меньше чем DPC/DISPATCH, обратился к отсутствующей в памяти странице. Эта страница находится не в памяти, а на диске, и требуется вызов подсистемы, которая загрузила-бы её в память. Однако эта подсистема (в соответствии с архитектурой Win) имеет IRQL меньше, чем DPC/DISPATCH. Следовательно, она не имеет права прерывать тот код, который вызвал ошибку страницы. В то же время привилегированный код не может продолжить выполнение, пока страница не будет загружена. Возникает логический тупик, который и приводит к краху ОС. Такой-вот получается клубок.
Конечно-же при помощи этих знаний у нас не получится полностью расшифровать данные BSOD, но кое что мы уже имеем...
Stop 0x0000000A (0x0227001d, 0x00000002, 0x00000000, 0x804eba3a)
IRQL_NOT_LESS_OR_EQUAL
...это возбудил "кто-то" с низким приоритетом и копать здесь системные устройства ни к чему! Код, зашитый в блок IRQL несёт в себе более детальную информацию, когда выглядет как в первом посте: 0xA0016B0E. Последний байт (0Eh) - это и есть привилегия IRQ, породившего BSOD (0Eh=14d). Остальные-же данные блока IRQL расшифровать не так-уж просто, т.к. они зависят от установленного железа и ОС, и не имеют систематизированной инфы. Здесь нужно будет применять сторонний софт.
Всё, что понадобится из софта, для определения драйвера, вызвавшего BSOD - это дамп памяти на момент краха, и программа BlueScreenView. Она не требует установки и после запуска сама лезет в папку [..\System32\MiniDump], чтоб показать нам всё что нарыла:
..двойнок клик на строке с именем дампа и вот она вся подноготная:
...ага, виновник всех проблем - драйвер NVIDIA. Чтоб определить, кому принадлежит файл, запускаем поиск в папке Windows по имени драйвера, и в свойствах файла смотрим принадлежность: NVIDIA Compatible Windows 2000 Display driver, Version 56.73. Проверяем, есть-ли он в списке неподписанных драйверов, и если да, то в первую очередь переустанавливаем его на "правильный". Если-же с подписью всё ОК, то остаётся дизасемблировать дамп и искать проблемы в нём. Не помешает просмотреть и лог системы - [Win+R -> Eventvwr -> Система].
Для самообразования!
Коллекцию BSOD'ов всех мастей и видов, можно найти здесь. Удачи Вам, и жизни без BSOD'ов!
|