51
|
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/memspyenginehelperactiveobject.h>
|
|
19 |
|
|
20 |
// System includes
|
|
21 |
#include <s32mem.h>
|
|
22 |
#include <e32svr.h>
|
|
23 |
|
|
24 |
// Driver includes
|
|
25 |
#include <memspy/driver/memspydriverclient.h>
|
|
26 |
|
|
27 |
// User includes
|
|
28 |
#include <memspy/engine/memspyengine.h>
|
|
29 |
#include <memspy/engine/memspyengineutils.h>
|
|
30 |
#include <memspy/engine/memspyengineoutputsink.h>
|
|
31 |
#include <memspy/engine/memspyengineobjectthread.h>
|
|
32 |
#include <memspy/engine/memspyengineobjectprocess.h>
|
|
33 |
#include <memspy/engine/memspyenginehelperheap.h>
|
|
34 |
|
|
35 |
// Driver includes
|
|
36 |
#include <memspy/driver/memspydriverconstants.h>
|
|
37 |
|
|
38 |
// Literal constants
|
|
39 |
_LIT( KMemSpyEngineAOOutputComma, ", " );
|
|
40 |
|
|
41 |
|
|
42 |
|
|
43 |
CMemSpyEngineHelperActiveObject::CMemSpyEngineHelperActiveObject( CMemSpyEngine& aEngine )
|
|
44 |
: iEngine( aEngine )
|
|
45 |
{
|
|
46 |
}
|
|
47 |
|
|
48 |
|
|
49 |
CMemSpyEngineHelperActiveObject::~CMemSpyEngineHelperActiveObject()
|
|
50 |
{
|
|
51 |
}
|
|
52 |
|
|
53 |
|
|
54 |
void CMemSpyEngineHelperActiveObject::ConstructL()
|
|
55 |
{
|
|
56 |
}
|
|
57 |
|
|
58 |
|
|
59 |
CMemSpyEngineHelperActiveObject* CMemSpyEngineHelperActiveObject::NewL( CMemSpyEngine& aEngine )
|
|
60 |
{
|
|
61 |
CMemSpyEngineHelperActiveObject* self = new(ELeave) CMemSpyEngineHelperActiveObject( aEngine );
|
|
62 |
CleanupStack::PushL( self );
|
|
63 |
self->ConstructL();
|
|
64 |
CleanupStack::Pop( self );
|
|
65 |
return self;
|
|
66 |
}
|
|
67 |
|
|
68 |
|
|
69 |
EXPORT_C CMemSpyEngineActiveObjectArray* CMemSpyEngineHelperActiveObject::ActiveObjectListL( const CMemSpyThread& aThread )
|
|
70 |
{
|
|
71 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ActiveObjectListL() - START");
|
|
72 |
CMemSpyEngineActiveObjectArray* array = CMemSpyEngineActiveObjectArray::NewLC();
|
|
73 |
|
|
74 |
// Is the thread's process already suspended? If not, we need to do it now.
|
|
75 |
const TProcessId parentProcessId( aThread.Process().Id() );
|
|
76 |
const TBool isSuspended = ( iEngine.SuspendedProcessId() == parentProcessId );
|
|
77 |
if ( !isSuspended )
|
|
78 |
{
|
|
79 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ActiveObjectListL() - suspending process");
|
|
80 |
iEngine.ProcessSuspendLC( parentProcessId );
|
|
81 |
}
|
|
82 |
|
|
83 |
// Push a cleanup item to close the heap walk in case of leaves
|
|
84 |
CleanupStack::PushL( TCleanupItem( CleanupHeapWalk, this ) );
|
|
85 |
|
|
86 |
// Get the thread info
|
|
87 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ActiveObjectListL() - getting thread info...");
|
|
88 |
TMemSpyDriverThreadInfo threadInfo;
|
|
89 |
TInt err = iEngine.Driver().GetThreadInfo( aThread.Id(), threadInfo );
|
|
90 |
User::LeaveIfError( err );
|
|
91 |
TAny* scheduler = threadInfo.iScheduler;
|
|
92 |
|
|
93 |
#if defined( _DEBUG ) && !defined( __WINS__ )
|
|
94 |
iEngine.HelperHeap().OutputCellListingUserL( aThread );
|
|
95 |
#endif
|
|
96 |
|
|
97 |
// Get the heap info - we need this for verification purposes
|
|
98 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ActiveObjectListL() - getting heap info...");
|
|
99 |
err = iEngine.Driver().GetHeapInfoUser( iHeapInfo, aThread.Id() );
|
|
100 |
User::LeaveIfError( err );
|
|
101 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ActiveObjectListL() - allocated cell header length is: %d", iHeapInfo.iHeapCellHeaderLengthAllocated);
|
|
102 |
|
|
103 |
// Do we have a ROM-based scheduler pointer?
|
|
104 |
if ( scheduler != NULL && iHeapInfo.Type() != TMemSpyHeapInfo::ETypeUnknown )
|
|
105 |
{
|
|
106 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ActiveObjectListL() - scheduler: 0x%08x", scheduler);
|
|
107 |
|
|
108 |
// Let's try to get the scheduler's heap cell...
|
|
109 |
HBufC8* data = SchedulerHeapCellDataLC( scheduler, aThread.Id() );
|
|
110 |
|
|
111 |
// Try to extract the active object addresses
|
|
112 |
ExtractActiveObjectAddressesL( scheduler, *data, *array );
|
|
113 |
CleanupStack::PopAndDestroy( data );
|
|
114 |
}
|
|
115 |
|
|
116 |
// Tidy up
|
|
117 |
CleanupStack::PopAndDestroy(this); // heap walk cleanup item
|
|
118 |
if ( !isSuspended )
|
|
119 |
{
|
|
120 |
CleanupStack::PopAndDestroy(); // will resume the process we suspended earlier
|
|
121 |
}
|
|
122 |
//
|
|
123 |
CleanupStack::Pop( array );
|
|
124 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ActiveObjectListL() - END");
|
|
125 |
return array;
|
|
126 |
}
|
|
127 |
|
|
128 |
|
|
129 |
HBufC8* CMemSpyEngineHelperActiveObject::SchedulerHeapCellDataLC( TAny*& aCellAddress, TThreadId aThreadId )
|
|
130 |
{
|
|
131 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::SchedulerHeapCellDataLC() - START - aCellAddress: 0x%08x, aThread: %d", aCellAddress, I64INT(aThreadId.Id()));
|
|
132 |
|
|
133 |
// This is what we'll return, if we find it...
|
|
134 |
HBufC8* heapCellData = NULL;
|
|
135 |
|
|
136 |
// Now walk the heap!
|
|
137 |
TInt err = iEngine.Driver().WalkHeapInit( aThreadId );
|
|
138 |
User::LeaveIfError( err );
|
|
139 |
|
|
140 |
// Now we can try to find the cell's info
|
|
141 |
TMemSpyDriverCellType cellType;
|
|
142 |
TInt cellLength;
|
|
143 |
TInt cellNestingLevel;
|
|
144 |
TInt cellAllocationNumber;
|
|
145 |
TInt cellHeaderSize;
|
|
146 |
TAny* cellPayloadAddress;
|
|
147 |
//
|
|
148 |
err = iEngine.Driver().WalkHeapGetCellInfo( aCellAddress, cellType, cellLength, cellNestingLevel, cellAllocationNumber, cellHeaderSize, cellPayloadAddress );
|
|
149 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::SchedulerHeapCellDataLC() - err: %d, cellLength: %d, cellAllocationNumber: %d, cellType: %d", err, cellLength, cellAllocationNumber, cellType);
|
|
150 |
User::LeaveIfError( err );
|
|
151 |
|
|
152 |
if (cellType & EMemSpyDriverAllocatedCellMask)
|
|
153 |
{
|
|
154 |
const TInt payloadLength = cellLength;
|
|
155 |
HBufC8* data = HBufC8::NewLC( payloadLength );
|
|
156 |
TPtr8 pData( data->Des() );
|
|
157 |
//
|
|
158 |
err = iEngine.Driver().WalkHeapReadCellData( aCellAddress, pData, payloadLength );
|
|
159 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::SchedulerHeapCellDataLC() - data fetch returned error: %d", err);
|
|
160 |
User::LeaveIfError( err );
|
|
161 |
heapCellData = data;
|
|
162 |
CleanupStack::Pop( data );
|
|
163 |
}
|
|
164 |
//
|
|
165 |
if ( heapCellData == NULL )
|
|
166 |
{
|
|
167 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::SchedulerHeapCellDataLC() - END - didn't find the right cell => KErrNotFound");
|
|
168 |
User::Leave( KErrNotFound );
|
|
169 |
}
|
|
170 |
//
|
|
171 |
CleanupStack::PushL( heapCellData );
|
|
172 |
|
|
173 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::SchedulerHeapCellDataLC() - END - everything okay, cell is: 0x%08x", aCellAddress);
|
|
174 |
return heapCellData;
|
|
175 |
}
|
|
176 |
|
|
177 |
|
|
178 |
void CMemSpyEngineHelperActiveObject::ExtractActiveObjectAddressesL( TAny* aSchedulerCellAddress, const TDesC8& aSchedulerCellData, CMemSpyEngineActiveObjectArray& aArray )
|
|
179 |
{
|
|
180 |
// Create read stream
|
|
181 |
RDesReadStream stream( aSchedulerCellData );
|
|
182 |
CleanupClosePushL( stream );
|
|
183 |
|
|
184 |
// First item is vtable
|
|
185 |
TUint address = stream.ReadUint32L();
|
|
186 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ExtractActiveObjectAddressesL() - vtable: 0x%08x", address );
|
|
187 |
(void) address;
|
|
188 |
|
|
189 |
// Next item is CActiveScheduler::iStack - which we'll skip, because it might be a stack address
|
|
190 |
// I suppose we could validate this against the thread's stack address range, but can't be bothered
|
|
191 |
// at the moment.
|
|
192 |
address = stream.ReadUint32L();
|
|
193 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ExtractActiveObjectAddressesL() - got CActiveScheduler::iStack as: 0x%08x", address);
|
|
194 |
(void) address;
|
|
195 |
|
|
196 |
// Then comes CActiveScheduler::iActiveQ - this is what we are interested in....
|
|
197 |
//
|
|
198 |
// class TPriQue : public TDblQueBase
|
|
199 |
// [TDblQueBase::iHead] - this just derives from TDblQueLinkBase and doesn't have any direct data members
|
|
200 |
// class TDblQueLink : public TDblQueLinkBase
|
|
201 |
// [ptr] TDblQueLinkBase::iNext*
|
|
202 |
// [ptr] TDblQueLinkBase::iPrev*
|
|
203 |
// [TInt] TDblQueBase::iOffset
|
|
204 |
__ASSERT_COMPILE( sizeof( TDblQueLinkBase* ) == sizeof(TUint) );
|
|
205 |
__ASSERT_COMPILE( sizeof( TInt ) == 4 );
|
|
206 |
|
|
207 |
// Get read offset so that we know the starting address of the queue
|
|
208 |
const TStreamPos pos = stream.Source()->TellL(MStreamBuf::ERead);
|
|
209 |
#ifdef __WINS__
|
|
210 |
const TAny* terminatingQueueAddress = (TAny*) (TUint(aSchedulerCellAddress) + pos.Offset());
|
|
211 |
#else
|
|
212 |
const TAny* terminatingQueueAddress = (TAny*) aSchedulerCellAddress;
|
|
213 |
#endif
|
|
214 |
|
|
215 |
const TAny* queueNext = (TAny*) stream.ReadUint32L();
|
|
216 |
const TAny* queuePrev = (TAny*) stream.ReadUint32L();
|
|
217 |
const TUint queueItemOffset = stream.ReadUint32L();
|
|
218 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ExtractActiveObjectAddressesL() - queueNext: 0x%08x, queuePrev: 0x%08x, queueItemOffset: %d, pos: %d, terminatingQueueAddress: 0x%08x", queueNext, queuePrev, queueItemOffset, pos.Offset(), terminatingQueueAddress);
|
|
219 |
(void) queuePrev;
|
|
220 |
CleanupStack::PopAndDestroy( &stream );
|
|
221 |
|
|
222 |
// Iterate through the active objects
|
|
223 |
if ( queueNext != NULL )
|
|
224 |
{
|
|
225 |
TAny* realNextCellHeapCell = NULL;
|
|
226 |
TAny* calculatedCellAddress = ((TAny*) (TUint(queueNext) - queueItemOffset));
|
|
227 |
|
|
228 |
while( !( calculatedCellAddress == NULL || calculatedCellAddress == terminatingQueueAddress || realNextCellHeapCell == terminatingQueueAddress ) )
|
|
229 |
{
|
|
230 |
// Create an active object for this cell
|
|
231 |
TAny* nextCell = ReadActiveObjectDataL( calculatedCellAddress, aArray );
|
|
232 |
|
|
233 |
// Work out next cell address
|
|
234 |
calculatedCellAddress = ((TAny*) ( TUint( nextCell ) - queueItemOffset ) );
|
|
235 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ExtractActiveObjectAddressesL() - calculatedCellAddress: 0x%08x, terminatingQueueAddress: 0x%08x", calculatedCellAddress, terminatingQueueAddress);
|
|
236 |
|
|
237 |
// Identify the next cell address
|
|
238 |
realNextCellHeapCell = ConvertAddressToRealHeapCellAddressL( nextCell );
|
|
239 |
}
|
|
240 |
}
|
|
241 |
}
|
|
242 |
|
|
243 |
|
|
244 |
TAny* CMemSpyEngineHelperActiveObject::ConvertAddressToRealHeapCellAddressL( TAny* aAddress )
|
|
245 |
{
|
|
246 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ConvertAddressToRealHeapCellAddressL() - START - aAddress: 0x%08x", aAddress);
|
|
247 |
|
|
248 |
TMemSpyDriverCellType cellType;
|
|
249 |
TInt cellLength;
|
|
250 |
TInt cellNestingLevel;
|
|
251 |
TInt cellAllocationNumber;
|
|
252 |
TInt cellHeaderSize;
|
|
253 |
TAny* cellPayloadAddress;
|
|
254 |
|
|
255 |
TInt err = iEngine.Driver().WalkHeapGetCellInfo( aAddress, cellType, cellLength, cellNestingLevel, cellAllocationNumber, cellHeaderSize, cellPayloadAddress );
|
|
256 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ConvertAddressToRealHeapCellAddressL() - END - err: %d, realCellAddress: 0x%08x, cellLength: %d, cellAllocationNumber: %d, cellType: %d", err, aAddress, cellLength, cellAllocationNumber, cellType);
|
|
257 |
User::LeaveIfError( err );
|
|
258 |
|
|
259 |
return aAddress;
|
|
260 |
}
|
|
261 |
|
|
262 |
|
|
263 |
TAny* CMemSpyEngineHelperActiveObject::ReadActiveObjectDataL( TAny* aCellAddress, CMemSpyEngineActiveObjectArray& aArray )
|
|
264 |
{
|
|
265 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ReadActiveObjectDataL() - START");
|
|
266 |
|
|
267 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ReadActiveObjectDataL() - AO.cellAddress: 0x%08x", aCellAddress);
|
|
268 |
TAny* nextCellAddress = NULL;
|
|
269 |
|
|
270 |
TMemSpyDriverCellType cellType;
|
|
271 |
TInt cellLength;
|
|
272 |
TInt cellNestingLevel;
|
|
273 |
TInt cellAllocationNumber;
|
|
274 |
TInt cellHeaderSize;
|
|
275 |
TAny* cellPayloadAddress;
|
|
276 |
|
|
277 |
// Make a separate copy of the cell address - calling GetCellInfo may well result in the address being
|
|
278 |
// changed in order to match the real starting address of a *heap cell*.
|
|
279 |
TAny* requestedCellAddress = aCellAddress;
|
|
280 |
TInt err = iEngine.Driver().WalkHeapGetCellInfo( requestedCellAddress, cellType, cellLength, cellNestingLevel, cellAllocationNumber, cellHeaderSize, cellPayloadAddress );
|
|
281 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ReadActiveObjectDataL() - err: %d, cellLength: %d, cellAllocationNumber: %d, cellType: %d", err, cellLength, cellAllocationNumber, cellType);
|
|
282 |
User::LeaveIfError( err );
|
|
283 |
|
|
284 |
if (cellType & EMemSpyDriverAllocatedCellMask)
|
|
285 |
{
|
|
286 |
const TInt payloadLength = cellLength;
|
|
287 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ReadActiveObjectDataL() - payloadLength: %d", payloadLength);
|
|
288 |
|
|
289 |
// const TInt payloadLength = Max( 512, cellLength - iHeapInfo.iHeapCellHeaderLengthAllocated ); // Prevent negative payload lengths?
|
|
290 |
CBufFlat* data = CBufFlat::NewL( payloadLength );
|
|
291 |
CleanupStack::PushL( data );
|
|
292 |
data->ResizeL( payloadLength );
|
|
293 |
TPtr8 pData( data->Ptr( 0 ) );
|
|
294 |
//
|
|
295 |
err = iEngine.Driver().WalkHeapReadCellData( requestedCellAddress, pData, payloadLength );
|
|
296 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ReadActiveObjectDataL() - AO.heapCellAddress: 0x%08x (err: %d)", requestedCellAddress, err);
|
|
297 |
User::LeaveIfError( err );
|
|
298 |
|
|
299 |
// If an object is embedded directly within a class, for example
|
|
300 |
//
|
|
301 |
// class CSomething : public CBase
|
|
302 |
// {
|
|
303 |
// CIdle iEmbeddedIdler;
|
|
304 |
// }
|
|
305 |
//
|
|
306 |
// then aCellAddress actually points to somewhere *within* a heap cell, not to the actual starting address of
|
|
307 |
// the heap cell itself. We must take this into account when parsing the heap cell data (i.e. the bit of the cell we
|
|
308 |
// are interested in starts part way through the cell data).
|
|
309 |
TInt cellOffset = TUint32( aCellAddress ) - TUint32( requestedCellAddress );
|
|
310 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ReadActiveObjectDataL() - AO.cellOffset: %d (ignoring cell header)", cellOffset);
|
|
311 |
cellOffset -= cellHeaderSize;
|
|
312 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ReadActiveObjectDataL() - AO.cellOffset: %d (adjusted for cell header)", cellOffset);
|
|
313 |
|
|
314 |
// Got the cell data for the active object. Let's parse it.
|
|
315 |
RBufReadStream stream( *data, cellOffset );
|
|
316 |
CleanupClosePushL( stream );
|
|
317 |
|
|
318 |
// First item should be vTable
|
|
319 |
TAny* vTable = (TAny*) stream.ReadUint32L();
|
|
320 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ReadActiveObjectDataL() - AO.vTable: 0x%08x", vTable );
|
|
321 |
|
|
322 |
// Next item should be the request status. First the iStatus, then the iFlags
|
|
323 |
const TInt requestStatusValue = stream.ReadInt32L();
|
|
324 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ReadActiveObjectDataL() - AO.rsVal: %10d", requestStatusValue );
|
|
325 |
const TUint requestStatusFlags = stream.ReadUint32L();
|
|
326 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ReadActiveObjectDataL() - AO.rsFlags: 0x%02x", requestStatusFlags );
|
|
327 |
|
|
328 |
// Next comes the baseclass for the link - TDblQueLinkBase
|
|
329 |
TAny* nextEntryAddress = (TAny*) stream.ReadUint32L();
|
|
330 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ReadActiveObjectDataL() - AO.iLink.Next: 0x%08x", nextEntryAddress );
|
|
331 |
TAny* prevEntryAddress = (TAny*) stream.ReadUint32L();
|
|
332 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ReadActiveObjectDataL() - AO.iLink.Prev: 0x%08x", prevEntryAddress );
|
|
333 |
|
|
334 |
// Next comes the TPriQueueLink itself
|
|
335 |
const TInt priority = stream.ReadInt32L();
|
|
336 |
//RDebug::Printf("CMemSpyEngineHelperActiveObject::ReadActiveObjectDataL() - AO.iLink.Pri: %d", priority );
|
|
337 |
|
|
338 |
// Done - save object & tidy up
|
|
339 |
CMemSpyEngineActiveObject* object = CMemSpyEngineActiveObject::NewLC( aCellAddress, vTable, priority, requestStatusValue, requestStatusFlags, nextEntryAddress, prevEntryAddress, iEngine );
|
|
340 |
aArray.AddItemL( object );
|
|
341 |
CleanupStack::Pop( object );
|
|
342 |
CleanupStack::PopAndDestroy( 2, data ); // stream & data
|
|
343 |
|
|
344 |
nextCellAddress = (TAny*) nextEntryAddress;
|
|
345 |
//RDebug::Printf(" ");
|
|
346 |
}
|
|
347 |
|
|
348 |
return nextCellAddress;
|
|
349 |
}
|
|
350 |
|
|
351 |
|
|
352 |
void CMemSpyEngineHelperActiveObject::CleanupHeapWalk( TAny* aSelf )
|
|
353 |
{
|
|
354 |
CMemSpyEngineHelperActiveObject* self = reinterpret_cast< CMemSpyEngineHelperActiveObject* >( aSelf );
|
|
355 |
self->iEngine.Driver().WalkHeapClose();
|
|
356 |
}
|
|
357 |
|
|
358 |
|
|
359 |
|
|
360 |
|
|
361 |
|
|
362 |
|
|
363 |
|
|
364 |
|
|
365 |
|
|
366 |
|
|
367 |
|
|
368 |
|
|
369 |
|
|
370 |
|
|
371 |
|
|
372 |
|
|
373 |
|
|
374 |
|
|
375 |
|
|
376 |
|
|
377 |
|
|
378 |
|
|
379 |
|
|
380 |
|
|
381 |
|
|
382 |
|
|
383 |
|
|
384 |
|
|
385 |
|
|
386 |
|
|
387 |
|
|
388 |
|
|
389 |
|
|
390 |
CMemSpyEngineActiveObjectArray::CMemSpyEngineActiveObjectArray()
|
|
391 |
{
|
|
392 |
}
|
|
393 |
|
|
394 |
|
|
395 |
EXPORT_C CMemSpyEngineActiveObjectArray::~CMemSpyEngineActiveObjectArray()
|
|
396 |
{
|
|
397 |
delete iHeader;
|
|
398 |
iObjects.ResetAndDestroy();
|
|
399 |
iObjects.Close();
|
|
400 |
}
|
|
401 |
|
|
402 |
|
|
403 |
void CMemSpyEngineActiveObjectArray::ConstructL()
|
|
404 |
{
|
|
405 |
}
|
|
406 |
|
|
407 |
|
|
408 |
CMemSpyEngineActiveObjectArray* CMemSpyEngineActiveObjectArray::NewLC( )
|
|
409 |
{
|
|
410 |
CMemSpyEngineActiveObjectArray* self = new(ELeave) CMemSpyEngineActiveObjectArray();
|
|
411 |
CleanupStack::PushL( self );
|
|
412 |
self->ConstructL();
|
|
413 |
return self;
|
|
414 |
}
|
|
415 |
|
|
416 |
|
|
417 |
EXPORT_C TInt CMemSpyEngineActiveObjectArray::Count() const
|
|
418 |
{
|
|
419 |
return iObjects.Count();
|
|
420 |
}
|
|
421 |
|
|
422 |
|
|
423 |
EXPORT_C CMemSpyEngineActiveObject& CMemSpyEngineActiveObjectArray::At( TInt aIndex )
|
|
424 |
{
|
|
425 |
return *iObjects[ aIndex ];
|
|
426 |
}
|
|
427 |
|
|
428 |
|
|
429 |
EXPORT_C const CMemSpyEngineActiveObject& CMemSpyEngineActiveObjectArray::At( TInt aIndex ) const
|
|
430 |
{
|
|
431 |
return *iObjects[ aIndex ];
|
|
432 |
}
|
|
433 |
|
|
434 |
|
|
435 |
EXPORT_C CMemSpyEngineActiveObject& CMemSpyEngineActiveObjectArray::ObjectByAddressL( TAny* aAddress )
|
|
436 |
{
|
|
437 |
const TInt index = ObjectIndexByAddress( aAddress );
|
|
438 |
User::LeaveIfError( index );
|
|
439 |
CMemSpyEngineActiveObject& ret = At( index );
|
|
440 |
return ret;
|
|
441 |
}
|
|
442 |
|
|
443 |
|
|
444 |
EXPORT_C TInt CMemSpyEngineActiveObjectArray::ObjectIndexByAddress( TAny* aAddress ) const
|
|
445 |
{
|
|
446 |
TInt ret = KErrNotFound;
|
|
447 |
//
|
|
448 |
const TInt count = Count();
|
|
449 |
for( TInt i=0; i<count; i++ )
|
|
450 |
{
|
|
451 |
const CMemSpyEngineActiveObject& object = At( i );
|
|
452 |
//
|
|
453 |
if ( object.Address() == aAddress )
|
|
454 |
{
|
|
455 |
ret = i;
|
|
456 |
break;
|
|
457 |
}
|
|
458 |
}
|
|
459 |
//
|
|
460 |
return ret;
|
|
461 |
}
|
|
462 |
|
|
463 |
|
|
464 |
EXPORT_C void CMemSpyEngineActiveObjectArray::OutputDataColumnsL( CMemSpyEngine& aEngine )
|
|
465 |
{
|
|
466 |
HBufC* columns = HBufC::NewLC( 1024 );
|
|
467 |
TPtr pColumns( columns->Des() );
|
|
468 |
//
|
|
469 |
_LIT(KCol1, "Address");
|
|
470 |
pColumns.Append( KCol1 );
|
|
471 |
pColumns.Append( KMemSpyEngineAOOutputComma );
|
|
472 |
//
|
|
473 |
_LIT(KCol3, "Priority");
|
|
474 |
pColumns.Append( KCol3 );
|
|
475 |
pColumns.Append( KMemSpyEngineAOOutputComma );
|
|
476 |
//
|
|
477 |
_LIT(KCol4, "Is Active");
|
|
478 |
pColumns.Append( KCol4 );
|
|
479 |
pColumns.Append( KMemSpyEngineAOOutputComma );
|
|
480 |
//
|
|
481 |
_LIT(KCol5, "Request Pending");
|
|
482 |
pColumns.Append( KCol5 );
|
|
483 |
pColumns.Append( KMemSpyEngineAOOutputComma );
|
|
484 |
//
|
|
485 |
_LIT(KCol6, "Status Value");
|
|
486 |
pColumns.Append( KCol6 );
|
|
487 |
pColumns.Append( KMemSpyEngineAOOutputComma );
|
|
488 |
//
|
|
489 |
_LIT(KCol7, "Status Flags");
|
|
490 |
pColumns.Append( KCol7 );
|
|
491 |
pColumns.Append( KMemSpyEngineAOOutputComma );
|
|
492 |
//
|
|
493 |
_LIT(KCol8, "vTable Address");
|
|
494 |
pColumns.Append( KCol8 );
|
|
495 |
pColumns.Append( KMemSpyEngineAOOutputComma );
|
|
496 |
//
|
|
497 |
_LIT(KCol9, "vTable for Symbolic Lookup");
|
|
498 |
pColumns.Append( KCol9 );
|
|
499 |
//
|
|
500 |
aEngine.Sink().OutputLineL( pColumns );
|
|
501 |
CleanupStack::PopAndDestroy( columns );
|
|
502 |
}
|
|
503 |
|
|
504 |
|
|
505 |
EXPORT_C TInt CMemSpyEngineActiveObjectArray::MdcaCount() const
|
|
506 |
{
|
|
507 |
TInt count = Count();
|
|
508 |
//
|
|
509 |
if ( count > 0 )
|
|
510 |
{
|
|
511 |
++count;
|
|
512 |
}
|
|
513 |
//
|
|
514 |
return count;
|
|
515 |
}
|
|
516 |
|
|
517 |
|
|
518 |
EXPORT_C TPtrC CMemSpyEngineActiveObjectArray::MdcaPoint( TInt aIndex ) const
|
|
519 |
{
|
|
520 |
TPtrC ret( *iHeader );
|
|
521 |
//
|
|
522 |
if ( aIndex > 0 )
|
|
523 |
{
|
|
524 |
const CMemSpyEngineActiveObject& object = At( aIndex - 1 );
|
|
525 |
ret.Set( object.Caption() );
|
|
526 |
}
|
|
527 |
//
|
|
528 |
return ret;
|
|
529 |
}
|
|
530 |
|
|
531 |
|
|
532 |
void CMemSpyEngineActiveObjectArray::AddItemL( CMemSpyEngineActiveObject* aItem )
|
|
533 |
{
|
|
534 |
iObjects.AppendL( aItem );
|
|
535 |
BuildHeaderCaptionL();
|
|
536 |
}
|
|
537 |
|
|
538 |
|
|
539 |
void CMemSpyEngineActiveObjectArray::InsertL( CMemSpyEngineActiveObject* aItem, TInt aIndex )
|
|
540 |
{
|
|
541 |
iObjects.InsertL( aItem, aIndex );
|
|
542 |
BuildHeaderCaptionL();
|
|
543 |
}
|
|
544 |
|
|
545 |
|
|
546 |
void CMemSpyEngineActiveObjectArray::BuildHeaderCaptionL()
|
|
547 |
{
|
|
548 |
const TInt KHeaderLength = 100;
|
|
549 |
//
|
|
550 |
if ( !iHeader )
|
|
551 |
{
|
|
552 |
iHeader = HBufC::NewL( KHeaderLength );
|
|
553 |
}
|
|
554 |
//
|
|
555 |
TPtr pHeader( iHeader->Des() );
|
|
556 |
//
|
|
557 |
_LIT(KCaption, "\tNumber of AO\'s\t\t%d");
|
|
558 |
pHeader.Format( KCaption, Count() );
|
|
559 |
}
|
|
560 |
|
|
561 |
|
|
562 |
|
|
563 |
|
|
564 |
|
|
565 |
|
|
566 |
|
|
567 |
|
|
568 |
|
|
569 |
|
|
570 |
|
|
571 |
|
|
572 |
|
|
573 |
|
|
574 |
|
|
575 |
|
|
576 |
|
|
577 |
|
|
578 |
|
|
579 |
|
|
580 |
|
|
581 |
|
|
582 |
|
|
583 |
|
|
584 |
|
|
585 |
CMemSpyEngineActiveObject::CMemSpyEngineActiveObject( TAny* aAddress, TAny* aVTable, TInt aPriority, TInt aRSValue, TUint aRSFlags, TAny* aNextAOAddress, TAny* aPrevAOAddress )
|
|
586 |
: CDesCArrayFlat(6), iAddress( aAddress ), iVTable( aVTable ), iPriority( aPriority ), iRequestStatusValue( aRSValue ), iRequestStatusFlags( aRSFlags ), iNextAOAddress( aNextAOAddress ), iPrevAOAddress( aPrevAOAddress )
|
|
587 |
{
|
|
588 |
}
|
|
589 |
|
|
590 |
|
|
591 |
EXPORT_C CMemSpyEngineActiveObject::~CMemSpyEngineActiveObject()
|
|
592 |
{
|
|
593 |
delete iCaption;
|
|
594 |
}
|
|
595 |
|
|
596 |
|
|
597 |
void CMemSpyEngineActiveObject::ConstructL( CMemSpyEngine& /*aEngine*/ )
|
|
598 |
{
|
|
599 |
TBuf<256> item;
|
|
600 |
|
|
601 |
_LIT(KBasicFormat, "\t0x%08x\t\t");
|
|
602 |
item.Format( KBasicFormat, VTable() );
|
|
603 |
|
|
604 |
// Add modifiers
|
|
605 |
_LIT( KModifiers, "%d" );
|
|
606 |
_LIT( KBoxedCharFormat, " [%c]" );
|
|
607 |
item.AppendFormat( KModifiers, RequestStatusValue() );
|
|
608 |
if ( IsActive() )
|
|
609 |
{
|
|
610 |
item.AppendFormat( KBoxedCharFormat, 'A' );
|
|
611 |
}
|
|
612 |
if ( RequestIsPending() )
|
|
613 |
{
|
|
614 |
item.AppendFormat( KBoxedCharFormat, 'P' );
|
|
615 |
}
|
|
616 |
iCaption = item.AllocL();
|
|
617 |
|
|
618 |
// Listbox items
|
|
619 |
TPtrC value;
|
|
620 |
|
|
621 |
// Address
|
|
622 |
_LIT(KCaption1, "\tAddress\t\t0x%08x");
|
|
623 |
item.Format( KCaption1, iAddress );
|
|
624 |
AppendL( item );
|
|
625 |
|
|
626 |
// vTable
|
|
627 |
_LIT(KCaption2, "\tVTable\t\t0x%08x");
|
|
628 |
item.Format( KCaption2, iVTable );
|
|
629 |
AppendL( item );
|
|
630 |
|
|
631 |
//
|
|
632 |
_LIT(KCaption3, "\tStatus Value\t\t%d");
|
|
633 |
item.Format( KCaption3, iRequestStatusValue );
|
|
634 |
AppendL( item );
|
|
635 |
|
|
636 |
//
|
|
637 |
_LIT(KCaption5, "\tIs Active\t\t%S");
|
|
638 |
value.Set( YesNoValue( IsActive() ) );
|
|
639 |
item.Format( KCaption5, &value );
|
|
640 |
AppendL( item );
|
|
641 |
|
|
642 |
//
|
|
643 |
_LIT(KCaption6, "\tRequest Pending\t\t%S");
|
|
644 |
value.Set( YesNoValue( RequestIsPending() ) );
|
|
645 |
item.Format( KCaption6, &value );
|
|
646 |
AppendL( item );
|
|
647 |
|
|
648 |
//
|
|
649 |
_LIT(KCaption4, "\tPriority\t\t%d");
|
|
650 |
item.Format( KCaption4, iPriority );
|
|
651 |
AppendL( item );
|
|
652 |
}
|
|
653 |
|
|
654 |
|
|
655 |
CMemSpyEngineActiveObject* CMemSpyEngineActiveObject::NewLC( TAny* aAddress, TAny* aVTable, TInt aPriority, TInt aRSValue, TUint aRSFlags, TAny* aNextAOAddress, TAny* aPrevAOAddress, CMemSpyEngine& aEngine )
|
|
656 |
{
|
|
657 |
CMemSpyEngineActiveObject* self = new(ELeave) CMemSpyEngineActiveObject( aAddress, aVTable, aPriority, aRSValue, aRSFlags, aNextAOAddress, aPrevAOAddress );
|
|
658 |
CleanupStack::PushL( self );
|
|
659 |
self->ConstructL( aEngine );
|
|
660 |
return self;
|
|
661 |
}
|
|
662 |
|
|
663 |
|
|
664 |
EXPORT_C TBool CMemSpyEngineActiveObject::IsActive() const
|
|
665 |
{
|
|
666 |
return ( iRequestStatusFlags & CMemSpyEngineActiveObject::EActive );
|
|
667 |
}
|
|
668 |
|
|
669 |
|
|
670 |
EXPORT_C TBool CMemSpyEngineActiveObject::IsAddedToScheduler() const
|
|
671 |
{
|
|
672 |
return ( iNextAOAddress != NULL );
|
|
673 |
}
|
|
674 |
|
|
675 |
|
|
676 |
EXPORT_C TBool CMemSpyEngineActiveObject::RequestIsPending() const
|
|
677 |
{
|
|
678 |
return ( iRequestStatusFlags & CMemSpyEngineActiveObject::ERequestPending );
|
|
679 |
}
|
|
680 |
|
|
681 |
|
|
682 |
EXPORT_C void CMemSpyEngineActiveObject::OutputDataL( CMemSpyEngine& aEngine ) const
|
|
683 |
{
|
|
684 |
_LIT(KMemSpyEngineAOOutputHex, "0x%08x");
|
|
685 |
_LIT(KMemSpyEngineAOOutputDecimal, "%d");
|
|
686 |
_LIT(KMemSpyEngineAOOutputDecimalFixed10, "%10d");
|
|
687 |
_LIT(KMemSpyEngineAOOutputString, "%S");
|
|
688 |
_LIT(KMemSpyEngineAOOutputVTable, "vTable: 0x%08x");
|
|
689 |
//
|
|
690 |
TPtrC yesNoValue( KNullDesC );
|
|
691 |
HBufC* columns = HBufC::NewLC( 1024 );
|
|
692 |
TPtr pColumns( columns->Des() );
|
|
693 |
//
|
|
694 |
pColumns.AppendFormat( KMemSpyEngineAOOutputHex, Address() );
|
|
695 |
pColumns.Append( KMemSpyEngineAOOutputComma );
|
|
696 |
//
|
|
697 |
pColumns.AppendFormat( KMemSpyEngineAOOutputDecimal, Priority() );
|
|
698 |
pColumns.Append( KMemSpyEngineAOOutputComma );
|
|
699 |
//
|
|
700 |
yesNoValue.Set( YesNoValue( IsActive() ) );
|
|
701 |
pColumns.AppendFormat( KMemSpyEngineAOOutputString, &yesNoValue );
|
|
702 |
pColumns.Append( KMemSpyEngineAOOutputComma );
|
|
703 |
//
|
|
704 |
yesNoValue.Set( YesNoValue( RequestIsPending() ) );
|
|
705 |
pColumns.AppendFormat( KMemSpyEngineAOOutputString, &yesNoValue );
|
|
706 |
pColumns.Append( KMemSpyEngineAOOutputComma );
|
|
707 |
//
|
|
708 |
pColumns.AppendFormat( KMemSpyEngineAOOutputDecimalFixed10, RequestStatusValue() );
|
|
709 |
pColumns.Append( KMemSpyEngineAOOutputComma );
|
|
710 |
//
|
|
711 |
pColumns.AppendFormat( KMemSpyEngineAOOutputDecimal, RequestStatusFlags() );
|
|
712 |
pColumns.Append( KMemSpyEngineAOOutputComma );
|
|
713 |
//
|
|
714 |
pColumns.AppendFormat( KMemSpyEngineAOOutputHex, VTable() );
|
|
715 |
pColumns.Append( KMemSpyEngineAOOutputComma );
|
|
716 |
//
|
|
717 |
pColumns.AppendFormat( KMemSpyEngineAOOutputVTable, VTable() );
|
|
718 |
//
|
|
719 |
aEngine.Sink().OutputLineL( pColumns );
|
|
720 |
CleanupStack::PopAndDestroy( columns );
|
|
721 |
}
|
|
722 |
|
|
723 |
|
|
724 |
TPtrC CMemSpyEngineActiveObject::YesNoValue( TBool aValue )
|
|
725 |
{
|
|
726 |
_LIT(KYesString, "Yes");
|
|
727 |
_LIT(KNoString, "No");
|
|
728 |
//
|
|
729 |
TPtrC pRet( KNoString );
|
|
730 |
if ( aValue )
|
|
731 |
{
|
|
732 |
pRet.Set( KYesString );
|
|
733 |
}
|
|
734 |
//
|
|
735 |
return pRet;
|
|
736 |
}
|
|
737 |
|