crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Plugins/Basic/StackAlgBasic.cs
author Matti Laitinen <matti.t.laitinen@nokia.com>
Thu, 11 Feb 2010 15:50:58 +0200
changeset 0 818e61de6cd1
permissions -rw-r--r--
Add initial version of Crash Analyser cmdline under EPL

/*
* 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 System.Threading;
using System.ComponentModel;
using System.Collections.Generic;
using System.IO;
using SymbianUtils.DataBuffer.Entry;
using SymbianStructuresLib.Arm.Registers;
using SymbianStructuresLib.CodeSegments;
using SymbianStructuresLib.Debug.Symbols;
using SymbianUtils;
using SymbianUtils.Range;
using SymbianUtils.Utilities;
using SymbianDebugLib.PluginAPI.Types;
using SymbianDebugLib.Engine;
using SymbianStackLib.Data.Source;
using SymbianStackLib.Data.Output;
using SymbianStackLib.Data.Output.Entry;
using SymbianStackLib.Interfaces;
using SymbianStackLib.Algorithms;

namespace SymbianStackAlgorithmBasic
{
    internal class StackAlgBasic : StackAlgorithm
    {
        #region Constructors
        public StackAlgBasic( IStackAlgorithmManager aManager, IStackAlgorithmObserver aObserver )
            : base( aManager, aObserver )
        {
        }
        #endregion

        #region API
        #endregion

        #region Properties
        #endregion

        #region From StackAlgorithm
        public override bool IsAvailable()
        {
            // This is always available
            return true;
        }

        public override string Name
        {
            get { return "Basic"; }
        }

        public override int Priority
        {
            get { return 200; }
        }
        #endregion

        #region From AsyncReaderBase
        protected override void PerformOperation()
        {
            // 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;

            // Indicates if we added LR and PC to the call stack
            bool addedLRandPC = false;

            // Get registers
            ArmRegisterCollection regs = base.Engine.Registers;

            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 );

                    // Is it the element tht corresponds to the current value of SP?
                    bool isCurrentSPEntry = ( outputEntry.AddressRange.Contains( base.Engine.AddressInfo.Pointer ) );
                    outputEntry.IsCurrentStackPointerEntry = isCurrentSPEntry;

                    // Is it within the pure 'stack pointer' address range?
                    bool outsidePureStackPointerRange = !pointerRange.Contains( sourceEntry.Address );
                    outputEntry.IsOutsideCurrentStackRange = outsidePureStackPointerRange;

                    // These are never accurate, but neither are they ghosts
                    outputEntry.IsAccurate = false;
                    outputEntry.IsGhost = false;

                    // Save entry
                    EmitElement( outputEntry );

                    // If we're inside the stack address range, then poke in the PC and LR values
                    if ( isCurrentSPEntry )
                    {
                        System.Diagnostics.Debug.Assert( !addedLRandPC );
                        addedLRandPC = AddLRAndPC();
                    }
                }
                else
                {
                    // Nope, ignore it...
                }

                NotifyEvent( TEvent.EReadingProgress );
                ++iDWordIndex;
            }

            // If the stack overflowed, then SP might be outside of the stack range. Therefore
            // LR and PC will not be added yet.
            if ( !addedLRandPC )
            {
                AddLRAndPC();
            }
        }

        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 Internal methods
        private bool AddLRAndPC()
        {
            bool addedLRandPC = false;
            //
            ArmRegisterCollection regs = base.Engine.Registers;

            // If we're inside the stack address range, then poke in the PC and LR values
            if ( regs.Count > 0 )
            {
                // Working bottom up, so LR should go on the stack first
                if ( regs.Contains( TArmRegisterType.EArmReg_LR ) )
                {
                    ArmRegister regLR = regs[ TArmRegisterType.EArmReg_LR ];

                    StackOutputEntry entryLR = new StackOutputEntry( 0, regLR.Value );
                    entryLR.IsRegisterBasedEntry = true;
                    entryLR.IsOutsideCurrentStackRange = true;
                    entryLR.AssociatedRegister = regLR.RegType;
                    EmitElement( entryLR );
                }

                // Then the PC...
                if ( regs.Contains( TArmRegisterType.EArmReg_PC ) )
                {
                    ArmRegister regPC = regs[ TArmRegisterType.EArmReg_PC ];

                    StackOutputEntry entryPC = new StackOutputEntry( 0, regPC.Value );
                    entryPC.IsRegisterBasedEntry = true;
                    entryPC.IsOutsideCurrentStackRange = true;
                    entryPC.AssociatedRegister = regPC.RegType;
                    EmitElement( entryPC );
                }

                // Even if they weren't added, we at least attempted to addd them
                addedLRandPC = true;
            }

            return addedLRandPC;
        }

        private void EmitElement( StackOutputEntry aEntry )
        {
            // Flush entry
            base.StackObserver.StackBuildingElementConstructed( this, aEntry );
        }
        #endregion

        #region Data members
        private int iDWordIndex = 0;
        #endregion
    }
}