--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sysperfana/heapanalyser/Libraries/Engine/HeapLib/Cells/HeapCell.cs Tue Jun 15 12:47:20 2010 +0300
@@ -0,0 +1,940 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*
+* - Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+* - Redistributions in binary form must reproduce the above copyright notice,
+* this list of conditions and the following disclaimer in the documentation
+* and/or other materials provided with the distribution.
+* - Neither the name of Nokia Corporation nor the names of its contributors
+* may be used to endorse or promote products derived from this software
+* without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using SymbianStructuresLib.Debug.Symbols;
+using SymbianUtils.RawItems;
+using SymbianUtils.Utilities;
+using HeapLib.Array;
+using HeapLib.Relationships;
+using HeapLib.Cells.Descriptors;
+
+namespace HeapLib.Cells
+{
+ public class HeapCell : IEnumerable<RawItem>, IEquatable<HeapCell>
+ {
+ #region Enumerations
+ public enum TRegion
+ {
+ EHeader = 0,
+ EPayload,
+ EBeforeCell,
+ EAfterCell
+ }
+
+ public enum TType : byte
+ {
+ EAllocated = 0,
+ EFree
+ }
+
+ public enum TBuildType
+ {
+ ERelease = 0,
+ EDebug = 1
+ }
+
+ public enum TDescriptorType
+ {
+ // These are Symbian's descriptor types
+ EBufC = 0,
+ EPtrC,
+ EPtr,
+ EBuf,
+ EBufCPtr,
+
+ // This are specific to this app
+ ENullTerminatedString,
+ EUnknown,
+ }
+ #endregion
+
+ #region Constructors & destructor
+ public HeapCell()
+ {
+ iRelationshipManager = new RelationshipManager(this);
+ }
+
+ internal HeapCell(HeapCell aCell)
+ : this()
+ {
+ iTag = aCell.Tag;
+ iAddress = aCell.Address;
+ iType = aCell.Type;
+ iFlags = aCell.iFlags;
+ iSymbol[0] = aCell.iSymbol[0];
+ iSymbol[1] = aCell.iSymbol[1];
+ iSymbol[2] = aCell.iSymbol[2];
+ iRawItems = aCell.iRawItems;
+ iDescriptorInfo = aCell.iDescriptorInfo;
+ iHeaderRawItems = aCell.iHeaderRawItems;
+ iLength = aCell.iLength;
+ //
+ iRelationshipManager = aCell.RelationshipManager;
+ iChecksum = new CRC32Checksum(aCell.Checksum);
+ }
+
+ internal HeapCell(uint aAddress, uint aLength, TType aType)
+ : this()
+ {
+ iAddress = aAddress;
+ iType = aType;
+ //
+ iHeaderRawItems.Clear();
+ AddRawItemHeader(new RawItem(aAddress, aLength));
+ }
+ #endregion
+
+ #region Constants
+ public const uint KHeapCellSizeAllocatedUREL = 4; // Just length
+ public const uint KHeapCellSizeAllocatedUDEB = 12; // Length + Allocation Number + Nesting Level
+ public const uint KHeapCellSizeFree = 8; // Length + Pointer to next free cell
+ #endregion
+
+ #region API
+ public void AddRawItem(RawItem aItem)
+ {
+ RawItems.Add(aItem);
+ //
+ byte[] dataArray = aItem.DataArray;
+ iChecksum.Checksum(dataArray);
+ }
+
+ public void AddRawItemHeader(RawItem aItem)
+ {
+ // Not checksummed
+ iHeaderRawItems.Add(aItem);
+ if (iHeaderRawItems.Count == 1)
+ {
+ iLength = iHeaderRawItems[0].Data;
+ }
+ }
+
+ public uint Remainder(uint aAddress)
+ {
+ uint ret = (Address + Length) - aAddress;
+ return ret;
+ }
+
+ public static uint CellHeaderSize(TType aType)
+ {
+ uint ret = AllocatedCellHeaderSize;
+ if (aType == TType.EFree)
+ {
+ ret = FreeCellHeaderSize;
+ }
+ return ret;
+ }
+
+ public static uint AllocatedCellSizeByBuildType(TBuildType aType)
+ {
+ uint size = 0;
+ //
+ switch (aType)
+ {
+ case TBuildType.EDebug:
+ size = KHeapCellSizeAllocatedUDEB;
+ break;
+ case TBuildType.ERelease:
+ size = KHeapCellSizeAllocatedUREL;
+ break;
+ }
+ //
+ return size;
+ }
+
+ public TRegion RegionForAddress(uint aAddress)
+ {
+ uint address = Address;
+ //
+ TRegion ret = TRegion.EBeforeCell;
+ //
+ if (aAddress < address)
+ {
+ ret = TRegion.EBeforeCell;
+ }
+ else
+ {
+ uint endAddress = EndAddress;
+ //
+ if (aAddress > endAddress)
+ {
+ ret = TRegion.EAfterCell;
+ }
+ else
+ {
+ uint startOfPayload = StartOfPayloadAddress;
+ //
+ if (aAddress >= startOfPayload)
+ {
+ ret = TRegion.EPayload;
+ }
+ else
+ {
+ ret = TRegion.EHeader;
+ }
+ }
+ }
+ //
+ return ret;
+ }
+
+ public TRegion RegionForAddress(uint aAddress, out int aRemainingUntilNextBoundary)
+ {
+ TRegion region = RegionForAddress(aAddress);
+ //
+ switch (region)
+ {
+ default:
+ aRemainingUntilNextBoundary = -1;
+ break;
+ case TRegion.EHeader:
+ case TRegion.EPayload:
+ if (region == TRegion.EHeader)
+ {
+ uint startOfPayload = StartOfPayloadAddress;
+ aRemainingUntilNextBoundary = (int)(startOfPayload - aAddress);
+ }
+ else
+ {
+ uint endAddress = EndAddress;
+ aRemainingUntilNextBoundary = (int)(endAddress - aAddress + 1);
+ }
+ break;
+ }
+ //
+ return region;
+ }
+
+ public bool IsIdentical(HeapCell aCell)
+ {
+ bool identical = false;
+ //
+ if (aCell.Length == this.Length &&
+ aCell.PossibleVTableAddress == this.PossibleVTableAddress &&
+ aCell.AllocationNumber == this.AllocationNumber &&
+ aCell.NestingLevel == this.NestingLevel &&
+ aCell.RawItems.Count == this.RawItems.Count)
+ {
+ identical = (aCell.Checksum == this.Checksum);
+ }
+ //
+ return identical;
+ }
+
+ internal void ConstructionComplete(Statistics.HeapStatistics aStats)
+ {
+ if (Type == TType.EAllocated)
+ {
+ iDescriptorInfo = Descriptors.DescriptorAlgorithmManager.DescriptorInfo(this, aStats);
+ }
+ }
+ #endregion
+
+ #region Properties
+ public HeapCell.TType Type
+ {
+ get { return iType; }
+ set { iType = value; }
+ }
+
+ public string TypeString
+ {
+ get
+ {
+ string ret = string.Empty;
+ //
+ switch (Type)
+ {
+ case TType.EAllocated:
+ ret = "Allocated";
+ break;
+ case TType.EFree:
+ ret = "Free";
+ break;
+ }
+ //
+ return ret;
+ }
+ }
+
+ // <summary>
+ // The index is the unique number assigned to each cell as it is
+ // added to the heap data for a given heap. This operation is
+ // performed by the reconstructor during parsing.
+ // </summary>
+ public uint Index
+ {
+ get { return iIndex; }
+ set { iIndex = value; }
+ }
+
+ public uint Address
+ {
+ get { return iAddress; }
+ set { iAddress = value; }
+ }
+
+ public uint StartOfPayloadAddress
+ {
+ get
+ {
+ uint ret = Address;
+ //
+ if (Type == TType.EAllocated)
+ {
+ ret += HeaderSize;
+ }
+ else if (Type == TType.EFree)
+ {
+ ret += KHeapCellSizeFree;
+ }
+ else
+ {
+ System.Diagnostics.Debug.Assert(false);
+ }
+ //
+ return ret;
+ }
+ }
+
+ public uint EndAddress
+ {
+ get { return iAddress + iLength - 1; }
+ }
+
+ public uint Length
+ {
+ // Optimisation: we cache the length when adding the first
+ // header raw item to avoid having to repeatedly access
+ // the raw items array during initial heap preparation.
+ get { return iLength; }
+ }
+
+ public uint NestingLevel
+ {
+ get
+ {
+ // Only applicable to allocated cells in debug builds
+ uint ret = 0;
+ //
+ if (Type == TType.EAllocated && IsDebugAllocator)
+ {
+ System.Diagnostics.Debug.Assert(HeaderRawItems.Count >= 2);
+ RawItem item = HeaderRawItems[1]; // Always 2nd raw item in header
+ ret = item.Data;
+ }
+ //
+ return ret;
+ }
+ }
+
+ public uint AllocationNumber
+ {
+ get
+ {
+ // Only applicable to allocated cells in debug builds
+ uint ret = 0;
+ //
+ if (Type == TType.EAllocated && IsDebugAllocator)
+ {
+ System.Diagnostics.Debug.Assert(HeaderRawItems.Count >= 3);
+ RawItem item = HeaderRawItems[2]; // Always 3rd raw item in header
+ ret = item.Data;
+ }
+ //
+ return ret;
+ }
+ }
+
+ public uint PossibleVTableAddress
+ {
+ get
+ {
+ // This is always the first raw item
+ uint ret = 0;
+ //
+ if (RawItems.Count > 0)
+ {
+ ret = RawItems[0].Data;
+ }
+ //
+ return ret;
+ }
+ }
+
+ public Symbol Symbol
+ {
+ get { return iSymbol[0]; }
+ set { iSymbol[0] = value; }
+ }
+
+ public Symbol Symbol2
+ {
+ get { return iSymbol[1]; }
+ set { iSymbol[1] = value; }
+ }
+
+ public Symbol Symbol3
+ {
+ get { return iSymbol[2]; }
+ set { iSymbol[2] = value; }
+ }
+
+ public string SymbolString
+ {
+ get
+ {
+ return SymbolStringRef(false);
+ }
+ }
+
+ private string SymbolStringRef(bool reference)
+ {
+ StringBuilder ret = new StringBuilder();
+
+ if (Type == TType.EAllocated)
+ {
+ if (Symbol != null)
+ {
+ ret.Append(Symbol.NameWithoutVTablePrefix);
+ }
+ else if (IsDescriptor)
+ {
+ ret.Append("[Descriptor] " + DescriptorTextBeautified);
+ }
+ }
+ else if (Type == TType.EFree)
+ {
+ ret.Append("[Free]");
+ if (Symbol != null)
+ {
+ ret.Append(" ");
+ ret.Append(Symbol.NameWithoutVTablePrefix);
+ }
+ }
+
+ // If no text as yet identified, then return [Unknown], if there is not unique referrer.
+ // If the referrer is unique, or if all referrers are of the same known type,
+ // instead of [Unknown], you can see [Part of XXX], where XXX is the type of the referrer.
+ if (ret.Length == 0)
+ {
+ if (!reference)
+ {
+ if (iRelationshipManager.ReferencedByUnique != null)
+ {
+ string symbolString = iRelationshipManager.ReferencedByUnique.SymbolStringRef(true);
+
+ if (!symbolString.Equals("[Unknown]"))
+ {
+ ret.Append("[Part of ");
+ ret.Append(symbolString);
+ ret.Append("]");
+ }
+ else
+ {
+ ret.Append("[Unknown]");
+ }
+ }
+ else
+ {
+ ret.Append("[Unknown]");
+ }
+ }
+ else
+ {
+ ret.Append("[Unknown]");
+ }
+ }
+ return ret.ToString();
+ }
+
+ public string SymbolStringWithoutDescriptorPrefix
+ {
+ get
+ {
+ string ret = SymbolString;
+ //
+ if (IsDescriptor)
+ {
+ ret = "[" + DescriptorLength.ToString("d4") + "] " + DescriptorTextBeautifiedWithoutLength;
+ }
+ //
+ return ret;
+ }
+ }
+
+ public uint HeaderSize
+ {
+ get
+ {
+ uint size = 0;
+ //
+ switch (Type)
+ {
+ case TType.EAllocated:
+ size = HeapCell.AllocatedCellHeaderSize;
+ break;
+ case TType.EFree:
+ size = KHeapCellSizeFree;
+ break;
+ }
+ //
+ return size;
+ }
+ }
+
+ public uint PayloadLength
+ {
+ get { return (EndAddress - StartOfPayloadAddress) + 1; }
+ }
+
+ public RawItem this[uint aAddress]
+ {
+ get
+ {
+ RawItem ret = null;
+ //
+ TRegion region = RegionForAddress(aAddress);
+ if (region == TRegion.EPayload || region == TRegion.EHeader)
+ {
+ if (region == TRegion.EHeader)
+ {
+ uint offset = aAddress - Address;
+ int index = System.Convert.ToInt32(offset / RawItem.KSizeOfOneRawItemInBytes);
+ //
+ if (index < 0 || index >= HeaderRawItems.Count)
+ {
+ throw new ArgumentException("Address 0x" + aAddress.ToString("x8") + " is beyond this cell's header");
+ }
+ //
+ ret = HeaderRawItems[index];
+ }
+ else
+ {
+ // Payload
+ uint offset = aAddress - StartOfPayloadAddress;
+ int index = System.Convert.ToInt32(offset / RawItem.KSizeOfOneRawItemInBytes);
+ //
+ if (index < 0 || index >= RawItems.Count)
+ {
+ throw new ArgumentException("Address 0x" + aAddress.ToString("x8") + " is beyond this cell's payload");
+ }
+ //
+ ret = this[index];
+ }
+ }
+ else
+ {
+ throw new ArgumentException("Address 0x" + aAddress.ToString("x8") + " is not within this cell's extent");
+ }
+ return ret;
+ }
+ }
+
+ public RawItem this[int aIndex]
+ {
+ get
+ {
+ return iRawItems[aIndex];
+ }
+ }
+
+ public RawItemCollection RawItems
+ {
+ get { return iRawItems; }
+ }
+
+ public RawItemCollection HeaderRawItems
+ {
+ get { return iHeaderRawItems; }
+ }
+
+ public long CombinedLinkedCellPayloadLengths
+ {
+ get
+ {
+ int depth = 0;
+ long ret = DoGetCombinedLinkedCellPayloadLengths(ref depth);
+ return ret;
+ }
+ }
+
+ public long PayloadLengthIncludingLinkedCells
+ {
+ get
+ {
+ long ret = PayloadLength;
+ ret += RelationshipManager.PayloadLengthOfEmbeddedCells;
+ //
+ return ret;
+ }
+ }
+
+ public object Tag
+ {
+ get { return iTag; }
+ set { iTag = value; }
+ }
+
+ public uint Checksum
+ {
+ get { return iChecksum.Value; }
+ }
+
+ public bool IsUnknown
+ {
+ get { return Symbol == null && Type == TType.EAllocated; }
+ }
+ #endregion
+
+ #region Descriptor related functionality
+ public TDescriptorType DescriptorType
+ {
+ get
+ {
+ TDescriptorType ret = TDescriptorType.EUnknown;
+ //
+ if (IsDescriptor && iDescriptorInfo != null)
+ {
+ ret = iDescriptorInfo.Type;
+ }
+ //
+ return ret;
+ }
+ }
+
+ public bool IsDescriptorUnicode
+ {
+ get
+ {
+ bool ret = false;
+ //
+ if (IsDescriptor && iDescriptorInfo != null)
+ {
+ ret = iDescriptorInfo.IsUnicode;
+ }
+ //
+ return ret;
+ }
+ }
+
+ public bool IsDescriptor
+ {
+ get
+ {
+ return (iDescriptorInfo != null);
+ }
+ }
+
+ public int DescriptorLength
+ {
+ get
+ {
+ int length = 0;
+ //
+ if (IsDescriptor && iDescriptorInfo != null)
+ {
+ length = iDescriptorInfo.Length;
+ }
+ //
+ return length;
+ }
+ }
+
+ public string DescriptorText
+ {
+ get
+ {
+ string ret = string.Empty;
+ //
+ if (IsDescriptor && iDescriptorInfo != null)
+ {
+ ret = iDescriptorInfo.Text;
+ }
+ //
+ return ret;
+ }
+ }
+
+ public string DescriptorTextBeautifiedWithoutLength
+ {
+ get
+ {
+ StringBuilder ret = new StringBuilder();
+ //
+ string des = DescriptorText;
+ if (des.Length > KMaxSymbolStringDescriptorLength)
+ {
+ ret.Append(" \"");
+ ret.Append(des.Substring(0, KMaxSymbolStringDescriptorLength));
+ ret.Append("...\"");
+ }
+ else
+ {
+ ret.Append(" \"");
+ ret.Append(des);
+ ret.Append("\"");
+ }
+ //
+ return ret.ToString();
+ }
+ }
+
+ public string DescriptorTextBeautified
+ {
+ get
+ {
+ StringBuilder ret = new StringBuilder();
+ //
+ ret.Append("{");
+ ret.Append(DescriptorLength.ToString("d4"));
+ ret.Append("}");
+ //
+ ret.Append(DescriptorTextBeautifiedWithoutLength);
+ //
+ return ret.ToString();
+ }
+ }
+ #endregion
+
+ #region Static properties
+ public static bool IsDebugAllocator
+ {
+ get
+ {
+ return AllocatedCellHeaderSize == AllocatedCellSizeByBuildType(TBuildType.EDebug);
+ }
+ }
+
+ public static uint FreeCellHeaderSize
+ {
+ get { return KFreeCellHeaderSize; }
+ }
+
+ public static uint AllocatedCellHeaderSize
+ {
+ get { return iAllocatedCellHeaderSize; }
+ set { iAllocatedCellHeaderSize = value; }
+ }
+ #endregion
+
+ #region Relationships
+ public RelationshipManager RelationshipManager
+ {
+ get { return iRelationshipManager; }
+ }
+ #endregion
+
+ #region IEnumerable Members
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return new HeapCellRawItemEnumerator(this);
+ }
+
+ IEnumerator<RawItem> IEnumerable<RawItem>.GetEnumerator()
+ {
+ return new HeapCellRawItemEnumerator(this);
+ }
+ #endregion
+
+ #region IEquatable<HeapCell> Members
+ public bool Equals(HeapCell aOther)
+ {
+ bool ret = (aOther.Address == this.Address);
+ return ret;
+ }
+ #endregion
+
+ #region Operators
+ public static bool operator ==(HeapCell aLeft, HeapCell aRight)
+ {
+ bool ret = false;
+
+ // If both are null, or both are same instance, return true.
+ if (System.Object.ReferenceEquals(aLeft, aRight))
+ {
+ ret = true;
+ }
+ else if (((object)aLeft == null) || ((object)aRight == null))
+ {
+ // If one is null, but not both, return false.
+ ret = false;
+ }
+ else
+ {
+ // Return true if the fields match:
+ ret = (aLeft.Address == aRight.Address);
+ }
+ //
+ return ret;
+ }
+
+ public static bool operator !=(HeapCell aLeft, HeapCell aRight)
+ {
+ return !(aLeft == aRight);
+ }
+ #endregion
+
+ #region From System.Object
+ public override int GetHashCode()
+ {
+ return Address.GetHashCode();
+ }
+
+ public override bool Equals(object aObject)
+ {
+ bool ret = false;
+ //
+ if (aObject is HeapCell)
+ {
+ HeapCell otherCell = (HeapCell)aObject;
+ ret = Equals(otherCell);
+ }
+ //
+ return ret;
+ }
+
+ public override string ToString()
+ {
+ string ret = "[0x" + Address.ToString("x8") + " " + TypeString + "]";
+ return ret;
+ }
+
+ public string ToStringExtended()
+ {
+ StringBuilder ret = new StringBuilder();
+
+ // Type
+ if (Type == HeapCell.TType.EAllocated)
+ {
+ if (IsDescriptor)
+ {
+ ret.Append("[D]");
+ }
+ else
+ {
+ ret.Append("[A]");
+ }
+ }
+ else
+ {
+ ret.Append("[F]");
+ }
+
+ // Address
+ ret.Append(" 0x" + Address.ToString("x8"));
+
+ // Symbol (if present)
+ if (Symbol != null)
+ {
+ ret.Append(" - " + SymbolString);
+ }
+ else if (IsDescriptor)
+ {
+ ret.Append(" - " + DescriptorTextBeautified);
+ }
+
+ return ret.ToString();
+ }
+ #endregion
+
+ #region Internal flags
+ [Flags]
+ private enum TFlags
+ {
+ EFlagsNone = 0,
+ EFlagsInCombiningCheck = 1
+ }
+ #endregion
+
+ #region Internal constants
+ private const int KMaxRecursiveLinkedCellDepth = 5; // levels
+ private const int KMaxSymbolStringDescriptorLength = 128;
+ private const int KFreeCellHeaderSize = 8; // always
+ #endregion
+
+ #region Internal methods
+ private long DoGetCombinedLinkedCellPayloadLengths(ref int aDepth)
+ {
+ long ret = PayloadLength;
+ //
+ if (aDepth <= KMaxRecursiveLinkedCellDepth)
+ {
+ iFlags |= TFlags.EFlagsInCombiningCheck;
+ //
+ foreach (RelationshipInfo relInfo in RelationshipManager.EmbeddedReferencesTo)
+ {
+ HeapCell linkedCell = relInfo.ToCell;
+ bool isInLinkCheck = ((linkedCell.iFlags & TFlags.EFlagsInCombiningCheck) == TFlags.EFlagsInCombiningCheck);
+ if (isInLinkCheck == false)
+ {
+ ++aDepth;
+ ret += linkedCell.DoGetCombinedLinkedCellPayloadLengths(ref aDepth);
+ }
+ else
+ {
+ }
+ }
+ //
+ iFlags &= ~TFlags.EFlagsInCombiningCheck;
+ }
+ //
+ return ret;
+ }
+ #endregion
+
+ #region Data members
+ private static uint iAllocatedCellHeaderSize = 0;
+ private object iTag;
+ private uint iIndex;
+ private uint iAddress;
+ private uint iLength;
+ private TType iType = TType.EAllocated;
+ private TFlags iFlags = TFlags.EFlagsNone;
+ private Symbol[] iSymbol = new Symbol[3] { null, null, null };
+ private CRC32Checksum iChecksum = new CRC32Checksum();
+ private DescriptorInfo iDescriptorInfo = null;
+ private RawItemCollection iRawItems = new RawItemCollection();
+ private RawItemCollection iHeaderRawItems = new RawItemCollection();
+ private readonly RelationshipManager iRelationshipManager;
+ #endregion
+ }
+}
\ No newline at end of file