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);