--- /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<TState, DExcExtractorList>();
+ 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<TState, DExcExtractorList> iLists = new Dictionary<TState, DExcExtractorList>();
+ #endregion
+ }
+}