|
1 /* |
|
2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * |
|
5 * Redistribution and use in source and binary forms, with or without |
|
6 * modification, are permitted provided that the following conditions are met: |
|
7 * |
|
8 * - Redistributions of source code must retain the above copyright notice, |
|
9 * this list of conditions and the following disclaimer. |
|
10 * - Redistributions in binary form must reproduce the above copyright notice, |
|
11 * this list of conditions and the following disclaimer in the documentation |
|
12 * and/or other materials provided with the distribution. |
|
13 * - Neither the name of Nokia Corporation nor the names of its contributors |
|
14 * may be used to endorse or promote products derived from this software |
|
15 * without specific prior written permission. |
|
16 * |
|
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
|
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
27 * POSSIBILITY OF SUCH DAMAGE. |
|
28 * |
|
29 * Initial Contributors: |
|
30 * Nokia Corporation - initial contribution. |
|
31 * |
|
32 * Contributors: |
|
33 * |
|
34 * Description: |
|
35 * |
|
36 */ |
|
37 |
|
38 using System; |
|
39 using System.Text; |
|
40 using System.Text.RegularExpressions; |
|
41 using System.Threading; |
|
42 using System.Collections; |
|
43 using System.Collections.Generic; |
|
44 using SymbianStructuresLib.CodeSegments; |
|
45 using SymbianStructuresLib.Debug.Symbols; |
|
46 using SymbianDebugLib.Engine; |
|
47 using SymbianDebugLib.PluginAPI.Types; |
|
48 using SymbianDebugLib.PluginAPI.Types.Symbol; |
|
49 using SymbianUtils; |
|
50 using SymbianUtils.Range; |
|
51 using SymbianUtils.RawItems; |
|
52 using HeapLib.Cells; |
|
53 using HeapLib.Array; |
|
54 using HeapLib.Statistics; |
|
55 using HeapLib.Relationships; |
|
56 using HeapLib.Reconstructor.Misc; |
|
57 using HeapLib.Reconstructor.DataSources; |
|
58 |
|
59 namespace HeapLib.Reconstructor.RHeap.Extractor |
|
60 { |
|
61 internal class RHeapExtractor : AsyncReaderBase |
|
62 { |
|
63 #region Constructors & destructor |
|
64 public RHeapExtractor( DataSource aDataSource, Options aOptions, DbgEngine aDebugEngine, RelationshipInspector aRelationshipInspector, HeapStatistics aStatistics, HeapCellArray aData ) |
|
65 { |
|
66 iData = aData; |
|
67 iOptions = aOptions; |
|
68 iStatistics = aStatistics; |
|
69 iDataSource = aDataSource; |
|
70 iDebugEngine = aDebugEngine; |
|
71 iState = new ExtractionState( aDataSource ); |
|
72 iRelationshipInspector = aRelationshipInspector; |
|
73 // |
|
74 HeapCell.AllocatedCellHeaderSize = AllocatedCellHeaderSize; |
|
75 |
|
76 // Must prime these |
|
77 iState.NextFreeCellAddress = aDataSource.MetaData.Heap.InfoFree.FreeCellAddress; |
|
78 iState.NextFreeCellLength = aDataSource.MetaData.Heap.InfoFree.FreeCellLength; |
|
79 // |
|
80 if ( iState.NextFreeCellAddress == 0 ) |
|
81 { |
|
82 throw new ArgumentException( "Next free cell information invalid" ); |
|
83 } |
|
84 |
|
85 //iState.DebugEnabled = true; |
|
86 } |
|
87 #endregion |
|
88 |
|
89 #region API |
|
90 public void Extract() |
|
91 { |
|
92 base.AsyncRead(); |
|
93 } |
|
94 #endregion |
|
95 |
|
96 #region Properties |
|
97 public AddressRange AddressRange |
|
98 { |
|
99 get { return Statistics.AddressRange; } |
|
100 } |
|
101 |
|
102 public DbgViewSymbol SymbolView |
|
103 { |
|
104 get { return iDebugView.Symbols; } |
|
105 } |
|
106 |
|
107 public Options Options |
|
108 { |
|
109 get { return iOptions; } |
|
110 } |
|
111 |
|
112 public HeapStatistics Statistics |
|
113 { |
|
114 get { return iStatistics; } |
|
115 } |
|
116 |
|
117 public uint AllocatedCellHeaderSize |
|
118 { |
|
119 get |
|
120 { |
|
121 HeapCell.TBuildType buildType = HeapCell.TBuildType.ERelease; |
|
122 // |
|
123 if ( iDataSource.MetaData.Heap.DebugAllocator ) |
|
124 { |
|
125 buildType = HeapCell.TBuildType.EDebug; |
|
126 } |
|
127 // |
|
128 uint size = HeapCell.AllocatedCellSizeByBuildType( buildType ); |
|
129 return size; |
|
130 } |
|
131 } |
|
132 |
|
133 public HeapCellArray Data |
|
134 { |
|
135 get { return iData; } |
|
136 } |
|
137 |
|
138 public DataSource SourceData |
|
139 { |
|
140 get { return iDataSource; } |
|
141 } |
|
142 #endregion |
|
143 |
|
144 #region From AsyncReaderBase |
|
145 protected override void HandleReadStarted() |
|
146 { |
|
147 try |
|
148 { |
|
149 // Prepare view |
|
150 CodeSegDefinitionCollection codeSegs = iDataSource.MetaData.CodeSegments; |
|
151 iDebugView = iDebugEngine.CreateView( "Heap Analyser: " + iDataSource.ThreadName, codeSegs ); |
|
152 } |
|
153 finally |
|
154 { |
|
155 base.HandleReadStarted(); |
|
156 } |
|
157 } |
|
158 |
|
159 protected override void HandleReadCompleted() |
|
160 { |
|
161 base.HandleReadCompleted(); |
|
162 |
|
163 // Do we have a cell that isn't quite flushed? |
|
164 if ( iCurrentHeapCell != null ) |
|
165 { |
|
166 FinaliseCurrentCell(); |
|
167 } |
|
168 |
|
169 // Finished with the debug view now. |
|
170 iDebugView.Dispose(); |
|
171 iDebugView = null; |
|
172 } |
|
173 |
|
174 protected override void PerformOperation() |
|
175 { |
|
176 uint baseAddress = iDataSource.MetaData.Heap.HeapBaseAddress; |
|
177 byte[] data = iDataSource.MetaData.HeapData.Data; |
|
178 long size = data.LongLength; |
|
179 iPosition = 0; |
|
180 // |
|
181 while ( iPosition < size ) |
|
182 { |
|
183 int amountToProcess = (int) Math.Min( KBatchSize, size - iPosition ); |
|
184 if ( amountToProcess > 0 ) |
|
185 { |
|
186 // Extract bytes |
|
187 byte[] transientData = new byte[ amountToProcess ]; |
|
188 System.Array.Copy( data, iPosition, transientData, 0, amountToProcess ); |
|
189 |
|
190 // Add them to queue |
|
191 uint address = (uint) ( baseAddress + iPosition ); |
|
192 iWorkingItemQueue.Add( transientData, address ); |
|
193 |
|
194 // Process items in queue |
|
195 ExecuteStateLoop(); |
|
196 |
|
197 // Move to next address |
|
198 iPosition += amountToProcess; |
|
199 } |
|
200 |
|
201 // Report progress |
|
202 NotifyEvent( TEvent.EReadingProgress ); |
|
203 } |
|
204 } |
|
205 |
|
206 protected override long Size |
|
207 { |
|
208 get { return iDataSource.MetaData.HeapData.Count; } |
|
209 } |
|
210 |
|
211 protected override long Position |
|
212 { |
|
213 get { return iPosition; } |
|
214 } |
|
215 #endregion |
|
216 |
|
217 #region Internal state enumeration |
|
218 private enum TState |
|
219 { |
|
220 EGettingHeapCellLength = 0, |
|
221 EGettingNestingLevel, |
|
222 EGettingNextFreeCellAddress, |
|
223 EGettingAllocationNumber, |
|
224 EGettingVTable, |
|
225 ESkippingToAddress, |
|
226 ECapturingRawData |
|
227 } |
|
228 #endregion |
|
229 |
|
230 #region State handlers |
|
231 private void ExecuteStateLoop() |
|
232 { |
|
233 // Now handle the items that were parsed according to the |
|
234 // current state |
|
235 bool continueProcessing = ( iWorkingItemQueue.Count > 0 ); |
|
236 while ( continueProcessing ) |
|
237 { |
|
238 switch ( iCurrentState ) |
|
239 { |
|
240 case TState.EGettingHeapCellLength: |
|
241 StateGettingHeapCellLength(); |
|
242 break; |
|
243 case TState.EGettingNextFreeCellAddress: |
|
244 StateGettingNextFreeCellAddress(); |
|
245 break; |
|
246 case TState.EGettingNestingLevel: |
|
247 StateGettingNestingLevel(); |
|
248 break; |
|
249 case TState.EGettingAllocationNumber: |
|
250 StateGettingAllocationNumber(); |
|
251 break; |
|
252 case TState.EGettingVTable: |
|
253 StateGettingVTable(); |
|
254 break; |
|
255 case TState.ESkippingToAddress: |
|
256 StateSkippingToAddress(); |
|
257 break; |
|
258 case TState.ECapturingRawData: |
|
259 StateCapturingRawData(); |
|
260 break; |
|
261 default: |
|
262 continueProcessing = false; |
|
263 break; |
|
264 } |
|
265 |
|
266 // If we don't have any items left then we must wait |
|
267 // for more data |
|
268 continueProcessing = ( iWorkingItemQueue.Count > 0 ); |
|
269 } |
|
270 } |
|
271 |
|
272 private void SetNextState( TState aNewState ) |
|
273 { |
|
274 iCurrentState = aNewState; |
|
275 } |
|
276 |
|
277 private void StateGettingHeapCellLength() |
|
278 { |
|
279 if ( iCurrentHeapCell != null ) |
|
280 throw new ArgumentException( "Heap cell should be NULL" ); |
|
281 |
|
282 RawItem item = iWorkingItemQueue.DequeueHeadItem(); |
|
283 |
|
284 // Now make a new cell |
|
285 iCurrentHeapCell = new HeapCell(); |
|
286 iCurrentHeapCell.Address = item.Address; |
|
287 iCurrentHeapCell.AddRawItemHeader( item ); |
|
288 // |
|
289 iState.NextCellAddress = iCurrentHeapCell.Address + iCurrentHeapCell.Length; |
|
290 iState.CurrentAddress = item.Address; |
|
291 // |
|
292 Debug( "[Cell] 0x" + iState.CurrentAddress.ToString( "x8" ) + ", " + item.Data.ToString() + " bytes long, next cell: 0x" + iState.NextCellAddress.ToString( "x8" ) ); |
|
293 // |
|
294 TState nextState = TState.EGettingVTable; |
|
295 if ( iState.IsFreeCellAddress() ) |
|
296 { |
|
297 // FREE cell |
|
298 iCurrentHeapCell.Type = HeapCell.TType.EFree; |
|
299 |
|
300 // Try to get the next free cell address |
|
301 nextState = TState.EGettingNextFreeCellAddress; |
|
302 } |
|
303 else |
|
304 { |
|
305 // ALLOCATED cell |
|
306 if ( HeapCell.IsDebugAllocator ) |
|
307 { |
|
308 nextState = TState.EGettingNestingLevel; |
|
309 } |
|
310 } |
|
311 // |
|
312 SetNextState( nextState ); |
|
313 } |
|
314 |
|
315 private void StateGettingNextFreeCellAddress() |
|
316 { |
|
317 if ( iCurrentHeapCell == null ) |
|
318 throw new ArgumentException( "Heap cell is NULL!" ); |
|
319 |
|
320 RawItem item = iWorkingItemQueue.DequeueHeadItem(); |
|
321 iState.NextFreeCellAddress = item.Data; |
|
322 if ( iState.NextFreeCellAddress > Statistics.AddressRange.Max ) |
|
323 { |
|
324 iDataSource.AddError( DataSource.TErrorTypes.EErrorTypeFreeCellAddressOutOfBounds ); |
|
325 } |
|
326 |
|
327 iCurrentHeapCell.AddRawItemHeader( item ); |
|
328 MarkForInspection( item ); |
|
329 |
|
330 iState.CurrentAddress += RawItem.KSizeOfOneRawItemInBytes; |
|
331 System.Diagnostics.Debug.Assert( iState.CurrentAddress == item.Address ); |
|
332 Debug( " {0x" + iState.CurrentAddress.ToString( "x8" ) + "} - free: " + item.Data.ToString( "x8" ) ); |
|
333 |
|
334 // If we're decoding free cell contents, instead |
|
335 // we should try to identify the vTable info from |
|
336 // what remains of the free cell data |
|
337 TState nextState = TState.ECapturingRawData; |
|
338 if ( Options.AttemptToDecodeFreeCellContents ) |
|
339 { |
|
340 nextState = TState.EGettingVTable; |
|
341 } |
|
342 SetNextState( nextState ); |
|
343 } |
|
344 |
|
345 private void StateGettingNestingLevel() |
|
346 { |
|
347 System.Diagnostics.Debug.Assert( HeapCell.IsDebugAllocator ); |
|
348 if ( iCurrentHeapCell == null ) |
|
349 throw new ArgumentException( "Heap cell is NULL!" ); |
|
350 // |
|
351 RawItem item = iWorkingItemQueue.DequeueHeadItem(); |
|
352 iCurrentHeapCell.AddRawItemHeader( item ); |
|
353 // |
|
354 iState.CurrentAddress += RawItem.KSizeOfOneRawItemInBytes; |
|
355 Debug( " {0x" + iState.CurrentAddress.ToString( "x8" ) + "} - nexting lev: " + iCurrentHeapCell.NestingLevel ); |
|
356 // |
|
357 SetNextState( TState.EGettingAllocationNumber ); |
|
358 } |
|
359 |
|
360 private void StateGettingAllocationNumber() |
|
361 { |
|
362 System.Diagnostics.Debug.Assert( HeapCell.IsDebugAllocator ); |
|
363 if ( iCurrentHeapCell == null ) |
|
364 throw new ArgumentException( "Heap cell is NULL!" ); |
|
365 // |
|
366 RawItem item = iWorkingItemQueue.DequeueHeadItem(); |
|
367 iCurrentHeapCell.AddRawItemHeader( item ); |
|
368 // |
|
369 iState.CurrentAddress += 4; |
|
370 System.Diagnostics.Debug.Assert( iState.CurrentAddress == item.Address ); |
|
371 Debug( " {0x" + iState.CurrentAddress.ToString( "x8" ) + "} - alloc num: " + iCurrentHeapCell.AllocationNumber ); |
|
372 // |
|
373 SetNextState( TState.EGettingVTable ); |
|
374 } |
|
375 |
|
376 private void StateGettingVTable() |
|
377 { |
|
378 if ( iCurrentHeapCell == null ) |
|
379 throw new ArgumentException( "Heap cell is NULL!" ); |
|
380 |
|
381 RawItem item = iWorkingItemQueue.DequeueHeadItem(); |
|
382 iState.CurrentAddress += RawItem.KSizeOfOneRawItemInBytes; |
|
383 System.Diagnostics.Debug.Assert( iState.CurrentAddress == item.Address ); |
|
384 |
|
385 // When dealing with allocated cells, then the vtable is always the first 4 bytes |
|
386 // of the cell. |
|
387 // |
|
388 // When dealing with free cells, then this raw data item might be part of the free |
|
389 // cell (if the free cell length is > 12 bytes) or then it might be part of the |
|
390 // next cell. |
|
391 bool isFromNextCell = ( item.Address == iState.NextCellAddress ); |
|
392 // |
|
393 System.Diagnostics.Debug.Assert( iState.CurrentAddress == item.Address ); |
|
394 Debug( " {0x" + iState.CurrentAddress.ToString( "x8" ) + "} - raw: " + item.Data.ToString( "x8" ) ); |
|
395 // |
|
396 if ( isFromNextCell ) |
|
397 { |
|
398 // Finalise the cell, i.e. update tracker and store |
|
399 // cell to array. |
|
400 FinaliseCurrentCell(); |
|
401 |
|
402 // Push the item back again ready for parings |
|
403 iWorkingItemQueue.ReEnqueueItem( item ); |
|
404 |
|
405 // We were skipping, but we found the first new item. |
|
406 // Save the cell as we've now completely processed it. |
|
407 SetNextState( TState.EGettingHeapCellLength ); |
|
408 } |
|
409 else |
|
410 { |
|
411 // Treat this as raw data for this cell |
|
412 AddRawItemToCurrentCell( item ); |
|
413 |
|
414 // Get next item |
|
415 SetNextState( TState.ECapturingRawData ); |
|
416 } |
|
417 } |
|
418 |
|
419 private void StateSkippingToAddress() |
|
420 { |
|
421 if ( iCurrentHeapCell != null ) |
|
422 throw new ArgumentException( "Heap cell should be NULL" ); |
|
423 if ( iState.NextCellAddress <= 0 ) |
|
424 throw new ArgumentException( "Start of next cell is <= 0" ); |
|
425 |
|
426 // Check to see if this item falls within our data range... |
|
427 RawItem item = iWorkingItemQueue.DequeueHeadItem(); |
|
428 bool preserveItem = ( item.Address >= iState.NextCellAddress ); |
|
429 // |
|
430 iState.CurrentAddress += RawItem.KSizeOfOneRawItemInBytes; |
|
431 System.Diagnostics.Debug.Assert( iState.CurrentAddress == item.Address ); |
|
432 Debug( " {0x" + iState.CurrentAddress.ToString( "x8" ) + "} - skiping: " + item.Data.ToString( "x8" ) ); |
|
433 // |
|
434 if ( preserveItem ) |
|
435 { |
|
436 // We were skipping, but we found the first new item |
|
437 SetNextState( TState.EGettingHeapCellLength ); |
|
438 |
|
439 // Push the item back again ready for parings |
|
440 iWorkingItemQueue.ReEnqueueItem( item ); |
|
441 } |
|
442 } |
|
443 |
|
444 private void StateCapturingRawData() |
|
445 { |
|
446 if ( iCurrentHeapCell == null ) |
|
447 throw new ArgumentException( "Heap cell is NULL!" ); |
|
448 if ( iState.NextCellAddress <= 0 ) |
|
449 throw new ArgumentException( "Start of next cell is <= 0" ); |
|
450 |
|
451 // Check to see if this item falls within our data range... |
|
452 RawItem item = iWorkingItemQueue.DequeueHeadItem(); |
|
453 bool isFromNextCell = ( item.Address == iState.NextCellAddress ); |
|
454 // |
|
455 iState.CurrentAddress += RawItem.KSizeOfOneRawItemInBytes; |
|
456 System.Diagnostics.Debug.Assert( iState.CurrentAddress == item.Address ); |
|
457 Debug( " {0x" + iState.CurrentAddress.ToString( "x8" ) + "} - raw: " + item.Data.ToString( "x8" ) ); |
|
458 // |
|
459 if ( isFromNextCell ) |
|
460 { |
|
461 // Finalise the cell, i.e. update tracker and store |
|
462 // cell to array. |
|
463 FinaliseCurrentCell(); |
|
464 |
|
465 // Push the item back again ready for parings |
|
466 iWorkingItemQueue.ReEnqueueItem( item ); |
|
467 |
|
468 // We were skipping, but we found the first new item. |
|
469 // Save the cell as we've now completely processed it. |
|
470 SetNextState( TState.EGettingHeapCellLength ); |
|
471 } |
|
472 else |
|
473 { |
|
474 // Treat this as raw data for this cell |
|
475 AddRawItemToCurrentCell( item ); |
|
476 } |
|
477 } |
|
478 #endregion |
|
479 |
|
480 #region Internal methods |
|
481 private bool AddressIsWithinHeapBounds( uint aAddress ) |
|
482 { |
|
483 bool inBounds = iStatistics.WithinHeapBounds( aAddress ); |
|
484 return inBounds; |
|
485 } |
|
486 |
|
487 private void AddRawItemToCurrentCell( RawItem aItem ) |
|
488 { |
|
489 iCurrentHeapCell.AddRawItem( aItem ); |
|
490 MarkForInspection( aItem ); |
|
491 } |
|
492 |
|
493 private void MarkForInspection( RawItem aItem ) |
|
494 { |
|
495 if ( !iAlreadyMarkedForInspection ) |
|
496 { |
|
497 // Check this cell later on to see what kind of relationships it has |
|
498 // with other cells. |
|
499 bool isWithinHeap = AddressIsWithinHeapBounds( aItem.Data ); |
|
500 if ( isWithinHeap ) |
|
501 { |
|
502 iRelationshipInspector.InspectLater( iCurrentHeapCell ); |
|
503 iAlreadyMarkedForInspection = true; |
|
504 } |
|
505 } |
|
506 } |
|
507 |
|
508 private Symbol FindMatchingSymbolAny( uint aAddress ) |
|
509 { |
|
510 return FindMatchingSymbol( aAddress, 0, false ); |
|
511 } |
|
512 |
|
513 private Symbol FindMatchingSymbolVTable( uint aAddress, uint aLength ) |
|
514 { |
|
515 return FindMatchingSymbol( aAddress, aLength, true ); |
|
516 } |
|
517 |
|
518 private Symbol FindMatchingSymbol( uint aAddress, uint aLength, bool aMustBeVTable ) |
|
519 { |
|
520 SymbolCollection collection; |
|
521 Symbol symbol = iDebugView.Symbols.Lookup( aAddress, out collection ); |
|
522 // |
|
523 if ( symbol != null ) |
|
524 { |
|
525 // If we just hit a "placeholder" symbol, then let's replace it with |
|
526 // something more unique so that we can better track statistics for these |
|
527 // binaries which we don't have proper symbolics for. |
|
528 if ( symbol.IsDefault && aLength > 0 ) |
|
529 { |
|
530 Symbol temp = Symbol.NewDefault(); |
|
531 temp.OffsetAddress = aAddress; |
|
532 temp.Size = aLength; // This is a kludge because we can never know |
|
533 temp.Object = symbol.Object; // how big the symbol was if we don't have symbolic info |
|
534 symbol = temp; |
|
535 System.Diagnostics.Debug.WriteLine( string.Format( "[IsUnknown] vTable: 0x{0:x8}, len: {1}", aAddress, aLength ) ); |
|
536 } |
|
537 else if ( aMustBeVTable && !symbol.IsVTable ) |
|
538 { |
|
539 // We did find a symbol, but it looks like a function or some other address |
|
540 // which is not type-info related. Do not associated with symbol in this situation. |
|
541 System.Diagnostics.Debug.WriteLine( string.Format( "[Not vTable] vTable: 0x{0:x8}, len: {1}, sym: {2}", aAddress, aLength, symbol.ToString() ) ); |
|
542 symbol = null; |
|
543 } |
|
544 } |
|
545 else if ( collection != null ) |
|
546 { |
|
547 System.Diagnostics.Debug.WriteLine( string.Format( "[No symbol] vTable: 0x{0:x8}, len: {1}, collection: {2}", aAddress, aLength, collection.FileName.FileNameInHost ) ); |
|
548 } |
|
549 // |
|
550 return symbol; |
|
551 } |
|
552 |
|
553 private void FinaliseCurrentCell() |
|
554 { |
|
555 HeapCell cell = iCurrentHeapCell; |
|
556 |
|
557 // Zero out cell. We'll make a new one in |
|
558 // StateGettingHeapCellLength() |
|
559 iCurrentHeapCell = null; |
|
560 |
|
561 // Set index |
|
562 cell.Index = (uint) iData.Count; |
|
563 |
|
564 // If we have just finished a cell, make sure we update |
|
565 // the statistics tracker with that cell's data. |
|
566 iData.Add( cell ); |
|
567 |
|
568 // Set this back to false since we're moving to a new cell |
|
569 iAlreadyMarkedForInspection = false; |
|
570 |
|
571 // Finish rest of construction |
|
572 DoFinaliseCell( cell ); |
|
573 } |
|
574 |
|
575 private void DoFinaliseCell( object aCell ) |
|
576 { |
|
577 HeapCell cell = (HeapCell) aCell; |
|
578 |
|
579 // Do symbolic lookups |
|
580 Debug( " {0x" + iState.CurrentAddress.ToString( "x8" ) + "} - vTable: " + cell.PossibleVTableAddress.ToString( "x8" ) ); |
|
581 cell.Symbol = FindMatchingSymbolVTable( cell.PossibleVTableAddress, cell.Length ); |
|
582 |
|
583 // If the MemSpy data includes stack-based function addresses stored instead |
|
584 // of nesting level, then we can also try to find a matching symbol. |
|
585 if ( SourceData.MetaData.Heap.IsDebugAllocatorWithStoredStackAddresses ) |
|
586 { |
|
587 cell.Symbol2 = FindMatchingSymbolAny( cell.NestingLevel ); |
|
588 cell.Symbol3 = FindMatchingSymbolAny( cell.AllocationNumber ); |
|
589 } |
|
590 |
|
591 // Cell is now finished. |
|
592 cell.ConstructionComplete( iStatistics ); |
|
593 |
|
594 // Update stats - do this after finalising the cell |
|
595 // as the act of finalisation may result in the |
|
596 // cell being tagged as a descriptor. This must be done |
|
597 // prior to the stats update, or else we won't treat |
|
598 // any cell as a descriptor! |
|
599 lock ( iStatistics ) |
|
600 { |
|
601 iStatistics.HandleCell( cell ); |
|
602 } |
|
603 } |
|
604 |
|
605 private void Debug( string aMessage ) |
|
606 { |
|
607 System.Diagnostics.Debug.WriteLineIf( iState.DebugEnabled, aMessage ); |
|
608 } |
|
609 #endregion |
|
610 |
|
611 #region Internal constants |
|
612 private const int KBatchSize = 1024; |
|
613 #endregion |
|
614 |
|
615 #region Data members |
|
616 private readonly DataSource iDataSource; |
|
617 private readonly Options iOptions; |
|
618 private readonly RelationshipInspector iRelationshipInspector; |
|
619 private readonly HeapStatistics iStatistics; |
|
620 private readonly HeapCellArray iData; |
|
621 private readonly ExtractionState iState; |
|
622 private readonly DbgEngine iDebugEngine; |
|
623 private DbgEngineView iDebugView = null; |
|
624 private TState iCurrentState; |
|
625 private HeapCell iCurrentHeapCell; |
|
626 private RawItemQueue iWorkingItemQueue = new RawItemQueue(); |
|
627 private long iPosition = 0; |
|
628 private bool iAlreadyMarkedForInspection = false; |
|
629 #endregion |
|
630 } |
|
631 } |