PageRenderTime 102ms CodeModel.GetById 22ms app.highlight 69ms RepoModel.GetById 1ms app.codeStats 1ms

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