5 // Jb Evain (jbevain@novell.com)
7 // (C) 2009 Novell, Inc. (http://www.novell.com)
11 using System.Collections.Generic;
16 using Microsoft.Cci.Pdb;
20 using Mono.CompilerServices.SymbolWriter;
24 public class Converter {
27 Dictionary<string, SourceFile> files = new Dictionary<string, SourceFile> ();
29 public static void Convert (string filename)
31 var asm = AssemblyDefinition.ReadAssembly (filename);
33 var pdb = asm.Name.Name + ".pdb";
34 pdb = Path.Combine (Path.GetDirectoryName (filename), pdb);
36 using (var stream = File.OpenRead (pdb)) {
37 var funcs = PdbFile.LoadFunctions (stream, true);
38 Converter.Convert (asm, funcs, new MonoSymbolWriter (filename));
42 internal Converter (MonoSymbolWriter mdb)
47 internal static void Convert (AssemblyDefinition assembly, IEnumerable<PdbFunction> functions, MonoSymbolWriter mdb)
49 var converter = new Converter (mdb);
51 foreach (var function in functions)
52 converter.ConvertFunction (function);
54 mdb.WriteSymbolFile (assembly.MainModule.Mvid);
57 void ConvertFunction (PdbFunction function)
59 if (function.lines == null)
62 var method = new SourceMethod { Name = function.name, Token = (int) function.token };
64 var file = GetSourceFile (mdb, function);
66 var builder = mdb.OpenMethod (file.CompilationUnit, 0, method);
68 ConvertSequencePoints (function, file, builder);
70 ConvertVariables (function);
75 void ConvertSequencePoints (PdbFunction function, SourceFile file, SourceMethodBuilder builder)
78 foreach (var line in function.lines.SelectMany (lines => lines.lines)) {
79 // 0xfeefee is an MS convention, we can't pass it into mdb files, so we use the last non-hidden line
80 bool is_hidden = line.lineBegin == 0xfeefee;
81 builder.MarkSequencePoint (
83 file.CompilationUnit.SourceFile,
84 is_hidden ? last_line : (int) line.lineBegin,
85 (int) line.colBegin, is_hidden ? -1 : (int)line.lineEnd, is_hidden ? -1 : (int)line.colEnd,
88 last_line = (int) line.lineBegin;
92 void ConvertVariables (PdbFunction function)
94 foreach (var scope in function.scopes)
98 void ConvertScope (PdbScope scope)
100 ConvertSlots (scope, scope.slots);
102 foreach (var s in scope.scopes)
106 void ConvertSlots (PdbScope scope, IEnumerable<PdbSlot> slots)
108 int scope_idx = mdb.OpenScope ((int)scope.address);
109 foreach (var slot in slots) {
110 mdb.DefineLocalVariable ((int) slot.slot, slot.name);
111 mdb.DefineScopeVariable (scope_idx, (int)slot.slot);
113 mdb.CloseScope ((int)(scope.address + scope.length));
116 SourceFile GetSourceFile (MonoSymbolWriter mdb, PdbFunction function)
118 var name = (from l in function.lines where l.file != null select l.file.name).First ();
121 if (files.TryGetValue (name, out file))
124 var entry = mdb.DefineDocument (name);
125 var unit = mdb.DefineCompilationUnit (entry);
127 file = new SourceFile (unit, entry);
128 files.Add (name, file);
132 class SourceFile : ISourceFile {
133 CompileUnitEntry comp_unit;
134 SourceFileEntry entry;
136 public SourceFileEntry Entry
138 get { return entry; }
141 public CompileUnitEntry CompilationUnit
143 get { return comp_unit; }
146 public SourceFile (CompileUnitEntry comp_unit, SourceFileEntry entry)
148 this.comp_unit = comp_unit;
153 class SourceMethod : IMethodDef {
155 public string Name { get; set; }
157 public int Token { get; set; }
163 static void Main (string [] args)
165 if (args.Length != 1)
170 if (!File.Exists (asm))
173 var assembly = AssemblyDefinition.ReadAssembly (asm);
175 var pdb = assembly.Name.Name + ".pdb";
176 pdb = Path.Combine (Path.GetDirectoryName (asm), pdb);
178 if (!File.Exists (pdb))
181 using (var stream = File.OpenRead (pdb)) {
182 Convert (assembly, stream, new MonoSymbolWriter (asm));
186 static void Convert (AssemblyDefinition assembly, Stream pdb, MonoSymbolWriter mdb)
189 Converter.Convert (assembly, PdbFile.LoadFunctions (pdb, true), mdb);
190 } catch (Exception e) {
197 Console.WriteLine ("Mono pdb to mdb debug symbol store converter");
198 Console.WriteLine ("Usage: pdb2mdb assembly");
200 Environment.Exit (1);
203 static void Error (Exception e)
205 Console.WriteLine ("Fatal error:");
206 Console.WriteLine (e);