4 * Function to implement assert clauses.
6 * Portable Windows Library
8 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
25 * All Rights Reserved.
27 * Contributor(s): ______________________________________.
30 * Revision 1.39 2004/07/06 10:12:55 csoutheren
31 * Added static integer o factory template to assist in ensuring factories are instantiated
33 * Revision 1.38 2004/04/03 06:54:30 rjongbloed
34 * Many and various changes to support new Visual C++ 2003
36 * Revision 1.37 2002/09/25 00:54:50 robertj
37 * Fixed memory leak on assertion.
39 * Revision 1.36 2002/09/23 07:17:24 robertj
40 * Changes to allow winsock2 to be included.
42 * Revision 1.35 2002/06/25 02:25:29 robertj
43 * Improved assertion system to allow C++ class name to be displayed if
44 * desired, especially relevant to container classes.
46 * Revision 1.34 2001/08/17 19:18:15 yurik
47 * Fixed compile error in release mode
49 * Revision 1.33 2001/08/16 18:38:05 yurik
50 * Fixed assert function
52 * Revision 1.32 2001/04/26 06:07:34 yurik
55 * Revision 1.31 2001/03/29 23:33:00 robertj
56 * Added missing structure initialisation, thanks Victor H.
58 * Revision 1.30 2001/03/02 06:54:04 yurik
59 * Rephrased pragma message
61 * Revision 1.29 2001/01/24 06:56:03 yurik
62 * Correcting a typo in WinCE related code
64 * Revision 1.28 2001/01/24 06:34:44 yurik
65 * Windows CE port-related changes
67 * Revision 1.27 2000/05/23 05:50:43 robertj
68 * Attempted to fix stack dump, still refuses to work even though used to work perfectly.
70 * Revision 1.26 2000/03/04 08:07:07 robertj
71 * Fixed problem with window not appearing when assert on GUI based win32 apps.
73 * Revision 1.25 1999/02/16 08:08:06 robertj
74 * MSVC 6.0 compatibility changes.
76 * Revision 1.24 1999/02/12 01:01:57 craigs
77 * Fixed problem with linking static versions of libraries
79 * Revision 1.23 1998/12/04 10:10:45 robertj
80 * Added virtual for determining if process is a service. Fixes linkage problem.
82 * Revision 1.22 1998/11/30 05:33:08 robertj
83 * Fixed duplicate debug stream class, ther can be only one.
85 * Revision 1.21 1998/11/30 04:48:38 robertj
86 * New directory structure
88 * Revision 1.20 1998/09/24 03:30:39 robertj
89 * Added open software license.
91 * Revision 1.19 1997/03/18 21:22:31 robertj
92 * Display error message if assert stack dump fails
94 * Revision 1.18 1997/02/09 01:27:18 robertj
95 * Added stack dump under NT.
97 * Revision 1.17 1997/02/05 11:49:40 robertj
98 * Changed current process function to return reference and validate objects descendancy.
100 * Revision 1.16 1997/01/04 06:52:04 robertj
101 * Removed the press a key to continue under win '95.
103 * Revision 1.15 1996/11/18 11:30:00 robertj
104 * Removed int 3 on non-debug versions.
106 * Revision 1.14 1996/11/16 10:51:51 robertj
107 * Changed assert to display message and break if in debug mode service.
109 * Revision 1.13 1996/11/10 21:02:08 robertj
110 * Fixed bug in assertion when as a service, string buffer not big enough.
112 * Revision 1.12 1996/10/08 13:00:46 robertj
113 * Changed default for assert to be ignore, not abort.
115 * Revision 1.11 1996/07/27 04:08:13 robertj
116 * Changed SystemLog to be stream based rather than printf based.
118 * Revision 1.10 1996/05/30 11:48:28 robertj
119 * Fixed press a key to continue to only require one key.
121 * Revision 1.9 1996/05/23 10:03:20 robertj
122 * Windows 95 support.
124 * Revision 1.8 1996/03/04 12:39:35 robertj
125 * Fixed Win95 support for console tasks.
127 * Revision 1.7 1996/01/28 14:13:04 robertj
128 * Made PServiceProcess special case global not just WIN32.
130 * Revision 1.6 1995/12/10 11:55:09 robertj
131 * Numerous fixes for WIN32 service processes.
133 * Revision 1.5 1995/04/25 11:32:34 robertj
134 * Fixed Borland compiler warnings.
136 * Revision 1.4 1995/03/12 05:00:04 robertj
137 * Re-organisation of DOS/WIN16 and WIN32 platforms to maximise common code.
138 * Used built-in equate for WIN32 API (_WIN32).
140 * Revision 1.3 1994/10/30 11:25:09 robertj
141 * Added error number to assert.
143 * Revision 1.2 1994/06/25 12:13:01 robertj
146 * Revision 1.1 1994/04/01 14:39:35 robertj
150 #define P_DISABLE_FACTORY_INSTANCES
153 #include <ptlib/svcproc.h>
158 ///////////////////////////////////////////////////////////////////////////////
163 #include <imagehlp.h>
165 static BOOL CALLBACK
EnumWindowsProc(HWND hWnd
, LPARAM thisProcess
)
167 char wndClassName
[100];
168 GetClassName(hWnd
, wndClassName
, sizeof(wndClassName
));
169 if (strcmp(wndClassName
, "ConsoleWindowClass") != 0)
173 GetWindowThreadProcessId(hWnd
, &wndProcess
);
174 if (wndProcess
!= (DWORD
)thisProcess
)
177 cerr
<< "\nPress a key to continue . . .";
180 HANDLE in
= GetStdHandle(STD_INPUT_HANDLE
);
181 SetConsoleMode(in
, ENABLE_PROCESSED_INPUT
);
182 FlushConsoleInputBuffer(in
);
185 ReadConsole(in
, &dummy
, 1, &readBytes
, NULL
);
190 void PWaitOnExitConsoleWindow()
193 EnumWindows(EnumWindowsProc
, GetCurrentProcessId());
199 class PImageDLL
: public PDynaLink
201 PCLASSINFO(PImageDLL
, PDynaLink
)
205 BOOL (__stdcall
*SymInitialize
)(
207 IN LPSTR UserSearchPath
,
208 IN BOOL fInvadeProcess
210 BOOL (__stdcall
*SymCleanup
)(
213 DWORD (__stdcall
*SymGetOptions
)();
214 DWORD (__stdcall
*SymSetOptions
)(
217 DWORD (__stdcall
*SymLoadModule
)(
225 BOOL (__stdcall
*StackWalk
)(
229 LPSTACKFRAME StackFrame
,
230 LPVOID ContextRecord
,
231 PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine
,
232 PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine
,
233 PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine
,
234 PTRANSLATE_ADDRESS_ROUTINE TranslateAddress
236 BOOL (__stdcall
*SymGetSymFromAddr
)(
239 OUT PDWORD pdwDisplacement
,
240 OUT PIMAGEHLP_SYMBOL Symbol
243 PFUNCTION_TABLE_ACCESS_ROUTINE SymFunctionTableAccess
;
244 PGET_MODULE_BASE_ROUTINE SymGetModuleBase
;
246 BOOL (__stdcall
*SymGetModuleInfo
)(
249 OUT PIMAGEHLP_MODULE ModuleInfo
254 PImageDLL::PImageDLL()
255 : PDynaLink("IMAGEHLP.DLL")
257 if (!GetFunction("SymInitialize", (Function
&)SymInitialize
) ||
258 !GetFunction("SymCleanup", (Function
&)SymCleanup
) ||
259 !GetFunction("SymGetOptions", (Function
&)SymGetOptions
) ||
260 !GetFunction("SymSetOptions", (Function
&)SymSetOptions
) ||
261 !GetFunction("SymLoadModule", (Function
&)SymLoadModule
) ||
262 !GetFunction("StackWalk", (Function
&)StackWalk
) ||
263 !GetFunction("SymGetSymFromAddr", (Function
&)SymGetSymFromAddr
) ||
264 !GetFunction("SymFunctionTableAccess", (Function
&)SymFunctionTableAccess
) ||
265 !GetFunction("SymGetModuleBase", (Function
&)SymGetModuleBase
) ||
266 !GetFunction("SymGetModuleInfo", (Function
&)SymGetModuleInfo
))
274 void PAssertFunc(const char * msg
)
281 #if defined(_WIN32) && defined(_M_IX86)
283 if (imagehlp
.IsLoaded()) {
284 // Turn on load lines.
285 imagehlp
.SymSetOptions(imagehlp
.SymGetOptions()|SYMOPT_LOAD_LINES
);
288 ver
.dwOSVersionInfoSize
= sizeof(ver
);
289 ::GetVersionEx(&ver
);
290 if (ver
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
291 hProcess
= GetCurrentProcess();
293 hProcess
= (HANDLE
)GetCurrentProcessId();
294 if (imagehlp
.SymInitialize(hProcess
, NULL
, TRUE
)) {
295 HANDLE hThread
= GetCurrentThread();
296 // The thread information.
297 CONTEXT threadContext
;
298 threadContext
.ContextFlags
= CONTEXT_FULL
;
299 if (GetThreadContext(hThread
, &threadContext
)) {
301 memset(&frame
, 0, sizeof(frame
));
303 #if defined (_M_IX86)
304 #define IMAGE_FILE_MACHINE IMAGE_FILE_MACHINE_I386
305 frame
.AddrPC
.Offset
= threadContext
.Eip
;
306 frame
.AddrPC
.Mode
= AddrModeFlat
;
307 frame
.AddrStack
.Offset
= threadContext
.Esp
;
308 frame
.AddrStack
.Mode
= AddrModeFlat
;
309 frame
.AddrFrame
.Offset
= threadContext
.Ebp
;
310 frame
.AddrFrame
.Mode
= AddrModeFlat
;
312 #elif defined (_M_ALPHA)
313 #define IMAGE_FILE_MACHINE IMAGE_FILE_MACHINE_ALPHA
314 frame
.AddrPC
.Offset
= (unsigned long)threadContext
.Fir
;
315 frame
.AddrPC
.Mode
= AddrModeFlat
;
317 #error ( "Unknown machine!" )
321 while (frameCount
++ < 16 &&
322 imagehlp
.StackWalk(IMAGE_FILE_MACHINE
,
327 NULL
, // ReadMemoryRoutine
328 imagehlp
.SymFunctionTableAccess
,
329 imagehlp
.SymGetModuleBase
,
331 if (frameCount
> 1 && frame
.AddrPC
.Offset
!= 0) {
332 char buffer
[sizeof(IMAGEHLP_SYMBOL
)+100];
333 PIMAGEHLP_SYMBOL symbol
= (PIMAGEHLP_SYMBOL
)buffer
;
334 symbol
->SizeOfStruct
= sizeof(IMAGEHLP_SYMBOL
);
335 symbol
->MaxNameLength
= sizeof(buffer
)-sizeof(IMAGEHLP_SYMBOL
);
336 DWORD displacement
= 0;
337 if (imagehlp
.SymGetSymFromAddr(hProcess
,
341 str
<< "\n " << symbol
->Name
;
345 << hex
<< setfill('0')
346 << setw(8) << frame
.AddrPC
.Offset
347 << dec
<< setfill(' ');
349 str
<< '(' << hex
<< setfill('0');
350 for (PINDEX i
= 0; i
< PARRAYSIZE(frame
.Params
); i
++) {
353 if (frame
.Params
[i
] != 0)
355 str
<< frame
.Params
[i
];
357 str
<< setfill(' ') << ')';
358 if (displacement
!= 0)
359 str
<< " + 0x" << displacement
;
363 if (frameCount
<= 2) {
364 DWORD e
= ::GetLastError();
365 str
<< "\n No stack dump: IMAGEHLP.DLL StackWalk failed: error=" << e
;
369 DWORD e
= ::GetLastError();
370 str
<< "\n No stack dump: IMAGEHLP.DLL GetThreadContext failed: error=" << e
;
373 imagehlp
.SymCleanup(hProcess
);
376 DWORD e
= ::GetLastError();
377 str
<< "\n No stack dump: IMAGEHLP.DLL SymInitialise failed: error=" << e
;
381 DWORD e
= ::GetLastError();
382 str
<< "\n No stack dump: IMAGEHLP.DLL could not be loaded: error=" << e
;
387 const char * pstr
= str
.str();
388 // Unfreeze str so frees memory
389 str
.rdbuf()->freeze(0);
390 // Must do nothing to str after this or it invalidates pstr
392 if (PProcess::Current().IsServiceProcess()) {
393 PSystemLog::Output(PSystemLog::Fatal
, pstr
);
394 #if defined(_MSC_VER) && defined(_DEBUG)
395 if (PServiceProcess::Current().debugMode
)
402 static HANDLE mutex
= CreateSemaphore(NULL
, 1, 1, NULL
);
403 WaitForSingleObject(mutex
, INFINITE
);
406 if (PProcess::Current().IsGUIProcess()) {
407 switch (MessageBox(NULL
, pstr
, "Portable Windows Library",
408 MB_ABORTRETRYIGNORE
|MB_ICONHAND
|MB_TASKMODAL
)) {
410 FatalExit(1); // Never returns
416 ReleaseSemaphore(mutex
, 1, NULL
);
422 cerr
<< pstr
<< "\n<A>bort, <B>reak, <I>gnore? ";
427 cerr
<< "Aborted" << endl
;
432 cerr
<< "Break" << endl
;
434 ReleaseSemaphore(mutex
, 1, NULL
);
443 cerr
<< "Ignored" << endl
;
445 ReleaseSemaphore(mutex
, 1, NULL
);
456 if ( AfxAssertFailedLine(file
, line
) )
465 // End Of File ///////////////////////////////////////////////////////////////