6e6b5b95e664c86000fb3d24e1335315400a1a83
[mono.git] / mcs / class / Mono.Cecil.Mdb / Mono.Cecil.Mdb / MdbWriter.cs
1 //
2 // MdbWriter.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@gmail.com)
6 //
7 // (C) 2006 Jb Evain
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 namespace Mono.Cecil.Mdb {
30
31         using System.Collections;
32         using SDS = System.Diagnostics.SymbolStore;
33         using Mono.CompilerServices.SymbolWriter;
34         using Mono.Cecil.Cil;
35
36         class MdbWriter : ISymbolWriter {
37
38                 SymbolWriterImpl m_writer;
39                 Hashtable m_documents;
40
41                 public MdbWriter (SymbolWriterImpl writer)
42                 {
43                         m_writer = writer;
44                         m_documents = new Hashtable ();
45                 }
46
47                 public void Write (MethodBody body, byte [][] variables)
48                 {
49                         Document document = CreateDocuments (body);
50                         if (document != null) {
51                                 SDS.ISymbolDocumentWriter docWriter = GetDocument (document);
52                                 m_writer.SetMethodSourceRange (docWriter, 1, 1, docWriter, int.MaxValue, int.MaxValue);
53                         }
54
55                         m_writer.OpenMethod (new SDS.SymbolToken ((int) body.Method.MetadataToken.ToUInt ()));
56                         m_writer.SetSymAttribute (new SDS.SymbolToken (), "__name", System.Text.Encoding.UTF8.GetBytes (body.Method.Name));
57
58                         CreateScopes (body, body.Scopes, variables);
59                         m_writer.CloseMethod ();
60                 }
61
62                 void CreateScopes (MethodBody body, ScopeCollection scopes, byte [][] variables)
63                 {
64                         foreach (Scope s in scopes) {
65                                 int startOffset = s.Start.Offset;
66                                 int endOffset = s.End == body.Instructions.Outside ?
67                                         body.Instructions[body.Instructions.Count - 1].Offset + 1 :
68                                         s.End.Offset;
69
70                                 m_writer.OpenScope (startOffset);
71                                 m_writer.UsingNamespace (body.Method.DeclaringType.Namespace);
72                                 m_writer.OpenNamespace (body.Method.DeclaringType.Namespace);
73
74                                 int start = body.Instructions.IndexOf (s.Start);
75                                 int end = s.End == body.Instructions.Outside ?
76                                         body.Instructions.Count - 1 :
77                                         body.Instructions.IndexOf (s.End);
78
79                                 ArrayList instructions = new ArrayList();
80                                 for (int i = start; i <= end; i++)
81                                         if (body.Instructions [i].SequencePoint != null)
82                                                 instructions.Add (body.Instructions [i]);
83
84                                 Document doc = null;
85
86                                 int [] offsets = new int [instructions.Count];
87                                 int [] startRows = new int [instructions.Count];
88                                 int [] startCols = new int [instructions.Count];
89                                 int [] endRows = new int [instructions.Count];
90                                 int [] endCols = new int [instructions.Count];
91
92                                 for (int i = 0; i < instructions.Count; i++) {
93                                         Instruction instr = (Instruction) instructions [i];
94                                         offsets [i] = instr.Offset;
95
96                                         if (doc == null)
97                                                 doc = instr.SequencePoint.Document;
98
99                                         startRows [i] = instr.SequencePoint.StartLine;
100                                         startCols [i] = instr.SequencePoint.StartColumn;
101                                         endRows [i] = instr.SequencePoint.EndLine;
102                                         endCols [i] = instr.SequencePoint.EndColumn;
103                                 }
104
105                                 m_writer.DefineSequencePoints (GetDocument (doc),
106                                         offsets, startRows, startCols, endRows, endCols);
107
108                                 CreateLocalVariables (s, startOffset, endOffset, variables);
109
110                                 CreateScopes (body, s.Scopes, variables);
111                                 m_writer.CloseNamespace ();
112
113                                 m_writer.CloseScope (endOffset);
114                         }
115                 }
116
117                 void CreateLocalVariables (Scope s, int startOffset, int endOffset, byte [][] variables)
118                 {
119                         for (int i = 0; i < s.Variables.Count; i++) {
120                                 VariableDefinition var = s.Variables [i];
121                                 m_writer.DefineLocalVariable (
122                                         var.Name,
123                                         0,
124                                         variables [var.Index],
125                                         0,
126                                         0,
127                                         0,
128                                         0,
129                                         startOffset,
130                                         endOffset);
131                         }
132                 }
133
134                 Document CreateDocuments (MethodBody body)
135                 {
136                         Document doc = null;
137                         foreach (Instruction instr in body.Instructions) {
138                                 if (instr.SequencePoint == null)
139                                         continue;
140
141                                 if (doc == null)
142                                         doc = instr.SequencePoint.Document;
143
144                                 GetDocument (instr.SequencePoint.Document);
145                         }
146
147                         return doc;
148                 }
149
150                 SDS.ISymbolDocumentWriter GetDocument (Document document)
151                 {
152                         SDS.ISymbolDocumentWriter docWriter = m_documents [document.Url] as SDS.ISymbolDocumentWriter;
153                         if (docWriter != null)
154                                 return docWriter;
155
156                         docWriter = m_writer.DefineDocument (
157                                 document.Url,
158                                 GuidAttribute.GetGuidFromValue ((int) document.Language, typeof (DocumentLanguage)),
159                                 GuidAttribute.GetGuidFromValue ((int) document.LanguageVendor, typeof (DocumentLanguageVendor)),
160                                 GuidAttribute.GetGuidFromValue ((int) document.Type, typeof (DocumentType)));
161
162                         m_documents [document.Url] = docWriter;
163                         return docWriter;
164                 }
165
166                 public void Dispose ()
167                 {
168                         m_writer.Close ();
169                 }
170         }
171 }