|
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.Text; |
|
20 using System.Collections.Generic; |
|
21 using System.Threading; |
|
22 using SymbianUtils; |
|
23 using SymbianUtils.Range; |
|
24 using SymbianStructuresLib.CodeSegments; |
|
25 using SymbianStructuresLib.Debug.Symbols.Interfaces; |
|
26 using SymbianStructuresLib.Debug.Common.Id; |
|
27 using SymbianStructuresLib.Debug.Common.Interfaces; |
|
28 using SymbianStructuresLib.Debug.Common.FileName; |
|
29 |
|
30 namespace SymbianStructuresLib.Debug.Symbols |
|
31 { |
|
32 public class SymbolCollection : DisposableObject, IEnumerable<Symbol>, IComparable<SymbolCollection>, IComparer<Symbol>, IFormattable |
|
33 { |
|
34 #region Static constructors |
|
35 public static SymbolCollection New( IPlatformIdAllocator aIdAllocator, string aFileNameInHost, string aFileNameInDevice ) |
|
36 { |
|
37 SymbolCollection ret = new SymbolCollection( aIdAllocator, aFileNameInHost, aFileNameInDevice ); |
|
38 return ret; |
|
39 } |
|
40 |
|
41 public static SymbolCollection NewCopy( IPlatformIdAllocator aIdAllocator, SymbolCollection aCollection ) |
|
42 { |
|
43 SymbolCollection ret = new SymbolCollection( aIdAllocator, aCollection ); |
|
44 return ret; |
|
45 } |
|
46 |
|
47 public static SymbolCollection NewByHostFileName( IPlatformIdAllocator aIdAllocator, string aFileName ) |
|
48 { |
|
49 SymbolCollection ret = new SymbolCollection( aIdAllocator, aFileName ); |
|
50 return ret; |
|
51 } |
|
52 #endregion |
|
53 |
|
54 #region Delegates & events |
|
55 public delegate void RelocationStatusChangeHandler( SymbolCollection aCollection ); |
|
56 public event RelocationStatusChangeHandler RelocationStatusChanged; |
|
57 #endregion |
|
58 |
|
59 #region Constructors |
|
60 private SymbolCollection( IPlatformIdAllocator aIdAllocator, string aFileNameInHost ) |
|
61 { |
|
62 iOriginalCollection = null; |
|
63 iId = aIdAllocator.AllocateId(); |
|
64 iIdAllocator = aIdAllocator; |
|
65 iFileName = PlatformFileName.NewByHostName( aFileNameInHost ); |
|
66 DefaultSymbolAdd(); |
|
67 } |
|
68 |
|
69 private SymbolCollection( IPlatformIdAllocator aIdAllocator, string aFileNameInHost, string aFileNameInDevice ) |
|
70 : this( aIdAllocator, aFileNameInHost ) |
|
71 { |
|
72 iFileName.FileNameInDevice = aFileNameInDevice; |
|
73 } |
|
74 |
|
75 private SymbolCollection( IPlatformIdAllocator aIdAllocator, SymbolCollection aCopy ) |
|
76 { |
|
77 iId = aIdAllocator.AllocateId(); |
|
78 iIdAllocator = aIdAllocator; |
|
79 iTag = aCopy.iTag; |
|
80 iOriginalCollection = aCopy; |
|
81 iFlags = aCopy.iFlags; |
|
82 iTagged = aCopy.iTagged; |
|
83 iBaseAddress = aCopy.iBaseAddress; |
|
84 iCodeSegmentResolver = aCopy.iCodeSegmentResolver; |
|
85 iRelocationHandler = aCopy.iRelocationHandler; |
|
86 iFileName = PlatformFileName.New( aCopy.FileName ); |
|
87 iCodeSegmentResolver = aCopy.IfaceCodeSegmentResolver; |
|
88 iRelocationHandler = aCopy.IfaceRelocationHandler; |
|
89 |
|
90 // Deep copy symbols |
|
91 foreach ( Symbol symbol in aCopy ) |
|
92 { |
|
93 Symbol clone = Symbol.NewClone( this, symbol ); |
|
94 iSymbols.Add( clone ); |
|
95 } |
|
96 |
|
97 // Recalculate addresses |
|
98 RecalculationAddressRange(); |
|
99 } |
|
100 #endregion |
|
101 |
|
102 #region API |
|
103 public void Serialize( StreamWriter aWriter ) |
|
104 { |
|
105 StringBuilder temp = new StringBuilder(); |
|
106 // |
|
107 lock ( iFileName ) |
|
108 { |
|
109 temp.AppendLine( string.Empty ); |
|
110 temp.AppendLine( "From " + iFileName.FileNameInHost ); |
|
111 temp.AppendLine( string.Empty ); |
|
112 } |
|
113 // |
|
114 lock ( iSymbols ) |
|
115 { |
|
116 foreach ( Symbol symbol in iSymbols ) |
|
117 { |
|
118 temp.AppendLine( symbol.ToString( "stream", null ) ); |
|
119 } |
|
120 } |
|
121 |
|
122 aWriter.Write( temp.ToString() ); |
|
123 } |
|
124 |
|
125 public void Add( Symbol aSymbol ) |
|
126 { |
|
127 if ( aSymbol.IsDefault ) |
|
128 { |
|
129 throw new ArgumentException( "Cannot add default symbol" ); |
|
130 } |
|
131 // |
|
132 lock ( iSymbols ) |
|
133 { |
|
134 int count = iSymbols.Count; |
|
135 if ( count == 1 ) |
|
136 { |
|
137 // Possibly... |
|
138 DefaultSymbolRemove(); |
|
139 } |
|
140 |
|
141 // Because count might have changed if we removed default |
|
142 // symbol. |
|
143 count = iSymbols.Count; |
|
144 if ( count >= 1 ) |
|
145 { |
|
146 Symbol last = iSymbols[ count - 1 ]; |
|
147 if ( aSymbol.Address < last.Address ) |
|
148 { |
|
149 // We appear to be adding a symbol with an earlier address, |
|
150 // which implies we need to sort the collection. |
|
151 lock( iFlagLock ) |
|
152 { |
|
153 iFlags |= TFlags.EFlagsRequiresSorting; |
|
154 } |
|
155 } |
|
156 } |
|
157 |
|
158 // Now add it |
|
159 iSymbols.Add( aSymbol ); |
|
160 // |
|
161 if ( !InTransaction ) |
|
162 { |
|
163 RecalculationAddressRange(); |
|
164 } |
|
165 } |
|
166 } |
|
167 |
|
168 public void AddRange( IEnumerable<Symbol> aSymbols ) |
|
169 { |
|
170 TransactionBegin(); |
|
171 // |
|
172 try |
|
173 { |
|
174 foreach ( Symbol symbol in aSymbols ) |
|
175 { |
|
176 Add( symbol ); |
|
177 } |
|
178 } |
|
179 finally |
|
180 { |
|
181 TransactionEnd(); |
|
182 } |
|
183 } |
|
184 |
|
185 public void Clear() |
|
186 { |
|
187 lock ( iSymbols ) |
|
188 { |
|
189 iSymbols.Clear(); |
|
190 |
|
191 // We are definitely empty so force the default symbol to be |
|
192 // added irrespective of flags |
|
193 DefaultSymbolAdd( true ); |
|
194 } |
|
195 } |
|
196 |
|
197 public void Remove( Symbol aSymbol ) |
|
198 { |
|
199 if ( aSymbol.IsDefault ) |
|
200 { |
|
201 throw new ArgumentException( "Cannot remove default symbol" ); |
|
202 } |
|
203 // |
|
204 lock ( iSymbols ) |
|
205 { |
|
206 iSymbols.Remove( aSymbol ); |
|
207 if ( iSymbols.Count == 0 ) |
|
208 { |
|
209 // We are definitely empty so force the default symbol to be |
|
210 // added irrespective of flags |
|
211 DefaultSymbolAdd( true ); |
|
212 System.Diagnostics.Debug.Assert( IsEmptyApartFromDefaultSymbol ); |
|
213 } |
|
214 } |
|
215 } |
|
216 |
|
217 public void RemoveAt( int aIndex ) |
|
218 { |
|
219 lock ( iSymbols ) |
|
220 { |
|
221 Symbol symbol = iSymbols[ aIndex ]; |
|
222 if ( symbol.IsDefault ) |
|
223 { |
|
224 throw new ArgumentException( "Cannot remove default symbol" ); |
|
225 } |
|
226 // |
|
227 iSymbols.RemoveAt( aIndex ); |
|
228 if ( iSymbols.Count == 0 ) |
|
229 { |
|
230 // We are definitely empty so force the default symbol to be |
|
231 // added irrespective of flags |
|
232 DefaultSymbolAdd( true ); |
|
233 System.Diagnostics.Debug.Assert( IsEmptyApartFromDefaultSymbol ); |
|
234 } |
|
235 } |
|
236 } |
|
237 |
|
238 public bool Contains( uint aAddress ) |
|
239 { |
|
240 if ( iAddresses == null ) |
|
241 { |
|
242 iAddresses = new AddressRangeCollection( (IEnumerable<AddressRange>) this ); |
|
243 RecalculationAddressRange(); |
|
244 } |
|
245 // |
|
246 bool found = iAddresses.Contains( aAddress ); |
|
247 return found; |
|
248 } |
|
249 |
|
250 public bool IsMatchingCodeSegment( CodeSegDefinition aCodeSegment ) |
|
251 { |
|
252 bool ret = false; |
|
253 // |
|
254 if ( iCodeSegmentResolver != null ) |
|
255 { |
|
256 ret = iCodeSegmentResolver.IsMatchingCodeSegment( this, aCodeSegment ); |
|
257 } |
|
258 else |
|
259 { |
|
260 PlatformFileName codeSegName = PlatformFileName.NewByDeviceName( aCodeSegment.FileName ); |
|
261 ret = FileName.Equals( codeSegName ); |
|
262 } |
|
263 // |
|
264 return ret; |
|
265 } |
|
266 |
|
267 public void Sort() |
|
268 { |
|
269 if ( ( iFlags & TFlags.EFlagsRequiresSorting ) == TFlags.EFlagsRequiresSorting ) |
|
270 { |
|
271 iSymbols.Sort( this ); |
|
272 RecalculationAddressRange(); |
|
273 } |
|
274 } |
|
275 |
|
276 public void SortAsync() |
|
277 { |
|
278 if ( ( iFlags & TFlags.EFlagsRequiresSorting ) == TFlags.EFlagsRequiresSorting ) |
|
279 { |
|
280 ThreadPool.QueueUserWorkItem( new WaitCallback( InitiateAsyncSort ) ); |
|
281 } |
|
282 } |
|
283 |
|
284 public void Relocate( uint aTo ) |
|
285 { |
|
286 uint old = iBaseAddress; |
|
287 iBaseAddress = aTo; |
|
288 // |
|
289 if ( iRelocationHandler != null ) |
|
290 { |
|
291 iRelocationHandler.PrepareForRelocation( this, old, BaseAddress ); |
|
292 } |
|
293 // |
|
294 RecalculationAddressRange(); |
|
295 } |
|
296 |
|
297 public void TransactionBegin() |
|
298 { |
|
299 lock ( iFlagLock ) |
|
300 { |
|
301 iFlags |= TFlags.EFlagsInTransaction; |
|
302 } |
|
303 } |
|
304 |
|
305 public void TransactionEnd() |
|
306 { |
|
307 lock ( iFlagLock ) |
|
308 { |
|
309 iFlags &= ~TFlags.EFlagsInTransaction; |
|
310 } |
|
311 |
|
312 RecalculationAddressRange(); |
|
313 } |
|
314 |
|
315 public void Clone( IEnumerable<Symbol> aSymbols ) |
|
316 { |
|
317 // Deep copy symbols |
|
318 Clear(); |
|
319 try |
|
320 { |
|
321 TransactionBegin(); |
|
322 foreach ( Symbol symbol in aSymbols ) |
|
323 { |
|
324 // Make sure we don't try to add the default symbol. The symbol collection |
|
325 // manages this automatically. |
|
326 if ( symbol.IsDefault ) |
|
327 { |
|
328 } |
|
329 else |
|
330 { |
|
331 Symbol clone = Symbol.NewClone( this, symbol ); |
|
332 Add( clone ); |
|
333 } |
|
334 } |
|
335 } |
|
336 finally |
|
337 { |
|
338 TransactionEnd(); |
|
339 } |
|
340 } |
|
341 #endregion |
|
342 |
|
343 #region Properties |
|
344 public int Count |
|
345 { |
|
346 get |
|
347 { |
|
348 lock ( iSymbols ) |
|
349 { |
|
350 return iSymbols.Count; |
|
351 } |
|
352 } |
|
353 } |
|
354 |
|
355 public Symbol this[ int aIndex ] |
|
356 { |
|
357 get |
|
358 { |
|
359 lock ( iSymbols ) |
|
360 { |
|
361 return iSymbols[ aIndex ]; |
|
362 } |
|
363 } |
|
364 } |
|
365 |
|
366 public Symbol this[ uint aAddress ] |
|
367 { |
|
368 get |
|
369 { |
|
370 // For debugging |
|
371 int x = 0; |
|
372 if ( x > 0 ) |
|
373 { |
|
374 string dump = Dump( aAddress ); |
|
375 System.Diagnostics.Debug.WriteLine( dump ); |
|
376 } |
|
377 // |
|
378 Symbol ret = null; |
|
379 Symbol temp = Symbol.NewTemp( this, aAddress ); |
|
380 // |
|
381 lock ( iSymbols ) |
|
382 { |
|
383 AddressFindingComparer comparer = new AddressFindingComparer(); |
|
384 int pos = iSymbols.BinarySearch( temp, comparer ); |
|
385 int count = iSymbols.Count; |
|
386 // |
|
387 if ( pos >= 0 && pos < count ) |
|
388 { |
|
389 ret = iSymbols[ pos ]; |
|
390 System.Diagnostics.Debug.Assert( ret.AddressRange.Contains( aAddress ) ); |
|
391 } |
|
392 } |
|
393 // |
|
394 return ret; |
|
395 } |
|
396 } |
|
397 |
|
398 public Symbol FirstSymbol |
|
399 { |
|
400 get |
|
401 { |
|
402 Symbol ret = null; |
|
403 lock ( iSymbols ) |
|
404 { |
|
405 if ( Count > 0 ) |
|
406 { |
|
407 ret = this[ 0 ]; |
|
408 } |
|
409 } |
|
410 return ret; |
|
411 } |
|
412 } |
|
413 |
|
414 public Symbol LastSymbol |
|
415 { |
|
416 get |
|
417 { |
|
418 Symbol ret = null; |
|
419 lock ( iSymbols ) |
|
420 { |
|
421 if ( Count > 0 ) |
|
422 { |
|
423 ret = this[ Count - 1 ]; |
|
424 } |
|
425 } |
|
426 return ret; |
|
427 } |
|
428 } |
|
429 |
|
430 public bool Tagged |
|
431 { |
|
432 get { return iTagged; } |
|
433 set |
|
434 { |
|
435 // The 'tagged' property is one of the few that we must (and can safely) |
|
436 // cascade to the original underlying collection. |
|
437 // |
|
438 // We do this, because when working with ROFS/relocated symbols, we generally |
|
439 // clone and fixup, rather than fixup the original. This permits us to use |
|
440 // a symbol collection at multiple base addresses (i.e. use the same symbols within |
|
441 // different process-relative views of the "world"). |
|
442 // |
|
443 // If we don't cascade the tagged attribute to the original (i.e. primary) symbol |
|
444 // collection, then when the client application wants to serialized tagged collections |
|
445 // the ROFS collections will potentially be missing (if they have been unloaded). |
|
446 if ( iOriginalCollection != null ) |
|
447 { |
|
448 iOriginalCollection.Tagged = value; |
|
449 iTagged = value; |
|
450 } |
|
451 else if ( iTagged != value ) |
|
452 { |
|
453 iTagged = value; |
|
454 if ( iTagged ) |
|
455 { |
|
456 System.Diagnostics.Debug.WriteLine( string.Format( "[S] TAGGING: 0x{0:x8}, {1}", this.BaseAddress, iFileName ) ); |
|
457 } |
|
458 } |
|
459 } |
|
460 } |
|
461 |
|
462 public bool InTransaction |
|
463 { |
|
464 get { return ( iFlags & TFlags.EFlagsInTransaction ) == TFlags.EFlagsInTransaction; } |
|
465 } |
|
466 |
|
467 public bool IsRelocatable |
|
468 { |
|
469 get { return ( iFlags & TFlags.EFlagsIsRelocatable ) == TFlags.EFlagsIsRelocatable; } |
|
470 set |
|
471 { |
|
472 lock ( iFlagLock ) |
|
473 { |
|
474 bool wasSet = ( iFlags & TFlags.EFlagsIsRelocatable ) == TFlags.EFlagsIsRelocatable; |
|
475 if ( wasSet != value ) |
|
476 { |
|
477 if ( value ) |
|
478 { |
|
479 iFlags |= TFlags.EFlagsIsRelocatable; |
|
480 } |
|
481 else |
|
482 { |
|
483 iFlags &= ~TFlags.EFlagsIsRelocatable; |
|
484 } |
|
485 |
|
486 // Report event if needed |
|
487 if ( RelocationStatusChanged != null ) |
|
488 { |
|
489 RelocationStatusChanged( this ); |
|
490 } |
|
491 } |
|
492 } |
|
493 } |
|
494 } |
|
495 |
|
496 public bool IsFixed |
|
497 { |
|
498 get { return !IsRelocatable; } |
|
499 set |
|
500 { |
|
501 IsRelocatable = !value; |
|
502 } |
|
503 } |
|
504 |
|
505 public bool IsEmptyApartFromDefaultSymbol |
|
506 { |
|
507 get |
|
508 { |
|
509 bool ret = ( iFlags & TFlags.EFlagsIsEmptyApartFromDefaultSymbol ) == TFlags.EFlagsIsEmptyApartFromDefaultSymbol; |
|
510 return ret; |
|
511 } |
|
512 private set |
|
513 { |
|
514 lock ( iFlagLock ) |
|
515 { |
|
516 if ( value ) |
|
517 { |
|
518 iFlags |= TFlags.EFlagsIsEmptyApartFromDefaultSymbol; |
|
519 } |
|
520 else |
|
521 { |
|
522 iFlags &= ~TFlags.EFlagsIsEmptyApartFromDefaultSymbol; |
|
523 } |
|
524 } |
|
525 } |
|
526 } |
|
527 |
|
528 public object Tag |
|
529 { |
|
530 get { return iTag; } |
|
531 set |
|
532 { |
|
533 iTag = value; |
|
534 } |
|
535 } |
|
536 |
|
537 public uint BaseAddress |
|
538 { |
|
539 get |
|
540 { |
|
541 uint ret = iBaseAddress; |
|
542 return ret; |
|
543 } |
|
544 } |
|
545 |
|
546 public PlatformId Id |
|
547 { |
|
548 get { return iId; } |
|
549 } |
|
550 |
|
551 public PlatformFileName FileName |
|
552 { |
|
553 get { return iFileName; } |
|
554 } |
|
555 |
|
556 public SymbolCollectionList ParentList |
|
557 { |
|
558 get { return iParentList; } |
|
559 internal set { iParentList = value; } |
|
560 } |
|
561 |
|
562 public AddressRange SubsumedPrimaryRange |
|
563 { |
|
564 get |
|
565 { |
|
566 AddressRange ret = new AddressRange( this.BaseAddress, this.BaseAddress ); |
|
567 // |
|
568 if ( iAddresses != null ) |
|
569 { |
|
570 int count = iAddresses.Count; |
|
571 for( int i=0; i<count; i++ ) |
|
572 { |
|
573 AddressRange segment = iAddresses[ i ]; |
|
574 |
|
575 // Ranges should be reliably sorted/calculated so that we |
|
576 // shouldn't end up going backwards beyond the base address |
|
577 // of the code segment |
|
578 System.Diagnostics.Debug.Assert( segment.Min >= ret.Min ); |
|
579 |
|
580 // If the segmented address range doesn't sit within the existing |
|
581 // range we are building, then we may need to extend our return |
|
582 // value. |
|
583 if ( !ret.Contains( segment ) ) |
|
584 { |
|
585 uint diff = segment.Min - ret.Max; |
|
586 if ( diff <= KMaximumNonConsecutiveAddressRangeDifferenceToSubsume ) |
|
587 { |
|
588 ret.UpdateMax( segment.Max ); |
|
589 } |
|
590 } |
|
591 } |
|
592 } |
|
593 // |
|
594 return ret; |
|
595 } |
|
596 } |
|
597 |
|
598 public object SyncRoot |
|
599 { |
|
600 get |
|
601 { |
|
602 return iSymbols; |
|
603 } |
|
604 } |
|
605 #endregion |
|
606 |
|
607 #region Properties - interfaces |
|
608 public ISymbolCodeSegmentResolver IfaceCodeSegmentResolver |
|
609 { |
|
610 get { return iCodeSegmentResolver; } |
|
611 set { iCodeSegmentResolver = value; } |
|
612 } |
|
613 |
|
614 public ISymbolCollectionRelocationHandler IfaceRelocationHandler |
|
615 { |
|
616 get { return iRelocationHandler; } |
|
617 set { iRelocationHandler = value; } |
|
618 } |
|
619 #endregion |
|
620 |
|
621 #region From IComparable<SymbolCollection> |
|
622 public int CompareTo( SymbolCollection aCollection ) |
|
623 { |
|
624 int ret = ( aCollection.FileName == this.FileName ) ? 0 : -1; |
|
625 // |
|
626 if ( ret == 0 ) |
|
627 { |
|
628 if ( BaseAddress == aCollection.BaseAddress ) |
|
629 { |
|
630 ret = 0; |
|
631 } |
|
632 else if ( BaseAddress > aCollection.BaseAddress ) |
|
633 { |
|
634 ret = 1; |
|
635 } |
|
636 else |
|
637 { |
|
638 ret = -1; |
|
639 } |
|
640 } |
|
641 // |
|
642 return ret; |
|
643 } |
|
644 #endregion |
|
645 |
|
646 #region From IComparer<Symbol> |
|
647 public int Compare( Symbol aLeft, Symbol aRight ) |
|
648 { |
|
649 System.Diagnostics.Debug.Assert( aLeft.EndAddress >= aLeft.Address ); |
|
650 System.Diagnostics.Debug.Assert( aRight.EndAddress >= aRight.Address ); |
|
651 // |
|
652 int ret = -1; |
|
653 // |
|
654 if ( aLeft.Address == aRight.Address && aLeft.EndAddress == aRight.EndAddress ) |
|
655 { |
|
656 ret = 0; |
|
657 } |
|
658 else if ( aLeft.EndAddress == aRight.Address ) |
|
659 { |
|
660 System.Diagnostics.Debug.Assert( aLeft.Address < aRight.Address ); |
|
661 System.Diagnostics.Debug.Assert( aRight.EndAddress >= aLeft.EndAddress ); |
|
662 // |
|
663 ret = -1; |
|
664 } |
|
665 else if ( aLeft.Address == aRight.EndAddress ) |
|
666 { |
|
667 System.Diagnostics.Debug.Assert( aRight.Address < aLeft.Address ); |
|
668 System.Diagnostics.Debug.Assert( aLeft.EndAddress >= aRight.EndAddress ); |
|
669 // |
|
670 ret = 1; |
|
671 } |
|
672 else if ( aLeft.Address > aRight.EndAddress ) |
|
673 { |
|
674 System.Diagnostics.Debug.Assert( aLeft.EndAddress > aRight.EndAddress ); |
|
675 System.Diagnostics.Debug.Assert( aLeft.EndAddress > aRight.Address ); |
|
676 ret = 1; |
|
677 } |
|
678 else if ( aLeft.EndAddress < aRight.Address ) |
|
679 { |
|
680 System.Diagnostics.Debug.Assert( aLeft.Address < aRight.EndAddress ); |
|
681 System.Diagnostics.Debug.Assert( aRight.EndAddress > aLeft.EndAddress ); |
|
682 ret = -1; |
|
683 } |
|
684 // |
|
685 return ret; |
|
686 } |
|
687 #endregion |
|
688 |
|
689 #region From IEnumerable<Symbol> |
|
690 IEnumerator<Symbol> IEnumerable<Symbol>.GetEnumerator() |
|
691 { |
|
692 foreach ( Symbol entry in iSymbols ) |
|
693 { |
|
694 yield return entry; |
|
695 } |
|
696 } |
|
697 |
|
698 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() |
|
699 { |
|
700 foreach ( Symbol entry in iSymbols ) |
|
701 { |
|
702 yield return entry; |
|
703 } |
|
704 } |
|
705 #endregion |
|
706 |
|
707 #region From IFormattable |
|
708 public string ToString( string aFormat, IFormatProvider aFormatProvider ) |
|
709 { |
|
710 string ret = string.Empty; |
|
711 // |
|
712 if ( aFormat == null ) |
|
713 { |
|
714 ret = iFileName.ToString(); |
|
715 } |
|
716 else if ( aFormat.ToUpper() == "FULL" ) |
|
717 { |
|
718 ret = Dump(); |
|
719 } |
|
720 else |
|
721 { |
|
722 throw new FormatException( string.Format( "Invalid format string: '{0}'.", aFormat ) ); |
|
723 } |
|
724 // |
|
725 return ret; |
|
726 } |
|
727 #endregion |
|
728 |
|
729 #region From System.Object |
|
730 public override string ToString() |
|
731 { |
|
732 return iFileName.ToString(); |
|
733 } |
|
734 |
|
735 public override bool Equals( object aObject ) |
|
736 { |
|
737 if ( aObject != null && aObject is SymbolCollection ) |
|
738 { |
|
739 SymbolCollection col = (SymbolCollection) aObject; |
|
740 bool ret = ( col.FileName == this.FileName ); |
|
741 return ret; |
|
742 } |
|
743 // |
|
744 return base.Equals( aObject ); |
|
745 } |
|
746 |
|
747 public override int GetHashCode() |
|
748 { |
|
749 return iFileName.GetHashCode(); |
|
750 } |
|
751 #endregion |
|
752 |
|
753 #region Internal enumerations |
|
754 [Flags] |
|
755 private enum TFlags : byte |
|
756 { |
|
757 EFlagsNone = 0, |
|
758 EFlagsInTransaction = 1, |
|
759 EFlagsIsRelocatable = 2, |
|
760 EFlagsIsEmptyApartFromDefaultSymbol = 4, |
|
761 EFlagsRequiresSorting = 8, |
|
762 }; |
|
763 #endregion |
|
764 |
|
765 #region Internal constants |
|
766 private const uint KMaximumNonConsecutiveAddressRangeDifferenceToSubsume = 512; |
|
767 #endregion |
|
768 |
|
769 #region Internal methods |
|
770 private string Dump() |
|
771 { |
|
772 string ret = Dump( uint.MaxValue ); |
|
773 return ret; |
|
774 } |
|
775 |
|
776 private string Dump( uint aAddress ) |
|
777 { |
|
778 #if SYMCOL_INVARIANT_CHECK |
|
779 DebugCheckInvariant(); |
|
780 #endif |
|
781 // |
|
782 StringBuilder ret = new StringBuilder(); |
|
783 // |
|
784 int i = 0; |
|
785 string line = string.Empty; |
|
786 // |
|
787 lock ( iSymbols ) |
|
788 { |
|
789 foreach ( Symbol entry in iSymbols ) |
|
790 { |
|
791 if ( aAddress != uint.MaxValue && entry.Contains( aAddress ) ) |
|
792 { |
|
793 line = i.ToString( "d8" ) + " * [" + entry.Address.ToString( "x8" ) + "-" + entry.EndAddress.ToString( "x8" ) + "] " + entry.Name; |
|
794 } |
|
795 else |
|
796 { |
|
797 line = i.ToString( "d8" ) + " [" + entry.Address.ToString( "x8" ) + "-" + entry.EndAddress.ToString( "x8" ) + "] " + entry.Name; |
|
798 } |
|
799 // |
|
800 ret.AppendLine( line ); |
|
801 i++; |
|
802 } |
|
803 } |
|
804 // |
|
805 return ret.ToString(); |
|
806 } |
|
807 |
|
808 private void DefaultSymbolAdd() |
|
809 { |
|
810 DefaultSymbolAdd( false ); |
|
811 } |
|
812 |
|
813 private void DefaultSymbolAdd( bool aForce ) |
|
814 { |
|
815 #if SYMCOL_INVARIANT_CHECK |
|
816 DebugCheckInvariant(); |
|
817 #endif |
|
818 // |
|
819 if ( !IsEmptyApartFromDefaultSymbol || aForce ) |
|
820 { |
|
821 lock ( iSymbols ) |
|
822 { |
|
823 System.Diagnostics.Debug.Assert( Count == 0 ); |
|
824 Symbol def = Symbol.NewDefault( this ); |
|
825 iSymbols.Add( def ); |
|
826 IsEmptyApartFromDefaultSymbol = true; |
|
827 } |
|
828 } |
|
829 } |
|
830 |
|
831 private void DefaultSymbolRemove() |
|
832 { |
|
833 #if SYMCOL_INVARIANT_CHECK |
|
834 DebugCheckInvariant(); |
|
835 #endif |
|
836 // |
|
837 if ( IsEmptyApartFromDefaultSymbol ) |
|
838 { |
|
839 lock ( iSymbols ) |
|
840 { |
|
841 int count = iSymbols.Count; |
|
842 // |
|
843 if ( IsEmptyApartFromDefaultSymbol ) |
|
844 { |
|
845 System.Diagnostics.Debug.Assert( count == 1 && this.FirstSymbol.IsDefault ); |
|
846 iSymbols.RemoveAt( 0 ); |
|
847 IsEmptyApartFromDefaultSymbol = false; |
|
848 } |
|
849 #if SYMCOL_INVARIANT_CHECK |
|
850 else if ( count > 0 ) |
|
851 { |
|
852 System.Diagnostics.Debug.Assert( this.FirstSymbol.IsDefault == false ); |
|
853 } |
|
854 #endif |
|
855 } |
|
856 } |
|
857 } |
|
858 |
|
859 private void InitiateAsyncSort( object aNotUsed ) |
|
860 { |
|
861 Sort(); |
|
862 } |
|
863 |
|
864 #if SYMCOL_INVARIANT_CHECK |
|
865 private void DebugCheckInvariant() |
|
866 { |
|
867 lock ( iSymbols ) |
|
868 { |
|
869 int count = Count; |
|
870 if ( count > 0 ) |
|
871 { |
|
872 Symbol first = this.FirstSymbol; |
|
873 if ( first.IsDefault ) |
|
874 { |
|
875 System.Diagnostics.Debug.Assert( IsEmptyApartFromDefaultSymbol ); |
|
876 System.Diagnostics.Debug.Assert( count == 1 ); |
|
877 } |
|
878 } |
|
879 } |
|
880 } |
|
881 #endif |
|
882 |
|
883 private void RecalculationAddressRange() |
|
884 { |
|
885 #if SYMCOL_INVARIANT_CHECK |
|
886 DebugCheckInvariant(); |
|
887 #endif |
|
888 // |
|
889 if ( !InTransaction ) |
|
890 { |
|
891 AddressRangeCollection range = new AddressRangeCollection(); |
|
892 lock ( iSymbols ) |
|
893 { |
|
894 foreach ( Symbol entry in iSymbols ) |
|
895 { |
|
896 range.Add( entry.AddressRange ); |
|
897 } |
|
898 } |
|
899 // |
|
900 iAddresses = range; |
|
901 } |
|
902 } |
|
903 #endregion |
|
904 |
|
905 #region Internal properties |
|
906 internal IPlatformIdAllocator IdAllocator |
|
907 { |
|
908 get { return iIdAllocator; } |
|
909 } |
|
910 |
|
911 internal AddressRangeCollection AddressRangeCollection |
|
912 { |
|
913 get { return iAddresses; } |
|
914 } |
|
915 #endregion |
|
916 |
|
917 #region Internal classes |
|
918 internal class AddressFindingComparer : IComparer<Symbol> |
|
919 { |
|
920 public int Compare( Symbol aLeft, Symbol aRight ) |
|
921 { |
|
922 int ret = -1; |
|
923 // |
|
924 AddressRange lr = aLeft.AddressRange; |
|
925 AddressRange rr = aRight.AddressRange; |
|
926 // |
|
927 if ( lr.Contains( rr ) || rr.Contains( lr ) ) |
|
928 { |
|
929 ret = 0; |
|
930 } |
|
931 else |
|
932 { |
|
933 ret = lr.CompareTo( rr ); |
|
934 } |
|
935 // |
|
936 return ret; |
|
937 } |
|
938 } |
|
939 #endregion |
|
940 |
|
941 #region From DisposableObject |
|
942 protected override void CleanupManagedResources() |
|
943 { |
|
944 try |
|
945 { |
|
946 base.CleanupManagedResources(); |
|
947 } |
|
948 finally |
|
949 { |
|
950 iTag = null; |
|
951 if ( iAddresses != null ) |
|
952 { |
|
953 iAddresses.Clear(); |
|
954 } |
|
955 iSymbols.Clear(); |
|
956 iParentList = null; |
|
957 iCodeSegmentResolver = null; |
|
958 iRelocationHandler = null; |
|
959 } |
|
960 } |
|
961 #endregion |
|
962 |
|
963 #region Data members |
|
964 private readonly PlatformId iId; |
|
965 private readonly IPlatformIdAllocator iIdAllocator; |
|
966 private readonly PlatformFileName iFileName; |
|
967 private readonly SymbolCollection iOriginalCollection = null; |
|
968 private object iTag = null; |
|
969 private object iFlagLock = new object(); |
|
970 private bool iTagged = false; |
|
971 private TFlags iFlags = TFlags.EFlagsNone; |
|
972 private uint iBaseAddress = 0; |
|
973 private AddressRangeCollection iAddresses = null; |
|
974 private List<Symbol> iSymbols = new List<Symbol>(); |
|
975 private SymbolCollectionList iParentList = null; |
|
976 private ISymbolCodeSegmentResolver iCodeSegmentResolver = null; |
|
977 private ISymbolCollectionRelocationHandler iRelocationHandler = null; |
|
978 #endregion |
|
979 } |
|
980 } |