Внедрение сбоев на основе стека
Примечание Инструкции по включению этой функции применяются только к WDK для Windows 8. Для Windows 8.1 эта функция была интегрирована в средство проверки драйверов. На компьютерах под управлением Windows 8.1 используйте параметр Имитация систематического нехватки ресурсов.
Параметр Внедрения сбоев на основе стека внедряет сбои ресурсов в драйверы режима ядра. Этот параметр использует специальный драйвер, KmAutoFail.sys, в сочетании с проверятелем драйверов для проникновения в пути обработки ошибок драйвера. Тестирование этих путей исторически было очень трудным. Параметр Внедрения сбоев на основе стека внедряет сбои ресурсов предсказуемым образом, что делает обнаруженные проблемы воспроизводимыми. Так как пути ошибок легко воспроизвести, это также упрощает проверку исправлений для этих проблем.
Чтобы помочь определить первопричину ошибки, предоставляется расширение отладчика, которое может точно указать, какие сбои были внедрены и в каком порядке.
Если параметр Внедрения сбоев на основе стека включен для определенного драйвера, он перехватывает некоторые вызовы из этого драйвера к ядру и Ndis.sys. Внедрение сбоев на основе стека анализирует стек вызовов, в частности часть стека вызовов, которая поступает из драйвера, в который он включен. Если этот стек встречается впервые, вызов завершится ошибкой в соответствии с семантикой этого вызова. В противном случае, если он видел этот вызов ранее, он будет передавать его через нетронутый. Внедрение сбоев на основе стека содержит логику, связанную с тем фактом, что драйвер можно загружать и выгружать несколько раз. Он распознает, что стек вызовов одинаков, даже если драйвер перезагружается в другое расположение памяти.
Активация этого параметра
Функцию внедрения сбоев на основе стека можно активировать для одного или нескольких драйверов при развертывании драйвера на тестовом компьютере. Вы можете выбрать параметр Внедрение сбоев на основе стека при настройке свойств средства проверки драйверов для проектов пакетов драйверов. Необходимо перезагрузить компьютер, чтобы активировать или отключить параметр Внедрения сбоев на основе стека. Вы также можете запустить тестовую служебную программу, чтобы включить средство проверки драйверов и эту функцию на тестовом компьютере.
Важно При активации внедрения сбоев на основе стека на тестовом компьютере убедитесь, что не выбирайте имитацию с низкими ресурсами.
Страница "Использование свойства средства проверки драйверов"
- Откройте страницы свойств для пакета драйверов. Щелкните правой кнопкой мыши проект пакета драйвера в Обозреватель решений и выберите Свойства.
- На страницах свойств пакета драйверов щелкните Свойства конфигурации, щелкните Установить драйвер, а затем — Средство проверки драйверов.
- Выберите Включить средство проверки драйверов. При включении средства проверки драйверов на тестовом компьютере можно включить средство проверки драйверов для всех драйверов на компьютере, только для проекта драйвера или для списка указанных драйверов.
- В разделе Инжектор сбоев на основе стека выберите (проверка) Внедрение сбоев на основе стека.
- Нажмите кнопку Применить или ОК.
- Дополнительные сведения см. в разделе Развертывание драйвера на тестовом компьютере . Чтобы активировать этот параметр, необходимо перезагрузить тестовый компьютер.
Использование теста включения и отключения проверки драйверов
Вы также можете включить средство проверки драйверов, запустив тест служебной программы. Следуйте инструкциям, описанным в статье Тестирование драйвера во время выполнения с помощью Visual Studio. В категории Все тесты\Проверка драйверов выберите тесты Включить проверку драйверов (требуется возможная перезагрузка) и Отключить проверку драйверов (требуется возможная перезагрузка).
Выберите параметры Средство проверки драйверов, щелкнув имя теста Включить проверку драйверов (требуется возможная перезагрузка) в окне Группа тестов драйверов .
Выберите (проверка) Внедрение сбоев на основе стека.
После добавления этих тестов в тестовую группу можно сохранить группу тестов. Чтобы включить внедрение сбоев на основе стека, запустите тест Enable Driver Verifier (требуется возможная перезагрузка) на компьютере, настроенном для тестирования.
Чтобы отключить средство проверки драйверов, запустите тест Отключение проверки драйверов (требуется возможная перезагрузка).
Использование параметра внедрения сбоев на основе стека
Одно из важных соображений при тестировании с помощью внедрения сбоев на основе стека заключается в том, что большинство обнаруженных ошибок приведет к проверка ошибок. Это может оказаться несколько болезненным, если ваш драйвер является загрузочным драйвером. По этой причине мы автоматически отключим внедрение сбоев на основе стека, если средство проверки драйверов отключено. Это означает, что вы можете отключить внедрение сбоев на основе стека во время загрузки из отладчика, отключив средство проверки драйверов с помощью команды !verifier –disable.
Если это возможно, для начальных тестов с внедрением сбоев на основе стека настройте драйвер так, чтобы он не загружался во время загрузки. Затем можно выполнить некоторые простые тесты загрузки и выгрузки. Многие ошибки, обнаруженные путем внедрения сбоев на основе стека, возникают во время инициализации или очистки. Их можно найти многократной загрузке и выгрузке драйвера.
После внесения исправлений, необходимых для успешного выполнения тестов выгрузки нагрузки, можно перейти к тестированию на основе IOCTL, полному функциональному тестированию и, наконец, нагрузочному тестированию. Как правило, если вы будете следовать этому ходу теста, вы не узнаете много новых проблем во время нагрузочного тестирования, так как большинство путей кода уже были выполнены до этого.
Использование расширения отладчика внедрения сбоев на основе стека (SBFI)
Большинство проблем, обнаруженных при внедрении сбоев на основе стека, приводят к проверкам ошибок. Чтобы определить причину этих ошибок в коде, WDK предоставляет расширение отладчика stack Based Failure Injection и необходимые символы. Процедура установки установит оба в системе отладчика. Расположение по умолчанию — C:\Program Files (x86)\Windows Kits\8.0\Debuggers\<arch>.
Запуск расширения отладчика
В командной строке отладчика введите следующую команду: !<path>\kmautofaildbg.dll.autofail. Например, если расширения отладчика установлены в папке c:\dbgext, а kmautofail.pdb находится в пути к символу, введите следующую команду:
!c:\dbgext\kmautofaildbg.dll.autofail
Это приведет к дампу сведений в отладчик, в котором отображаются стеки вызовов из последних внедренных сбоев. Каждая запись выглядит примерно так, как показано ниже, взятое из реального тестового запуска. В следующем примере внедрение сбоев на основе стека включено на Mydriver.sys
Sequence: 2, Test Number: 0, Process ID: 0, Thread ID: 0
IRQ Level: 2, HASH: 0xea98a56083aae93c
0xfffff8800129ed83 kmautofail!ShimHookExAllocatePoolWithTag+0x37
0xfffff88003c77566 mydriver!AddDestination+0x66
0xfffff88003c5eeb2 mydriver!ProcessPacketDestination+0x82
0xfffff88003c7db82 mydriver!ProcessPacketSource+0x8b2
0xfffff88003c5d0d8 mydriver!ForwardPackets+0xb8
0xfffff88003c81102 mydriver!RoutePackets+0x142
0xfffff88003c83826 mydriver!RouteNetBufferLists+0x306
0xfffff88003c59a76 mydriver!DeviceSendPackets+0x156
0xfffff88003c59754 mydriver!ProcessingComplete+0x4a4
0xfffff88001b69b81 systemdriver2!ProcessEvent+0x1a1
0xfffff88001b3edc4 systemdriver1!CallChildDriver+0x20
0xfffff88001b3fc0a systemdriver1!ProcessEvent+0x3e
0xfffff800c3ea6eb9 nt!KiRetireDpcList+0x209
0xfffff800c3ea869a nt!KiIdleLoop+0x5a
В верхней части выходных данных порядковый номер подсчитывает количество внедренных ошибок. В этом примере показан второй сбой, внедренный во время тестового запуска. Идентификатор процесса равен 0, поэтому это был системный процесс. ЗНАЧЕНИЕ IRQL равно 2, поэтому оно вызывается на уровне диспетчеризации.
В стеке KmAutoFail является драйвером внедрения сбоев на основе стека. Имя функции KmAutoFail указывает, какой вызов функции из Mydriver.sys был перехвачен и введен сбой. Здесь произошла ошибка функции ExAllocatePoolWithTag. Все функции в KmAutoFail, которые перехватывают вызовы Ntoskrnl.sys или Ndis.sys использовать это соглашение об именовании. Далее мы видим стек вызовов с тестируемым драйвером (Mydriver.sys). Это часть стека вызовов, которая используется для определения уникальности стека. Таким образом, каждая запись, созданная расширением отладчика, будет уникальной в этой части стека вызовов. Остальная часть стека вызовов указывает, кто вызвал драйвер. Main важность заключается в том, вызывается ли драйвер из пользовательского режима (с помощью IOCTL) или из драйвера в режиме ядра.
Обратите внимание, что если драйвер вернул ошибку из процедуры DriverEntry , попытка перезагрузки обычно выполняется в другом расположении памяти. В этом случае стек вызовов из предыдущего расположения, вероятно, будет содержать "мусор", а не сведения о стеке из драйвера. Но это не проблема; он сообщает, что драйвер правильно обработал эту ошибку.
В следующей записи показан вызов драйвера с помощью IOCTL из пользовательского режима. Обратите внимание на идентификатор процесса и уровень IRQ. Так как Mydriver.sys является драйвером фильтра NDIS, IOCTL пришел через Ndis.sys. Обратите внимание, что nt! NtDeviceIoControlFile находится в стеке. Все тесты, выполняемые в драйвере, который использует IOCTL, будут проходить через эту функцию.
Sequence: 5, Test Number: 0, Process ID: 2052, Thread ID: 4588
IRQ Level: 0, HASH: 0xecd4650e9c25ee4
0xfffff8800129ed83 kmautofail!ShimHookExAllocatePoolWithTag+0x37
0xfffff88003c6fb39 mydriver!SendMultipleOids+0x41
0xfffff88003c7157b mydriver!PvtDisconnect+0x437
0xfffff88003c71069 mydriver!NicDisconnect+0xd9
0xfffff88003ca3538 mydriver!NicControl+0x10c
0xfffff88003c99625 mydriver!DeviceControl+0x4c5
0xfffff88001559d93 NDIS!ndisDummyIrpHandler+0x73
0xfffff88001559339 NDIS!ndisDeviceControlIrpHandler+0xc9
0xfffff800c445cc96 nt!IovCallDriver+0x3e6
0xfffff800c42735ae nt!IopXxxControlFile+0x7cc
0xfffff800c4274836 nt!NtDeviceIoControlFile+0x56
0xfffff800c3e74753 nt!KiSystemServiceCopyEnd+0x13
Анализ результатов внедрения сбоев на основе стека
Вы запускаете тесты на драйвере, и вдруг вы столкнулись с проблемой. Скорее всего, это была ошибка проверка, но это также может быть связано с тем, что компьютер не отвечает. Как найти причину? Предполагая, что это ошибка проверка, сначала используйте расширение выше, чтобы найти список внедренных сбоев, а затем используйте команду отладчика: !analyze –v.
Наиболее распространенная ошибка проверка вызвана отсутствием проверки на успешность выделения. В этом случае стек из анализа проверка ошибок, вероятно, почти идентичен стеку последнего внедренного сбоя. В какой-то момент после сбоя выделения (часто в самой следующей строке) драйвер будет обращаться к указателю NULL. Этот тип ошибки очень легко исправить. Иногда неудающееся выделение составляет один или два в списке, но этот тип по-прежнему очень легко найти и исправить.
Вторая наиболее распространенная ошибка проверка возникает во время очистки. В этом случае драйвер, вероятно, обнаружил сбой выделения и перепрыгнул к очистке; но во время очистки драйвер не проверка указатель и снова обращается к пустому указателю. В тесно связанном случае очистка может быть вызвана дважды. Если очистка не устанавливает для указателя на структуру значение NULL после ее освобождения, при втором вызове функции очистки она попытается освободить структуру во второй раз, что приведет к ошибке проверка.
Ошибки, из-за которых компьютер перестает отвечать, сложнее диагностировать, но процедура их отладки аналогична. Эти ошибки часто возникают из-за количества ссылок или проблем со спин-блокировкой. К счастью, средство проверки драйверов перехватит множество проблем спин-блокировки, прежде чем они приведут к проблемам. В таких случаях войдите в отладчик и используйте расширение отладчика для дампа списка ошибок, которые были внедрены путем внедрения сбоев на основе стека. При кратком рассмотрении кода с последними сбоями может отобразиться число ссылок, которое было принято до сбоя, но не было выпущено после. В противном случае найдите поток в драйвере, который ожидает блокировки спина, или любой счетчик ссылок, который заведомо неправильный.