2003-02-05 Martin Baulig <martin@ximian.com>
[mono.git] / mcs / class / Mono.CSharp.Debugger / MonoSymbolFile.cs
1 //
2 // System.Diagnostics.SymbolStore/MonoSymbolFile.cs
3 //
4 // Author:
5 //   Martin Baulig (martin@gnome.org)
6 //
7 // (C) 2003 Ximian, Inc.  http://www.ximian.com
8 //
9
10 using System;
11 using System.Reflection;
12 using System.Reflection.Emit;
13 using System.Collections;
14 using System.Text;
15 using System.IO;
16         
17 namespace Mono.CSharp.Debugger
18 {
19         public class MonoSymbolFileException : Exception
20         {
21                 public MonoSymbolFileException ()
22                         : base ()
23                 { }
24
25                 public MonoSymbolFileException (string message, params object[] args)
26                         : base (String.Format (message, args))
27                 { }
28         }
29
30         public class MonoSymbolFile : IDisposable
31         {
32                 ArrayList methods = new ArrayList ();
33                 ArrayList sources = new ArrayList ();
34                 Hashtable source_hash = new Hashtable ();
35                 Hashtable type_hash = new Hashtable ();
36
37                 OffsetTable ot;
38                 int last_type_index;
39                 int last_method_index;
40
41                 public MonoSymbolFile ()
42                 { }
43
44                 public SourceFileEntry DefineSource (string source_file)
45                 {
46                         if (reader != null)
47                                 throw new InvalidOperationException ();
48
49                         SourceFileEntry source = (SourceFileEntry) source_hash [source_file];
50                         if (source == null) {
51                                 source = new SourceFileEntry (this, source_file, sources.Count + 1);
52                                 source_hash.Add (source_file, source);
53                                 sources.Add (source);
54                         }
55                         return source;
56                 }
57
58                 internal int DefineType (Type type)
59                 {
60                         if (type_hash.Contains (type))
61                                 return (int) type_hash [type];
62
63                         int index = ++last_type_index;
64                         type_hash.Add (type, index);
65                         return index;
66                 }
67
68                 internal void AddMethod (MethodEntry entry)
69                 {
70                         methods.Add (entry);
71                 }
72
73                 internal int GetNextTypeIndex ()
74                 {
75                         return ++last_type_index;
76                 }
77
78                 internal int GetNextMethodIndex ()
79                 {
80                         return ++last_method_index;
81                 }
82
83                 internal void WriteString (BinaryWriter bw, string text)
84                 {
85                         byte[] data = Encoding.UTF8.GetBytes (text);
86                         bw.Write ((int) data.Length);
87                         bw.Write (data);
88                 }
89
90                 internal string ReadString (int offset)
91                 {
92                         int old_pos = (int) reader.BaseStream.Position;
93                         reader.BaseStream.Position = offset;
94                         int length = reader.ReadInt32 ();
95
96                         byte[] data = reader.ReadBytes (length);
97                         string text = Encoding.UTF8.GetString (data);
98                         reader.BaseStream.Position = old_pos;
99                         return text;
100                 }
101
102                 void Write (BinaryWriter bw)
103                 {
104                         // Magic number and file version.
105                         bw.Write (OffsetTable.Magic);
106                         bw.Write (OffsetTable.Version);
107
108                         //
109                         // Offsets of file sections; we must write this after we're done
110                         // writing the whole file, so we just reserve the space for it here.
111                         //
112                         long offset_table_offset = bw.BaseStream.Position;
113                         ot.Write (bw);
114
115                         //
116                         // Write data sections.
117                         //
118                         ot.DataSectionOffset = (int) bw.BaseStream.Position;
119                         foreach (SourceFileEntry source in sources)
120                                 source.WriteData (bw);
121                         ot.DataSectionSize = (int) bw.BaseStream.Position - ot.DataSectionOffset;
122
123                         //
124                         // Write method table.
125                         //
126                         ot.MethodTableOffset = (int) bw.BaseStream.Position;
127                         for (int i = 0; i < methods.Count; i++) {
128                                 MethodEntry entry = (MethodEntry) methods [i];
129                                 entry.WriteIndex (bw);
130                         }
131                         ot.MethodTableSize = (int) bw.BaseStream.Position - ot.MethodTableOffset;
132
133                         //
134                         // Write source table.
135                         //
136                         ot.SourceTableOffset = (int) bw.BaseStream.Position;
137                         for (int i = 0; i < sources.Count; i++) {
138                                 SourceFileEntry source = (SourceFileEntry) sources [i];
139                                 source.Write (bw);
140                         }
141                         ot.SourceTableSize = (int) bw.BaseStream.Position - ot.SourceTableOffset;
142
143                         //
144                         // Fixup offset table.
145                         //
146                         ot.TypeCount = last_type_index;
147                         ot.MethodCount = methods.Count;
148                         ot.SourceCount = sources.Count;
149
150                         //
151                         // Write offset table.
152                         //
153                         ot.TotalFileSize = (int) bw.BaseStream.Position;
154                         bw.Seek ((int) offset_table_offset, SeekOrigin.Begin);
155                         ot.Write (bw);
156                         bw.Seek (0, SeekOrigin.End);
157                 }
158
159                 public void WriteSymbolFile (string output_filename)
160                 {
161                         if (reader != null)
162                                 throw new InvalidOperationException ();
163
164                         using (FileStream stream = new FileStream (output_filename, FileMode.Create))
165                                 Write (new BinaryWriter (stream));
166                 }
167
168                 FileStream stream;
169                 BinaryReader reader;
170                 Hashtable method_hash;
171                 Hashtable source_file_hash;
172
173                 Hashtable method_name_hash;
174                 Hashtable source_name_hash;
175
176                 public MonoSymbolFile (string file_name)
177                 {
178                         stream = File.OpenRead (file_name);
179                         reader = new BinaryReader (stream);
180
181                         try {
182                                 long magic = reader.ReadInt64 ();
183                                 long version = reader.ReadInt32 ();
184                                 if ((magic != OffsetTable.Magic) || (version != OffsetTable.Version))
185                                         throw new MonoSymbolFileException ();
186                                 ot = new OffsetTable (reader);
187                         } catch {
188                                 throw new MonoSymbolFileException ();
189                         }
190
191                         method_hash = new Hashtable ();
192                         source_file_hash = new Hashtable ();
193                 }
194
195                 public int SourceCount {
196                         get { return ot.SourceCount; }
197                 }
198
199                 public int MethodCount {
200                         get { return ot.MethodCount; }
201                 }
202
203                 public int TypeCount {
204                         get { return ot.TypeCount; }
205                 }
206
207                 public SourceFileEntry GetSourceFile (int index)
208                 {
209                         if ((index < 1) || (index > ot.SourceCount))
210                                 throw new ArgumentException ();
211                         if (reader == null)
212                                 throw new InvalidOperationException ();
213
214                         SourceFileEntry source = (SourceFileEntry) source_file_hash [index];
215                         if (source != null)
216                                 return source;
217
218                         reader.BaseStream.Position = ot.SourceTableOffset +
219                                 SourceFileEntry.Size * (index - 1);
220                         source = new SourceFileEntry (this, reader);
221                         source_file_hash.Add (index, source);
222                         return source;
223                 }
224
225                 public MethodEntry GetMethod (int index)
226                 {
227                         if ((index < 1) || (index > ot.MethodCount))
228                                 throw new ArgumentException ();
229                         if (reader == null)
230                                 throw new InvalidOperationException ();
231
232                         MethodEntry entry = (MethodEntry) method_hash [index];
233                         if (entry != null)
234                                 return entry;
235
236                         reader.BaseStream.Position = ot.MethodTableOffset + 8 * (index - 1);
237                         reader.BaseStream.Position = reader.ReadInt32 ();
238
239                         entry = new MethodEntry (this, reader);
240                         method_hash.Add (index, entry);
241                         return entry;
242                 }
243
244                 public int FindMethod (string full_name)
245                 {
246                         if (reader == null)
247                                 throw new InvalidOperationException ();
248
249                         if (method_name_hash == null) {
250                                 method_name_hash = new Hashtable ();
251
252                                 for (int i = 0; i < ot.MethodCount; i++) {
253                                         reader.BaseStream.Position = ot.MethodTableOffset + 8 * i;
254
255                                         int offset = reader.ReadInt32 ();
256                                         int name_offset = reader.ReadInt32 ();
257                                         string name = ReadString (name_offset);
258
259                                         method_name_hash.Add (name, i);
260                                 }
261                         }
262
263                         object value = method_name_hash [full_name];
264                         if (value == null)
265                                 return -1;
266                         return (int) value;
267                 }
268
269                 public int FindSource (string file_name)
270                 {
271                         if (reader == null)
272                                 throw new InvalidOperationException ();
273
274                         if (source_name_hash == null) {
275                                 source_name_hash = new Hashtable ();
276
277                                 for (int i = 0; i < ot.SourceCount; i++) {
278                                         SourceFileEntry source = GetSourceFile (i + 1);
279
280                                         source_name_hash.Add (source.FileName, i);
281                                 }
282                         }
283
284                         object value = source_name_hash [file_name];
285                         if (value == null)
286                                 return -1;
287                         return (int) value;
288                 }
289
290                 internal BinaryReader BinaryReader {
291                         get {
292                                 if (reader == null)
293                                         throw new InvalidOperationException ();
294
295                                 return reader;
296                         }
297                 }
298
299                 void IDisposable.Dispose ()
300                 {
301                         Dispose (true);
302                 }
303
304                 protected virtual void Dispose (bool disposing)
305                 {
306                         if (disposing) {
307                                 if (stream != null) {
308                                         stream.Close ();
309                                         stream = null;
310                                 }
311                                 if (reader != null) {
312                                         reader.Close ();
313                                         reader = null;
314                                 }
315                         }
316                 }
317         }
318 }