доброго времени суток! есть драйвер. он падает на единственном компе у клиента. доступа к тому компу доступа не имею, но мне присылают crash dumps. после анализа этих дампов обнаружилось, что проблема KMODE_EXCEPTION_NOT_HANDLED STATUS_ACCESS_VIOLATION + некоторый stack trace: f2de55c8 804e36d5 f2de5a40 00000000 feae64c0 nt+0x92eb5 f2de55ec f3461f27 feae64c0 8226ed90 00de5624 nt+0xc6d5 f2de5a4c 804e37f7 821c7030 feae64b0 feae64b0 MyDriver+0x3f27 так вот вопрос: как мне найти где именно падает драйвер (т.е. как найти в исходнике что соответствует MyDriver+0x3f27)? кто-нибудь может подсказать ка решить проблему? Заранее благодарен!
Если сохранился pdb и исходники в том виде как они были на момент компиляции, то самое простое влить дамп в WinDbg и набрать .ecxr - WinDbg встанет на нужную строку прямо в исходнике (исходники должны лежать в каталоге где они были при компиляции). Если pdb нет, то 0x3f27 - это смещение от начала образа драйвера или File Offset. Нужно преобразовать его в Virtual Address. Если руками не умеешь, то во многих PE-редакторах есть такая функция. Например в PE Tools есть FLC - File Locator Calculator. Поимев RVA, вливаешь драйвер в дизассемблер и идёшь по нужному RVA (в IDA клавиша G). Строку в исходнике в этом случае получишь путём анализа дизасма. А вообще, WinDbg должен сам показать нужную строку (дизасм), по крайней мере, по команде !analyze -v ЗЫ: Судя по стеку падает внутри ядра, после вызова драйвером какой-то функции.
спасибо! но что-то не сильно полчилось... .ecxr выдаёт кучу ошибок вида: ERROR: Module load completed but symbols could not be loaded for NAVENG.Sys и в конце: Couldn't resolve error at 'cxr' pdb и исходники лежат там же где и копилились, но windbg их почему-то не подхватывает...
Извиняюсь, забыл что .ecxr - только для юзер-модной отладки. Имея файловое смещение MyDriver+0x3f27 можно однозначно и просто найти это место в дизассемблере. В IDA, оказывается, можно перемещаться прямо по File Offset. Вливай драйвер в IDA, Jump->Jump to file offset... и вводи свои 0x3f27. Окажешься в нужном месте. Положи рядом pdb - когда ида спросит вливать его или нет, скажи да - увидишь имена функций вместо sub_xxxx. На худой конец, если хочешь и секретов нет, можешь мне на мыло (<мой ник> собака mail.ru) скинуть драйвер (без исходников, разумеется, - голый sys) - я посмотрю. Если опыта анализа крэшдампов нет, то для начала почитай kernel_debugging_tutorial.doc (лежит в каталоге с WinDbg). Потом поброди по debugger.chm (лежит там же). Затем набросай драйвер, который вызовет крах системы... нет... лучше слей готовый Notmyfault http://www.sysinternals.com/windowsinternals.html и поанализируй дампы. В книжке по ссылке, кстати, есть хорошая вводная статья по анализу крэшдампов. Тут на словах трудно помочь. Я прошёлся по тем ядрам, что у меня есть, но зацепить ничего не удалось - адреса не совпадают. Какая у клиета система? Если не знаешь, то WinDbg должен показать в самом верху. Или лучше приаттачь сюда, то что WinDbg говорит. Сделай... !analyze -v lmnt kd ...хотя kd без символов мало что даст. Какой у тя дамп? Мини (64К)? Вобщем "Делайте что-нибудь, Шарапов, делайте - не сидите сиднем!" (с) Груздев
Four-F, огромное спасибо за помощь! я обязательно почитаю, то ты мне посоветовал! но проблему уже и так удалось решить (надеюсь...) в IDA я что-то не нашел Jump to file offset. может она у меня сильно старая...зато если пойти по 00013f27 то полученный блок исходников один в один совпадает с тем, что говорит windbg... а проблема была в том, что остался кусок кода с незапамятных времен...и если файла !!!!test5.txt не находит, то падает вот такие вот косяки хотя, если это не поможет, буду еще спрашивать Огромнейшее спасибо за помощь!!!
Four-F Чтобы исследовать аварийный дампы, надо почитать то что ты предложил, т.к. у Касперски это очень мало! А на русском кроме Криса мало кто пишет, толково! Хотелось бы чтобы ты написал такую статью, вопросами обеспечим! )) Я конечно предполжу твою рекомендацию: учите английский, но ведь бывает, что человеку Именно сейчас надо! А язык он только еще учит, как быть такому челу?
В принципе, можно было бы подумать, но в четвёртом издании "Внутреннее устройство Microsoft Windows" этому посвещена целая глава на 28 страниц. Всё по-русски. Если писАть статью, то минимум на 50% это будет копирка. ЗЫ: А вопросы давайте, интересно ЗЗЫ: А где у Криса про это?
Four-F написал бы маленький тутор по WinDbg в режиме ядра (судя по ответам, знаешь его) на русском А то сколько искал - ни одной ссылки не видел Приходится отлаживать путем бсодов
Этого точно не будет. Во-первых, для ядерной отладки нужны две машины: отлаживаемая и отлаживающая. Хотя это и жутко удобно и производительнее чем в айсе, но много тут людей имеющих такую связку? Во-вторых, WinDbg я знаю но, честно говоря, плохо. В-третьих, был тут один человек, который обещал написАть такой тутор
<font color="gray][ cresta</font><!--color--><font color="gray]: написал бы маленький тутор по WinDbg в режиме ядра на русском ]</font><!--color--> Вот вам, типа, первая часть ------------------------------ >> На худой конец, если хочешь и секретов нет, можешь мне на мыло... > посмотри плиз...а то у меня уже совсем урыша съезжает 100% ты переполняешь стек. Код (Text): kd> !analyze -v ********************************************************************** ********* * * * Bugcheck Analysis * * * ********************************************************************** ********* UNEXPECTED_KERNEL_MODE_TRAP_M (1000007f) Arguments: Arg1: 00000008, EXCEPTION_DOUBLE_FAULT Arg2: 80042000 Arg3: 00000000 Arg4: 00000000 STACK_TEXT: WARNING: Stack unwind information not available. Following frames may be wrong. f392385c 804e37f7 83370020 f9e26008 02c03000 Driver+0xf79 f3923880 804f552f 83370020 82a7520a 82a752c8 nt+0xc7f7 f39238a0 804f5194 83372810 82a752e8 82a752c8 nt+0x1e52f ... f3925d6c 012cea68 f66de54a 00000000 00000000 0xbadb0d00 f3925d70 f66de54a 00000000 00000000 00000000 0x12cea68 f3925d74 00000000 00000000 00000000 00000000 somename+0x54a FOLLOWUP_IP: Driver+f79 f1fb9f79 56 push esi Первым делом идем в DDK и смотрим описание UNEXPECTED_KERNEL_MODE_TRAP_M, которое гласит, что одной из вероятных причин падения может быть A kernel stack overflow. К сожалению, в минидампе команда !thread не работает, а то можно было бы сразу увидеть начало и конец стека. Придётся по трассе стека разбирать. Стек ядра очень мал - всего 3 страницы, т.е. 12Кб. Из первой (нижней) строки трассы можно заключить, что вершина стека равна 0xF3926000-1. Нужно просто округлить 0xF3925D74 до максимального адреса в пределах страницы: 0xF3925D74+0x28B=0xf3926000-1. Если вершина стека 0xF3926000-1, то его дно 0xF3926000-3*0x1000=0xF3923000. Когда ты входишь в свою Driver!DispatchRead (верхняя строка по трассе), esp уже равен 0xF392385C, т.е. до дна стека остаётся 0xF392385C-0xF3923000=0x85C байт. Код (Text): .text:00010F70 DispatchRead proc near .text:00010F70 push ebp .text:00010F71 mov ebp, esp .text:00010F73 sub esp, 918h <-- выделяшь на стеке 2328 (много!) байт для локальных переменных .text:00010F79 push esi <-- UNEXPECTED_KERNEL_MODE_TRAP_M .text:00010F7A push edi В Driver!DispatchRead ты выделяешь на стеке 0x918 байт, что болше остатка равного 0x85C, и таким образом выходишь за границы стека. Когда процессор пытается затолкнуть esi в стек, происходит кирдык, т.к. указатель стека esp равен 0xF3922F44, что ниже дна. Код (Text): kd> r eax=00000003 ebx=82a752c0 ecx=83370020 edx=f9e26008 esi=8322e490 edi=83372810 eip=f1fb9f79 esp=[b]f3922f44[/b] ebp=f392385c iopl=0 nv up ei ng nz na po nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010286 Мораль: не нужно использовать в дровах много локальных переменных и буферов. Если требуется большой локальный буфер, то юзайте системные пулы. Решение: вытекает из морали. Исправить процедуру Driver!DispatchRead так, чтобы она не использовала так много стека. После этого, скорее всего, всё заработает нормально, т.к. драйвер, похоже последний в цепочке, т.е. стек больше никому не потребуется. Если клиент, у которого падает, продвинут и морально устойчив, то можно пихнуть в драйвер вызовы IoGetStackLimits и IoGetInitialStack, вывести в лог и попросить прислать лог. При этом можно воспользоваться IoGetRemainingStackSize (враппер над IoGetStackLimits) для определения остатка стека, и если стека не хватает - уходить.
Вот не я тему заводил, а за первую часть - спасибо. Очень понятно, особенно для новичков - все объяснено, показано. Понятно, что это в доках есть, - но тут объяснения человека, реально использующего продукт, практика. Очень часто страничка таких объяснений (не важно на каком языке) заменяет целые главы в книгах (многие любят так книги писАть, наверное, чтобы можно было, с помощью объема, в глазах читателя цену книги оправдать ;0)). А новичку бывает просто страшно лезть в изучение, потому как по мануалам, хелпу и т.д. не все сразу понятно (в силу отсутствия опыта). Думаю, не ошибусь, если скажу, что народ жаждет второй части :0). Извините за некоторый оффтопик.
/offtop В книге Руссиновича(новой 2005 г.) на стр.92 внизу, указывается понятие "Стек ядра" в www.ya.ru Чаще встречается "Стек режима ядра", я до ответа Гуру думал, что это разные понятия. Вобщем такой разброд, Может уважаемый Four-F дал бы понятие, я бы принял его слова за стандарт!
<font color="gray][ ksu_ant</font><!--color--><font color="gray]: Думаю, не ошибусь, если скажу, что народ жаждет второй части :0). ]</font><!--color--> Кидайтесь в меня минидампами с sys'ами ( только не все сразу ), может и будет вторая. <font color="gray][ EvilsInterrupt</font><!--color--><font color="gray]: Может уважаемый Four-F дал бы понятие, я бы принял его слова за стандарт! ]</font><!--color--> Обратимся к первоисточнику: "Using the Kernel Stack The size of the kernel-mode stack is limited to approximately three pages. Consequently, when passing data to internal routines, drivers cannot pass large amounts of data on the kernel stack. To avoid running out of kernel-mode stack space, use the following design guidelines: Avoid making deeply nested calls from one internal driver routine to another, if each routine passes data on the kernel stack. Take care to limit the number of recursive calls that can occur, if you design a driver with a recursive routine. In other words, the call-tree structure of a driver should be relatively flat. You can call the IoGetStackLimits and IoGetRemainingStackSize routines to determine the amount of kernel stack space that is available. Note that the size of the kernel-mode stack can vary among different hardware platforms and different versions of the operating system. Running out of kernel stack space causes a fatal system error. Therefore, it is better for a driver to allocate system-space memory than to run out of kernel stack space. However, nonpaged pool is also a limited system resource." Как видно, используются оба понятия, но kernel stack в DDK используется чаще. У любого потока (кроме чисто ядерных) - два стека. Один используется, когда поток работает в режиме пользователя (user mode). Когда поток переходит в режим ядра (kernel mode), система переключает стеки и поток начинает использовать свой стек ядра. Отсюда и происходит kernel-mode stack. Так что "cтек ядра" и "cтек режима ядра" - это просто дословные переводы соответствующих англоязычных словосочетаний и означают они абсолютно одно и то же.
EvilsInterrupt http://www.sysinternals.com/Publications.html ХАчу ВСЕ и на Русском! Там все ссылки на windowsitpro, где требуется регистрация и, как я понял, она не совсем бесплатная Можно ли где-нибудь почитать то же самое, но более "пролетарским" способом?
Four-F Хорошо что рад учить народ ловить рыбку, все же лучше чем давать ему уже пойманную! Когда страницы в памяти нет, возникает возникает исключение с номером 0xe, так? Значит запись в IDT с этим номером и есть системный обработчик. Судя потому, что прочитал в Руссиновиче это так, теперь наберу: Код (Text): kd> !idt Dumping IDT: 37: 806ed728 hal!PicSpuriousService37 3d: 806eeb70 hal!HalpApcInterrupt 41: 806ee9cc hal!HalpDispatchInterrupt 50: 806ed800 hal!HalpApicRebootService 62: 823aedd4 Unknown_Module_f8451000!IdePortInterrupt (KINTERRUPT 823aed98) 63: 81e5d2cc USBPORT!USBPORT_InterruptService (KINTERRUPT 81e5d290) 73: 81fdddd4 VIDEOPRT!pVideoPortInterrupt (KINTERRUPT 81fddd98) USBPORT!USBPORT_InterruptService (KINTERRUPT 82103008) USBPORT!USBPORT_InterruptService (KINTERRUPT 81ddd008) 82: 8236ddd4 Unknown_Module_f8451000!IdePortInterrupt (KINTERRUPT 8236dd98) 83: 81ffd044 portcls!CKsShellRequestor::`vector deleting destructor'+0x26 (KINTERRUPT 81ffd008) 92: 821dd784 serial!SerialCIsrSw (KINTERRUPT 821dd748) 93: 8220f704 i8042prt!I8042KeyboardInterruptService (KINTERRUPT 8220f6c8) 94: 820ce1fc NDIS!ndisMIsr (KINTERRUPT 820ce1c0) a3: 81e9e2cc i8042prt!I8042MouseInterruptService (KINTERRUPT 81e9e290) a4: 82082334 USBPORT!USBPORT_InterruptService (KINTERRUPT 820822f8) b1: 823cc044 ACPI!ACPIInterruptServiceRoutine (KINTERRUPT 823cc008) b4: 81dff2cc USBPORT!USBPORT_InterruptService (KINTERRUPT 81dff290) c1: 806ed984 hal!HalpBroadcastCallService d1: 806ecd34 hal!HalpClockInterrupt e1: 806edf0c hal!HalpIpiHandler e3: 806edc70 hal!HalpLocalApicErrorService fd: 806ee464 hal!HalpProfileInterrupt что-то я не могу понять, где здесь оно?