crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Plugins/Accurate/Algorithm/AccurateAlgorithm.cs
changeset 0 818e61de6cd1
equal deleted inserted replaced
-1:000000000000 0:818e61de6cd1
       
     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 using System;
       
    18 using System.Text;
       
    19 using SymbianStackAlgorithmAccurate.Engine;
       
    20 using SymbianStackAlgorithmAccurate.Interfaces;
       
    21 using SymbianStackAlgorithmAccurate.Stack;
       
    22 using SymbianStackLib.Algorithms;
       
    23 using SymbianStackLib.Data.Output;
       
    24 using SymbianStackLib.Data.Output.Entry;
       
    25 using SymbianStackLib.Data.Source;
       
    26 using SymbianStackLib.Interfaces;
       
    27 using SymbianStructuresLib.Arm.Registers;
       
    28 using SymbianStructuresLib.Debug.Symbols.Constants;
       
    29 using SymbianUtils.DataBuffer.Entry;
       
    30 using SymbianUtils.Range;
       
    31 
       
    32 namespace SymbianStackAlgorithmAccurate.Algorithm
       
    33 {
       
    34     internal class AccurateAlgorithm : StackAlgorithm, IArmStackInterface
       
    35     {
       
    36         #region Constructors
       
    37         public AccurateAlgorithm( IStackAlgorithmManager aManager, IStackAlgorithmObserver aObserver )
       
    38             : base( aManager, aObserver )
       
    39         {
       
    40         }
       
    41         #endregion
       
    42 
       
    43         #region API
       
    44         #endregion
       
    45 
       
    46         #region Properties
       
    47         #endregion
       
    48 
       
    49         #region From StackAlgorithm
       
    50         public override string Name
       
    51         {
       
    52             get { return "Accurate"; }
       
    53         }
       
    54 
       
    55         public override int Priority
       
    56         {
       
    57             get { return 0; }
       
    58         }
       
    59 
       
    60         public override bool IsAvailable()
       
    61         {
       
    62             bool ret = base.IsAvailable();
       
    63             //
       
    64             if ( ret )
       
    65             {
       
    66                 // We need some registers
       
    67                 ret = !base.Engine.Registers.IsEmpty;
       
    68                 //
       
    69                 if ( ret )
       
    70                 {
       
    71                     // This algorithm can only work if we have code available 
       
    72                     // to work with...
       
    73                     ret = base.DebugEngineView.Code.IsReady;
       
    74                     //
       
    75                     if ( ret == false )
       
    76                     {
       
    77                         base.Trace( "[AccurateAlgorithm] IsAvailable() - code not provided" );
       
    78                     }
       
    79                 }
       
    80                 else
       
    81                 {
       
    82                     base.Trace( "[AccurateAlgorithm] IsAvailable() - registers not provided" );
       
    83                 }
       
    84             }
       
    85             else
       
    86             {
       
    87                 base.Trace( "[AccurateAlgorithm] IsAvailable() - symbols not provided" );
       
    88             }
       
    89             //
       
    90             base.Trace( "[AccurateAlgorithm] IsAvailable() - ret: {0}", ret );
       
    91             return ret;
       
    92         }
       
    93         #endregion
       
    94 
       
    95         #region From IArmStackInterface
       
    96         uint IArmStackInterface.StackBase
       
    97         {
       
    98             get { return base.Engine.AddressInfo.Base; }
       
    99         }
       
   100 
       
   101         uint IArmStackInterface.StackTop
       
   102         {
       
   103             get { return base.Engine.AddressInfo.Top; }
       
   104         }
       
   105 
       
   106         uint IArmStackInterface.StackValueAtAddress( uint aAddress )
       
   107         {
       
   108             DataBufferUint entry = base.SourceData[ aAddress ];
       
   109             return entry.Uint;
       
   110         }
       
   111         #endregion
       
   112 
       
   113         #region From AsyncReaderBase
       
   114         protected override void HandleReadException( Exception aException )
       
   115         {
       
   116             // If an exception occurred during frame building or
       
   117             // stack reconstruction, then we are aborting the entire operation.
       
   118             //
       
   119             // However, HandleReadcompleted() is always called irrespective
       
   120             // of whether or not an operation succeeded or failed.
       
   121             //
       
   122             // Therefore, to ensure we do not generate a nested exception in
       
   123             // an abort scenario we toggle the 'accurate entry check required'
       
   124             // status flag to false so that we will not complain if the
       
   125             // algorithm did not locate any accurate frames.
       
   126             iAccurateEntryCheckRequired = false;
       
   127             base.Trace( "[AccurateAlgorithm] HandleReadException() - aException: {0}, stack: {1}", aException.Message, aException.StackTrace );
       
   128 
       
   129             // Now we can propagate the exception onwards.
       
   130             base.HandleReadException( aException );
       
   131         }
       
   132 
       
   133         protected override void HandleReadCompleted()
       
   134         {
       
   135             // If we didn't identify any accurate entries, then we bail out
       
   136             // and let the heuristic algorithm run instead.
       
   137             //
       
   138             // NB: we don't do this unless we succeeded to reconstruct
       
   139             // the entire stack.
       
   140             base.Trace( "[AccurateAlgorithm] HandleReadCompleted() - iAccurateEntryCheckRequired: {0}, iAccurateEntryCount: {1}", iAccurateEntryCheckRequired, iAccurateEntryCount );
       
   141             if ( iAccurateEntryCheckRequired )
       
   142             {
       
   143                 if ( iAccurateEntryCount == 0 )
       
   144                 {
       
   145                     throw new Exception( "Unable to locate any accurate entries" );
       
   146                 }
       
   147             }
       
   148 
       
   149             // We're an accurate algorithm
       
   150             base.OutputData.IsAccurate = true;
       
   151 
       
   152             base.Trace( "[AccurateAlgorithm] HandleReadCompleted() - read ok!" );
       
   153             base.HandleReadCompleted();
       
   154         }
       
   155 
       
   156         protected override void HandleReadStarted()
       
   157         {
       
   158             try
       
   159             {
       
   160                 base.Trace( "[AccurateAlgorithm] HandleReadStarted() - START" );
       
   161 
       
   162                 // Indicate that we will throw an exception if we do not
       
   163                 // find at least one accurate entry. This is the default behaviour
       
   164                 // to ensure we don't result in stack data containing just ghost entries.
       
   165                 // We toggle this to false if we abort stack walking due to an exception,
       
   166                 // thereby preventing nested exception throwing.
       
   167                 iAccurateEntryCheckRequired = true;
       
   168                 
       
   169                 // Create arm engine
       
   170                 iArmEngine = new AccurateEngine( base.DebugEngineView, this, base.Manager.Engine );
       
   171 
       
   172                 // Seed it with the registers
       
   173                 iArmEngine.CPU.Registers = base.Engine.Registers;
       
   174 
       
   175                 // Dump the registers in verbose mode
       
   176                 base.Trace( "STACK ENGINE REGISTERS:" );
       
   177                 foreach ( ArmRegister reg in base.Engine.Registers )
       
   178                 {
       
   179                     string symbol = base.DebugEngineView.Symbols.PlainText[ reg.Value ];
       
   180                     base.Trace( reg.ToString() + " " + symbol );
       
   181                 }
       
   182                 //
       
   183                 base.Trace( System.Environment.NewLine );
       
   184                 base.Trace( "[AccurateAlgorithm] HandleReadStarted() - setup complete." );
       
   185             }
       
   186             finally
       
   187             {
       
   188                 base.HandleReadStarted();
       
   189             }
       
   190 
       
   191             base.Trace( "[AccurateAlgorithm] HandleReadStarted() - END" );
       
   192         }
       
   193 
       
   194         protected override void PerformOperation()
       
   195         {
       
   196             System.Diagnostics.Debug.Assert( iArmEngine != null );
       
   197 
       
   198             // First step is to read as many valid stack frames as possible
       
   199             BuildStackFrames();
       
   200 
       
   201             // Second step is to try to fill any gaps in the stack data
       
   202             CreateStackOutput();
       
   203         }
       
   204 
       
   205         protected override long Size
       
   206         {
       
   207             get
       
   208             {
       
   209                 int bytes = base.SourceData.Count;
       
   210                 int dWords = bytes / 4;
       
   211                 return dWords;
       
   212             }
       
   213         }
       
   214 
       
   215         protected override long Position
       
   216         {
       
   217             get
       
   218             {
       
   219                 return iDWordIndex;
       
   220             }
       
   221         }
       
   222         #endregion
       
   223 
       
   224         #region From DisposableObject
       
   225         protected override void CleanupManagedResources()
       
   226         {
       
   227             try
       
   228             {
       
   229                 base.CleanupManagedResources();
       
   230             }
       
   231             finally
       
   232             {
       
   233                 if ( iArmEngine != null )
       
   234                 {
       
   235                     iArmEngine.Dispose();
       
   236                     iArmEngine = null;
       
   237                 }
       
   238             }
       
   239         }
       
   240         #endregion
       
   241 
       
   242         #region Internal methods
       
   243         private ArmStackFrame FrameByStackAddress( uint aAddress )
       
   244         {
       
   245             ArmStackFrame ret = null;
       
   246             //
       
   247             ArmStackFrame[] frames = iArmEngine.StackFrames;
       
   248             foreach ( ArmStackFrame frame in frames )
       
   249             {
       
   250                 if ( frame.Address == aAddress )
       
   251                 {
       
   252                     ret = frame;
       
   253                     break;
       
   254                 }
       
   255             }
       
   256             //
       
   257             return ret;
       
   258         }
       
   259 
       
   260         private ArmStackFrame FrameByRegisterType( TArmRegisterType aRegister )
       
   261         {
       
   262             ArmStackFrame ret = null;
       
   263             //
       
   264             ArmStackFrame[] frames = iArmEngine.StackFrames;
       
   265             foreach ( ArmStackFrame frame in frames )
       
   266             {
       
   267                 if ( frame.IsRegisterBasedEntry && frame.AssociatedRegister == aRegister )
       
   268                 {
       
   269                     ret = frame;
       
   270                     break;
       
   271                 }
       
   272             }
       
   273             //
       
   274             return ret;
       
   275         }
       
   276 
       
   277         private void BuildStackFrames()
       
   278         {
       
   279             bool success = iArmEngine.Process();
       
   280             while ( success )
       
   281             {
       
   282                 success = iArmEngine.Process();
       
   283             }
       
   284 
       
   285             base.Trace( string.Empty );
       
   286             base.Trace( string.Empty );
       
   287         }
       
   288 
       
   289         private void CreateStackOutput()
       
   290         {
       
   291             // Get the source data we need to reconstruct and signal we're about to start
       
   292             StackSourceData sourceData = base.SourceData;
       
   293 
       
   294             // Get the output data sink
       
   295             StackOutputData outputData = base.OutputData;
       
   296             outputData.Clear();
       
   297             outputData.AlgorithmName = Name;
       
   298 
       
   299             // Get the address range of the stack pointer data
       
   300             AddressRange pointerRange = base.Engine.AddressInfo.StackPointerRange;
       
   301             AddressRange pointerRangeExtended = base.Engine.AddressInfo.StackPointerRangeWithExtensionArea;
       
   302 
       
   303             foreach ( DataBufferUint sourceEntry in sourceData.GetUintEnumerator() )
       
   304             {
       
   305                 // Check if it is within the stack domain, taking into account
       
   306                 // our extended range
       
   307                 if ( pointerRangeExtended.Contains( sourceEntry.Address ) )
       
   308                 {
       
   309                     StackOutputEntry outputEntry = new StackOutputEntry( sourceEntry.Address, sourceEntry.Uint, base.DebugEngineView );
       
   310 
       
   311                     // Is it the element that corresponds to the current value of SP?
       
   312                     bool isCurrentSPEntry = ( outputEntry.AddressRange.Contains( base.Engine.AddressInfo.Pointer ) );
       
   313 
       
   314                     // Is it within the pure 'stack pointer' address range?
       
   315                     bool outsidePureStackPointerRange = !pointerRange.Contains( sourceEntry.Address );
       
   316                     outputEntry.IsOutsideCurrentStackRange = outsidePureStackPointerRange;
       
   317 
       
   318                     // Is it a ghost?
       
   319                     if ( outputEntry.Symbol != null )
       
   320                     {
       
   321                         ArmStackFrame realStackFrame = FrameByStackAddress( sourceEntry.Address );
       
   322                         outputEntry.IsAccurate = ( realStackFrame != null );
       
   323                         outputEntry.IsGhost = ( realStackFrame == null );
       
   324                     }
       
   325 
       
   326                     // Save entry
       
   327                     EmitElement( outputEntry );
       
   328 
       
   329                     // If we're inside the stack address range, then poke in the PC and LR values
       
   330                     if ( isCurrentSPEntry )
       
   331                     {
       
   332                         outputEntry.IsCurrentStackPointerEntry = true;
       
   333 
       
   334                         // Working bottom up, so LR should go on the stack first
       
   335                         ArmStackFrame stackFrameLR = FrameByRegisterType( TArmRegisterType.EArmReg_LR );
       
   336                         if ( stackFrameLR != null )
       
   337                         {
       
   338                             StackOutputEntry entryLR = new StackOutputEntry( 0, stackFrameLR.Data, base.DebugEngineView );
       
   339                             entryLR.IsRegisterBasedEntry = true;
       
   340                             entryLR.IsOutsideCurrentStackRange = true;
       
   341                             entryLR.AssociatedRegister = stackFrameLR.AssociatedRegister;
       
   342                             EmitElement( entryLR );
       
   343                         }
       
   344 
       
   345                         // Then the PC...
       
   346                         ArmStackFrame stackFramePC = FrameByRegisterType( TArmRegisterType.EArmReg_PC );
       
   347                         if ( stackFramePC != null )
       
   348                         {
       
   349                             StackOutputEntry entryPC = new StackOutputEntry( 0, stackFramePC.Data, base.DebugEngineView );
       
   350                             entryPC.IsRegisterBasedEntry = true;
       
   351                             entryPC.IsOutsideCurrentStackRange = true;
       
   352                             entryPC.AssociatedRegister = stackFramePC.AssociatedRegister;
       
   353                             EmitElement( entryPC );
       
   354                         }
       
   355                     }
       
   356                 }
       
   357                 else
       
   358                 {
       
   359                     // Nope, ignore it...
       
   360                 }
       
   361 
       
   362                 NotifyEvent( TEvent.EReadingProgress );
       
   363                 ++iDWordIndex;
       
   364             }
       
   365         }
       
   366 
       
   367         private void EmitElement( StackOutputEntry aEntry )
       
   368         {
       
   369             // Debug support
       
   370             if ( base.Engine.Verbose )
       
   371             {
       
   372                 StringBuilder line = new StringBuilder( "[AccurateAlgorithm] " );
       
   373                 //
       
   374                 if ( aEntry.IsCurrentStackPointerEntry )
       
   375                 {
       
   376                     line.Append( "[C]       " );
       
   377                 }
       
   378                 else if ( aEntry.IsRegisterBasedEntry )
       
   379                 {
       
   380                     const int KNormalAddressWidth = 10;
       
   381                     string prefix = "[ " + aEntry.AssociatedRegisterName;
       
   382                     prefix = prefix.PadRight( KNormalAddressWidth - 2 );
       
   383                     prefix += " ]";
       
   384                     line.Append( prefix );
       
   385                 }
       
   386                 else if ( aEntry.IsGhost )
       
   387                 {
       
   388                     line.Append( "[G]       " );
       
   389                 }
       
   390                 else if ( aEntry.IsOutsideCurrentStackRange )
       
   391                 {
       
   392                     line.Append( "          " );
       
   393                 }
       
   394                 else
       
   395                 {
       
   396                     line.AppendFormat( "[{0:x8}]", aEntry.Address );
       
   397                 }
       
   398 
       
   399                 line.AppendFormat( " {0:x8} {1}", aEntry.Data, aEntry.DataAsString );
       
   400 
       
   401                 if ( aEntry.Symbol != null )
       
   402                 {
       
   403                     string baseAddressOffset = aEntry.Symbol.ToStringOffset( aEntry.Data );
       
   404                     line.AppendFormat( "{0} {1}", baseAddressOffset, aEntry.Symbol.Name );
       
   405                 }
       
   406                 else if ( aEntry.AssociatedBinary != string.Empty )
       
   407                 {
       
   408                     line.AppendFormat( "{0} {1}", SymbolConstants.KUnknownOffset, aEntry.AssociatedBinary );
       
   409                 }
       
   410 
       
   411                 base.Trace( line.ToString() );
       
   412             }
       
   413 
       
   414             // Count the number of accurate entries
       
   415             if ( aEntry.IsAccurate )
       
   416             {
       
   417                 ++iAccurateEntryCount;
       
   418             }
       
   419 
       
   420             // Flush entry
       
   421             base.StackObserver.StackBuildingElementConstructed( this, aEntry );
       
   422         }
       
   423         #endregion
       
   424 
       
   425         #region Data members
       
   426         private AccurateEngine iArmEngine = null;
       
   427         private int iDWordIndex = 0;
       
   428         private bool iAccurateEntryCheckRequired = true;
       
   429         private int iAccurateEntryCount = 0;
       
   430         #endregion
       
   431     }
       
   432 }