2010-07-09 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / tools / pdb2mdb / Driver.cs
1 //
2 // Driver.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@novell.com)
6 //
7 // (C) 2009 Novell, Inc. (http://www.novell.com)
8 //
9
10 using System;
11 using System.Collections.Generic;
12 using System.IO;
13 using System.Linq;
14
15 using Microsoft.Cci;
16 using Microsoft.Cci.Pdb;
17
18 using Mono.Cecil;
19
20 using Mono.CompilerServices.SymbolWriter;
21
22 namespace Pdb2Mdb {
23
24         class Converter {
25
26                 MonoSymbolWriter mdb;
27                 Dictionary<string, SourceFile> files = new Dictionary<string, SourceFile> ();
28
29                 public Converter (MonoSymbolWriter mdb)
30                 {
31                         this.mdb = mdb;
32                 }
33
34                 public static void Convert (AssemblyDefinition assembly, IEnumerable<PdbFunction> functions, MonoSymbolWriter mdb)
35                 {
36                         var converter = new Converter (mdb);
37
38                         foreach (var function in functions)
39                                 converter.ConvertFunction (function);
40
41                         mdb.WriteSymbolFile (assembly.MainModule.Mvid);
42                 }
43
44                 void ConvertFunction (PdbFunction function)
45                 {
46                         var method = new SourceMethod { Name = function.name, Token = (int) function.token };
47
48                         var file = GetSourceFile (mdb, function);
49
50                         var builder = mdb.OpenMethod (file.CompilationUnit, 0, method);
51
52                         ConvertSequencePoints (function, file, builder);
53
54                         ConvertVariables (function);
55
56                         mdb.CloseMethod ();
57                 }
58
59                 void ConvertSequencePoints (PdbFunction function, SourceFile file, SourceMethodBuilder builder)
60                 {
61                         if (function.lines == null)
62                                 return;
63
64                         foreach (var line in function.lines.SelectMany (lines => lines.lines))
65                                 builder.MarkSequencePoint (
66                                         (int) line.offset,
67                                         file.CompilationUnit.SourceFile,
68                                         (int) line.lineBegin,
69                                         (int) line.colBegin, line.lineBegin == 0xfeefee);
70                 }
71
72                 void ConvertVariables (PdbFunction function)
73                 {
74                         foreach (var scope in function.scopes)
75                                 ConvertScope (scope);
76                 }
77
78                 void ConvertScope (PdbScope scope)
79                 {
80                         ConvertSlots (scope.slots);
81
82                         foreach (var s in scope.scopes)
83                                 ConvertScope (s);
84                 }
85
86                 void ConvertSlots (IEnumerable<PdbSlot> slots)
87                 {
88                         foreach (var slot in slots)
89                                 mdb.DefineLocalVariable ((int) slot.slot, slot.name);
90                 }
91
92                 SourceFile GetSourceFile (MonoSymbolWriter mdb, PdbFunction function)
93                 {
94                         var name = (from l in function.lines where l.file != null select l.file.name).First ();
95
96                         SourceFile file;
97                         if (files.TryGetValue (name, out file))
98                                 return file;
99
100                         var entry = mdb.DefineDocument (name);
101                         var unit = mdb.DefineCompilationUnit (entry);
102
103                         file = new SourceFile (unit, entry);
104                         files.Add (name, file);
105                         return file;
106                 }
107
108                 class SourceFile : ISourceFile {
109                         CompileUnitEntry comp_unit;
110                         SourceFileEntry entry;
111
112                         public SourceFileEntry Entry
113                         {
114                                 get { return entry; }
115                         }
116
117                         public CompileUnitEntry CompilationUnit
118                         {
119                                 get { return comp_unit; }
120                         }
121
122                         public SourceFile (CompileUnitEntry comp_unit, SourceFileEntry entry)
123                         {
124                                 this.comp_unit = comp_unit;
125                                 this.entry = entry;
126                         }
127                 }
128
129                 class SourceMethod : IMethodDef {
130
131                         public string Name { get; set; }
132
133                         public int Token { get; set; }
134                 }
135         }
136
137         class Driver {
138
139                 static void Main (string [] args)
140                 {
141                         if (args.Length != 1)
142                                 Usage ();
143
144                         var asm = args [0];
145
146                         if (!File.Exists (asm))
147                                 Usage ();
148
149                         var assembly = AssemblyFactory.GetAssembly (asm);
150
151                         var pdb = assembly.Name.Name + ".pdb";
152
153                         if (!File.Exists (pdb))
154                                 Usage ();
155
156                         using (var stream = File.OpenRead (pdb)) {
157                                 Convert (assembly, stream, new MonoSymbolWriter (asm));
158                         }
159                 }
160
161                 static void Convert (AssemblyDefinition assembly, Stream pdb, MonoSymbolWriter mdb)
162                 {
163                         try {
164                                 Converter.Convert (assembly, PdbFile.LoadFunctions (pdb, true), mdb);
165                         } catch (Exception e) {
166                                 Error (e);
167                         }
168                 }
169
170                 static void Usage ()
171                 {
172                         Console.WriteLine ("Mono pdb to mdb debug symbol store converter");
173                         Console.WriteLine ("Usage: pdb2mdb assembly");
174
175                         Environment.Exit (1);
176                 }
177
178                 static void Error (Exception e)
179                 {
180                         Console.WriteLine ("Fatal error:");
181                         Console.WriteLine (e);
182                 }
183         }
184 }