Что такое BSOD изнутри или лезем в исходный код Windows

Автор: | 09.08.2015

Сразу хочу предупредить правообладателей, что этот пост касается только исходного кода Windows 2000, который доступен в интернете и которого нет на моей машине. Единственная цель с которой я это все делаю – это лучше знакомство и понимание читателя, что такое BSOD. Этот материал предназначен в основном для ИТ специалистов, мы будем смотреть исходный код Windows 2000 :).

Итак приступим. Начнем с кода, который непосредственно вызывает сам крах, делает дампы и т.д. Это функция с именем KeBugCheckEx, вот ее полная сигнатура

VOID
KeBugCheckEx (
IN ULONG BugCheckCode,
IN ULONG_PTR BugCheckParameter1,
IN ULONG_PTR BugCheckParameter2,
IN ULONG_PTR BugCheckParameter3,
IN ULONG_PTR BugCheckParameter4
)

Обратите внимание на комментарий:

Routine Description:    This function crashes the system in a controlled manner.

Я опускаю часть кода не до конца понятную для меня, например:

    //
// Try to simulate a power failure for Cluster testing
//

if (BugCheckCode == POWER_FAILURE_SIMULATE) {
KiScanBugCheckCallbackList();
HalReturnToFirmware(HalRebootRoutine);
}

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

Далее выполняются вызовы:

    RtlCaptureContext(&KeGetCurrentPrcb()->ProcessorState.ContextFrame);
KiSaveProcessorControlState(&KeGetCurrentPrcb()->ProcessorState);

Опять не будем уделять внимание детализации работы этих функций, можно предположить, что их смысл в сохранении данных которые касаются текущего состояния процессора, например, значения регистров. Только обратим внимание, что при анализе дампов в отладчике Windbg есть специальное расширение !prcb, которое отображает информацию о контрольном блоке процессора. Вот пример:

image

Далее опять же будет код, который будет выполнять дополнительные проверки,  опускаем его разбор и доходим до кода, который показывает синий экран смерти:

        if (InbvIsBootDriverInstalled()) {

InbvAcquireDisplayOwnership();

InbvResetDisplay();
InbvSolidColorFill(0,0,639,479,4); // make the screen blue
InbvSetTextColor(15);
InbvInstallDisplayStringFilter((INBV_DISPLAY_STRING_FILTER)NULL);
InbvEnableDisplayString(TRUE);     // enable display string
InbvSetScrollRegion(0,0,639,479);  // set to use entire screen
}

if (!hardErrorCalled) {
sprintf((char *)Buffer,
"
*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)
",
BugCheckCode,
BugCheckParameter1,
BugCheckParameter2,
BugCheckParameter3,
BugCheckParameter4
);
InbvDisplayString((char *)Buffer);

KeGetBugMessageText(BugCheckCode, NULL);
InbvDisplayString("
");

if (KiBugCheckDriver != NULL) {

//
// Output the driver name.
//

KeGetBugMessageText(BUGCODE_ID_DRIVER, NULL);
InbvDisplayString(AnsiBuffer);
InbvDisplayString("
");
}

Теперь нам нужно записать дамп памяти, делаем и это:

        KeGetCurrentPrcb()->ProcessorState.ContextFrame = ContextSave;

if (!IoWriteCrashDump(BugCheckCode,
BugCheckParameter1,
BugCheckParameter2,
BugCheckParameter3,
BugCheckParameter4,
&ContextSave
)) {

В интернете можно найти описание ф-ции IoWriteCrashDump, мы не будем ее разбирать, обращаю только внимание, что TRIAGE_DUMP – этот минидамп. Минидамп не включает в себя содержимоем всех страниц памяти.

Я этим постом хотел лишь показать, что разработчикам  ОС Windows нужно ставить лайки за то, что они предусмотрели механизм BSOD, который:

  • предотвращает более серьезные повреждение данных;
  • предоставляет возможность анализировать дампы памяти и находить проблему.

Этот обзор очень краток и не был бы полным без некоторых примером. Рассмотрим как генерируется крах INACCESSIBLE_BOOT_DEVICE

Есть такая функция, вот ее сигнатура:

NTSTATUS
IopMountVolume(
IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN AllowRawMount,
IN BOOLEAN DeviceLockAlreadyHeld,
IN BOOLEAN Alertable
)

Эта функция выполняет монтиривание тома на указанном устройстве. Если в ходе операции возникли проблемы выполняется следующий участок кода:

    //
// Finally, if the mount operation failed, and the target device is the
// boot partition, then bugcheck the system.  It is not possible for the
// system to run properly if the system's boot partition cannot be mounted.
//
// Note: Don't bugcheck if the system is already booted.
//

if (!NT_SUCCESS( status ) &&
DeviceObject->Flags & DO_SYSTEM_BOOT_PARTITION &&
InitializationPhase < 2) {
KeBugCheckEx( INACCESSIBLE_BOOT_DEVICE, (ULONG_PTR) DeviceObject, status, 0, 0 );
}

Смысл этого кода показать читатель, что синий экран смерти (BSOD), это нечто сродни ошибки в приложении, например, если вы забили вставить дискетку, а ваша программа пытается считать файл оттуда и выдает ошибку “Ошибка чтения файла с диска A:”

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *