1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 #include <memspy/engine/memspyenginehelperstack.h> |
|
19 |
|
20 // Driver includes |
|
21 #include <memspy/driver/memspydriverclient.h> |
|
22 |
|
23 // User includes |
|
24 #include <memspy/engine/memspyengine.h> |
|
25 #include <memspy/engine/memspyengineoutputsink.h> |
|
26 #include <memspy/engine/memspyengineoutputlist.h> |
|
27 #include <memspy/engine/memspyengineobjectthread.h> |
|
28 #include <memspy/engine/memspyengineobjectprocess.h> |
|
29 #include "MemSpyEngineOutputListItem.h" |
|
30 #include <memspy/engine/memspyengineobjectcontainer.h> |
|
31 #include <memspy/engine/memspyenginehelpercodesegment.h> |
|
32 |
|
33 // Literal constants |
|
34 _LIT( KMemSpyPrefixStackData, "StackData - %S - " ); |
|
35 _LIT( KMemSpyMarkerStackData, "<%SMEMSPY_STACK_DATA_%03d>" ); |
|
36 |
|
37 |
|
38 CMemSpyEngineHelperStack::CMemSpyEngineHelperStack( CMemSpyEngine& aEngine ) |
|
39 : iEngine( aEngine ) |
|
40 { |
|
41 } |
|
42 |
|
43 |
|
44 CMemSpyEngineHelperStack::~CMemSpyEngineHelperStack() |
|
45 { |
|
46 } |
|
47 |
|
48 |
|
49 void CMemSpyEngineHelperStack::ConstructL() |
|
50 { |
|
51 } |
|
52 |
|
53 |
|
54 CMemSpyEngineHelperStack* CMemSpyEngineHelperStack::NewL( CMemSpyEngine& aEngine ) |
|
55 { |
|
56 CMemSpyEngineHelperStack* self = new(ELeave) CMemSpyEngineHelperStack( aEngine ); |
|
57 CleanupStack::PushL( self ); |
|
58 self->ConstructL(); |
|
59 CleanupStack::Pop( self ); |
|
60 return self; |
|
61 } |
|
62 |
|
63 |
|
64 EXPORT_C void CMemSpyEngineHelperStack::OutputStackInfoL( const CMemSpyThread& aThread ) |
|
65 { |
|
66 const TFullName pName( aThread.FullName() ); |
|
67 // |
|
68 _LIT(KHeader, "STACK INFO FOR THREAD '%S'"); |
|
69 TBuf<KMaxFullName + 100> printFormat; |
|
70 printFormat.Format( KHeader, &pName ); |
|
71 iEngine.Sink().OutputSectionHeadingL( printFormat, '=' ); |
|
72 |
|
73 OutputStackInfoL( aThread.Process().Id(), aThread.Id(), printFormat ); |
|
74 } |
|
75 |
|
76 |
|
77 EXPORT_C void CMemSpyEngineHelperStack::OutputStackInfoL( TProcessId aPid, TThreadId aTid, TDes& aLineBuffer ) |
|
78 { |
|
79 TMemSpyDriverStackInfo info; |
|
80 // |
|
81 iEngine.ProcessSuspendLC( aPid ); |
|
82 const TInt r = iEngine.Driver().GetStackInfo( aTid, info ); |
|
83 CleanupStack::PopAndDestroy(); // ProcessSuspendLC |
|
84 // |
|
85 if ( r == KErrNone ) |
|
86 { |
|
87 CMemSpyEngineOutputList* list = CMemSpyEngineOutputList::NewLC( iEngine.Sink() ); |
|
88 |
|
89 { |
|
90 // Header - user stack |
|
91 list->AddItemL( _L("USER STACK") ); |
|
92 list->AddUnderlineForPreviousItemL(); |
|
93 |
|
94 // Summary |
|
95 list->AddItemFormatL( _L("Address range"), _L("0x%08x - 0x%08x (%8d)"), info.iUserStackBase, info.iUserStackBase + info.iUserStackSize, info.iUserStackSize ); |
|
96 list->AddItemHexL( _L("Current stack pointer"), info.iUserStackPointer ); |
|
97 |
|
98 // Calculate usage |
|
99 const TInt usedUserStack = (TInt) ( info.iUserStackBase + info.iUserStackSize ) - info.iUserStackPointer; |
|
100 const TInt userStackUsagePct = (TInt) (( (TReal) usedUserStack / (TReal) info.iUserStackSize) * 100.0); |
|
101 aLineBuffer.Format(_L("%d (%3d"), usedUserStack, userStackUsagePct); |
|
102 aLineBuffer.Append(_L(" pct)")); |
|
103 list->AddItemL( _L("Stack usage"), aLineBuffer ); |
|
104 |
|
105 // High watermark |
|
106 list->AddItemHexL( _L("High watermark"), info.iUserStackHighWatermark ); |
|
107 const TInt userHighWaterMarkUsage = (TInt) ( info.iUserStackBase + info.iUserStackSize ) - info.iUserStackHighWatermark; |
|
108 const TInt userStackHighWaterMarkUsagePct = (TInt) (( (TReal) userHighWaterMarkUsage / (TReal) info.iUserStackSize) * 100.0); |
|
109 aLineBuffer.Format(_L("%d (%3d"), userHighWaterMarkUsage, userStackHighWaterMarkUsagePct); |
|
110 aLineBuffer.Append(_L(" pct)")); |
|
111 list->AddItemL( _L("High watermark usage"), aLineBuffer ); |
|
112 } |
|
113 |
|
114 |
|
115 { |
|
116 // Header - supervisor stack |
|
117 list->AddItemL( _L("SUPERVISOR STACK") ); |
|
118 list->AddUnderlineForPreviousItemL(); |
|
119 |
|
120 // Summary |
|
121 list->AddItemFormatL( _L("Address range"), _L("0x%08x - 0x%08x (%8d)"), info.iSupervisorStackBase, info.iSupervisorStackBase + info.iSupervisorStackSize, info.iSupervisorStackSize ); |
|
122 list->AddItemHexL( _L("Current stack pointer"), info.iSupervisorStackPointer ); |
|
123 |
|
124 // Calculate usage |
|
125 const TInt usedSupervisorStack = (TInt) ( info.iSupervisorStackBase + info.iSupervisorStackSize ) - info.iSupervisorStackPointer; |
|
126 const TInt supervisorStackUsagePct = (TInt) (( (TReal) usedSupervisorStack / (TReal) info.iSupervisorStackSize) * 100.0); |
|
127 aLineBuffer.Format(_L("%d (%3d"), usedSupervisorStack, supervisorStackUsagePct ); |
|
128 aLineBuffer.Append(_L(" pct)")); |
|
129 list->AddItemL( _L("Stack usage"), aLineBuffer ); |
|
130 |
|
131 // High watermark |
|
132 list->AddItemHexL( _L("High watermark"), info.iSupervisorStackHighWatermark ); |
|
133 const TInt supervisorStackHighWaterMarkUsage = (TInt) ( info.iSupervisorStackBase + info.iSupervisorStackSize ) - info.iSupervisorStackHighWatermark; |
|
134 const TInt supervisorStackHighWaterMarkUsagePct = (TInt) (( (TReal) supervisorStackHighWaterMarkUsage / (TReal) info.iSupervisorStackSize) * 100.0); |
|
135 aLineBuffer.Format(_L("%d (%3d"), supervisorStackHighWaterMarkUsage, supervisorStackHighWaterMarkUsagePct ); |
|
136 aLineBuffer.Append(_L(" pct)")); |
|
137 list->AddItemL( _L("High watermark usage"), aLineBuffer ); |
|
138 } |
|
139 |
|
140 list->PrintL(); |
|
141 CleanupStack::PopAndDestroy( list ); |
|
142 } |
|
143 |
|
144 } |
|
145 |
|
146 |
|
147 EXPORT_C void CMemSpyEngineHelperStack::OutputStackDataL( const CMemSpyThread& aThread, TMemSpyDriverDomainType aType ) |
|
148 { |
|
149 OutputStackDataL( aThread, aType, ETrue ); |
|
150 } |
|
151 |
|
152 |
|
153 EXPORT_C void CMemSpyEngineHelperStack::OutputStackDataL( const CMemSpyThread& aThread, TMemSpyDriverDomainType aType, TBool aEntireStack ) |
|
154 { |
|
155 TBuf<KMaxFullName + 100> printFormat; |
|
156 printFormat = aThread.FullName(); |
|
157 |
|
158 // Begin a new data stream |
|
159 _LIT( KMemSpyFolder, "Stack" ); |
|
160 HBufC* context = HBufC::NewLC( KMaxFileName ); |
|
161 TPtr pContext( context->Des() ); |
|
162 if ( aType == EMemSpyDriverDomainUser ) |
|
163 { |
|
164 _LIT(KMemSpyContext, "Data (User) - %S"); |
|
165 pContext.Format( KMemSpyContext, &printFormat ); |
|
166 } |
|
167 else if ( aType == EMemSpyDriverDomainKernel ) |
|
168 { |
|
169 _LIT(KMemSpyContext, "Data (Supervisor) - %S"); |
|
170 pContext.Format( KMemSpyContext, &printFormat ); |
|
171 } |
|
172 iEngine.Sink().DataStreamBeginL( pContext, KMemSpyFolder ); |
|
173 CleanupStack::PopAndDestroy( context ); |
|
174 |
|
175 // Suspend all threads in the process |
|
176 iEngine.ProcessSuspendLC( aThread.Process().Id() ); |
|
177 |
|
178 // Start marker |
|
179 iEngine.Sink().OutputLineFormattedL( KMemSpyMarkerStackData, &KNullDesC, (TUint) aThread.Id() ); |
|
180 |
|
181 // Set overall prefix |
|
182 iEngine.Sink().OutputPrefixSetFormattedLC( KMemSpyPrefixStackData, &printFormat ); |
|
183 |
|
184 // Prepare data buffer |
|
185 HBufC8* data = HBufC8::NewLC( 4096 * 4 ); |
|
186 TPtr8 pData(data->Des()); |
|
187 TUint remaining = 0; |
|
188 |
|
189 TMemSpyDriverStackInfo info; |
|
190 TInt r = iEngine.Driver().GetStackInfo( aThread.Id(), info ); |
|
191 if ( r == KErrNone ) |
|
192 { |
|
193 TUint spAddress = 0; |
|
194 if ( aType == EMemSpyDriverDomainUser ) |
|
195 { |
|
196 _LIT(KHeaderUser, "USER STACK DATA"); |
|
197 iEngine.Sink().OutputSectionHeadingL(KHeaderUser, '-'); |
|
198 spAddress = info.iUserStackPointer; |
|
199 } |
|
200 else if ( aType == EMemSpyDriverDomainKernel ) |
|
201 { |
|
202 _LIT(KHeaderKernel, "SUPERVISOR STACK DATA"); |
|
203 iEngine.Sink().OutputSectionHeadingL(KHeaderKernel, '-'); |
|
204 spAddress = info.iSupervisorStackPointer; |
|
205 } |
|
206 |
|
207 // Print header information |
|
208 // ======================== |
|
209 TBuf<240> buf; |
|
210 |
|
211 // Stack pointer |
|
212 _LIT( KLine1, "Current stack pointer: 0x%08x"); |
|
213 buf.Format( KLine1, spAddress ); |
|
214 iEngine.Sink().OutputLineL( buf ); |
|
215 |
|
216 // Stack address range |
|
217 _LIT( KLine2, "Stack address range: 0x%08x - 0x%08x"); |
|
218 if ( aType == EMemSpyDriverDomainUser ) |
|
219 { |
|
220 buf.Format( KLine2, info.iUserStackBase, info.iUserStackBase + info.iUserStackSize ); |
|
221 } |
|
222 else |
|
223 { |
|
224 buf.Format( KLine2, info.iSupervisorStackBase, info.iSupervisorStackBase + info.iSupervisorStackSize ); |
|
225 } |
|
226 iEngine.Sink().OutputLineL( buf ); |
|
227 |
|
228 // Stack size |
|
229 _LIT( KLine3, "Stack size: %d"); |
|
230 buf.Format( KLine3, ( aType == EMemSpyDriverDomainUser ) ? info.iUserStackSize : info.iSupervisorStackSize ); |
|
231 iEngine.Sink().OutputLineL( buf ); |
|
232 iEngine.Sink().OutputBlankLineL(); |
|
233 |
|
234 // If we are only fetching the 'current' part of the stack, then we need to maniuplate the |
|
235 // printing address used to display the stack content |
|
236 if ( !aEntireStack ) |
|
237 { |
|
238 // We start at the stack pointer address and work towards the end of the stack. |
|
239 info.iUserStackBase = spAddress; |
|
240 } |
|
241 |
|
242 // Code segments (needed for map file reading...) |
|
243 _LIT(KCodeSegInfoPrefix, "CodeSeg - "); |
|
244 iEngine.HelperCodeSegment().OutputCodeSegmentsL( aThread.Process().Id(), printFormat, KCodeSegInfoPrefix ); |
|
245 |
|
246 // Get the stack data |
|
247 // ================== |
|
248 _LIT(KStackDataPrefix, "%S"); |
|
249 r = iEngine.Driver().GetStackData( aThread.Id(), pData, remaining, aType, aEntireStack ); |
|
250 |
|
251 if ( r == KErrNone ) |
|
252 { |
|
253 while ( r == KErrNone ) |
|
254 { |
|
255 iEngine.Sink().OutputBinaryDataL( KStackDataPrefix, pData.Ptr(), (const TUint8*) info.iUserStackBase, pData.Length() ); |
|
256 // |
|
257 if ( remaining > 0 ) |
|
258 { |
|
259 info.iUserStackBase += pData.Length(); |
|
260 r = iEngine.Driver().GetStackDataNext( aThread.Id(), pData, remaining, aType, aEntireStack ); |
|
261 } |
|
262 else |
|
263 { |
|
264 break; |
|
265 } |
|
266 } |
|
267 } |
|
268 |
|
269 } |
|
270 CleanupStack::PopAndDestroy( data ); |
|
271 |
|
272 CleanupStack::PopAndDestroy(); // clear prefix |
|
273 CleanupStack::PopAndDestroy(); // resume process |
|
274 |
|
275 // End marker |
|
276 iEngine.Sink().OutputLineFormattedL( KMemSpyMarkerStackData, &KMemSpySinkTagClose, (TUint) aThread.Id() ); |
|
277 iEngine.Sink().DataStreamEndL(); |
|
278 } |
|
279 |
|
280 |
|
281 EXPORT_C void CMemSpyEngineHelperStack::OutputStackInfoForDeviceL() |
|
282 { |
|
283 const TInt count = iEngine.Container().Count(); |
|
284 // |
|
285 HBufC* buf = HBufC::NewLC( 1024 ); |
|
286 TPtr pBuf(buf->Des()); |
|
287 // |
|
288 _LIT( KMemSpyContext, "Stack" ); |
|
289 _LIT( KMemSpyFolder, "Device-Wide" ); |
|
290 _LIT( KMemSpyExtension, ".csv" ); |
|
291 iEngine.Sink().DataStreamBeginL( KMemSpyContext, KMemSpyFolder, KMemSpyExtension ); |
|
292 |
|
293 // Set overall prefix |
|
294 _LIT(KOverallPrefix, "[Stack Summary]"); |
|
295 iEngine.Sink().OutputPrefixSetLC( KOverallPrefix ); |
|
296 |
|
297 _LIT(KListingHeader, "Thread, US. Base Address, US. Size, US. Addr, US. Usage, US. Usage Pct, US. HWM Addr, US. HWM Usage, US. HWM Usage Pct, SS. Base Address, SS. Size, SS. Addr, SS. Usage, SS. Usage Pct., SS. HWM Addr, SS. HWM Usage, SS. HWM Usage Pct"); |
|
298 iEngine.Sink().OutputBlankLineL(); |
|
299 iEngine.Sink().OutputLineL(KListingHeader); |
|
300 |
|
301 for(TInt ii=0; ii<count; ii++) |
|
302 { |
|
303 const CMemSpyProcess& process = iEngine.Container().At( ii ); |
|
304 const TPtrC procName( process.Name() ); |
|
305 // |
|
306 if ( iEngine.ProcessSuspendAndGetErrorLC( process.Id() ) == KErrNone ) |
|
307 { |
|
308 TMemSpyDriverStackInfo info; |
|
309 const TInt threadCount = process.Count(); |
|
310 // |
|
311 for(TInt j=0; j<threadCount; j++) |
|
312 { |
|
313 const CMemSpyThread& thread = process.At( j ); |
|
314 const TPtrC threadName(thread.Name()); |
|
315 |
|
316 const TInt error = iEngine.Driver().GetStackInfo( thread.Id(), info ); |
|
317 if ( error == KErrNone ) |
|
318 { |
|
319 const TInt userStackUsage = (TInt) ( info.iUserStackBase + info.iUserStackSize ) - info.iUserStackPointer; |
|
320 const TInt userStackUsagePct = (TInt) (( (TReal) userStackUsage / (TReal) info.iUserStackSize) * 100.0); |
|
321 const TInt userStackHighWaterMarkUsage = (TInt) ( info.iUserStackBase + info.iUserStackSize ) - info.iUserStackHighWatermark; |
|
322 const TInt userStackHighWaterMarkUsagePct = (TInt) (( (TReal) userStackHighWaterMarkUsage / (TReal) info.iUserStackSize) * 100.0); |
|
323 const TInt supervisorStackUsage = (TInt) ( info.iSupervisorStackBase + info.iSupervisorStackSize ) - info.iSupervisorStackPointer; |
|
324 const TInt supervisorStackUsagePct = (TInt) (( (TReal) supervisorStackUsage / (TReal) info.iSupervisorStackSize) * 100.0); |
|
325 const TInt supervisorStackHighWaterMarkUsage = (TInt) ( info.iSupervisorStackBase + info.iSupervisorStackSize ) - info.iSupervisorStackHighWatermark; |
|
326 const TInt supervisorStackHighWaterMarkUsagePct = (TInt) (( (TReal) supervisorStackHighWaterMarkUsage / (TReal) info.iSupervisorStackSize) * 100.0); |
|
327 |
|
328 _LIT(KFormat, "%S::%S, 0x%08x, %8d, 0x%08x, %8d, %8d, 0x%08x, %8d, %8d, 0x%08x, %8d, 0x%08x, %8d, %8d, 0x%08x, %8d, %8d"); |
|
329 pBuf.Format( KFormat, &procName, &threadName, |
|
330 info.iUserStackBase, |
|
331 info.iUserStackSize, |
|
332 info.iUserStackPointer, |
|
333 userStackUsage, |
|
334 userStackUsagePct, |
|
335 info.iUserStackHighWatermark, |
|
336 userStackHighWaterMarkUsage, |
|
337 userStackHighWaterMarkUsagePct, |
|
338 info.iSupervisorStackBase, |
|
339 info.iSupervisorStackSize, |
|
340 info.iSupervisorStackPointer, |
|
341 supervisorStackUsage, |
|
342 supervisorStackUsagePct, |
|
343 info.iSupervisorStackHighWatermark, |
|
344 supervisorStackHighWaterMarkUsage, |
|
345 supervisorStackHighWaterMarkUsagePct |
|
346 ); |
|
347 iEngine.Sink().OutputLineL( pBuf ); |
|
348 } |
|
349 } |
|
350 } |
|
351 |
|
352 CleanupStack::PopAndDestroy(); // ProcessSuspendLC |
|
353 } |
|
354 |
|
355 CleanupStack::PopAndDestroy(); // clear prefix |
|
356 |
|
357 CleanupStack::PopAndDestroy( buf ); |
|
358 |
|
359 _LIT(KEndOfHeapListing, "<= End Stack Summary =>"); |
|
360 iEngine.Sink().OutputLineL( KEndOfHeapListing ); |
|
361 |
|
362 iEngine.Sink().DataStreamEndL(); |
|
363 } |
|
364 |
|
365 |
|
366 EXPORT_C TInt CMemSpyEngineHelperStack::CalculateStackSizes( const CMemSpyProcess& aProcess ) |
|
367 { |
|
368 TInt ret = 0; |
|
369 // |
|
370 TRAPD( error, ret = CalculateStackSizesL( aProcess ) ); |
|
371 // |
|
372 if ( error != KErrNone ) |
|
373 { |
|
374 ret = error; |
|
375 } |
|
376 // |
|
377 return ret; |
|
378 } |
|
379 |
|
380 |
|
381 TInt CMemSpyEngineHelperStack::CalculateStackSizesL( const CMemSpyProcess& aProcess ) |
|
382 { |
|
383 TInt ret = 0; |
|
384 // |
|
385 iEngine.ProcessSuspendLC( aProcess.Id() ); |
|
386 |
|
387 TMemSpyDriverStackInfo info; |
|
388 // |
|
389 const TInt threadCount = aProcess.Count(); |
|
390 for( TInt i=0; i<threadCount; i++ ) |
|
391 { |
|
392 const CMemSpyThread& thread = aProcess.At( i ); |
|
393 // |
|
394 TInt r = iEngine.Driver().GetStackInfo( thread.Id(), info ); |
|
395 if ( r == KErrNone ) |
|
396 { |
|
397 ret += info.iUserStackSize; |
|
398 ret += info.iSupervisorStackSize; |
|
399 } |
|
400 } |
|
401 // |
|
402 CleanupStack::PopAndDestroy(); // ProcessSuspendLC |
|
403 return ret; |
|
404 } |
|
405 |
|
406 |
|
407 |
|