Обычно ошибки "проявляются" в виде исключений. Обычно в программу встраивается один из механизмов сохранения появляющихся ошибок в файл (лог-файл) для того, чтобы была возможность отправить эту информацию разработчикам для исправления. В лог может сохраняться информацию о возникшем исключении, стек вызов, список загруженных модулей, информация о системе и т.п. В Delphi наиболее известны EurekaLog, MadExcept и JclDebug (Project JEDI).
Но есть ошибки, которые не могут быть обработаны и сохранены - т.н. необработанные исключения, когда приложение вдруг показывает сообщение об ошибке, а при закрытии этого сообщение - выгружается из памяти. А может вообще тихо закрыться. В Windows в такой ситуации может сохранить дамп процесса перед его уничтожением (т.н. посмертный дамп, [1]).
Для анализа дампов можно использовать Visual Studio и Windbg (Debugging Tools for Windows). Лично я предпочитаю Windbg.
Область применения достаточно широкая: это анализ дампов упавших, зависших или усиленно нагружающих процессор приложений.
Только существует одна проблема - Windbg/VS не понимают формата отладочной информации для бинарников, скомпилированных Delphi (*.map, *.jdbg). И скорее всего никогда не научится их понимать :)
А без символов анализировать дампы не особо захватывающее занятие. Нельзя сказать, что совершенно невозможное, но все таки с символами оно как-то приятнее.
Но, как оказалось, есть и решение - Map2Dbg [2]. Map2Dbg - это небольшая утилита, которая конвертирует .map-файлы (Delphi, CBuilder) в формат, понимаемый Windbg и VS - Microsoft .dbg-файлы (codeview symbols) [3]. Конвертирование .jdbg в .dbg пока на стадии реализации. Да, формат .dbg уступает .pdb в плане детальности и информативности, но полученных таким образом файлов достаточно для получение более-менее читаемого и достоверного стека вызовов. Ну и можно посмотреть значение глобальных переменных.
Для примера возьмем дамп зависшего тестового приложения. После открытия дампа в Windbg видим, что в программе два потока: один ждет освобождения критической секции, а второй спит.
. 0 Id: ac0.dcc Suspend: 1 Teb: 7ffde000 Unfrozen ChildEBP RetAddr 0012f50c 7c90df5a ntdll!KiFastSystemCallRet 0012f510 7c91b24b ntdll!ZwWaitForSingleObject+0xc 0012f598 7c901046 ntdll!RtlpWaitForCriticalSection+0x132 0012f5a0 00425629 ntdll!RtlEnterCriticalSection+0x46 WARNING: Stack unwind information not available. Following frames may be wrong. 0012f5b4 00456d68 Project22+0x25629 0012f5bc 00456d5c Project22+0x56d68 0012f5c4 004381da Project22+0x56d5c 0012f708 0043bb7c Project22+0x381da 0012f748 00426f69 Project22+0x3bb7c 0012f774 0043bccc Project22+0x26f69 0012f8cc 0043bb7c Project22+0x3bccc 0012f90c 0044cc80 Project22+0x3bb7c 0012f934 0043b2a3 Project22+0x4cc80 0012f964 0041b802 Project22+0x3b2a3 0012f97c 7e418734 Project22+0x1b802 0012f9a8 7e418816 user32!InternalCallWinProc+0x28 0012fa10 7e42927b user32!UserCallWinProcCheckWow+0x150 0012fa4c 7e4292e3 user32!SendMessageWorker+0x4a5 0012fa6c 773f7354 user32!SendMessageW+0x7f 0012fa8c 773f7436 comctl32!Button_NotifyParent+0x3d 0012faa8 773f973b comctl32!Button_ReleaseCapture+0xd7 0012fb38 7e418734 comctl32!Button_WndProc+0x887 0012fb64 7e418816 user32!InternalCallWinProc+0x28 0012fbcc 7e42a013 user32!UserCallWinProcCheckWow+0x150 0012fbfc 7e42a998 user32!CallWindowProcAorW+0x98 0012fc1c 0043bc78 user32!CallWindowProcA+0x1b 0012fd9c 0043bb7c Project22+0x3bc78 0012fddc 00426f69 Project22+0x3bb7c 0012fe1c 0041b802 Project22+0x26f69 0012fe34 7e418734 Project22+0x1b802 0012fe60 7e418816 user32!InternalCallWinProc+0x28 0012fec8 7e4189cd user32!UserCallWinProcCheckWow+0x150 0012ff28 7e4196c7 user32!DispatchMessageWorker+0x306 0012ff38 004549fd user32!DispatchMessageA+0xf 0012ff54 00454a1f Project22+0x549fd 0012ff78 00454d14 Project22+0x54a1f 0012ffa8 0045876a Project22+0x54d14 0012ffc0 7c817077 Project22+0x5876a 0012fff0 00000000 kernel32!BaseProcessStart+0x23 1 Id: ac0.f88 Suspend: 1 Teb: 7ffdd000 Unfrozen ChildEBP RetAddr 00cbfef8 7c90d21a ntdll!KiFastSystemCallRet 00cbfefc 7c8023f1 ntdll!NtDelayExecution+0xc 00cbff54 7c802455 kernel32!SleepEx+0x61 00cbff64 00456ebd kernel32!Sleep+0xf WARNING: Stack unwind information not available. Following frames may be wrong. 00cbff70 0041a17f Project22+0x56ebd 00cbffa0 0040484e Project22+0x1a17f 00cbffb4 7c80b729 Project22+0x484e 00cbffec 00000000 kernel32!BaseThreadStart+0x37
К гадалке не ходи - критическая секция захвачена вторым потоком. Так что в приведенном дампе можно обойтись и без символов. Но это же просто пример - для демонстрации техники, так что я особо не извращался в создании дедлока :)
После загрузки символов, картина становится красочнее :)
. 0 Id: ac0.dcc Suspend: 1 Teb: 7ffde000 Unfrozen ChildEBP RetAddr 0012f50c 7c90df5a ntdll!KiFastSystemCallRet 0012f510 7c91b24b ntdll!ZwWaitForSingleObject+0xc 0012f598 7c901046 ntdll!RtlpWaitForCriticalSection+0x132 0012f5a0 00425629 ntdll!RtlEnterCriticalSection+0x46 0012f5b4 00456d68 Project22!SyncObjs.TCriticalSection.Acquire+0x9 0012f5bc 00456d5c Project22!Unit22.TForm22.Procedure1+0x8 0012f5c4 004381da Project22!Unit22.TForm22.Button2Click+0x8 0012f708 0043bb7c Project22!Controls.TControl.Click+0x6a 0012f748 00426f69 Project22!Controls.TWinControl.WndProc+0x500 0012f774 0043bccc Project22!StdCtrls.TButtonControl.WndProc+0x71 0012f8cc 0043bb7c Project22!Controls.DoControlMsg+0x28 0012f90c 0044cc80 Project22!Controls.TWinControl.WndProc+0x500 0012f934 0043b2a3 Project22!Forms.TCustomForm.WndProc+0x558 0012f964 0041b802 Project22!Controls.TWinControl.MainWndProc+0x2f 0012f97c 7e418734 Project22!Classes.StdWndProc+0x16 0012f9a8 7e418816 user32!InternalCallWinProc+0x28 0012fa10 7e42927b user32!UserCallWinProcCheckWow+0x150 0012fa4c 7e4292e3 user32!SendMessageWorker+0x4a5 0012fa6c 773f7354 user32!SendMessageW+0x7f 0012fa8c 773f7436 comctl32!Button_NotifyParent+0x3d 0012faa8 773f973b comctl32!Button_ReleaseCapture+0xd7 0012fb38 7e418734 comctl32!Button_WndProc+0x887 0012fb64 7e418816 user32!InternalCallWinProc+0x28 0012fbcc 7e42a013 user32!UserCallWinProcCheckWow+0x150 0012fbfc 7e42a998 user32!CallWindowProcAorW+0x98 0012fc1c 0043bc78 user32!CallWindowProcA+0x1b 0012fd9c 0043bb7c Project22!Controls.TWinControl.DefaultHandler+0xdc 0012fddc 00426f69 Project22!Controls.TWinControl.WndProc+0x500 0012fe1c 0041b802 Project22!StdCtrls.TButtonControl.WndProc+0x71 0012fe34 7e418734 Project22!Classes.StdWndProc+0x16 0012fe60 7e418816 user32!InternalCallWinProc+0x28 0012fec8 7e4189cd user32!UserCallWinProcCheckWow+0x150 0012ff28 7e4196c7 user32!DispatchMessageWorker+0x306 0012ff38 004549fd user32!DispatchMessageA+0xf 0012ff54 00454a1f Project22!Forms.TApplication.ProcessMessage+0x101 0012ff78 00454d14 Project22!Forms.TApplication.HandleMessage+0xf 0012ffa8 0045876a Project22!Forms.TApplication.Run+0xb8 0012ffc0 7c817077 Project22!Project22.Project22+0x4e 0012fff0 00000000 kernel32!BaseProcessStart+0x23 1 Id: ac0.f88 Suspend: 1 Teb: 7ffdd000 Unfrozen ChildEBP RetAddr 00cbfef8 7c90d21a ntdll!KiFastSystemCallRet 00cbfefc 7c8023f1 ntdll!NtDelayExecution+0xc 00cbff54 7c802455 kernel32!SleepEx+0x61 00cbff64 00456ebd kernel32!Sleep+0xf 00cbff70 0041a17f Project22!Unit22.TSomeThread.Execute+0x15 00cbffa0 0040484e Project22!Classes.ThreadProc+0x37 00cbffb4 7c80b729 Project22!System.ThreadWrapper+0x2a 00cbffec 00000000 kernel32!BaseThreadStart+0x37
Для эпизодического анализа достаточно полученные .dbg-файлы положить рядом с дампом (в случае живой отладки в Windbg - в каталоге с бинарниками). Ну а для более-менее регулярного использования лучше завести сервер символов.
И еще один пример - использование в Process Explorer. Стек вызовов спящего потока зависшего тестового приложения.
Ссылки
[1] Specifying the Debugger for Unhandled User Mode Exceptions
[2] Map2Dbg is a mall tool to convert a .map file to a .dbg file
[3] Description of the .PDB files and of the .DBG files
Комментариев нет:
Отправить комментарий