Отладка / обход BSOD без исходного кода - PullRequest
3 голосов
/ 29 сентября 2011

Здравствуйте и хорошего вам дня.

Здесь нужно немного помочь:

Ситуация :
У меня неясное приложение DirectX 9 (имя и детали приложения не имеют отношения к вопросу), которое вызываетсиний экран смерти на всех картах NVIDIA (GeForce 8400GS и выше), начиная с определенной версии драйвера.Я считаю, что проблема косвенно вызвана вызовом DirectX 9 или флагом, вызывающим ошибку драйвера.

Цель :
Я бы хотел отследить вызывающий вызов флаг / вызов функции (для удовольствия, это не моя работа / домашняя работа) и обойти условие ошибки, написав прокси dll.У меня уже есть готовый прокси-dll, который предоставляет оболочки для IDirect3D9, IDirect3DDevice9, IDirect3DVertexBuffer9 и IDirect3DIndexBuffer9 и обеспечивает базовую регистрацию / трассировку вызовов Direct3D.Однако я не могу точно определить функцию, которая вызывает сбой.

Проблемы :

  1. Исходный код или техническая поддержка недоступны.Помощи не будет, и никто другой не решит проблему.
  2. Дамп памяти, созданный ядром, не помог - очевидно, нарушение прав доступа происходит в nv4_disp.dll, но я не могу использовать stacktrace для перехода кВызов метода IDirect3DDevice9, плюс есть вероятность, что ошибка возникает асинхронно.
  3. (Основная проблема) Из-за большого количества вызовов метода Direct3D9Device я не могу надежно зарегистрировать их в файле или по сети:
    1. Вход в файл приводит к значительному замедлению даже без очистки, и из-за этого все последнее содержимое журнала теряется, когда системные BSODы.
    2. Вход по сети (с использованием UDP и WINSOck sendto) также вызывает значительное замедление ине должно выполняться асинхронно (асинхронные пакеты теряются в BSOD), плюс пакеты (те, которые находятся в аварийном состоянии) иногда теряются даже при синхронной отправке.
    3. Когда приложение «замедляется» из-за регистрации подпрограмм, вероятность возникновения BSOD снижается, что затрудняет его отслеживание.

Вопрос:
Обычно я не пишу драйверы и не выполняю этот уровень отладки, поэтому у меня сложилось впечатление, что я упускаю что-то важное, есть более простой способ отследить проблему, чем написание прокси IDirect3DDevice9DLL с пользовательским механизмом регистрации.Что это?Каков стандартный способ диагностики / обработки / исправления проблемы, подобной этой (без исходного кода, метод интерфейса COM запускает BSOD)?

Анализ мини-дампов (WinDBG) :

Loading User Symbols
Loading unloaded module list
...........
Unable to load image nv4_disp.dll, Win32 error 0n2
*** WARNING: Unable to verify timestamp for nv4_disp.dll
*** ERROR: Module load completed but symbols could not be loaded for nv4_disp.dll
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

Use !analyze -v to get detailed debugging information.

BugCheck 1000008E, {c0000005, bd0a2fd0, b0562b40, 0}

Probably caused by : nv4_disp.dll ( nv4_disp+90fd0 )

Followup: MachineOwner
---------

0: kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

KERNEL_MODE_EXCEPTION_NOT_HANDLED_M (1000008e)
This is a very common bugcheck.  Usually the exception address pinpoints
the driver/function that caused the problem.  Always note this address
as well as the link date of the driver/image that contains this address.
Some common problems are exception code 0x80000003.  This means a hard
coded breakpoint or assertion was hit, but this system was booted
/NODEBUG.  This is not supposed to happen as developers should never have
hardcoded breakpoints in retail code, but ...
If this happens, make sure a debugger gets connected, and the
system is booted /DEBUG.  This will let us see why this breakpoint is
happening.
Arguments:
Arg1: c0000005, The exception code that was not handled
Arg2: bd0a2fd0, The address that the exception occurred at
Arg3: b0562b40, Trap Frame
Arg4: 00000000

Debugging Details:
------------------


EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at "0x%08lx" referenced memory at "0x%08lx". The memory could not be "%s".

FAULTING_IP: 
nv4_disp+90fd0
bd0a2fd0 39b8f8000000    cmp     dword ptr [eax+0F8h],edi

TRAP_FRAME:  b0562b40 -- (.trap 0xffffffffb0562b40)
ErrCode = 00000000
eax=00000808 ebx=e37f8200 ecx=e4ae1c68 edx=e37f8328 esi=e37f8400 edi=00000000
eip=bd0a2fd0 esp=b0562bb4 ebp=e37e09c0 iopl=0         nv up ei pl nz na po nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010202
nv4_disp+0x90fd0:
bd0a2fd0 39b8f8000000    cmp     dword ptr [eax+0F8h],edi ds:0023:00000900=????????
Resetting default scope

CUSTOMER_CRASH_COUNT:  3

DEFAULT_BUCKET_ID:  DRIVER_FAULT

BUGCHECK_STR:  0x8E

LAST_CONTROL_TRANSFER:  from bd0a2e33 to bd0a2fd0

STACK_TEXT:  
WARNING: Stack unwind information not available. Following frames may be wrong.
b0562bc4 bd0a2e33 e37f8200 e37f8200 e4ae1c68 nv4_disp+0x90fd0
b0562c3c bf8edd6b b0562cfc e2601714 e4ae1c58 nv4_disp+0x90e33
b0562c74 bd009530 b0562cfc bf8ede06 e2601714 win32k!WatchdogDdDestroySurface+0x38
b0562d30 bd00b3a4 e2601008 e4ae1c58 b0562d50 dxg!vDdDisableSurfaceObject+0x294
b0562d54 8054161c e2601008 00000001 0012c518 dxg!DxDdDestroySurface+0x42
b0562d54 7c90e4f4 e2601008 00000001 0012c518 nt!KiFastCallEntry+0xfc
0012c518 00000000 00000000 00000000 00000000 0x7c90e4f4


