1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_tools.hxx" 30 31 #include <string.h> 32 33 #include <tools/debug.hxx> 34 35 // ----------------------------------------------------------------------- 36 37 #if defined( DBG_UTIL ) && defined( WNT ) && defined( INTEL ) 38 39 struct ImpDbgStackTree 40 { 41 ImpDbgStackTree* pLeft_; 42 ImpDbgStackTree* pRight_; 43 ImpDbgStackTree* pCaller_; 44 ImpDbgStackTree* pSub_; 45 sal_uIntPtr nIP_; 46 sal_uIntPtr nBytesLeak_; 47 sal_uIntPtr nBytesPeak_; 48 sal_uIntPtr nBytes_; 49 sal_uIntPtr nCountLeak_; 50 sal_uIntPtr nCountPeak_; 51 sal_uIntPtr nCount_; 52 sal_uIntPtr nMax_; 53 sal_uIntPtr nMin_; 54 55 ImpDbgStackTree( ImpDbgStackTree* pSub, sal_uIntPtr nIP ); 56 ~ImpDbgStackTree(); 57 58 ImpDbgStackTree* Add( sal_uIntPtr nAlloc, sal_uIntPtr* pBP, sal_uIntPtr nIP ); 59 void Print( int nLevel, sal_uIntPtr nCount, sal_uIntPtr nCountLeak ); 60 void Print( int nLevel ); 61 }; 62 63 static ImpDbgStackTree* pImpDbgStackTreeRoot = NULL; 64 static sal_uIntPtr* pImpDbgStackTreeBP = NULL; 65 static sal_uIntPtr nImpDbgStackTreeMain = 0; 66 static int nImpDbgStackTreeSem = 0; 67 68 // ----------------------------------------------------------------------- 69 70 ImpDbgStackTree::ImpDbgStackTree( ImpDbgStackTree* pSub, sal_uIntPtr nIP ) 71 { 72 pSub_ = pSub; 73 nIP_ = nIP; 74 pLeft_ = pRight_ = pCaller_ = NULL; 75 nBytesLeak_ = nBytesPeak_ = nBytes_ = 0; 76 nCountLeak_ = nCountPeak_ = nCount_ = 0; 77 } 78 79 // ----------------------------------------------------------------------- 80 81 ImpDbgStackTree::~ImpDbgStackTree() 82 { 83 if ( pLeft_ ) 84 delete pLeft_; 85 if ( pRight_ ) 86 delete pRight_; 87 if ( pCaller_ ) 88 delete pCaller_; 89 } 90 91 // ----------------------------------------------------------------------- 92 93 void ImpDbgStackTree::Print( int nLevel, sal_uIntPtr nCount, sal_uIntPtr nCountLeak ) 94 { 95 if ( pLeft_ ) 96 pLeft_->Print( nLevel, nCount, nCountLeak ); 97 98 if ( nCount_ >= nCount && nCountLeak_ >= nCountLeak ) 99 { 100 if ( nMax_ == nMin_ ) 101 { 102 sal_uIntPtr nTemp = nCountLeak_ * nMin_; 103 DbgOutf( "%*c%08lx Count=%lu/%lu/%lu Bytes=%lu/%lu/%lu Size=%lu", 104 nLevel, ' ', nIP_, 105 nCount_, nCountPeak_, nCountLeak_, 106 nBytes_, nBytesPeak_, nTemp, 107 nMin_ ); 108 } 109 else 110 { 111 DbgOutf( "%*c%08lx Count=%lu/%lu/%lu Bytes=%lu/%lu/%lu Size=%lu-%lu", 112 nLevel, ' ', nIP_, 113 nCount_, nCountPeak_, nCountLeak_, 114 nBytes_, nBytesPeak_, nBytesLeak_, 115 nMin_, nMax_ ); 116 } 117 118 if ( pCaller_ ) 119 if( nLevel > 3 && nCountLeak ) 120 pCaller_->Print( nLevel + 1, nCount, 1 ); 121 else 122 pCaller_->Print( nLevel + 1, nCount, nCountLeak ); 123 } 124 125 if ( pRight_ ) 126 pRight_->Print( nLevel, nCount, nCountLeak ); 127 } 128 129 // ----------------------------------------------------------------------- 130 131 void ImpDbgStackTree::Print( int nLevel ) 132 { 133 if ( pSub_ ) 134 pSub_->Print( nLevel + 1 ); 135 DbgOutf( "%*c%08lx", nLevel, ' ',nIP_ ); 136 } 137 138 // ----------------------------------------------------------------------- 139 140 ImpDbgStackTree* ImpDbgStackTree::Add( sal_uIntPtr nAlloc, sal_uIntPtr *pBP, sal_uIntPtr nIP ) 141 { 142 if ( nIP < nIP_ ) 143 { 144 if ( !pLeft_ ) 145 pLeft_ = new ImpDbgStackTree( pSub_, nIP ); 146 return pLeft_->Add( nAlloc, pBP, nIP ); 147 } 148 if ( nIP > nIP_ ) 149 { 150 if ( !pRight_ ) 151 pRight_ = new ImpDbgStackTree( pSub_, nIP ); 152 return pRight_->Add( nAlloc, pBP, nIP ); 153 } 154 155 nCount_++; 156 nCountLeak_++; 157 if ( nCountLeak_ > nCountPeak_ ) 158 nCountPeak_ = nCountLeak_; 159 nBytes_ += nAlloc; 160 nBytesLeak_ += nAlloc; 161 if ( nBytesLeak_ > nBytesPeak_ ) 162 nBytesPeak_ = nBytesLeak_; 163 if ( nCount_ == 1 ) 164 nMax_ = nMin_ = nAlloc; 165 else if ( nMax_ < nAlloc ) 166 nMax_ = nAlloc; 167 else if ( nMin_ > nAlloc ) 168 nMin_ = nAlloc; 169 170 if ( !(pBP[0] & 3) && (sal_uIntPtr)pBP < pBP[0] && pBP[0] < (sal_uIntPtr)pImpDbgStackTreeBP ) 171 { 172 pBP = (sal_uIntPtr*)pBP[0]; 173 nIP = pBP[1]; 174 if ( 0x01100000 <= nIP && nIP < 0x20000000 && nIP != nImpDbgStackTreeMain ) 175 { 176 if ( !pCaller_ ) 177 pCaller_ = new ImpDbgStackTree( this, nIP ); 178 return pCaller_->Add( nAlloc, pBP, nIP ); 179 } 180 else 181 return this; 182 } 183 184 return this; 185 } 186 187 // ----------------------------------------------------------------------- 188 189 void DbgStartStackTree() 190 { 191 if ( !nImpDbgStackTreeMain ) 192 { 193 sal_uIntPtr* pBP; 194 __asm mov pBP, ebp; 195 196 pImpDbgStackTreeBP = (sal_uIntPtr*)pBP[0]; 197 nImpDbgStackTreeMain = pImpDbgStackTreeBP[1]; 198 } 199 } 200 201 // ----------------------------------------------------------------------- 202 203 void DbgEndStackTree() 204 { 205 if ( nImpDbgStackTreeMain ) 206 { 207 nImpDbgStackTreeMain = 0; 208 if ( pImpDbgStackTreeRoot ) 209 { 210 // Ausgaben ins File umleiten 211 DbgData* pData = DbgGetData(); 212 sal_uIntPtr nOldOut = pData->nTraceOut; 213 pData->nTraceOut = DBG_OUT_FILE; 214 215 DbgOutf( "Leak-Report" ); 216 DbgOutf( "===========" ); 217 DbgOutf( "Mem-StackTree:" ); 218 DbgOutf( "{" ); 219 pImpDbgStackTreeRoot->Print( 1, 1, 2 ); 220 DbgOutf( "}" ); 221 222 DbgOutf( "Alloc-Report" ); 223 DbgOutf( "===========" ); 224 DbgOutf( "Mem-StackTree:" ); 225 DbgOutf( "{" ); 226 pImpDbgStackTreeRoot->Print( 1, 1000, 0 ); // ??? 227 DbgOutf( "}" ); 228 229 pData->nTraceOut = nOldOut; 230 231 nImpDbgStackTreeSem++; 232 delete pImpDbgStackTreeRoot; 233 pImpDbgStackTreeRoot = NULL; 234 nImpDbgStackTreeSem--; 235 } 236 } 237 } 238 239 // ----------------------------------------------------------------------- 240 241 void* DbgGetStackTree( sal_uIntPtr nAlloc ) 242 { 243 ImpDbgStackTree* pReturn = NULL; 244 245 if ( nImpDbgStackTreeMain && !nImpDbgStackTreeSem ) 246 { 247 nImpDbgStackTreeSem++; 248 249 sal_uIntPtr* pBP; 250 __asm mov pBP, ebp; 251 252 sal_uIntPtr nIP = pBP[1]; 253 if ( !pImpDbgStackTreeRoot ) 254 pImpDbgStackTreeRoot = new ImpDbgStackTree( NULL, nIP ); 255 pReturn = pImpDbgStackTreeRoot->Add( nAlloc, pBP, nIP ); 256 nImpDbgStackTreeSem--; 257 } 258 259 return pReturn; 260 } 261 262 // ----------------------------------------------------------------------- 263 264 void DbgFreeStackTree( void* pVoid, sal_uIntPtr nAlloc ) 265 { 266 ImpDbgStackTree* p = (ImpDbgStackTree*)pVoid; 267 268 if ( p && nImpDbgStackTreeMain && !nImpDbgStackTreeSem ) 269 { 270 if ( nAlloc < p->nMin_ ) 271 nAlloc = p->nMin_; 272 273 p->nCountLeak_--; 274 p->nBytesLeak_ -= nAlloc; 275 276 if ( p->nMax_ && 0xFFFFFFFF / p->nMax_ > p->nCountLeak_ ) 277 { 278 if ( p->nBytesLeak_ > p->nMax_ * p->nCountLeak_ ) 279 { 280 nAlloc += p->nBytesLeak_ - p->nMax_ * p->nCountLeak_; 281 p->nBytesLeak_ = p->nMax_ * p->nCountLeak_; 282 } 283 } 284 285 if ( p->pSub_ ) 286 DbgFreeStackTree( (void*)(p->pSub_), nAlloc ); 287 } 288 } 289 290 // ----------------------------------------------------------------------- 291 292 void DbgPrintStackTree( void* pVoid ) 293 { 294 ImpDbgStackTree* p = (ImpDbgStackTree*)pVoid; 295 296 if ( p && nImpDbgStackTreeMain && !nImpDbgStackTreeSem ) 297 { 298 // Ausgaben ins File umleiten 299 DbgData* pData = DbgGetData(); 300 sal_uIntPtr nOldOut = pData->nTraceOut; 301 pData->nTraceOut = DBG_OUT_FILE; 302 303 DbgOutf( "Mem-StackTree:" ); 304 DbgOutf( "{" ); 305 p->Print( 1 ); 306 DbgOutf( "}" ); 307 308 pData->nTraceOut = nOldOut; 309 } 310 } 311 312 #else 313 314 void DbgStartStackTree() {} 315 void DbgEndStackTree() {} 316 void* DbgGetStackTree( sal_uIntPtr ) { return NULL; } 317 void DbgFreeStackTree( void*, sal_uIntPtr ) {} 318 void DbgPrintStackTree( void* ) {} 319 320 #endif 321