- ¹Ì´Ï ´ýÇÁ¶õ?
- ÁغñÇØ¾ßÇÒ °Íµé
- ¹Ì´Ï ´ýÇÁ ³²±â´Â ¹æ¹ý
- MiniDump.h
- MiniDump.cpp
- ¹Ì´Ï ´ýÇÁ ºÐ¼®
- ÀϹÝÀûÀÎ ½Ã³ª¸®¿À
- ¹Ì´Ï ´ýÇÁ¿¡¼ ÀÚÁÖ º¸´Â Á¤º¸ ÀÚµ¿À¸·Î »Ì¾Æ³»±â
- ´ýÇÁ ÆÄÀÏÀ» »ý¼ºÇÏ´Â µ¥ »ç¿ëÇÒ ¼ö ÀÖ´Â µµ±¸µé
- ¸µÅ©
1 ¹Ì´Ï ´ýÇÁ¶õ?
¹Ì´Ï ´ýÇÁ ÆÄÀÏÀº Å©·¡½ÃµÈ ¾ÖÇø®ÄÉÀ̼ǿ¡ ´ëÇÑ °¡Àå Áß¿äÇÑ Á¤º¸(½ºÅà Ʈ·¹À̽º, Èü Á¤º¸...)¸¸À» °¡Áö°í ÀÖ´Â ÆÄÀÏÀÌ´Ù. »ç¿ëÀÚÀÇ ÄÄÇ»ÅÍ¿¡¼ ¾ÖÇø®ÄÉÀ̼ÇÀÌ ´Ù¿îµÇ¸é¼ ¹Ì´Ï ´ýÇÁ¸¦ »ý¼ºÇϸé, »ç¿ëÀÚ´Â ±×°ÍÀ» °³¹ßÀÚ¿¡°Ô º¸³¾ ¼ö ÀÖ´Ù. ±×·¯¸é °³¹ßÀÚ´Â ±× ´ýÇÁ ÆÄÀÏÀ» ÀÌ¿ëÇØ ¹ö±×¸¦ Àâ´Â °ÍÀÌ´Ù.
2 ÁغñÇØ¾ßÇÒ °Íµé
- ¹öÀü 5.1.2600 ÀÌ»óÀÇ dbghelp.dll - ¹öÀüÀÌ ³·Àº DLL¿¡´Â ¹Ì´Ï ´ýÇÁ¸¦ À§Çؼ »ç¿ëÇÏ´Â MiniDumpWriteDump ÇÔ¼ö°¡ Á¸ÀçÇÏÁö ¾Ê±â ¶§¹®ÀÌ´Ù. À©µµ¿ìÁî 2000ÀÇ °æ¿ì, µðÆúÆ®·Î Á¸ÀçÇÏ´Â dbghelp.dllÀº ¹öÀüÀÌ ¿À·¡µÈ °ÍÀ̹ǷΠÁÖÀÇÇØ¾ßÇÑ´Ù. ¿©·¯ °¡Áö ¹®Á¦¸¦ ÇÇÇϱâ À§Çؼ, ½ÇÇà ÆÄÀÏÀÌ ÀÖ´Â µð·ºÅ丮¿¡ °°ÀÌ µÎ´Â °ÍÀ» ÃßõÇÑ´Ù.
- ÇØ´ç ¹öÀüÀÇ ¾ÖÇø®ÄÉÀÌ¼Ç ¹ÙÀ̳ʸ®¿Í ½Éº¼(PDB), OS ¹ÙÀ̳ʸ®¿Í ½Éº¼ - SymbolServer ÆäÀÌÁö¸¦ Âü°íÇϱ⠹ٶõ´Ù.
3 ¹Ì´Ï ´ýÇÁ ³²±â´Â ¹æ¹ý
¾Æ·¡¿¡ ÀÖ´Â MiniDump.h¿Í MiniDump.cpp µÎ ÆÄÀÏÀ» ÇÁ·ÎÁ§Æ®¿¡´Ù Áý¾î³ÖÀº ´ÙÀ½, ¸ÞÀÎ ·çÇÁ¸¦ ÃʱâÈÇϱâ ÀÌÀü¿¡ ´ÙÀ½ Äڵ带 Áý¾î³Ö¾îÁÖ¸é µÈ´Ù. dbghelp ¶óÀ̺귯¸® ¸µÅ© ÇØÁÖ´Â °Å ±î¸ÔÀ¸¸é ³¶ÆÐ.
#pragma comment(lib, "dbghelp")
...
// ¹Ì´Ï ´ýÇÁ ÃʱâÈ
cMiniDump::Install(cMiniDump::DUMP_LEVEL_LIGHT);
...
VisualCpp 8.0 ±âÁØÀ¸·Î Á¦ÀÛµÈ ¼Ò½º¶ó, ³·Àº ¹öÀü¿¡¼ ÄÄÆÄÀÏÇϰíÀÚ ÇÏ´Â °æ¿ì, printf ·ù ÇÔ¼öµé¿¡¼ ¿¡·¯°¡ ¹ß»ýÇÒ °ÍÀÌ´Ù. ifdef·Î °¨½Î´Ï±î, ¼Ò½º°¡ ³Ê¹« ÁöÀúºÐÇØÁ®¼, ÇÏÀ§ ȣȯ¼ºÀº Æ÷±âÇß´Ù. -_-
´ýÇÁ¸¦ ³²±æ ¶§, ÄݽºÅà Á¤º¸µµ ±â·ÏÇϵµ·Ï Çϰí Àִµ¥, ÀÌ´Â
¿©±â¿¡ ÀÖ´Â ¼Ò½º¸¦ ÀÌ¿ëÇÑ´Ù. °°ÀÌ Ã·ºÎÇÏ´Â °Íµµ ¿ô±â´Â ÀÏÀ̶ó¼ ifdef·Î µû·Î »©³ù´Ù. HAS_STACK_WALKER ¸ÅÅ©·Î ÁÖÀ§¸¦ »ìÆìº¸¸é µÉ °ÍÀÌ´Ù.
3.1 MiniDump.h
////////////////////////////////////////////////////////////////////////////////
/// \file MiniDump.h
/// \author excel96
/// \date 2003.11.18
////////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef _WINDOWS_
#include <windows.h>
#endif
////////////////////////////////////////////////////////////////////////////////
/// \class cMiniDump
/// \brief ¹Ì´Ï ´ýÇÁ¸¦ ½ÇÇàÇϱâ À§ÇÑ Å¬·¡½º. Ưº°È÷ ¾î¶² ´çÀ§¼ºÀÌ ÀÖ¾î¼ ¸¸µç
/// Ŭ·¡½º´Â ¾Æ´Ï°í, Á¤Àû º¯¼ö¿Í ÇÔ¼ö¸¦ °¡Áö°í ÀÖ±â À§ÇØ ¸¸µç ³×ÀÓ ½ºÆäÀ̽º
/// ¿ªÇÒ Å¬·¡½ºÀÌ´Ù.
///
/// ´ýÇÁÀÇ ÃʱâÈ´Â Install ÇÔ¼ö¸¦ ÅëÇØ ÀÌ·ç¾îÁø´Ù. ÇÁ·Î±×·¥ ½ÃÀÛ ºÎºÐ ¾Æ¹«
/// °÷¿¡¼³ª cMiniDump::Install(...) ÇÔ¼ö¸¦ È£ÃâÇØÁÖ¸é µÈ´Ù.
///
/// <pre>
/// int main()
/// {
/// ...
/// cMiniDump::Install(cMiniDump::DUMP_LEVEL_LIGHT);
/// ...
/// }
/// </pre>
///
/// GUI¸¦ »ç¿ëÇÒ ¼ö ÀÖ´Â ÇÁ·Î±×·¥ÀÇ °æ¿ì, »ç¿ëÀÚ¿¡°Ô ´ýÇÁ ÆÄÀÏ »ý¼º ¿©ºÎ¸¦ ¹¯´Â
/// °Íµµ ±¦Âú´Ù°í »ý°¢Çؼ, ´ëÈâ Äݹé ÇÔ¼ö¸¦ Çϳª Áý¾î ³Ö¾ú´Ù. Install ÇÔ¼ö¸¦
/// ÅëÇØ ´ëÈâ Äݹé ÇÔ¼ö¸¦ ¼³Á¤Çϸé, ´ýÇÁ »ý¼º½Ã À̸¦ È®ÀÎÇØ ¸ÕÀú ´ëÈâÀ»
/// ¶ç¿î´Ù. ´ëÈâÀÌ IDOK·Î ³¡³ª¸é, ´ýÇÁ ÆÄÀÏÀ» »ý¼ºÇϰí, ±×¿ÜÀÇ °ªÀ¸·Î ³¡³ª¸é
/// ´ýÇÁ ÆÄÀÏÀ» »ý¼ºÇÏÁö ¾Ê´Â´Ù. ±âº»ÀûÀÎ ´ëÈâ ÇÔ¼ö¸¦ ±¸ÇöÇÏÀÚ¸é ´ëÃæ ¾Æ·¡¿Í
/// °°À» °ÍÀÌ´Ù.
///
/// <pre>
/// BOOL CALLBACK CrashDialogProc(
/// HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM /*lParam*/)
/// {
/// RECT parent, dlg;
/// int x, y;
///
/// switch (iMessage)
/// {
/// case WM_INITDIALOG:
/// ::GetWindowRect(::GetForegroundWindow(), &parent);
/// ::GetWindowRect(hDlg, &dlg);
/// x = (parent.left + parent.right - dlg.right) / 2;
/// y = (parent.top + parent.bottom - dlg.bottom) / 2;
/// ::MoveWindow(hDlg, x, y, dlg.right, dlg.bottom, FALSE);
// ...
/// return TRUE;
/// case WM_COMMAND:
/// switch (LOWORD(wParam))
/// {
/// case IDOK: EndDialog(hDlg, IDOK); break;
/// case IDCANCEL: EndDialog(hDlg, IDCANCEL); break;
/// default: break;
/// }
/// return FALSE;
/// default:
/// break;
/// }
///
/// return FALSE;
/// }
/// </pre>
////////////////////////////////////////////////////////////////////////////////
class cMiniDump
{
public:
/// ´ýÇÁÇÒ µ¥ÀÌÅÍÀÇ ¼öÁØ
enum DumpLevel
{
DUMP_LEVEL_LIGHT, ///< MiniDumpNormalÀ» »ç¿ë
DUMP_LEVEL_MEDIUM, ///< MiniDumpWithDataSegs¸¦ »ç¿ë
DUMP_LEVEL_HEAVY ///< MiniDumpWithFullMemory¸¦ »ç¿ë
};
private:
static DumpLevel s_DumpLevel; ///< ´ýÇÁ ·¹º§.
static bool s_AddTimeStamp; ///< ³¯Â¥ ±â¹Ý ´ýÇÁ ÆÄÀÏ À̸§ »ç¿ë
static TCHAR s_AppName[_MAX_PATH]; ///< ´ýÇÁ ÆÄÀÏ À̸§
static TCHAR s_CallStack[8192]; ///< ÄݽºÅà ¹®ÀÚ¿
static TCHAR s_Modules[8192]; ///< ¸ðµâ ¹®ÀÚ¿
static LPCTSTR s_DialogTemplate; ///< ´ëÈâ ÅÛÇø´
static DLGPROC s_DialogProc; ///< ´ëÈâ ÇÁ·Î½ÃÁ®
public:
/// \brief ¹Ì´Ï ´ýÇÁ ±â´ÉÀ» ÃʱâÈÇÑ´Ù.
static void Install(DumpLevel dumpLevel, bool addTimestamp=true,
LPCTSTR dialogTemplate=NULL, DLGPROC dialogProc=NULL);
/// \brief ÄݽºÅà ¹®ÀÚ¿À» ¹ÝȯÇÑ´Ù.
static LPCTSTR GetCallStack() { return s_CallStack; }
/// \brief ¸ðµâ ¹®ÀÚ¿À» ¹ÝȯÇÑ´Ù.
static LPCTSTR GetModules() { return s_Modules; }
private:
/// \brief ¿¹¿Ü¿¡ ´ëÇÑ Á¤º¸¸¦ ¹Þ¾Æ¼, ¹Ì´Ï ´ýÇÁ ÆÄÀÏÀ» »ý¼ºÇÑ´Ù.
static LONG WINAPI WriteDump(PEXCEPTION_POINTERS exPtrs);
/// \brief »ý¼º ±ÝÁö
cMiniDump() {}
/// \brief º¹»ç »ý¼º ±ÝÁö
cMiniDump(const cMiniDump&) {}
/// \brief ´ëÀÔ ¿¬»ê ±ÝÁö
cMiniDump& operator = (const cMiniDump&) { return *this; }
};
3.2 MiniDump.cpp
////////////////////////////////////////////////////////////////////////////////
/// \file MiniDump.cpp
/// \author excel96
/// \date 2003.11.18
///
/// ´ýÇÁ ÆÄÀÏ ¿É¼Ç... from MSDN
///
/// - MiniDumpNormal
/// Include just the information necessary to capture stack traces for
/// all existing threads in a process.
///
/// - MiniDumpWithDataSegs
/// Include the data sections from all loaded modules. This results in
/// the inclusion of global variables, which can make the minidump file
/// significantly larger.
///
/// - MiniDumpWithFullMemory
/// Include all accessible memory in the process. The raw memory data is
/// included at the end, so that the Initial structures can be mapped
/// directly without the raw memory information. This option can result
/// in a very large file.
///
/// - MiniDumpWithHandleData
/// Include high-level information about the operating system handles
/// that are active when the minidump is made.
/// \n Windows Me/98/95: This value is not supported.
///
/// - MiniDumpFilterMemory
/// Stack and backing store memory written to the minidump file should be
/// filtered to remove all but the pointer values necessary to reconstruct
/// a stack trace. Typically, this removes any private information.
///
/// - MiniDumpScanMemory
/// Stack and backing store memory should be scanned for pointer
/// references to modules in the module list. If a module is referenced by
/// stack or backing store memory, the ModuleWriteFlags member of the
/// MINIDUMP_CALLBACK_OUTPUT structure is set to ModuleReferencedByMemory.
///
/// - MiniDumpWithUnloadedModules
/// Include information from the list of modules that were recently
/// unloaded, if this information is maintained by the operating system.
/// \n DbgHelp 5.1 and earlier: This value is not supported.
///
/// - MiniDumpWithIndirectlyReferencedMemory
/// Include pages with data referenced by locals or other stack memory.
/// This option can increase the size of the minidump file significantly.
/// \n DbgHelp 5.1 and earlier: This value is not supported.
///
/// - MiniDumpFilterModulePaths
/// Filter module paths for information such as user names or important
/// directories. This option may prevent the system from locating the
/// image file and should be used only in special situations.
/// \n DbgHelp 5.1 and earlier: This value is not supported.
///
/// - MiniDumpWithProcessThreadData
/// Include complete per-process and per-thread information from the
/// operating system.
/// \n DbgHelp 5.1 and earlier: This value is not supported.
///
/// - MiniDumpWithPrivateReadWriteMemory
/// Scan the virtual address space for other types of memory to be
/// included.
/// \n DbgHelp 5.1 and earlier: This value is not supported.
////////////////////////////////////////////////////////////////////////////////
#include "MiniDump.h"
#include <dbghelp.h>
#include <stdio.h>
#include <tchar.h>
#define HAS_STACK_WALKER 1
#ifdef HAS_STACK_WALKER
#include "StackWalker.h"
#endif
#ifndef Assert
#include <assert.h>
#define Assert assert
#define LogToFile (void)(0);
#endif
cMiniDump::DumpLevel cMiniDump::s_DumpLevel = cMiniDump::DUMP_LEVEL_LIGHT;
bool cMiniDump::s_AddTimeStamp = true;
TCHAR cMiniDump::s_AppName[_MAX_PATH] = {0,};
TCHAR cMiniDump::s_CallStack[8192] = {0,};
TCHAR cMiniDump::s_Modules[8192] = {0,};
LPCTSTR cMiniDump::s_DialogTemplate = NULL;
DLGPROC cMiniDump::s_DialogProc = NULL;
namespace
{
/// \brief ¿¹¿ÜÀÇ ¿øÀο¡ ´ëÇÑ ¹®ÀÚ¿À» ¹ÝȯÇÑ´Ù.
LPCTSTR GetFaultReason(PEXCEPTION_POINTERS exPtrs);
/// \brief »ç¿ëÀÚ Á¤º¸¸¦ ¹ÝȯÇÑ´Ù.
LPCTSTR GetUserInfo();
/// \brief À©µµ¿ìÁî ¹öÀüÀ» ¹ÝȯÇÑ´Ù.
LPCTSTR GetOSInfo();
/// \brief CPU Á¤º¸¸¦ ¹ÝȯÇÑ´Ù.
LPCTSTR GetCpuInfo();
/// \brief ¸Þ¸ð¸® Á¤º¸¸¦ ¹ÝȯÇÑ´Ù.
LPCTSTR GetMemoryInfo();
/// \brief À©µµ¿ìÁî ¹öÀüÀ» ¾Ë¾Æ³½´Ù.
bool GetWinVersion(LPTSTR pszVersion, int *nVersion, LPTSTR pszMajorMinorBuild);
/// \brief strrchr TCHAR ¹öÀü
TCHAR* lstrrchr(TCHAR* str, TCHAR ch);
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ¹Ì´Ï ´ýÇÁ ±â´ÉÀ» ÃʱâÈÇÑ´Ù.
/// \param dumpLevel ´ýÇÁ ·¹º§
/// \param addTimeStamp ´ýÇÁ ÆÄÀÏ À̸§¿¡´Ù°¡ ´ýÇÁ ÆÄÀÏÀÌ »ý¼ºµÈ ³¯Â¥¸¦
/// Áý¾î³Ö´Â°¡ÀÇ ¿©ºÎ.
/// \param dialogTemplate ´ëÈâ ÅÛÇø´
/// \param dialogProc ´ëÈâ ÇÁ·Î½ÃÁ®
////////////////////////////////////////////////////////////////////////////////
void cMiniDump::Install(
DumpLevel dumpLevel, bool addTimeStamp, LPCTSTR dialogTemplate, DLGPROC dialogProc)
{
Assert(s_AppName[0] == 0);
Assert(dumpLevel >= DUMP_LEVEL_LIGHT);
Assert(dumpLevel <= DUMP_LEVEL_HEAVY);
s_DumpLevel = dumpLevel;
s_AddTimeStamp = addTimeStamp;
s_DialogTemplate = dialogTemplate;
s_DialogProc = dialogProc;
// ¸ðµâ °æ·Î¸¦ ¾Ë¾Æ³½´Ù.
// C:\somewhere\something.exe
TCHAR szFileName[_MAX_PATH];
::GetModuleFileName(NULL, szFileName, _MAX_PATH);
// È®ÀåÀÚ¸¦ Á¦°ÅÇÑ ¸ðµâ °æ·Î¸¦ ÁغñÇØµÐ´Ù.
// C:\somewhere\something.exe -> C:\somewhere\something
TCHAR* dot = lstrrchr(szFileName, '.');
::lstrcpyn(s_AppName, szFileName, (int)(dot - szFileName + 1));
// ¿¹¿Ü ó¸® Çڵ鷯¸¦ ¼³Á¤ÇÑ´Ù.
::SetUnhandledExceptionFilter(WriteDump);
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ¿¹¿Ü¿¡ ´ëÇÑ Á¤º¸¸¦ ¹Þ¾Æ¼, ¹Ì´Ï ´ýÇÁ ÆÄÀÏÀ» »ý¼ºÇÑ´Ù.
///
/// SetUnhandledExceptionFilter() API¿¡ ÀÇÇØ¼ ¼³Á¤µÇ°í, ÇÁ·Î¼¼½º ³»ºÎ¿¡¼
/// Unhandled ExceptionÀÌ ¹ß»ýµÉ °æ¿ì, È£ÃâµÇ°Ô µÈ´Ù. ´Ü µð¹ö°Å°¡ ºÙ¾îÀÖ´Â
/// °æ¿ì, Unhandled Exception Filter´Â È£ÃâµÇÁö ¾Ê´Â´Ù. ÀÌ ¸»Àº ÀÌ ÇÔ¼ö
/// ³»ºÎ¸¦ µð¹ö±ëÇÒ ¼ö´Â ¾ø´Ù´Â ¸»ÀÌ´Ù. ÀÌ ÇÔ¼ö ³»ºÎ¸¦ µð¹ö±ëÇϱâ À§Çؼ´Â
/// ¸Þ½ÃÁö ¹Ú½º ¶Ç´Â ÆÄÀÏÀ» ÀÌ¿ëÇØ¾ßÇÑ´Ù.
///
/// \param exPtrs ¿¹¿Ü Á¤º¸
/// \return LONG ÀÌ ÇÔ¼ö¸¦ ½ÇÇàÇÏ°í ³ ´ÙÀ½, ÃëÇÒ Çൿ°ª. ÀÚ¼¼ÇÑ °ÍÀº SEH
/// ¹®¼¸¦ Âü°íÇϵµ·Ï.
////////////////////////////////////////////////////////////////////////////////
LONG WINAPI cMiniDump::WriteDump(PEXCEPTION_POINTERS exPtrs)
{
// based on dbghelp.h
typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(
HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);
#ifdef UNICODE
fwprintf_s(stderr,
L"=============================================\n"
L"unhandled excetpion triggerd! writing dump...\n"
L"=============================================\n"
);
#else
fprintf_s(stderr,
"=============================================\n"
"unhandled excetpion triggerd! writing dump...\n"
"=============================================\n"
);
#endif
#ifdef HAS_STACK_WALKER
// ¸ÕÀú ÄݽºÅðú ¸ðµâµéÀ» ¹®ÀÚ¿·Î ¸¸µç´Ù.
cStackWalker msw;
msw.ShowCallStack(GetCurrentThread(), exPtrs->ContextRecord);
::lstrcpyn(s_CallStack, msw.GetStackString(), _ARRAYSIZE(s_CallStack)-1);
::lstrcpyn(s_Modules, msw.GetModuleString(), _ARRAYSIZE(s_Modules)-1);
#endif
// ´ëÈâÀÌ ¼³Á¤µÇ¾î ÀÖ´Ù¸é º¸¿©ÁØ´Ù.
if (s_DialogTemplate != NULL && s_DialogProc != NULL)
{
if (DialogBox(NULL, s_DialogTemplate, HWND_DESKTOP, s_DialogProc) != IDOK)
return EXCEPTION_EXECUTE_HANDLER;
}
HMODULE hDLL = NULL;
TCHAR szDbgHelpPath[_MAX_PATH] = {0, };
TCHAR szDumpPath[MAX_PATH * 2] = {0,};
TCHAR szLogPath[MAX_PATH * 2] = {0,};
// ´ýÇÁ ÆÄÀÏ À̸§ += ½Ã°£ ¹®ÀÚ¿
::lstrcat(szDumpPath, s_AppName);
::lstrcat(szLogPath, s_AppName);
if (s_AddTimeStamp)
{
SYSTEMTIME t;
::GetLocalTime(&t);
TCHAR szTail[_MAX_PATH];
#ifdef UNICODE
swprintf(szTail, _ARRAYSIZE(szTail)-1,
L" %04d-%02d-%02d %02d-%02d-%02d",
t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);
#else
_snprintf_s(szTail, _ARRAYSIZE(szTail)-1, _TRUNCATE,
" %04d-%02d-%02d %02d-%02d-%02d",
t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);
#endif
::lstrcat(szDumpPath, szTail);
::lstrcat(szLogPath, szTail);
}
::lstrcat(szDumpPath, _T(".dmp"));
::lstrcat(szLogPath, _T(".log"));
// ¸ÕÀú ½ÇÇà ÆÄÀÏÀÌ ÀÖ´Â µð·ºÅ丮¿¡¼ DBGHELP.DLLÀ» ·ÎµåÇØ º»´Ù.
// Windows 2000 ÀÇ System32 µð·ºÅ丮¿¡ ÀÖ´Â DBGHELP.DLL ÆÄÀÏÀº ¹öÀüÀÌ
// ¿À·¡µÈ °ÍÀÏ ¼ö Àֱ⠶§¹®ÀÌ´Ù. (ÃÖ¼Ò 5.1.2600.0 ÀÌ»óÀ̾î¾ß ÇÑ´Ù.)
if (::GetModuleFileName(NULL, szDbgHelpPath, _MAX_PATH))
{
if (LPTSTR slash = ::lstrrchr(szDbgHelpPath, '\\'))
{
::lstrcpy(slash + 1, _T("DBGHELP.DLL"));
hDLL = ::LoadLibrary(szDbgHelpPath);
}
}
// ÇöÀç µð·ºÅ丮¿¡ ¾ø´Ù¸é, ¾Æ¹« ¹öÀüÀ̳ª ·ÎµåÇÑ´Ù.
if (hDLL == NULL) hDLL = ::LoadLibrary(_T("dbghelp.dll"));
// DBGHELP.DLLÀ» ãÀ» ¼ö ¾ø´Ù¸é ´õ ÀÌ»ó ÁøÇàÇÒ ¼ö ¾ø´Ù.
if (hDLL == NULL)
{
LogToFile(szLogPath, _T("dbghelp.dll not found"));
return EXCEPTION_CONTINUE_SEARCH;
}
// DLL ³»ºÎ¿¡¼ MiniDumpWriteDump API¸¦ ã´Â´Ù.
MINIDUMPWRITEDUMP pfnMiniDumpWriteDump =
(MINIDUMPWRITEDUMP)::GetProcAddress(hDLL, "MiniDumpWriteDump");
if (pfnMiniDumpWriteDump == NULL)
{
LogToFile(szLogPath, _T("dbghelp.dll too old"));
return EXCEPTION_CONTINUE_SEARCH;
}
// ÆÄÀÏÀ» »ý¼ºÇÑ´Ù.
HANDLE hFile = ::CreateFile(
szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
LogToFile(szLogPath, _T("failed to create dump file '%s' (error %d)"),
szDumpPath, ::GetLastError());
return EXCEPTION_CONTINUE_SEARCH;
}
MINIDUMP_EXCEPTION_INFORMATION ExParam;
ExParam.ThreadId = ::GetCurrentThreadId();
ExParam.ExceptionPointers = exPtrs;
ExParam.ClientPointers = FALSE;
MINIDUMP_TYPE dumptype = MiniDumpNormal;
switch (s_DumpLevel)
{
case DUMP_LEVEL_LIGHT: dumptype = MiniDumpNormal; break;
case DUMP_LEVEL_MEDIUM: dumptype = MiniDumpWithDataSegs; break;
case DUMP_LEVEL_HEAVY: dumptype = MiniDumpWithFullMemory; break;
}
// ´ýÇÁ ÆÄÀÏ »ý¼º °á°ú¸¦ ·Î±× ÆÄÀÏ¿¡´Ù ±â·ÏÇÑ´Ù.
if (pfnMiniDumpWriteDump(
::GetCurrentProcess(), ::GetCurrentProcessId(),
hFile, dumptype, &ExParam, NULL, NULL))
{
#ifdef UNICODE
FILE* log = NULL;
if (_wfopen_s(&log, szLogPath, _T("a")) == 0)
#else
FILE* log = NULL;
if (fopen_s(&log, szLogPath, "a") == 0)
#endif
{
fprintf(log,
"saved dump file to '%s'\n"
"\n<fault reason>\n%s"
"\n\n<user>\n%s"
"\n\n<os>\n%s"
"\n\n<cpu>\n%s"
"\n\n<memory>\n%s",
szDumpPath,
GetFaultReason(exPtrs),
GetUserInfo(),
GetOSInfo(),
GetCpuInfo(),
GetMemoryInfo()
);
#ifdef HAS_STACK_WALKER
fprintf(log, "\n\n<stack>\n%s\n", GetCallStack());
fprintf(log, "\n<modules>\n%s\n", GetModules());
#endif
fclose(log);
}
}
else
{
LogToFile(szLogPath, _T("failed to save dump file to '%s' (error %d)"),
szDumpPath, ::GetLastError());
Assert(false);
}
::CloseHandle(hFile);
return EXCEPTION_EXECUTE_HANDLER;
}
namespace
{
/// \brief ¿¹¿ÜÀÇ ¿øÀο¡ ´ëÇÑ ¹®ÀÚ¿À» ¹ÝȯÇÑ´Ù.
/// \param exPtrs ¿¹¿Ü ±¸Á¶Ã¼ Æ÷ÀÎÅÍ
/// \return LPCTSTR ¿øÀÎ ¹®ÀÚ¿
LPCTSTR GetFaultReason(PEXCEPTION_POINTERS exPtrs)
{
if (::IsBadReadPtr(exPtrs, sizeof(EXCEPTION_POINTERS)))
return _T("bad exception pointers");
// °£´ÜÇÑ ¿¡·¯ ÄÚµå¶ó¸é ±×³É º¯È¯ÇÒ ¼ö ÀÖ´Ù.
switch (exPtrs->ExceptionRecord->ExceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION: return _T("EXCEPTION_ACCESS_VIOLATION");
case EXCEPTION_DATATYPE_MISALIGNMENT: return _T("EXCEPTION_DATATYPE_MISALIGNMENT");
case EXCEPTION_BREAKPOINT: return _T("EXCEPTION_BREAKPOINT");
case EXCEPTION_SINGLE_STEP: return _T("EXCEPTION_SINGLE_STEP");
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return _T("EXCEPTION_ARRAY_BOUNDS_EXCEEDED");
case EXCEPTION_FLT_DENORMAL_OPERAND: return _T("EXCEPTION_FLT_DENORMAL_OPERAND");
case EXCEPTION_FLT_DIVIDE_BY_ZERO: return _T("EXCEPTION_FLT_DIVIDE_BY_ZERO");
case EXCEPTION_FLT_INEXACT_RESULT: return _T("EXCEPTION_FLT_INEXACT_RESULT");
case EXCEPTION_FLT_INVALID_OPERATION: return _T("EXCEPTION_FLT_INVALID_OPERATION");
case EXCEPTION_FLT_OVERFLOW: return _T("EXCEPTION_FLT_OVERFLOW");
case EXCEPTION_FLT_STACK_CHECK: return _T("EXCEPTION_FLT_STACK_CHECK");
case EXCEPTION_FLT_UNDERFLOW: return _T("EXCEPTION_FLT_UNDERFLOW");
case EXCEPTION_INT_DIVIDE_BY_ZERO: return _T("EXCEPTION_INT_DIVIDE_BY_ZERO");
case EXCEPTION_INT_OVERFLOW: return _T("EXCEPTION_INT_OVERFLOW");
case EXCEPTION_PRIV_INSTRUCTION: return _T("EXCEPTION_PRIV_INSTRUCTION");
case EXCEPTION_IN_PAGE_ERROR: return _T("EXCEPTION_IN_PAGE_ERROR");
case EXCEPTION_ILLEGAL_INSTRUCTION: return _T("EXCEPTION_ILLEGAL_INSTRUCTION");
case EXCEPTION_NONCONTINUABLE_EXCEPTION: return _T("EXCEPTION_NONCONTINUABLE_EXCEPTION");
case EXCEPTION_STACK_OVERFLOW: return _T("EXCEPTION_STACK_OVERFLOW");
case EXCEPTION_INVALID_DISPOSITION: return _T("EXCEPTION_INVALID_DISPOSITION");
case EXCEPTION_GUARD_PAGE: return _T("EXCEPTION_GUARD_PAGE");
case EXCEPTION_INVALID_HANDLE: return _T("EXCEPTION_INVALID_HANDLE");
//case EXCEPTION_POSSIBLE_DEADLOCK: return _T("EXCEPTION_POSSIBLE_DEADLOCK");
case CONTROL_C_EXIT: return _T("CONTROL_C_EXIT");
case 0xE06D7363: return _T("Microsoft C++ Exception");
default:
break;
}
// ¹º°¡ Á» ´õ º¹ÀâÇÑ ¿¡·¯¶ó¸é...
static TCHAR szFaultReason[2048];
::lstrcpy(szFaultReason, _T("Unknown"));
::FormatMessage(
FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS,
::GetModuleHandle(_T("ntdll.dll")),
exPtrs->ExceptionRecord->ExceptionCode,
0,
szFaultReason,
0,
NULL);
return szFaultReason;
}
/// \brief »ç¿ëÀÚ Á¤º¸¸¦ ¹ÝȯÇÑ´Ù.
/// \return LPCTSTR »ç¿ëÀÚ À̸§
LPCTSTR GetUserInfo()
{
static TCHAR szUserName[200] = {0,};
ZeroMemory(szUserName, sizeof(szUserName));
DWORD UserNameSize = _ARRAYSIZE(szUserName) - 1;
if (!::GetUserName(szUserName, &UserNameSize))
::lstrcpy(szUserName, _T("Unknown"));
return szUserName;
}
/// \brief À©µµ¿ìÁî ¹öÀüÀ» ¹ÝȯÇÑ´Ù.
/// \return LPCTSTR À©µµ¿ìÁî ¹öÀü ¹®ÀÚ¿
LPCTSTR GetOSInfo()
{
TCHAR szWinVer[50] = {0,};
TCHAR szMajorMinorBuild[50] = {0,};
int nWinVer = 0;
::GetWinVersion(szWinVer, &nWinVer, szMajorMinorBuild);
static TCHAR szOSInfo[512] = {0,};
#ifdef UNICODE
swprintf(szOSInfo, _ARRAYSIZE(szOSInfo)-1, L"%s (%s)",
szWinVer, szMajorMinorBuild);
#else
_snprintf_s(szOSInfo, _ARRAYSIZE(szOSInfo)-1, _TRUNCATE, "%s (%s)",
szWinVer, szMajorMinorBuild);
#endif
szOSInfo[_ARRAYSIZE(szOSInfo)-1] = 0;
return szOSInfo;
}
/// \brief CPU Á¤º¸¸¦ ¹ÝȯÇÑ´Ù.
/// \return LPCTSTR CPU Á¤º¸ ¹®ÀÚ¿
LPCTSTR GetCpuInfo()
{
// CPU Á¤º¸ ±â·Ï
SYSTEM_INFO SystemInfo;
GetSystemInfo(&SystemInfo);
static TCHAR szCpuInfo[512] = {0,};
#ifdef UNICODE
swprintf(szCpuInfo, _ARRAYSIZE(szCpuInfo)-1,
L"%d processor(s), type %d",
SystemInfo.dwNumberOfProcessors, SystemInfo.dwProcessorType);
#else
_snprintf_s(szCpuInfo, _ARRAYSIZE(szCpuInfo)-1, _TRUNCATE,
"%d processor(s), type %d",
SystemInfo.dwNumberOfProcessors, SystemInfo.dwProcessorType);
#endif
return szCpuInfo;
}
/// \brief ¸Þ¸ð¸® Á¤º¸¸¦ ¹ÝȯÇÑ´Ù.
/// \return LPCTSTR ¸Þ¸ð¸® Á¤º¸ ¹®ÀÚ¿
LPCTSTR GetMemoryInfo()
{
static const int ONE_K = 1024;
static const int ONE_M = ONE_K * ONE_K;
static const int ONE_G = ONE_K * ONE_K * ONE_K;
MEMORYSTATUS MemInfo;
MemInfo.dwLength = sizeof(MemInfo);
GlobalMemoryStatus(&MemInfo);
static TCHAR szMemoryInfo[2048] = {0,};
#ifdef UNICODE
swprintf(szMemoryInfo, _ARRAYSIZE(szMemoryInfo)-1,
L"%d%% of memory in use.\n"
L"%d MB physical memory.\n"
L"%d MB physical memory free.\n"
L"%d MB paging file.\n"
L"%d MB paging file free.\n"
L"%d MB user address space.\n"
L"%d MB user address space free.",
MemInfo.dwMemoryLoad,
(MemInfo.dwTotalPhys + ONE_M - 1) / ONE_M,
(MemInfo.dwAvailPhys + ONE_M - 1) / ONE_M,
(MemInfo.dwTotalPageFile + ONE_M - 1) / ONE_M,
(MemInfo.dwAvailPageFile + ONE_M - 1) / ONE_M,
(MemInfo.dwTotalVirtual + ONE_M - 1) / ONE_M,
(MemInfo.dwAvailVirtual + ONE_M - 1) / ONE_M);
#else
_snprintf_s(szMemoryInfo, _ARRAYSIZE(szMemoryInfo)-1, _TRUNCATE,
"%d%% of memory in use.\n"
"%d MB physical memory.\n"
"%d MB physical memory free.\n"
"%d MB paging file.\n"
"%d MB paging file free.\n"
"%d MB user address space.\n"
"%d MB user address space free.",
MemInfo.dwMemoryLoad,
(MemInfo.dwTotalPhys + ONE_M - 1) / ONE_M,
(MemInfo.dwAvailPhys + ONE_M - 1) / ONE_M,
(MemInfo.dwTotalPageFile + ONE_M - 1) / ONE_M,
(MemInfo.dwAvailPageFile + ONE_M - 1) / ONE_M,
(MemInfo.dwTotalVirtual + ONE_M - 1) / ONE_M,
(MemInfo.dwAvailVirtual + ONE_M - 1) / ONE_M);
#endif
return szMemoryInfo;
}
/// \brief À©µµ¿ìÁî ¹öÀüÀ» ¾Ë¾Æ³½´Ù.
///
/// This table has been assembled from Usenet postings, personal observations,
/// and reading other people's code. Please feel free to add to it or correct
/// it.
///
/// <pre>
/// dwPlatFormID dwMajorVersion dwMinorVersion dwBuildNumber
/// 95 1 4 0 950
/// 95 SP1 1 4 0 >950 && <=1080
/// 95 OSR2 1 4 <10 >1080
/// 98 1 4 10 1998
/// 98 SP1 1 4 10 >1998 && <2183
/// 98 SE 1 4 10 >=2183
/// ME 1 4 90 3000
///
/// NT 3.51 2 3 51
/// NT 4 2 4 0 1381
/// 2000 2 5 0 2195
/// XP 2 5 1 2600
/// 2003 Server 2 5 2 3790
///
/// CE 3
/// </pre>
///
/// \param pszVersion ¹öÀü ¹®ÀÚ¿À» Áý¾î³ÖÀ» Æ÷ÀÎÅÍ
/// \param nVersion ¹öÀü ¼ýÀÚ°ªÀ» Áý¾î³ÖÀ» Æ÷ÀÎÅÍ
/// \param pszMajorMinorBuild ºôµå ¹®ÀÚ¿À» Áý¾î³ÖÀ» Æ÷ÀÎÅÍ
/// \return bool ¹«»çÈ÷ ½ÇÇàÇÑ °æ¿ì¿¡´Â true, ¹º°¡ ¿¡·¯°¡ »ý±ä °æ¿ì¿¡´Â false
bool GetWinVersion(LPTSTR pszVersion, int *nVersion, LPTSTR pszMajorMinorBuild)
{
// from winbase.h
#ifndef VER_PLATFORM_WIN32s
#define VER_PLATFORM_WIN32s 0
#endif
#ifndef VER_PLATFORM_WIN32_WINDOWS
#define VER_PLATFORM_WIN32_WINDOWS 1
#endif
#ifndef VER_PLATFORM_WIN32_NT
#define VER_PLATFORM_WIN32_NT 2
#endif
#ifndef VER_PLATFORM_WIN32_CE
#define VER_PLATFORM_WIN32_CE 3
#endif
static LPCTSTR WUNKNOWNSTR = _T("Unknown Windows Version");
static LPCTSTR W95STR = _T("Windows 95");
static LPCTSTR W95SP1STR = _T("Windows 95 SP1");
static LPCTSTR W95OSR2STR = _T("Windows 95 OSR2");
static LPCTSTR W98STR = _T("Windows 98");
static LPCTSTR W98SP1STR = _T("Windows 98 SP1");
static LPCTSTR W98SESTR = _T("Windows 98 SE");
static LPCTSTR WMESTR = _T("Windows ME");
static LPCTSTR WNT351STR = _T("Windows NT 3.51");
static LPCTSTR WNT4STR = _T("Windows NT 4");
static LPCTSTR W2KSTR = _T("Windows 2000");
static LPCTSTR WXPSTR = _T("Windows XP");
static LPCTSTR W2003SERVERSTR = _T("Windows 2003 Server");
static LPCTSTR WCESTR = _T("Windows CE");
static const int WUNKNOWN = 0;
static const int W9XFIRST = 1;
static const int W95 = 1;
static const int W95SP1 = 2;
static const int W95OSR2 = 3;
static const int W98 = 4;
static const int W98SP1 = 5;
static const int W98SE = 6;
static const int WME = 7;
static const int W9XLAST = 99;
static const int WNTFIRST = 101;
static const int WNT351 = 101;
static const int WNT4 = 102;
static const int W2K = 103;
static const int WXP = 104;
static const int W2003SERVER = 105;
static const int WNTLAST = 199;
static const int WCEFIRST = 201;
static const int WCE = 201;
static const int WCELAST = 299;
if (!pszVersion || !nVersion || !pszMajorMinorBuild) return false;
::lstrcpy(pszVersion, WUNKNOWNSTR);
*nVersion = WUNKNOWN;
OSVERSIONINFO osinfo;
osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (!GetVersionEx(&osinfo)) return false;
DWORD dwPlatformId = osinfo.dwPlatformId;
DWORD dwMinorVersion = osinfo.dwMinorVersion;
DWORD dwMajorVersion = osinfo.dwMajorVersion;
DWORD dwBuildNumber = osinfo.dwBuildNumber & 0xFFFF; // Win 95 needs this
TCHAR buf[50] = {0, };
#ifdef UNICODE
swprintf(buf, _ARRAYSIZE(buf), L"%u.%u.%u",
dwMajorVersion, dwMinorVersion, dwBuildNumber);
#else
_snprintf_s(buf, _ARRAYSIZE(buf), _TRUNCATE, "%u.%u.%u",
dwMajorVersion, dwMinorVersion, dwBuildNumber);
#endif
::lstrcpy(pszMajorMinorBuild, buf);
if ((dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) && (dwMajorVersion == 4))
{
if ((dwMinorVersion < 10) && (dwBuildNumber == 950))
{
::lstrcpy(pszVersion, W95STR);
*nVersion = W95;
}
else if ((dwMinorVersion < 10) &&
((dwBuildNumber > 950) && (dwBuildNumber <= 1080)))
{
::lstrcpy(pszVersion, W95SP1STR);
*nVersion = W95SP1;
}
else if ((dwMinorVersion < 10) && (dwBuildNumber > 1080))
{
::lstrcpy(pszVersion, W95OSR2STR);
*nVersion = W95OSR2;
}
else if ((dwMinorVersion == 10) && (dwBuildNumber == 1998))
{
::lstrcpy(pszVersion, W98STR);
*nVersion = W98;
}
else if ((dwMinorVersion == 10) &&
((dwBuildNumber > 1998) && (dwBuildNumber < 2183)))
{
::lstrcpy(pszVersion, W98SP1STR);
*nVersion = W98SP1;
}
else if ((dwMinorVersion == 10) && (dwBuildNumber >= 2183))
{
::lstrcpy(pszVersion, W98SESTR);
*nVersion = W98SE;
}
else if (dwMinorVersion == 90)
{
::lstrcpy(pszVersion, WMESTR);
*nVersion = WME;
}
}
else if (dwPlatformId == VER_PLATFORM_WIN32_NT)
{
if ((dwMajorVersion == 3) && (dwMinorVersion == 51))
{
::lstrcpy(pszVersion, WNT351STR);
*nVersion = WNT351;
}
else if ((dwMajorVersion == 4) && (dwMinorVersion == 0))
{
::lstrcpy(pszVersion, WNT4STR);
*nVersion = WNT4;
}
else if ((dwMajorVersion == 5) && (dwMinorVersion == 0))
{
::lstrcpy(pszVersion, W2KSTR);
*nVersion = W2K;
}
else if ((dwMajorVersion == 5) && (dwMinorVersion == 1))
{
::lstrcpy(pszVersion, WXPSTR);
*nVersion = WXP;
}
else if ((dwMajorVersion == 5) && (dwMinorVersion == 2))
{
::lstrcpy(pszVersion, W2003SERVERSTR);
*nVersion = W2003SERVER;
}
}
else if (dwPlatformId == VER_PLATFORM_WIN32_CE)
{
::lstrcpy(pszVersion, WCESTR);
*nVersion = WCE;
}
return true;
#undef VER_PLATFORM_WIN32s
#undef VER_PLATFORM_WIN32_WINDOWS
#undef VER_PLATFORM_WIN32_NT
#undef VER_PLATFORM_WIN32_CE
}
/// \brief strrchr TCHAR ¹öÀü
/// \param str °Ë»öÇÒ ¹®ÀÚ¿
/// \param ch ã°íÀÚ ÇÏ´Â ±ÛÀÚ
/// \return TCHAR* ÁÖ¾îÁø ±ÛÀÚ¸¦ ãÀº °æ¿ì ÇØ´ç À§Ä¡ Æ÷ÀÎÅ͸¦ ¹ÝȯÇϰí,
/// ãÁö ¸øÇÑ °æ¿ì¿¡´Â NULLÀ» ¹ÝȯÇÑ´Ù.
TCHAR* lstrrchr(TCHAR* str, TCHAR ch)
{
TCHAR* start = str;
while (*str++) ;
while (--str != start && *str != ch) ;
return *str == ch ? str : NULL;
}
}
4 ¹Ì´Ï ´ýÇÁ ºÐ¼®
4.1 ÀϹÝÀûÀÎ ½Ã³ª¸®¿À
ÀÏ´Ü À¯ÀúÀÇ ÄÄÇ»ÅÍ¿¡¼ ¹» ¹ÞÀ»Áö¸¦ Á¤ÇؾßÇÑ´Ù. Å©·¡½Ã ·Î±× ÆÄÀÏ(½ºÅà ¿öÄ¿ µîÀ» ÀÌ¿ëÇØ ÇÁ·Î±×·¡¸Ó°¡ ¸¸µå´Â ·Î±×)¸¸ ¹Þ±â¸¦ ¿øÇÑ´Ù¸é PDB¸¦ ¹èÆ÷ÇØ¾ß ÇÑ´Ù. ´Ü À̶§ Private SymbolÀ» ¹èÆ÷ÇÏ¸é °ï¶õÇϹǷÎ, WinDbg¿¡ µþ·Á¿À´Â pdbcopy¸¦ ÀÌ¿ëÇØ Public SymbolÀ» ¸¸µé¾î ¹èÆ÷ÇÏÀÚ.
pdbcopy PrivateSymbolName.pdb PublicSymbolName.pdb -p
±×°Ô ¾Æ´Ï¶ó ±×³É ´ýÇÁ ÆÄÀÏÀ» ¹Þ±â¸¦ ¿øÇÑ´Ù¸é PDB ÆÄÀÏÀ» ¹èÆ÷ÇÒ ÇÊ¿ä´Â ¾ø´Ù. »ç½Ç MiniDumpNormal Á¤µµÀÇ ¿É¼ÇÀ¸·Î ´ýÇÁ¸¦ »ý¼ºÇÏ¸é ´ýÇÁ ÆÄÀÏ Å©±â°¡ ±×¸® Å©Áö ¾Ê±â ¶§¹®¿¡, ´ýÇÁ ÆÄÀÏÀ» ¹Þ´Â °Ô ³´´Ù.
À¯Àú·ÎºÎÅÍ ´ýÇÁ ÆÄÀÏÀ» ¹Þ¾Ò´Ù¸é, ±× ´ýÇÁ ÆÄÀÏ¿¡ ÇØ´çÇÏ´Â PDB¿Í EXE¸¦ ã´Â´Ù. ¿ä°Ç ½Éº¼ ½ºÅä¾î¸¦ ÀÌ¿ëÇÏ¸é ±×³ª¸¶ ÀÛ¾÷ÀÌ Á» ½¬¿öÁú °Í °°±â´Â Çѵ¥, ¾ÆÁ÷±îÁö´Â ÇØº¸Áú ¾Ê¾Æ¼ Àß ¸ð¸£°Ú´Ù. _NT_SYMBOL_PATH ¼³Á¤°ú WinDbg ¼³Ä¡´Â Çʼö´Ù. 2008¿¡¼´Â Á» ³ª¾ÆÁ³´ÂÁö ¸ð¸£°Ú´Âµ¥, 2005 VC µð¹ö°Å´Â WinDbgº¸´Ù ±â´ÉÀÌ µþ¸°´Ù. ¹¹ ¿Ø¸¸ÇÏ¸é ±×³É VC »ç¿ëÇØµµ µÇ±â´Â Çϴµ¥...
½ÇÇà ÆÄÀÏ, PDB, DMP ÆÄÀÏÀ» ¸ðµÎ °°Àº °æ·Î¿¡´Ù Áý¾î³Ö°í ±× µð·ºÅ丮·Î °¡¼ ¾Æ·¡¿Í °°Àº ¸í·É¾î¸¦ ÀÔ·ÂÇÑ´Ù.
windbg -y . -i . DumpFileName.dmp
¿ø·¡ ¸í·É¾î´Â ÀÌ·± ´À³¦ÀÌ´Ù.
windbg -y SymbolPath -i ImagePath -z DumpFileName
º¸´Ù½ÃÇÇ EXE, PDB, DMP ÆÄÀÏÀ» ¸ðµÎ °°Àº °æ·Î¿¡ Áý¾î³Ö¾îµÎ¾ú±â ¶§¹®¿¡ "." °æ·Î¸¦ ÀÔ·ÂÇÑ °ÍÀÌ´Ù.
WinDbg°¡ ¶ß¸é .reload /i /f ¸í·É¾î¸¦ ÀÔ·ÂÇÑ´Ù. ½Éº¼ ·ÎµùÇ϶ó´Â ¸í·ÉÀÌ´Ù. º° ¹®Á¦¾øÀÌ ½Éº¼ ·ÎµùÀÌ ³¡³ª¸é .ecxr ¸í·É¾î¸¦ ÀÔ·ÂÇÑ´Ù. ±×´ÙÀ½ ÄݽºÅÃ(ALT+6)À» º¸¸é ´Ù¿îµÈ À§Ä¡¸¦ ¾Ë ¼ö ÀÖ´Ù. ȤÀº !analyze -v ¸í·É¾î¸¦ ÀÌ¿ëÇØµµ µÈ´Ù.
EXE ÆÄÀÏÀÇ °æ·Î°¡ ½ÇÁ¦ À¯ÀúÀÇ ÄÄÇ»ÅÍ¿¡¼ÀÇ À§Ä¡¿Í ´Ù¸£¸é ½Éº¼ ·ÎµùÀÌ Àß µÇÁö ¾Ê´Â´Ù. ¿¹¸¦ µé¾î À¯Àú°¡ ÇÁ·Î±×·¥À» C:\XXX\ µð·ºÅ丮¿¡´Ù ¼³Ä¡Çß´Ù¸é ÇÁ·Î±×·¡¸ÓÀÇ ÄÄÇ»ÅÍ¿¡¼µµ ±× °æ·Î¿Í ¶È°°Àº À§Ä¡¿¡´Ù EXE, PDB, DMP ÆÄÀÏÀ» º¹»çÇÑ ´ÙÀ½ µð¹ö±ëÀ» ÇØ¾ßÇÑ´Ù´Â À̾߱â´Ù. ÀÌÀ¯°¡ ¹»±î?
4.2 ¹Ì´Ï ´ýÇÁ¿¡¼ ÀÚÁÖ º¸´Â Á¤º¸ ÀÚµ¿À¸·Î »Ì¾Æ³»±â
$$
$$ MiniDmp2Txt: Dump information from minidump into log
$$
.logopen /d /u
.echo "command> ||"
||
.echo "command> vertarget"
vertarget
.echo "command> r (before analysis)"
r
.echo "command> kv (before analysis)"
kv 100
.echo "command> !analyze -v"
!analyze -v
.echo "command> r"
r
.echo "command> kv"
kv 100
.echo "command> ub eip"
ub eip
.echo "command> u eip"
u eip
.echo "command> uf eip"
uf eip
.echo "command> lmv"
lmv
.echo "command> !sysinfo cpuinfo"
!sysinfo cpuinfo
.echo "command> !sysinfo cpuspeed"
!sysinfo cpuspeed
.echo "command> !sysinfo cpumicrocode"
!sysinfo cpumicrocode
.echo "command> !sysinfo gbl"
!sysinfo gbl
.echo "command> !sysinfo machineid"
!sysinfo machineid
.echo "command> !sysinfo registers"
!sysinfo registers
.echo "command> !sysinfo smbios -v"
!sysinfo smbios -v
.logclose
$$
$$ MiniDmp2Txt: End of File
$$
ÀÌ ÆÄÀÏÀ» C:\Scripts\MiniDmp2Txt.txt¶ó´Â À̸§À¸·Î ÀúÀåÇß´Ù°í ÇÏÀÚ. ±× ´ÙÀ½ WinDbg·Î Å©·¡½Ã ´ýÇÁ¸¦ ¿¸é¼ À§¿¡¼ ÀÛ¼ºÇÑ ½ºÅ©¸³Æ®¸¦ È£ÃâÇÑ´Ù.
windbg -y "SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols;." -z "DumpFileName.dmp" -c "$$><C:\Scripts\MiniDmp2Txt.txt;q" -Q -QS -QY -QSY
±×·¯¸é WinDbg°¡ ½ÇÇàµÇ¸é¼ ½ºÅ©¸³Æ® ¾È¿¡ ÀÖ´Â ¸í·ÉÀ» Âß ½ÇÇàÇÏ¸é¼ ·Î±× ÆÄÀÏÀ» ¸¸µé°Ô µÈ´Ù. -y ¿É¼ÇÀº ½Éº¼ ÆÐ½º¸¦ ÁöÁ¤ÇÏ´Â ¿É¼ÇÀ¸·Î¼ _NT_SYMBOL_PATH °ªÀÌ Àß ¼³Á¤µÇ¾îÀÖ´Ù¸é »ý·«Çصµ µÈ´Ù.
5 ´ýÇÁ ÆÄÀÏÀ» »ý¼ºÇÏ´Â µ¥ »ç¿ëÇÒ ¼ö ÀÖ´Â µµ±¸µé
- DrWatson
´ýÇÁ ÆÄÀÏ »ý¼ºÀ» À§ÇÑ ±âº» À¯Æ¿¸®Æ¼.
- AdPlus
´ýÇÁ ÆÄÀÏ »ý¼ºÀ» À§ÇÑ VB ½ºÅ©¸³Æ®.
- WinDbg
µð¹ö°Å¸¦ ºÙÀÎ ´ÙÀ½, ¸Þ´º¸¦ ÅëÇØ ´ýÇÁ ÆÄÀÏÀ» »ý¼ºÇÒ ¼ö ÀÖ´Ù. µð¹ö±ëÀ» ÁßÁöÇÏ¸é¼ ÇÁ·Î¼¼½º°¡ Á¾·áµÇ¹Ç·Î ÀÚÁÖ »ç¿ëÇÏÁö ¾Ê´Â °ÍÀÌ ÁÁ´Ù. AdPlus¸¦ ÀÌ¿ëÇ϶ó.
- userdump.exe
OEM ¼Æ÷Æ® Åø¿¡ Æ÷ÇԵǾî ÀÖ´Â µµ±¸·Î¼, ÇÑ ÇÁ·Î¼¼½ºÀÇ Ç® ´ýÇÁ ÆÄÀÏÀ» »ý¼ºÇÏ´Â µ¥ »ç¿ëÇÒ ¼ö ÀÖ´Ù. Á» ´õ ÀÚ¼¼ÇÑ °ÍÀº
¿©±â¸¦ Âü°íÇϽöó.
6 ¸µÅ©
SeriousMoin v1 (koMoinMoin 1.0a4 Modified)