crashanalysercmd/Libraries/File Formats/Plugins/CrashInfoFilePlugin/FileFormat/CCrashInfoHashBuilder.cs
changeset 2 0c91f0baec58
parent 1 7a31f7298d8f
child 3 045ade241ef5
--- a/crashanalysercmd/Libraries/File Formats/Plugins/CrashInfoFilePlugin/FileFormat/CCrashInfoHashBuilder.cs	Tue Feb 23 17:05:24 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,399 +0,0 @@
-/*
-* 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.IO;
-using System.Text;
-using System.Security.Cryptography;
-using System.Collections.Generic;
-using CrashItemLib.Crash;
-using CrashItemLib.Crash.Base;
-using CrashItemLib.Crash.Processes;
-using CrashItemLib.Crash.Registers;
-using CrashItemLib.Crash.Registers.Special;
-using CrashItemLib.Crash.Stacks;
-using CrashItemLib.Crash.Threads;
-using CrashItemLib.Crash.Symbols;
-using CrashItemLib.Crash.Summarisable;
-using SymbianStructuresLib.Arm.Registers;
-
-
-namespace CrashInfoFilePlugin.PluginImplementations.FileFormat
-{
-    public class CCrashInfoHashBuilder
-    {
-        #region Enumerations
-        [Flags]
-        public enum TConfiguration
-        {
-            // <summary>
-            // Include stack data in hash
-            // </summary>
-            EIncludeStack = 1,
-
-            // <summary>
-            // Force inclusion of stack data in hash, even if hash builder
-            // believes that it's inclusion is not needed in order to uniquely
-            // pin-point the crash.
-            // </summary>
-            EIncludeStackForced = 2,
-
-            // <summary>
-            // By default, offset is only included in program counter symbol. 
-            // This will force it to be incldued for all symbols (i.e. even
-            // those within stack trace).
-            // </summary>
-            EIncludeOffsetsForAllSymbols = 4,
-
-            // <summary>
-            // Include the processor mode at the time of the crash within the hash.
-            // </summary>
-            EIncludeProcessorMode = 8,
-
-            // <summary>
-            // By default we output an MD5 hash, but you can enable plain text
-            // output by using this option.
-            // </summary>
-            EOutputAsText = 16,
-            
-            // <summary>
-            // A general purpose default configuration
-            // </summary>
-            EDefault = EIncludeStack | EIncludeStackForced | EIncludeProcessorMode
-        }
-        #endregion
-
-        #region Factory
-        public static CCrashInfoHashBuilder New( TConfiguration aConfig, CISummarisableEntity aEntity )
-        {
-            CCrashInfoHashBuilder ret = CCrashInfoHashBuilder.New( aConfig, aEntity, KDefaultNumberOfStackEntriesToCheckForSymbols );
-            return ret;
-        }
-
-        public static CCrashInfoHashBuilder New( TConfiguration aConfig, CISummarisableEntity aEntity, int aNumberOfStackEntriesToCheck )
-        {
-            // By default we'll return an empty string for the hash if mandatory input
-            // elements are not available
-            CCrashInfoHashBuilder ret = null;
-            //
-            CIStack stack = aEntity.Stack;
-            CIThread thread = aEntity.Thread;
-            CIProcess process = aEntity.Process;
-            CIRegisterList regs = aEntity.Registers;
-            //
-            if ( stack != null && regs != null )
-            {
-                if ( process == null || thread == null )
-                {
-                    ret = new CCrashInfoHashBuilder( aConfig, regs, stack, aNumberOfStackEntriesToCheck );
-                }
-                else
-                {
-                    ret = new CCrashInfoHashBuilder( aConfig, regs, stack, thread, process, aNumberOfStackEntriesToCheck );
-                }
-            }
-            else
-            {
-                throw new ArgumentException( LibResources.KRes_CCrashInfoHashBuilder_BadSummarisable );
-            }
-            //
-            return ret;
-        }
-        #endregion
-
-        #region Constructors
-        private CCrashInfoHashBuilder( TConfiguration aConfig, CIRegisterList aRegisters, CIStack aStack, int aNumberOfStackEntriesToCheck )
-            : this( aConfig, aRegisters, aStack, null, null, aNumberOfStackEntriesToCheck )
-        {
-        }
-
-        private CCrashInfoHashBuilder( TConfiguration aConfig, CIRegisterList aRegisters, CIStack aStack, CIThread aThread, CIProcess aProcess, int aNumberOfStackEntriesToCheck )
-        {
-            iConfig = aConfig;
-            iRegisters = aRegisters;
-            iStack = aStack;
-            iProcess = aProcess;
-            iThread = aThread;
-            iNumberOfStackEntriesToCheck = aNumberOfStackEntriesToCheck;
-        }
-        #endregion
-
-        #region API
-        public string GetHash()
-        {
-            StringBuilder hash = new StringBuilder();
-            //
-            if ( ( iConfig & TConfiguration.EIncludeProcessorMode ) != 0 )
-            {
-                string processorMode = GetProcessorMode();
-                hash.AppendFormat( "MODE: [{0}] ", processorMode );
-            }
-            //
-            string moduleName = GetAppropriateBinaryModuleName();
-            hash.AppendFormat( "MODN: [{0}] ", moduleName );
-            //
-            string programCounter = GetProgramCounter();
-            hash.AppendFormat( "PC: [{0}] ", programCounter );
-            //
-            if ( ( iConfig & TConfiguration.EIncludeStack ) != 0 || ( iConfig & TConfiguration.EIncludeStackForced ) != 0 )
-            {
-                string stackSymbols = GetStackSymbols();
-                hash.AppendFormat( "STK: [{0}] ", stackSymbols );
-            }
-            
-            // Final stage is to MD5 hash the text, unless the caller requested
-            // plain text output.
-            string ret = hash.ToString();            
-            if ( ( iConfig & TConfiguration.EOutputAsText ) == 0 )
-            {
-                ret = GetMD5( ret );
-            }
-            //
-            return ret;
-        }
-        #endregion
-
-        #region Internal constants
-        private const int KDefaultNumberOfStackEntriesToCheckForSymbols = 4;
-        #endregion
-
-        #region Internal methods
-        private string GetProcessorMode()
-        {
-            string ret = LibResources.KRes_CCrashInfoHashBuilder_NoCPUMode;
-            //
-            if ( iRegisters.IsCurrentProcessorMode )
-            {
-                CIRegisterCPSR cpsr = iRegisters[ TArmRegisterType.EArmReg_CPSR ] as CIRegisterCPSR;
-                if ( cpsr != null )
-                {
-                    ret = ArmRegisterBankUtils.BankAsString( cpsr.ProcessorMode );
-                }
-            }
-            //
-            return ret;
-        }
-
-        private string GetAppropriateBinaryModuleName()
-        {
-            // We'll use the name of the binary associated with the program 
-            // counter symbol (if present) or then if not, we'll fall back
-            // to using the process name.
-            string ret = string.Empty;
-            //
-            bool fallBack = false;
-            if ( iRegisters.Contains( TArmRegisterType.EArmReg_PC ) )
-            {
-                CIRegister pc = iRegisters[ TArmRegisterType.EArmReg_PC ];
-                if ( pc.Symbol.IsNull == false )
-                {
-                    // Symbol available - use the associated binary name
-                    string binName = pc.Symbol.Symbol.Collection.FileName.EitherFullNameButDevicePreferred;
-                    ret = Path.GetFileName( binName );
-                }
-                else
-                {
-                    fallBack = true;
-                }
-            }
-            else
-            {
-                fallBack = true;
-            }
-
-            // Do we need to fallback because symbol et al was unavailable?
-            if ( fallBack )
-            {
-                // No Symbol, then in this case we'll try to fall back
-                // to the process name. 
-                if ( iProcess != null )
-                {
-                    ret = iProcess.Name;
-                }
-                else
-                {
-                    // Must be e.g. IRQ, FIQ, ABT, etc
-                    ret = LibResources.KRes_CCrashInfoHashBuilder_AbortModeStack;
-                }
-            }
-            //
-            return ret;
-        }
-
-        private string GetProgramCounter()
-        {
-            string ret = string.Empty;
-            //
-            if ( iRegisters.Contains( TArmRegisterType.EArmReg_PC ) )
-            {
-                CIRegister pc = iRegisters[ TArmRegisterType.EArmReg_PC ];
-                ret = CleanSymbol( pc.Value, pc.Symbol, true );
-            }
-            //
-            return ret;
-        }
-
-        private string GetStackSymbols()
-        {
-            StringBuilder ret = new StringBuilder();
-            //
-            if ( iStack.IsStackOutputAvailable )
-            {
-                bool isOverflow = iStack.IsOverflow;
-                bool isForced = ( iConfig & TConfiguration.EIncludeStackForced ) != 0;
-                bool isNullDereference = ( iStack.Registers.Contains( TArmRegisterType.EArmReg_00 ) && iStack.Registers[ TArmRegisterType.EArmReg_00 ].Value == 0 );
-
-                // If dealing with a stack overflow, then we don't, by default, include any
-                // symbols from the stack, as they are likely to be entirely dirty or "ghosts" for
-                // the most part. 
-                //
-                // Furthermore, if the 'crash' was caused by dereferencing a NULL this pointer
-                // (which is somewhat of a guess on our part, but we ascertain this by inspecting
-                // the value of R0) then we don't include stack either.
-                //
-                // However, the above behaviour can be overriden by forcing stack processing.
-                bool processEntries = ( ( isOverflow == false && isNullDereference == false ) || isForced );
-                if ( processEntries )
-                {
-                    // Get the entries and work out the number of items we should check for
-                    // associated symbols.
-                    CIElementList<CIStackEntry> stackEntries = iStack.ChildrenByType<CIStackEntry>();
-
-                    // Discard all the entries that are outside of the stack pointer range.
-                    // Once we see a register-based entry (for accurate decoding) or the current
-                    // stack pointer entry, we've reached the start of the interesting stack data.
-                    //
-                    // However, if there has been a stack overflow then don't discard anything
-                    // or else we'll end up with nothing left!
-                    if ( iStack.IsOverflow == false && stackEntries.Count > 0 )
-                    {
-                        int i = 0;
-                        while ( stackEntries.Count > 0 )
-                        {
-                            // If we see a register based entry then the stack reconstruction almost certainly
-                            // used the accurate algorithm.
-                            //
-                            // Since we have already included the program counter in the hash text, it doesn't
-                            // make sense to include it twice, so skip that.
-                            // However, link register might be useful.
-                            bool remove = true;
-                            CIStackEntry entry = stackEntries[ i ];
-
-                            if ( entry.IsCurrentStackPointerEntry )
-                            {
-                                break;
-                            }
-                            else if ( entry.IsRegisterBasedEntry )
-                            {
-                                // Preserve LR, skip PC
-                                if ( entry.Register.Type == TArmRegisterType.EArmReg_LR )
-                                {
-                                    ++i;
-                                    remove = false;
-                                }
-                            }
-
-                            if ( remove )
-                            {
-                                stackEntries.RemoveAt( 0 );
-                            }
-                        }
-                    }
-
-                    // Did the caller also want offsets within the output? By default only the program
-                    // counter receives this treatment, but it can be overridden.
-                    bool includeOffset = ( iConfig & TConfiguration.EIncludeOffsetsForAllSymbols ) != 0;
-
-                    // We should now have the stack entries directly relating to the crash call stack.
-                    // Process them in turn, but only look at entries which happen to have associated
-                    // symbols.
-                    
-                    int SymbolsNeeded = iNumberOfStackEntriesToCheck;
-                    foreach (CIStackEntry entry in stackEntries)
-                    {                       
-                        if ( entry.Symbol != null && entry.Symbol.IsNull == false )
-                        {
-                            string txt = CleanSymbol( entry.Data, entry.Symbol, includeOffset );
-                            ret.AppendFormat( "{0}, ", txt );
-                            SymbolsNeeded--;
-                        }     
-                        if (SymbolsNeeded == 0)
-                        {
-                            break;
-                        }
-                    }
-                   
-                    // Remove trailing comma
-                    string t = ret.ToString();
-                    if ( t.EndsWith( ", " ) )
-                    {
-                        ret = ret.Remove( ret.Length - 2, 2 );
-                    }
-                }
-            }
-            //
-            string final = ret.ToString().TrimEnd();
-            return final;
-        }
-
-        private string GetMD5( string aMakeHash )
-        {
-            MD5 md5 = MD5.Create();
-            byte[] inputBytes = Encoding.ASCII.GetBytes( aMakeHash );
-            byte[] hash = md5.ComputeHash( inputBytes );
-            //
-            StringBuilder sb = new StringBuilder();
-            //
-            for ( int i = 0; i < hash.Length; i++ )
-            {
-                sb.Append( hash[ i ].ToString( "x2" ) );
-            }
-            //
-            return sb.ToString();
-        }
-
-        private static string CleanSymbol( uint aAddress, CISymbol aSymbol, bool aAddOffset )
-        {
-            string ret = string.Empty;
-            //
-            if ( aSymbol.IsNull == false )
-            {
-                if ( aAddOffset )
-                {
-                    // Only include the name and offset, not the address
-                    uint offset = aSymbol.Symbol.Offset( aAddress );
-                    ret = string.Format( "|0x{0:x4}| {1}", offset, aSymbol.Symbol.Name );
-                }
-                else
-                {
-                    ret = aSymbol.Symbol.Name;
-                }
-            }
-            //
-            return ret;
-        }
-        #endregion
-
-        #region Data members
-        private readonly TConfiguration iConfig;
-        private readonly CIRegisterList iRegisters;
-        private readonly CIStack iStack;
-        private readonly CIThread iThread;
-        private readonly CIProcess iProcess;
-        private readonly int iNumberOfStackEntriesToCheck;
-        #endregion
-    }
-}