blob: af94ec0680a43dc26484f7342f6d1d752f7e4fe1 [file] [log] [blame]
/**************************************************************
*
* 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