|
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 } |