PageRenderTime 29ms CodeModel.GetById 15ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/symbols/mdb/Mono.Cecil.Mdb/MdbReader.cs

http://github.com/jbevain/cecil
C# | 207 lines | 151 code | 47 blank | 9 comment | 23 complexity | e86acffd88489648590ff299528970ce MD5 | raw file
  1//
  2// Author:
  3//   Jb Evain (jbevain@gmail.com)
  4//
  5// Copyright (c) 2008 - 2015 Jb Evain
  6// Copyright (c) 2008 - 2011 Novell, Inc.
  7//
  8// Licensed under the MIT/X11 license.
  9//
 10
 11using System;
 12using System.Collections.Generic;
 13using System.IO;
 14
 15using Mono.Cecil.Cil;
 16using Mono.Collections.Generic;
 17using Mono.CompilerServices.SymbolWriter;
 18
 19namespace Mono.Cecil.Mdb {
 20
 21	public sealed class MdbReaderProvider : ISymbolReaderProvider {
 22
 23		public ISymbolReader GetSymbolReader (ModuleDefinition module, string fileName)
 24		{
 25			Mixin.CheckModule (module);
 26			Mixin.CheckFileName (fileName);
 27
 28			return new MdbReader (module, MonoSymbolFile.ReadSymbolFile (Mixin.GetMdbFileName (fileName)));
 29		}
 30
 31		public ISymbolReader GetSymbolReader (ModuleDefinition module, Stream symbolStream)
 32		{
 33			Mixin.CheckModule (module);
 34			Mixin.CheckStream (symbolStream);
 35
 36			return new MdbReader (module, MonoSymbolFile.ReadSymbolFile (symbolStream));
 37		}
 38	}
 39
 40	public sealed class MdbReader : ISymbolReader {
 41
 42		readonly ModuleDefinition module;
 43		readonly MonoSymbolFile symbol_file;
 44		readonly Dictionary<string, Document> documents;
 45
 46		public MdbReader (ModuleDefinition module, MonoSymbolFile symFile)
 47		{
 48			this.module = module;
 49			this.symbol_file = symFile;
 50			this.documents = new Dictionary<string, Document> ();
 51		}
 52
 53		public ISymbolWriterProvider GetWriterProvider ()
 54		{
 55			return new MdbWriterProvider ();
 56		}
 57
 58		public bool ProcessDebugHeader (ImageDebugHeader header)
 59		{
 60			return symbol_file.Guid == module.Mvid;
 61		}
 62
 63		public MethodDebugInformation Read (MethodDefinition method)
 64		{
 65			var method_token = method.MetadataToken;
 66			var entry = symbol_file.GetMethodByToken (method_token.ToInt32	());
 67			if (entry == null)
 68				return null;
 69
 70			var info = new MethodDebugInformation (method);
 71			info.code_size = ReadCodeSize (method);
 72
 73			var scopes = ReadScopes (entry, info);
 74			ReadLineNumbers (entry, info);
 75			ReadLocalVariables (entry, scopes);
 76
 77			return info;
 78		}
 79
 80		static int ReadCodeSize (MethodDefinition method)
 81		{
 82			return method.Module.Read (method, (m, reader) => reader.ReadCodeSize (m));
 83		}
 84
 85		static void ReadLocalVariables (MethodEntry entry, ScopeDebugInformation [] scopes)
 86		{
 87			var locals = entry.GetLocals ();
 88
 89			foreach (var local in locals) {
 90				var variable = new VariableDebugInformation (local.Index, local.Name);
 91
 92				var index = local.BlockIndex;
 93				if (index < 0 || index >= scopes.Length)
 94					continue;
 95
 96				var scope = scopes [index];
 97				if (scope == null)
 98					continue;
 99
100				scope.Variables.Add (variable);
101			}
102		}
103
104		void ReadLineNumbers (MethodEntry entry, MethodDebugInformation info)
105		{
106			var table = entry.GetLineNumberTable ();
107
108			info.sequence_points = new Collection<SequencePoint> (table.LineNumbers.Length);
109
110			for (var i = 0; i < table.LineNumbers.Length; i++) {
111				var line = table.LineNumbers [i];
112				if (i > 0 && table.LineNumbers [i - 1].Offset == line.Offset)
113					continue;
114
115				info.sequence_points.Add (LineToSequencePoint (line));
116			}
117		}
118
119		Document GetDocument (SourceFileEntry file)
120		{
121			var file_name = file.FileName;
122
123			Document document;
124			if (documents.TryGetValue (file_name, out document))
125				return document;
126
127			document = new Document (file_name) {
128				Hash = file.Checksum,
129			};
130
131			documents.Add (file_name, document);
132
133			return document;
134		}
135
136		static ScopeDebugInformation [] ReadScopes (MethodEntry entry, MethodDebugInformation info)
137		{
138			var blocks = entry.GetCodeBlocks ();
139			var scopes = new ScopeDebugInformation [blocks.Length + 1];
140
141			info.scope = scopes [0] = new ScopeDebugInformation {
142				Start = new InstructionOffset (0),
143				End = new InstructionOffset (info.code_size),
144			};
145
146			foreach (var block in blocks) {
147				if (block.BlockType != CodeBlockEntry.Type.Lexical && block.BlockType != CodeBlockEntry.Type.CompilerGenerated)
148					continue;
149
150				var scope = new ScopeDebugInformation ();
151				scope.Start = new InstructionOffset (block.StartOffset);
152				scope.End = new InstructionOffset (block.EndOffset);
153
154				scopes [block.Index + 1] = scope;
155
156				if (!AddScope (info.scope.Scopes, scope))
157					info.scope.Scopes.Add (scope);
158			}
159
160			return scopes;
161		}
162
163		static bool AddScope (Collection<ScopeDebugInformation> scopes, ScopeDebugInformation scope)
164		{
165			foreach (var sub_scope in scopes) {
166				if (sub_scope.HasScopes && AddScope (sub_scope.Scopes, scope))
167					return true;
168
169				if (scope.Start.Offset >= sub_scope.Start.Offset && scope.End.Offset <= sub_scope.End.Offset) {
170					sub_scope.Scopes.Add (scope);
171					return true;
172				}
173			}
174
175			return false;
176		}
177
178		SequencePoint LineToSequencePoint (LineNumberEntry line)
179		{
180			var source = symbol_file.GetSourceFile (line.File);
181			return new SequencePoint (line.Offset, GetDocument (source)) {
182				StartLine = line.Row,
183				EndLine = line.EndRow,
184				StartColumn = line.Column,
185				EndColumn = line.EndColumn,
186			};
187		}
188
189		public void Dispose ()
190		{
191			symbol_file.Dispose ();
192		}
193	}
194
195	static class MethodEntryExtensions {
196
197		public static bool HasColumnInfo (this MethodEntry entry)
198		{
199			return (entry.MethodFlags & MethodEntry.Flags.ColumnsInfoIncluded) != 0;
200		}
201
202		public static bool HasEndInfo (this MethodEntry entry)
203		{
204			return (entry.MethodFlags & MethodEntry.Flags.EndInfoIncluded) != 0;
205		}
206	}
207}