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