crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStructuresLib/Debug/Symbols/Symbols/Symbol.cs
author Matti Laitinen <matti.t.laitinen@nokia.com>
Thu, 11 Feb 2010 15:50:58 +0200
changeset 0 818e61de6cd1
permissions -rw-r--r--
Add initial version of Crash Analyser cmdline under EPL

#define TRACE_INTERNING
/*
* 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.Collections;
using System.Text;
using System.Text.RegularExpressions;
using System.ComponentModel;
using SymbianUtils.Range;
using SymbianUtils.Strings;
using SymbianStructuresLib.Arm;
using SymbianStructuresLib.MemoryModel;
using SymbianStructuresLib.Debug.Symbols.Constants;
using SymbianStructuresLib.Debug.Common.Id;

namespace SymbianStructuresLib.Debug.Symbols
{
	public class Symbol : IFormattable
    {
        #region Static constructors
        public static Symbol New( SymbolCollection aCollection )
        {
            return new Symbol( aCollection );
        }

        public static Symbol NewDefault()
        {
            Symbol ret = new Symbol( null );
            //
            ret.IsDefault = true;
            ret.Size = 0;
            ret.OffsetAddress = SymbolConstants.KNullEntryAddress;
            ret.Object = SymbolConstants.KNonMatchingObjectName;
            ret.iName = InternedName.NewExplicit( SymbolConstants.KNonMatchingInternedName );
            //
            return ret;
        }

        internal static Symbol NewDefault( SymbolCollection aCollection )
        {
            Symbol ret = new Symbol( aCollection );
            //
            ret.IsDefault = true;
            ret.Size = 0;
            ret.OffsetAddress = SymbolConstants.KNullEntryAddress;
            ret.Object = SymbolConstants.KNonMatchingObjectName;
            ret.iName = InternedName.NewExplicit( SymbolConstants.KNonMatchingInternedName );
            //
            return ret;
        }

        internal static Symbol NewTemp( SymbolCollection aCollection, uint aAddress )
        {
            Symbol ret = new Symbol( aCollection );
            //
            ret.Size = 0;
            ret.OffsetAddress = aAddress - aCollection.BaseAddress;
            ret.iName = InternedName.NewExplicit( "TempInternal" );
            ret.Object = "TempInternal";
            //
            return ret;
        }

        internal static Symbol NewClone( SymbolCollection aCollection, Symbol aSymbol )
        {
            return new Symbol( aCollection, aSymbol );
        }
        #endregion

        #region Constructors
        private Symbol( SymbolCollection aCollection )
		{
            iCollection = aCollection;
            //
            if ( aCollection != null )
            {
                iId = aCollection.IdAllocator.AllocateId().Value;
            }
		}

        private Symbol( SymbolCollection aCollection, Symbol aSymbol )
            : this( aCollection )
        {
            iSize = aSymbol.iSize;
            iOffsetAddress = aSymbol.iOffsetAddress;
            iName = aSymbol.iName;
            iObject = aSymbol.iObject;
            iFlags = aSymbol.iFlags;
            iId = aCollection.IdAllocator.AllocateId().Value;
        }
		#endregion

		#region API
		public bool Contains( uint aAddress )
		{
            bool ret = ( aAddress >= Address && aAddress <= EndAddress );
            return ret;
		}

        public uint Offset( uint aInstructionAddress )
        {
            uint offset = aInstructionAddress - Address;
            return offset;
        }
        #endregion

        #region Properties
		public uint Address
		{
			get
            {
                uint address = BaseAddress + OffsetAddress;
                return address;
            }
		}

		public uint EndAddress
		{
			get
            {
                uint address = Address;
                uint size = Size;
                //
                if ( size > 0 )
                {
                    address += ( size - 1 );
                }
                //
                return address;
            }
		}

		public uint Size
		{
			get { return iSize; }
			set
			{
				iSize = value;
				System.Diagnostics.Debug.Assert( OffsetEndAddress >= OffsetAddress );
			}
		}

        public AddressRange AddressRange
        {
            get { return new AddressRange( Address, EndAddress ); }
        }

		public string Name
		{
			get
            {
                string ret = string.Empty;
                //
                if ( iName != null )
                {
                    ret = iName.ToString();
                }
                //
                return ret;
            }
			set
			{
                iName = InternedName.New( value );
               
                // Remove all property flags
                iFlags &= ~TFlags.EFlagsIsFunction;
                iFlags &= ~TFlags.EFlagsIsVTable;
                iFlags &= ~TFlags.EFlagsIsReadonly;
                iFlags &= ~TFlags.EFlagsIsSubObject;

                if ( InternedName.IsVTable( value ) )
                {
                    iFlags |= TFlags.EFlagsIsVTable;
                }
                else if ( InternedName.IsReadOnly( value ) )
                {
                    iFlags |= TFlags.EFlagsIsReadonly;
                }
                else if ( InternedName.IsSubObject( value ) )
                {
                    iFlags |= TFlags.EFlagsIsSubObject;
                }
                else if ( InternedName.IsFunction( value ) )
                {
                    iFlags |= TFlags.EFlagsIsFunction;
                }
            }
		}

        public string NameWithoutVTablePrefix
		{
			get
            {
                StringBuilder ret = new StringBuilder( Name );
                //
                ret = ret.Replace( "vtable for ", string.Empty );
                ret = ret.Replace( "typeinfo for ", string.Empty );
                ret = ret.Replace( "typeinfo name for ", string.Empty );
                //
                return ret.ToString();
            }
		}

		public string Object
		{
			get
            {
                string ret = string.Empty;
                //
                if ( iObject != null )
                {
                    ret = iObject;
                }
                //
                return ret;
            }
			set
            {
                iObject = string.Intern( value );
            }
		}

		public string ObjectWithoutSection
		{
			get
			{
				string ret = string.Empty;
                //
                if  ( Object != null )
                {
                    ret = Object;
                    //
                    int bracketPos = ret.IndexOf( "(" );
                    if	( bracketPos > 0 )
                    {
                        ret = ret.Substring( 0, bracketPos ).Trim();
                    }
                }
                //
				return ret;
			}
		}

        public SymbolCollection Collection
        {
            // NB: can be null
            get { return iCollection; }
        }

        public TArmInstructionSet InstructionSet
        {
            get
            {
                TArmInstructionSet ret = TArmInstructionSet.EARM;
                uint remainder = iOffsetAddress & 0x1;
                if ( remainder != 0 )
                {
                    ret = TArmInstructionSet.ETHUMB;
                }
                return ret;
            }
        }

        public PlatformId Id
        {
            get { return new PlatformId( iId ); }
        }

        [Browsable( false )]
        [EditorBrowsable( EditorBrowsableState.Never )]
        public uint OffsetAddress
        {
            get
            {
                // Don't include the top bit in any returned address
                uint ret = iOffsetAddress & 0xFFFFFFFE;
                return ret;
            }
            set
            {
                iOffsetAddress = value;
            }
        }

        [Browsable( false )]
        [EditorBrowsable( EditorBrowsableState.Never )]
        private uint OffsetEndAddress
        {
            get
            {
                uint ret = iOffsetAddress + iSize;
                if ( InstructionSet == TArmInstructionSet.ETHUMB && iSize > 0 )
                {
                    // For thumb, the end address is one too big, due to the MSB.
                    --ret;
                }
                return ret;
            }
        }
        #endregion

        #region Type query
        public bool IsFunction
        {
            get
            {
                bool ret = ( iFlags & TFlags.EFlagsIsFunction ) != 0;
                return ret;
            }
        }

        public bool IsVTable
        {
            get
            {
                bool ret = ( iFlags & TFlags.EFlagsIsVTable ) == TFlags.EFlagsIsVTable;
                return ret;
            }
        }

        public bool IsDefault
        {
            get
            {
                bool ret = ( iFlags & TFlags.EFlagsIsDefault ) == TFlags.EFlagsIsDefault;
                return ret;
            }
            set
            {
                if ( value )
                {
                    iFlags |= TFlags.EFlagsIsDefault;
                }
                else
                {
                    iFlags &= ~TFlags.EFlagsIsDefault;
                }
            }
        }

        public bool IsFromRAMLoadedCode
        {
            get
            {
                uint address = this.Address;
                TMemoryModelRegion region = MMUtilities.RegionByAddress( address );
                bool ret = ( region == TMemoryModelRegion.EMemoryModelRegionRAMLoadedCode );
                return ret;
            }
        }

		public TSymbolType Type
		{
			get
			{
                TSymbolType ret = TSymbolType.EUnknown;

                // First check against forced flags
                if ( ( iFlags & TFlags.EFlagsIsForcedSection ) == TFlags.EFlagsIsForcedSection )
                {
                    ret = TSymbolType.ESection;
                }
                else if ( ( iFlags & TFlags.EFlagsIsForcedCode ) == TFlags.EFlagsIsForcedCode )
                {
                    ret = TSymbolType.ECode;
                }
                else if ( ( iFlags & TFlags.EFlagsIsForcedData ) == TFlags.EFlagsIsForcedData )
                {
                    ret = TSymbolType.EData;
                }
                else if ( ( iFlags & TFlags.EFlagsIsForcedNumber ) == TFlags.EFlagsIsForcedNumber )
                {
                    ret = TSymbolType.ENumber;
                }
                 
                // If still unknown, work it out...
                if ( ret == TSymbolType.EUnknown )
                {
                    // First entries override type
                    if ( ( iFlags & TFlags.EFlagsIsReadonly ) != 0 )
                    {
                        ret = TSymbolType.EReadOnlySymbol;
                    }
                    else if ( ( iFlags & TFlags.EFlagsIsSubObject ) != 0 )
                    {
                        ret = TSymbolType.ESubObject;
                    }
                    else if ( Address >= 0xF8000000 && Address < 0xFFEFFFFF )
                    {
                        // ROM Symbol, Moving Memory Model
                        ret = TSymbolType.EROMSymbol;
                    }
                    else if ( Address >= 0xF4000000 && Address < 0xF7FFFFFF )
                    {
                        // RAM Symbol, Moving Memory Model
                        ret = TSymbolType.ERAMSymbol;
                    }
                    else if ( Address >= 0x64000000 && Address < 0x64FFFFFF )
                    {
                        // Kernel global, Moving Memory Model
                        ret = TSymbolType.EKernelGlobalVariable;
                    }
                    else if ( Address >= 0xc8000000 && Address < 0xC8FFFFFF )
                    {
                        // Kernel global, Multiple Memory Model
                        ret = TSymbolType.EKernelGlobalVariable;
                    }
                    else if ( Address >= 0x80000000 && Address < 0x8FFFFFFF )
                    {
                        // ROM Symbol, Multiple Memory Model
                        ret = TSymbolType.EROMSymbol;
                    }
                    else if ( Address >= 0x3C000000 && Address < 0x3DFFFFFF )
                    {
                        // RAM Symbol, Moving Memory Model [1gb]
                        ret = TSymbolType.ERAMSymbol;
                    }
                    else if ( Address >= 0x70000000 && Address < 0x7FFFFFFF )
                    {
                        // RAM Symbol, Moving Memory Model [2gb]
                        ret = TSymbolType.ERAMSymbol;
                    }
                    else if ( Address < 0x10000000 )
                    {
                        // A non-fixed up ROFS symbol entry
                        ret = TSymbolType.ERAMSymbol;
                    }
                    else if ( ret != TSymbolType.EKernelGlobalVariable )
                    {
                        bool isFunction = IsFunction;
                        if ( isFunction == false )
                        {
                            ret = TSymbolType.ELabel;
                        }
                    }
                }
                //
				return ret;
			}
            set
            {
                iFlags &= ~TFlags.EFlagsIsForcedCode;
                iFlags &= ~TFlags.EFlagsIsForcedData;
                iFlags &= ~TFlags.EFlagsIsForcedNumber;
                iFlags &= ~TFlags.EFlagsIsForcedSection;
                //
                switch ( value )
                {
                case TSymbolType.ESection:
                    iFlags |= TFlags.EFlagsIsForcedSection;
                    break;
                case TSymbolType.ECode:
                    iFlags |= TFlags.EFlagsIsForcedCode;
                    break;
                case TSymbolType.EData:
                    iFlags |= TFlags.EFlagsIsForcedData;
                    break;
                case TSymbolType.ENumber:
                    iFlags |= TFlags.EFlagsIsForcedNumber;
                    break;
                default:
                    throw new ArgumentException( "Specified type cannot be programatically set" );
                }
            }
        }

        public TSymbolSource Source
        {
            get
            {
                TSymbolSource ret = TSymbolSource.ESourceWasUnknown;
                //
                if ( ( iFlags & TFlags.EFlagsIsFromMapFile ) == TFlags.EFlagsIsFromMapFile )
                {
                    ret = TSymbolSource.ESourceWasMapFile;
                }
                else if ( ( iFlags & TFlags.EFlagsIsFromSymbolFile ) == TFlags.EFlagsIsFromSymbolFile )
                {
                    ret = TSymbolSource.ESourceWasSymbolFile;
                }
                //
                return ret;
            }
            set
            {
                iFlags &= ~TFlags.EFlagsIsFromMapFile;
                iFlags &= ~TFlags.EFlagsIsFromSymbolFile;
                //
                switch ( value )
                {
                case TSymbolSource.ESourceWasMapFile:
                    iFlags |= TFlags.EFlagsIsFromMapFile;
                    break;
                case TSymbolSource.ESourceWasSymbolFile:
                    iFlags |= TFlags.EFlagsIsFromSymbolFile;
                    break;
                default:
                case TSymbolSource.ESourceWasUnknown:
                    break;
                }
            }
        }
		#endregion
        
        #region Internal enumerations
        [Flags]
        private enum TFlags : ushort
        {
            EFlagsNone = 0,
            EFlagsIsDefault = 1,
            EFlagsIsVTable = 2,
            EFlagsIsFunction = 4,
            EFlagsIsReadonly = 8,
            EFlagsIsSubObject = 16,
            EFlagsIsForcedCode = 32,
            EFlagsIsForcedData = 64,
            EFlagsIsForcedNumber = 128,
            EFlagsIsForcedSection = 256,
            EFlagsIsFromMapFile = 512,
            EFlagsIsFromSymbolFile = 1024
        };
        #endregion

        #region Internal methods
        private uint BaseAddress
        {
            get
            {
                if ( iCollection != null )
                {
                    return iCollection.BaseAddress;
                }
                //
                return 0;
            }
        }
        #endregion

        #region From System.Object
        public override string ToString()
		{
            string ret = ToString( null, null );
			return ret;
		}

        public string ToStringOffset( uint aFrom )
        {
            uint baseAddressOffset = Offset( aFrom );
            string text = "[+ 0x" + baseAddressOffset.ToString( "x4" ) + "]";
            return text;
        }
	    #endregion

        #region IFormattable Members
        public string ToString( string aFormat, IFormatProvider aFormatProvider )
        {
            string ret = string.Empty;
            //
            if ( string.IsNullOrEmpty( aFormat ) )
            {
                ret = string.Format( "{0:x8}    {1:x4}    {2} [{3}]", Address, Size, Name, Object );
            }
            else
            {
                string format = aFormat.Trim().ToUpper();
                //
                if ( format == "STREAM" )
                {
                    ret = string.Format( "{0:x8}    {1:x4}    {2} [{3}]", Address, Size, Name.PadRight( 40, ' ' ), Object );
                }
                else
                {
                    throw new FormatException( String.Format( "Invalid format string: '{0}'.", aFormat ) );
                }
            }
            //
            return ret;
        }
        #endregion

		#region Data members
        private readonly SymbolCollection iCollection;
        private readonly uint iId; // This saves 8 bytes per instance over using PlatformId directly
        private uint iSize;
		private uint iOffsetAddress;
        private string iObject = null;
        private InternedName iName = null;
        private TFlags iFlags = TFlags.EFlagsNone;
		#endregion
    }
}