/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_tools.hxx" #define _TOOLS_DEBUG_CXX #if defined (UNX) || defined (GCC) #include #else #include #endif #include #include // combinations #include #include #include #ifdef OS2 #define INCL_DOSSEMAPHORES #define INCL_DOSMISC #define INCL_WINDIALOGS #define INCL_WINSHELLDATA #include #endif #if defined ( WNT ) #ifdef _MSC_VER #pragma warning (push,1) #endif #include #ifdef _MSC_VER #pragma warning (pop) #endif #endif #include #include #include #include // ======================================================================= #ifdef DBG_UTIL // --- DbgErrors --- static sal_Char const DbgError_ProfEnd1[] = "DBG_PROF...() without DBG_PROFSTART(): "; static sal_Char const DbgError_Xtor1[] = "DBG_DTOR() or DBG_CHKTHIS() without DBG_CTOR(): "; static sal_Char const DbgError_CtorDtor1[] = "this == NULL in class "; static sal_Char const DbgError_CtorDtor2[] = "invalid this-Pointer %p in class "; static sal_Char const DbgError_CtorDtor3[] = "Error-Msg from Object %p in class "; static sal_Char const DbgTrace_EnterCtor[] = "Enter Ctor from class "; static sal_Char const DbgTrace_LeaveCtor[] = "Leave Ctor from class "; static sal_Char const DbgTrace_EnterDtor[] = "Enter Dtor from class "; static sal_Char const DbgTrace_LeaveDtor[] = "Leave Dtor from class "; static sal_Char const DbgTrace_EnterMeth[] = "Enter method from class "; static sal_Char const DbgTrace_LeaveMeth[] = "Leave method from class "; // --- PointerList --- #define PBLOCKCOUNT 1024 struct PBlock { void* aData[PBLOCKCOUNT]; sal_uInt16 nCount; PBlock* pPrev; PBlock* pNext; }; class PointerList { private: PBlock* pFirst; PBlock* pLast; sal_uIntPtr nCount; public: PointerList() { pFirst = NULL; pLast = NULL; nCount = 0; } ~PointerList(); void Add( const void* p ); sal_Bool Remove( const void* p ); const void* Get( sal_uIntPtr nPos ) const; sal_Bool IsIn( const void* p ) const; sal_uIntPtr Count() const { return nCount; } }; // --- Datentypen --- #define DBG_MAXNAME 28 struct ProfType { sal_uIntPtr nCount; sal_uIntPtr nTime; sal_uIntPtr nMinTime; sal_uIntPtr nMaxTime; sal_uIntPtr nStart; sal_uIntPtr nContinueTime; sal_uIntPtr nContinueStart; sal_Char aName[DBG_MAXNAME+1]; }; struct XtorType { sal_uIntPtr nCtorCalls; sal_uIntPtr nDtorCalls; sal_uIntPtr nMaxCount; sal_uIntPtr nStatics; sal_Char aName[DBG_MAXNAME+1]; sal_Bool bTest; PointerList aThisList; }; struct DebugData { DbgData aDbgData; sal_uInt16 bInit; DbgPrintLine pDbgPrintMsgBox; DbgPrintLine pDbgPrintWindow; DbgPrintLine pDbgPrintTestTool; DbgPrintLine pDbgAbort; ::std::vector< DbgPrintLine > aDbgPrintUserChannels; PointerList* pProfList; PointerList* pXtorList; DbgTestSolarMutexProc pDbgTestSolarMutex; pfunc_osl_printDetailedDebugMessage pOldDebugMessageFunc; bool bOslIsHooked; DebugData() :bInit( sal_False ) ,pDbgPrintMsgBox( NULL ) ,pDbgPrintWindow( NULL ) ,pDbgPrintTestTool( NULL ) ,pDbgAbort( NULL ) ,pProfList( NULL ) ,pXtorList( NULL ) ,pDbgTestSolarMutex( NULL ) ,pOldDebugMessageFunc( NULL ) ,bOslIsHooked( false ) { aDbgData.nTestFlags = DBG_TEST_RESOURCE | DBG_TEST_MEM_INIT; aDbgData.bOverwrite = sal_True; aDbgData.nTraceOut = DBG_OUT_NULL; aDbgData.nWarningOut = DBG_OUT_NULL; aDbgData.nErrorOut = DBG_OUT_MSGBOX; aDbgData.bMemInit = 0x77; aDbgData.bMemBound = 0x55; aDbgData.bMemFree = 0x33; aDbgData.bHookOSLAssert = sal_True; aDbgData.aDebugName[0] = 0; aDbgData.aInclFilter[0] = 0; aDbgData.aExclFilter[0] = 0; aDbgData.aInclClassFilter[0] = 0; aDbgData.aExclClassFilter[0] = 0; aDbgData.aDbgWinState[0] = 0; } }; #define DBG_TEST_XTOR_EXTRA (DBG_TEST_XTOR_THIS | DBG_TEST_XTOR_FUNC | \ DBG_TEST_XTOR_EXIT | DBG_TEST_XTOR_REPORT ) // ------------------------------ // - statische Verwaltungsdaten - // ------------------------------ static DebugData aDebugData; static sal_Char aCurPath[260]; static int bDbgImplInMain = sal_False; // ======================================================================= #if defined( WNT ) static CRITICAL_SECTION aImplCritDbgSection; #elif defined( OS2 ) static HMTX hImplCritDbgSection = 0; #endif static sal_Bool bImplCritDbgSectionInit = sal_False; // ----------------------------------------------------------------------- void ImplDbgInitLock() { #if defined( WNT ) InitializeCriticalSection( &aImplCritDbgSection ); #elif defined( OS2 ) DosCreateMutexSem( NULL, &hImplCritDbgSection, 0, sal_False ); #endif bImplCritDbgSectionInit = sal_True; } // ----------------------------------------------------------------------- void ImplDbgDeInitLock() { #if defined( WNT ) DeleteCriticalSection( &aImplCritDbgSection ); #elif defined( OS2 ) DosCloseMutexSem( hImplCritDbgSection ); #endif bImplCritDbgSectionInit = sal_False; } // ----------------------------------------------------------------------- void ImplDbgLock() { if ( !bImplCritDbgSectionInit ) return; #if defined( WNT ) EnterCriticalSection( &aImplCritDbgSection ); #elif defined( OS2 ) DosRequestMutexSem( hImplCritDbgSection, SEM_INDEFINITE_WAIT ); #endif } // ----------------------------------------------------------------------- void ImplDbgUnlock() { if ( !bImplCritDbgSectionInit ) return; #if defined( WNT ) LeaveCriticalSection( &aImplCritDbgSection ); #elif defined( OS2 ) DosReleaseMutexSem( hImplCritDbgSection ); #endif } // ======================================================================= #if (defined WNT || defined OS2) && !defined SVX_LIGHT //#define SV_MEMMGR // #endif #ifdef SV_MEMMGR void DbgImpCheckMemory( void* p = NULL ); void DbgImpCheckMemoryDeInit(); void DbgImpMemoryInfo( sal_Char* pBuf ); #endif #define FILE_LINEEND "\n" // ======================================================================= static sal_Bool ImplActivateDebugger( const sal_Char* pMsg ) { #if defined( WNT ) static sal_Char aImplDbgOutBuf[DBG_BUF_MAXLEN]; strcpy( aImplDbgOutBuf, pMsg ); strcat( aImplDbgOutBuf, "\r\n" ); OutputDebugString( aImplDbgOutBuf ); DebugBreak(); return sal_True; #else (void) pMsg; // avoid warning about unused parameter return sal_False; #endif } // ----------------------------------------------------------------------- static sal_Bool ImplCoreDump() { #if defined( WNT ) DebugBreak(); #else long* pTemp = 0; *pTemp = 0xCCCC; #endif return sal_True; } // ======================================================================= static sal_uIntPtr ImplGetPerfTime() { #if defined( WNT ) return (sal_uIntPtr)GetTickCount(); #elif defined( OS2 ) sal_uIntPtr nClock; DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &nClock, sizeof( nClock ) ); return (sal_uIntPtr)nClock; #else static sal_uIntPtr nImplTicksPerSecond = 0; static double dImplTicksPerSecond; sal_uIntPtr nTicks = (sal_uIntPtr)clock(); if ( !nImplTicksPerSecond ) { nImplTicksPerSecond = CLOCKS_PER_SEC; dImplTicksPerSecond = nImplTicksPerSecond; } double fTicks = nTicks; fTicks *= 1000; fTicks /= dImplTicksPerSecond; return (sal_uIntPtr)fTicks; #endif } // ----------------------------------------------------------------------- typedef FILE* FILETYPE; #define FileOpen fopen #define FileRead fread #define FileWrite fwrite #define FilePrintF fprintf #define FileClose fclose // ======================================================================= namespace { enum ConfigSection { eOutput, eMemory, eGUI, eObjects, eTest, eUnknown }; void lcl_lineFeed( FILETYPE _pFile ) { FilePrintF( _pFile, "%s", FILE_LINEEND ); } const sal_Char* lcl_getSectionName( ConfigSection _eSection ) { const sal_Char* pSectionName = NULL; switch ( _eSection ) { case eOutput : pSectionName = "output"; break; case eMemory : pSectionName = "memory"; break; case eGUI : pSectionName = "gui"; break; case eObjects : pSectionName = "objects"; break; case eTest : pSectionName = "test"; break; case eUnknown: OSL_ASSERT(false); break; } return pSectionName; } ConfigSection lcl_getSectionFromName( const sal_Char* _pSectionName, size_t _nSectionNameLength ) { if ( strncmp( _pSectionName, "output", _nSectionNameLength < 6 ? _nSectionNameLength : 6 ) == 0 ) return eOutput; if ( strncmp( _pSectionName, "memory", _nSectionNameLength < 6 ? _nSectionNameLength : 6 ) == 0 ) return eMemory; if ( strncmp( _pSectionName, "gui", _nSectionNameLength < 3 ? _nSectionNameLength : 3 ) == 0 ) return eGUI; if ( strncmp( _pSectionName, "objects", _nSectionNameLength < 7 ? _nSectionNameLength : 7 ) == 0 ) return eObjects; if ( strncmp( _pSectionName, "test", _nSectionNameLength < 4 ? _nSectionNameLength : 4 ) == 0 ) return eTest; return eUnknown; } void lcl_startSection( FILETYPE _pFile, ConfigSection _eSection ) { FilePrintF( _pFile, "[%s]%s", lcl_getSectionName( _eSection ), FILE_LINEEND ); } void lcl_writeConfigString( FILETYPE _pFile, const sal_Char* _pKeyName, const sal_Char* _pValue ) { FilePrintF( _pFile, "%s=%s%s", _pKeyName, _pValue, FILE_LINEEND ); } void lcl_writeConfigBoolean( FILETYPE _pFile, const sal_Char* _pKeyName, bool _bValue ) { lcl_writeConfigString( _pFile, _pKeyName, _bValue ? "1" : "0" ); } void lcl_writeConfigFlag( FILETYPE _pFile, const sal_Char* _pKeyName, sal_uIntPtr _nAllFlags, sal_uIntPtr _nCheckFlag ) { lcl_writeConfigBoolean( _pFile, _pKeyName, ( _nAllFlags & _nCheckFlag ) != 0 ); } void lcl_writeConfigOutChannel( FILETYPE _pFile, const sal_Char* _pKeyName, sal_uIntPtr _nValue ) { const sal_Char* names[ DBG_OUT_COUNT ] = { "dev/null", "file", "window", "shell", "messagebox", "testtool", "debugger", "abort" }; lcl_writeConfigString( _pFile, _pKeyName, names[ _nValue ] ); } void lcl_writeHexByte( FILETYPE _pFile, const sal_Char* _pKeyName, sal_uInt8 _nValue ) { sal_Char buf[RTL_STR_MAX_VALUEOFINT32]; rtl_String* stringData = NULL; rtl_string_newFromStr_WithLength( &stringData, buf, rtl_str_valueOfInt32( buf, _nValue, 16 ) ); lcl_writeConfigString( _pFile, _pKeyName, stringData->buffer ); rtl_string_release( stringData ); } bool lcl_isConfigSection( const sal_Char* _pLine, size_t _nLineLen ) { if ( _nLineLen < 2 ) // not even enough space for '[' and ']' return false; if ( ( _pLine[0] == '[' ) && ( _pLine[ _nLineLen - 1 ] == ']' ) ) return true; return false; } bool lcl_isConfigKey( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName ) { size_t nKeyLength = strlen( _pKeyName ); if ( nKeyLength + 1 >= _nLineLen ) // not even long enough for the key name plus "=" plus a one-character value return false; if ( ( strncmp( _pLine, _pKeyName, nKeyLength ) == 0 ) && ( _pLine[ nKeyLength ] == '=' ) ) return true; return false; } sal_Int32 lcl_tryReadConfigString( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName, sal_Char* _pValue, size_t _nValueLen ) { if ( !lcl_isConfigKey( _pLine, _nLineLen, _pKeyName ) ) return 0; size_t nValuePos = strlen( _pKeyName ) + 1; size_t nValueLen = _nLineLen - nValuePos; const sal_Char* pValue = _pLine + nValuePos; strncpy( _pValue, pValue, ( _nValueLen > nValueLen ) ? nValueLen : _nValueLen ); _pValue[ ( _nValueLen > nValueLen ) ? nValueLen : _nValueLen - 1 ] = 0; return strlen( _pValue ); } void lcl_tryReadConfigBoolean( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName, sal_uIntPtr* _out_pnValue ) { sal_Char aBuf[2]; size_t nValueLen = lcl_tryReadConfigString( _pLine, _nLineLen, _pKeyName, aBuf, sizeof( aBuf ) ); if ( nValueLen ) *_out_pnValue = strcmp( aBuf, "1" ) == 0 ? sal_True : sal_False; } void lcl_matchOutputChannel( sal_Char const * i_buffer, sal_uIntPtr* o_value ) { if ( i_buffer == NULL ) return; const sal_Char* names[ DBG_OUT_COUNT ] = { "dev/null", "file", "window", "shell", "messagebox", "testtool", "debugger", "abort" }; for ( sal_uIntPtr name = 0; name < sizeof( names ) / sizeof( names[0] ); ++name ) { if ( strcmp( i_buffer, names[ name ] ) == 0 ) { *o_value = name; return; } } } void lcl_tryReadOutputChannel( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName, sal_uIntPtr* _out_pnValue ) { sal_Char aBuf[20]; size_t nValueLen = lcl_tryReadConfigString( _pLine, _nLineLen, _pKeyName, aBuf, sizeof( aBuf ) ); if ( nValueLen ) lcl_matchOutputChannel( aBuf, _out_pnValue ); } void lcl_tryReadConfigFlag( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName, sal_uIntPtr* _out_pnAllFlags, sal_uIntPtr _nCheckFlag ) { sal_Char aBuf[2]; size_t nValueLen = lcl_tryReadConfigString( _pLine, _nLineLen, _pKeyName, aBuf, sizeof( aBuf ) ); if ( nValueLen ) if ( strcmp( aBuf, "1" ) == 0 ) *_out_pnAllFlags |= _nCheckFlag; else *_out_pnAllFlags &= ~_nCheckFlag; } void lcl_tryReadHexByte( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName, sal_uInt8* _out_pnValue ) { sal_Char aBuf[3]; size_t nValueLen = lcl_tryReadConfigString( _pLine, _nLineLen, _pKeyName, aBuf, sizeof( aBuf ) ); if ( nValueLen ) *_out_pnValue = (sal_uInt8)rtl_str_toInt32( aBuf, 16 ); } } // ======================================================================= PointerList::~PointerList() { PBlock* pBlock = pFirst; while ( pBlock ) { PBlock* pNextBlock = pBlock->pNext; delete pBlock; pBlock = pNextBlock; } } // ----------------------------------------------------------------------- void PointerList::Add( const void* p ) { if ( !pFirst ) { pFirst = new PBlock; memset( pFirst->aData, 0, PBLOCKCOUNT * sizeof( void* ) ); pFirst->nCount = 0; pFirst->pPrev = NULL; pFirst->pNext = NULL; pLast = pFirst; } PBlock* pBlock = pFirst; while ( pBlock && (pBlock->nCount == PBLOCKCOUNT) ) pBlock = pBlock->pNext; if ( !pBlock ) { pBlock = new PBlock; memset( pBlock->aData, 0, PBLOCKCOUNT * sizeof( void* ) ); pBlock->nCount = 0; pBlock->pPrev = pLast; pBlock->pNext = NULL; pLast->pNext = pBlock; pLast = pBlock; } sal_uInt16 i = 0; while ( pBlock->aData[i] ) i++; pBlock->aData[i] = (void*)p; pBlock->nCount++; nCount++; } // ----------------------------------------------------------------------- sal_Bool PointerList::Remove( const void* p ) { if ( !p ) return sal_False; PBlock* pBlock = pFirst; while ( pBlock ) { sal_uInt16 i = 0; while ( i < PBLOCKCOUNT ) { if ( ((sal_uIntPtr)p) == ((sal_uIntPtr)pBlock->aData[i]) ) { pBlock->aData[i] = NULL; pBlock->nCount--; nCount--; if ( !pBlock->nCount ) { if ( pBlock->pPrev ) pBlock->pPrev->pNext = pBlock->pNext; if ( pBlock->pNext ) pBlock->pNext->pPrev = pBlock->pPrev; if ( pBlock == pFirst ) pFirst = pBlock->pNext; if ( pBlock == pLast ) pLast = pBlock->pPrev; delete pBlock; } return sal_True; } i++; } pBlock = pBlock->pNext; } return sal_False; } // ----------------------------------------------------------------------- const void* PointerList::Get( sal_uIntPtr nPos ) const { if ( nCount <= nPos ) return NULL; PBlock* pBlock = pFirst; sal_uIntPtr nStart = 0; while ( pBlock ) { sal_uInt16 i = 0; while ( i < PBLOCKCOUNT ) { if ( pBlock->aData[i] ) { nStart++; if ( (nStart-1) == nPos ) return pBlock->aData[i]; } i++; } pBlock = pBlock->pNext; } return NULL; } // ----------------------------------------------------------------------- sal_Bool PointerList::IsIn( const void* p ) const { if ( !p ) return sal_False; PBlock* pBlock = pFirst; while ( pBlock ) { sal_uInt16 i = 0; while ( i < PBLOCKCOUNT ) { if ( ((sal_uIntPtr)p) == ((sal_uIntPtr)pBlock->aData[i]) ) return sal_True; i++; } pBlock = pBlock->pNext; } return sal_False; } // ======================================================================= static void DbgGetDbgFileName( sal_Char* pStr, sal_Int32 nMaxLen ) { #if defined( UNX ) const sal_Char* pName = getenv("DBGSV_INIT"); if ( !pName ) pName = ".dbgsv.init"; strncpy( pStr, pName, nMaxLen ); #elif defined( WNT ) const sal_Char* pName = getenv("DBGSV_INIT"); if ( pName ) strncpy( pStr, pName, nMaxLen ); else GetProfileStringA( "sv", "dbgsv", "dbgsv.ini", pStr, nMaxLen ); #elif defined( OS2 ) PrfQueryProfileString( HINI_PROFILE, (PSZ)"SV", (PSZ)"DBGSV", "dbgsv.ini", (PSZ)pStr, nMaxLen ); #else strncpy( pStr, "dbgsv.ini", nMaxLen ); #endif pStr[ nMaxLen - 1 ] = 0; } // ----------------------------------------------------------------------- static void DbgGetLogFileName( sal_Char* pStr ) { #if defined( UNX ) const sal_Char* pName = getenv("DBGSV_LOG"); if ( !pName ) pName = "dbgsv.log"; strcpy( pStr, pName ); #elif defined( WNT ) const sal_Char* pName = getenv("DBGSV_LOG"); if ( pName ) strcpy( pStr, pName ); else GetProfileStringA( "sv", "dbgsvlog", "dbgsv.log", pStr, 200 ); #elif defined( OS2 ) PrfQueryProfileString( HINI_PROFILE, (PSZ)"SV", (PSZ)"DBGSVLOG", "dbgsv.log", (PSZ)pStr, 200 ); #else strcpy( pStr, "dbgsv.log" ); #endif } // ----------------------------------------------------------------------- static void DbgDebugBeep() { #if defined( WNT ) MessageBeep( MB_ICONHAND ); #elif defined( OS2 ) WinAlarm( HWND_DESKTOP, WA_ERROR ); #endif } // ----------------------------------------------------------------------- static DebugData* GetDebugData() { if ( !aDebugData.bInit ) { aDebugData.bInit = sal_True; // Default Debug-Namen setzen DbgGetLogFileName( aDebugData.aDbgData.aDebugName ); // DEBUG.INI-File sal_Char aBuf[ 4096 ]; DbgGetDbgFileName( aBuf, sizeof( aBuf ) ); FILETYPE pIniFile = FileOpen( aBuf, "r" ); if ( pIniFile != NULL ) { ConfigSection eCurrentSection = eUnknown; // no sophisticated algorithm here, assume that the whole file fits into aBuf ... sal_uIntPtr nReallyRead = FileRead( aBuf, 1, sizeof( aBuf ) / sizeof( sal_Char ) - 1, pIniFile ); aBuf[ nReallyRead ] = 0; const sal_Char* pLine = aBuf; while ( const sal_Char* pNextLine = strstr( pLine, FILE_LINEEND ) ) { size_t nLineLength = pNextLine - pLine; if ( lcl_isConfigSection( pLine, nLineLength ) ) eCurrentSection = lcl_getSectionFromName( pLine + 1, nLineLength - 2 ); // elements of the [output] section if ( eCurrentSection == eOutput ) { lcl_tryReadConfigString( pLine, nLineLength, "log_file", aDebugData.aDbgData.aDebugName, sizeof( aDebugData.aDbgData.aDebugName ) ); lcl_tryReadConfigBoolean( pLine, nLineLength, "overwrite", &aDebugData.aDbgData.bOverwrite ); lcl_tryReadConfigString( pLine, nLineLength, "include", aDebugData.aDbgData.aInclFilter, sizeof( aDebugData.aDbgData.aInclFilter ) ); lcl_tryReadConfigString( pLine, nLineLength, "exclude", aDebugData.aDbgData.aExclFilter, sizeof( aDebugData.aDbgData.aExclFilter ) ); lcl_tryReadConfigString( pLine, nLineLength, "include_class", aDebugData.aDbgData.aInclClassFilter, sizeof( aDebugData.aDbgData.aInclClassFilter ) ); lcl_tryReadConfigString( pLine, nLineLength, "exclude_class", aDebugData.aDbgData.aExclClassFilter, sizeof( aDebugData.aDbgData.aExclClassFilter ) ); lcl_tryReadOutputChannel( pLine, nLineLength, "trace", &aDebugData.aDbgData.nTraceOut ); lcl_tryReadOutputChannel( pLine, nLineLength, "warning", &aDebugData.aDbgData.nWarningOut ); lcl_tryReadOutputChannel( pLine, nLineLength, "error", &aDebugData.aDbgData.nErrorOut ); lcl_tryReadConfigBoolean( pLine, nLineLength, "oslhook", &aDebugData.aDbgData.bHookOSLAssert ); } // elements of the [memory] section if ( eCurrentSection == eMemory ) { lcl_tryReadConfigFlag( pLine, nLineLength, "initialize", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_INIT ); lcl_tryReadConfigFlag( pLine, nLineLength, "overwrite", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_OVERWRITE ); lcl_tryReadConfigFlag( pLine, nLineLength, "overwrite_free", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_OVERWRITEFREE ); lcl_tryReadConfigFlag( pLine, nLineLength, "pointer", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_POINTER ); lcl_tryReadConfigFlag( pLine, nLineLength, "report", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_REPORT ); lcl_tryReadConfigFlag( pLine, nLineLength, "trace", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_TRACE ); lcl_tryReadConfigFlag( pLine, nLineLength, "new_and_delete", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_NEWDEL ); lcl_tryReadConfigFlag( pLine, nLineLength, "object_test", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_XTOR ); lcl_tryReadConfigFlag( pLine, nLineLength, "sys_alloc", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_SYSALLOC ); lcl_tryReadConfigFlag( pLine, nLineLength, "leak_report", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_LEAKREPORT ); lcl_tryReadHexByte( pLine, nLineLength, "init_byte", &aDebugData.aDbgData.bMemInit ); lcl_tryReadHexByte( pLine, nLineLength, "bound_byte", &aDebugData.aDbgData.bMemBound ); lcl_tryReadHexByte( pLine, nLineLength, "free_byte", &aDebugData.aDbgData.bMemFree ); } // elements of the [gui] section if ( eCurrentSection == eGUI ) { lcl_tryReadConfigString( pLine, nLineLength, "debug_window_state", aDebugData.aDbgData.aDbgWinState, sizeof( aDebugData.aDbgData.aDbgWinState ) ); } // elements of the [objects] section if ( eCurrentSection == eObjects ) { lcl_tryReadConfigFlag( pLine, nLineLength, "check_this", &aDebugData.aDbgData.nTestFlags, DBG_TEST_XTOR_THIS ); lcl_tryReadConfigFlag( pLine, nLineLength, "check_function", &aDebugData.aDbgData.nTestFlags, DBG_TEST_XTOR_FUNC ); lcl_tryReadConfigFlag( pLine, nLineLength, "check_exit", &aDebugData.aDbgData.nTestFlags, DBG_TEST_XTOR_EXIT ); lcl_tryReadConfigFlag( pLine, nLineLength, "generate_report", &aDebugData.aDbgData.nTestFlags, DBG_TEST_XTOR_REPORT ); lcl_tryReadConfigFlag( pLine, nLineLength, "trace", &aDebugData.aDbgData.nTestFlags, DBG_TEST_XTOR_TRACE ); } // elements of the [test] section if ( eCurrentSection == eTest ) { lcl_tryReadConfigFlag( pLine, nLineLength, "profiling", &aDebugData.aDbgData.nTestFlags, DBG_TEST_PROFILING ); lcl_tryReadConfigFlag( pLine, nLineLength, "resources", &aDebugData.aDbgData.nTestFlags, DBG_TEST_RESOURCE ); lcl_tryReadConfigFlag( pLine, nLineLength, "dialog", &aDebugData.aDbgData.nTestFlags, DBG_TEST_DIALOG ); lcl_tryReadConfigFlag( pLine, nLineLength, "bold_app_font", &aDebugData.aDbgData.nTestFlags, DBG_TEST_BOLDAPPFONT ); } pLine = pNextLine + strlen( FILE_LINEEND ); } FileClose( pIniFile ); } else { lcl_matchOutputChannel( getenv( "DBGSV_TRACE_OUT" ), &aDebugData.aDbgData.nTraceOut ); lcl_matchOutputChannel( getenv( "DBGSV_WARNING_OUT" ), &aDebugData.aDbgData.nWarningOut ); lcl_matchOutputChannel( getenv( "DBGSV_ERROR_OUT" ), &aDebugData.aDbgData.nErrorOut ); } getcwd( aCurPath, sizeof( aCurPath ) ); // Daten initialisieren if ( aDebugData.aDbgData.nTestFlags & DBG_TEST_XTOR ) aDebugData.pXtorList = new PointerList; if ( aDebugData.aDbgData.nTestFlags & DBG_TEST_PROFILING ) aDebugData.pProfList = new PointerList; } return &aDebugData; } // ----------------------------------------------------------------------- inline DebugData* ImplGetDebugData() { if ( !aDebugData.bInit ) return GetDebugData(); else return &aDebugData; } // ----------------------------------------------------------------------- static FILETYPE ImplDbgInitFile() { static sal_Bool bFileInit = sal_False; sal_Char aBuf[4096]; getcwd( aBuf, sizeof( aBuf ) ); chdir( aCurPath ); DebugData* pData = GetDebugData(); FILETYPE pDebugFile; if ( !bFileInit ) { bFileInit = sal_True; if ( pData->aDbgData.bOverwrite ) pDebugFile = FileOpen( pData->aDbgData.aDebugName, "w" ); else pDebugFile = FileOpen( pData->aDbgData.aDebugName, "a" ); if ( pDebugFile ) { time_t nTime = time( 0 ); tm* pTime; #ifdef UNX tm aTime; pTime = localtime_r( &nTime, &aTime ); #else pTime = localtime( &nTime ); #endif // Header ausgeben FilePrintF( pDebugFile, "******************************************************************************%s", FILE_LINEEND ); FilePrintF( pDebugFile, "%s%s", pData->aDbgData.aDebugName, FILE_LINEEND ); if ( pTime ) FilePrintF( pDebugFile, "%s%s", asctime( pTime ), FILE_LINEEND ); } } else pDebugFile = FileOpen( pData->aDbgData.aDebugName, "a" ); chdir( aBuf ); return pDebugFile; } // ----------------------------------------------------------------------- static void ImplDbgPrintFile( const sal_Char* pLine ) { FILETYPE pDebugFile = ImplDbgInitFile(); if ( pDebugFile ) { FilePrintF( pDebugFile, "%s%s", pLine, FILE_LINEEND ); FileClose( pDebugFile ); } } // ----------------------------------------------------------------------- static int ImplStrSearch( const sal_Char* pSearchStr, int nSearchLen, const sal_Char* pStr, int nLen ) { int nPos = 0; while ( nPos+nSearchLen <= nLen ) { if ( strncmp( pStr+nPos, pSearchStr, nSearchLen ) == 0 ) return 1; nPos++; } return 0; } // ----------------------------------------------------------------------- static int ImplDbgFilter( const sal_Char* pFilter, const sal_Char* pMsg, int bEmpty ) { int nStrLen = strlen( pFilter ); if ( !nStrLen ) return bEmpty; int nMsgLen = strlen( pMsg ); const sal_Char* pTok = pFilter; int nTok = 0; while ( pTok[nTok] ) { if ( pTok[nTok] == ';' ) { if ( nTok && ImplStrSearch( pTok, nTok, pMsg, nMsgLen ) ) return sal_True; pTok += nTok+1; nTok = 0; } nTok++; } if ( nTok && ImplStrSearch( pTok, nTok, pMsg, nMsgLen ) ) return sal_True; else return sal_False; } // ----------------------------------------------------------------------- extern "C" void SAL_CALL dbg_printOslDebugMessage( const sal_Char * pszFileName, sal_Int32 nLine, const sal_Char * pszMessage ) { DbgOut( pszMessage ? pszMessage : "assertion failed!", DBG_OUT_ERROR, pszFileName, (sal_uInt16)nLine ); } // ----------------------------------------------------------------------- static void DebugInit() { bDbgImplInMain = sal_True; ImplDbgInitLock(); DebugData* pData = GetDebugData(); if( pData->aDbgData.bHookOSLAssert && ! pData->bOslIsHooked ) { pData->pOldDebugMessageFunc = osl_setDetailedDebugMessageFunc( &dbg_printOslDebugMessage ); pData->bOslIsHooked = true; } } // ----------------------------------------------------------------------- static void DebugDeInit() { DebugData* pData = GetDebugData(); sal_uIntPtr i; sal_uIntPtr nCount; sal_uIntPtr nOldOut; if( pData->bOslIsHooked ) { osl_setDetailedDebugMessageFunc( pData->pOldDebugMessageFunc ); pData->bOslIsHooked = sal_False; } // Statistik-Ausgaben immer in File nOldOut = pData->aDbgData.nTraceOut; pData->aDbgData.nTraceOut = DBG_OUT_FILE; // Xtor-Liste ausgeben if ( pData->pXtorList && pData->pXtorList->Count() && (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_REPORT) ) { DbgOutf( "------------------------------------------------------------------------------" ); DbgOutf( "Object Report" ); DbgOutf( "------------------------------------------------------------------------------" ); DbgOutf( "%-27s : %-9s : %-9s : %-7s : %-3s : %-6s :", "XTor-List", "Ctor", "Dtor", "MaxInst", "St.", "Diff." ); DbgOutf( "----------------------------:-----------:-----------:---------:----:---------:" ); for( i = 0, nCount = pData->pXtorList->Count(); i < nCount; i++ ) { XtorType* pXtorData = (XtorType*)pData->pXtorList->Get( i ); if ( pXtorData->bTest ) { // Static-Objekte dazurechnen pXtorData->nDtorCalls += pXtorData->nStatics; if ( pXtorData->nStatics && (pXtorData->nDtorCalls > pXtorData->nCtorCalls) ) pXtorData->nDtorCalls = pXtorData->nCtorCalls; DbgOutf( "%-27s : %9lu : %9lu : %7lu : %3lu : %4lu %-1s :", pXtorData->aName, pXtorData->nCtorCalls, pXtorData->nDtorCalls, pXtorData->nMaxCount, pXtorData->nStatics, pXtorData->nCtorCalls - pXtorData->nDtorCalls, (pXtorData->nCtorCalls - pXtorData->nDtorCalls) ? "!" : " " ); } } DbgOutf( "==============================================================================" ); } // Aufraeumen if ( pData->pXtorList ) { for( i = 0, nCount = pData->pXtorList->Count(); i < nCount; i++ ) { XtorType* pXtorData = (XtorType*)pData->pXtorList->Get( i ); delete pXtorData; } delete pData->pXtorList; pData->pXtorList = NULL; } // Alles auf sal_False setzen, damit globale Variablen nicht das // System zum Abstuerzen bringt. Dabei muessen aber die // Memory-Flags erhalten bleiben, da sonst new/delete in globalen // Variablen abstuerzen, da die Pointeranpassung dann nicht mehr richtig // funktioniert pData->aDbgData.nTraceOut = nOldOut; pData->aDbgData.nTestFlags &= (DBG_TEST_MEM | DBG_TEST_PROFILING); pData->aDbgPrintUserChannels.clear(); pData->pDbgPrintTestTool = NULL; pData->pDbgPrintWindow = NULL; pData->pOldDebugMessageFunc = NULL; ImplDbgDeInitLock(); } // ----------------------------------------------------------------------- static void DebugGlobalDeInit() { DebugData* pData = GetDebugData(); sal_uIntPtr i; sal_uIntPtr nCount; sal_uIntPtr nOldOut; // Statistik-Ausgaben immer in File nOldOut = pData->aDbgData.nTraceOut; pData->aDbgData.nTraceOut = DBG_OUT_FILE; // Profileliste ausgeben if ( pData->pProfList && pData->pProfList->Count() ) { DbgOutf( "------------------------------------------------------------------------------" ); DbgOutf( "Profiling Report" ); DbgOutf( "------------------------------------------------------------------------------" ); DbgOutf( "%-25s : %-9s : %-6s : %-6s : %-6s : %-9s :", "Prof-List (ms)", "Time", "Min", "Max", "Ave", "Count" ); DbgOutf( "--------------------------:-----------:--------:--------:--------:-----------:" ); for( i = 0, nCount = pData->pProfList->Count(); i < nCount; i++ ) { ProfType* pProfData = (ProfType*)pData->pProfList->Get( i ); sal_uIntPtr nAve = pProfData->nTime / pProfData->nCount; DbgOutf( "%-25s : %9lu : %6lu : %6lu : %6lu : %9lu :", pProfData->aName, pProfData->nTime, pProfData->nMinTime, pProfData->nMaxTime, nAve, pProfData->nCount ); } DbgOutf( "==============================================================================" ); } // Aufraeumen if ( pData->pProfList ) { for( i = 0, nCount = pData->pProfList->Count(); i < nCount; i++ ) { ProfType* pProfData = (ProfType*)pData->pProfList->Get( i ); delete pProfData; } delete pData->pProfList; pData->pProfList = NULL; } #ifdef SV_MEMMGR DbgImpCheckMemoryDeInit(); #endif // Profiling-Flags ausschalten pData->aDbgData.nTraceOut = nOldOut; pData->aDbgData.nTestFlags &= ~DBG_TEST_PROFILING; } // ----------------------------------------------------------------------- void ImpDbgOutfBuf( sal_Char* pBuf, const sal_Char* pFStr, ... ) { va_list pList; va_start( pList, pFStr ); sal_Char aBuf[DBG_BUF_MAXLEN]; vsprintf( aBuf, pFStr, pList ); va_end( pList ); strcat( pBuf, aBuf ); strcat( pBuf, "\n" ); } // ----------------------------------------------------------------------- static void DebugXTorInfo( sal_Char* pBuf ) { DebugData* pData = GetDebugData(); sal_uIntPtr i; sal_uIntPtr nCount; // Xtor-Liste ausgeben if ( pData->pXtorList && pData->pXtorList->Count() && (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_REPORT) ) { ImpDbgOutfBuf( pBuf, "------------------------------------------------------------------------------" ); ImpDbgOutfBuf( pBuf, "Object Report" ); ImpDbgOutfBuf( pBuf, "------------------------------------------------------------------------------" ); ImpDbgOutfBuf( pBuf, "%-27s : %-9s : %-9s : %-7s : %-3s : %-6s :", "XTor-List", "Ctor", "Dtor", "MaxInst", "St.", "Diff." ); ImpDbgOutfBuf( pBuf, "----------------------------:-----------:-----------:---------:----:---------:" ); for( i = 0, nCount = pData->pXtorList->Count(); i < nCount; i++ ) { XtorType* pXtorData = (XtorType*)pData->pXtorList->Get( i ); if ( pXtorData->bTest ) { ImpDbgOutfBuf( pBuf, "%-27s : %9lu : %9lu : %7lu : %3lu : %6lu :", pXtorData->aName, pXtorData->nCtorCalls, pXtorData->nDtorCalls, pXtorData->nMaxCount, pXtorData->nStatics, pXtorData->nCtorCalls - pXtorData->nDtorCalls ); } } ImpDbgOutfBuf( pBuf, "==============================================================================" ); ImpDbgOutfBuf( pBuf, "" ); } } // ----------------------------------------------------------------------- sal_Bool ImplDbgFilterMessage( const sal_Char* pMsg ) { DebugData* pData = GetDebugData(); if ( !ImplDbgFilter( pData->aDbgData.aInclFilter, pMsg, sal_True ) ) return sal_True; if ( ImplDbgFilter( pData->aDbgData.aExclFilter, pMsg, sal_False ) ) return sal_True; return sal_False; } // ----------------------------------------------------------------------- void* DbgFunc( sal_uInt16 nAction, void* pParam ) { DebugData* pDebugData = ImplGetDebugData(); if ( nAction == DBG_FUNC_GETDATA ) return (void*)&(pDebugData->aDbgData); else if ( nAction == DBG_FUNC_GETPRINTMSGBOX ) return (void*)(sal_IntPtr)(pDebugData->pDbgPrintMsgBox); else if ( nAction == DBG_FUNC_FILTERMESSAGE ) if ( ImplDbgFilterMessage( (const sal_Char*) pParam ) ) return (void*) -1; else return (void*) 0; // aka NULL else { switch ( nAction ) { case DBG_FUNC_DEBUGSTART: DebugInit(); break; case DBG_FUNC_DEBUGEND: DebugDeInit(); break; case DBG_FUNC_GLOBALDEBUGEND: DebugGlobalDeInit(); break; case DBG_FUNC_SETPRINTMSGBOX: pDebugData->pDbgPrintMsgBox = (DbgPrintLine)(sal_IntPtr)pParam; break; case DBG_FUNC_SETPRINTWINDOW: pDebugData->pDbgPrintWindow = (DbgPrintLine)(sal_IntPtr)pParam; break; case DBG_FUNC_SETPRINTTESTTOOL: pDebugData->pDbgPrintTestTool = (DbgPrintLine)(sal_IntPtr)pParam; break; case DBG_FUNC_SET_ABORT: pDebugData->pDbgAbort = (DbgPrintLine)(sal_IntPtr)pParam; break; case DBG_FUNC_SAVEDATA: { const DbgData* pData = static_cast< const DbgData* >( pParam ); sal_Char aBuf[ 4096 ]; DbgGetDbgFileName( aBuf, sizeof( aBuf ) ); FILETYPE pIniFile = FileOpen( aBuf, "w" ); if ( pIniFile == NULL ) break; lcl_startSection( pIniFile, eOutput ); lcl_writeConfigString( pIniFile, "log_file", pData->aDebugName ); lcl_writeConfigBoolean( pIniFile, "overwrite", pData->bOverwrite ); lcl_writeConfigString( pIniFile, "include", pData->aInclFilter ); lcl_writeConfigString( pIniFile, "exclude", pData->aExclFilter ); lcl_writeConfigString( pIniFile, "include_class", pData->aInclClassFilter ); lcl_writeConfigString( pIniFile, "exclude_class", pData->aExclClassFilter ); lcl_writeConfigOutChannel( pIniFile, "trace", pData->nTraceOut ); lcl_writeConfigOutChannel( pIniFile, "warning", pData->nWarningOut ); lcl_writeConfigOutChannel( pIniFile, "error", pData->nErrorOut ); lcl_writeConfigBoolean( pIniFile, "oslhook", pData->bHookOSLAssert ); lcl_lineFeed( pIniFile ); lcl_startSection( pIniFile, eMemory ); lcl_writeConfigFlag( pIniFile, "initialize", pData->nTestFlags, DBG_TEST_MEM_INIT ); lcl_writeConfigFlag( pIniFile, "overwrite", pData->nTestFlags, DBG_TEST_MEM_OVERWRITE ); lcl_writeConfigFlag( pIniFile, "overwrite_free", pData->nTestFlags, DBG_TEST_MEM_OVERWRITEFREE ); lcl_writeConfigFlag( pIniFile, "pointer", pData->nTestFlags, DBG_TEST_MEM_POINTER ); lcl_writeConfigFlag( pIniFile, "report", pData->nTestFlags, DBG_TEST_MEM_REPORT ); lcl_writeConfigFlag( pIniFile, "trace", pData->nTestFlags, DBG_TEST_MEM_TRACE ); lcl_writeConfigFlag( pIniFile, "new_and_delete", pData->nTestFlags, DBG_TEST_MEM_NEWDEL ); lcl_writeConfigFlag( pIniFile, "object_test", pData->nTestFlags, DBG_TEST_MEM_XTOR ); lcl_writeConfigFlag( pIniFile, "sys_alloc", pData->nTestFlags, DBG_TEST_MEM_SYSALLOC ); lcl_writeConfigFlag( pIniFile, "leak_report", pData->nTestFlags, DBG_TEST_MEM_LEAKREPORT ); lcl_lineFeed( pIniFile ); lcl_writeHexByte( pIniFile, "init_byte", pData->bMemInit ); lcl_writeHexByte( pIniFile, "bound_byte", pData->bMemBound ); lcl_writeHexByte( pIniFile, "free_byte", pData->bMemFree ); lcl_lineFeed( pIniFile ); lcl_startSection( pIniFile, eGUI ); lcl_writeConfigString( pIniFile, "debug_window_state", pData->aDbgWinState ); lcl_lineFeed( pIniFile ); lcl_startSection( pIniFile, eObjects ); lcl_writeConfigFlag( pIniFile, "check_this", pData->nTestFlags, DBG_TEST_XTOR_THIS ); lcl_writeConfigFlag( pIniFile, "check_function", pData->nTestFlags, DBG_TEST_XTOR_FUNC ); lcl_writeConfigFlag( pIniFile, "check_exit", pData->nTestFlags, DBG_TEST_XTOR_EXIT ); lcl_writeConfigFlag( pIniFile, "generate_report", pData->nTestFlags, DBG_TEST_XTOR_REPORT ); lcl_writeConfigFlag( pIniFile, "trace", pData->nTestFlags, DBG_TEST_XTOR_TRACE ); lcl_lineFeed( pIniFile ); lcl_startSection( pIniFile, eTest ); lcl_writeConfigFlag( pIniFile, "profiling", pData->nTestFlags, DBG_TEST_PROFILING ); lcl_writeConfigFlag( pIniFile, "resources", pData->nTestFlags, DBG_TEST_RESOURCE ); lcl_writeConfigFlag( pIniFile, "dialog", pData->nTestFlags, DBG_TEST_DIALOG ); lcl_writeConfigFlag( pIniFile, "bold_app_font", pData->nTestFlags, DBG_TEST_BOLDAPPFONT ); FileClose( pIniFile ); } break; case DBG_FUNC_MEMTEST: #ifdef SV_MEMMGR DbgImpCheckMemory( pParam ); #endif break; case DBG_FUNC_XTORINFO: DebugXTorInfo( (sal_Char*)pParam ); break; case DBG_FUNC_MEMINFO: #ifdef SV_MEMMGR DbgImpMemoryInfo( (sal_Char*)pParam ); #endif break; case DBG_FUNC_COREDUMP: ImplCoreDump(); break; case DBG_FUNC_ALLERROROUT: return (void*)(sal_uIntPtr)sal_True; case DBG_FUNC_SETTESTSOLARMUTEX: pDebugData->pDbgTestSolarMutex = (DbgTestSolarMutexProc)(sal_IntPtr)pParam; break; case DBG_FUNC_TESTSOLARMUTEX: if ( pDebugData->pDbgTestSolarMutex ) pDebugData->pDbgTestSolarMutex(); break; case DBG_FUNC_PRINTFILE: ImplDbgPrintFile( (const sal_Char*)pParam ); break; case DBG_FUNC_UPDATEOSLHOOK: { const DbgData* pData = static_cast< const DbgData* >( pParam ); pDebugData->aDbgData.bHookOSLAssert = pData->bHookOSLAssert; if( pDebugData->bOslIsHooked && ! pData->bHookOSLAssert ) { osl_setDetailedDebugMessageFunc( pDebugData->pOldDebugMessageFunc ); pDebugData->bOslIsHooked = sal_False; } else if( ! pDebugData->bOslIsHooked && pData->bHookOSLAssert ) { pDebugData->pOldDebugMessageFunc = osl_setDetailedDebugMessageFunc( &dbg_printOslDebugMessage ); pDebugData->bOslIsHooked = sal_True; } } break; } return NULL; } } // ----------------------------------------------------------------------- DbgChannelId DbgRegisterUserChannel( DbgPrintLine pProc ) { DebugData* pData = ImplGetDebugData(); pData->aDbgPrintUserChannels.push_back( pProc ); return (DbgChannelId)( pData->aDbgPrintUserChannels.size() - 1 + DBG_OUT_USER_CHANNEL_0 ); } // ----------------------------------------------------------------------- void DbgProf( sal_uInt16 nAction, DbgDataType* pDbgData ) { // Ueberhaupt Profiling-Test an DebugData* pData = ImplGetDebugData(); if ( !(pData->aDbgData.nTestFlags & DBG_TEST_PROFILING) ) return; sal_Char aBuf[DBG_BUF_MAXLEN]; ProfType* pProfData = (ProfType*)pDbgData->pData; sal_uIntPtr nTime; if ( (nAction != DBG_PROF_START) && !pProfData ) { strcpy( aBuf, DbgError_ProfEnd1 ); strcat( aBuf, pDbgData->pName ); DbgError( aBuf ); return; } switch ( nAction ) { case DBG_PROF_START: if ( !pDbgData->pData ) { pDbgData->pData = (void*)new ProfType; pProfData = (ProfType*)pDbgData->pData; strncpy( pProfData->aName, pDbgData->pName, DBG_MAXNAME ); pProfData->aName[DBG_MAXNAME] = '\0'; pProfData->nCount = 0; pProfData->nTime = 0; pProfData->nMinTime = 0xFFFFFFFF; pProfData->nMaxTime = 0; pProfData->nStart = 0xFFFFFFFF; pProfData->nContinueTime = 0; pProfData->nContinueStart = 0xFFFFFFFF; pData->pProfList->Add( (void*)pProfData ); } if ( pProfData->nStart == 0xFFFFFFFF ) { pProfData->nStart = ImplGetPerfTime(); pProfData->nCount++; } break; case DBG_PROF_STOP: nTime = ImplGetPerfTime(); if ( pProfData->nStart == 0xFFFFFFFF ) { DbgError( DbgError_ProfEnd1 ); return; } if ( pProfData->nContinueStart != 0xFFFFFFFF ) { pProfData->nContinueTime += ImplGetPerfTime() - pProfData->nContinueStart; pProfData->nContinueStart = 0xFFFFFFFF; } nTime -= pProfData->nStart; nTime -= pProfData->nContinueTime; if ( nTime < pProfData->nMinTime ) pProfData->nMinTime = nTime; if ( nTime > pProfData->nMaxTime ) pProfData->nMaxTime = nTime; pProfData->nTime += nTime; pProfData->nStart = 0xFFFFFFFF; pProfData->nContinueTime = 0; pProfData->nContinueStart = 0xFFFFFFFF; break; case DBG_PROF_CONTINUE: if ( pProfData->nContinueStart != 0xFFFFFFFF ) { pProfData->nContinueTime += ImplGetPerfTime() - pProfData->nContinueStart; pProfData->nContinueStart = 0xFFFFFFFF; } break; case DBG_PROF_PAUSE: if ( pProfData->nContinueStart == 0xFFFFFFFF ) pProfData->nContinueStart = ImplGetPerfTime(); break; } } // ----------------------------------------------------------------------- void DbgXtor( DbgDataType* pDbgData, sal_uInt16 nAction, const void* pThis, DbgUsr fDbgUsr ) { DebugData* pData = ImplGetDebugData(); // Verbindung zu Debug-Memory-Manager testen #ifdef SV_MEMMGR if ( pData->aDbgData.nTestFlags & DBG_TEST_MEM_XTOR ) DbgImpCheckMemory(); #endif // Schnell-Test if ( !(pData->aDbgData.nTestFlags & DBG_TEST_XTOR) ) return; XtorType* pXtorData = (XtorType*)pDbgData->pData; if ( !pXtorData ) { pDbgData->pData = (void*)new XtorType; pXtorData = (XtorType*)pDbgData->pData; strncpy( pXtorData->aName, pDbgData->pName, DBG_MAXNAME ); pXtorData->aName[DBG_MAXNAME] = '\0'; pXtorData->nCtorCalls = 0; pXtorData->nDtorCalls = 0; pXtorData->nMaxCount = 0; pXtorData->nStatics = 0; pXtorData->bTest = sal_True; pData->pXtorList->Add( (void*)pXtorData ); if ( !ImplDbgFilter( pData->aDbgData.aInclClassFilter, pXtorData->aName, sal_True ) ) pXtorData->bTest = sal_False; if ( ImplDbgFilter( pData->aDbgData.aExclClassFilter, pXtorData->aName, sal_False ) ) pXtorData->bTest = sal_False; } if ( !pXtorData->bTest ) return; sal_Char aBuf[DBG_BUF_MAXLEN]; sal_uInt16 nAct = nAction & ~DBG_XTOR_DTOROBJ; // Trace (Enter) if ( (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_TRACE) && !(nAction & DBG_XTOR_DTOROBJ) ) { if ( nAct != DBG_XTOR_CHKOBJ ) { if ( nAct == DBG_XTOR_CTOR ) strcpy( aBuf, DbgTrace_EnterCtor ); else if ( nAct == DBG_XTOR_DTOR ) strcpy( aBuf, DbgTrace_EnterDtor ); else strcpy( aBuf, DbgTrace_EnterMeth ); strcat( aBuf, pDbgData->pName ); DbgTrace( aBuf ); } } // Sind noch Xtor-Tests als Trace an if ( pData->aDbgData.nTestFlags & DBG_TEST_XTOR_EXTRA ) { // DBG_CTOR-Aufruf vor allen anderen DBG_XTOR-Aufrufen if ( ((nAction & ~DBG_XTOR_DTOROBJ) != DBG_XTOR_CTOR) && !pDbgData->pData ) { strcpy( aBuf, DbgError_Xtor1 ); strcat( aBuf, pDbgData->pName ); DbgError( aBuf ); return; } // Testen, ob This-Pointer gueltig if ( pData->aDbgData.nTestFlags & DBG_TEST_XTOR_THIS ) { if ( (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_EXIT) || !(nAction & DBG_XTOR_DTOROBJ) ) { // This-Pointer == NULL if ( !pThis ) { strcpy( aBuf, DbgError_CtorDtor1 ); strcat( aBuf, pDbgData->pName ); DbgError( aBuf ); return; } if ( (nAction & ~DBG_XTOR_DTOROBJ) != DBG_XTOR_CTOR ) { if ( !pXtorData->aThisList.IsIn( pThis ) ) { sprintf( aBuf, DbgError_CtorDtor2, pThis ); strcat( aBuf, pDbgData->pName ); DbgError( aBuf ); } } } } // Function-Test durchfuehren und Verwaltungsdaten updaten const sal_Char* pMsg = NULL; switch ( nAction & ~DBG_XTOR_DTOROBJ ) { case DBG_XTOR_CTOR: if ( nAction & DBG_XTOR_DTOROBJ ) { if ( fDbgUsr && (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_EXIT) && (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_FUNC) ) pMsg = fDbgUsr( pThis ); } else { pXtorData->nCtorCalls++; if ( !bDbgImplInMain ) pXtorData->nStatics++; if ( (pXtorData->nCtorCalls-pXtorData->nDtorCalls) > pXtorData->nMaxCount ) pXtorData->nMaxCount = pXtorData->nCtorCalls - pXtorData->nDtorCalls; if ( pData->aDbgData.nTestFlags & DBG_TEST_XTOR_THIS ) pXtorData->aThisList.Add( pThis ); } break; case DBG_XTOR_DTOR: if ( nAction & DBG_XTOR_DTOROBJ ) { pXtorData->nDtorCalls++; if ( pData->aDbgData.nTestFlags & DBG_TEST_XTOR_THIS ) pXtorData->aThisList.Remove( pThis ); } else { if ( fDbgUsr && (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_FUNC) ) pMsg = fDbgUsr( pThis ); } break; case DBG_XTOR_CHKTHIS: case DBG_XTOR_CHKOBJ: if ( nAction & DBG_XTOR_DTOROBJ ) { if ( fDbgUsr && (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_EXIT) && (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_FUNC) ) pMsg = fDbgUsr( pThis ); } else { if ( fDbgUsr && (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_FUNC) ) pMsg = fDbgUsr( pThis ); } break; } // Gegebenenfalls Fehlermeldung ausgeben if ( pMsg ) { sprintf( aBuf, DbgError_CtorDtor3, pThis ); strcat( aBuf, pDbgData->pName ); strcat( aBuf, ": \n" ); strcat( aBuf, pMsg ); DbgError( aBuf ); } } // Trace (Leave) if ( (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_TRACE) && (nAction & DBG_XTOR_DTOROBJ) ) { if ( nAct != DBG_XTOR_CHKOBJ ) { if ( nAct == DBG_XTOR_CTOR ) strcpy( aBuf, DbgTrace_LeaveCtor ); else if ( nAct == DBG_XTOR_DTOR ) strcpy( aBuf, DbgTrace_LeaveDtor ); else strcpy( aBuf, DbgTrace_LeaveMeth ); strcat( aBuf, pDbgData->pName ); DbgTrace( aBuf ); } } } // ----------------------------------------------------------------------- void DbgOut( const sal_Char* pMsg, sal_uInt16 nDbgOut, const sal_Char* pFile, sal_uInt16 nLine ) { static sal_Bool bIn = sal_False; if ( bIn ) return; bIn = sal_True; DebugData* pData = GetDebugData(); sal_Char const * pStr; sal_uIntPtr nOut; int nBufLen = 0; if ( nDbgOut == DBG_OUT_ERROR ) { nOut = pData->aDbgData.nErrorOut; pStr = "Error: "; if ( pData->aDbgData.nErrorOut == DBG_OUT_FILE ) DbgDebugBeep(); } else if ( nDbgOut == DBG_OUT_WARNING ) { nOut = pData->aDbgData.nWarningOut; pStr = "Warning: "; } else { nOut = pData->aDbgData.nTraceOut; pStr = NULL; } if ( nOut == DBG_OUT_NULL ) { bIn = sal_False; return; } if ( ImplDbgFilterMessage( pMsg ) ) { bIn = sal_False; return; } ImplDbgLock(); sal_Char aBufOut[DBG_BUF_MAXLEN]; if ( pStr ) { strcpy( aBufOut, pStr ); nBufLen = strlen( pStr ); } else aBufOut[0] = '\0'; int nMsgLen = strlen( pMsg ); if ( nBufLen+nMsgLen > DBG_BUF_MAXLEN ) { int nCopyLen = DBG_BUF_MAXLEN-nBufLen-3; strncpy( &(aBufOut[nBufLen]), pMsg, nCopyLen ); strcpy( &(aBufOut[nBufLen+nCopyLen]), "..." ); } else strcpy( &(aBufOut[nBufLen]), pMsg ); if ( pFile && nLine && (nBufLen+nMsgLen < DBG_BUF_MAXLEN) ) { if ( nOut == DBG_OUT_MSGBOX ) strcat( aBufOut, "\n" ); else strcat( aBufOut, " " ); strcat( aBufOut, "From File " ); strcat( aBufOut, pFile ); strcat( aBufOut, " at Line " ); // Line in String umwandeln und dranhaengen sal_Char aLine[9]; sal_Char* pLine = &aLine[7]; sal_uInt16 i; memset( aLine, 0, sizeof( aLine ) ); do { i = nLine % 10; pLine--; *(pLine) = (sal_Char)i + 48; nLine /= 10; } while ( nLine ); strcat( aBufOut, pLine ); } if ( ( nOut >= DBG_OUT_USER_CHANNEL_0 ) && ( nOut - DBG_OUT_USER_CHANNEL_0 < pData->aDbgPrintUserChannels.size() ) ) { DbgPrintLine pPrinter = pData->aDbgPrintUserChannels[ nOut - DBG_OUT_USER_CHANNEL_0 ]; if ( pPrinter ) pPrinter( aBufOut ); else nOut = DBG_OUT_DEBUGGER; } if ( nOut == DBG_OUT_ABORT ) { if ( pData->pDbgAbort != NULL ) pData->pDbgAbort( aBufOut ); abort(); } if ( nOut == DBG_OUT_DEBUGGER ) { if ( !ImplActivateDebugger( aBufOut ) ) nOut = DBG_OUT_TESTTOOL; } if ( nOut == DBG_OUT_TESTTOOL ) { if ( pData->pDbgPrintTestTool ) pData->pDbgPrintTestTool( aBufOut ); else nOut = DBG_OUT_MSGBOX; } if ( nOut == DBG_OUT_MSGBOX ) { if ( pData->pDbgPrintMsgBox ) pData->pDbgPrintMsgBox( aBufOut ); else nOut = DBG_OUT_WINDOW; } if ( nOut == DBG_OUT_WINDOW ) { if ( pData->pDbgPrintWindow ) pData->pDbgPrintWindow( aBufOut ); else nOut = DBG_OUT_FILE; } switch ( nOut ) { case DBG_OUT_SHELL: DbgPrintShell( aBufOut ); break; case DBG_OUT_FILE: ImplDbgPrintFile( aBufOut ); break; } ImplDbgUnlock(); bIn = sal_False; } void DbgPrintShell(char const * message) { fprintf(stderr, "%s\n", message); #if defined WNT OutputDebugStringA(message); #endif } // ----------------------------------------------------------------------- void DbgOutTypef( sal_uInt16 nDbgOut, const sal_Char* pFStr, ... ) { va_list pList; va_start( pList, pFStr ); sal_Char aBuf[DBG_BUF_MAXLEN]; vsprintf( aBuf, pFStr, pList ); va_end( pList ); DbgOut( aBuf, nDbgOut ); } // ----------------------------------------------------------------------- void DbgOutf( const sal_Char* pFStr, ... ) { va_list pList; va_start( pList, pFStr ); sal_Char aBuf[DBG_BUF_MAXLEN]; vsprintf( aBuf, pFStr, pList ); va_end( pList ); DbgOut( aBuf ); } // ======================================================================= #else void* DbgFunc( sal_uInt16, void* ) { return NULL; } void DbgProf( sal_uInt16, DbgDataType* ) {} void DbgXtor( DbgDataType*, sal_uInt16, const void*, DbgUsr ) {} void DbgOut( const sal_Char*, sal_uInt16, const sal_Char*, sal_uInt16 ) {} void DbgOutTypef( sal_uInt16, const sal_Char*, ... ) {} void DbgOutf( const sal_Char*, ... ) {} #endif