You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
248 lines
5.2 KiB
248 lines
5.2 KiB
using System; |
|
using System.Text.RegularExpressions; |
|
using System.Collections; |
|
using System.IO; |
|
|
|
namespace MapSorter |
|
{ |
|
public class Element : IComparable |
|
{ |
|
/// <summary> |
|
/// Segment this element is in. |
|
/// </summary> |
|
public int Segment; |
|
|
|
/// <summary> |
|
/// Base or virtual file address. |
|
/// </summary> |
|
public int Address; |
|
|
|
/// <summary> |
|
/// Adjusted relative virtual address. |
|
/// </summary> |
|
public int RVA; |
|
|
|
/// <summary> |
|
/// Name of this element. |
|
/// </summary> |
|
public string Text; |
|
|
|
/// <summary> |
|
/// Object file this element is located in. |
|
/// </summary> |
|
public string Obj; |
|
|
|
/// <summary> |
|
/// Size of this element, or -1. |
|
/// </summary> |
|
public int Size = -1; |
|
|
|
/// <summary> |
|
/// True if this is the last element in an object file. |
|
/// </summary> |
|
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; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// An atomic class that loads and parses a given map file. |
|
/// </summary> |
|
public class MapFileLoader |
|
{ |
|
ArrayList Elements; |
|
ArrayList Modules; |
|
|
|
/// <summary> |
|
/// Regular expression to break mapfile elements up: |
|
/// </summary> |
|
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(); |
|
} |
|
|
|
} |
|
}
|
|
|