crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbolLib/Sources/Symbol/File/SymbolsForBinary.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.IO;
       
    19 using System.Collections;
       
    20 using System.Collections.Generic;
       
    21 using SymbianUtils;
       
    22 using SymbianUtils.Range;
       
    23 using SymbolLib.Generics;
       
    24 using SymbolLib.Sources.Symbol.Symbol;
       
    25 
       
    26 namespace SymbolLib.Sources.Symbol.File
       
    27 {
       
    28     public class SymbolsForBinary : GenericSymbolCollection
       
    29 	{
       
    30 		#region Construct & destruct
       
    31         public SymbolsForBinary( string aHostFileName )
       
    32             : base( aHostFileName )
       
    33 		{
       
    34             // Add default unknown entry
       
    35             SymbolSymbol nullEntry = SymbolSymbol.NewUnknown( this );
       
    36             iEntries.Add( nullEntry );
       
    37 		}
       
    38 		#endregion
       
    39 
       
    40         #region Properties
       
    41         internal GenericSymbol InternalLastSymbol
       
    42         {
       
    43             get
       
    44             {
       
    45                 // We don't want to return the last symbol
       
    46                 GenericSymbol ret = base.LastSymbol;
       
    47                 //
       
    48                 if ( ret != null && ret.IsUnknownSymbol )
       
    49                 {
       
    50                     ret = null;
       
    51                 }
       
    52                 //
       
    53                 return ret;
       
    54             }
       
    55         }
       
    56         #endregion
       
    57 
       
    58         #region API
       
    59         internal void Add( GenericSymbolEngine aEngine, GenericSymbol aSymbol, bool aAllowNonRomSymbols )
       
    60         {
       
    61             System.Diagnostics.Debug.Assert( aSymbol is SymbolSymbol );
       
    62  
       
    63             // Check for Image$$ER_RO$$Base or Image$$ER_RO$$Limit. 
       
    64             // This symbol is emitted for user-side code and can be used to work around some maksym problems.
       
    65             string symbolName = aSymbol.Symbol;
       
    66             if ( symbolName.StartsWith( KSymbolNameImageBaseOrLimitPrefix ) )
       
    67             {
       
    68                 bool isBase = symbolName.Contains( "Base" );
       
    69 
       
    70                 // If we've just seen the base entry, but we already have some stored symbols, then
       
    71                 // probably this is a maksym problem that we must try to work around.
       
    72                 if ( isBase )
       
    73                 {
       
    74                     int count = iEntries.Count;
       
    75                     if ( count > 0 && !iEntries[ 0 ].IsUnknownSymbol )
       
    76                     {
       
    77                         // Discard all the entries we've seen so far because most likely
       
    78                         // they are invalid.
       
    79                         System.Diagnostics.Debug.WriteLine( string.Format( "Discarding {0} invalid symbols for library: {1}", count, base.HostBinaryFileName ) );
       
    80                         iEntries.Clear();
       
    81 
       
    82                         // At this point, we need to reset the base address because any symbols that have gone 
       
    83                         // before are invalid.
       
    84                         iFlags &= ~TFlags.EFlagsHaveSeenFirstSymbol;
       
    85                     }
       
    86                 }
       
    87                 else
       
    88                 {
       
    89                     // Reached the limit - stop storing symbols at this point as everything else is likely data.
       
    90                     iFlags |= TFlags.EFlagsDisallowFurtherSymbolsForCollection;
       
    91                 }
       
    92             }
       
    93 
       
    94             // Don't save the entry if we're in disabled state.
       
    95             bool newAdditionsDisabled = ( iFlags & TFlags.EFlagsDisallowFurtherSymbolsForCollection ) == TFlags.EFlagsDisallowFurtherSymbolsForCollection;
       
    96             if ( !newAdditionsDisabled )
       
    97             {
       
    98                 // Whether or not we keep the entry
       
    99                 bool addEntry = false;
       
   100 
       
   101                 // Set base address
       
   102                 UpdateCollectionBaseAddressBasedUponFirstSymbol( aSymbol );
       
   103 
       
   104                 GenericSymbol lastSymbol = InternalLastSymbol;
       
   105                 if ( lastSymbol != null )
       
   106                 {
       
   107                     if ( lastSymbol.Address > aSymbol.Address )
       
   108                     {
       
   109                         // Work-around for maksym problem where it fails to parse some MAP files correctly.
       
   110                     }
       
   111                     else
       
   112                     {
       
   113                         // If we have a last symbol, and it's address is prior to that of the new symbol, we can
       
   114                         // try to update the last symbol's size (if it needs it updating - the method will check that).
       
   115                         UpdateLengthOfPreviousSymbol( aSymbol );
       
   116   
       
   117                         // Check to see if we already have a symbol within this address range
       
   118                         bool overlappingSymbol = LastSymbolSharesSameAddressRange( aSymbol );
       
   119                         if ( overlappingSymbol )
       
   120                         {
       
   121                             // They overlap - which one do we keep? 
       
   122                             addEntry = FilterOutCommonAddressEntry( lastSymbol, aSymbol );
       
   123                         }
       
   124                         else
       
   125                         {
       
   126                             addEntry = TakeEntry( aSymbol, aAllowNonRomSymbols );
       
   127                         }
       
   128                     }
       
   129                 }
       
   130                 else
       
   131                 {
       
   132                     addEntry = TakeEntry( aSymbol, aAllowNonRomSymbols );
       
   133                 }
       
   134 
       
   135                 // If we need to keep the symbol, then save it now...
       
   136                 if ( addEntry )
       
   137                 {
       
   138                     DoAddEntry( aSymbol );
       
   139                 }
       
   140             }
       
   141         }
       
   142 
       
   143         internal void Fixup( long aNewBaseAddress )
       
   144         {
       
   145             BaseAddress = aNewBaseAddress;
       
   146             if ( aNewBaseAddress != 0 )
       
   147             {
       
   148                 iFlags |= TFlags.EFlagsHaveDoneFixup;
       
   149             }
       
   150 
       
   151             base.RebuildAddressRange();
       
   152         }
       
   153         #endregion
       
   154 
       
   155         #region From GenericSymbolCollection
       
   156         public override void WriteToStream( StreamWriter aWriter )
       
   157         {
       
   158             if ( ( iFlags & TFlags.EFlagsHaveDoneFixup ) == TFlags.EFlagsHaveDoneFixup )
       
   159             {
       
   160                 long originalBaseAddress = BaseAddress;
       
   161                 try
       
   162                 {
       
   163                     // For fixed up symbol collections, i.e. those with a base address of zero
       
   164                     // that have subsequently been fixed up at runtime (rofs) then we
       
   165                     // must ensure we write base addresses of zero again when externalising
       
   166                     // the symbol data.
       
   167                     BaseAddress = 0;
       
   168                     base.WriteToStream( aWriter );
       
   169                 }
       
   170                 finally
       
   171                 {
       
   172                     BaseAddress = originalBaseAddress;
       
   173                 }
       
   174             }
       
   175             else
       
   176             {
       
   177                 base.WriteToStream( aWriter );
       
   178             }
       
   179         }
       
   180 
       
   181         public override void Add( GenericSymbolEngine aEngine, GenericSymbol aSymbol )
       
   182         {
       
   183             Add( aEngine, aSymbol, true );
       
   184         }
       
   185 
       
   186 		public override void Remove( GenericSymbol aSymbol )
       
   187 		{
       
   188 			iEntries.Remove( aSymbol );
       
   189 		}
       
   190 
       
   191 		public override void RemoveAt( int aIndex )
       
   192 		{
       
   193 			iEntries.RemoveAt( aIndex );
       
   194 		}
       
   195 
       
   196         public override int Count
       
   197         {
       
   198             get
       
   199             {
       
   200                 return iEntries.Count;
       
   201             }
       
   202         }
       
   203 
       
   204         public override void Sort()
       
   205         {
       
   206             iEntries.Sort( new GenericSymbolComparer() );
       
   207 #if PROFILING
       
   208             System.DateTime startTime = DateTime.Now;
       
   209             System.DateTime endTime = DateTime.Now;
       
   210             long tickDuration = ( ( endTime.Ticks - startTime.Ticks ) / 100 );
       
   211             System.Diagnostics.Debug.WriteLine( "SORT TIME " + tickDuration.ToString( "d6" ) );
       
   212 #endif
       
   213         }
       
   214 
       
   215         public override GenericSymbol SymbolForAddress( long aAddress )
       
   216         {
       
   217 #if DEBUG
       
   218             int x = 0;
       
   219             if ( x > 0 )
       
   220             {
       
   221                 base.Dump( aAddress );
       
   222             }
       
   223 #endif
       
   224             GenericSymbol ret = null;
       
   225             //
       
   226             AddressFindingComparer comparer = new AddressFindingComparer();
       
   227             SymbolSymbol temp = SymbolSymbol.NewUnknown( (uint) aAddress, 0, string.Empty );
       
   228             int pos = iEntries.BinarySearch( temp, comparer );
       
   229             if ( pos >= 0 && pos < iEntries.Count )
       
   230             {
       
   231                 ret = iEntries[ pos ];
       
   232                 System.Diagnostics.Debug.Assert( ret.AddressRange.Contains( aAddress ) );
       
   233             }
       
   234             //
       
   235             return ret;
       
   236         }
       
   237 
       
   238         public override IEnumerator CreateEnumerator()
       
   239         {
       
   240             IEnumerator<GenericSymbol> self = (IEnumerator<GenericSymbol>) this;
       
   241             return self;
       
   242         }
       
   243 
       
   244         public override IEnumerator<GenericSymbol> CreateGenericEnumerator()
       
   245         {
       
   246             foreach ( GenericSymbol sym in iEntries )
       
   247             {
       
   248                 yield return sym;
       
   249             }
       
   250         }
       
   251 
       
   252         public override GenericSymbol this[ int aIndex ]
       
   253         {
       
   254             get
       
   255             {
       
   256                 return iEntries[ aIndex ];
       
   257             }
       
   258         }
       
   259         #endregion
       
   260 
       
   261         #region Internal enumerations
       
   262         [Flags]
       
   263 		private enum TFlags
       
   264 		{
       
   265 			EFlagsNone = 0,
       
   266 			EFlagsCalculateLengthOfPreviousSymbol = 1,
       
   267 			EFlagsDisallowFurtherSymbolsForCollection = 2,
       
   268 			EFlagsHaveSeenFirstSymbol = 4,
       
   269             EFlagsHaveDoneFixup = 8
       
   270 		}
       
   271 		#endregion
       
   272 
       
   273         #region Internal constants
       
   274         private const string KSymbolNameImageBaseOrLimitPrefix = "Image$$ER_RO$$";
       
   275         private const long KMaxDifferenceBetweenConsecutiveSymbols = 1024 * 64;
       
   276         #endregion
       
   277 
       
   278         #region Internal methods
       
   279         private void UpdateCollectionBaseAddressBasedUponFirstSymbol( GenericSymbol aSymbol )
       
   280         {
       
   281             // If we are not processing the first Symbol in the collection, then we
       
   282             // can rely on the base address being set. Otherwise, we are
       
   283             // defining the base address itself.
       
   284             if ( !( ( iFlags & TFlags.EFlagsHaveSeenFirstSymbol ) == TFlags.EFlagsHaveSeenFirstSymbol ) )
       
   285             {
       
   286                 // Set collection base address to symbol starting address
       
   287                 BaseAddress = aSymbol.Address;
       
   288 
       
   289                 // Since this is the first symbol in the collection, and we're going to use
       
   290                 // its address as the offset (base) address for the entire collection, 
       
   291                 // if we just set the collection base address to the symbol's address and
       
   292                 // the continue, this entry will be double offset (the new offset for the collection
       
   293                 // + the offset of the symbol itself). We must therefore set the symbol's offset
       
   294                 // address to zero.
       
   295                 SymbolSymbol realSymbol = (SymbolSymbol) aSymbol;
       
   296                 realSymbol.ResetOffsetAddress( 0 );
       
   297 
       
   298                 // Make sure we set a flag so that we don't attempt to do this again.
       
   299                 iFlags |= TFlags.EFlagsHaveSeenFirstSymbol;
       
   300             }
       
   301         }
       
   302 
       
   303         private void UpdateLengthOfPreviousSymbol( GenericSymbol aNewSymbol )
       
   304         {
       
   305             bool clearFlag = false;
       
   306             //
       
   307             if ( ( iFlags & TFlags.EFlagsCalculateLengthOfPreviousSymbol ) == TFlags.EFlagsCalculateLengthOfPreviousSymbol )
       
   308             {
       
   309                 // Must have some existing symbol.
       
   310                 System.Diagnostics.Debug.Assert( Count > 0 );
       
   311 
       
   312                 // Last symbol must have bad size?
       
   313                 GenericSymbol previousSymbol = InternalLastSymbol;
       
   314                 System.Diagnostics.Debug.Assert( previousSymbol.Size == 0 );
       
   315 
       
   316                 // The new symbol must be exactly the same address as the last symbol
       
   317                 // (in which case, the new symbol must have a valid size or else we're
       
   318                 // unable to do anything sensible with it) 
       
   319                 //
       
   320                 // OR
       
   321                 //
       
   322                 // The new symbol must be after the last symbol. It cannot be before.
       
   323                 System.Diagnostics.Debug.Assert( aNewSymbol.Address >= previousSymbol.Address );
       
   324                 if ( aNewSymbol.Address == previousSymbol.Address )
       
   325                 {
       
   326                     if ( aNewSymbol.Size > 0 )
       
   327                     {
       
   328                         // Okay, the new symbol has a valid size, the old one didn't.
       
   329                         clearFlag = true;
       
   330                         previousSymbol.Size = aNewSymbol.Size;
       
   331                     }
       
   332                     else
       
   333                     {
       
   334                         // Hmm, neither the last or new symbol have a valid size.
       
   335                         // Nothing we can do in this case...
       
   336                     }
       
   337                 }
       
   338                 else
       
   339                 {
       
   340                     // Need to work out the length of the previous symbol by comparing the
       
   341                     // address of this symbol against it.
       
   342                     //
       
   343                     // Only do this if the region type hasn't changed.
       
   344                     MemoryModel.TMemoryModelRegion previousType = MemoryModel.RegionByAddress( previousSymbol.Address, aNewSymbol.MemoryModelType );
       
   345                     MemoryModel.TMemoryModelRegion regionType = MemoryModel.RegionByAddress( aNewSymbol.Address, aNewSymbol.MemoryModelType );
       
   346                     if ( regionType == previousType )
       
   347                     {
       
   348                         // If this new symbol and the old symbol have the same address, then
       
   349                         // also check the size of the previous symbol. If it was zero, then discard it
       
   350                         // and keep this new entry. Otherwise, discard this new one instead.
       
   351                         long delta = aNewSymbol.Address - previousSymbol.Address;
       
   352                         if ( delta > 1 )
       
   353                         {
       
   354                             // It's okay, this symbol had a later address than the last one
       
   355                             // This is normal.
       
   356                             previousSymbol.Size = delta;
       
   357                         }
       
   358                         else
       
   359                         {
       
   360                             // This is not good. Two symbols both have the same address.
       
   361                             iEntries.Remove( previousSymbol );
       
   362                         }
       
   363                     }
       
   364 
       
   365                     clearFlag = true;
       
   366                 }
       
   367             }
       
   368 
       
   369             if ( clearFlag )
       
   370             {
       
   371                 iFlags &= ~TFlags.EFlagsCalculateLengthOfPreviousSymbol;
       
   372             }
       
   373         }
       
   374 
       
   375         private void DoAddEntry( GenericSymbol aSymbol )
       
   376         {
       
   377             // Make sure we remove the null symbol if this is the first 'valid' symbol for
       
   378             // the collection.
       
   379             if ( OnlyContainsDefaultSymbol )
       
   380             {
       
   381                 RemoveAt( 0 );
       
   382             }
       
   383 
       
   384             // If the symbol has no size, then try to work it out next time around
       
   385             if ( aSymbol.Size == 0 )
       
   386             {
       
   387                 iFlags |= TFlags.EFlagsCalculateLengthOfPreviousSymbol;
       
   388             }
       
   389 
       
   390             // Save it
       
   391             iEntries.Add( aSymbol );
       
   392         }
       
   393 
       
   394         private bool LastSymbolSharesSameAddressRange( GenericSymbol aSymbol )
       
   395         {
       
   396             bool ret = false;
       
   397             //
       
   398             GenericSymbol last = InternalLastSymbol;
       
   399             if ( last != null && last.FallsWithinDomain( aSymbol.Address ) )
       
   400             {
       
   401                 ret = true;
       
   402             }
       
   403             //
       
   404             return ret;
       
   405         }
       
   406 
       
   407         private bool FilterOutCommonAddressEntry( GenericSymbol aLast, GenericSymbol aNew )
       
   408         {
       
   409             bool acceptNew = false;
       
   410             //
       
   411             if ( aLast.IsUnknownSymbol )
       
   412             {
       
   413                 // Always discard the unknown symbol in preference of anything better
       
   414                 iEntries.Remove( aLast );
       
   415                 acceptNew = true;
       
   416             }
       
   417             else if ( aNew.Size > 0 )
       
   418             {
       
   419                 if ( aLast.Size == 0 )
       
   420                 {
       
   421                     // New is 'better' because it contains proper sizing information
       
   422                     iEntries.Remove( aLast );
       
   423                     acceptNew = true;
       
   424                 }
       
   425                 else if ( aLast.Size < aNew.Size )
       
   426                 {
       
   427                     // New is 'better' because it is bigger
       
   428                     iEntries.Remove( aLast );
       
   429                     acceptNew = true;
       
   430                 }
       
   431                 else if ( aLast.Size == aNew.Size )
       
   432                 {
       
   433                     // Both the same size. Take symbols over everything else.
       
   434                     if ( aNew.IsSymbol && !aLast.IsSymbol )
       
   435                     {
       
   436                         // Keep the symbol (new)
       
   437                         iEntries.Remove( aLast );
       
   438                         acceptNew = true;
       
   439                     }
       
   440                     else if ( !aNew.IsSymbol && aLast.IsSymbol )
       
   441                     {
       
   442                         // Keep the symbol (last)
       
   443                         acceptNew = false;
       
   444                     }
       
   445                     else
       
   446                     {
       
   447                         // Take higher priority...
       
   448                         if ( aNew.AddressType > aLast.AddressType )
       
   449                         {
       
   450                             iEntries.Remove( aLast );
       
   451                             acceptNew = true;
       
   452                         }
       
   453                         else
       
   454                         {
       
   455                             acceptNew = false;
       
   456                         }
       
   457                     }
       
   458                 }
       
   459             }
       
   460             else if ( aLast.Size > 0 )
       
   461             {
       
   462                 // Last is 'better' because the new entry doesn't have any size
       
   463                 acceptNew = false;
       
   464             }
       
   465             else if ( aLast.Size == 0 && aNew.Size == 0 )
       
   466             {
       
   467                 // Both entries have no size and the same address. We cannot
       
   468                 // accept both, therefore we make an arbitrary decision about
       
   469                 // which to keep.
       
   470                 if ( aLast.IsSubObject && !aNew.IsSubObject )
       
   471                 {
       
   472                     // Discard the sub object (last)
       
   473                     iEntries.Remove( aLast );
       
   474                     acceptNew = true;
       
   475                 }
       
   476                 else if ( aNew.IsSubObject && !aLast.IsSubObject )
       
   477                 {
       
   478                     // Discard the sub object (new)
       
   479                     acceptNew = false;
       
   480                 }
       
   481                 else if ( aNew.IsSymbol && !aLast.IsSymbol )
       
   482                 {
       
   483                     // Keep the symbol (new)
       
   484                     iEntries.Remove( aLast );
       
   485                     acceptNew = true;
       
   486                 }
       
   487                 else if ( !aNew.IsSymbol && aLast.IsSymbol )
       
   488                 {
       
   489                     // Keep the symbol (last)
       
   490                     acceptNew = false;
       
   491                 }
       
   492                 else
       
   493                 {
       
   494                     // Couldn't make a good decision. Junk the new entry
       
   495                     acceptNew = false;
       
   496                 }
       
   497             }
       
   498             //
       
   499             return acceptNew;
       
   500         }
       
   501 
       
   502         private bool IsEntryReallyData( GenericSymbol aSymbol )
       
   503         {
       
   504             bool isData = false;
       
   505 
       
   506             // Check to see if its from a data=<something> IBY entry...
       
   507             string baseName = Path.GetFileName( HostBinaryFileName ).ToLower();
       
   508             string symbolName = aSymbol.Symbol.ToLower();
       
   509 
       
   510             if ( symbolName == baseName && aSymbol.Size == 0 )
       
   511             {
       
   512                 // Its from a data entry
       
   513                 isData = true;
       
   514 
       
   515                 // Data entries only consist of a single symbol (the data itself)
       
   516                 iFlags |= TFlags.EFlagsDisallowFurtherSymbolsForCollection;
       
   517             }
       
   518 
       
   519             return isData;
       
   520         }
       
   521 
       
   522         private bool TakeEntry( GenericSymbol aSymbol, bool aAllowNonRomSymbols )
       
   523         {
       
   524             bool take = IsEntryReallyData( aSymbol );
       
   525 
       
   526             if ( !take )
       
   527             {
       
   528                 // We'll take the entry if all we have at the moment is
       
   529                 // the default entry or then no entries at all.
       
   530                 if ( OnlyContainsDefaultSymbol || iEntries.Count == 0 )
       
   531                 {
       
   532                     take = true;
       
   533                 }
       
   534                 else
       
   535                 {
       
   536                     GenericSymbol last = LastSymbol;
       
   537                     System.Diagnostics.Debug.Assert( last != null );
       
   538                     GenericSymbol.TAddressType addressType = aSymbol.AddressType;
       
   539                     //
       
   540                     switch ( addressType )
       
   541                     {
       
   542                     // We always take these...
       
   543                     case GenericSymbol.TAddressType.EAddressTypeROMSymbol:
       
   544                         take = true;
       
   545                         break;
       
   546 
       
   547                     // We sometimes take these...
       
   548                     case GenericSymbol.TAddressType.EAddressTypeRAMSymbol:
       
   549                         take = aAllowNonRomSymbols;
       
   550                         break;
       
   551 
       
   552                     case GenericSymbol.TAddressType.EAddressTypeLabel:
       
   553                         take = true;
       
   554                         break;
       
   555                     case GenericSymbol.TAddressType.EAddressTypeSubObject:
       
   556                         take = ( aSymbol.Size > 0 ) || ( last.EndAddress < aSymbol.Address );
       
   557                         break;
       
   558 
       
   559                     // We never take these
       
   560                     default:
       
   561                     case GenericSymbol.TAddressType.EAddressTypeReadOnlySymbol:
       
   562                     case GenericSymbol.TAddressType.EAddressTypeUnknown:
       
   563                     case GenericSymbol.TAddressType.EAddressTypeKernelGlobalVariable:
       
   564                         break;
       
   565                     }
       
   566                 }
       
   567             }
       
   568             //
       
   569             return take;
       
   570         }
       
   571 
       
   572         private bool OnlyContainsDefaultSymbol
       
   573         {
       
   574             get
       
   575             {
       
   576                 bool ret = ( Count == 1 && this[ 0 ].IsUnknownSymbol );
       
   577                 return ret;
       
   578             }
       
   579         }
       
   580         #endregion
       
   581 
       
   582         #region Data members
       
   583         private TFlags iFlags = TFlags.EFlagsNone;
       
   584         private List<GenericSymbol> iEntries = new List<GenericSymbol>( 200 );
       
   585         #endregion
       
   586     }
       
   587 
       
   588     #region Internal classes
       
   589     internal class AddressFindingComparer : IComparer<GenericSymbol>
       
   590     {
       
   591         public int Compare( GenericSymbol aLeft, GenericSymbol aRight )
       
   592         {
       
   593             int ret = -1;
       
   594             //
       
   595             AddressRange lr = aLeft.AddressRange;
       
   596             AddressRange rr = aRight.AddressRange;
       
   597             //
       
   598             if ( lr.Contains( rr ) || rr.Contains( lr ) )
       
   599             {
       
   600                 ret = 0;
       
   601             }
       
   602             else
       
   603             {
       
   604                 ret = lr.CompareTo( rr );
       
   605             }
       
   606             //
       
   607             return ret;
       
   608         }
       
   609     }
       
   610     #endregion
       
   611 }