1 // 2 // MdbWriter.cs 3 // 4 // Author: 5 // Jb Evain (jbevain@gmail.com) 6 // 7 // Copyright (c) 2008 - 2011 Jb Evain 8 // 9 // Permission is hereby granted, free of charge, to any person obtaining 10 // a copy of this software and associated documentation files (the 11 // "Software"), to deal in the Software without restriction, including 12 // without limitation the rights to use, copy, modify, merge, publish, 13 // distribute, sublicense, and/or sell copies of the Software, and to 14 // permit persons to whom the Software is furnished to do so, subject to 15 // the following conditions: 16 // 17 // The above copyright notice and this permission notice shall be 18 // included in all copies or substantial portions of the Software. 19 // 20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 // 28 29 using System; 30 using System.Collections.Generic; 31 using System.IO; 32 33 using Mono.Cecil.Cil; 34 using Mono.Collections.Generic; 35 using Mono.CompilerServices.SymbolWriter; 36 37 namespace Mono.Cecil.Mdb { 38 39 #if !READ_ONLY 40 public class MdbWriterProvider : ISymbolWriterProvider { 41 GetSymbolWriter(ModuleDefinition module, string fileName)42 public ISymbolWriter GetSymbolWriter (ModuleDefinition module, string fileName) 43 { 44 return new MdbWriter (module.Mvid, fileName); 45 } 46 GetSymbolWriter(ModuleDefinition module, Stream symbolStream)47 public ISymbolWriter GetSymbolWriter (ModuleDefinition module, Stream symbolStream) 48 { 49 throw new NotImplementedException (); 50 } 51 } 52 53 public class MdbWriter : ISymbolWriter { 54 55 readonly Guid mvid; 56 readonly MonoSymbolWriter writer; 57 readonly Dictionary<string, SourceFile> source_files; 58 MdbWriter(Guid mvid, string assembly)59 public MdbWriter (Guid mvid, string assembly) 60 { 61 this.mvid = mvid; 62 this.writer = new MonoSymbolWriter (assembly); 63 this.source_files = new Dictionary<string, SourceFile> (); 64 } 65 GetInstructions(MethodBody body)66 static Collection<Instruction> GetInstructions (MethodBody body) 67 { 68 var instructions = new Collection<Instruction> (); 69 foreach (var instruction in body.Instructions) 70 if (instruction.SequencePoint != null) 71 instructions.Add (instruction); 72 73 return instructions; 74 } 75 GetSourceFile(Document document)76 SourceFile GetSourceFile (Document document) 77 { 78 var url = document.Url; 79 80 SourceFile source_file; 81 if (source_files.TryGetValue (url, out source_file)) 82 return source_file; 83 84 var entry = writer.DefineDocument (url); 85 var compile_unit = writer.DefineCompilationUnit (entry); 86 87 source_file = new SourceFile (compile_unit, entry); 88 source_files.Add (url, source_file); 89 return source_file; 90 } 91 Populate(Collection<Instruction> instructions, int [] offsets, int [] startRows, int [] startCols, out SourceFile file)92 void Populate (Collection<Instruction> instructions, int [] offsets, 93 int [] startRows, int [] startCols, out SourceFile file) 94 { 95 SourceFile source_file = null; 96 97 for (int i = 0; i < instructions.Count; i++) { 98 var instruction = instructions [i]; 99 offsets [i] = instruction.Offset; 100 101 var sequence_point = instruction.SequencePoint; 102 if (source_file == null) 103 source_file = GetSourceFile (sequence_point.Document); 104 105 startRows [i] = sequence_point.StartLine; 106 startCols [i] = sequence_point.StartColumn; 107 } 108 109 file = source_file; 110 } 111 Write(MethodBody body)112 public void Write (MethodBody body) 113 { 114 var method = new SourceMethod (body.Method); 115 116 var instructions = GetInstructions (body); 117 int count = instructions.Count; 118 if (count == 0) 119 return; 120 121 var offsets = new int [count]; 122 var start_rows = new int [count]; 123 var start_cols = new int [count]; 124 125 SourceFile file; 126 Populate (instructions, offsets, start_rows, start_cols, out file); 127 128 var builder = writer.OpenMethod (file.CompilationUnit, 0, method); 129 130 for (int i = 0; i < count; i++) 131 builder.MarkSequencePoint ( 132 offsets [i], 133 file.CompilationUnit.SourceFile, 134 start_rows [i], 135 start_cols [i], 136 false); 137 138 if (body.HasVariables) 139 AddVariables (body.Variables); 140 141 writer.CloseMethod (); 142 } 143 144 readonly static byte [] empty_header = new byte [0]; 145 GetDebugHeader(out ImageDebugDirectory directory, out byte [] header)146 public bool GetDebugHeader (out ImageDebugDirectory directory, out byte [] header) 147 { 148 directory = new ImageDebugDirectory (); 149 header = empty_header; 150 return false; 151 } 152 AddVariables(IList<VariableDefinition> variables)153 void AddVariables (IList<VariableDefinition> variables) 154 { 155 for (int i = 0; i < variables.Count; i++) { 156 var variable = variables [i]; 157 writer.DefineLocalVariable (i, variable.Name); 158 } 159 } 160 Write(MethodSymbols symbols)161 public void Write (MethodSymbols symbols) 162 { 163 var method = new SourceMethodSymbol (symbols); 164 165 var file = GetSourceFile (symbols.Instructions [0].SequencePoint.Document); 166 var builder = writer.OpenMethod (file.CompilationUnit, 0, method); 167 var count = symbols.Instructions.Count; 168 169 for (int i = 0; i < count; i++) { 170 var instruction = symbols.Instructions [i]; 171 var sequence_point = instruction.SequencePoint; 172 173 builder.MarkSequencePoint ( 174 instruction.Offset, 175 GetSourceFile (sequence_point.Document).CompilationUnit.SourceFile, 176 sequence_point.StartLine, 177 sequence_point.EndLine, 178 false); 179 } 180 181 if (symbols.HasVariables) 182 AddVariables (symbols.Variables); 183 184 writer.CloseMethod (); 185 } 186 Dispose()187 public void Dispose () 188 { 189 writer.WriteSymbolFile (mvid); 190 } 191 192 class SourceFile : ISourceFile { 193 194 readonly CompileUnitEntry compilation_unit; 195 readonly SourceFileEntry entry; 196 197 public SourceFileEntry Entry { 198 get { return entry; } 199 } 200 201 public CompileUnitEntry CompilationUnit { 202 get { return compilation_unit; } 203 } 204 SourceFile(CompileUnitEntry comp_unit, SourceFileEntry entry)205 public SourceFile (CompileUnitEntry comp_unit, SourceFileEntry entry) 206 { 207 this.compilation_unit = comp_unit; 208 this.entry = entry; 209 } 210 } 211 212 class SourceMethodSymbol : IMethodDef { 213 214 readonly string name; 215 readonly int token; 216 217 public string Name { 218 get { return name;} 219 } 220 221 public int Token { 222 get { return token; } 223 } 224 SourceMethodSymbol(MethodSymbols symbols)225 public SourceMethodSymbol (MethodSymbols symbols) 226 { 227 name = symbols.MethodName; 228 token = symbols.MethodToken.ToInt32 (); 229 } 230 } 231 232 class SourceMethod : IMethodDef { 233 234 readonly MethodDefinition method; 235 236 public string Name { 237 get { return method.Name; } 238 } 239 240 public int Token { 241 get { return method.MetadataToken.ToInt32 (); } 242 } 243 SourceMethod(MethodDefinition method)244 public SourceMethod (MethodDefinition method) 245 { 246 this.method = method; 247 } 248 } 249 } 250 #endif 251 } 252