STACK_COMMAND:  kb

FOLLOWUP_IP: 
nv4_disp+90fd0
bd0a2fd0 39b8f8000000    cmp     dword ptr [eax+0F8h],edi

SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  nv4_disp+90fd0

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: nv4_disp

IMAGE_NAME:  nv4_disp.dll

DEBUG_FLR_IMAGE_TIMESTAMP:  4e390d56

FAILURE_BUCKET_ID:  0x8E_nv4_disp+90fd0

BUCKET_ID:  0x8E_nv4_disp+90fd0

Followup: MachineOwner

Ответы [ 3 ]

6 голосов
/ 01 октября 2011

Нашли решение.

Проблема
Ведение журнала ненадежно, так как сообщения (при сохранении в файл) исчезают во время bsod, пакеты иногда теряются при входе в сеть по сети, и происходит замедление из-за ведения журнала.

Решение
Вместо записи в файл или по сети настройте систему на создание полного дампа физической памяти в BSOD и запишите все сообщения в любой буфер памяти. Это будет быстрее. После сбоя системы она выгрузит всю память в файл, и можно будет либо просмотреть содержимое буфера файла журнала с помощью команды WinDBG dt (если у вас есть символы отладки), либо вы сможете искать и найдите файл журнала, хранящийся в памяти, используя представление «память».

Я использовал кольцевой буфер std :: strings для хранения сообщений и отдельный массив const char *, чтобы упростить чтение в WinDBG, но вы можете просто создать огромный массив char и хранить все сообщения внутри него в виде открытого текста.

подробности
Весь процесс на winxp:

  1. Убедитесь, что минимальный размер файла подкачки равен или превышает общий объем ОЗУ + 1 мегабайт. (Щелкните правой кнопкой мыши «Мой компьютер» -> «Свойства» -> «Дополнительно» -> «Производительность» -> «Дополнительно» -> «Изменить»)
  2. Сконфигурируйте систему для создания полного дампа памяти в BSOD (щелкните «Мой компьютер» -> «Свойства» -> «Дополнительно» -> «Запуск и восстановление» -> «Настройки» -> «Запись отладочной информации». Выберите «Полный сброс памяти» и укажите нужный путь). ).
  3. Убедитесь, что на диске (где будет записан файл) достаточно свободного места (общий объем оперативной памяти в вашей системе.
  4. Сборка app / dll (той, которая ведёт логи) с символом отладки и Trigger BSOD.
  5. Дождаться окончания дампа памяти, перезагрузиться. Не стесняйтесь ругаться на разработчика драйвера, пока система записывает дамп памяти и перезагружается.
  6. Скопируйте созданную систему MEMORY.DMP в безопасное место, чтобы вы не потеряли все, если система снова выйдет из строя.
  7. Запустите windbg.
  8. Открыть дамп памяти (Файл-> Открыть дамп памяти).
  9. Если вы хотите увидеть, что произошло, используйте команду !analyze -v.
  10. Доступ к буферу памяти, в котором хранятся зарегистрированные сообщения, одним из следующих способов:
    1. Чтобы увидеть содержимое глобальной переменной, используйте dt module!variable, где «module» - это имя вашей библиотеки (без * .dll), а «variable» - это имя переменной. Вы можете использовать подстановочные знаки. Вы можете использовать адрес без module!variable
    2. Чтобы увидеть содержимое одного поля глобальной переменной (если глобальная переменная является структурой), используйте dt module!variable field, где «field» - член переменной.
    3. Для просмотра более подробной информации о varaible (содержании массивов и подструктур) используйте dt -b module!variable field или dt -b module!variable
    4. Если у вас нет символов, вам придется искать свой «лог-файл», используя окно памяти.

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

Кроме того ...

  1. Чтобы увидеть информацию о процессе, который сбил систему, используйте !process.
  2. Чтобы увидеть загруженные модули, используйте lm
  3. Для получения информации о потоке !thread id, где id - это шестнадцатеричный идентификатор, который вы видели в !process выходных данных.
6 голосов
/ 29 сентября 2011
nv4_disp+90fd0
bd0a2fd0 39b8f8000000    cmp     dword ptr [eax+0F8h],edi

Это важная часть.Глядя на это, наиболее вероятно, что eax является недействительным, следовательно, пытаясь получить доступ к неверному адресу памяти.

Что вам нужно сделать, это загрузить nv4_disp.dll в IDA (вы можете получить бесплатную версию), проверьтебаза изображений, в которую IDA загружает nv4_disp и нажимает «g», чтобы перейти к адресу, попробуйте добавить 90fd0 к базе изображений, которую использует IDA, и должно привести вас непосредственно к ошибочной инструкции (в зависимости от структуры раздела).

Отсюда вы можете проанализировать поток управления, а также установить и использовать eax.Если у вас есть хороший отладчик уровня ядра, вы можете установить точку останова на этом адресе и попытаться заставить ее срабатывать.

Анализируя функцию, вы должны попытаться выяснить, что делает функция, на что должен указывать eax в этой точке, на что указывает ее на самом деле и почему.Это сложная часть и большая часть сложности и навыка реверс-инжиниринга.

1 голос
/ 01 октября 2011

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

Вы можете попытаться выяснить, какая последовательность событий приводит к этому повреждению кучи, но здесь нет «серебряной пули» - как предполагает смещение файла, вам нужно будет на самом деле перепроектировать драйвер, чтобы понять, почему это происходит (это может помочь сравнивать драйверы до и после версии драйвера, который нарушил работу!)

...