assert.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:13k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * assert.cxx
  3.  *
  4.  * Function to implement assert clauses.
  5.  *
  6.  * Portable Windows Library
  7.  *
  8.  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9.  *
  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/
  14.  *
  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.
  19.  *
  20.  * The Original Code is Portable Windows Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25.  * All Rights Reserved.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: assert.cxx,v $
  30.  * Revision 1.27  2000/05/23 05:50:43  robertj
  31.  * Attempted to fix stack dump, still refuses to work even though used to work perfectly.
  32.  *
  33.  * Revision 1.26  2000/03/04 08:07:07  robertj
  34.  * Fixed problem with window not appearing when assert on GUI based win32 apps.
  35.  *
  36.  * Revision 1.25  1999/02/16 08:08:06  robertj
  37.  * MSVC 6.0 compatibility changes.
  38.  *
  39.  * Revision 1.24  1999/02/12 01:01:57  craigs
  40.  * Fixed problem with linking static versions of libraries
  41.  *
  42.  * Revision 1.23  1998/12/04 10:10:45  robertj
  43.  * Added virtual for determining if process is a service. Fixes linkage problem.
  44.  *
  45.  * Revision 1.22  1998/11/30 05:33:08  robertj
  46.  * Fixed duplicate debug stream class, ther can be only one.
  47.  *
  48.  * Revision 1.21  1998/11/30 04:48:38  robertj
  49.  * New directory structure
  50.  *
  51.  * Revision 1.20  1998/09/24 03:30:39  robertj
  52.  * Added open software license.
  53.  *
  54.  * Revision 1.19  1997/03/18 21:22:31  robertj
  55.  * Display error message if assert stack dump fails
  56.  *
  57.  * Revision 1.18  1997/02/09 01:27:18  robertj
  58.  * Added stack dump under NT.
  59.  *
  60.  * Revision 1.17  1997/02/05 11:49:40  robertj
  61.  * Changed current process function to return reference and validate objects descendancy.
  62.  *
  63.  * Revision 1.16  1997/01/04 06:52:04  robertj
  64.  * Removed the press a key to continue under win  '95.
  65.  *
  66.  * Revision 1.15  1996/11/18 11:30:00  robertj
  67.  * Removed int 3 on non-debug versions.
  68.  *
  69.  * Revision 1.14  1996/11/16 10:51:51  robertj
  70.  * Changed assert to display message and break if in debug mode service.
  71.  *
  72.  * Revision 1.13  1996/11/10 21:02:08  robertj
  73.  * Fixed bug in assertion when as a service, string buffer not big enough.
  74.  *
  75.  * Revision 1.12  1996/10/08 13:00:46  robertj
  76.  * Changed default for assert to be ignore, not abort.
  77.  *
  78.  * Revision 1.11  1996/07/27 04:08:13  robertj
  79.  * Changed SystemLog to be stream based rather than printf based.
  80.  *
  81.  * Revision 1.10  1996/05/30 11:48:28  robertj
  82.  * Fixed press a key to continue to only require one key.
  83.  *
  84.  * Revision 1.9  1996/05/23 10:03:20  robertj
  85.  * Windows 95 support.
  86.  *
  87.  * Revision 1.8  1996/03/04 12:39:35  robertj
  88.  * Fixed Win95 support for console tasks.
  89.  *
  90.  * Revision 1.7  1996/01/28 14:13:04  robertj
  91.  * Made PServiceProcess special case global not just WIN32.
  92.  *
  93.  * Revision 1.6  1995/12/10 11:55:09  robertj
  94.  * Numerous fixes for WIN32 service processes.
  95.  *
  96.  * Revision 1.5  1995/04/25 11:32:34  robertj
  97.  * Fixed Borland compiler warnings.
  98.  *
  99.  * Revision 1.4  1995/03/12 05:00:04  robertj
  100.  * Re-organisation of DOS/WIN16 and WIN32 platforms to maximise common code.
  101.  * Used built-in equate for WIN32 API (_WIN32).
  102.  *
  103.  * Revision 1.3  1994/10/30  11:25:09  robertj
  104.  * Added error number to assert.
  105.  *
  106.  * Revision 1.2  1994/06/25  12:13:01  robertj
  107.  * Synchronisation.
  108.  *
  109.  * Revision 1.1  1994/04/01  14:39:35  robertj
  110.  * Initial revision
  111.  */
  112. #include <ptlib.h>
  113. #include <ptlib/svcproc.h>
  114. #include <errno.h>
  115. #include <strstrea.h>
  116. ///////////////////////////////////////////////////////////////////////////////
  117. // PProcess
  118. #if defined(_WIN32)
  119. static BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM thisProcess)
  120. {
  121.   char wndClassName[100];
  122.   GetClassName(hWnd, wndClassName, sizeof(wndClassName));
  123.   if (strcmp(wndClassName, "ConsoleWindowClass") != 0)
  124.     return TRUE;
  125.   DWORD wndProcess;
  126.   GetWindowThreadProcessId(hWnd, &wndProcess);
  127.   if (wndProcess != (DWORD)thisProcess)
  128.     return TRUE;
  129.   cerr << "nPress a key to continue . . .";
  130.   cerr.flush();
  131.   HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
  132.   SetConsoleMode(in, ENABLE_PROCESSED_INPUT);
  133.   FlushConsoleInputBuffer(in);
  134.   char dummy;
  135.   DWORD readBytes;
  136.   ReadConsole(in, &dummy, 1, &readBytes, NULL);
  137.   return FALSE;
  138. }
  139. void PWaitOnExitConsoleWindow()
  140. {
  141.   EnumWindows(EnumWindowsProc, GetCurrentProcessId());
  142. }
  143. #include <imagehlp.h>
  144. class PImageDLL : public PDynaLink
  145. {
  146.   PCLASSINFO(PImageDLL, PDynaLink)
  147.   public:
  148.     PImageDLL();
  149.   BOOL (__stdcall *SymInitialize)(
  150.     IN HANDLE   hProcess,
  151.     IN LPSTR    UserSearchPath,
  152.     IN BOOL     fInvadeProcess
  153.     );
  154.   BOOL (__stdcall *SymCleanup)(
  155.     IN HANDLE hProcess
  156.     );
  157.   DWORD (__stdcall *SymGetOptions)();
  158.   DWORD (__stdcall *SymSetOptions)(
  159.     DWORD options
  160.     );
  161.   DWORD (__stdcall *SymLoadModule)(
  162.     HANDLE hProcess,
  163.     HANDLE hFile,     
  164.     PSTR   ImageName,  
  165.     PSTR   ModuleName, 
  166.     DWORD  BaseOfDll,  
  167.     DWORD  SizeOfDll   
  168.     );
  169.   BOOL (__stdcall *StackWalk)(
  170.     DWORD                             MachineType,
  171.     HANDLE                            hProcess,
  172.     HANDLE                            hThread,
  173.     LPSTACKFRAME                      StackFrame,
  174.     LPVOID                            ContextRecord,
  175.     PREAD_PROCESS_MEMORY_ROUTINE      ReadMemoryRoutine,
  176.     PFUNCTION_TABLE_ACCESS_ROUTINE    FunctionTableAccessRoutine,
  177.     PGET_MODULE_BASE_ROUTINE          GetModuleBaseRoutine,
  178.     PTRANSLATE_ADDRESS_ROUTINE        TranslateAddress
  179.     );
  180.   BOOL (__stdcall *SymGetSymFromAddr)(
  181.     IN  HANDLE              hProcess,
  182.     IN  DWORD               dwAddr,
  183.     OUT PDWORD              pdwDisplacement,
  184.     OUT PIMAGEHLP_SYMBOL    Symbol
  185.     );
  186.   PFUNCTION_TABLE_ACCESS_ROUTINE SymFunctionTableAccess;
  187.   PGET_MODULE_BASE_ROUTINE       SymGetModuleBase;
  188.   BOOL (__stdcall *SymGetModuleInfo)(
  189.     IN  HANDLE              hProcess,
  190.     IN  DWORD               dwAddr,
  191.     OUT PIMAGEHLP_MODULE    ModuleInfo
  192.     );
  193. };
  194. PImageDLL::PImageDLL()
  195.   : PDynaLink("IMAGEHLP.DLL")
  196. {
  197.   if (!GetFunction("SymInitialize", (Function &)SymInitialize) ||
  198.       !GetFunction("SymCleanup", (Function &)SymCleanup) ||
  199.       !GetFunction("SymGetOptions", (Function &)SymGetOptions) ||
  200.       !GetFunction("SymSetOptions", (Function &)SymSetOptions) ||
  201.       !GetFunction("SymLoadModule", (Function &)SymLoadModule) ||
  202.       !GetFunction("StackWalk", (Function &)StackWalk) ||
  203.       !GetFunction("SymGetSymFromAddr", (Function &)SymGetSymFromAddr) ||
  204.       !GetFunction("SymFunctionTableAccess", (Function &)SymFunctionTableAccess) ||
  205.       !GetFunction("SymGetModuleBase", (Function &)SymGetModuleBase) ||
  206.       !GetFunction("SymGetModuleInfo", (Function &)SymGetModuleInfo))
  207.     Close();
  208. }
  209. #endif
  210. void PAssertFunc(const char * file, int line, const char * msg)
  211. {
  212. #if defined(_WIN32)
  213.   DWORD err = GetLastError();
  214. #else
  215.   int err = errno;
  216. #endif
  217.   ostrstream str;
  218.   str << "Assertion fail: ";
  219.   if (msg != NULL)
  220.     str << msg << ", ";
  221.   str << "file " << file << ", line " << line;
  222.   if (err != 0)
  223.     str << ", Error=" << err;
  224. #if defined(_WIN32) && defined(_M_IX86)
  225.   PImageDLL imagehlp;
  226.   if (imagehlp.IsLoaded()) {
  227.     // Turn on load lines.
  228.     imagehlp.SymSetOptions(imagehlp.SymGetOptions()|SYMOPT_LOAD_LINES);
  229.     HANDLE hProcess;
  230.     OSVERSIONINFO ver;
  231.     ::GetVersionEx(&ver);
  232.     if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT)
  233.       hProcess = GetCurrentProcess();
  234.     else
  235.       hProcess = (HANDLE)GetCurrentProcessId();
  236.     if (imagehlp.SymInitialize(hProcess, NULL, TRUE)) {
  237.       HANDLE hThread = GetCurrentThread();
  238.       // The thread information.
  239.       CONTEXT threadContext;
  240.       threadContext.ContextFlags = CONTEXT_FULL ;
  241.       if (GetThreadContext(hThread, &threadContext)) {
  242.         STACKFRAME frame;
  243.         memset(&frame, 0, sizeof(frame));
  244. #if defined (_M_IX86)
  245. #define IMAGE_FILE_MACHINE IMAGE_FILE_MACHINE_I386
  246.         frame.AddrPC.Offset    = threadContext.Eip;
  247.         frame.AddrPC.Mode      = AddrModeFlat;
  248.         frame.AddrStack.Offset = threadContext.Esp;
  249.         frame.AddrStack.Mode   = AddrModeFlat;
  250.         frame.AddrFrame.Offset = threadContext.Ebp;
  251.         frame.AddrFrame.Mode   = AddrModeFlat;
  252. #elif defined (_M_ALPHA)
  253. #define IMAGE_FILE_MACHINE IMAGE_FILE_MACHINE_ALPHA
  254.         frame.AddrPC.Offset = (unsigned long)threadContext.Fir;
  255.         frame.AddrPC.Mode   = AddrModeFlat;
  256. #else
  257. #error ( "Unknown machine!" )
  258. #endif
  259.         int frameCount = 0;
  260.         while (frameCount++ < 16 &&
  261.                imagehlp.StackWalk(IMAGE_FILE_MACHINE,
  262.                                   hProcess,
  263.                                   hThread,
  264.                                   &frame,
  265.                                   &threadContext,
  266.                                   NULL, // ReadMemoryRoutine
  267.                                   imagehlp.SymFunctionTableAccess,
  268.                                   imagehlp.SymGetModuleBase,
  269.                                   NULL)) {
  270.           if (frameCount > 1 && frame.AddrPC.Offset != 0) {
  271.             char buffer[sizeof(IMAGEHLP_SYMBOL)+100];
  272.             PIMAGEHLP_SYMBOL symbol = (PIMAGEHLP_SYMBOL)buffer;
  273.             symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  274.             symbol->MaxNameLength = sizeof(buffer)-sizeof(IMAGEHLP_SYMBOL);
  275.             DWORD displacement = 0;
  276.             if (imagehlp.SymGetSymFromAddr(hProcess,
  277.                                            frame.AddrPC.Offset,
  278.                                            &displacement,
  279.                                            symbol)) {
  280.               str << "n    " << symbol->Name;
  281.             }
  282.             else {
  283.               str << "n    0x"
  284.                   << hex << setfill('0')
  285.                   << setw(8) << frame.AddrPC.Offset
  286.                   << dec << setfill(' ');
  287.             }
  288.             str << '(' << hex << setfill('0');
  289.             for (PINDEX i = 0; i < PARRAYSIZE(frame.Params); i++) {
  290.               if (i > 0)
  291.                 str << ", ";
  292.               if (frame.Params[i] != 0)
  293.                 str << "0x";
  294.               str << frame.Params[i];
  295.             }
  296.             str << setfill(' ') << ')';
  297.             if (displacement != 0)
  298.               str << " + 0x" << displacement;
  299.           }
  300.         }
  301.         if (frameCount <= 2) {
  302.           DWORD e = ::GetLastError();
  303.           str << "n    No stack dump: IMAGEHLP.DLL StackWalk failed: error=" << e;
  304.         }
  305.       }
  306.       else {
  307.         DWORD e = ::GetLastError();
  308.         str << "n    No stack dump: IMAGEHLP.DLL GetThreadContext failed: error=" << e;
  309.       }
  310.       imagehlp.SymCleanup(hProcess);
  311.     }
  312.     else {
  313.       DWORD e = ::GetLastError();
  314.       str << "n    No stack dump: IMAGEHLP.DLL SymInitialise failed: error=" << e;
  315.     }
  316.   }
  317.   else {
  318.     DWORD e = ::GetLastError();
  319.     str << "n    No stack dump: IMAGEHLP.DLL could not be loaded: error=" << e;
  320.   }
  321. #endif
  322.   str << ends;
  323.   if (PProcess::Current().IsServiceProcess()) {
  324.     PSystemLog::Output(PSystemLog::Fatal, str.str());
  325. #if defined(_MSC_VER) && defined(_DEBUG)
  326.     if (PServiceProcess::Current().debugMode)
  327.       __asm int 3;
  328. #endif
  329.     return;
  330.   }
  331. #if defined(_WIN32)
  332.   static HANDLE mutex = CreateSemaphore(NULL, 1, 1, NULL);
  333.   WaitForSingleObject(mutex, INFINITE);
  334. #endif
  335.   if (PProcess::Current().IsGUIProcess()) {
  336.     switch (MessageBox(NULL, str.str(), "Portable Windows Library",
  337.                               MB_ABORTRETRYIGNORE|MB_ICONHAND|MB_TASKMODAL)) {
  338.       case IDABORT :
  339.         FatalExit(1);  // Never returns
  340.       case IDRETRY :
  341.         DebugBreak();
  342.     }
  343. #if defined(_WIN32)
  344.     ReleaseSemaphore(mutex, 1, NULL);
  345. #endif
  346.     return;
  347.   }
  348.   for (;;) {
  349.     cerr << str.str() << "n<A>bort, <B>reak, <I>gnore? ";
  350.     cerr.flush();
  351.     switch (cin.get()) {
  352.       case 'A' :
  353.       case 'a' :
  354.         cerr << "Aborted" << endl;
  355.         _exit(100);
  356.         
  357.       case 'B' :
  358.       case 'b' :
  359.         cerr << "Break" << endl;
  360. #if defined(_WIN32)
  361.         ReleaseSemaphore(mutex, 1, NULL);
  362. #endif
  363. #ifdef _MSC_VER
  364.         __asm int 3;
  365. #endif
  366.       case 'I' :
  367.       case 'i' :
  368.       case EOF :
  369.         cerr << "Ignored" << endl;
  370. #if defined(_WIN32)
  371.         ReleaseSemaphore(mutex, 1, NULL);
  372. #endif
  373.         return;
  374.     }
  375.   }
  376. }
  377. // End Of File ///////////////////////////////////////////////////////////////