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 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));
48 static bool IsPortablePdb (FileStream stream)
50 const uint ppdb_signature = 0x424a5342;
52 var position = stream.Position;
54 var reader = new BinaryReader (stream);
55 return reader.ReadUInt32 () == ppdb_signature;
57 stream.Position = position;
61 internal Converter (MonoSymbolWriter mdb)
66 internal static void Convert (AssemblyDefinition assembly, IEnumerable<PdbFunction> functions, MonoSymbolWriter mdb)
68 var converter = new Converter (mdb);
70 foreach (var function in functions)
71 converter.ConvertFunction (function);
73 mdb.WriteSymbolFile (assembly.MainModule.Mvid);
76 void ConvertFunction (PdbFunction function)
78 if (function.lines == null)
81 var method = new SourceMethod { Name = function.name, Token = (int) function.token };
83 var file = GetSourceFile (mdb, function);
85 var builder = mdb.OpenMethod (file.CompilationUnit, 0, method);
87 ConvertSequencePoints (function, file, builder);
89 ConvertVariables (function);
94 void ConvertSequencePoints (PdbFunction function, SourceFile file, SourceMethodBuilder builder)
97 foreach (var line in function.lines.SelectMany (lines => lines.lines)) {
98 // 0xfeefee is an MS convention, we can't pass it into mdb files, so we use the last non-hidden line
99 bool is_hidden = line.lineBegin == 0xfeefee;
100 builder.MarkSequencePoint (
102 file.CompilationUnit.SourceFile,
103 is_hidden ? last_line : (int) line.lineBegin,
104 (int) line.colBegin, is_hidden ? -1 : (int)line.lineEnd, is_hidden ? -1 : (int)line.colEnd,
107 last_line = (int) line.lineBegin;
111 void ConvertVariables (PdbFunction function)
113 foreach (var scope in function.scopes)
114 ConvertScope (scope);
117 void ConvertScope (PdbScope scope)
119 ConvertSlots (scope, scope.slots);
121 foreach (var s in scope.scopes)
125 void ConvertSlots (PdbScope scope, IEnumerable<PdbSlot> slots)
127 int scope_idx = mdb.OpenScope ((int)scope.address);
128 foreach (var slot in slots) {
129 mdb.DefineLocalVariable ((int) slot.slot, slot.name);
130 mdb.DefineScopeVariable (scope_idx, (int)slot.slot);
132 mdb.CloseScope ((int)(scope.address + scope.length));
135 SourceFile GetSourceFile (MonoSymbolWriter mdb, PdbFunction function)
137 var name = (from l in function.lines where l.file != null select l.file.name).First ();
140 if (files.TryGetValue (name, out file))
143 var entry = mdb.DefineDocument (name);
144 var unit = mdb.DefineCompilationUnit (entry);
146 file = new SourceFile (unit, entry);
147 files.Add (name, file);
151 class SourceFile : ISourceFile {
152 CompileUnitEntry comp_unit;
153 SourceFileEntry entry;
155 public SourceFileEntry Entry
157 get { return entry; }
160 public CompileUnitEntry CompilationUnit
162 get { return comp_unit; }
165 public SourceFile (CompileUnitEntry comp_unit, SourceFileEntry entry)
167 this.comp_unit = comp_unit;
172 class SourceMethod : IMethodDef {
174 public string Name { get; set; }
176 public int Token { get; set; }
180 public class PortablePdbNotSupportedException : Exception {
185 static void Main (string [] args)
187 if (args.Length != 1)
192 if (!File.Exists (asm))
196 Converter.Convert (asm);
197 } catch (FileNotFoundException ex) {
199 } catch (PortablePdbNotSupportedException) {
200 Console.WriteLine ("Error: A portable PDB can't be converted to mdb.");
201 Environment.Exit (2);
203 catch (Exception ex) {
210 Console.WriteLine ("Mono pdb to mdb debug symbol store converter");
211 Console.WriteLine ("Usage: pdb2mdb assembly");
213 Environment.Exit (1);
216 static void Error (Exception e)
218 Console.WriteLine ("Fatal error:");
219 Console.WriteLine (e);
221 Environment.Exit (1);