crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStructuresLib/Debug/Symbols/Utilities/SymbolCollectionHarmoniser.cs
changeset 0 818e61de6cd1
equal deleted inserted replaced
-1:000000000000 0:818e61de6cd1
       
     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.Collections.Generic;
       
    19 using System.Text;
       
    20 using SymbianUtils;
       
    21 using SymbianStructuresLib.MemoryModel;
       
    22 
       
    23 namespace SymbianStructuresLib.Debug.Symbols.Utilities
       
    24 {
       
    25     public class SymbolCollectionHarmoniser : DisposableObject
       
    26     {
       
    27         #region Enumerations
       
    28         public enum TCollectionType
       
    29         {
       
    30             EXIP = 0,
       
    31             ENotXIP,
       
    32             EPossiblyXIP
       
    33         }
       
    34         #endregion
       
    35 
       
    36         #region Constructors
       
    37         public SymbolCollectionHarmoniser( SymbolCollection aCollection )
       
    38             : this( aCollection, TCollectionType.ENotXIP )
       
    39         {
       
    40         }
       
    41         
       
    42         public SymbolCollectionHarmoniser( SymbolCollection aCollection, TCollectionType aType )
       
    43         {
       
    44             iCollection = aCollection;
       
    45             iType = aType;
       
    46 
       
    47             // If the collection is not XIP, then we can definitely say it is relocatable
       
    48             if ( aType == TCollectionType.ENotXIP )
       
    49             {
       
    50                 iCollection.IsFixed = false;
       
    51             }
       
    52             else if ( aType == TCollectionType.EXIP )
       
    53             {
       
    54                 iCollection.IsFixed = true;
       
    55             }
       
    56         }
       
    57         #endregion
       
    58 
       
    59         #region API
       
    60         public bool Add( Symbol aSymbol )
       
    61         {
       
    62             Debug( aSymbol );
       
    63 
       
    64             // Perform pre-filter, which might currently include a blanket ban
       
    65             // on new symbols for this collection
       
    66             bool save = PreFilterBasedUponFlags( aSymbol );
       
    67             if ( save )
       
    68             {
       
    69                 // Flags indicate we can accept the symbol, so perform
       
    70                 // normal checks based upon symbol meta-data
       
    71                 Symbol last = this.LastSymbol;
       
    72                 if ( last != null && !last.IsDefault )
       
    73                 {
       
    74                     if ( aSymbol.Size == 0 )
       
    75                     {
       
    76                         save = ShouldSaveWhenNewSymbolHasNoSize( last, aSymbol );
       
    77                     }
       
    78                     else
       
    79                     {
       
    80                         save = ShouldSaveWhenNewSymbolHasValidSize( last, aSymbol );
       
    81                     }
       
    82                 }
       
    83                 //
       
    84                 if ( save )
       
    85                 {
       
    86                     Collection.Add( aSymbol );
       
    87                 }
       
    88             }
       
    89 
       
    90             // Perform any final updates
       
    91             PostFilterBasedUponFlags( aSymbol );
       
    92             //
       
    93             return save;
       
    94         }
       
    95         #endregion
       
    96 
       
    97         #region Properties
       
    98         public bool DisallowSymbolsOnceReadOnlyLimitReached
       
    99         {
       
   100             get 
       
   101             {
       
   102                 bool disallow = false;
       
   103 
       
   104                 // We can only do this once we have one non-default symbol and after
       
   105                 // we have set the base address.
       
   106                 if ( ( iFlags & TFlags.EFlagsHaveSetXIPBaseAddress ) == TFlags.EFlagsHaveSetXIPBaseAddress )
       
   107                 {
       
   108                     bool isEmpty = Collection.IsEmptyApartFromDefaultSymbol;
       
   109                     if ( !isEmpty )
       
   110                     {
       
   111                         Symbol first = Collection.FirstSymbol;
       
   112                         disallow = ( first.Address == 0 );
       
   113                     }
       
   114                 }
       
   115                 //
       
   116                 return disallow; 
       
   117             }
       
   118         }
       
   119         #endregion
       
   120 
       
   121         #region Internal enumerations
       
   122         [Flags]
       
   123         private enum TFlags
       
   124         {
       
   125             EFlagsNone = 0,
       
   126             EFlagsUpdateLengthOfPreviousSymbol = 1,
       
   127             EFlagsDisallowFurtherSymbolsForCollection = 2,
       
   128             EFlagsHaveSetXIPBaseAddress = 4,
       
   129         }
       
   130         #endregion
       
   131 
       
   132         #region Internal constants
       
   133         private const uint KMaxAutomaticLengthUpdateDelta = 4 * 1024 * 1024;
       
   134         private const string KSectionNameMarker = "$$";
       
   135         private const string KSectionNameUserBase = "Image$$ER_RO$$Base";
       
   136         private const string KSectionNameUserLimit = "Image$$ER_RO$$Limit";
       
   137         #endregion
       
   138 
       
   139         #region Internal properties
       
   140         private SymbolCollection Collection
       
   141         {
       
   142             get { return iCollection; }
       
   143         }
       
   144 
       
   145         private Symbol LastSymbol
       
   146         {
       
   147             get
       
   148             {
       
   149                 Symbol ret = null;
       
   150                 //
       
   151                 if ( Collection.Count > 0 )
       
   152                 {
       
   153                     ret = Collection.LastSymbol;
       
   154                 }
       
   155                 //
       
   156                 return ret;
       
   157             }
       
   158         }
       
   159         #endregion
       
   160 
       
   161         #region Internal methods
       
   162         private void Debug( Symbol aSymbol )
       
   163         {
       
   164         }
       
   165 
       
   166         private bool PreFilterBasedUponFlags( Symbol aSymbol )
       
   167         {
       
   168             // Do we need to update the length of the previous symbol?
       
   169             if ( ( iFlags & TFlags.EFlagsUpdateLengthOfPreviousSymbol ) == TFlags.EFlagsUpdateLengthOfPreviousSymbol )
       
   170             {
       
   171                 FlagBasedUpdateOfLastSymbolLength( aSymbol );
       
   172             }
       
   173 
       
   174             // Check for Image$$ER_RO$$Base
       
   175             // This symbol is emitted for user-side code and can be used to work around some maksym problems.
       
   176             string symbolName = aSymbol.Name;
       
   177             if ( symbolName == KSectionNameUserBase )
       
   178             {
       
   179                 int count = iCollection.Count;
       
   180                 if ( !iCollection.IsEmptyApartFromDefaultSymbol )
       
   181                 {
       
   182                     // Discard all the entries we've seen so far because most likely
       
   183                     // they are invalid.
       
   184                     System.Diagnostics.Debug.WriteLine( string.Format( "Discarding {0} invalid symbols for library: {1}", count, iCollection.FileName ) );
       
   185                     iCollection.Clear();
       
   186 
       
   187                     // At this point, we need to reset the base address because any symbols that have gone 
       
   188                     // before are invalid.
       
   189                     iFlags &= ~TFlags.EFlagsHaveSetXIPBaseAddress;
       
   190                 }
       
   191             }
       
   192 
       
   193             // Do we need to set the base address for the symbol collection?
       
   194             bool haveSetXIPBase = ( ( iFlags & TFlags.EFlagsHaveSetXIPBaseAddress ) == TFlags.EFlagsHaveSetXIPBaseAddress );
       
   195             if ( !haveSetXIPBase && iType != TCollectionType.ENotXIP )
       
   196             {
       
   197                 // If we're seeing the first valid symbol, then try to set the base address
       
   198                 bool needToSet = true;
       
   199                 if ( iType == TCollectionType.EPossiblyXIP )
       
   200                 {
       
   201                     // Perhaps we're dealing with an XIP collection. In which case, we need to check
       
   202                     // with the memory model utility to decide if it really is or not.
       
   203                     //
       
   204                     // If the symbol address is zero (NULL), then we can't be dealing with an
       
   205                     // XIP collection.
       
   206                     if ( aSymbol.Address == 0 )
       
   207                     {
       
   208                         // ROFS
       
   209                         needToSet = true;
       
   210                     }
       
   211                     else
       
   212                     {
       
   213                         TMemoryModelRegion region = MMUtilities.RegionByAddress( aSymbol.Address );
       
   214                         needToSet = ( region == TMemoryModelRegion.EMemoryModelRegionROM );
       
   215                     }
       
   216                 }
       
   217 
       
   218                 if ( needToSet )
       
   219                 {
       
   220                     SetCollectionBaseAddress( aSymbol );
       
   221                 }
       
   222             }
       
   223 
       
   224             bool disallowNewSymbols = ( iFlags & TFlags.EFlagsDisallowFurtherSymbolsForCollection ) == TFlags.EFlagsDisallowFurtherSymbolsForCollection;
       
   225             return !disallowNewSymbols;
       
   226         }
       
   227 
       
   228         private void PostFilterBasedUponFlags( Symbol aSymbol )
       
   229         {
       
   230             string symbolName = aSymbol.Name;
       
   231             if ( symbolName.Contains( KSectionNameMarker ) )
       
   232             {
       
   233                 if ( symbolName == KSectionNameUserLimit )
       
   234                 {
       
   235                     // User data follows - don't update length of previous symbol
       
   236                     iFlags &= ~TFlags.EFlagsUpdateLengthOfPreviousSymbol;
       
   237 
       
   238                     // If we're reading a ROFS symbol then most likely we don't want
       
   239                     // to allow any more entries since they start to be a little wacky...
       
   240                     bool disallow = this.DisallowSymbolsOnceReadOnlyLimitReached;
       
   241                     if ( disallow )
       
   242                     {
       
   243                         iFlags |= TFlags.EFlagsDisallowFurtherSymbolsForCollection;
       
   244                     }
       
   245                 }
       
   246                 else if ( symbolName.Contains( "$$Limit" ) )
       
   247                 {
       
   248                     // Don't change the length of a limit symbol should we happen to encounter a data item.
       
   249                     iFlags &= ~TFlags.EFlagsUpdateLengthOfPreviousSymbol;
       
   250                 }
       
   251             }
       
   252         }
       
   253 
       
   254         /// <summary>
       
   255         /// Called when the new proposed symbol has no size.
       
   256         /// </summary>
       
   257         private bool ShouldSaveWhenNewSymbolHasNoSize( Symbol aLastSymbol, Symbol aNewSymbol )
       
   258         {
       
   259             bool save = true;
       
   260             //
       
   261             if ( aLastSymbol.Contains( aNewSymbol.Address ) )
       
   262             {
       
   263                 // The new symbol overlaps the previous one. Additionally, the new symbol has a size of zero.
       
   264                 //
       
   265                 // E.g. #1:
       
   266                 //
       
   267                 //  _E32Dll                                         0x00008000   ARM Code      40  uc_dll_.o(.emb_text)
       
   268                 //  Symbian$$CPP$$Exception$$Descriptor             0x00008014   Data           0  uc_dll_.o(.emb_text)
       
   269                 //
       
   270                 // E.g. #2:
       
   271                 //
       
   272                 //  RArray<unsigned long>::RArray()                 0x00009289   Thumb Code    10  abcd.in(t._ZN6RArrayImEC1Ev)
       
   273                 //  RArray<unsigned long>::RArray__sub_object()     0x00009289   Thumb Code     0  abcd.in(t._ZN6RArrayImEC1Ev)
       
   274                 //
       
   275                 //      => NEW SYMBOL IS DISCARDED
       
   276                 //
       
   277                 save = false;
       
   278             }
       
   279             else if ( aNewSymbol.Address > aLastSymbol.EndAddress )
       
   280             {
       
   281                 // The new symbol has a size of zero, but it doesn't overlap with prior symbol address.
       
   282                 //
       
   283                 //             _E32Dll_Body                             0x00008ecd   Thumb Code    34  uc_dll.o(.text)
       
   284                 //             __DLL_Export_Table__                     0x00008f5c   ARM Code       0  abcd{000a0000}.exp(ExportTable)
       
   285                 //             DLL##ExportTableSize                     0x00008f60   Data           0  abcd{000a0000}.exp(ExportTable)
       
   286                 //             DLL##ExportTable                         0x00008f64   Data           0  abcd{000a0000}.exp(ExportTable)
       
   287                 //             CActive::Cancel()                        0x00008f9c   ARM Code       0  euser{000a0000}-1088.o(StubCode)
       
   288                 // aSymbol ==> CActive::SetActive()                     0x00008fa4   ARM Code       0  euser{000a0000}-1090.o(StubCode)
       
   289                 //             CActive::CActive__sub_object(int)        0x00008fac   ARM Code       0  euser{000a0000}-1091.o(StubCode)
       
   290                 //             CActive::~CActive__sub_object()          0x00008fb4   ARM Code       0  euser{000a0000}-1094.o(StubCode)
       
   291                 //             RArrayBase::At(int) const                0x00008fbc   ARM Code       0  euser{000a0000}-1507.o(StubCode)
       
   292                 //
       
   293                 //      => NEW SYMBOL IS SAVED
       
   294                 //
       
   295                 iFlags |= TFlags.EFlagsUpdateLengthOfPreviousSymbol;
       
   296             }
       
   297             //
       
   298             return save;
       
   299         }
       
   300 
       
   301         /// <summary>
       
   302         /// Called when the new symbol has a valid size
       
   303         /// </summary>
       
   304         private bool ShouldSaveWhenNewSymbolHasValidSize( Symbol aLastSymbol, Symbol aNewSymbol )
       
   305         {
       
   306             bool save = true;
       
   307 
       
   308             if ( aLastSymbol.Contains( aNewSymbol.Address ) )
       
   309             {
       
   310                 // The new symbol and the last symbol somehow overlap.
       
   311                 if ( aLastSymbol.Address == aNewSymbol.Address && aLastSymbol.Size == aNewSymbol.Size )
       
   312                 {
       
   313                     // The symbols start at the same address:
       
   314                     //
       
   315                     // E.g. #1:
       
   316                     //
       
   317                     //      CABCMonitor::~CABCMonitor()              0x000091a5   Thumb Code     0  abcmonitor.in(i._ZN11CABCMonitorD2Ev)
       
   318                     //      CABCMonitor::~CABCMonitor__sub_object()  0x000091a5   Thumb Code     8  abcmonitor.in(i._ZN11CABCMonitorD2Ev)
       
   319                     //
       
   320                     // E.g. #2: 
       
   321                     //
       
   322                     //      8022ab10    0060    Math::DivMod64(long long, long long, long long&)  
       
   323                     //      8022ab70    0014    Math::UDivMod64(unsigned long long, unsigned long long, unsigned long long&)
       
   324                     //      8022ab84    0000    $v0                                      
       
   325                     // >>>  8022ab84    0018    TRealX::Set(int)                         
       
   326                     //      8022ab9c    0044    TRealX::operator =(int)                  
       
   327                     //
       
   328                     // For example #1, we want to discard the new symbol and keep the original.
       
   329                     // For example #2, we want to discard the original symbol and keep the new one.
       
   330                     //
       
   331                     //
       
   332                     if ( !aLastSymbol.IsFunction )
       
   333                     {
       
   334                         // E.g. #2 => discard old symbol
       
   335                         Collection.RemoveAt( Collection.Count - 1 );
       
   336                     }
       
   337                     else
       
   338                     {
       
   339                         // E.g. #1 => discard new symbol
       
   340                         save = false;
       
   341                     }
       
   342                 }
       
   343                 else if ( aLastSymbol.Address == aNewSymbol.Address && aLastSymbol.Size == 0 )
       
   344                 {
       
   345                     // E.g. : 
       
   346                     //
       
   347                     //      8342d6b8    0000    Image$$ER_RO$$Base                       anon$$obj.o(linker$$defined$$symbols)
       
   348                     // >>>  8342d6b8    0070    _E32Startup                              uc_exe_.o(.emb_text)
       
   349                     //
       
   350                     Collection.RemoveAt( Collection.Count - 1 );
       
   351                 }
       
   352                 else
       
   353                 {
       
   354                     // The symbols start at different addresses, but somehow they still overlap.
       
   355                     //
       
   356                     // E.g.:
       
   357                     //
       
   358                     //    typeinfo name for CABCMonitorCapMapper   0x000094a8   Data          23  accmonitor.in(.constdata__ZTS20CABCMonitorCapMapper)
       
   359                     //    typeinfo name for CABCMonitorContainer   0x000094bf   Data          23  accmonitor.in(.constdata__ZTS20CABCMonitorContainer)
       
   360                     //
       
   361                     // In this scenario, the size of the 0x94a8 entry (23 bytes) causes it's address to overlap
       
   362                     // with the first byte from the entry starting at 0x94bf.
       
   363                     //
       
   364                     // In this scenario, we make an assumption that the size of the 0x94A8 entry is incorrect/invalid
       
   365                     uint overlap = aLastSymbol.AddressRange.Max - aNewSymbol.Address + 1;
       
   366                     aLastSymbol.Size = aLastSymbol.Size - overlap;
       
   367                 }
       
   368             }
       
   369             else
       
   370             {
       
   371                 if ( aLastSymbol.Address > aNewSymbol.Address )
       
   372                 {
       
   373 
       
   374                 }
       
   375             }
       
   376             //
       
   377             return save;
       
   378         }
       
   379 
       
   380         private void FlagBasedUpdateOfLastSymbolLength( Symbol aSymbol )
       
   381         {
       
   382             System.Diagnostics.Debug.Assert( ( iFlags & TFlags.EFlagsUpdateLengthOfPreviousSymbol ) == TFlags.EFlagsUpdateLengthOfPreviousSymbol );
       
   383             bool clearFlag = true;
       
   384 
       
   385             // Don't set the length of the default symbol!
       
   386             if ( !Collection.IsEmptyApartFromDefaultSymbol )
       
   387             {
       
   388                 // Must have some existing symbol.
       
   389                 int count = Collection.Count;
       
   390                 System.Diagnostics.Debug.Assert( count > 0 );
       
   391 
       
   392                 // Last symbol must have bad size?
       
   393                 Symbol previousSymbol = LastSymbol;
       
   394                 System.Diagnostics.Debug.Assert( previousSymbol.Size == 0 );
       
   395 
       
   396                 // The new symbol must be exactly the same address as the last symbol
       
   397                 // (in which case, the new symbol must have a valid size or else we're
       
   398                 // unable to do anything sensible with it) 
       
   399                 //
       
   400                 // OR
       
   401                 //
       
   402                 // The new symbol must be after the last symbol. It cannot be before.
       
   403                 if ( aSymbol.Address < previousSymbol.Address )
       
   404                 {
       
   405                     // Data can confuse us, so skip when the address is earlier. E.g.:
       
   406                     //
       
   407                     //    83409b88    0000    .ARM.exidx$$Base                          uc_exe_.o(.ARM.exidx)
       
   408                     //    83409f80    0000    .ARM.exidx$$Limit                         xxx.in(.ARM.exidx)
       
   409                     //    83409f80    0000    Image$$ER_RO$$Limit                       anon$$obj.o(linker$$defined$$symbols)
       
   410                     // >> 00400000    0008    AllCapabilities                           xxx.in(.data)
       
   411                     //    00400008    0008    DisabledCapabilities                      xxx.in(.data)
       
   412                     //
       
   413                     clearFlag = true;
       
   414                 }
       
   415                 else
       
   416                 {
       
   417                     if ( aSymbol.Address == previousSymbol.Address )
       
   418                     {
       
   419                         if ( aSymbol.Size > 0 )
       
   420                         {
       
   421                             // Okay, the new symbol has a valid size, the old one didn't.
       
   422                             previousSymbol.Size = aSymbol.Size;
       
   423                         }
       
   424                         else
       
   425                         {
       
   426                             // Hmm, neither the last or new symbol have a valid size.
       
   427                             // Nothing we can do in this case...
       
   428                             clearFlag = false;
       
   429                         }
       
   430                     }
       
   431                     else
       
   432                     {
       
   433                         // Need to work out the length of the previous symbol by comparing the
       
   434                         // address of this symbol against it.
       
   435                         uint delta = aSymbol.Address - previousSymbol.Address;
       
   436 
       
   437                         if ( delta > KMaxAutomaticLengthUpdateDelta )
       
   438                         {
       
   439                             // The delta is huge. Don't allow this kind of update.
       
   440                         }
       
   441                         else if ( delta > 1 )
       
   442                         {
       
   443                             // It's okay, this symbol had a later address than the last one
       
   444                             // This is normal.
       
   445                             previousSymbol.Size = delta - 1;
       
   446                         }
       
   447                         else
       
   448                         {
       
   449                             // This is not good. Two symbols both have the same address. In this
       
   450                             // situation discard the old symbol and take the new one instead because
       
   451                             // in all aspects other than name, they are identical.
       
   452                             Collection.RemoveAt( count - 1 );
       
   453                         }
       
   454                     }
       
   455                 }
       
   456             }
       
   457 
       
   458             if ( clearFlag )
       
   459             {
       
   460                 iFlags &= ~TFlags.EFlagsUpdateLengthOfPreviousSymbol;
       
   461             }
       
   462         }
       
   463 
       
   464         private void SetCollectionBaseAddress( Symbol aSymbolToUse )
       
   465         {
       
   466             uint baseAddress = aSymbolToUse.Address;
       
   467             bool haveSet = ( iFlags & TFlags.EFlagsHaveSetXIPBaseAddress ) == TFlags.EFlagsHaveSetXIPBaseAddress;
       
   468             System.Diagnostics.Debug.Assert( haveSet == false );
       
   469 
       
   470             // Relocate (changes base address)
       
   471             iCollection.Relocate( baseAddress );
       
   472             iFlags |= TFlags.EFlagsHaveSetXIPBaseAddress;
       
   473 
       
   474             // The symbol address needs to be reset to zero (i.e. start of collection)
       
   475             uint symbolSize = aSymbolToUse.Size;
       
   476             aSymbolToUse.OffsetAddress = 0;
       
   477         }
       
   478         #endregion
       
   479 
       
   480         #region From DisposableObject
       
   481         protected override void CleanupManagedResources()
       
   482         {
       
   483             try
       
   484             {
       
   485                 base.CleanupManagedResources();
       
   486             }
       
   487             finally
       
   488             {
       
   489                 // When we aren't sure if we're being used to harmonise an XIP collection
       
   490                 // we must check whether the base address has been set to something other than
       
   491                 // zero and that the address is in the XIP range.
       
   492                 // NB: Other cases are handled in the constructor.
       
   493                 if ( iType == TCollectionType.EPossiblyXIP )
       
   494                 {
       
   495                     if ( !iCollection.IsEmptyApartFromDefaultSymbol )
       
   496                     {
       
   497                         Symbol first = iCollection.FirstSymbol;
       
   498                         uint address = first.Address;
       
   499                         if ( address > 0 )
       
   500                         {
       
   501                             TMemoryModelRegion region = MMUtilities.RegionByAddress( address );
       
   502                             bool isFixed = ( region == TMemoryModelRegion.EMemoryModelRegionROM );
       
   503                             iCollection.IsFixed = isFixed;
       
   504                         }
       
   505                         else
       
   506                         {
       
   507                             // First address is zero, indicates RAM-loaded code and therefore
       
   508                             // non-XIP.
       
   509                             iCollection.IsFixed = false;
       
   510                         }
       
   511                     }
       
   512                     else
       
   513                     {
       
   514                         // The collection only contains the default symbol so in that case
       
   515                         // it can be thought to be relocatable (although in practise that wouldn't
       
   516                         // be very helpful). The main point is that we don't want this collection
       
   517                         // to start matching null addresses (quite common when performing symbolic
       
   518                         // lookup).
       
   519                         iCollection.IsFixed = false;
       
   520                     }
       
   521                 }
       
   522             }
       
   523         }
       
   524         #endregion
       
   525 
       
   526         #region Data members
       
   527         private readonly SymbolCollection iCollection;
       
   528         private readonly TCollectionType iType;
       
   529         private TFlags iFlags = TFlags.EFlagsNone;
       
   530         #endregion
       
   531     }
       
   532 }