|
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 } |