Added PSharedptr class
[pwlib.git] / src / ptlib / msos / assert.cxx
blob8b9488d8f0e157a0e7c304cf828ee0f835fc6c22
1 /*
2 * assert.cxx
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
18 * under the License.
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): ______________________________________.
29 * $Log$
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
53 * UI improvements
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
144 * Synchronisation.
146 * Revision 1.1 1994/04/01 14:39:35 robertj
147 * Initial revision
150 #define P_DISABLE_FACTORY_INSTANCES
152 #include <ptlib.h>
153 #include <ptlib/svcproc.h>
155 #include <errno.h>
158 ///////////////////////////////////////////////////////////////////////////////
159 // PProcess
161 #if defined(_WIN32)
162 #ifndef _WIN32_WCE
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)
170 return TRUE;
172 DWORD wndProcess;
173 GetWindowThreadProcessId(hWnd, &wndProcess);
174 if (wndProcess != (DWORD)thisProcess)
175 return TRUE;
177 cerr << "\nPress a key to continue . . .";
178 cerr.flush();
180 HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
181 SetConsoleMode(in, ENABLE_PROCESSED_INPUT);
182 FlushConsoleInputBuffer(in);
183 char dummy;
184 DWORD readBytes;
185 ReadConsole(in, &dummy, 1, &readBytes, NULL);
186 return FALSE;
188 #endif // _WIN32_WCE
190 void PWaitOnExitConsoleWindow()
192 #ifndef _WIN32_WCE
193 EnumWindows(EnumWindowsProc, GetCurrentProcessId());
194 #else
195 #endif // _WIN32_WCE
198 #ifndef _WIN32_WCE
199 class PImageDLL : public PDynaLink
201 PCLASSINFO(PImageDLL, PDynaLink)
202 public:
203 PImageDLL();
205 BOOL (__stdcall *SymInitialize)(
206 IN HANDLE hProcess,
207 IN LPSTR UserSearchPath,
208 IN BOOL fInvadeProcess
210 BOOL (__stdcall *SymCleanup)(
211 IN HANDLE hProcess
213 DWORD (__stdcall *SymGetOptions)();
214 DWORD (__stdcall *SymSetOptions)(
215 DWORD options
217 DWORD (__stdcall *SymLoadModule)(
218 HANDLE hProcess,
219 HANDLE hFile,
220 PSTR ImageName,
221 PSTR ModuleName,
222 DWORD BaseOfDll,
223 DWORD SizeOfDll
225 BOOL (__stdcall *StackWalk)(
226 DWORD MachineType,
227 HANDLE hProcess,
228 HANDLE hThread,
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)(
237 IN HANDLE hProcess,
238 IN DWORD dwAddr,
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)(
247 IN HANDLE hProcess,
248 IN DWORD dwAddr,
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))
267 Close();
271 #endif
272 #endif
274 void PAssertFunc(const char * msg)
276 #ifndef _WIN32_WCE
278 ostrstream str;
279 str << msg;
281 #if defined(_WIN32) && defined(_M_IX86)
282 PImageDLL imagehlp;
283 if (imagehlp.IsLoaded()) {
284 // Turn on load lines.
285 imagehlp.SymSetOptions(imagehlp.SymGetOptions()|SYMOPT_LOAD_LINES);
286 HANDLE hProcess;
287 OSVERSIONINFO ver;
288 ver.dwOSVersionInfoSize = sizeof(ver);
289 ::GetVersionEx(&ver);
290 if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT)
291 hProcess = GetCurrentProcess();
292 else
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)) {
300 STACKFRAME frame;
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;
316 #else
317 #error ( "Unknown machine!" )
318 #endif
320 int frameCount = 0;
321 while (frameCount++ < 16 &&
322 imagehlp.StackWalk(IMAGE_FILE_MACHINE,
323 hProcess,
324 hThread,
325 &frame,
326 &threadContext,
327 NULL, // ReadMemoryRoutine
328 imagehlp.SymFunctionTableAccess,
329 imagehlp.SymGetModuleBase,
330 NULL)) {
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,
338 frame.AddrPC.Offset,
339 &displacement,
340 symbol)) {
341 str << "\n " << symbol->Name;
343 else {
344 str << "\n 0x"
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++) {
351 if (i > 0)
352 str << ", ";
353 if (frame.Params[i] != 0)
354 str << "0x";
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;
368 else {
369 DWORD e = ::GetLastError();
370 str << "\n No stack dump: IMAGEHLP.DLL GetThreadContext failed: error=" << e;
373 imagehlp.SymCleanup(hProcess);
375 else {
376 DWORD e = ::GetLastError();
377 str << "\n No stack dump: IMAGEHLP.DLL SymInitialise failed: error=" << e;
380 else {
381 DWORD e = ::GetLastError();
382 str << "\n No stack dump: IMAGEHLP.DLL could not be loaded: error=" << e;
384 #endif
386 str << ends;
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)
396 __asm int 3;
397 #endif
398 return;
401 #if defined(_WIN32)
402 static HANDLE mutex = CreateSemaphore(NULL, 1, 1, NULL);
403 WaitForSingleObject(mutex, INFINITE);
404 #endif
406 if (PProcess::Current().IsGUIProcess()) {
407 switch (MessageBox(NULL, pstr, "Portable Windows Library",
408 MB_ABORTRETRYIGNORE|MB_ICONHAND|MB_TASKMODAL)) {
409 case IDABORT :
410 FatalExit(1); // Never returns
412 case IDRETRY :
413 DebugBreak();
415 #if defined(_WIN32)
416 ReleaseSemaphore(mutex, 1, NULL);
417 #endif
418 return;
421 for (;;) {
422 cerr << pstr << "\n<A>bort, <B>reak, <I>gnore? ";
423 cerr.flush();
424 switch (cin.get()) {
425 case 'A' :
426 case 'a' :
427 cerr << "Aborted" << endl;
428 _exit(100);
430 case 'B' :
431 case 'b' :
432 cerr << "Break" << endl;
433 #if defined(_WIN32)
434 ReleaseSemaphore(mutex, 1, NULL);
435 #endif
436 #ifdef _MSC_VER
437 __asm int 3;
438 #endif
440 case 'I' :
441 case 'i' :
442 case EOF :
443 cerr << "Ignored" << endl;
444 #if defined(_WIN32)
445 ReleaseSemaphore(mutex, 1, NULL);
446 #endif
447 return;
451 #else
453 #ifdef _DEBUG
456 if ( AfxAssertFailedLine(file, line) )
457 AfxDebugBreak();
458 } while (0);
459 #endif // _DEBUG
461 #endif // _WIN32_WCE
465 // End Of File ///////////////////////////////////////////////////////////////