sysperfana/heapanalyser/Libraries/Engine/HeapLib/Reconstructor/RHeap/Extractor/Extractor.cs
changeset 8 15296fd0af4a
equal deleted inserted replaced
7:8e12a575a9b5 8:15296fd0af4a
       
     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 }