| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643 | 
							- //
 
- // MonoSymbolFile.cs
 
- //
 
- // Authors:
 
- //   Martin Baulig (martin@ximian.com)
 
- //   Marek Safar (marek.safar@gmail.com)
 
- //
 
- // (C) 2003 Ximian, Inc.  http://www.ximian.com
 
- // Copyright (C) 2012 Xamarin Inc (http://www.xamarin.com)
 
- //
 
- //
 
- // Permission is hereby granted, free of charge, to any person obtaining
 
- // a copy of this software and associated documentation files (the
 
- // "Software"), to deal in the Software without restriction, including
 
- // without limitation the rights to use, copy, modify, merge, publish,
 
- // distribute, sublicense, and/or sell copies of the Software, and to
 
- // permit persons to whom the Software is furnished to do so, subject to
 
- // the following conditions:
 
- //
 
- // The above copyright notice and this permission notice shall be
 
- // included in all copies or substantial portions of the Software.
 
- //
 
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
- //
 
- using System;
 
- using System.Reflection;
 
- using System.Collections.Generic;
 
- using System.IO;
 
- namespace ILRuntime.Mono.CompilerServices.SymbolWriter
 
- {
 
- 	public class MonoSymbolFileException : Exception
 
- 	{
 
- 		public MonoSymbolFileException ()
 
- 			: base ()
 
- 		{ }
 
- 		public MonoSymbolFileException (string message, params object[] args)
 
- 			: base (String.Format (message, args))
 
- 		{
 
- 		}
 
- 		public MonoSymbolFileException (string message, Exception innerException)
 
- 			: base (message, innerException)
 
- 		{
 
- 		}
 
- 	}
 
- 	sealed class MyBinaryWriter : BinaryWriter
 
- 	{
 
- 		public MyBinaryWriter (Stream stream)
 
- 			: base (stream)
 
- 		{ }
 
- 		public void WriteLeb128 (int value)
 
- 		{
 
- 			base.Write7BitEncodedInt (value);
 
- 		}
 
- 	}
 
- 	internal class MyBinaryReader : BinaryReader
 
- 	{
 
- 		public MyBinaryReader (Stream stream)
 
- 			: base (stream)
 
- 		{ }
 
- 		public int ReadLeb128 ()
 
- 		{
 
- 			return base.Read7BitEncodedInt ();
 
- 		}
 
- 		public string ReadString (int offset)
 
- 		{
 
- 			long old_pos = BaseStream.Position;
 
- 			BaseStream.Position = offset;
 
- 			string text = ReadString ();
 
- 			BaseStream.Position = old_pos;
 
- 			return text;
 
- 		}
 
- 	}
 
- 	public interface ISourceFile
 
- 	{
 
- 		SourceFileEntry Entry {
 
- 			get;
 
- 		}
 
- 	}
 
- 	public interface ICompileUnit
 
- 	{
 
- 		CompileUnitEntry Entry {
 
- 			get;
 
- 		}
 
- 	}
 
- 	public interface IMethodDef
 
- 	{
 
- 		string Name {
 
- 			get;
 
- 		}
 
- 		int Token {
 
- 			get;
 
- 		}
 
- 	}
 
- 	public class MonoSymbolFile : IDisposable
 
- 	{
 
- 		List<MethodEntry> methods = new List<MethodEntry> ();
 
- 		List<SourceFileEntry> sources = new List<SourceFileEntry> ();
 
- 		List<CompileUnitEntry> comp_units = new List<CompileUnitEntry> ();
 
- 		Dictionary<int, AnonymousScopeEntry> anonymous_scopes;
 
- 		OffsetTable ot;
 
- 		int last_type_index;
 
- 		int last_method_index;
 
- 		int last_namespace_index;
 
- 		public readonly int MajorVersion = OffsetTable.MajorVersion;
 
- 		public readonly int MinorVersion = OffsetTable.MinorVersion;
 
- 		public int NumLineNumbers;
 
- 		public MonoSymbolFile ()
 
- 		{
 
- 			ot = new OffsetTable ();
 
- 		}
 
- 		public int AddSource (SourceFileEntry source)
 
- 		{
 
- 			sources.Add (source);
 
- 			return sources.Count;
 
- 		}
 
- 		public int AddCompileUnit (CompileUnitEntry entry)
 
- 		{
 
- 			comp_units.Add (entry);
 
- 			return comp_units.Count;
 
- 		}
 
- 		public void AddMethod (MethodEntry entry)
 
- 		{
 
- 			methods.Add (entry);
 
- 		}
 
- 		public MethodEntry DefineMethod (CompileUnitEntry comp_unit, int token,
 
- 						 ScopeVariable[] scope_vars, LocalVariableEntry[] locals,
 
- 						 LineNumberEntry[] lines, CodeBlockEntry[] code_blocks,
 
- 						 string real_name, MethodEntry.Flags flags,
 
- 						 int namespace_id)
 
- 		{
 
- 			if (reader != null)
 
- 				throw new InvalidOperationException ();
 
- 			MethodEntry method = new MethodEntry (
 
- 				this, comp_unit, token, scope_vars, locals, lines, code_blocks,
 
- 				real_name, flags, namespace_id);
 
- 			AddMethod (method);
 
- 			return method;
 
- 		}
 
- 		internal void DefineAnonymousScope (int id)
 
- 		{
 
- 			if (reader != null)
 
- 				throw new InvalidOperationException ();
 
- 			if (anonymous_scopes == null)
 
- 				anonymous_scopes = new Dictionary<int, AnonymousScopeEntry>  ();
 
- 			anonymous_scopes.Add (id, new AnonymousScopeEntry (id));
 
- 		}
 
- 		internal void DefineCapturedVariable (int scope_id, string name, string captured_name,
 
- 						      CapturedVariable.CapturedKind kind)
 
- 		{
 
- 			if (reader != null)
 
- 				throw new InvalidOperationException ();
 
- 			AnonymousScopeEntry scope = anonymous_scopes [scope_id];
 
- 			scope.AddCapturedVariable (name, captured_name, kind);
 
- 		}
 
- 		internal void DefineCapturedScope (int scope_id, int id, string captured_name)
 
- 		{
 
- 			if (reader != null)
 
- 				throw new InvalidOperationException ();
 
- 			AnonymousScopeEntry scope = anonymous_scopes [scope_id];
 
- 			scope.AddCapturedScope (id, captured_name);
 
- 		}
 
- 		internal int GetNextTypeIndex ()
 
- 		{
 
- 			return ++last_type_index;
 
- 		}
 
- 		internal int GetNextMethodIndex ()
 
- 		{
 
- 			return ++last_method_index;
 
- 		}
 
- 		internal int GetNextNamespaceIndex ()
 
- 		{
 
- 			return ++last_namespace_index;
 
- 		}
 
- 		void Write (MyBinaryWriter bw, Guid guid)
 
- 		{
 
- 			// Magic number and file version.
 
- 			bw.Write (OffsetTable.Magic);
 
- 			bw.Write (MajorVersion);
 
- 			bw.Write (MinorVersion);
 
- 			bw.Write (guid.ToByteArray ());
 
- 			//
 
- 			// Offsets of file sections; we must write this after we're done
 
- 			// writing the whole file, so we just reserve the space for it here.
 
- 			//
 
- 			long offset_table_offset = bw.BaseStream.Position;
 
- 			ot.Write (bw, MajorVersion, MinorVersion);
 
- 			//
 
- 			// Sort the methods according to their tokens and update their index.
 
- 			//
 
- 			methods.Sort ();
 
- 			for (int i = 0; i < methods.Count; i++)
 
- 				methods [i].Index = i + 1;
 
- 			//
 
- 			// Write data sections.
 
- 			//
 
- 			ot.DataSectionOffset = (int) bw.BaseStream.Position;
 
- 			foreach (SourceFileEntry source in sources)
 
- 				source.WriteData (bw);
 
- 			foreach (CompileUnitEntry comp_unit in comp_units)
 
- 				comp_unit.WriteData (bw);
 
- 			foreach (MethodEntry method in methods)
 
- 				method.WriteData (this, bw);
 
- 			ot.DataSectionSize = (int) bw.BaseStream.Position - ot.DataSectionOffset;
 
- 			//
 
- 			// Write the method index table.
 
- 			//
 
- 			ot.MethodTableOffset = (int) bw.BaseStream.Position;
 
- 			for (int i = 0; i < methods.Count; i++) {
 
- 				MethodEntry entry = methods [i];
 
- 				entry.Write (bw);
 
- 			}
 
- 			ot.MethodTableSize = (int) bw.BaseStream.Position - ot.MethodTableOffset;
 
- 			//
 
- 			// Write source table.
 
- 			//
 
- 			ot.SourceTableOffset = (int) bw.BaseStream.Position;
 
- 			for (int i = 0; i < sources.Count; i++) {
 
- 				SourceFileEntry source = sources [i];
 
- 				source.Write (bw);
 
- 			}
 
- 			ot.SourceTableSize = (int) bw.BaseStream.Position - ot.SourceTableOffset;
 
- 			//
 
- 			// Write compilation unit table.
 
- 			//
 
- 			ot.CompileUnitTableOffset = (int) bw.BaseStream.Position;
 
- 			for (int i = 0; i < comp_units.Count; i++) {
 
- 				CompileUnitEntry unit = comp_units [i];
 
- 				unit.Write (bw);
 
- 			}
 
- 			ot.CompileUnitTableSize = (int) bw.BaseStream.Position - ot.CompileUnitTableOffset;
 
- 			//
 
- 			// Write anonymous scope table.
 
- 			//
 
- 			ot.AnonymousScopeCount = anonymous_scopes != null ? anonymous_scopes.Count : 0;
 
- 			ot.AnonymousScopeTableOffset = (int) bw.BaseStream.Position;
 
- 			if (anonymous_scopes != null) {
 
- 				foreach (AnonymousScopeEntry scope in anonymous_scopes.Values)
 
- 					scope.Write (bw);
 
- 			}
 
- 			ot.AnonymousScopeTableSize = (int) bw.BaseStream.Position - ot.AnonymousScopeTableOffset;
 
- 			//
 
- 			// Fixup offset table.
 
- 			//
 
- 			ot.TypeCount = last_type_index;
 
- 			ot.MethodCount = methods.Count;
 
- 			ot.SourceCount = sources.Count;
 
- 			ot.CompileUnitCount = comp_units.Count;
 
- 			//
 
- 			// Write offset table.
 
- 			//
 
- 			ot.TotalFileSize = (int) bw.BaseStream.Position;
 
- 			bw.Seek ((int) offset_table_offset, SeekOrigin.Begin);
 
- 			ot.Write (bw, MajorVersion, MinorVersion);
 
- 			bw.Seek (0, SeekOrigin.End);
 
- #if false
 
- 			Console.WriteLine ("TOTAL: {0} line numbes, {1} bytes, extended {2} bytes, " +
 
- 					   "{3} methods.", NumLineNumbers, LineNumberSize,
 
- 					   ExtendedLineNumberSize, methods.Count);
 
- #endif
 
- 		}
 
- 		public void CreateSymbolFile (Guid guid, FileStream fs)
 
- 		{
 
- 			if (reader != null)
 
- 				throw new InvalidOperationException ();
 
- 			Write (new MyBinaryWriter (fs), guid);
 
- 		}
 
- 		MyBinaryReader reader;
 
- 		Dictionary<int, SourceFileEntry> source_file_hash;
 
- 		Dictionary<int, CompileUnitEntry> compile_unit_hash;
 
- 		List<MethodEntry> method_list;
 
- 		Dictionary<int, MethodEntry> method_token_hash;
 
- 		Dictionary<string, int> source_name_hash;
 
- 		Guid guid;
 
- 		MonoSymbolFile (Stream stream)
 
- 		{
 
- 			reader = new MyBinaryReader (stream);
 
- 			try {
 
- 				long magic = reader.ReadInt64 ();
 
- 				int major_version = reader.ReadInt32 ();
 
- 				int minor_version = reader.ReadInt32 ();
 
- 				if (magic != OffsetTable.Magic)
 
- 					throw new MonoSymbolFileException ("Symbol file is not a valid");
 
- 				if (major_version != OffsetTable.MajorVersion)
 
- 					throw new MonoSymbolFileException (
 
- 						"Symbol file has version {0} but expected {1}", major_version, OffsetTable.MajorVersion);
 
- 				if (minor_version != OffsetTable.MinorVersion)
 
- 					throw new MonoSymbolFileException ("Symbol file has version {0}.{1} but expected {2}.{3}",
 
- 						major_version, minor_version,
 
- 						OffsetTable.MajorVersion, OffsetTable.MinorVersion);
 
- 				MajorVersion = major_version;
 
- 				MinorVersion = minor_version;
 
- 				guid = new Guid (reader.ReadBytes (16));
 
- 				ot = new OffsetTable (reader, major_version, minor_version);
 
- 			} catch (Exception e) {
 
- 				throw new MonoSymbolFileException ("Cannot read symbol file", e);
 
- 			}
 
- 			source_file_hash = new Dictionary<int, SourceFileEntry> ();
 
- 			compile_unit_hash = new Dictionary<int, CompileUnitEntry> ();
 
- 		}
 
- #if !NET_CORE
 
- 		public static MonoSymbolFile ReadSymbolFile (Assembly assembly)
 
- 		{
 
- 			string filename = assembly.Location;
 
- 			string name = filename + ".mdb";
 
- 			Module[] modules = assembly.GetModules ();
 
- 			Guid assembly_guid = modules[0].ModuleVersionId;
 
- 			return ReadSymbolFile (name, assembly_guid);
 
- 		}
 
- #endif
 
- 		public static MonoSymbolFile ReadSymbolFile (string mdbFilename)
 
- 		{
 
- 			return ReadSymbolFile (new FileStream (mdbFilename, FileMode.Open, FileAccess.Read));
 
- 		}
 
- 		public static MonoSymbolFile ReadSymbolFile (string mdbFilename, Guid assemblyGuid)
 
- 		{
 
- 			var sf = ReadSymbolFile (mdbFilename);
 
- 			if (assemblyGuid != sf.guid)
 
- 				throw new MonoSymbolFileException ("Symbol file `{0}' does not match assembly", mdbFilename);
 
- 			return sf;
 
- 		}
 
- 		public static MonoSymbolFile ReadSymbolFile (Stream stream)
 
- 		{
 
- 			return new MonoSymbolFile (stream);
 
- 		}
 
- 		public int CompileUnitCount {
 
- 			get { return ot.CompileUnitCount; }
 
- 		}
 
- 		public int SourceCount {
 
- 			get { return ot.SourceCount; }
 
- 		}
 
- 		public int MethodCount {
 
- 			get { return ot.MethodCount; }
 
- 		}
 
- 		public int TypeCount {
 
- 			get { return ot.TypeCount; }
 
- 		}
 
- 		public int AnonymousScopeCount {
 
- 			get { return ot.AnonymousScopeCount; }
 
- 		}
 
- 		public int NamespaceCount {
 
- 			get { return last_namespace_index; }
 
- 		}
 
- 		public Guid Guid {
 
- 			get { return guid; }
 
- 		}
 
- 		public OffsetTable OffsetTable {
 
- 			get { return ot; }
 
- 		}
 
- 		internal int LineNumberCount = 0;
 
- 		internal int LocalCount = 0;
 
- 		internal int StringSize = 0;
 
- 		internal int LineNumberSize = 0;
 
- 		internal int ExtendedLineNumberSize = 0;
 
- 		public SourceFileEntry GetSourceFile (int index)
 
- 		{
 
- 			if ((index < 1) || (index > ot.SourceCount))
 
- 				throw new ArgumentException ();
 
- 			if (reader == null)
 
- 				throw new InvalidOperationException ();
 
- 			lock (this) {
 
- 				SourceFileEntry source;
 
- 				if (source_file_hash.TryGetValue (index, out source))
 
- 					return source;
 
- 				long old_pos = reader.BaseStream.Position;
 
- 				reader.BaseStream.Position = ot.SourceTableOffset +
 
- 					SourceFileEntry.Size * (index - 1);
 
- 				source = new SourceFileEntry (this, reader);
 
- 				source_file_hash.Add (index, source);
 
- 				reader.BaseStream.Position = old_pos;
 
- 				return source;
 
- 			}
 
- 		}
 
- 		public SourceFileEntry[] Sources {
 
- 			get {
 
- 				if (reader == null)
 
- 					throw new InvalidOperationException ();
 
- 				SourceFileEntry[] retval = new SourceFileEntry [SourceCount];
 
- 				for (int i = 0; i < SourceCount; i++)
 
- 					retval [i] = GetSourceFile (i + 1);
 
- 				return retval;
 
- 			}
 
- 		}
 
- 		public CompileUnitEntry GetCompileUnit (int index)
 
- 		{
 
- 			if ((index < 1) || (index > ot.CompileUnitCount))
 
- 				throw new ArgumentException ();
 
- 			if (reader == null)
 
- 				throw new InvalidOperationException ();
 
- 			lock (this) {
 
- 				CompileUnitEntry unit;
 
- 				if (compile_unit_hash.TryGetValue (index, out unit))
 
- 					return unit;
 
- 				long old_pos = reader.BaseStream.Position;
 
- 				reader.BaseStream.Position = ot.CompileUnitTableOffset +
 
- 					CompileUnitEntry.Size * (index - 1);
 
- 				unit = new CompileUnitEntry (this, reader);
 
- 				compile_unit_hash.Add (index, unit);
 
- 				reader.BaseStream.Position = old_pos;
 
- 				return unit;
 
- 			}
 
- 		}
 
- 		public CompileUnitEntry[] CompileUnits {
 
- 			get {
 
- 				if (reader == null)
 
- 					throw new InvalidOperationException ();
 
- 				CompileUnitEntry[] retval = new CompileUnitEntry [CompileUnitCount];
 
- 				for (int i = 0; i < CompileUnitCount; i++)
 
- 					retval [i] = GetCompileUnit (i + 1);
 
- 				return retval;
 
- 			}
 
- 		}
 
- 		void read_methods ()
 
- 		{
 
- 			lock (this) {
 
- 				if (method_token_hash != null)
 
- 					return;
 
- 				method_token_hash = new Dictionary<int, MethodEntry> ();
 
- 				method_list = new List<MethodEntry> ();
 
- 				long old_pos = reader.BaseStream.Position;
 
- 				reader.BaseStream.Position = ot.MethodTableOffset;
 
- 				for (int i = 0; i < MethodCount; i++) {
 
- 					MethodEntry entry = new MethodEntry (this, reader, i + 1);
 
- 					method_token_hash.Add (entry.Token, entry);
 
- 					method_list.Add (entry);
 
- 				}
 
- 				reader.BaseStream.Position = old_pos;
 
- 			}
 
- 		}
 
- 		public MethodEntry GetMethodByToken (int token)
 
- 		{
 
- 			if (reader == null)
 
- 				throw new InvalidOperationException ();
 
- 			lock (this) {
 
- 				read_methods ();
 
- 				MethodEntry me;
 
- 				method_token_hash.TryGetValue (token, out me);
 
- 				return me;
 
- 			}
 
- 		}
 
- 		public MethodEntry GetMethod (int index)
 
- 		{
 
- 			if ((index < 1) || (index > ot.MethodCount))
 
- 				throw new ArgumentException ();
 
- 			if (reader == null)
 
- 				throw new InvalidOperationException ();
 
- 			lock (this) {
 
- 				read_methods ();
 
- 				return method_list [index - 1];
 
- 			}
 
- 		}
 
- 		public MethodEntry[] Methods {
 
- 			get {
 
- 				if (reader == null)
 
- 					throw new InvalidOperationException ();
 
- 				lock (this) {
 
- 					read_methods ();
 
- 					MethodEntry[] retval = new MethodEntry [MethodCount];
 
- 					method_list.CopyTo (retval, 0);
 
- 					return retval;
 
- 				}
 
- 			}
 
- 		}
 
- 		public int FindSource (string file_name)
 
- 		{
 
- 			if (reader == null)
 
- 				throw new InvalidOperationException ();
 
- 			lock (this) {
 
- 				if (source_name_hash == null) {
 
- 					source_name_hash = new Dictionary<string, int> ();
 
- 					for (int i = 0; i < ot.SourceCount; i++) {
 
- 						SourceFileEntry source = GetSourceFile (i + 1);
 
- 						source_name_hash.Add (source.FileName, i);
 
- 					}
 
- 				}
 
- 				int value;
 
- 				if (!source_name_hash.TryGetValue (file_name, out value))
 
- 					return -1;
 
- 				return value;
 
- 			}
 
- 		}
 
- 		public AnonymousScopeEntry GetAnonymousScope (int id)
 
- 		{
 
- 			if (reader == null)
 
- 				throw new InvalidOperationException ();
 
- 			AnonymousScopeEntry scope;
 
- 			lock (this) {
 
- 				if (anonymous_scopes != null) {
 
- 					anonymous_scopes.TryGetValue (id, out scope);
 
- 					return scope;
 
- 				}
 
- 				anonymous_scopes = new Dictionary<int, AnonymousScopeEntry> ();
 
- 				reader.BaseStream.Position = ot.AnonymousScopeTableOffset;
 
- 				for (int i = 0; i < ot.AnonymousScopeCount; i++) {
 
- 					scope = new AnonymousScopeEntry (reader);
 
- 					anonymous_scopes.Add (scope.ID, scope);
 
- 				}
 
- 				return anonymous_scopes [id];
 
- 			}
 
- 		}
 
- 		internal MyBinaryReader BinaryReader {
 
- 			get {
 
- 				if (reader == null)
 
- 					throw new InvalidOperationException ();
 
- 				return reader;
 
- 			}
 
- 		}
 
- 		public void Dispose ()
 
- 		{
 
- 			Dispose (true);
 
- 		}
 
- 		protected virtual void Dispose (bool disposing)
 
- 		{
 
- 			if (disposing) {
 
- 				if (reader != null) {
 
- #if NET_CORE
 
- 					reader.Dispose ();
 
- #else
 
- 					reader.Close ();
 
- #endif
 
- 					reader = null;
 
- 				}
 
- 			}
 
- 		}
 
- 	}
 
- }
 
 
  |