Team Fortress 2 Source Code as on 22/4/2020
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

  1. using System;
  2. using System.Text.RegularExpressions;
  3. using System.Collections;
  4. using System.IO;
  5. namespace MapSorter
  6. {
  7. public class Element : IComparable
  8. {
  9. /// <summary>
  10. /// Segment this element is in.
  11. /// </summary>
  12. public int Segment;
  13. /// <summary>
  14. /// Base or virtual file address.
  15. /// </summary>
  16. public int Address;
  17. /// <summary>
  18. /// Adjusted relative virtual address.
  19. /// </summary>
  20. public int RVA;
  21. /// <summary>
  22. /// Name of this element.
  23. /// </summary>
  24. public string Text;
  25. /// <summary>
  26. /// Object file this element is located in.
  27. /// </summary>
  28. public string Obj;
  29. /// <summary>
  30. /// Size of this element, or -1.
  31. /// </summary>
  32. public int Size = -1;
  33. /// <summary>
  34. /// True if this is the last element in an object file.
  35. /// </summary>
  36. public bool bCrossObj = false;
  37. public Element( int Segment, int Address, string Text, int RVA, string Obj )
  38. {
  39. this.Segment = Segment;
  40. this.Address = Address;
  41. this.RVA = RVA;
  42. this.Text = Text;
  43. this.Obj = Obj;
  44. }
  45. // Comparable interface:
  46. int System.IComparable.CompareTo( object o )
  47. {
  48. // HACK HACK - sorts according to size if size field is non negative, otherwise sorts by segment then address
  49. Element other = (Element)o;
  50. // Sort by size:
  51. if( other.Size != -1 || Size != -1 )
  52. {
  53. if( Size < other.Size )
  54. return -1;
  55. if( Size > other.Size )
  56. return 1;
  57. return 0;
  58. }
  59. // Sizes aren't defined, sort by Segment then Address:
  60. if( Segment != other.Segment )
  61. {
  62. if( Segment < other.Segment )
  63. return -1;
  64. else
  65. return 0;
  66. }
  67. if( Address < other.Address )
  68. return -1;
  69. else if( Address > other.Address )
  70. return 1;
  71. return 0;
  72. }
  73. }
  74. public class Module : IComparable
  75. {
  76. public string Name;
  77. public int Size;
  78. public Module(string Name, int Size)
  79. {
  80. this.Name = Name;
  81. this.Size = Size;
  82. }
  83. int System.IComparable.CompareTo( object o )
  84. {
  85. Module m = (Module)o;
  86. if( Size < m.Size )
  87. return -1;
  88. if( Size > m.Size )
  89. return 1;
  90. return 0;
  91. }
  92. }
  93. /// <summary>
  94. /// An atomic class that loads and parses a given map file.
  95. /// </summary>
  96. public class MapFileLoader
  97. {
  98. ArrayList Elements;
  99. ArrayList Modules;
  100. /// <summary>
  101. /// Regular expression to break mapfile elements up:
  102. /// </summary>
  103. 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 );
  104. public MapFileLoader( string filename )
  105. {
  106. // Load the element data from the mapfile:
  107. LoadElements( new StreamReader(filename).ReadToEnd() );
  108. // Compute modules and their sizes:
  109. ComputeModules();
  110. }
  111. public void DumpReport()
  112. {
  113. Console.WriteLine("***** Elements by size ascending. (*) = element straddles an .obj file boundary, so the size may not be correct.");
  114. Console.WriteLine();
  115. foreach (Element e in Elements )
  116. {
  117. if( e.Size < 1024 )
  118. continue;
  119. if( e.bCrossObj )
  120. Console.Write("(*)");
  121. Console.WriteLine( e.Size / 1024 + "k : " +e.Obj + " : " + e.Text );
  122. }
  123. Console.WriteLine();
  124. Console.WriteLine();
  125. Console.WriteLine("***** Modules by size, ascending. This is estimated based on elements that don't straddle .obj boundaries.");
  126. Console.WriteLine();
  127. foreach(Module m in Modules )
  128. {
  129. if( m.Size < 1024 )
  130. continue;
  131. Console.WriteLine( m.Size / 1024 + "k : " + m.Name );
  132. }
  133. }
  134. protected void LoadElements( string mapfile )
  135. {
  136. // Match each appropriate line in the map file. The summary entries at the top of each map file are NOT matched by this regex.
  137. MatchCollection matches = ElementRegex.Matches(mapfile);
  138. Elements = new ArrayList();
  139. // Convert each match to an Element type and add them to an array list.
  140. foreach( Match m in matches )
  141. {
  142. Element e = new Element(int.Parse(m.Groups[1].Value,System.Globalization.NumberStyles.AllowHexSpecifier),
  143. int.Parse(m.Groups[2].Value,System.Globalization.NumberStyles.AllowHexSpecifier),
  144. m.Groups[3].Value,
  145. int.Parse(m.Groups[4].Value,System.Globalization.NumberStyles.AllowHexSpecifier),
  146. m.Groups[7].Value);
  147. Elements.Add(e);
  148. }
  149. // Sort the list by address:
  150. Elements.Sort();
  151. Element previous = null;
  152. // Compute estimated sizes for each element in the list:
  153. foreach( Element e in Elements )
  154. {
  155. if( previous != null )
  156. {
  157. if( e.Segment == previous.Segment )
  158. {
  159. previous.Size = e.Address- previous.Address;
  160. // Take note of the symbols that cross object file boundaries:
  161. if( !previous.Obj.Equals(e.Obj) )
  162. {
  163. previous.bCrossObj = true;
  164. }
  165. }
  166. }
  167. previous = e;
  168. }
  169. // Sort the list by size
  170. Elements.Sort();
  171. }
  172. protected void ComputeModules()
  173. {
  174. // Estimate the size of each object file:
  175. Hashtable h = new Hashtable();
  176. foreach(Element e in Elements )
  177. {
  178. if( !h.ContainsKey(e.Obj) )
  179. h.Add(e.Obj,0);
  180. if( !e.bCrossObj )
  181. {
  182. h[e.Obj] = (int)h[e.Obj] + e.Size;
  183. }
  184. }
  185. Modules = new ArrayList();
  186. foreach( string key in h.Keys )
  187. {
  188. Modules.Add( new Module(key, (int)h[key] ));
  189. }
  190. Modules.Sort();
  191. }
  192. }
  193. }