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