crashanalysercmd/Libraries/Engine/CrashItemLib/Crash/Stacks/CIStackBuilder.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.Collections.Generic;
using SymbianUtils;
using SymbianDebugLib.Engine;
using SymbianStackLib.Engine;
using SymbianStackLib.Exceptions;
using CrashItemLib.Engine.Operations;
using CrashItemLib.Crash;
using CrashItemLib.Crash.Base;
using CrashItemLib.Crash.Symbols;
using CrashItemLib.Crash.Registers;
using CrashItemLib.Crash.Processes;
using CrashItemLib.Crash.CodeSegs;
using CrashItemLib.Crash.Messages;
using CrashItemLib.Engine;

namespace CrashItemLib.Crash.Stacks
{
	internal class CIStackBuilder
    {
        #region Constructors
        public CIStackBuilder( CIStack aStack, DbgEngine aDebugEngine )
        {
            iStack = aStack;
            iStackEngine = new StackEngine( aDebugEngine );
            iStackEngine.AddressInfo.Pointer = aStack.PointerValue;
            iStackEngine.AddressInfo.Range = aStack.Range;
            iStackEngine.Registers = aStack.Registers;
            iStackEngine.DataSource = aStack.RawSourceData;

            // Get the code segments for the process
            bool isThreadStack = aStack.IsThreadAvailable;
            if ( isThreadStack )
            {
                CIProcess process = OwningProcess;
                System.Diagnostics.Debug.Assert( process != null );

                // Seed stack engine with relevant code segments
                iStackEngine.CodeSegments = process.CodeSegments;
            }
        }
        #endregion

        #region API
        public void Build( TSynchronicity aSynchronicity )
        {
            StackEventsSubscribe();
            iStackEngine.Reconstruct( aSynchronicity );
        }
        #endregion

        #region Properties
        public bool IsReady
        {
            get { return iIsReady; }
            private set
            {
                lock ( this )
                {
                    iIsReady = value;
                }
            }
        }

        public CIProcess OwningProcess
        {
            get
            {
                CIProcess ret = iStack.OwningProcess;
                return ret;
            }
        }

        public StackEngine StackEngine
        {
            get { return iStackEngine; }
        }
        #endregion

        #region Event handlers
        private void StackEngine_EventHandler( StackEngine.TEvent aEvent, StackEngine aEngine )
        {
            if ( aEvent == StackEngine.TEvent.EStackBuildingComplete )
            {
                StackEventsUnsubscribe();
                IsReady = true;
            }
        }

        private void StackEngine_ExceptionHandler( Exception aException, StackEngine aEngine )
        {
            // Operation failed, but we must mark ourselves as ready or else UI clients will block forever...
            IsReady = true;

            // We'll deal with the public exceptions ourselves. Any kind of exception we cannot handle
            // will just get treated as a generic error.
            string msg = string.Empty;
            bool recognized = false;
            //
            if ( aException is StackAddressException )
            {
                recognized = true;
                StackAddressException exception = (StackAddressException) aException;
                switch ( exception.Type )
                {
                case StackAddressException.TType.ETypePointerIsNull:
                    msg = LibResources.CIStackBuilder_AddressInfoException_PointerMissing;
                    break;
                case StackAddressException.TType.ETypePointerOutOfBounds:
                    msg = LibResources.CIStackBuilder_AddressInfoException_PointerOutOfBounds;
                    break;
                case StackAddressException.TType.ETypeBaseAddressBeforeTopAddress:
                    msg = LibResources.CIStackBuilder_AddressInfoException_BaseAddressBeforeTopAddress;
                    break;
                case StackAddressException.TType.ETypeTopAddressAfterBaseAddress:
                    msg = LibResources.CIStackBuilder_AddressInfoException_TopAddressAfterBaseAddress;
                    break;
                default:
                    recognized = false;
                    break;
                }
            }

            // Not recognized? Unfortunately have to leak the original underlying .NET exception details
            if ( recognized == false )
            {
                msg = aException.Message;
            }

            if ( string.IsNullOrEmpty( msg ) == false )
            {
                // Treat exceptions as fatal errors
                CIMessageError error = new CIMessageError( iStack.Container, LibResources.CIStackBuilder_Error_Title );
                error.AddLine( msg );
                iStack.AddChild( error );
            }
        }

        private void StackEngine_MessageHandler( StackEngine.TMessageType aType, string aMessage, StackEngine aEngine )
        {
            switch ( aType )
            {
            default:
                break;
            case StackEngine.TMessageType.ETypeError:
                {
                CIMessageError error = new CIMessageError( iStack.Container, LibResources.CIStackBuilder_Error_Title );
                error.AddLine( aMessage );
                iStack.AddChild( error );
                break;
                }
            case StackEngine.TMessageType.ETypeWarning:
                {
                CIMessageWarning warning = new CIMessageWarning( iStack.Container, LibResources.CIStackBuilder_Warning_Title );
                warning.AddLine( aMessage );
                iStack.AddChild( warning );
                break;
                }
            }
        }
        #endregion

        #region Internal methods
        private void StackEventsSubscribe()
        {
            StackEngine.MessageHandler += new StackEngine.StackEngineMessageHandler( StackEngine_MessageHandler );
            StackEngine.EventHandler += new StackEngine.StackEngineEventHandler( StackEngine_EventHandler );
            StackEngine.ExceptionHandler += new StackEngine.StackEngineExceptionHandler( StackEngine_ExceptionHandler );
        }

        private void StackEventsUnsubscribe()
        {
            StackEngine.MessageHandler -= new StackEngine.StackEngineMessageHandler( StackEngine_MessageHandler );
            StackEngine.EventHandler -= new StackEngine.StackEngineEventHandler( StackEngine_EventHandler );
            StackEngine.ExceptionHandler -= new StackEngine.StackEngineExceptionHandler( StackEngine_ExceptionHandler );
        }
        #endregion

        #region From System.Object
        public override string ToString()
        {
            StringBuilder ret = new StringBuilder();
            ret.AppendFormat( "CIStackBuilder_{0}_{1}", iStack.Id, iStack.Name );
            return ret.ToString();
        }
        #endregion

        #region Data members
        private readonly CIStack iStack;
        private readonly StackEngine iStackEngine;
        private bool iIsReady = false;
        #endregion
    }
}