crashanalysercmd/Libraries/File Formats/Plugins/DExcPlugin/Extractor/DExcExtractor.cs
changeset 0 818e61de6cd1
equal deleted inserted replaced
-1:000000000000 0:818e61de6cd1
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 * 
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 using System;
       
    18 using System.Text;
       
    19 using System.Text.RegularExpressions;
       
    20 using System.Collections.Generic;
       
    21 using SymbianUtils.Range;
       
    22 using EM=DExcPlugin.ExpressionManager.DExcExpressionManager;
       
    23 
       
    24 namespace DExcPlugin.Extractor
       
    25 {
       
    26 	internal class DExcExtractor
       
    27 	{
       
    28         #region Events
       
    29         public enum TEvent
       
    30         {
       
    31             EEventExtractedAllData
       
    32         }
       
    33 
       
    34         public delegate void EventHandler( TEvent aEvent, DExcExtractor aExtractor );
       
    35         public event EventHandler StateChanged;
       
    36         #endregion
       
    37 
       
    38         #region Constructors
       
    39         public DExcExtractor()
       
    40 		{
       
    41             Init();
       
    42         }
       
    43 		#endregion
       
    44 
       
    45 		#region API
       
    46         public void Init()
       
    47         {
       
    48             iState = TState.EStateIdle;
       
    49             iData = new DExcExtractedData();
       
    50             iLists = new Dictionary<TState, DExcExtractorList>();
       
    51             iCurrentLineNumber = 0;
       
    52 		    
       
    53             // Null (really just exists to catch a state transition)
       
    54             // =======================================================
       
    55             CreateList( TState.EStateIdle, DExcExtractorListType.EListNull ).AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.LogStart, TState.EStateHeader ) );
       
    56 		    
       
    57             // Header
       
    58             // =======================================================
       
    59             CreateList( TState.EStateHeader, DExcExtractorListType.EListHeader ).AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.ThreadName, TState.EStateThreadInfo ) );
       
    60 
       
    61             // Thread info
       
    62             // ===========
       
    63             DExcExtractorListThreadInfo listThreadInfo = new DExcExtractorListThreadInfo( TState.EStateThreadInfo, DExcExtractorListType.EListThread );
       
    64             PrepareList( listThreadInfo, EM.ThreadName, EM.ThreadId, EM.ThreadStackRange, EM.ThreadPanicDetails );
       
    65             listThreadInfo.AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.RegistersExceptionStart, TState.EStateRegisterInfoException ) );
       
    66             listThreadInfo.AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.RegistersUserStart, TState.EStateRegisterInfoUser ) );
       
    67 
       
    68             // Registers (exception)
       
    69             // =====================
       
    70             DExcExtractorList listRegisterInfoException = CreateList( TState.EStateRegisterInfoException, DExcExtractorListType.EListRegistersException,
       
    71                                                                         EM.RegistersExceptionSet1,
       
    72                                                                         EM.RegistersExceptionSet2 );
       
    73             listRegisterInfoException.AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.RegistersUserStart, TState.EStateRegisterInfoUser ) );
       
    74 
       
    75             // Registers (user)
       
    76             // ================
       
    77             DExcExtractorList listRegisterInfoUser = CreateList( TState.EStateRegisterInfoUser, DExcExtractorListType.EListRegistersUser,
       
    78                                                                    EM.RegistersUserCPSR,
       
    79                                                                    EM.RegistersUserSet );
       
    80 
       
    81             // Since code segs are optional, we want to record that we at least saw the header text (which is mandatory). This
       
    82             // tracking allows us to validate that we have received/observed data for all states.
       
    83             listRegisterInfoUser.AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.CodeSegmentsStart, TState.EStateCodeSegments ) );
       
    84 
       
    85             // Code segments
       
    86             // =============
       
    87             DExcExtractorList listCodeSegments = CreateList( TState.EStateCodeSegments, DExcExtractorListType.EListCodeSegments, EM.CodeSegmentsEntry );
       
    88 
       
    89             // We need to transition state to "stack data", but we must be sure not to throw away the state line we just encountered.
       
    90             listCodeSegments.AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.StackDataEntry, TState.EStateStackData ) );
       
    91 
       
    92             // Stack data
       
    93             // ==========
       
    94             DExcExtractorListStackData listStackData = new DExcExtractorListStackData( TState.EStateStackData, DExcExtractorListType.EListStackData );
       
    95             PrepareList( listStackData, EM.StackDataEntry );
       
    96             listStackData.AddExpression( DExcExtractorEntry.NewMatchSaveAndTransition( EM.LogStart, TState.EStateHeader ) );
       
    97 
       
    98             // We want to observe the stack data as it arrives so that we can identify when all stack data has been supplied.
       
    99             listStackData.StackChanged += new DExcExtractorListStackData.StackDataChangeHandler( StackDataChanged );
       
   100         }
       
   101 
       
   102         public void Init( string aStackFileName )
       
   103         {
       
   104             Init();
       
   105             //
       
   106             DExcExtractorListStackData stackData = (DExcExtractorListStackData) iLists[ TState.EStateStackData ];
       
   107             stackData.Prime( aStackFileName );
       
   108         }
       
   109 
       
   110         public bool Offer( string aLine, long aLineNumber )
       
   111 		{
       
   112             bool consumed = false;
       
   113 
       
   114             // Cache line number - we use this to update the data starting position
       
   115             // when the state is changed.
       
   116             iCurrentLineNumber = aLineNumber;
       
   117 
       
   118             // Get list for current state
       
   119             DExcExtractorList list = CurrentList;
       
   120             if ( list != null )
       
   121             {
       
   122                 consumed = list.Offer( aLine, aLineNumber, this );
       
   123             }
       
   124 
       
   125             return consumed;
       
   126 		}
       
   127 
       
   128         public void Finialize()
       
   129 		{
       
   130 			// If we were parsing code segs but we didn't get any stack
       
   131 			// data then we must ensure we still notify when we've reached
       
   132 			// the end of the code seg data (or else no crash item will be
       
   133 			// created).
       
   134             switch ( State )
       
   135             {
       
   136             case TState.EStateIdle:
       
   137                 // Already finished or not started
       
   138                 return;
       
   139             default:
       
   140                 break;
       
   141             }
       
   142 
       
   143             // Did we create entries in all non-idle lists?
       
   144             bool haveEntriesForAllLists = ListsAreValid;
       
   145             if ( haveEntriesForAllLists )
       
   146             {
       
   147                 NotifyEvent( TEvent.EEventExtractedAllData );
       
   148                 State = TState.EStateIdle;
       
   149             }
       
   150 		}
       
   151 		#endregion
       
   152 
       
   153         #region Properties
       
   154         public TState State
       
   155 		{
       
   156             get { return iState; }
       
   157             set
       
   158             {
       
   159                 if ( value != iState )
       
   160                 {
       
   161                     TState oldState = value;
       
   162                     iState = value;
       
   163                     //
       
   164                     if ( oldState == TState.EStateIdle )
       
   165                     {
       
   166                         // Was idle, now not - set starting line number
       
   167                         iData.LineNumber = iCurrentLineNumber;
       
   168                     }
       
   169                     else if ( iState == TState.EStateIdle )
       
   170                     {
       
   171                         Init();
       
   172                     }
       
   173                 }
       
   174             }
       
   175 		}
       
   176 
       
   177         public DExcExtractedData CurrentData
       
   178         {
       
   179             get { return iData; }
       
   180         }
       
   181 
       
   182         public DExcExtractorList CurrentList
       
   183         {
       
   184             get
       
   185             {
       
   186                 DExcExtractorList ret = null;
       
   187                 //
       
   188                 if ( iLists.ContainsKey( State ) )
       
   189                 {
       
   190                     ret = iLists[ State ];
       
   191                 }
       
   192                 //
       
   193                 return ret;
       
   194             }
       
   195         }
       
   196 		#endregion
       
   197 
       
   198         #region Event handlers
       
   199         private void StackDataChanged( DExcExtractorListStackData aSelf )
       
   200         {
       
   201             DExcExtractorListThreadInfo threadInfo = (DExcExtractorListThreadInfo) iLists[ TState.EStateThreadInfo ];
       
   202             AddressRange range = threadInfo.StackRange;
       
   203             if ( range.IsValid )
       
   204             {
       
   205                 uint lastAddress = aSelf.StackData.Last.Address;
       
   206                 if ( lastAddress == range.Max - 1 )
       
   207                 {
       
   208                     NotifyEvent( TEvent.EEventExtractedAllData );
       
   209                     State = TState.EStateIdle;
       
   210                 }
       
   211             }
       
   212         }
       
   213         #endregion
       
   214         
       
   215         #region Internal enumerations
       
   216         internal enum TState
       
   217         {
       
   218             EStateIdle = 0,
       
   219             EStateHeader,
       
   220             EStateThreadInfo,
       
   221             EStateRegisterInfoException,
       
   222             EStateRegisterInfoUser,
       
   223             EStateCodeSegments,
       
   224             EStateStackData,
       
   225         }
       
   226         #endregion
       
   227 
       
   228         #region Internal methods
       
   229         private void NotifyEvent( TEvent aEvent )
       
   230         {
       
   231             if ( StateChanged != null )
       
   232             {
       
   233                 StateChanged( aEvent, this );
       
   234             }
       
   235         }
       
   236 
       
   237         private void PrepareList( DExcExtractorList aList, params Regex[] aExpressions )
       
   238         {
       
   239             foreach ( Regex exp in aExpressions )
       
   240             {
       
   241                 DExcExtractorEntry entry = DExcExtractorEntry.NewMatchAndSave( exp );
       
   242                 aList.AddExpression( entry );
       
   243             }
       
   244             //
       
   245             iLists.Add( aList.State, aList );
       
   246             iData.Add( aList );
       
   247         }
       
   248 
       
   249         private DExcExtractorList CreateList( TState aAssociatedState, DExcExtractorListType aType, params Regex[] aExpressions )
       
   250         {
       
   251             DExcExtractorList ret = new DExcExtractorList( aAssociatedState, aType );
       
   252             PrepareList( ret, aExpressions );
       
   253             return ret;
       
   254         }
       
   255 
       
   256         private bool ListsAreValid
       
   257         {
       
   258             get
       
   259             {
       
   260                 int countThreadInfo = iLists[ TState.EStateThreadInfo ].Count;
       
   261                 int countRegUser = iLists[ TState.EStateRegisterInfoUser ].Count;
       
   262                 int countCodeSegs = iLists[ TState.EStateCodeSegments ].Count;
       
   263                 int countStackData = ((DExcExtractorListStackData) iLists[ TState.EStateStackData ]).StackData.Count;
       
   264                 //
       
   265                 bool valid = ( countThreadInfo >= 3 ) && ( countRegUser > 0 ) && ( countCodeSegs > 0 ) && ( countStackData > 0 );
       
   266                 return valid;
       
   267             }
       
   268         }
       
   269         #endregion
       
   270 
       
   271         #region From System.Object
       
   272         public override string ToString()
       
   273         {
       
   274             string ret = iData.ToString();
       
   275             return ret;
       
   276         }
       
   277         #endregion
       
   278 
       
   279         #region Data members
       
   280         private TState iState;
       
   281         private long iCurrentLineNumber = 0;
       
   282         private DExcExtractedData iData = new DExcExtractedData();
       
   283         private Dictionary<TState, DExcExtractorList> iLists = new Dictionary<TState, DExcExtractorList>();
       
   284 		#endregion
       
   285 	}
       
   286 }