diff -r 000000000000 -r 818e61de6cd1 crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Plugins/Accurate/Algorithm/AccurateAlgorithm.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Plugins/Accurate/Algorithm/AccurateAlgorithm.cs Thu Feb 11 15:50:58 2010 +0200 @@ -0,0 +1,432 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ +using System; +using System.Text; +using SymbianStackAlgorithmAccurate.Engine; +using SymbianStackAlgorithmAccurate.Interfaces; +using SymbianStackAlgorithmAccurate.Stack; +using SymbianStackLib.Algorithms; +using SymbianStackLib.Data.Output; +using SymbianStackLib.Data.Output.Entry; +using SymbianStackLib.Data.Source; +using SymbianStackLib.Interfaces; +using SymbianStructuresLib.Arm.Registers; +using SymbianStructuresLib.Debug.Symbols.Constants; +using SymbianUtils.DataBuffer.Entry; +using SymbianUtils.Range; + +namespace SymbianStackAlgorithmAccurate.Algorithm +{ + internal class AccurateAlgorithm : StackAlgorithm, IArmStackInterface + { + #region Constructors + public AccurateAlgorithm( IStackAlgorithmManager aManager, IStackAlgorithmObserver aObserver ) + : base( aManager, aObserver ) + { + } + #endregion + + #region API + #endregion + + #region Properties + #endregion + + #region From StackAlgorithm + public override string Name + { + get { return "Accurate"; } + } + + public override int Priority + { + get { return 0; } + } + + public override bool IsAvailable() + { + bool ret = base.IsAvailable(); + // + if ( ret ) + { + // We need some registers + ret = !base.Engine.Registers.IsEmpty; + // + if ( ret ) + { + // This algorithm can only work if we have code available + // to work with... + ret = base.DebugEngineView.Code.IsReady; + // + if ( ret == false ) + { + base.Trace( "[AccurateAlgorithm] IsAvailable() - code not provided" ); + } + } + else + { + base.Trace( "[AccurateAlgorithm] IsAvailable() - registers not provided" ); + } + } + else + { + base.Trace( "[AccurateAlgorithm] IsAvailable() - symbols not provided" ); + } + // + base.Trace( "[AccurateAlgorithm] IsAvailable() - ret: {0}", ret ); + return ret; + } + #endregion + + #region From IArmStackInterface + uint IArmStackInterface.StackBase + { + get { return base.Engine.AddressInfo.Base; } + } + + uint IArmStackInterface.StackTop + { + get { return base.Engine.AddressInfo.Top; } + } + + uint IArmStackInterface.StackValueAtAddress( uint aAddress ) + { + DataBufferUint entry = base.SourceData[ aAddress ]; + return entry.Uint; + } + #endregion + + #region From AsyncReaderBase + protected override void HandleReadException( Exception aException ) + { + // If an exception occurred during frame building or + // stack reconstruction, then we are aborting the entire operation. + // + // However, HandleReadcompleted() is always called irrespective + // of whether or not an operation succeeded or failed. + // + // Therefore, to ensure we do not generate a nested exception in + // an abort scenario we toggle the 'accurate entry check required' + // status flag to false so that we will not complain if the + // algorithm did not locate any accurate frames. + iAccurateEntryCheckRequired = false; + base.Trace( "[AccurateAlgorithm] HandleReadException() - aException: {0}, stack: {1}", aException.Message, aException.StackTrace ); + + // Now we can propagate the exception onwards. + base.HandleReadException( aException ); + } + + protected override void HandleReadCompleted() + { + // If we didn't identify any accurate entries, then we bail out + // and let the heuristic algorithm run instead. + // + // NB: we don't do this unless we succeeded to reconstruct + // the entire stack. + base.Trace( "[AccurateAlgorithm] HandleReadCompleted() - iAccurateEntryCheckRequired: {0}, iAccurateEntryCount: {1}", iAccurateEntryCheckRequired, iAccurateEntryCount ); + if ( iAccurateEntryCheckRequired ) + { + if ( iAccurateEntryCount == 0 ) + { + throw new Exception( "Unable to locate any accurate entries" ); + } + } + + // We're an accurate algorithm + base.OutputData.IsAccurate = true; + + base.Trace( "[AccurateAlgorithm] HandleReadCompleted() - read ok!" ); + base.HandleReadCompleted(); + } + + protected override void HandleReadStarted() + { + try + { + base.Trace( "[AccurateAlgorithm] HandleReadStarted() - START" ); + + // Indicate that we will throw an exception if we do not + // find at least one accurate entry. This is the default behaviour + // to ensure we don't result in stack data containing just ghost entries. + // We toggle this to false if we abort stack walking due to an exception, + // thereby preventing nested exception throwing. + iAccurateEntryCheckRequired = true; + + // Create arm engine + iArmEngine = new AccurateEngine( base.DebugEngineView, this, base.Manager.Engine ); + + // Seed it with the registers + iArmEngine.CPU.Registers = base.Engine.Registers; + + // Dump the registers in verbose mode + base.Trace( "STACK ENGINE REGISTERS:" ); + foreach ( ArmRegister reg in base.Engine.Registers ) + { + string symbol = base.DebugEngineView.Symbols.PlainText[ reg.Value ]; + base.Trace( reg.ToString() + " " + symbol ); + } + // + base.Trace( System.Environment.NewLine ); + base.Trace( "[AccurateAlgorithm] HandleReadStarted() - setup complete." ); + } + finally + { + base.HandleReadStarted(); + } + + base.Trace( "[AccurateAlgorithm] HandleReadStarted() - END" ); + } + + protected override void PerformOperation() + { + System.Diagnostics.Debug.Assert( iArmEngine != null ); + + // First step is to read as many valid stack frames as possible + BuildStackFrames(); + + // Second step is to try to fill any gaps in the stack data + CreateStackOutput(); + } + + protected override long Size + { + get + { + int bytes = base.SourceData.Count; + int dWords = bytes / 4; + return dWords; + } + } + + protected override long Position + { + get + { + return iDWordIndex; + } + } + #endregion + + #region From DisposableObject + protected override void CleanupManagedResources() + { + try + { + base.CleanupManagedResources(); + } + finally + { + if ( iArmEngine != null ) + { + iArmEngine.Dispose(); + iArmEngine = null; + } + } + } + #endregion + + #region Internal methods + private ArmStackFrame FrameByStackAddress( uint aAddress ) + { + ArmStackFrame ret = null; + // + ArmStackFrame[] frames = iArmEngine.StackFrames; + foreach ( ArmStackFrame frame in frames ) + { + if ( frame.Address == aAddress ) + { + ret = frame; + break; + } + } + // + return ret; + } + + private ArmStackFrame FrameByRegisterType( TArmRegisterType aRegister ) + { + ArmStackFrame ret = null; + // + ArmStackFrame[] frames = iArmEngine.StackFrames; + foreach ( ArmStackFrame frame in frames ) + { + if ( frame.IsRegisterBasedEntry && frame.AssociatedRegister == aRegister ) + { + ret = frame; + break; + } + } + // + return ret; + } + + private void BuildStackFrames() + { + bool success = iArmEngine.Process(); + while ( success ) + { + success = iArmEngine.Process(); + } + + base.Trace( string.Empty ); + base.Trace( string.Empty ); + } + + private void CreateStackOutput() + { + // Get the source data we need to reconstruct and signal we're about to start + StackSourceData sourceData = base.SourceData; + + // Get the output data sink + StackOutputData outputData = base.OutputData; + outputData.Clear(); + outputData.AlgorithmName = Name; + + // Get the address range of the stack pointer data + AddressRange pointerRange = base.Engine.AddressInfo.StackPointerRange; + AddressRange pointerRangeExtended = base.Engine.AddressInfo.StackPointerRangeWithExtensionArea; + + foreach ( DataBufferUint sourceEntry in sourceData.GetUintEnumerator() ) + { + // Check if it is within the stack domain, taking into account + // our extended range + if ( pointerRangeExtended.Contains( sourceEntry.Address ) ) + { + StackOutputEntry outputEntry = new StackOutputEntry( sourceEntry.Address, sourceEntry.Uint, base.DebugEngineView ); + + // Is it the element that corresponds to the current value of SP? + bool isCurrentSPEntry = ( outputEntry.AddressRange.Contains( base.Engine.AddressInfo.Pointer ) ); + + // Is it within the pure 'stack pointer' address range? + bool outsidePureStackPointerRange = !pointerRange.Contains( sourceEntry.Address ); + outputEntry.IsOutsideCurrentStackRange = outsidePureStackPointerRange; + + // Is it a ghost? + if ( outputEntry.Symbol != null ) + { + ArmStackFrame realStackFrame = FrameByStackAddress( sourceEntry.Address ); + outputEntry.IsAccurate = ( realStackFrame != null ); + outputEntry.IsGhost = ( realStackFrame == null ); + } + + // Save entry + EmitElement( outputEntry ); + + // If we're inside the stack address range, then poke in the PC and LR values + if ( isCurrentSPEntry ) + { + outputEntry.IsCurrentStackPointerEntry = true; + + // Working bottom up, so LR should go on the stack first + ArmStackFrame stackFrameLR = FrameByRegisterType( TArmRegisterType.EArmReg_LR ); + if ( stackFrameLR != null ) + { + StackOutputEntry entryLR = new StackOutputEntry( 0, stackFrameLR.Data, base.DebugEngineView ); + entryLR.IsRegisterBasedEntry = true; + entryLR.IsOutsideCurrentStackRange = true; + entryLR.AssociatedRegister = stackFrameLR.AssociatedRegister; + EmitElement( entryLR ); + } + + // Then the PC... + ArmStackFrame stackFramePC = FrameByRegisterType( TArmRegisterType.EArmReg_PC ); + if ( stackFramePC != null ) + { + StackOutputEntry entryPC = new StackOutputEntry( 0, stackFramePC.Data, base.DebugEngineView ); + entryPC.IsRegisterBasedEntry = true; + entryPC.IsOutsideCurrentStackRange = true; + entryPC.AssociatedRegister = stackFramePC.AssociatedRegister; + EmitElement( entryPC ); + } + } + } + else + { + // Nope, ignore it... + } + + NotifyEvent( TEvent.EReadingProgress ); + ++iDWordIndex; + } + } + + private void EmitElement( StackOutputEntry aEntry ) + { + // Debug support + if ( base.Engine.Verbose ) + { + StringBuilder line = new StringBuilder( "[AccurateAlgorithm] " ); + // + if ( aEntry.IsCurrentStackPointerEntry ) + { + line.Append( "[C] " ); + } + else if ( aEntry.IsRegisterBasedEntry ) + { + const int KNormalAddressWidth = 10; + string prefix = "[ " + aEntry.AssociatedRegisterName; + prefix = prefix.PadRight( KNormalAddressWidth - 2 ); + prefix += " ]"; + line.Append( prefix ); + } + else if ( aEntry.IsGhost ) + { + line.Append( "[G] " ); + } + else if ( aEntry.IsOutsideCurrentStackRange ) + { + line.Append( " " ); + } + else + { + line.AppendFormat( "[{0:x8}]", aEntry.Address ); + } + + line.AppendFormat( " {0:x8} {1}", aEntry.Data, aEntry.DataAsString ); + + if ( aEntry.Symbol != null ) + { + string baseAddressOffset = aEntry.Symbol.ToStringOffset( aEntry.Data ); + line.AppendFormat( "{0} {1}", baseAddressOffset, aEntry.Symbol.Name ); + } + else if ( aEntry.AssociatedBinary != string.Empty ) + { + line.AppendFormat( "{0} {1}", SymbolConstants.KUnknownOffset, aEntry.AssociatedBinary ); + } + + base.Trace( line.ToString() ); + } + + // Count the number of accurate entries + if ( aEntry.IsAccurate ) + { + ++iAccurateEntryCount; + } + + // Flush entry + base.StackObserver.StackBuildingElementConstructed( this, aEntry ); + } + #endregion + + #region Data members + private AccurateEngine iArmEngine = null; + private int iDWordIndex = 0; + private bool iAccurateEntryCheckRequired = true; + private int iAccurateEntryCount = 0; + #endregion + } +}