eb302a8ac4d31260103c8d828760b78ecf29b76b
[mono.git] / mcs / class / Mono.Cecil.Mdb / Mono.Cecil.Mdb / MdbWriter.cs
1 //
2 // MdbWriter.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@novell.com)
6 //
7 // (C) 2007 Novell, Inc.
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 // Inspired by the pdb2mdb tool written by Robert Jordan, thanks Robert!
30
31 namespace Mono.Cecil.Mdb {
32
33         using System;
34         using System.Collections;
35
36         using Mono.CompilerServices.SymbolWriter;
37
38         using Mono.Cecil;
39         using Mono.Cecil.Cil;
40
41         class MdbWriter : ISymbolWriter {
42
43                 Guid m_mvid;
44                 MonoSymbolWriter m_writer;
45
46                 Hashtable m_documents;
47
48                 public MdbWriter (Guid mvid, string assembly)
49                 {
50                         m_mvid = mvid;
51                         m_writer = new MonoSymbolWriter (assembly);
52                         m_documents = new Hashtable ();
53                 }
54
55                 static Instruction [] GetInstructions (MethodBody body)
56                 {
57                         ArrayList list = new ArrayList ();
58                         foreach (Instruction instruction in body.Instructions)
59                                 if (instruction.SequencePoint != null)
60                                         list.Add (instruction);
61
62                         return list.ToArray (typeof (Instruction)) as Instruction [];
63                 }
64
65                 SourceFile GetSourceFile (Document document)
66                 {
67                         string url = document.Url;
68                         SourceFile file = m_documents [url] as SourceFile;
69                         if (file != null)
70                                 return file;
71
72                         file = new SourceFile (m_writer.DefineDocument (url));
73                         m_documents [url] = file;
74                         return file;
75                 }
76
77                 void Populate (Instruction [] instructions, int [] offsets,
78                         int [] startRows, int [] startCols, int [] endRows, int [] endCols,
79                         out SourceFile file)
80                 {
81                         SourceFile document = null;
82
83                         for (int i = 0; i < instructions.Length; i++) {
84                                 Instruction instr = (Instruction) instructions [i];
85                                 offsets [i] = instr.Offset;
86
87                                 if (document == null)
88                                         document = GetSourceFile (instr.SequencePoint.Document);
89
90                                 startRows [i] = instr.SequencePoint.StartLine;
91                                 startCols [i] = instr.SequencePoint.StartColumn;
92                                 endRows [i] = instr.SequencePoint.EndLine;
93                                 endCols [i] = instr.SequencePoint.EndColumn;
94                         }
95
96                         file = document;
97                 }
98
99                 public void Write (MethodBody body, byte [][] variables)
100                 {
101                         SourceMethod meth = new SourceMethod (body.Method);
102
103                         SourceFile file;
104
105                         Instruction [] instructions = GetInstructions (body);
106                         int length = instructions.Length;
107                         if (length == 0)
108                                 return;
109
110                         int [] offsets = new int [length];
111                         int [] startRows = new int [length];
112                         int [] startCols = new int [length];
113                         int [] endRows = new int [length];
114                         int [] endCols = new int [length];
115
116                         Populate (instructions, offsets, startRows, startCols, endRows, endCols, out file);
117
118                         m_writer.OpenMethod (file, meth,
119                                 startRows [0], startCols [0],
120                                 endRows [length - 1], endCols [length - 1]);
121
122                         for (int i = 0; i < length; i++)
123                                 m_writer.MarkSequencePoint (offsets [i], startRows [i], startCols [i]);
124
125                         MarkVariables (body, variables);
126
127                         m_writer.CloseMethod ();
128                 }
129
130                 void MarkVariables (MethodBody body, byte [][] variables)
131                 {
132                         for (int i = 0; i < body.Variables.Count; i++) {
133                                 VariableDefinition var = body.Variables [i];
134                                 m_writer.DefineLocalVariable (i, var.Name, variables [i]);
135                         }
136                 }
137
138                 public void Dispose ()
139                 {
140                         m_writer.WriteSymbolFile (m_mvid);
141                 }
142
143                 class SourceFile : ISourceFile {
144
145                         SourceFileEntry m_entry;
146
147                         public SourceFileEntry Entry {
148                                 get { return m_entry; }
149                         }
150
151                         public SourceFile (SourceFileEntry entry)
152                         {
153                                 m_entry = entry;
154                         }
155                 }
156
157                 class SourceMethod : ISourceMethod {
158
159                         MethodDefinition m_method;
160
161                         public string Name {
162                                 get { return m_method.Name; }
163                         }
164
165                         public int NamespaceID {
166                                 get { return 0; }
167                         }
168
169                         public int Token {
170                                 get { return (int) m_method.MetadataToken.ToUInt (); }
171                         }
172
173                         public SourceMethod (MethodDefinition method)
174                         {
175                                 m_method = method;
176                         }
177                 }
178         }
179 }