| /************************************************************** |
| * |
| * 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 <string.h> |
| |
| #include <tools/debug.hxx> |
| |
| // ----------------------------------------------------------------------- |
| |
| #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 |