/symbols/mdb/Mono.CompilerServices.SymbolWriter/MonoSymbolTable.cs

http://github.com/jbevain/cecil · C# · 1446 lines · 1138 code · 242 blank · 66 comment · 147 complexity · aa6670851b3da998f784e65a4c930eb4 MD5 · raw file

  1. //
  2. // Mono.CSharp.Debugger/MonoSymbolTable.cs
  3. //
  4. // Author:
  5. // Martin Baulig (martin@ximian.com)
  6. //
  7. // (C) 2002 Ximian, Inc. http://www.ximian.com
  8. //
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining
  11. // a copy of this software and associated documentation files (the
  12. // "Software"), to deal in the Software without restriction, including
  13. // without limitation the rights to use, copy, modify, merge, publish,
  14. // distribute, sublicense, and/or sell copies of the Software, and to
  15. // permit persons to whom the Software is furnished to do so, subject to
  16. // the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be
  19. // included in all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  25. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  26. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  27. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. //
  29. using System;
  30. using System.Security.Cryptography;
  31. using System.Collections.Generic;
  32. using System.Text;
  33. using System.IO;
  34. //
  35. // Parts which are actually written into the symbol file are marked with
  36. //
  37. // #region This is actually written to the symbol file
  38. // #endregion
  39. //
  40. // Please do not modify these regions without previously talking to me.
  41. //
  42. // All changes to the file format must be synchronized in several places:
  43. //
  44. // a) The fields in these regions (and their order) must match the actual
  45. // contents of the symbol file.
  46. //
  47. // This helps people to understand the symbol file format without reading
  48. // too much source code, ie. you look at the appropriate region and then
  49. // you know what's actually in the file.
  50. //
  51. // It is also required to help me enforce b).
  52. //
  53. // b) The regions must be kept in sync with the unmanaged code in
  54. // mono/metadata/debug-mono-symfile.h
  55. //
  56. // When making changes to the file format, you must also increase two version
  57. // numbers:
  58. //
  59. // i) OffsetTable.Version in this file.
  60. // ii) MONO_SYMBOL_FILE_VERSION in mono/metadata/debug-mono-symfile.h
  61. //
  62. // After doing so, recompile everything, including the debugger. Symbol files
  63. // with different versions are incompatible to each other and the debugger and
  64. // the runtime enfore this, so you need to recompile all your assemblies after
  65. // changing the file format.
  66. //
  67. namespace Mono.CompilerServices.SymbolWriter
  68. {
  69. public class OffsetTable
  70. {
  71. public const int MajorVersion = 50;
  72. public const int MinorVersion = 0;
  73. public const long Magic = 0x45e82623fd7fa614;
  74. #region This is actually written to the symbol file
  75. public int TotalFileSize;
  76. public int DataSectionOffset;
  77. public int DataSectionSize;
  78. public int CompileUnitCount;
  79. public int CompileUnitTableOffset;
  80. public int CompileUnitTableSize;
  81. public int SourceCount;
  82. public int SourceTableOffset;
  83. public int SourceTableSize;
  84. public int MethodCount;
  85. public int MethodTableOffset;
  86. public int MethodTableSize;
  87. public int TypeCount;
  88. public int AnonymousScopeCount;
  89. public int AnonymousScopeTableOffset;
  90. public int AnonymousScopeTableSize;
  91. [Flags]
  92. public enum Flags
  93. {
  94. IsAspxSource = 1,
  95. WindowsFileNames = 2
  96. }
  97. public Flags FileFlags;
  98. public int LineNumberTable_LineBase = LineNumberTable.Default_LineBase;
  99. public int LineNumberTable_LineRange = LineNumberTable.Default_LineRange;
  100. public int LineNumberTable_OpcodeBase = LineNumberTable.Default_OpcodeBase;
  101. #endregion
  102. internal OffsetTable ()
  103. {
  104. #if !NET_CORE
  105. int platform = (int) Environment.OSVersion.Platform;
  106. if ((platform != 4) && (platform != 128))
  107. FileFlags |= Flags.WindowsFileNames;
  108. #endif
  109. }
  110. internal OffsetTable (BinaryReader reader, int major_version, int minor_version)
  111. {
  112. TotalFileSize = reader.ReadInt32 ();
  113. DataSectionOffset = reader.ReadInt32 ();
  114. DataSectionSize = reader.ReadInt32 ();
  115. CompileUnitCount = reader.ReadInt32 ();
  116. CompileUnitTableOffset = reader.ReadInt32 ();
  117. CompileUnitTableSize = reader.ReadInt32 ();
  118. SourceCount = reader.ReadInt32 ();
  119. SourceTableOffset = reader.ReadInt32 ();
  120. SourceTableSize = reader.ReadInt32 ();
  121. MethodCount = reader.ReadInt32 ();
  122. MethodTableOffset = reader.ReadInt32 ();
  123. MethodTableSize = reader.ReadInt32 ();
  124. TypeCount = reader.ReadInt32 ();
  125. AnonymousScopeCount = reader.ReadInt32 ();
  126. AnonymousScopeTableOffset = reader.ReadInt32 ();
  127. AnonymousScopeTableSize = reader.ReadInt32 ();
  128. LineNumberTable_LineBase = reader.ReadInt32 ();
  129. LineNumberTable_LineRange = reader.ReadInt32 ();
  130. LineNumberTable_OpcodeBase = reader.ReadInt32 ();
  131. FileFlags = (Flags) reader.ReadInt32 ();
  132. }
  133. internal void Write (BinaryWriter bw, int major_version, int minor_version)
  134. {
  135. bw.Write (TotalFileSize);
  136. bw.Write (DataSectionOffset);
  137. bw.Write (DataSectionSize);
  138. bw.Write (CompileUnitCount);
  139. bw.Write (CompileUnitTableOffset);
  140. bw.Write (CompileUnitTableSize);
  141. bw.Write (SourceCount);
  142. bw.Write (SourceTableOffset);
  143. bw.Write (SourceTableSize);
  144. bw.Write (MethodCount);
  145. bw.Write (MethodTableOffset);
  146. bw.Write (MethodTableSize);
  147. bw.Write (TypeCount);
  148. bw.Write (AnonymousScopeCount);
  149. bw.Write (AnonymousScopeTableOffset);
  150. bw.Write (AnonymousScopeTableSize);
  151. bw.Write (LineNumberTable_LineBase);
  152. bw.Write (LineNumberTable_LineRange);
  153. bw.Write (LineNumberTable_OpcodeBase);
  154. bw.Write ((int) FileFlags);
  155. }
  156. public override string ToString ()
  157. {
  158. return String.Format (
  159. "OffsetTable [{0} - {1}:{2} - {3}:{4}:{5} - {6}:{7}:{8} - {9}]",
  160. TotalFileSize, DataSectionOffset, DataSectionSize, SourceCount,
  161. SourceTableOffset, SourceTableSize, MethodCount, MethodTableOffset,
  162. MethodTableSize, TypeCount);
  163. }
  164. }
  165. public class LineNumberEntry
  166. {
  167. #region This is actually written to the symbol file
  168. public readonly int Row;
  169. public int Column;
  170. public int EndRow, EndColumn;
  171. public readonly int File;
  172. public readonly int Offset;
  173. public readonly bool IsHidden; // Obsolete is never used
  174. #endregion
  175. public sealed class LocationComparer : IComparer<LineNumberEntry>
  176. {
  177. public static readonly LocationComparer Default = new LocationComparer ();
  178. public int Compare (LineNumberEntry l1, LineNumberEntry l2)
  179. {
  180. return l1.Row == l2.Row ?
  181. l1.Column.CompareTo (l2.Column) :
  182. l1.Row.CompareTo (l2.Row);
  183. }
  184. }
  185. public static readonly LineNumberEntry Null = new LineNumberEntry (0, 0, 0, 0);
  186. public LineNumberEntry (int file, int row, int column, int offset)
  187. : this (file, row, column, offset, false)
  188. {
  189. }
  190. public LineNumberEntry (int file, int row, int offset)
  191. : this (file, row, -1, offset, false)
  192. {
  193. }
  194. public LineNumberEntry (int file, int row, int column, int offset, bool is_hidden)
  195. : this (file, row, column, -1, -1, offset, is_hidden)
  196. {
  197. }
  198. public LineNumberEntry (int file, int row, int column, int end_row, int end_column, int offset, bool is_hidden)
  199. {
  200. this.File = file;
  201. this.Row = row;
  202. this.Column = column;
  203. this.EndRow = end_row;
  204. this.EndColumn = end_column;
  205. this.Offset = offset;
  206. this.IsHidden = is_hidden;
  207. }
  208. public override string ToString ()
  209. {
  210. return String.Format ("[Line {0}:{1},{2}-{3},{4}:{5}]", File, Row, Column, EndRow, EndColumn, Offset);
  211. }
  212. }
  213. public class CodeBlockEntry
  214. {
  215. public int Index;
  216. #region This is actually written to the symbol file
  217. public int Parent;
  218. public Type BlockType;
  219. public int StartOffset;
  220. public int EndOffset;
  221. #endregion
  222. public enum Type {
  223. Lexical = 1,
  224. CompilerGenerated = 2,
  225. IteratorBody = 3,
  226. IteratorDispatcher = 4
  227. }
  228. public CodeBlockEntry (int index, int parent, Type type, int start_offset)
  229. {
  230. this.Index = index;
  231. this.Parent = parent;
  232. this.BlockType = type;
  233. this.StartOffset = start_offset;
  234. }
  235. internal CodeBlockEntry (int index, MyBinaryReader reader)
  236. {
  237. this.Index = index;
  238. int type_flag = reader.ReadLeb128 ();
  239. BlockType = (Type) (type_flag & 0x3f);
  240. this.Parent = reader.ReadLeb128 ();
  241. this.StartOffset = reader.ReadLeb128 ();
  242. this.EndOffset = reader.ReadLeb128 ();
  243. /* Reserved for future extensions. */
  244. if ((type_flag & 0x40) != 0) {
  245. int data_size = reader.ReadInt16 ();
  246. reader.BaseStream.Position += data_size;
  247. }
  248. }
  249. public void Close (int end_offset)
  250. {
  251. this.EndOffset = end_offset;
  252. }
  253. internal void Write (MyBinaryWriter bw)
  254. {
  255. bw.WriteLeb128 ((int) BlockType);
  256. bw.WriteLeb128 (Parent);
  257. bw.WriteLeb128 (StartOffset);
  258. bw.WriteLeb128 (EndOffset);
  259. }
  260. public override string ToString ()
  261. {
  262. return String.Format ("[CodeBlock {0}:{1}:{2}:{3}:{4}]",
  263. Index, Parent, BlockType, StartOffset, EndOffset);
  264. }
  265. }
  266. public struct LocalVariableEntry
  267. {
  268. #region This is actually written to the symbol file
  269. public readonly int Index;
  270. public readonly string Name;
  271. public readonly int BlockIndex;
  272. #endregion
  273. public LocalVariableEntry (int index, string name, int block)
  274. {
  275. this.Index = index;
  276. this.Name = name;
  277. this.BlockIndex = block;
  278. }
  279. internal LocalVariableEntry (MonoSymbolFile file, MyBinaryReader reader)
  280. {
  281. Index = reader.ReadLeb128 ();
  282. Name = reader.ReadString ();
  283. BlockIndex = reader.ReadLeb128 ();
  284. }
  285. internal void Write (MonoSymbolFile file, MyBinaryWriter bw)
  286. {
  287. bw.WriteLeb128 (Index);
  288. bw.Write (Name);
  289. bw.WriteLeb128 (BlockIndex);
  290. }
  291. public override string ToString ()
  292. {
  293. return String.Format ("[LocalVariable {0}:{1}:{2}]",
  294. Name, Index, BlockIndex - 1);
  295. }
  296. }
  297. public struct CapturedVariable
  298. {
  299. #region This is actually written to the symbol file
  300. public readonly string Name;
  301. public readonly string CapturedName;
  302. public readonly CapturedKind Kind;
  303. #endregion
  304. public enum CapturedKind : byte
  305. {
  306. Local,
  307. Parameter,
  308. This
  309. }
  310. public CapturedVariable (string name, string captured_name,
  311. CapturedKind kind)
  312. {
  313. this.Name = name;
  314. this.CapturedName = captured_name;
  315. this.Kind = kind;
  316. }
  317. internal CapturedVariable (MyBinaryReader reader)
  318. {
  319. Name = reader.ReadString ();
  320. CapturedName = reader.ReadString ();
  321. Kind = (CapturedKind) reader.ReadByte ();
  322. }
  323. internal void Write (MyBinaryWriter bw)
  324. {
  325. bw.Write (Name);
  326. bw.Write (CapturedName);
  327. bw.Write ((byte) Kind);
  328. }
  329. public override string ToString ()
  330. {
  331. return String.Format ("[CapturedVariable {0}:{1}:{2}]",
  332. Name, CapturedName, Kind);
  333. }
  334. }
  335. public struct CapturedScope
  336. {
  337. #region This is actually written to the symbol file
  338. public readonly int Scope;
  339. public readonly string CapturedName;
  340. #endregion
  341. public CapturedScope (int scope, string captured_name)
  342. {
  343. this.Scope = scope;
  344. this.CapturedName = captured_name;
  345. }
  346. internal CapturedScope (MyBinaryReader reader)
  347. {
  348. Scope = reader.ReadLeb128 ();
  349. CapturedName = reader.ReadString ();
  350. }
  351. internal void Write (MyBinaryWriter bw)
  352. {
  353. bw.WriteLeb128 (Scope);
  354. bw.Write (CapturedName);
  355. }
  356. public override string ToString ()
  357. {
  358. return String.Format ("[CapturedScope {0}:{1}]",
  359. Scope, CapturedName);
  360. }
  361. }
  362. public struct ScopeVariable
  363. {
  364. #region This is actually written to the symbol file
  365. public readonly int Scope;
  366. public readonly int Index;
  367. #endregion
  368. public ScopeVariable (int scope, int index)
  369. {
  370. this.Scope = scope;
  371. this.Index = index;
  372. }
  373. internal ScopeVariable (MyBinaryReader reader)
  374. {
  375. Scope = reader.ReadLeb128 ();
  376. Index = reader.ReadLeb128 ();
  377. }
  378. internal void Write (MyBinaryWriter bw)
  379. {
  380. bw.WriteLeb128 (Scope);
  381. bw.WriteLeb128 (Index);
  382. }
  383. public override string ToString ()
  384. {
  385. return String.Format ("[ScopeVariable {0}:{1}]", Scope, Index);
  386. }
  387. }
  388. public class AnonymousScopeEntry
  389. {
  390. #region This is actually written to the symbol file
  391. public readonly int ID;
  392. #endregion
  393. List<CapturedVariable> captured_vars = new List<CapturedVariable> ();
  394. List<CapturedScope> captured_scopes = new List<CapturedScope> ();
  395. public AnonymousScopeEntry (int id)
  396. {
  397. this.ID = id;
  398. }
  399. internal AnonymousScopeEntry (MyBinaryReader reader)
  400. {
  401. ID = reader.ReadLeb128 ();
  402. int num_captured_vars = reader.ReadLeb128 ();
  403. for (int i = 0; i < num_captured_vars; i++)
  404. captured_vars.Add (new CapturedVariable (reader));
  405. int num_captured_scopes = reader.ReadLeb128 ();
  406. for (int i = 0; i < num_captured_scopes; i++)
  407. captured_scopes.Add (new CapturedScope (reader));
  408. }
  409. internal void AddCapturedVariable (string name, string captured_name,
  410. CapturedVariable.CapturedKind kind)
  411. {
  412. captured_vars.Add (new CapturedVariable (name, captured_name, kind));
  413. }
  414. public CapturedVariable[] CapturedVariables {
  415. get {
  416. CapturedVariable[] retval = new CapturedVariable [captured_vars.Count];
  417. captured_vars.CopyTo (retval, 0);
  418. return retval;
  419. }
  420. }
  421. internal void AddCapturedScope (int scope, string captured_name)
  422. {
  423. captured_scopes.Add (new CapturedScope (scope, captured_name));
  424. }
  425. public CapturedScope[] CapturedScopes {
  426. get {
  427. CapturedScope[] retval = new CapturedScope [captured_scopes.Count];
  428. captured_scopes.CopyTo (retval, 0);
  429. return retval;
  430. }
  431. }
  432. internal void Write (MyBinaryWriter bw)
  433. {
  434. bw.WriteLeb128 (ID);
  435. bw.WriteLeb128 (captured_vars.Count);
  436. foreach (CapturedVariable cv in captured_vars)
  437. cv.Write (bw);
  438. bw.WriteLeb128 (captured_scopes.Count);
  439. foreach (CapturedScope cs in captured_scopes)
  440. cs.Write (bw);
  441. }
  442. public override string ToString ()
  443. {
  444. return String.Format ("[AnonymousScope {0}]", ID);
  445. }
  446. }
  447. public class CompileUnitEntry : ICompileUnit
  448. {
  449. #region This is actually written to the symbol file
  450. public readonly int Index;
  451. int DataOffset;
  452. #endregion
  453. MonoSymbolFile file;
  454. SourceFileEntry source;
  455. List<SourceFileEntry> include_files;
  456. List<NamespaceEntry> namespaces;
  457. bool creating;
  458. public static int Size {
  459. get { return 8; }
  460. }
  461. CompileUnitEntry ICompileUnit.Entry {
  462. get { return this; }
  463. }
  464. public CompileUnitEntry (MonoSymbolFile file, SourceFileEntry source)
  465. {
  466. this.file = file;
  467. this.source = source;
  468. this.Index = file.AddCompileUnit (this);
  469. creating = true;
  470. namespaces = new List<NamespaceEntry> ();
  471. }
  472. public void AddFile (SourceFileEntry file)
  473. {
  474. if (!creating)
  475. throw new InvalidOperationException ();
  476. if (include_files == null)
  477. include_files = new List<SourceFileEntry> ();
  478. include_files.Add (file);
  479. }
  480. public SourceFileEntry SourceFile {
  481. get {
  482. if (creating)
  483. return source;
  484. ReadData ();
  485. return source;
  486. }
  487. }
  488. public int DefineNamespace (string name, string[] using_clauses, int parent)
  489. {
  490. if (!creating)
  491. throw new InvalidOperationException ();
  492. int index = file.GetNextNamespaceIndex ();
  493. NamespaceEntry ns = new NamespaceEntry (name, index, using_clauses, parent);
  494. namespaces.Add (ns);
  495. return index;
  496. }
  497. internal void WriteData (MyBinaryWriter bw)
  498. {
  499. DataOffset = (int) bw.BaseStream.Position;
  500. bw.WriteLeb128 (source.Index);
  501. int count_includes = include_files != null ? include_files.Count : 0;
  502. bw.WriteLeb128 (count_includes);
  503. if (include_files != null) {
  504. foreach (SourceFileEntry entry in include_files)
  505. bw.WriteLeb128 (entry.Index);
  506. }
  507. bw.WriteLeb128 (namespaces.Count);
  508. foreach (NamespaceEntry ns in namespaces)
  509. ns.Write (file, bw);
  510. }
  511. internal void Write (BinaryWriter bw)
  512. {
  513. bw.Write (Index);
  514. bw.Write (DataOffset);
  515. }
  516. internal CompileUnitEntry (MonoSymbolFile file, MyBinaryReader reader)
  517. {
  518. this.file = file;
  519. Index = reader.ReadInt32 ();
  520. DataOffset = reader.ReadInt32 ();
  521. }
  522. public void ReadAll ()
  523. {
  524. ReadData ();
  525. }
  526. void ReadData ()
  527. {
  528. if (creating)
  529. throw new InvalidOperationException ();
  530. lock (file) {
  531. if (namespaces != null)
  532. return;
  533. MyBinaryReader reader = file.BinaryReader;
  534. int old_pos = (int) reader.BaseStream.Position;
  535. reader.BaseStream.Position = DataOffset;
  536. int source_idx = reader.ReadLeb128 ();
  537. source = file.GetSourceFile (source_idx);
  538. int count_includes = reader.ReadLeb128 ();
  539. if (count_includes > 0) {
  540. include_files = new List<SourceFileEntry> ();
  541. for (int i = 0; i < count_includes; i++)
  542. include_files.Add (file.GetSourceFile (reader.ReadLeb128 ()));
  543. }
  544. int count_ns = reader.ReadLeb128 ();
  545. namespaces = new List<NamespaceEntry> ();
  546. for (int i = 0; i < count_ns; i ++)
  547. namespaces.Add (new NamespaceEntry (file, reader));
  548. reader.BaseStream.Position = old_pos;
  549. }
  550. }
  551. public NamespaceEntry[] Namespaces {
  552. get {
  553. ReadData ();
  554. NamespaceEntry[] retval = new NamespaceEntry [namespaces.Count];
  555. namespaces.CopyTo (retval, 0);
  556. return retval;
  557. }
  558. }
  559. public SourceFileEntry[] IncludeFiles {
  560. get {
  561. ReadData ();
  562. if (include_files == null)
  563. return new SourceFileEntry [0];
  564. SourceFileEntry[] retval = new SourceFileEntry [include_files.Count];
  565. include_files.CopyTo (retval, 0);
  566. return retval;
  567. }
  568. }
  569. }
  570. public class SourceFileEntry
  571. {
  572. #region This is actually written to the symbol file
  573. public readonly int Index;
  574. int DataOffset;
  575. #endregion
  576. MonoSymbolFile file;
  577. string file_name;
  578. byte[] guid;
  579. byte[] hash;
  580. bool creating;
  581. bool auto_generated;
  582. readonly string sourceFile;
  583. public static int Size {
  584. get { return 8; }
  585. }
  586. public SourceFileEntry (MonoSymbolFile file, string file_name)
  587. {
  588. this.file = file;
  589. this.file_name = file_name;
  590. this.Index = file.AddSource (this);
  591. creating = true;
  592. }
  593. public SourceFileEntry (MonoSymbolFile file, string sourceFile, byte [] guid, byte [] checksum)
  594. : this (file, sourceFile, sourceFile, guid, checksum)
  595. {
  596. }
  597. public SourceFileEntry (MonoSymbolFile file, string fileName, string sourceFile, byte[] guid, byte[] checksum)
  598. : this (file, fileName)
  599. {
  600. this.guid = guid;
  601. this.hash = checksum;
  602. this.sourceFile = sourceFile;
  603. }
  604. public byte[] Checksum {
  605. get {
  606. return hash;
  607. }
  608. }
  609. internal void WriteData (MyBinaryWriter bw)
  610. {
  611. DataOffset = (int) bw.BaseStream.Position;
  612. bw.Write (file_name);
  613. if (guid == null)
  614. guid = new byte[16];
  615. if (hash == null) {
  616. try {
  617. using (FileStream fs = new FileStream (sourceFile, FileMode.Open, FileAccess.Read)) {
  618. MD5 md5 = MD5.Create ();
  619. hash = md5.ComputeHash (fs);
  620. }
  621. } catch {
  622. hash = new byte [16];
  623. }
  624. }
  625. bw.Write (guid);
  626. bw.Write (hash);
  627. bw.Write ((byte) (auto_generated ? 1 : 0));
  628. }
  629. internal void Write (BinaryWriter bw)
  630. {
  631. bw.Write (Index);
  632. bw.Write (DataOffset);
  633. }
  634. internal SourceFileEntry (MonoSymbolFile file, MyBinaryReader reader)
  635. {
  636. this.file = file;
  637. Index = reader.ReadInt32 ();
  638. DataOffset = reader.ReadInt32 ();
  639. int old_pos = (int) reader.BaseStream.Position;
  640. reader.BaseStream.Position = DataOffset;
  641. sourceFile = file_name = reader.ReadString ();
  642. guid = reader.ReadBytes (16);
  643. hash = reader.ReadBytes (16);
  644. auto_generated = reader.ReadByte () == 1;
  645. reader.BaseStream.Position = old_pos;
  646. }
  647. public string FileName {
  648. get { return file_name; }
  649. set { file_name = value; }
  650. }
  651. public bool AutoGenerated {
  652. get { return auto_generated; }
  653. }
  654. public void SetAutoGenerated ()
  655. {
  656. if (!creating)
  657. throw new InvalidOperationException ();
  658. auto_generated = true;
  659. file.OffsetTable.FileFlags |= OffsetTable.Flags.IsAspxSource;
  660. }
  661. public bool CheckChecksum ()
  662. {
  663. try {
  664. using (FileStream fs = new FileStream (sourceFile, FileMode.Open)) {
  665. MD5 md5 = MD5.Create ();
  666. byte[] data = md5.ComputeHash (fs);
  667. for (int i = 0; i < 16; i++)
  668. if (data [i] != hash [i])
  669. return false;
  670. return true;
  671. }
  672. } catch {
  673. return false;
  674. }
  675. }
  676. public override string ToString ()
  677. {
  678. return String.Format ("SourceFileEntry ({0}:{1})", Index, DataOffset);
  679. }
  680. }
  681. public class LineNumberTable
  682. {
  683. protected LineNumberEntry[] _line_numbers;
  684. public LineNumberEntry[] LineNumbers {
  685. get { return _line_numbers; }
  686. }
  687. public readonly int LineBase;
  688. public readonly int LineRange;
  689. public readonly byte OpcodeBase;
  690. public readonly int MaxAddressIncrement;
  691. #region Configurable constants
  692. public const int Default_LineBase = -1;
  693. public const int Default_LineRange = 8;
  694. public const byte Default_OpcodeBase = 9;
  695. #endregion
  696. public const byte DW_LNS_copy = 1;
  697. public const byte DW_LNS_advance_pc = 2;
  698. public const byte DW_LNS_advance_line = 3;
  699. public const byte DW_LNS_set_file = 4;
  700. public const byte DW_LNS_const_add_pc = 8;
  701. public const byte DW_LNE_end_sequence = 1;
  702. // MONO extensions.
  703. public const byte DW_LNE_MONO_negate_is_hidden = 0x40;
  704. internal const byte DW_LNE_MONO__extensions_start = 0x40;
  705. internal const byte DW_LNE_MONO__extensions_end = 0x7f;
  706. protected LineNumberTable (MonoSymbolFile file)
  707. {
  708. this.LineBase = file.OffsetTable.LineNumberTable_LineBase;
  709. this.LineRange = file.OffsetTable.LineNumberTable_LineRange;
  710. this.OpcodeBase = (byte) file.OffsetTable.LineNumberTable_OpcodeBase;
  711. this.MaxAddressIncrement = (255 - OpcodeBase) / LineRange;
  712. }
  713. internal LineNumberTable (MonoSymbolFile file, LineNumberEntry[] lines)
  714. : this (file)
  715. {
  716. this._line_numbers = lines;
  717. }
  718. internal void Write (MonoSymbolFile file, MyBinaryWriter bw, bool hasColumnsInfo, bool hasEndInfo)
  719. {
  720. int start = (int) bw.BaseStream.Position;
  721. bool last_is_hidden = false;
  722. int last_line = 1, last_offset = 0, last_file = 1;
  723. for (int i = 0; i < LineNumbers.Length; i++) {
  724. int line_inc = LineNumbers [i].Row - last_line;
  725. int offset_inc = LineNumbers [i].Offset - last_offset;
  726. if (LineNumbers [i].File != last_file) {
  727. bw.Write (DW_LNS_set_file);
  728. bw.WriteLeb128 (LineNumbers [i].File);
  729. last_file = LineNumbers [i].File;
  730. }
  731. if (LineNumbers [i].IsHidden != last_is_hidden) {
  732. bw.Write ((byte) 0);
  733. bw.Write ((byte) 1);
  734. bw.Write (DW_LNE_MONO_negate_is_hidden);
  735. last_is_hidden = LineNumbers [i].IsHidden;
  736. }
  737. if (offset_inc >= MaxAddressIncrement) {
  738. if (offset_inc < 2 * MaxAddressIncrement) {
  739. bw.Write (DW_LNS_const_add_pc);
  740. offset_inc -= MaxAddressIncrement;
  741. } else {
  742. bw.Write (DW_LNS_advance_pc);
  743. bw.WriteLeb128 (offset_inc);
  744. offset_inc = 0;
  745. }
  746. }
  747. if ((line_inc < LineBase) || (line_inc >= LineBase + LineRange)) {
  748. bw.Write (DW_LNS_advance_line);
  749. bw.WriteLeb128 (line_inc);
  750. if (offset_inc != 0) {
  751. bw.Write (DW_LNS_advance_pc);
  752. bw.WriteLeb128 (offset_inc);
  753. }
  754. bw.Write (DW_LNS_copy);
  755. } else {
  756. byte opcode;
  757. opcode = (byte) (line_inc - LineBase + (LineRange * offset_inc) +
  758. OpcodeBase);
  759. bw.Write (opcode);
  760. }
  761. last_line = LineNumbers [i].Row;
  762. last_offset = LineNumbers [i].Offset;
  763. }
  764. bw.Write ((byte) 0);
  765. bw.Write ((byte) 1);
  766. bw.Write (DW_LNE_end_sequence);
  767. if (hasColumnsInfo) {
  768. for (int i = 0; i < LineNumbers.Length; i++) {
  769. var ln = LineNumbers [i];
  770. if (ln.Row >= 0)
  771. bw.WriteLeb128 (ln.Column);
  772. }
  773. }
  774. if (hasEndInfo) {
  775. for (int i = 0; i < LineNumbers.Length; i++) {
  776. var ln = LineNumbers [i];
  777. if (ln.EndRow == -1 || ln.EndColumn == -1 || ln.Row > ln.EndRow) {
  778. bw.WriteLeb128 (0xffffff);
  779. } else {
  780. bw.WriteLeb128 (ln.EndRow - ln.Row);
  781. bw.WriteLeb128 (ln.EndColumn);
  782. }
  783. }
  784. }
  785. file.ExtendedLineNumberSize += (int) bw.BaseStream.Position - start;
  786. }
  787. internal static LineNumberTable Read (MonoSymbolFile file, MyBinaryReader br, bool readColumnsInfo, bool readEndInfo)
  788. {
  789. LineNumberTable lnt = new LineNumberTable (file);
  790. lnt.DoRead (file, br, readColumnsInfo, readEndInfo);
  791. return lnt;
  792. }
  793. void DoRead (MonoSymbolFile file, MyBinaryReader br, bool includesColumns, bool includesEnds)
  794. {
  795. var lines = new List<LineNumberEntry> ();
  796. bool is_hidden = false, modified = false;
  797. int stm_line = 1, stm_offset = 0, stm_file = 1;
  798. while (true) {
  799. byte opcode = br.ReadByte ();
  800. if (opcode == 0) {
  801. byte size = br.ReadByte ();
  802. long end_pos = br.BaseStream.Position + size;
  803. opcode = br.ReadByte ();
  804. if (opcode == DW_LNE_end_sequence) {
  805. if (modified)
  806. lines.Add (new LineNumberEntry (
  807. stm_file, stm_line, -1, stm_offset, is_hidden));
  808. break;
  809. } else if (opcode == DW_LNE_MONO_negate_is_hidden) {
  810. is_hidden = !is_hidden;
  811. modified = true;
  812. } else if ((opcode >= DW_LNE_MONO__extensions_start) &&
  813. (opcode <= DW_LNE_MONO__extensions_end)) {
  814. ; // reserved for future extensions
  815. } else {
  816. throw new MonoSymbolFileException ("Unknown extended opcode {0:x}", opcode);
  817. }
  818. br.BaseStream.Position = end_pos;
  819. continue;
  820. } else if (opcode < OpcodeBase) {
  821. switch (opcode) {
  822. case DW_LNS_copy:
  823. lines.Add (new LineNumberEntry (
  824. stm_file, stm_line, -1, stm_offset, is_hidden));
  825. modified = false;
  826. break;
  827. case DW_LNS_advance_pc:
  828. stm_offset += br.ReadLeb128 ();
  829. modified = true;
  830. break;
  831. case DW_LNS_advance_line:
  832. stm_line += br.ReadLeb128 ();
  833. modified = true;
  834. break;
  835. case DW_LNS_set_file:
  836. stm_file = br.ReadLeb128 ();
  837. modified = true;
  838. break;
  839. case DW_LNS_const_add_pc:
  840. stm_offset += MaxAddressIncrement;
  841. modified = true;
  842. break;
  843. default:
  844. throw new MonoSymbolFileException (
  845. "Unknown standard opcode {0:x} in LNT",
  846. opcode);
  847. }
  848. } else {
  849. opcode -= OpcodeBase;
  850. stm_offset += opcode / LineRange;
  851. stm_line += LineBase + (opcode % LineRange);
  852. lines.Add (new LineNumberEntry (
  853. stm_file, stm_line, -1, stm_offset, is_hidden));
  854. modified = false;
  855. }
  856. }
  857. _line_numbers = lines.ToArray ();
  858. if (includesColumns) {
  859. for (int i = 0; i < _line_numbers.Length; ++i) {
  860. var ln = _line_numbers[i];
  861. if (ln.Row >= 0)
  862. ln.Column = br.ReadLeb128 ();
  863. }
  864. }
  865. if (includesEnds) {
  866. for (int i = 0; i < _line_numbers.Length; ++i) {
  867. var ln = _line_numbers[i];
  868. int row = br.ReadLeb128 ();
  869. if (row == 0xffffff) {
  870. ln.EndRow = -1;
  871. ln.EndColumn = -1;
  872. } else {
  873. ln.EndRow = ln.Row + row;
  874. ln.EndColumn = br.ReadLeb128 ();
  875. }
  876. }
  877. }
  878. }
  879. public bool GetMethodBounds (out LineNumberEntry start, out LineNumberEntry end)
  880. {
  881. if (_line_numbers.Length > 1) {
  882. start = _line_numbers [0];
  883. end = _line_numbers [_line_numbers.Length - 1];
  884. return true;
  885. }
  886. start = LineNumberEntry.Null;
  887. end = LineNumberEntry.Null;
  888. return false;
  889. }
  890. }
  891. public class MethodEntry : IComparable
  892. {
  893. #region This is actually written to the symbol file
  894. public readonly int CompileUnitIndex;
  895. public readonly int Token;
  896. public readonly int NamespaceID;
  897. int DataOffset;
  898. int LocalVariableTableOffset;
  899. int LineNumberTableOffset;
  900. int CodeBlockTableOffset;
  901. int ScopeVariableTableOffset;
  902. int RealNameOffset;
  903. Flags flags;
  904. #endregion
  905. int index;
  906. public Flags MethodFlags {
  907. get { return flags; }
  908. }
  909. public readonly CompileUnitEntry CompileUnit;
  910. LocalVariableEntry[] locals;
  911. CodeBlockEntry[] code_blocks;
  912. ScopeVariable[] scope_vars;
  913. LineNumberTable lnt;
  914. string real_name;
  915. public readonly MonoSymbolFile SymbolFile;
  916. public int Index {
  917. get { return index; }
  918. set { index = value; }
  919. }
  920. [Flags]
  921. public enum Flags
  922. {
  923. LocalNamesAmbiguous = 1,
  924. ColumnsInfoIncluded = 1 << 1,
  925. EndInfoIncluded = 1 << 2
  926. }
  927. public const int Size = 12;
  928. internal MethodEntry (MonoSymbolFile file, MyBinaryReader reader, int index)
  929. {
  930. this.SymbolFile = file;
  931. this.index = index;
  932. Token = reader.ReadInt32 ();
  933. DataOffset = reader.ReadInt32 ();
  934. LineNumberTableOffset = reader.ReadInt32 ();
  935. long old_pos = reader.BaseStream.Position;
  936. reader.BaseStream.Position = DataOffset;
  937. CompileUnitIndex = reader.ReadLeb128 ();
  938. LocalVariableTableOffset = reader.ReadLeb128 ();
  939. NamespaceID = reader.ReadLeb128 ();
  940. CodeBlockTableOffset = reader.ReadLeb128 ();
  941. ScopeVariableTableOffset = reader.ReadLeb128 ();
  942. RealNameOffset = reader.ReadLeb128 ();
  943. flags = (Flags) reader.ReadLeb128 ();
  944. reader.BaseStream.Position = old_pos;
  945. CompileUnit = file.GetCompileUnit (CompileUnitIndex);
  946. }
  947. internal MethodEntry (MonoSymbolFile file, CompileUnitEntry comp_unit,
  948. int token, ScopeVariable[] scope_vars,
  949. LocalVariableEntry[] locals, LineNumberEntry[] lines,
  950. CodeBlockEntry[] code_blocks, string real_name,
  951. Flags flags, int namespace_id)
  952. {
  953. this.SymbolFile = file;
  954. this.real_name = real_name;
  955. this.locals = locals;
  956. this.code_blocks = code_blocks;
  957. this.scope_vars = scope_vars;
  958. this.flags = flags;
  959. index = -1;
  960. Token = token;
  961. CompileUnitIndex = comp_unit.Index;
  962. CompileUnit = comp_unit;
  963. NamespaceID = namespace_id;
  964. CheckLineNumberTable (lines);
  965. lnt = new LineNumberTable (file, lines);
  966. file.NumLineNumbers += lines.Length;
  967. int num_locals = locals != null ? locals.Length : 0;
  968. if (num_locals <= 32) {
  969. // Most of the time, the O(n^2) factor is actually
  970. // less than the cost of allocating the hash table,
  971. // 32 is a rough number obtained through some testing.
  972. for (int i = 0; i < num_locals; i ++) {
  973. string nm = locals [i].Name;
  974. for (int j = i + 1; j < num_locals; j ++) {
  975. if (locals [j].Name == nm) {
  976. flags |= Flags.LocalNamesAmbiguous;
  977. goto locals_check_done;
  978. }
  979. }
  980. }
  981. locals_check_done :
  982. ;
  983. } else {
  984. var local_names = new Dictionary<string, LocalVariableEntry> ();
  985. foreach (LocalVariableEntry local in locals) {
  986. if (local_names.ContainsKey (local.Name)) {
  987. flags |= Flags.LocalNamesAmbiguous;
  988. break;
  989. }
  990. local_names.Add (local.Name, local);
  991. }
  992. }
  993. }
  994. static void CheckLineNumberTable (LineNumberEntry[] line_numbers)
  995. {
  996. int last_offset = -1;
  997. int last_row = -1;
  998. if (line_numbers == null)
  999. return;
  1000. for (int i = 0; i < line_numbers.Length; i++) {
  1001. LineNumberEntry line = line_numbers [i];
  1002. if (line.Equals (LineNumberEntry.Null))
  1003. throw new MonoSymbolFileException ();
  1004. if (line.Offset < last_offset)
  1005. throw new MonoSymbolFileException ();
  1006. if (line.Offset > last_offset) {
  1007. last_row = line.Row;
  1008. last_offset = line.Offset;
  1009. } else if (line.Row > last_row) {
  1010. last_row = line.Row;
  1011. }
  1012. }
  1013. }
  1014. internal void Write (MyBinaryWriter bw)
  1015. {
  1016. if ((index <= 0) || (DataOffset == 0))
  1017. throw new InvalidOperationException ();
  1018. bw.Write (Token);
  1019. bw.Write (DataOffset);
  1020. bw.Write (LineNumberTableOffset);
  1021. }
  1022. internal void WriteData (MonoSymbolFile file, MyBinaryWriter bw)
  1023. {
  1024. if (index <= 0)
  1025. throw new InvalidOperationException ();
  1026. LocalVariableTableOffset = (int) bw.BaseStream.Position;
  1027. int num_locals = locals != null ? locals.Length : 0;
  1028. bw.WriteLeb128 (num_locals);
  1029. for (int i = 0; i < num_locals; i++)
  1030. locals [i].Write (file, bw);
  1031. file.LocalCount += num_locals;
  1032. CodeBlockTableOffset = (int) bw.BaseStream.Position;
  1033. int num_code_blocks = code_blocks != null ? code_blocks.Length : 0;
  1034. bw.WriteLeb128 (num_code_blocks);
  1035. for (int i = 0; i < num_code_blocks; i++)
  1036. code_blocks [i].Write (bw);
  1037. ScopeVariableTableOffset = (int) bw.BaseStream.Position;
  1038. int num_scope_vars = scope_vars != null ? scope_vars.Length : 0;
  1039. bw.WriteLeb128 (num_scope_vars);
  1040. for (int i = 0; i < num_scope_vars; i++)
  1041. scope_vars [i].Write (bw);
  1042. if (real_name != null) {
  1043. RealNameOffset = (int) bw.BaseStream.Position;
  1044. bw.Write (real_name);
  1045. }
  1046. foreach (var lne in lnt.LineNumbers) {
  1047. if (lne.EndRow != -1 || lne.EndColumn != -1)
  1048. flags |= Flags.EndInfoIncluded;
  1049. }
  1050. LineNumberTableOffset = (int) bw.BaseStream.Position;
  1051. lnt.Write (file, bw, (flags & Flags.ColumnsInfoIncluded) != 0, (flags & Flags.EndInfoIncluded) != 0);
  1052. DataOffset = (int) bw.BaseStream.Position;
  1053. bw.WriteLeb128 (CompileUnitIndex);
  1054. bw.WriteLeb128 (LocalVariableTableOffset);
  1055. bw.WriteLeb128 (NamespaceID);
  1056. bw.WriteLeb128 (CodeBlockTableOffset);
  1057. bw.WriteLeb128 (ScopeVariableTableOffset);
  1058. bw.WriteLeb128 (RealNameOffset);
  1059. bw.WriteLeb128 ((int) flags);
  1060. }
  1061. public void ReadAll ()
  1062. {
  1063. GetLineNumberTable ();
  1064. GetLocals ();
  1065. GetCodeBlocks ();
  1066. GetScopeVariables ();
  1067. GetRealName ();
  1068. }
  1069. public LineNumberTable GetLineNumberTable ()
  1070. {
  1071. lock (SymbolFile) {
  1072. if (lnt != null)
  1073. return lnt;
  1074. if (LineNumberTableOffset == 0)
  1075. return null;
  1076. MyBinaryReader reader = SymbolFile.BinaryReader;
  1077. long old_pos = reader.BaseStream.Position;
  1078. reader.BaseStream.Position = LineNumberTableOffset;
  1079. lnt = LineNumberTable.Read (SymbolFile, reader, (flags & Flags.ColumnsInfoIncluded) != 0, (flags & Flags.EndInfoIncluded) != 0);
  1080. reader.BaseStream.Position = old_pos;
  1081. return lnt;
  1082. }
  1083. }
  1084. public LocalVariableEntry[] GetLocals ()
  1085. {
  1086. lock (SymbolFile) {
  1087. if (locals != null)
  1088. return locals;
  1089. if (LocalVariableTableOffset == 0)
  1090. return null;
  1091. MyBinaryReader reader = SymbolFile.BinaryReader;
  1092. long old_pos = reader.BaseStream.Position;
  1093. reader.BaseStream.Position = LocalVariableTableOffset;
  1094. int num_locals = reader.ReadLeb128 ();
  1095. locals = new LocalVariableEntry [num_locals];
  1096. for (int i = 0; i < num_locals; i++)
  1097. locals [i] = new LocalVariableEntry (SymbolFile, reader);
  1098. reader.BaseStream.Position = old_pos;
  1099. return locals;
  1100. }
  1101. }
  1102. public CodeBlockEntry[] GetCodeBlocks ()
  1103. {
  1104. lock (SymbolFile) {
  1105. if (code_blocks != null)
  1106. return code_blocks;
  1107. if (CodeBlockTableOffset == 0)
  1108. return null;
  1109. MyBinaryReader reader = SymbolFile.BinaryReader;
  1110. long old_pos = reader.BaseStream.Position;
  1111. reader.BaseStream.Position = CodeBlockTableOffset;
  1112. int num_code_blocks = reader.ReadLeb128 ();
  1113. code_blocks = new CodeBlockEntry [num_code_blocks];
  1114. for (int i = 0; i < num_code_blocks; i++)
  1115. code_blocks [i] = new CodeBlockEntry (i, reader);
  1116. reader.BaseStream.Position = old_pos;
  1117. return code_blocks;
  1118. }
  1119. }
  1120. public ScopeVariable[] GetScopeVariables ()
  1121. {
  1122. lock (SymbolFile) {
  1123. if (scope_vars != null)
  1124. return scope_vars;
  1125. if (ScopeVariableTableOffset == 0)
  1126. return null;
  1127. MyBinaryReader reader = SymbolFile.BinaryReader;
  1128. long old_pos = reader.BaseStream.Position;
  1129. reader.BaseStream.Position = ScopeVariableTableOffset;
  1130. int num_scope_vars = reader.ReadLeb128 ();
  1131. scope_vars = new ScopeVariable [num_scope_vars];
  1132. for (int i = 0; i < num_scope_vars; i++)
  1133. scope_vars [i] = new ScopeVariable (reader);
  1134. reader.BaseStream.Position = old_pos;
  1135. return scope_vars;
  1136. }
  1137. }
  1138. public string GetRealName ()
  1139. {
  1140. lock (SymbolFile) {
  1141. if (real_name != null)
  1142. return real_name;
  1143. if (RealNameOffset == 0)
  1144. return null;
  1145. real_name = SymbolFile.BinaryReader.ReadString (RealNameOffset);
  1146. return real_name;
  1147. }
  1148. }
  1149. public int CompareTo (object obj)
  1150. {
  1151. MethodEntry method = (MethodEntry) obj;
  1152. if (method.Token < Token)
  1153. return 1;
  1154. else if (method.Token > Token)
  1155. return -1;
  1156. else
  1157. return 0;
  1158. }
  1159. public override string ToString ()
  1160. {
  1161. return String.Format ("[Method {0}:{1:x}:{2}:{3}]",
  1162. index, Token, CompileUnitIndex, CompileUnit);
  1163. }
  1164. }
  1165. public struct NamespaceEntry
  1166. {
  1167. #region This is actually written to the symbol file
  1168. public readonly string Name;
  1169. public readonly int Index;
  1170. public readonly int Parent;
  1171. public readonly string[] UsingClauses;
  1172. #endregion
  1173. public NamespaceEntry (string name, int index, string[] using_clauses, int parent)
  1174. {
  1175. this.Name = name;
  1176. this.Index = index;
  1177. this.Parent = parent;
  1178. this.UsingClauses = using_clauses != null ? using_clauses : new string [0];
  1179. }
  1180. internal NamespaceEntry (MonoSymbolFile file, MyBinaryReader reader)
  1181. {
  1182. Name = reader.ReadString ();
  1183. Index = reader.ReadLeb128 ();
  1184. Parent = reader.ReadLeb128 ();
  1185. int count = reader.ReadLeb128 ();
  1186. UsingClauses = new string [count];
  1187. for (int i = 0; i < count; i++)
  1188. UsingClauses [i] = reader.ReadString ();
  1189. }
  1190. internal void Write (MonoSymbolFile file, MyBinaryWriter bw)
  1191. {
  1192. bw.Write (Name);
  1193. bw.WriteLeb128 (Index);
  1194. bw.WriteLeb128 (Parent);
  1195. bw.WriteLeb128 (UsingClauses.Length);
  1196. foreach (string uc in UsingClauses)
  1197. bw.Write (uc);
  1198. }
  1199. public override string ToString ()
  1200. {
  1201. return String.Format ("[Namespace {0}:{1}:{2}]", Name, Index, Parent);
  1202. }
  1203. }
  1204. }