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 using (var asm = AssemblyDefinition.ReadAssembly (filename)) {
33 var pdb = asm.Name.Name + ".pdb";
34 pdb = Path.Combine (Path.GetDirectoryName (filename), pdb);
36 if (!File.Exists (pdb))
37 throw new FileNotFoundException ("PDB file doesn't exist: " + pdb);
39 using (var stream = File.OpenRead (pdb)) {
40 if (IsPortablePdb (stream))
41 throw new PortablePdbNotSupportedException ();
43 var funcs = PdbFile.LoadFunctions (stream, true);
44 Converter.Convert (asm, funcs, new MonoSymbolWriter (filename));
49 static bool IsPortablePdb (FileStream stream)
51 const uint ppdb_signature = 0x424a5342;
53 var position = stream.Position;
55 var reader = new BinaryReader (stream);
56 return reader.ReadUInt32 () == ppdb_signature;
58 stream.Position = position;
62 internal Converter (MonoSymbolWriter mdb)
67 internal static void Convert (AssemblyDefinition assembly, IEnumerable<PdbFunction> functions, MonoSymbolWriter mdb)
69 var converter = new Converter (mdb);
71 foreach (var function in functions)
72 converter.ConvertFunction (function);
74 mdb.WriteSymbolFile (assembly.MainModule.Mvid);
77 void ConvertFunction (PdbFunction function)
79 if (function.lines == null)
82 var method = new SourceMethod { Name = function.name, Token = (int) function.token };
84 var file = GetSourceFile (mdb, function);
86 var builder = mdb.OpenMethod (file.CompilationUnit, 0, method);
88 ConvertSequencePoints (function, file, builder);
90 ConvertVariables (function);
95 void ConvertSequencePoints (PdbFunction function, SourceFile file, SourceMethodBuilder builder)
98 foreach (var line in function.lines.SelectMany (lines => lines.lines)) {
99 // 0xfeefee is an MS convention, we can't pass it into mdb files, so we use the last non-hidden line
100 bool is_hidden = line.lineBegin == 0xfeefee;
101 builder.MarkSequencePoint (
103 file.CompilationUnit.SourceFile,
104 is_hidden ? last_line : (int) line.lineBegin,
105 (int) line.colBegin, is_hidden ? -1 : (int)line.lineEnd, is_hidden ? -1 : (int)line.colEnd,
108 last_line = (int) line.lineBegin;
112 void ConvertVariables (PdbFunction function)
114 foreach (var scope in function.scopes)
115 ConvertScope (scope);
118 void ConvertScope (PdbScope scope)
120 ConvertSlots (scope, scope.slots);
122 foreach (var s in scope.scopes)
126 void ConvertSlots (PdbScope scope, IEnumerable<PdbSlot> slots)
128 int scope_idx = mdb.OpenScope ((int)scope.address);
129 foreach (var slot in slots) {
130 mdb.DefineLocalVariable ((int) slot.slot, slot.name);
131 mdb.DefineScopeVariable (scope_idx, (int)slot.slot);
133 mdb.CloseScope ((int)(scope.address + scope.length));
136 SourceFile GetSourceFile (MonoSymbolWriter mdb, PdbFunction function)
138 var name = (from l in function.lines where l.file != null select l.file.name).First ();
141 if (files.TryGetValue (name, out file))
144 var entry = mdb.DefineDocument (name);
145 var unit = mdb.DefineCompilationUnit (entry);
147 file = new SourceFile (unit, entry);
148 files.Add (name, file);
152 class SourceFile : ISourceFile {
153 CompileUnitEntry comp_unit;
154 SourceFileEntry entry;
156 public SourceFileEntry Entry
158 get { return entry; }
161 public CompileUnitEntry CompilationUnit
163 get { return comp_unit; }
166 public SourceFile (CompileUnitEntry comp_unit, SourceFileEntry entry)
168 this.comp_unit = comp_unit;
173 class SourceMethod : IMethodDef {
175 public string Name { get; set; }
177 public int Token { get; set; }
181 public class PortablePdbNotSupportedException : Exception {
186 static void Main (string [] args)
188 if (args.Length != 1)
193 if (!File.Exists (asm))
197 Converter.Convert (asm);
198 } catch (FileNotFoundException ex) {
200 } catch (PortablePdbNotSupportedException) {
201 Console.WriteLine ("Error: A portable PDB can't be converted to mdb.");
202 Environment.Exit (2);
204 catch (Exception ex) {
211 Console.WriteLine ("Mono pdb to mdb debug symbol store converter");
212 Console.WriteLine ("Usage: pdb2mdb assembly");
214 Environment.Exit (1);
217 static void Error (Exception e)
219 Console.WriteLine ("Fatal error:");
220 Console.WriteLine (e);
222 Environment.Exit (1);