diff -r 000000000000 -r 818e61de6cd1 crashanalysercmd/Libraries/File Formats/Plugins/DExcPlugin/Extractor/DExcExtractor.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crashanalysercmd/Libraries/File Formats/Plugins/DExcPlugin/Extractor/DExcExtractor.cs Thu Feb 11 15:50:58 2010 +0200 @@ -0,0 +1,286 @@ +/* +* 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.Text.RegularExpressions; +using System.Collections.Generic; +using SymbianUtils.Range; +using EM=DExcPlugin.ExpressionManager.DExcExpressionManager; + +namespace DExcPlugin.Extractor +{ + internal class DExcExtractor + { + #region Events + public enum TEvent + { + EEventExtractedAllData + } + + public delegate void EventHandler( TEvent aEvent, DExcExtractor aExtractor ); + public event EventHandler StateChanged; + #endregion + + #region Constructors + public DExcExtractor() + { + Init(); + } + #endregion + + #region API + public void Init() + { + iState = TState.EStateIdle; + iData = new DExcExtractedData(); + iLists = new Dictionary(); + iCurrentLineNumber = 0; + + // Null (really just exists to catch a state transition) + // ======================================================= + CreateList( TState.EStateIdle, DExcExtractorListType.EListNull ).AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.LogStart, TState.EStateHeader ) ); + + // Header + // ======================================================= + CreateList( TState.EStateHeader, DExcExtractorListType.EListHeader ).AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.ThreadName, TState.EStateThreadInfo ) ); + + // Thread info + // =========== + DExcExtractorListThreadInfo listThreadInfo = new DExcExtractorListThreadInfo( TState.EStateThreadInfo, DExcExtractorListType.EListThread ); + PrepareList( listThreadInfo, EM.ThreadName, EM.ThreadId, EM.ThreadStackRange, EM.ThreadPanicDetails ); + listThreadInfo.AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.RegistersExceptionStart, TState.EStateRegisterInfoException ) ); + listThreadInfo.AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.RegistersUserStart, TState.EStateRegisterInfoUser ) ); + + // Registers (exception) + // ===================== + DExcExtractorList listRegisterInfoException = CreateList( TState.EStateRegisterInfoException, DExcExtractorListType.EListRegistersException, + EM.RegistersExceptionSet1, + EM.RegistersExceptionSet2 ); + listRegisterInfoException.AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.RegistersUserStart, TState.EStateRegisterInfoUser ) ); + + // Registers (user) + // ================ + DExcExtractorList listRegisterInfoUser = CreateList( TState.EStateRegisterInfoUser, DExcExtractorListType.EListRegistersUser, + EM.RegistersUserCPSR, + EM.RegistersUserSet ); + + // Since code segs are optional, we want to record that we at least saw the header text (which is mandatory). This + // tracking allows us to validate that we have received/observed data for all states. + listRegisterInfoUser.AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.CodeSegmentsStart, TState.EStateCodeSegments ) ); + + // Code segments + // ============= + DExcExtractorList listCodeSegments = CreateList( TState.EStateCodeSegments, DExcExtractorListType.EListCodeSegments, EM.CodeSegmentsEntry ); + + // We need to transition state to "stack data", but we must be sure not to throw away the state line we just encountered. + listCodeSegments.AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.StackDataEntry, TState.EStateStackData ) ); + + // Stack data + // ========== + DExcExtractorListStackData listStackData = new DExcExtractorListStackData( TState.EStateStackData, DExcExtractorListType.EListStackData ); + PrepareList( listStackData, EM.StackDataEntry ); + listStackData.AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.LogStart, TState.EStateHeader ) ); + + // We want to observe the stack data as it arrives so that we can identify when all stack data has been supplied. + listStackData.StackChanged += new DExcExtractorListStackData.StackDataChangeHandler( StackDataChanged ); + } + + public void Init( string aStackFileName ) + { + Init(); + // + DExcExtractorListStackData stackData = (DExcExtractorListStackData) iLists[ TState.EStateStackData ]; + stackData.Prime( aStackFileName ); + } + + public bool Offer( string aLine, long aLineNumber ) + { + bool consumed = false; + + // Cache line number - we use this to update the data starting position + // when the state is changed. + iCurrentLineNumber = aLineNumber; + + // Get list for current state + DExcExtractorList list = CurrentList; + if ( list != null ) + { + consumed = list.Offer( aLine, aLineNumber, this ); + } + + return consumed; + } + + public void Finialize() + { + // If we were parsing code segs but we didn't get any stack + // data then we must ensure we still notify when we've reached + // the end of the code seg data (or else no crash item will be + // created). + switch ( State ) + { + case TState.EStateIdle: + // Already finished or not started + return; + default: + break; + } + + // Did we create entries in all non-idle lists? + bool haveEntriesForAllLists = ListsAreValid; + if ( haveEntriesForAllLists ) + { + NotifyEvent( TEvent.EEventExtractedAllData ); + State = TState.EStateIdle; + } + } + #endregion + + #region Properties + public TState State + { + get { return iState; } + set + { + if ( value != iState ) + { + TState oldState = value; + iState = value; + // + if ( oldState == TState.EStateIdle ) + { + // Was idle, now not - set starting line number + iData.LineNumber = iCurrentLineNumber; + } + else if ( iState == TState.EStateIdle ) + { + Init(); + } + } + } + } + + public DExcExtractedData CurrentData + { + get { return iData; } + } + + public DExcExtractorList CurrentList + { + get + { + DExcExtractorList ret = null; + // + if ( iLists.ContainsKey( State ) ) + { + ret = iLists[ State ]; + } + // + return ret; + } + } + #endregion + + #region Event handlers + private void StackDataChanged( DExcExtractorListStackData aSelf ) + { + DExcExtractorListThreadInfo threadInfo = (DExcExtractorListThreadInfo) iLists[ TState.EStateThreadInfo ]; + AddressRange range = threadInfo.StackRange; + if ( range.IsValid ) + { + uint lastAddress = aSelf.StackData.Last.Address; + if ( lastAddress == range.Max - 1 ) + { + NotifyEvent( TEvent.EEventExtractedAllData ); + State = TState.EStateIdle; + } + } + } + #endregion + + #region Internal enumerations + internal enum TState + { + EStateIdle = 0, + EStateHeader, + EStateThreadInfo, + EStateRegisterInfoException, + EStateRegisterInfoUser, + EStateCodeSegments, + EStateStackData, + } + #endregion + + #region Internal methods + private void NotifyEvent( TEvent aEvent ) + { + if ( StateChanged != null ) + { + StateChanged( aEvent, this ); + } + } + + private void PrepareList( DExcExtractorList aList, params Regex[] aExpressions ) + { + foreach ( Regex exp in aExpressions ) + { + DExcExtractorEntry entry = DExcExtractorEntry.NewMatchAndSave( exp ); + aList.AddExpression( entry ); + } + // + iLists.Add( aList.State, aList ); + iData.Add( aList ); + } + + private DExcExtractorList CreateList( TState aAssociatedState, DExcExtractorListType aType, params Regex[] aExpressions ) + { + DExcExtractorList ret = new DExcExtractorList( aAssociatedState, aType ); + PrepareList( ret, aExpressions ); + return ret; + } + + private bool ListsAreValid + { + get + { + int countThreadInfo = iLists[ TState.EStateThreadInfo ].Count; + int countRegUser = iLists[ TState.EStateRegisterInfoUser ].Count; + int countCodeSegs = iLists[ TState.EStateCodeSegments ].Count; + int countStackData = ((DExcExtractorListStackData) iLists[ TState.EStateStackData ]).StackData.Count; + // + bool valid = ( countThreadInfo >= 3 ) && ( countRegUser > 0 ) && ( countCodeSegs > 0 ) && ( countStackData > 0 ); + return valid; + } + } + #endregion + + #region From System.Object + public override string ToString() + { + string ret = iData.ToString(); + return ret; + } + #endregion + + #region Data members + private TState iState; + private long iCurrentLineNumber = 0; + private DExcExtractedData iData = new DExcExtractedData(); + private Dictionary iLists = new Dictionary(); + #endregion + } +}