using System; using System.Text.RegularExpressions; using System.Collections; using System.IO; namespace MapSorter { public class Element : IComparable { /// /// Segment this element is in. /// public int Segment; /// /// Base or virtual file address. /// public int Address; /// /// Adjusted relative virtual address. /// public int RVA; /// /// Name of this element. /// public string Text; /// /// Object file this element is located in. /// public string Obj; /// /// Size of this element, or -1. /// public int Size = -1; /// /// True if this is the last element in an object file. /// public bool bCrossObj = false; public Element( int Segment, int Address, string Text, int RVA, string Obj ) { this.Segment = Segment; this.Address = Address; this.RVA = RVA; this.Text = Text; this.Obj = Obj; } // Comparable interface: int System.IComparable.CompareTo( object o ) { // HACK HACK - sorts according to size if size field is non negative, otherwise sorts by segment then address Element other = (Element)o; // Sort by size: if( other.Size != -1 || Size != -1 ) { if( Size < other.Size ) return -1; if( Size > other.Size ) return 1; return 0; } // Sizes aren't defined, sort by Segment then Address: if( Segment != other.Segment ) { if( Segment < other.Segment ) return -1; else return 0; } if( Address < other.Address ) return -1; else if( Address > other.Address ) return 1; return 0; } } public class Module : IComparable { public string Name; public int Size; public Module(string Name, int Size) { this.Name = Name; this.Size = Size; } int System.IComparable.CompareTo( object o ) { Module m = (Module)o; if( Size < m.Size ) return -1; if( Size > m.Size ) return 1; return 0; } } /// /// An atomic class that loads and parses a given map file. /// public class MapFileLoader { ArrayList Elements; ArrayList Modules; /// /// Regular expression to break mapfile elements up: /// protected static Regex ElementRegex = new Regex(@"([0-9a-fA-F]{4})\:([0-9a-fA-F]{8})\s+([^\s]*)\s+([0-9a-fA-F]{8})\s(f\s)?(i\s)?\s+(.*\.obj)",RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.IgnoreCase ); public MapFileLoader( string filename ) { // Load the element data from the mapfile: LoadElements( new StreamReader(filename).ReadToEnd() ); // Compute modules and their sizes: ComputeModules(); } public void DumpReport() { Console.WriteLine("***** Elements by size ascending. (*) = element straddles an .obj file boundary, so the size may not be correct."); Console.WriteLine(); foreach (Element e in Elements ) { if( e.Size < 1024 ) continue; if( e.bCrossObj ) Console.Write("(*)"); Console.WriteLine( e.Size / 1024 + "k : " +e.Obj + " : " + e.Text ); } Console.WriteLine(); Console.WriteLine(); Console.WriteLine("***** Modules by size, ascending. This is estimated based on elements that don't straddle .obj boundaries."); Console.WriteLine(); foreach(Module m in Modules ) { if( m.Size < 1024 ) continue; Console.WriteLine( m.Size / 1024 + "k : " + m.Name ); } } protected void LoadElements( string mapfile ) { // Match each appropriate line in the map file. The summary entries at the top of each map file are NOT matched by this regex. MatchCollection matches = ElementRegex.Matches(mapfile); Elements = new ArrayList(); // Convert each match to an Element type and add them to an array list. foreach( Match m in matches ) { Element e = new Element(int.Parse(m.Groups[1].Value,System.Globalization.NumberStyles.AllowHexSpecifier), int.Parse(m.Groups[2].Value,System.Globalization.NumberStyles.AllowHexSpecifier), m.Groups[3].Value, int.Parse(m.Groups[4].Value,System.Globalization.NumberStyles.AllowHexSpecifier), m.Groups[7].Value); Elements.Add(e); } // Sort the list by address: Elements.Sort(); Element previous = null; // Compute estimated sizes for each element in the list: foreach( Element e in Elements ) { if( previous != null ) { if( e.Segment == previous.Segment ) { previous.Size = e.Address- previous.Address; // Take note of the symbols that cross object file boundaries: if( !previous.Obj.Equals(e.Obj) ) { previous.bCrossObj = true; } } } previous = e; } // Sort the list by size Elements.Sort(); } protected void ComputeModules() { // Estimate the size of each object file: Hashtable h = new Hashtable(); foreach(Element e in Elements ) { if( !h.ContainsKey(e.Obj) ) h.Add(e.Obj,0); if( !e.bCrossObj ) { h[e.Obj] = (int)h[e.Obj] + e.Size; } } Modules = new ArrayList(); foreach( string key in h.Keys ) { Modules.Add( new Module(key, (int)h[key] )); } Modules.Sort(); } } }