성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Roll A Lisp In C - Reading ; https...
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C/C++ Native 스레드 콜 스택 덤프를 얻는 공개 라이브러리</h1> <p> 오호... UnityBuild 소스 코드를 보면서 새로운 것을 알게 되는군요. ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C/C++ 프로젝트 빌드 속도 개선 - UnityBuild를 아세요? ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/1250'>http://www.sysnet.pe.kr/2/0/1250</a> </pre> <br /> 아래의 사이트에 가서 "checkout-scripts.zip" 파일을 다운로드 하고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > earlgrey - Providing the fundamental of the online game server. ; <a target='tab' href='http://code.google.com/p/earlgrey/downloads/list'>http://code.google.com/p/earlgrey/downloads/list</a> </pre> <br /> 압축을 해제한 후, 아래와 같이 실행하면 UnityBuild 관련 소스 코드를 다운로드 받을 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > MSBuild_Win32.bat checkout-engine.xml </pre> <br /> svn.exe를 설치하지 않은 분들은 다음과 같은 오류가 발생할 텐데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > D:\unitybuilder\checkout-scripts\checkout-scripts><span style='color: blue; font-weight: bold'>MSBuild_Win32.bat checkout-engine.xml</span> The system cannot find the path specified. Microsoft (R) Build Engine Version 3.5.30729.5420 [Microsoft .NET Framework, Version 2.0.50727.5448] Copyright (C) Microsoft Corporation 2007. All rights reserved. Build started 2012-02-26 ?? 7:57:29. Project "D:\unitybuilder\checkout-scripts\checkout-scripts\checkout-engine.xml" on node 0 (default targets). <span style='color: blue; font-weight: bold'>'svn.exe' is not recognized as an internal or external command, operable program or batch file.</span> D:\unitybuilder\checkout-scripts\checkout-scripts\checkout-engine.xml(50,2): error MSB3073: The command "svn.exe checkout https://earlgrey.googlecode.com/svn "earlgrey-engine" --depth empty" exited with code 9009. Done Building Project "D:\unitybuilder\checkout-scripts\checkout-scripts\checkout-engine.xml" (default targets) -- FAILED. </pre> <br /> svn 설치를 위해 다음의 사이트를 방문합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > subversion ; <a target='tab' href='http://subversion.tigris.org/servlets/ProjectDocumentList'>http://subversion.tigris.org/servlets/ProjectDocumentList</a> </pre> <br /> 제 경우에는 위의 사이트에서 1.6.x 버전 폴더의 <a target='tab' href='http://subversion.tigris.org/files/documents/15/47914/svn-win32-1.6.6.zip'>svn-win32-1.6.6.zip</a> 파일을 다운로드 받았습니다.<br /> <br /> 자, 이제 MSBuild_Win32.bat 파일에 svn.exe의 경로를 "SET PATH"로 잡아주고 실행하면, 소스 코드를 다운로드 받게 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > @echo off <span style='color: blue; font-weight: bold'>PATH=%PATH%;E:\svn-win32-1.6.6\bin</span> SETLOCAL call "%VS90COMNTOOLS%\..\..\VC\vcvarsall.bat" x86 call "C:\WINDOWS\Microsoft.NET\Framework\v3.5\msbuild.exe" %* SET ERR_LEVEL=%errorlevel% exit /b %ERR_LEVEL% </pre> <br /> <hr style='width: 50%' /><br /> <br /> 재미있게도, UnityBuild 압축 해제를 하면 다음과 같은 프로젝트 경로를 볼 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > \checkout-scripts\checkout-scripts\earlgrey-engine\trunk\vendor\StackWalker_2009-11-01\StackWalker </pre> <br /> 정적 라이브러리 프로젝트로 되어 있는데, main 함수를 포함한 main.cpp 파일이 함께 있으므로 다음과 같이 프로젝트 속성을 바꿔주고,<br /> <br /> <img alt='native_call_stack_1.png' src='/SysWebRes/bbs/native_call_stack_1.png' /><br /> <br /> 이어서, Linker / System에서 "SubSystem" 설정을 "Console (/SUBSYSTEM:CONSOLE)"로 변경해 준 다음, main.cpp 파일에 대해서 "Excluded From Build" 설정을 "No"로 변경해 주면 일반 콘솔 프로그램처럼 실행해 볼 수 있습니다.<br /> <br /> main.cpp 파일에서는 자기 자신에 대해 직접 call stack을 뜨는 것을 테스트 하고 있는데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > int _tmain(int argc, _TCHAR* argv[]) { StackWalkTest(); ...[생략]... return 0; } void Func5() { <span style='color: blue; font-weight: bold'> StackWalkerToConsole sw; sw.ShowCallstack();</span> } void Func4() { Func5(); } void Func3() { Func4(); } void Func2() { Func3(); } void Func1() { Func2(); } void StackWalkTest() { Func1(); } </pre> <br /> 보시는 것처럼, 사용 방법이 매우 간단합니다. StackWalkerToConsole 클래스를 생성하고 ShowCallstack을 부르는 것으로 현재 실행 중인 스레드의 콜 스택을 얻을 수 있습니다.<br /> <br /> 일단, 제가 실행해 보니 다음과 같이 출력이 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > D:\StackWalker\Win32\Debug>StackWalker_VC10.exe SymInit: Symbol-SearchPath: '.;D:\StackWalker\Win32\Debug;D:\StackWalker\Win32\Debug;C:\Windows;C:\Windows\system32;SRV*C:\websymbols*http://msdl.microsoft.com/download/symbols;', symOptions: 530, UserName: 'SeongTae Jeong' OS-Version: 6.1.7601 (Service Pack 1) 0x100-0x1 D:\Settings\desktop\native_callstack\StackWalker\Win32\Debug\StackWalker_VC10.exe:StackWalker_VC10.exe (008B0000), size: 45056 (result: 0), SymType: '-nosymbols-', PDB: 'D:\Settings\desktop\native_callstack\StackWalker\Win32\Debug\StackWalker_VC10.exe' C:\Windows\SysWOW64\ntdll.dll:ntdll.dll (77830000), size: 1572864 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\SysWOW64\ntdll.dll', fileVersion: 6.1.7601.17725 C:\Windows\syswow64\kernel32.dll:kernel32.dll (74F70000), size: 1114112 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\syswow64\kernel32.dll', fileVersion: 6.1.7601.17651 C:\Windows\syswow64\KERNELBASE.dll:KERNELBASE.dll (76C10000), size: 286720 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\syswow64\KERNELBASE.dll', fileVersion: 6.1.7601.17651 C:\Windows\syswow64\ADVAPI32.dll:ADVAPI32.dll (75440000), size: 655360 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\syswow64\ADVAPI32.dll', fileVersion: 6.1.7601.17514 C:\Windows\syswow64\msvcrt.dll:msvcrt.dll (76EC0000), size: 704512 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\syswow64\msvcrt.dll', fileVersion: 7.0.7601.17744 C:\Windows\SysWOW64\sechost.dll:sechost.dll (75680000), size: 102400 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\SysWOW64\sechost.dll', fileVersion: 6.1.7600.16385 C:\Windows\syswow64\RPCRT4.dll:RPCRT4.dll (75080000), size: 983040 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\syswow64\RPCRT4.dll', fileVersion: 6.1.7601.17514 C:\Windows\syswow64\SspiCli.dll:SspiCli.dll (74F10000), size: 393216 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\syswow64\SspiCli.dll', fileVersion: 6.1.7601.17725 C:\Windows\syswow64\CRYPTBASE.dll:CRYPTBASE.dll (74F00000), size: 49152 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\syswow64\CRYPTBASE.dll', fileVersion: 6.1.7600.16385 C:\Windows\system32\MSVCR100D.dll:MSVCR100D.dll (57A30000), size: 1519616 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\system32\MSVCR100D.dll', fileVersion: 10.0.40219.325 C:\Windows\system32\VERSION.dll:VERSION.dll (73560000), size: 36864 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\system32\VERSION.dll', fileVersion: 6.1.7600.16385 C:\Program Files (x86)\Debugging Tools for Windows (x86)\dbghelp.dll:dbghelp.dll (578E0000), size: 1314816 (result: 0), SymType: 'PDB', PDB: 'C:\Program Files (x86)\Debugging Tools for Windows (x86)\dbghelp.dll', fileVersion: 6.12.2.633 <span style='color: blue; font-weight: bold'>ERROR: SymGetSymFromAddr64, GetLastError: 487 (Address: 008B1C27) ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 008B1C27) 008B1C27 (StackWalker_VC10): (filename not available): (function-name not available) ERROR: SymGetSymFromAddr64, GetLastError: 487 (Address: 008B1063) ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 008B1063) 008B1063 (StackWalker_VC10): (filename not available): (function-name not available) ERROR: SymGetSymFromAddr64, GetLastError: 487 (Address: 008B10C8) ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 008B10C8) 008B10C8 (StackWalker_VC10): (filename not available): (function-name not available) ERROR: SymGetSymFromAddr64, GetLastError: 487 (Address: 008B10E8) ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 008B10E8) 008B10E8 (StackWalker_VC10): (filename not available): (function-name not available) ERROR: SymGetSymFromAddr64, GetLastError: 487 (Address: 008B1108) ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 008B1108) 008B1108 (StackWalker_VC10): (filename not available): (function-name not available) ERROR: SymGetSymFromAddr64, GetLastError: 487 (Address: 008B1128) ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 008B1128) 008B1128 (StackWalker_VC10): (filename not available): (function-name not available) ERROR: SymGetSymFromAddr64, GetLastError: 487 (Address: 008B1148) ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 008B1148) 008B1148 (StackWalker_VC10): (filename not available): (function-name not available) ERROR: SymGetSymFromAddr64, GetLastError: 487 (Address: 008B1168) ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 008B1168) 008B1168 (StackWalker_VC10): (filename not available): (function-name not available) ERROR: SymGetSymFromAddr64, GetLastError: 487 (Address: 008B43EF) ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 008B43EF) 008B43EF (StackWalker_VC10): (filename not available): (function-name not available) ERROR: SymGetSymFromAddr64, GetLastError: 487 (Address: 008B421F) ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 008B421F) 008B421F (StackWalker_VC10): (filename not available): (function-name not available) ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 74F8339A) 74F8339A (kernel32): (filename not available): BaseThreadInitThunk ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 77869EF2) 77869EF2 (ntdll): (filename not available): __RtlUserThreadStart ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 77869EC5) 77869EC5 (ntdll): (filename not available): _RtlUserThreadStart</span> </pre> <br /> 처음에 위의 결과를 보았을 때... '에게 이게 뭐야?'라는 생각이 들더군요. ^^; 뭔가 로직이 불안정해서 안되는 것인가 라고 여기다가 문득 해당 StackWalker_VC10.exe 파일만 있을 뿐 StackWalker_VC10.PDB 파일이 없다는 것을 알게 되었습니다. 그래서, 프로젝트 속성 창에서 PDB 파일을 생성하도록 변경하고 다시 실행을 했더니... 오호~~~ 이제는 제법 그럴듯 하게 콜 스택이 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > D:\StackWalker\Win32\Debug>StackWalker_VC10.exe SymInit: Symbol-SearchPath: '.;D:\StackWalker\Win32\Debug;D:\StackWalker\Win32\Debug;C:\Windows;C:\Windows\system32;SRV*C:\websymbols*http://msdl.microsoft.com/download/symbols;', symOptions: 530, UserName: 'SeongTae Jeong' OS-Version: 6.1.7601 (Service Pack 1) 0x100-0x1 D:\Settings\desktop\native_callstack\StackWalker\Win32\Debug\StackWalker_VC10.exe:StackWalker_VC10.exe (000C0000), size: 69632 (result: 0), SymType: 'PDB', PDB: 'D:\Settings\desktop\native_callstack\StackWalker\Win32\Debug\StackWalker_VC10.exe' C:\Windows\SysWOW64\ntdll.dll:ntdll.dll (77830000), size: 1572864 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\SysWOW64\ntdll.dll', fileVersion: 6.1.7601.17725 C:\Windows\syswow64\kernel32.dll:kernel32.dll (74F70000), size: 1114112 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\syswow64\kernel32.dll', fileVersion: 6.1.7601.17651 C:\Windows\syswow64\KERNELBASE.dll:KERNELBASE.dll (76C10000), size: 286720 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\syswow64\KERNELBASE.dll', fileVersion: 6.1.7601.17651 C:\Windows\syswow64\ADVAPI32.dll:ADVAPI32.dll (75440000), size: 655360 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\syswow64\ADVAPI32.dll', fileVersion: 6.1.7601.17514 C:\Windows\syswow64\msvcrt.dll:msvcrt.dll (76EC0000), size: 704512 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\syswow64\msvcrt.dll', fileVersion: 7.0.7601.17744 C:\Windows\SysWOW64\sechost.dll:sechost.dll (75680000), size: 102400 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\SysWOW64\sechost.dll', fileVersion: 6.1.7600.16385 C:\Windows\syswow64\RPCRT4.dll:RPCRT4.dll (75080000), size: 983040 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\syswow64\RPCRT4.dll', fileVersion: 6.1.7601.17514 C:\Windows\syswow64\SspiCli.dll:SspiCli.dll (74F10000), size: 393216 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\syswow64\SspiCli.dll', fileVersion: 6.1.7601.17725 C:\Windows\syswow64\CRYPTBASE.dll:CRYPTBASE.dll (74F00000), size: 49152 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\syswow64\CRYPTBASE.dll', fileVersion: 6.1.7600.16385 C:\Windows\system32\MSVCR100D.dll:MSVCR100D.dll (578B0000), size: 1519616 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\system32\MSVCR100D.dll', fileVersion: 10.0.40219.325 C:\Windows\system32\VERSION.dll:VERSION.dll (73560000), size: 36864 (result: 0), SymType: 'PDB', PDB: 'C:\Windows\system32\VERSION.dll', fileVersion: 6.1.7600.16385 C:\Program Files (x86)\Debugging Tools for Windows (x86)\dbghelp.dll:dbghelp.dll (57A60000), size: 1314816 (result: 0), SymType: 'PDB', PDB: 'C:\Program Files (x86)\Debugging Tools for Windows (x86)\dbghelp.dll', fileVersion: 6.12.2.633 <span style='color: blue; font-weight: bold'>d:\settings\desktop\native_callstack\stackwalker\stackwalker.cpp (1017): StackWalker::ShowCallstack d:\settings\desktop\native_callstack\stackwalker\main.cpp (43): Func5 d:\settings\desktop\native_callstack\stackwalker\main.cpp (47): Func4 d:\settings\desktop\native_callstack\stackwalker\main.cpp (51): Func3 d:\settings\desktop\native_callstack\stackwalker\main.cpp (55): Func2 d:\settings\desktop\native_callstack\stackwalker\main.cpp (59): Func1 d:\settings\desktop\native_callstack\stackwalker\main.cpp (64): StackWalkTest d:\settings\desktop\native_callstack\stackwalker\main.cpp (220): wmain f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (552): __tmainCRTStartup f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (371): wmainCRTStartup ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 74F8339A) 74F8339A (kernel32): (filename not available): BaseThreadInitThunk ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 77869EF2) 77869EF2 (ntdll): (filename not available): __RtlUserThreadStart ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 77869EC5) 77869EC5 (ntdll): (filename not available): _RtlUserThreadStart</span> </pre> <br /> 근데... 대부분의 경우에 콜스택만을 얻고 싶을 텐데, 부가적인 문자열 출력이 너무 많아서 심란해 보입니다. 어디... 한번 다듬어 볼까요? ^^<br /> <br /> 우선, 디버깅을 해보면 StackWalker.cpp 파일의 LoadModules 함수를 보면 Init 함수와 LoadModules 함수 실행 시에 부가적인 메시지가 나오는 것을 알 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // First Init the whole stuff... BOOL bRet = <span style='color: blue; font-weight: bold'>this->m_sw->Init(szSymPath);</span> if (szSymPath != NULL) free(szSymPath); szSymPath = NULL; if (bRet == FALSE) { this->OnDbgHelpErr("Error while initializing dbghelp.dll", 0, 0); SetLastError(ERROR_DLL_INIT_FAILED); return FALSE; } bRet = <span style='color: blue; font-weight: bold'>this->m_sw->LoadModules(this->m_hProcess, this->m_dwProcessId);</span> if (bRet != FALSE) m_modulesLoaded = TRUE; return bRet; </pre> <br /> Init 출력 부분을 제거하기 위해 따라가다 보면, OnSymInit 함수까지 오게 되는데요. 아래의 함수에서 OnOutput 부분만 주석처리해 주시면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName) { CHAR buffer[STACKWALK_MAX_NAMELEN]; _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n", szSearchPath, symOptions, szUserName); OnOutput(buffer); // Also display the OS-version #if _MSC_VER <= 1200 OSVERSIONINFOA ver; ZeroMemory(&ver, sizeof(OSVERSIONINFOA)); ver.dwOSVersionInfoSize = sizeof(ver); if (GetVersionExA(&ver) != FALSE) { _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s)\n", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, ver.szCSDVersion); <span style='color: blue; font-weight: bold'>// OnOutput(buffer);</span> } #else OSVERSIONINFOEXA ver; ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA)); ver.dwOSVersionInfoSize = sizeof(ver); if (GetVersionExA( (OSVERSIONINFOA*) &ver) != FALSE) { _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, ver.szCSDVersion, ver.wSuiteMask, ver.wProductType); <span style='color: blue; font-weight: bold'>// OnOutput(buffer);</span> } #endif } </pre> <br /> 그다음, LoadModules 출력은 다음과 같이 OnLoadModule의 OnOutput 출력을 주석 처리하면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > void StackWalker::OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion) { CHAR buffer[STACKWALK_MAX_NAMELEN]; if (fileVersion == 0) _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName); else { DWORD v4 = (DWORD) (fileVersion & 0xFFFF); DWORD v3 = (DWORD) ((fileVersion>>16) & 0xFFFF); DWORD v2 = (DWORD) ((fileVersion>>32) & 0xFFFF); DWORD v1 = (DWORD) ((fileVersion>>48) & 0xFFFF); _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName, v1, v2, v3, v4); } <span style='color: blue; font-weight: bold'>// OnOutput(buffer);</span> } </pre> <br /> 이렇게 해서 실행하면 출력 결과는 다음과 같이 정제됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > d:\settings\desktop\native_callstack\stackwalker\stackwalker.cpp (1017): StackWalker::ShowCallstack d:\settings\desktop\native_callstack\stackwalker\main.cpp (55): Func5 d:\settings\desktop\native_callstack\stackwalker\main.cpp (59): Func4 d:\settings\desktop\native_callstack\stackwalker\main.cpp (63): Func3 d:\settings\desktop\native_callstack\stackwalker\main.cpp (67): Func2 d:\settings\desktop\native_callstack\stackwalker\main.cpp (71): Func1 d:\settings\desktop\native_callstack\stackwalker\main.cpp (80): StackWalkTest d:\settings\desktop\native_callstack\stackwalker\main.cpp (236): wmain f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (552): __tmainCRTStartup f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (371): wmainCRTStartup <span style='color: blue; font-weight: bold'>ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 74F8339A)</span> 74F8339A (kernel32): (filename not available): BaseThreadInitThunk <span style='color: blue; font-weight: bold'>ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 77869EF2)</span> 77869EF2 (ntdll): (filename not available): __RtlUserThreadStart <span style='color: blue; font-weight: bold'>ERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 77869EC5)</span> 77869EC5 (ntdll): (filename not available): _RtlUserThreadStart </pre> <br /> 그래도 약간 마음에 안 드는 부분이 있는데, "ERROR" 라인은 굳이 없어도 될 것 같다는 생각이 듭니다. 이를 제거하기 위해서는 ShowCallstack 메서드에서 OnDbgHelpErr 라인을 주석 처리해 주시면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > BOOL StackWalker::ShowCallstack(HANDLE hThread, const CONTEXT *context, PReadProcessMemoryRoutine readMemoryFunction, LPVOID pUserData) { ... [생략]... // show line number info, NT5.0-method (SymGetLineFromAddr64()) if (this->m_sw->pSGLFA != NULL ) { // yes, we have SymGetLineFromAddr64() if (this->m_sw->pSGLFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine), &Line) != FALSE) { csEntry.lineNumber = Line.LineNumber; // TODO: Mache dies sicher...! strcpy_s(csEntry.lineFileName, Line.FileName); } else { <span style='color: blue; font-weight: bold'>// this->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), s.AddrPC.Offset);</span> } } // yes, we have SymGetLineFromAddr64() ... [생략]... } </pre> <br /> 아래는 이렇게 해서 얻은 최종 결과입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > d:\settings\desktop\native_callstack\stackwalker\stackwalker.cpp (1017): StackWalker::ShowCallstack d:\settings\desktop\native_callstack\stackwalker\main.cpp (55): Func5 d:\settings\desktop\native_callstack\stackwalker\main.cpp (59): Func4 d:\settings\desktop\native_callstack\stackwalker\main.cpp (63): Func3 d:\settings\desktop\native_callstack\stackwalker\main.cpp (67): Func2 d:\settings\desktop\native_callstack\stackwalker\main.cpp (71): Func1 d:\settings\desktop\native_callstack\stackwalker\main.cpp (80): StackWalkTest d:\settings\desktop\native_callstack\stackwalker\main.cpp (236): wmain f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (552): __tmainCRTStartup f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (371): wmainCRTStartup 74F8339A (kernel32): (filename not available): BaseThreadInitThunk 77869EF2 (ntdll): (filename not available): __RtlUserThreadStart 77869EC5 (ntdll): (filename not available): _RtlUserThreadStart </pre> <br /> 훨씬 낫군요. ^^ <br /> <br /> 디버그 빌드로 했으니, 이번엔 릴리스 빌드로 해보면 결과가 어떨까요?<br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > d:\settings\desktop\native_callstack\stackwalker\stackwalker.cpp (1017): StackWalker::ShowCallstack d:\settings\desktop\native_callstack\stackwalker\main.cpp (226): wmainf:\dd\vctools\crt_bld\self_x86\crt\src\crt0.c (278): __tmainCRTStartup 76AC33CA (kernel32): (filename not available): BaseThreadInitThunk 771F9ED2 (ntdll): (filename not available): RtlInitializeExceptionChain 771F9EA5 (ntdll): (filename not available): RtlInitializeExceptionChain </pre> <br /> Func... 함수들이 모두 inline 되는 식의 최적화가 이뤄져서 다 없어지고 StackWalker::ShowCallstack만 보입니다. 와~~~ 잘 만들어졌군요. ^^<br /> <br /> StackWalker 소스 코드가 마음에 드는 점이 하나 더 있다면, 자신의 스레드 뿐만 아니라 다른 스레드의 콜스택을 뜨는 것도 가능하다는 점입니다. 그래서, 다음과 같이 소스 코드를 변경해 주면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > void StackWalkTest() { <span style='color: blue; font-weight: bold'>HANDLE targetThread</span> = ::CreateThread(NULL, 0, ThreadFunc, NULL, 0, NULL); Sleep(2000); StackWalkerToConsole sw; <span style='color: blue; font-weight: bold'>sw.ShowCallstack(targetThread);</span> } DWORD WINAPI ThreadFunc(LPVOID lpParameter) { do { Sleep(1000); } while (true); } </pre> <br /> 다음과 같은 Call 스택을 얻을 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <span style='color: blue; font-weight: bold'>7784FD71 (ntdll): (filename not available): ZwDelayExecution 76C231BB (KERNELBASE): (filename not available): SleepEx 76C23A8B (KERNELBASE): (filename not available): Sleep</span> d:\settings\desktop\native_callstack\stackwalker\main.cpp (44): ThreadFunc 74F8339A (kernel32): (filename not available): BaseThreadInitThunk 77869EF2 (ntdll): (filename not available): __RtlUserThreadStart 77869EC5 (ntdll): (filename not available): _RtlUserThreadStart </pre> <br /> 이쯤에서, 가장 중요한 라이선스가 어떻게 되는지 궁금하실 텐데요. BSD LICENSE (<a target='tab' href='http://www.opensource.org/licenses/bsd-license.php'>http://www.opensource.org/licenses/bsd-license.php</a>)이니 상용 제품에도 걱정없이 적용하실 수 있습니다.<br /> <br /> (<a target='tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=703&boardid=331301885'>첨부된 파일은 StackWalker를 포함</a>하고 있습니다.)<br /> </p><br /> <br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
2259
(왼쪽의 숫자를 입력해야 합니다.)