|
1 /* |
|
2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * |
|
5 * Redistribution and use in source and binary forms, with or without |
|
6 * modification, are permitted provided that the following conditions are met: |
|
7 * |
|
8 * - Redistributions of source code must retain the above copyright notice, |
|
9 * this list of conditions and the following disclaimer. |
|
10 * - Redistributions in binary form must reproduce the above copyright notice, |
|
11 * this list of conditions and the following disclaimer in the documentation |
|
12 * and/or other materials provided with the distribution. |
|
13 * - Neither the name of Nokia Corporation nor the names of its contributors |
|
14 * may be used to endorse or promote products derived from this software |
|
15 * without specific prior written permission. |
|
16 * |
|
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
|
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
27 * POSSIBILITY OF SUCH DAMAGE. |
|
28 * |
|
29 * Initial Contributors: |
|
30 * Nokia Corporation - initial contribution. |
|
31 * |
|
32 * Contributors: |
|
33 * |
|
34 * Description: |
|
35 * |
|
36 */ |
|
37 |
|
38 using System; |
|
39 using System.Text; |
|
40 using System.IO; |
|
41 using System.Xml; |
|
42 using System.Collections.Generic; |
|
43 using System.Windows.Forms; |
|
44 using SymbianUtils; |
|
45 using SymbianUtils.Settings; |
|
46 using SymbianUtils.Tracer; |
|
47 using SymbianUtils.FileSystem.Utilities; |
|
48 using SymbianXmlInputLib.Parser; |
|
49 using SymbianXmlInputLib.Parser.Nodes; |
|
50 using SymbianXmlInputLib.Elements; |
|
51 using SymbianXmlInputLib.Elements.Types.Category; |
|
52 using SymbianXmlInputLib.Elements.Types.FileSystem; |
|
53 using SymbianXmlInputLib.Elements.Types.Command; |
|
54 using SymbianDebugLib.Engine; |
|
55 using SymbianDebugLib.Entity; |
|
56 using SymbianStructuresLib.CodeSegments; |
|
57 using HeapLib; |
|
58 using HeapLib.Reconstructor; |
|
59 using HeapLib.Reconstructor.Misc; |
|
60 using HeapLib.Reconstructor.DataSources; |
|
61 using HeapLib.Reconstructor.DataSources.Analyser; |
|
62 using HeapUiLib.Dialogs; |
|
63 using HeapUiLib.Forms; |
|
64 using HeapAnalyser.Engine; |
|
65 using HeapAnalyser.Engine.Types; |
|
66 using HeapAnalyser.Exceptions; |
|
67 using HeapComparisonUiLib.Progress; |
|
68 using HeapAnalyser.UIs.Console.Files; |
|
69 using HeapAnalyser.UIs.Console.Inputs; |
|
70 |
|
71 namespace HeapAnalyser.UIs.Console |
|
72 { |
|
73 public class HAUIConsole : HAUI |
|
74 { |
|
75 #region Constructors |
|
76 public HAUIConsole( string[] aArgs, XmlSettings aSettings, HeapWizardEngine aEngine, ITracer aTracer ) |
|
77 : base( aArgs, aSettings, aEngine, aTracer ) |
|
78 { |
|
79 iInputs = new HACmdLineInputParameters( this, aEngine ); |
|
80 } |
|
81 #endregion |
|
82 |
|
83 #region From HAUI |
|
84 public override bool IsAppropriateUI |
|
85 { |
|
86 get |
|
87 { |
|
88 // There must be command line arguments in order to use the command line UI |
|
89 bool ret = base.Args.Length != 0; |
|
90 // |
|
91 if ( ret ) |
|
92 { |
|
93 string[] args = base.Args; |
|
94 for ( int i = 0; i < args.Length; i++ ) |
|
95 { |
|
96 string cmd = args[ i ].Trim().ToUpper(); |
|
97 string nextArg = ( i < args.Length - 1 ? args[ i + 1 ].Trim().ToUpper() : string.Empty ); |
|
98 // |
|
99 try |
|
100 { |
|
101 if ( cmd == KPluginInputParameter && nextArg != string.Empty ) |
|
102 { |
|
103 ret = true; |
|
104 break; |
|
105 } |
|
106 } |
|
107 catch ( Exception ) |
|
108 { |
|
109 } |
|
110 } |
|
111 } |
|
112 // |
|
113 return ret; |
|
114 } |
|
115 } |
|
116 |
|
117 public override Form PrepareInitialForm() |
|
118 { |
|
119 Form formToShow = null; |
|
120 // |
|
121 ParseInputs(); |
|
122 PrimeDebugEngine(); |
|
123 |
|
124 // If we're running the graphical UI then show the main analysis form, |
|
125 // otherwise just run the comparison operation and exit. |
|
126 switch ( base.Engine.OperationType ) |
|
127 { |
|
128 case HeapWizardEngine.TOperationType.EOperationTypeAnalyseAndView: |
|
129 formToShow = RunAnalyser(); |
|
130 break; |
|
131 case HeapWizardEngine.TOperationType.EOperationTypeCompareHeapDumps: |
|
132 RunComparison(); |
|
133 break; |
|
134 } |
|
135 |
|
136 return formToShow; |
|
137 } |
|
138 |
|
139 public override Form HandleFormClosed( object aSender, EventArgs aArgs ) |
|
140 { |
|
141 Form ret = null; |
|
142 return ret; |
|
143 } |
|
144 #endregion |
|
145 |
|
146 #region Properties |
|
147 #endregion |
|
148 |
|
149 #region Event handlers |
|
150 private void DbgEngine_EntityPrimingStarted( DbgEngine aEngine, DbgEntity aEntity, object aContext ) |
|
151 { |
|
152 Trace( "[HA Cmd] Priming debug meta-data: " + aEntity.FullName ); |
|
153 } |
|
154 |
|
155 private void DbgEngine_EntityPrimingProgress( DbgEngine aEngine, DbgEntity aEntity, object aContext ) |
|
156 { |
|
157 if ( aContext != null ) |
|
158 { |
|
159 if ( aContext.GetType() == typeof( int ) ) |
|
160 { |
|
161 int value = (int) aContext; |
|
162 Trace( "[HA Cmd] Priming debug meta-data progress: {0:d3}% {1}", value, aEntity.FullName ); |
|
163 } |
|
164 } |
|
165 } |
|
166 |
|
167 private void DbgEngine_EntityPrimingComplete( DbgEngine aEngine, DbgEntity aEntity, object aContext ) |
|
168 { |
|
169 Trace( "[HA Cmd] Primed debug meta-data: " + aEntity.FullName ); |
|
170 } |
|
171 |
|
172 private void SymbolLibCodeSegDefinitionResolver_LocatedFile( string aFileName ) |
|
173 { |
|
174 Trace( "[HA Cmd] Located debug meta data: " + aFileName ); |
|
175 } |
|
176 #endregion |
|
177 |
|
178 #region Internal constants |
|
179 private const string KPluginInputParameter = "-INPUT"; |
|
180 #endregion |
|
181 |
|
182 #region Internal methods |
|
183 private void ParseInputs() |
|
184 { |
|
185 Trace( "[HA Cmd] ParseInputs() - START " ); |
|
186 Trace( string.Empty ); |
|
187 Trace( "[HA Cmd] command line: " + System.Environment.CommandLine ); |
|
188 Trace( "[HA Cmd] command wd: " + System.Environment.CurrentDirectory ); |
|
189 Trace( "[HA Cmd] proc count: " + System.Environment.ProcessorCount ); |
|
190 Trace( "[HA Cmd] sysdir: " + System.Environment.SystemDirectory ); |
|
191 Trace( "[HA Cmd] version: " + System.Environment.Version.ToString() ); |
|
192 Trace( string.Empty ); |
|
193 |
|
194 // We expect to see an "-input" parameter |
|
195 string inputFileName = ExtractCommandLineInputParameter( Args ); |
|
196 |
|
197 // If no file was found then inputFileName will be an empty string. |
|
198 if ( string.IsNullOrEmpty( inputFileName ) ) |
|
199 { |
|
200 throw new HAUIException( "Input file parameter missing", HAUIException.KErrCommandLineArgumentsMissing ); |
|
201 } |
|
202 else if ( !FSUtilities.Exists( inputFileName ) ) |
|
203 { |
|
204 throw new HAUIException( "Input file not found", HAUIException.KErrCommandLineArgumentsFileNotFound ); |
|
205 } |
|
206 else |
|
207 { |
|
208 Trace( "[HA Cmd] ParseInputs() - start read inputs" ); |
|
209 iInputs.Read( inputFileName ); |
|
210 Trace( "[HA Cmd] ParseInputs() - inputs read successfully" ); |
|
211 |
|
212 // Validate the inputs are correct. |
|
213 if ( string.IsNullOrEmpty( iInputs.ThreadName ) ) |
|
214 { |
|
215 throw new HAUIException( "The specified thread name is invalid", HAUIException.KErrCommandLineAnalysisThreadNameInvalid ); |
|
216 } |
|
217 else |
|
218 { |
|
219 // Validate input data |
|
220 int sourceCount = iInputs.SourceFiles.Count; |
|
221 switch( base.Engine.OperationType ) |
|
222 { |
|
223 case HeapWizardEngine.TOperationType.EOperationTypeAnalyseAndView: |
|
224 if ( iInputs.SourceFiles.Count != 1 && iInputs.SourceFiles[ 0 ].IsFile ) |
|
225 { |
|
226 Trace( "[HA Cmd] ParseInputs() - viewer - missing source file!" ); |
|
227 throw new HAUIException( "Source file not specified", HAUIException.KErrCommandLineSourceFileNotFound ); |
|
228 } |
|
229 break; |
|
230 case HeapWizardEngine.TOperationType.EOperationTypeCompareHeapDumps: |
|
231 if ( iInputs.SourceFiles.Count != 2 && iInputs.SourceFiles[ 0 ].IsFile && iInputs.SourceFiles[ 1 ].IsFile ) |
|
232 { |
|
233 Trace( "[HA Cmd] ParseInputs() - comparison - missing source files!" ); |
|
234 throw new HAUIException( "Source files not specified", HAUIException.KErrCommandLineSourceFileNotFound ); |
|
235 } |
|
236 break; |
|
237 } |
|
238 |
|
239 // Validate output (where needed) |
|
240 if ( base.Engine.OperationType == HeapWizardEngine.TOperationType.EOperationTypeCompareHeapDumps ) |
|
241 { |
|
242 bool outputSet = iInputs.OutputFile != null; |
|
243 if ( !outputSet ) |
|
244 { |
|
245 throw new HAUIException( "Output file not specified", HAUIException.KErrCommandLineAnalysisOutputInvalid ); |
|
246 } |
|
247 } |
|
248 } |
|
249 } |
|
250 |
|
251 Trace( "[HA Cmd] ParseInputs() - END" ); |
|
252 } |
|
253 |
|
254 private void PrimeDebugEngine() |
|
255 { |
|
256 DbgEngine debugEngine = base.Engine.DebugEngine; |
|
257 // |
|
258 Exception primerException = null; |
|
259 HACmdLineFSEntityList<HACmdLineFSEntity> metaDataFiles = iInputs.MetaDataFiles; |
|
260 // |
|
261 try |
|
262 { |
|
263 debugEngine.Clear(); |
|
264 |
|
265 foreach ( HACmdLineFSEntity entry in metaDataFiles ) |
|
266 { |
|
267 Trace( "[HA Cmd] Seeding debug meta engine with entry: " + entry.Name ); |
|
268 DbgEntity entity = debugEngine.Add( entry.Name ); |
|
269 if ( entity != null ) |
|
270 { |
|
271 Trace( "[HA Cmd] Entry type detected as: [" + entity.CategoryName + "]" ); |
|
272 entity.Tag = entry; |
|
273 } |
|
274 else |
|
275 { |
|
276 Trace( "[HA Cmd] Entry not handled: " + entry.Name ); |
|
277 } |
|
278 } |
|
279 |
|
280 // Listen to prime events |
|
281 try |
|
282 { |
|
283 Trace( "[HA Cmd] Starting prime operation... " ); |
|
284 debugEngine.EntityPrimingStarted += new DbgEngine.EventHandler( DbgEngine_EntityPrimingStarted ); |
|
285 debugEngine.EntityPrimingProgress += new DbgEngine.EventHandler( DbgEngine_EntityPrimingProgress ); |
|
286 debugEngine.EntityPrimingComplete += new DbgEngine.EventHandler( DbgEngine_EntityPrimingComplete ); |
|
287 debugEngine.Prime( TSynchronicity.EAsynchronous ); |
|
288 Trace( "[HA Cmd] Debug meta data priming completed successfully." ); |
|
289 } |
|
290 finally |
|
291 { |
|
292 debugEngine.EntityPrimingStarted -= new DbgEngine.EventHandler( DbgEngine_EntityPrimingStarted ); |
|
293 debugEngine.EntityPrimingProgress -= new DbgEngine.EventHandler( DbgEngine_EntityPrimingProgress ); |
|
294 debugEngine.EntityPrimingComplete -= new DbgEngine.EventHandler( DbgEngine_EntityPrimingComplete ); |
|
295 } |
|
296 } |
|
297 catch ( Exception exception ) |
|
298 { |
|
299 Trace( "[HA Cmd] Debug meta data priming exception: " + exception.Message + ", " + exception.StackTrace ); |
|
300 primerException = exception; |
|
301 } |
|
302 } |
|
303 |
|
304 private Form RunAnalyser() |
|
305 { |
|
306 string file = iInputs.SourceFiles[ 0 ].File.FullName; |
|
307 base.Engine.AnalysisEngine.DataSource = PrepareDataSource( file ); |
|
308 base.Engine.AnalysisEngine.CreateParser(); |
|
309 // |
|
310 Form ret = new HeapViewerForm( base.Engine.AnalysisEngine.Reconstructor, base.Settings ); |
|
311 return ret; |
|
312 } |
|
313 |
|
314 private void RunComparison() |
|
315 { |
|
316 // Does the output file already exist? If so, try to delete it. |
|
317 // If not, then carry on. |
|
318 if ( iInputs.OutputFile.File.Exists ) |
|
319 { |
|
320 // If deletion fails then return an error by way of heap analyser exception. |
|
321 try |
|
322 { |
|
323 iInputs.OutputFile.File.Delete(); |
|
324 } |
|
325 catch ( Exception ) |
|
326 { |
|
327 throw new HAUIException( "Could not overwrite output file", HAUIException.KErrCommandLineAnalysisOutputInvalid ); |
|
328 } |
|
329 } |
|
330 |
|
331 ComparisonEngineHeapData comparisonEngine = base.Engine.ComparisonEngineData; |
|
332 // |
|
333 string file1 = iInputs.SourceFiles[ 0 ].File.FullName; |
|
334 comparisonEngine.DataSource1 = PrepareDataSource( file1 ); |
|
335 // |
|
336 string file2 = iInputs.SourceFiles[ 1 ].File.FullName; |
|
337 comparisonEngine.DataSource2 = PrepareDataSource( file2 ); |
|
338 // |
|
339 comparisonEngine.OutputFileName = iInputs.OutputFile.File.FullName; |
|
340 base.Engine.ComparisonEngineData.CreateReconstructors(); |
|
341 ComparisonProgressDialogData.Compare( comparisonEngine.Reconstructor1, |
|
342 comparisonEngine.Reconstructor2, |
|
343 comparisonEngine.OutputFileName ); |
|
344 |
|
345 } |
|
346 |
|
347 private DataSource PrepareDataSource( string aFileName ) |
|
348 { |
|
349 DataSourceAnalyser analyser = HeapReconstructorDataSourceAnalyserDialog.Analyse( aFileName ); |
|
350 DataSourceCollection sources = analyser.DataSources; |
|
351 DataSource source = sources[ iInputs.ThreadName ]; |
|
352 if ( source == null ) |
|
353 { |
|
354 throw new HAUIException( "Thread was not found in source data", HAUIException.KErrCommandLineAnalysisThreadNameInvalid ); |
|
355 } |
|
356 // |
|
357 return source; |
|
358 } |
|
359 |
|
360 private static string ExtractCommandLineInputParameter( string[] aArgs ) |
|
361 { |
|
362 string ret = string.Empty; |
|
363 |
|
364 // -input d:\ca_fullsummary.xml |
|
365 for ( int i = 0; i < aArgs.Length; i++ ) |
|
366 { |
|
367 string cmd = aArgs[ i ].Trim().ToUpper(); |
|
368 string nextArg = ( i < aArgs.Length - 1 ? aArgs[ i + 1 ].Trim().ToUpper() : string.Empty ); |
|
369 // |
|
370 if ( cmd == KPluginInputParameter && nextArg != string.Empty ) |
|
371 { |
|
372 ret = nextArg; |
|
373 } |
|
374 } |
|
375 |
|
376 return ret; |
|
377 } |
|
378 #endregion |
|
379 |
|
380 #region Data members |
|
381 private readonly HACmdLineInputParameters iInputs; |
|
382 #endregion |
|
383 } |
|
384 } |