/************************************************************** * * 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" #include #include // ----------------------------------------------------------------------- #if defined( DBG_UTIL ) && defined( WNT ) && defined( INTEL ) struct ImpDbgStackTree { ImpDbgStackTree* pLeft_; ImpDbgStackTree* pRight_; ImpDbgStackTree* pCaller_; ImpDbgStackTree* pSub_; sal_uIntPtr nIP_; sal_uIntPtr nBytesLeak_; sal_uIntPtr nBytesPeak_; sal_uIntPtr nBytes_; sal_uIntPtr nCountLeak_; sal_uIntPtr nCountPeak_; sal_uIntPtr nCount_; sal_uIntPtr nMax_; sal_uIntPtr nMin_; ImpDbgStackTree( ImpDbgStackTree* pSub, sal_uIntPtr nIP ); ~ImpDbgStackTree(); ImpDbgStackTree* Add( sal_uIntPtr nAlloc, sal_uIntPtr* pBP, sal_uIntPtr nIP ); void Print( int nLevel, sal_uIntPtr nCount, sal_uIntPtr nCountLeak ); void Print( int nLevel ); }; static ImpDbgStackTree* pImpDbgStackTreeRoot = NULL; static sal_uIntPtr* pImpDbgStackTreeBP = NULL; static sal_uIntPtr nImpDbgStackTreeMain = 0; static int nImpDbgStackTreeSem = 0; // ----------------------------------------------------------------------- ImpDbgStackTree::ImpDbgStackTree( ImpDbgStackTree* pSub, sal_uIntPtr nIP ) { pSub_ = pSub; nIP_ = nIP; pLeft_ = pRight_ = pCaller_ = NULL; nBytesLeak_ = nBytesPeak_ = nBytes_ = 0; nCountLeak_ = nCountPeak_ = nCount_ = 0; } // ----------------------------------------------------------------------- ImpDbgStackTree::~ImpDbgStackTree() { if ( pLeft_ ) delete pLeft_; if ( pRight_ ) delete pRight_; if ( pCaller_ ) delete pCaller_; } // ----------------------------------------------------------------------- void ImpDbgStackTree::Print( int nLevel, sal_uIntPtr nCount, sal_uIntPtr nCountLeak ) { if ( pLeft_ ) pLeft_->Print( nLevel, nCount, nCountLeak ); if ( nCount_ >= nCount && nCountLeak_ >= nCountLeak ) { if ( nMax_ == nMin_ ) { sal_uIntPtr nTemp = nCountLeak_ * nMin_; DbgOutf( "%*c%08lx Count=%lu/%lu/%lu Bytes=%lu/%lu/%lu Size=%lu", nLevel, ' ', nIP_, nCount_, nCountPeak_, nCountLeak_, nBytes_, nBytesPeak_, nTemp, nMin_ ); } else { DbgOutf( "%*c%08lx Count=%lu/%lu/%lu Bytes=%lu/%lu/%lu Size=%lu-%lu", nLevel, ' ', nIP_, nCount_, nCountPeak_, nCountLeak_, nBytes_, nBytesPeak_, nBytesLeak_, nMin_, nMax_ ); } if ( pCaller_ ) if( nLevel > 3 && nCountLeak ) pCaller_->Print( nLevel + 1, nCount, 1 ); else pCaller_->Print( nLevel + 1, nCount, nCountLeak ); } if ( pRight_ ) pRight_->Print( nLevel, nCount, nCountLeak ); } // ----------------------------------------------------------------------- void ImpDbgStackTree::Print( int nLevel ) { if ( pSub_ ) pSub_->Print( nLevel + 1 ); DbgOutf( "%*c%08lx", nLevel, ' ',nIP_ ); } // ----------------------------------------------------------------------- ImpDbgStackTree* ImpDbgStackTree::Add( sal_uIntPtr nAlloc, sal_uIntPtr *pBP, sal_uIntPtr nIP ) { if ( nIP < nIP_ ) { if ( !pLeft_ ) pLeft_ = new ImpDbgStackTree( pSub_, nIP ); return pLeft_->Add( nAlloc, pBP, nIP ); } if ( nIP > nIP_ ) { if ( !pRight_ ) pRight_ = new ImpDbgStackTree( pSub_, nIP ); return pRight_->Add( nAlloc, pBP, nIP ); } nCount_++; nCountLeak_++; if ( nCountLeak_ > nCountPeak_ ) nCountPeak_ = nCountLeak_; nBytes_ += nAlloc; nBytesLeak_ += nAlloc; if ( nBytesLeak_ > nBytesPeak_ ) nBytesPeak_ = nBytesLeak_; if ( nCount_ == 1 ) nMax_ = nMin_ = nAlloc; else if ( nMax_ < nAlloc ) nMax_ = nAlloc; else if ( nMin_ > nAlloc ) nMin_ = nAlloc; if ( !(pBP[0] & 3) && (sal_uIntPtr)pBP < pBP[0] && pBP[0] < (sal_uIntPtr)pImpDbgStackTreeBP ) { pBP = (sal_uIntPtr*)pBP[0]; nIP = pBP[1]; if ( 0x01100000 <= nIP && nIP < 0x20000000 && nIP != nImpDbgStackTreeMain ) { if ( !pCaller_ ) pCaller_ = new ImpDbgStackTree( this, nIP ); return pCaller_->Add( nAlloc, pBP, nIP ); } else return this; } return this; } // ----------------------------------------------------------------------- void DbgStartStackTree() { if ( !nImpDbgStackTreeMain ) { sal_uIntPtr* pBP; __asm mov pBP, ebp; pImpDbgStackTreeBP = (sal_uIntPtr*)pBP[0]; nImpDbgStackTreeMain = pImpDbgStackTreeBP[1]; } } // ----------------------------------------------------------------------- void DbgEndStackTree() { if ( nImpDbgStackTreeMain ) { nImpDbgStackTreeMain = 0; if ( pImpDbgStackTreeRoot ) { // Ausgaben ins File umleiten DbgData* pData = DbgGetData(); sal_uIntPtr nOldOut = pData->nTraceOut; pData->nTraceOut = DBG_OUT_FILE; DbgOutf( "Leak-Report" ); DbgOutf( "===========" ); DbgOutf( "Mem-StackTree:" ); DbgOutf( "{" ); pImpDbgStackTreeRoot->Print( 1, 1, 2 ); DbgOutf( "}" ); DbgOutf( "Alloc-Report" ); DbgOutf( "===========" ); DbgOutf( "Mem-StackTree:" ); DbgOutf( "{" ); pImpDbgStackTreeRoot->Print( 1, 1000, 0 ); // ??? DbgOutf( "}" ); pData->nTraceOut = nOldOut; nImpDbgStackTreeSem++; delete pImpDbgStackTreeRoot; pImpDbgStackTreeRoot = NULL; nImpDbgStackTreeSem--; } } } // ----------------------------------------------------------------------- void* DbgGetStackTree( sal_uIntPtr nAlloc ) { ImpDbgStackTree* pReturn = NULL; if ( nImpDbgStackTreeMain && !nImpDbgStackTreeSem ) { nImpDbgStackTreeSem++; sal_uIntPtr* pBP; __asm mov pBP, ebp; sal_uIntPtr nIP = pBP[1]; if ( !pImpDbgStackTreeRoot ) pImpDbgStackTreeRoot = new ImpDbgStackTree( NULL, nIP ); pReturn = pImpDbgStackTreeRoot->Add( nAlloc, pBP, nIP ); nImpDbgStackTreeSem--; } return pReturn; } // ----------------------------------------------------------------------- void DbgFreeStackTree( void* pVoid, sal_uIntPtr nAlloc ) { ImpDbgStackTree* p = (ImpDbgStackTree*)pVoid; if ( p && nImpDbgStackTreeMain && !nImpDbgStackTreeSem ) { if ( nAlloc < p->nMin_ ) nAlloc = p->nMin_; p->nCountLeak_--; p->nBytesLeak_ -= nAlloc; if ( p->nMax_ && 0xFFFFFFFF / p->nMax_ > p->nCountLeak_ ) { if ( p->nBytesLeak_ > p->nMax_ * p->nCountLeak_ ) { nAlloc += p->nBytesLeak_ - p->nMax_ * p->nCountLeak_; p->nBytesLeak_ = p->nMax_ * p->nCountLeak_; } } if ( p->pSub_ ) DbgFreeStackTree( (void*)(p->pSub_), nAlloc ); } } // ----------------------------------------------------------------------- void DbgPrintStackTree( void* pVoid ) { ImpDbgStackTree* p = (ImpDbgStackTree*)pVoid; if ( p && nImpDbgStackTreeMain && !nImpDbgStackTreeSem ) { // Ausgaben ins File umleiten DbgData* pData = DbgGetData(); sal_uIntPtr nOldOut = pData->nTraceOut; pData->nTraceOut = DBG_OUT_FILE; DbgOutf( "Mem-StackTree:" ); DbgOutf( "{" ); p->Print( 1 ); DbgOutf( "}" ); pData->nTraceOut = nOldOut; } } #else void DbgStartStackTree() {} void DbgEndStackTree() {} void* DbgGetStackTree( sal_uIntPtr ) { return NULL; } void DbgFreeStackTree( void*, sal_uIntPtr ) {} void DbgPrintStackTree( void* ) {} #endif