Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

459 lines
12 KiB

  1. #include <windows.h>
  2. #include <debug.h>
  3. #include <crtdbg.h>
  4. #include <tstr.h>
  5. #include <stdarg.h>
  6. #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
  7. #define TRACE_HRESULT 0x01
  8. #define TRACE_Win32 0x02
  9. void OutputDebugStringDBWIN( LPCTSTR lpOutputString, ...);
  10. void WriteFilename( TSTR & msg, LPCTSTR pFile );
  11. void StackTrace( TSTR & str );
  12. LPCTSTR g_pLevelStrs [ ] =
  13. {
  14. TEXT("DBG"),
  15. TEXT("INF"),
  16. TEXT("WRN"),
  17. TEXT("ERR"),
  18. TEXT("PRM"),
  19. TEXT("PRW"),
  20. TEXT("IOP"),
  21. TEXT("ASD"),
  22. TEXT("ASR"),
  23. TEXT("CAL"),
  24. TEXT("RET"),
  25. TEXT("???"),
  26. };
  27. static
  28. void InternalTrace( LPCTSTR pFile, ULONG uLineNo, DWORD dwLevel, DWORD dwFlags, const void * pThis, HRESULT hr, LPCTSTR pStr )
  29. {
  30. if( dwLevel >= ARRAYSIZE( g_pLevelStrs ) )
  31. dwLevel = ARRAYSIZE( g_pLevelStrs ) - 1; // "???" unknown entry
  32. // Basic message stuff - pid, tid... (also pass this and use object ptr?)
  33. // TODO - allow naming of threads?
  34. DWORD pid = GetCurrentProcessId();
  35. DWORD tid = GetCurrentThreadId();
  36. // Module:file:line pid:tid str
  37. TSTR msg(512);
  38. msg << g_pLevelStrs[ dwLevel ] << TEXT(" ");
  39. if( ! pFile )
  40. WriteFilename( msg, TEXT("[missing file]") );
  41. else
  42. WriteFilename( msg, pFile );
  43. msg << TEXT(":")
  44. << uLineNo << TEXT(" ")
  45. << WriteHex( pid ) << TEXT(":")
  46. << WriteHex( tid ) << TEXT(" ");
  47. if( pThis )
  48. {
  49. msg << TEXT("this=") << WriteHex( pThis, 8 ) << TEXT(" ");
  50. }
  51. if( dwFlags & TRACE_HRESULT )
  52. {
  53. msg << WriteError( hr ) << TEXT(" ");
  54. }
  55. if( dwFlags & TRACE_Win32 )
  56. {
  57. msg << WriteError( GetLastError() ) << TEXT(" ");
  58. }
  59. if( ! pStr )
  60. msg << TEXT("[missing string]") << TEXT("\r\n");
  61. else
  62. msg << pStr << TEXT("\r\n");
  63. // For the moment, just send to DBWIN...
  64. // OutputDebugString( msg );
  65. OutputDebugStringDBWIN( msg );
  66. #ifdef DEBUG
  67. if( dwLevel == _TRACE_ASSERT_D || dwLevel == _TRACE_ERR )
  68. {
  69. _ASSERT(0);
  70. // DebugBreak();
  71. }
  72. #endif // DEBUG
  73. }
  74. void _Trace( LPCTSTR pFile, ULONG uLineNo, DWORD dwLevel, const void * pThis, LPCTSTR pStr )
  75. {
  76. InternalTrace( pFile, uLineNo, dwLevel, 0, pThis, 0, pStr );
  77. }
  78. void _TraceHR( LPCTSTR pFile, ULONG uLineNo, DWORD dwLevel, const void * pThis, HRESULT hr, LPCTSTR pStr )
  79. {
  80. InternalTrace( pFile, uLineNo, dwLevel, TRACE_HRESULT, pThis, hr, pStr );
  81. }
  82. void _TraceW32( LPCTSTR pFile, ULONG uLineNo, DWORD dwLevel, const void * pThis, LPCTSTR pStr )
  83. {
  84. InternalTrace( pFile, uLineNo, dwLevel, TRACE_Win32, pThis, 0, pStr );
  85. }
  86. // Add just the 'filename' part of the full path, minus base and extention.
  87. // So for "g:\dev\vss\msaa\common\file.cpp", write "file".
  88. // The start of this string is that last found ':', '\', or start of string if those are not present.
  89. // The end of this string is the last '.' found after the start position, otherwise the end of the string.
  90. void WriteFilename( TSTR & str, LPCTSTR pPath )
  91. {
  92. LPCTSTR pScan = pPath;
  93. LPCTSTR pStart = pPath;
  94. LPCTSTR pEnd = NULL;
  95. // Scan till we hit the end, or a '.'...
  96. while( *pScan != '\0' )
  97. {
  98. if( *pScan == '.' )
  99. {
  100. pEnd = pScan;
  101. pScan++;
  102. }
  103. if( *pScan == '\\' || *pScan == ':' )
  104. {
  105. pScan++;
  106. pStart = pScan;
  107. pEnd = NULL;
  108. }
  109. else
  110. {
  111. pScan++;
  112. }
  113. }
  114. if( pEnd == NULL )
  115. pEnd = pScan;
  116. str.append( pStart, pEnd - pStart );
  117. }
  118. void OutputDebugStringDBWIN( LPCTSTR lpOutputString, ... )
  119. {
  120. // create the output buffer
  121. TCHAR achBuffer[500];
  122. va_list args;
  123. va_start(args, lpOutputString);
  124. wvsprintf(achBuffer, lpOutputString, args);
  125. va_end(args);
  126. // make sure DBWIN is open and waiting
  127. HANDLE heventDBWIN = OpenEvent(EVENT_MODIFY_STATE, FALSE, TEXT("DBWIN_BUFFER_READY"));
  128. if( !heventDBWIN )
  129. {
  130. //MessageBox(NULL, TEXT("DBWIN_BUFFER_READY nonexistent"), NULL, MB_OK);
  131. return;
  132. }
  133. // get a handle to the data synch object
  134. HANDLE heventData = OpenEvent(EVENT_MODIFY_STATE, FALSE, TEXT("DBWIN_DATA_READY"));
  135. if ( !heventData )
  136. {
  137. // MessageBox(NULL, TEXT("DBWIN_DATA_READY nonexistent"), NULL, MB_OK);
  138. CloseHandle(heventDBWIN);
  139. return;
  140. }
  141. HANDLE hSharedFile = CreateFileMapping((HANDLE)-1, NULL, PAGE_READWRITE, 0, 4096, TEXT("DBWIN_BUFFER"));
  142. if (!hSharedFile)
  143. {
  144. //MessageBox(NULL, TEXT("DebugTrace: Unable to create file mapping object DBWIN_BUFFER"), TEXT("Error"), MB_OK);
  145. CloseHandle(heventDBWIN);
  146. CloseHandle(heventData);
  147. return;
  148. }
  149. LPSTR lpszSharedMem = (LPSTR)MapViewOfFile(hSharedFile, FILE_MAP_WRITE, 0, 0, 512);
  150. if (!lpszSharedMem)
  151. {
  152. //MessageBox(NULL, "DebugTrace: Unable to map shared memory", "Error", MB_OK);
  153. CloseHandle(heventDBWIN);
  154. CloseHandle(heventData);
  155. return;
  156. }
  157. // wait for buffer event
  158. WaitForSingleObject(heventDBWIN, INFINITE);
  159. // write it to the shared memory
  160. *((LPDWORD)lpszSharedMem) = GetCurrentProcessId();
  161. #ifdef UNICODE
  162. CHAR szBuf[500];
  163. wcstombs(szBuf, achBuffer, sizeof( szBuf ) );
  164. sprintf(lpszSharedMem + sizeof(DWORD), "%s", szBuf);
  165. #else
  166. sprintf(lpszSharedMem + sizeof(DWORD), "%s", achBuffer);
  167. #endif
  168. // signal data ready event
  169. SetEvent(heventData);
  170. // clean up handles
  171. CloseHandle(hSharedFile);
  172. CloseHandle(heventData);
  173. CloseHandle(heventDBWIN);
  174. return;
  175. }
  176. // Prototype stack trace code...
  177. typedef struct _IMAGEHLP_SYMBOL {
  178. DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOL)
  179. DWORD Address; // virtual address including dll base address
  180. DWORD Size; // estimated size of symbol, can be zero
  181. DWORD Flags; // info about the symbols, see the SYMF defines
  182. DWORD MaxNameLength; // maximum size of symbol name in 'Name'
  183. CHAR Name[1]; // symbol name (null terminated string)
  184. } IMAGEHLP_SYMBOL, *PIMAGEHLP_SYMBOL;
  185. typedef enum {
  186. AddrMode1616,
  187. AddrMode1632,
  188. AddrModeReal,
  189. AddrModeFlat
  190. } ADDRESS_MODE;
  191. typedef struct _tagADDRESS64 {
  192. DWORD64 Offset;
  193. WORD Segment;
  194. ADDRESS_MODE Mode;
  195. } ADDRESS64, *LPADDRESS64;
  196. typedef struct _tagADDRESS {
  197. DWORD Offset;
  198. WORD Segment;
  199. ADDRESS_MODE Mode;
  200. } ADDRESS, *LPADDRESS;
  201. typedef struct _KDHELP {
  202. DWORD Thread;
  203. DWORD ThCallbackStack;
  204. DWORD NextCallback;
  205. DWORD FramePointer;
  206. DWORD KiCallUserMode;
  207. DWORD KeUserCallbackDispatcher;
  208. DWORD SystemRangeStart;
  209. DWORD ThCallbackBStore;
  210. DWORD Reserved[8];
  211. } KDHELP, *PKDHELP;
  212. typedef struct _tagSTACKFRAME {
  213. ADDRESS AddrPC; // program counter
  214. ADDRESS AddrReturn; // return address
  215. ADDRESS AddrFrame; // frame pointer
  216. ADDRESS AddrStack; // stack pointer
  217. PVOID FuncTableEntry; // pointer to pdata/fpo or NULL
  218. DWORD Params[4]; // possible arguments to the function
  219. BOOL Far; // WOW far call
  220. BOOL Virtual; // is this a virtual frame?
  221. DWORD Reserved[3];
  222. KDHELP KdHelp;
  223. ADDRESS AddrBStore; // backing store pointer
  224. } STACKFRAME, *LPSTACKFRAME;
  225. typedef
  226. BOOL
  227. (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE)(
  228. HANDLE hProcess,
  229. LPCVOID lpBaseAddress,
  230. PVOID lpBuffer,
  231. DWORD nSize,
  232. PDWORD lpNumberOfBytesRead
  233. );
  234. typedef
  235. PVOID
  236. (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE)(
  237. HANDLE hProcess,
  238. DWORD AddrBase
  239. );
  240. typedef
  241. DWORD
  242. (__stdcall *PGET_MODULE_BASE_ROUTINE)(
  243. HANDLE hProcess,
  244. DWORD Address
  245. );
  246. typedef
  247. DWORD
  248. (__stdcall *PTRANSLATE_ADDRESS_ROUTINE)(
  249. HANDLE hProcess,
  250. HANDLE hThread,
  251. LPADDRESS lpaddr
  252. );
  253. typedef BOOL (WINAPI * PFN_SymInitialize)( HANDLE, LPSTR, BOOL );
  254. typedef BOOL (WINAPI * PFN_StackWalk)( DWORD, HANDLE, HANDLE, LPSTACKFRAME, LPVOID,
  255. PREAD_PROCESS_MEMORY_ROUTINE,
  256. PFUNCTION_TABLE_ACCESS_ROUTINE,
  257. PGET_MODULE_BASE_ROUTINE,
  258. PTRANSLATE_ADDRESS_ROUTINE );
  259. typedef LPVOID (WINAPI * PFN_SymFunctionTableAccess)( HANDLE, DWORD );
  260. typedef DWORD (WINAPI * PFN_SymGetModuleBase)( HANDLE, DWORD );
  261. typedef BOOL (WINAPI * PFN_SymGetSymFromAddr)( HANDLE, DWORD, PDWORD, PIMAGEHLP_SYMBOL );
  262. typedef BOOL (WINAPI * PFN_SymCleanup)( HANDLE hProcess );
  263. PFN_SymInitialize pfnSymInitialize;
  264. PFN_StackWalk pfnStackWalk;
  265. PFN_SymFunctionTableAccess pfnSymFunctionTableAccess;
  266. PFN_SymGetModuleBase pfnSymGetModuleBase;
  267. PFN_SymGetSymFromAddr pfnSymGetSymFromAddr;
  268. PFN_SymCleanup pfnSymCleanup;
  269. #ifdef _ALPHA_
  270. #define CH_MACHINE IMAGE_FILE_MACHINE_ALPHA
  271. #else
  272. #define CH_MACHINE IMAGE_FILE_MACHINE_I386
  273. #endif
  274. #define MAX_SYM_LEN 128
  275. void StackTrace1( EXCEPTION_POINTERS *exp, TSTR & str );
  276. #define MY_DBG_EXCEPTION 3
  277. void StackTrace( TSTR & str )
  278. {
  279. __try {
  280. // raise an exception to get the exception record to start the stack walk
  281. RaiseException(MY_DBG_EXCEPTION, 0, 0, NULL);
  282. }
  283. __except( StackTrace1( GetExceptionInformation(), str ), EXCEPTION_CONTINUE_EXECUTION ) {
  284. }
  285. }
  286. void StackTrace1( EXCEPTION_POINTERS *exp, TSTR & str )
  287. {
  288. CONTEXT * context = exp->ContextRecord;
  289. HMODULE hModule = LoadLibrary( TEXT( "dbghelp" ) );
  290. pfnSymInitialize = (PFN_SymInitialize) GetProcAddress( hModule, "SymInitialize" );
  291. pfnStackWalk = (PFN_StackWalk) GetProcAddress( hModule, "StackWalk" );
  292. pfnSymFunctionTableAccess = (PFN_SymFunctionTableAccess) GetProcAddress( hModule, "SymFunctionTableAccess" );
  293. pfnSymGetModuleBase = (PFN_SymGetModuleBase) GetProcAddress( hModule, "SymGetModuleBase" );
  294. pfnSymGetSymFromAddr = (PFN_SymGetSymFromAddr) GetProcAddress( hModule, "SymGetSymFromAddr" );
  295. pfnSymCleanup = (PFN_SymCleanup) GetProcAddress( hModule, "SymCleanup" );
  296. HANDLE hProcess = GetCurrentProcess();
  297. HANDLE hThread = GetCurrentThread();
  298. pfnSymInitialize( hProcess, NULL, TRUE );
  299. IMAGEHLP_SYMBOL * psym = (IMAGEHLP_SYMBOL *) new char[ sizeof(IMAGEHLP_SYMBOL) + MAX_SYM_LEN ];
  300. STACKFRAME frame;
  301. memset( &frame, 0, sizeof( frame ) );
  302. #if defined (_M_IX86)
  303. // Initialize the STACKFRAME structure for the first call. This is only
  304. // necessary for Intel CPUs, and isn't mentioned in the documentation.
  305. frame.AddrPC.Offset = context->Eip;
  306. frame.AddrPC.Mode = AddrModeFlat;
  307. frame.AddrFrame.Offset = context->Ebp;
  308. frame.AddrFrame.Mode = AddrModeFlat;
  309. frame.AddrStack.Offset = context->Esp;
  310. frame.AddrStack.Mode = AddrModeFlat;
  311. #endif // _M_IX86
  312. for( ; ; )
  313. {
  314. BOOL bSWRet = pfnStackWalk( CH_MACHINE,
  315. hProcess,
  316. hThread,
  317. & frame,
  318. NULL, // CONTEXT - NULL for i386
  319. NULL, // Use ReadProcessMemory
  320. pfnSymFunctionTableAccess,
  321. pfnSymGetModuleBase,
  322. NULL );
  323. if( ! bSWRet )
  324. {
  325. break;
  326. }
  327. /*
  328. frame.AddrPC
  329. frame.AddrReturn
  330. frame.AddrFrame
  331. frame.AddrStack
  332. frame.Params[ 4 ]
  333. */
  334. psym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  335. psym->MaxNameLength = MAX_SYM_LEN;
  336. DWORD dwDisplacement;
  337. if( pfnSymGetSymFromAddr( hProcess, frame.AddrPC.Offset, & dwDisplacement, psym ) )
  338. {
  339. }
  340. else
  341. {
  342. }
  343. }
  344. delete psym;
  345. pfnSymCleanup( hProcess );
  346. }