* Makefile: Build the make-map.exe in Mono.Unix.Native; add /nowarn:0618 to
[mono.git] / mcs / class / Mono.CompilerServices.SymbolWriter / MonoSymbolFile.cs
1 //
2 // Mono.CSharp.Debugger/MonoSymbolFile.cs
3 //
4 // Author:
5 //   Martin Baulig (martin@ximian.com)
6 //
7 // (C) 2003 Ximian, Inc.  http://www.ximian.com
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System;
32 using System.Reflection;
33 using SRE = System.Reflection.Emit;
34 using System.Collections;
35 using System.Text;
36 using System.Threading;
37 using System.IO;
38         
39 namespace Mono.CompilerServices.SymbolWriter
40 {
41         public class MonoSymbolFileException : Exception
42         {
43                 public MonoSymbolFileException ()
44                         : base ()
45                 { }
46
47                 public MonoSymbolFileException (string message, params object[] args)
48                         : base (String.Format (message, args))
49                 { }
50         }
51
52         internal class MyBinaryWriter : BinaryWriter
53         {
54                 public MyBinaryWriter (Stream stream)
55                         : base (stream)
56                 { }
57
58                 public void WriteLeb128 (int value)
59                 {
60                         base.Write7BitEncodedInt (value);
61                 }
62         }
63
64         internal class MyBinaryReader : BinaryReader
65         {
66                 public MyBinaryReader (Stream stream)
67                         : base (stream)
68                 { }
69
70                 public int ReadLeb128 ()
71                 {
72                         return base.Read7BitEncodedInt ();
73                 }
74         }
75
76         internal class MonoDebuggerSupport
77         {
78                 static GetMethodTokenFunc get_method_token;
79                 static GetGuidFunc get_guid;
80                 static GetLocalIndexFunc get_local_index;
81
82                 delegate int GetMethodTokenFunc (MethodBase method);
83                 delegate Guid GetGuidFunc (Module module);
84                 delegate int GetLocalIndexFunc (SRE.LocalBuilder local);
85
86                 static Delegate create_delegate (Type type, Type delegate_type, string name)
87                 {
88                         MethodInfo mi = type.GetMethod (name, BindingFlags.Static |
89                                                         BindingFlags.NonPublic);
90                         if (mi == null)
91                                 throw new Exception ("Can't find " + name);
92
93                         return Delegate.CreateDelegate (delegate_type, mi);
94                 }
95
96                 static MonoDebuggerSupport ()
97                 {
98                         get_method_token = (GetMethodTokenFunc) create_delegate (
99                                 typeof (Assembly), typeof (GetMethodTokenFunc),
100                                 "MonoDebugger_GetMethodToken");
101
102                         get_guid = (GetGuidFunc) create_delegate (
103                                 typeof (Module), typeof (GetGuidFunc), "Mono_GetGuid");
104
105                         get_local_index = (GetLocalIndexFunc) create_delegate (
106                                 typeof (SRE.LocalBuilder), typeof (GetLocalIndexFunc),
107                                 "Mono_GetLocalIndex");
108                 }
109
110                 public static int GetMethodToken (MethodBase method)
111                 {
112                         return get_method_token (method);
113                 }
114
115                 public static Guid GetGuid (Module module)
116                 {
117                         return get_guid (module);
118                 }
119
120                 public static int GetLocalIndex (SRE.LocalBuilder local)
121                 {
122                         return get_local_index (local);
123                 }
124         }
125
126         public class MonoSymbolFile : IDisposable
127         {
128                 ArrayList methods = new ArrayList ();
129                 ArrayList sources = new ArrayList ();
130                 Hashtable method_source_hash = new Hashtable ();
131                 Hashtable type_hash = new Hashtable ();
132
133                 OffsetTable ot;
134                 int last_type_index;
135                 int last_method_index;
136                 int last_source_index;
137                 int last_namespace_index;
138
139                 public int NumLineNumbers;
140
141                 public MonoSymbolFile ()
142                 { }
143
144                 internal int AddSource (SourceFileEntry source)
145                 {
146                         sources.Add (source);
147                         return ++last_source_index;
148                 }
149
150                 internal int DefineType (Type type)
151                 {
152                         if (type_hash.Contains (type))
153                                 return (int) type_hash [type];
154
155                         int index = ++last_type_index;
156                         type_hash.Add (type, index);
157                         return index;
158                 }
159
160                 internal void AddMethod (MethodEntry entry)
161                 {
162                         methods.Add (entry);
163                 }
164
165                 internal int GetNextTypeIndex ()
166                 {
167                         return ++last_type_index;
168                 }
169
170                 internal int GetNextMethodIndex ()
171                 {
172                         return ++last_method_index;
173                 }
174
175                 internal int GetNextNamespaceIndex ()
176                 {
177                         return ++last_namespace_index;
178                 }
179                 
180                 internal string ReadString (int offset)
181                 {
182                         int old_pos = (int) reader.BaseStream.Position;
183                         reader.BaseStream.Position = offset;
184
185                         string text = reader.ReadString ();
186
187                         reader.BaseStream.Position = old_pos;
188                         return text;
189                 }
190
191                 void Write (MyBinaryWriter bw, Guid guid)
192                 {
193                         // Magic number and file version.
194                         bw.Write (OffsetTable.Magic);
195                         bw.Write (OffsetTable.Version);
196
197                         bw.Write (guid.ToByteArray ());
198
199                         //
200                         // Offsets of file sections; we must write this after we're done
201                         // writing the whole file, so we just reserve the space for it here.
202                         //
203                         long offset_table_offset = bw.BaseStream.Position;
204                         ot.Write (bw);
205
206                         //
207                         // Sort the methods according to their tokens and update their index.
208                         //
209                         methods.Sort ();
210                         for (int i = 0; i < methods.Count; i++)
211                                 ((MethodEntry) methods [i]).Index = i + 1;
212
213                         //
214                         // Write data sections.
215                         //
216                         ot.DataSectionOffset = (int) bw.BaseStream.Position;
217                         foreach (SourceFileEntry source in sources)
218                                 source.WriteData (bw);
219                         ot.DataSectionSize = (int) bw.BaseStream.Position - ot.DataSectionOffset;
220
221                         //
222                         // Write the method index table.
223                         //
224                         ot.MethodTableOffset = (int) bw.BaseStream.Position;
225                         for (int i = 0; i < methods.Count; i++) {
226                                 MethodEntry entry = (MethodEntry) methods [i];
227                                 entry.WriteIndex (bw);
228                         }
229                         ot.MethodTableSize = (int) bw.BaseStream.Position - ot.MethodTableOffset;
230
231                         //
232                         // Write source table.
233                         //
234                         ot.SourceTableOffset = (int) bw.BaseStream.Position;
235                         for (int i = 0; i < sources.Count; i++) {
236                                 SourceFileEntry source = (SourceFileEntry) sources [i];
237                                 source.Write (bw);
238                         }
239                         ot.SourceTableSize = (int) bw.BaseStream.Position - ot.SourceTableOffset;
240
241                         //
242                         // Fixup offset table.
243                         //
244                         ot.TypeCount = last_type_index;
245                         ot.MethodCount = methods.Count;
246                         ot.SourceCount = sources.Count;
247
248                         //
249                         // Write offset table.
250                         //
251                         ot.TotalFileSize = (int) bw.BaseStream.Position;
252                         bw.Seek ((int) offset_table_offset, SeekOrigin.Begin);
253                         ot.Write (bw);
254                         bw.Seek (0, SeekOrigin.End);
255                 }
256
257                 public void CreateSymbolFile (Guid guid, FileStream fs)
258                 {
259                         if (reader != null)
260                                 throw new InvalidOperationException ();
261                         
262                         Write (new MyBinaryWriter (fs), guid);
263                 }
264
265                 Assembly assembly;
266                 MyBinaryReader reader;
267                 Hashtable method_hash;
268                 Hashtable source_file_hash;
269
270                 Hashtable method_token_hash;
271                 Hashtable source_name_hash;
272
273                 protected MonoSymbolFile (string filename, Assembly assembly)
274                 {
275                         this.assembly = assembly;
276
277                         FileStream stream = new FileStream (filename, FileMode.Open, FileAccess.Read);
278                         reader = new MyBinaryReader (stream);
279
280                         Guid guid;
281
282                         try {
283                                 long magic = reader.ReadInt64 ();
284                                 long version = reader.ReadInt32 ();
285                                 if (magic != OffsetTable.Magic)
286                                         throw new MonoSymbolFileException (
287                                                 "Symbol file `{0}' is not a valid " +
288                                                 "Mono symbol file", filename);
289                                 if (version != OffsetTable.Version)
290                                         throw new MonoSymbolFileException (
291                                                 "Symbol file `{0}' has version {1}, " +
292                                                 "but expected {2}", filename, version,
293                                                 OffsetTable.Version);
294
295                                 guid = new Guid (reader.ReadBytes (16));
296
297                                 ot = new OffsetTable (reader);
298                         } catch {
299                                 throw new MonoSymbolFileException (
300                                         "Cannot read symbol file `{0}'", filename);
301                         }
302
303                         Module[] modules = assembly.GetModules ();
304                         Guid assembly_guid = MonoDebuggerSupport.GetGuid (modules [0]);
305
306                         if (guid != assembly_guid)
307                                 throw new MonoSymbolFileException (
308                                         "Symbol file `{0}' does not match assembly `{1}'",
309                                         filename, assembly.Location);
310
311                         method_hash = new Hashtable ();
312                         source_file_hash = new Hashtable ();
313                 }
314
315                 public static MonoSymbolFile ReadSymbolFile (Assembly assembly)
316                 {
317                         string filename = assembly.Location;
318                         string name = filename + ".mdb";
319
320                         return new MonoSymbolFile (name, assembly);
321                 }
322
323                 public Assembly Assembly {
324                         get { return assembly; }
325                 }
326
327                 public int SourceCount {
328                         get { return ot.SourceCount; }
329                 }
330
331                 public int MethodCount {
332                         get { return ot.MethodCount; }
333                 }
334
335                 public int TypeCount {
336                         get { return ot.TypeCount; }
337                 }
338
339                 public int NamespaceCount {
340                         get { return last_namespace_index; }
341                 }
342
343                 internal int LineNumberCount = 0;
344                 internal int LocalCount = 0;
345                 internal int StringSize = 0;
346
347                 public SourceFileEntry GetSourceFile (int index)
348                 {
349                         if ((index < 1) || (index > ot.SourceCount))
350                                 throw new ArgumentException ();
351                         if (reader == null)
352                                 throw new InvalidOperationException ();
353
354                         SourceFileEntry source = (SourceFileEntry) source_file_hash [index];
355                         if (source != null)
356                                 return source;
357
358                         reader.BaseStream.Position = ot.SourceTableOffset +
359                                 SourceFileEntry.Size * (index - 1);
360                         source = new SourceFileEntry (this, reader);
361                         source_file_hash.Add (index, source);
362                         return source;
363                 }
364
365                 public SourceFileEntry[] Sources {
366                         get {
367                                 if (reader == null)
368                                         throw new InvalidOperationException ();
369
370                                 SourceFileEntry[] retval = new SourceFileEntry [SourceCount];
371                                 for (int i = 0; i < SourceCount; i++)
372                                         retval [i] = GetSourceFile (i + 1);
373                                 return retval;
374                         }
375                 }
376
377                 public MethodIndexEntry GetMethodIndexEntry (int index)
378                 {
379                         int old_pos = (int) reader.BaseStream.Position;
380                         reader.BaseStream.Position = ot.MethodTableOffset +
381                                 MethodIndexEntry.Size * (index - 1);
382                         MethodIndexEntry ie = new MethodIndexEntry (reader);
383                         reader.BaseStream.Position = old_pos;
384                         return ie;
385                 }
386
387                 public MethodEntry GetMethodByToken (int token)
388                 {
389                         if (reader == null)
390                                 throw new InvalidOperationException ();
391
392                         if (method_token_hash == null) {
393                                 method_token_hash = new Hashtable ();
394
395                                 for (int i = 0; i < MethodCount; i++) {
396                                         MethodIndexEntry ie = GetMethodIndexEntry (i + 1);
397
398                                         method_token_hash.Add (ie.Token, i + 1);
399                                 }
400                         }
401
402                         object value = method_token_hash [token];
403                         if (value == null)
404                                 return null;
405
406                         return GetMethod ((int) value);
407                 }
408
409                 public MethodEntry GetMethod (MethodBase method)
410                 {
411                         if (reader == null)
412                                 throw new InvalidOperationException ();
413                         int token = MonoDebuggerSupport.GetMethodToken (method);
414                         return GetMethodByToken (token);
415                 }
416
417                 public MethodEntry GetMethod (int index)
418                 {
419                         if ((index < 1) || (index > ot.MethodCount))
420                                 throw new ArgumentException ();
421                         if (reader == null)
422                                 throw new InvalidOperationException ();
423
424                         MethodEntry entry = (MethodEntry) method_hash [index];
425                         if (entry != null)
426                                 return entry;
427
428                         MethodIndexEntry ie = GetMethodIndexEntry (index);
429                         reader.BaseStream.Position = ie.FileOffset;
430
431                         entry = new MethodEntry (this, reader, index);
432                         method_hash.Add (index, entry);
433                         return entry;
434                 }
435
436                 public MethodEntry[] Methods {
437                         get {
438                                 if (reader == null)
439                                         throw new InvalidOperationException ();
440
441                                 MethodEntry[] retval = new MethodEntry [MethodCount];
442                                 for (int i = 0; i < MethodCount; i++)
443                                         retval [i] = GetMethod (i + 1);
444                                 return retval;
445                         }
446                 }
447
448                 public MethodSourceEntry GetMethodSource (int index)
449                 {
450                         if ((index < 1) || (index > ot.MethodCount))
451                                 throw new ArgumentException ();
452                         if (reader == null)
453                                 throw new InvalidOperationException ();
454
455                         object entry = method_source_hash [index];
456                         if (entry != null)
457                                 return (MethodSourceEntry) entry;
458
459                         MethodEntry method = GetMethod (index);
460                         foreach (MethodSourceEntry source in method.SourceFile.Methods) {
461                                 if (source.Index == index) {
462                                         method_source_hash.Add (index, source);
463                                         return source;
464                                 }
465                         }
466
467                         throw new MonoSymbolFileException ("Internal error.");
468                 }
469
470                 public int FindSource (string file_name)
471                 {
472                         if (reader == null)
473                                 throw new InvalidOperationException ();
474
475                         if (source_name_hash == null) {
476                                 source_name_hash = new Hashtable ();
477
478                                 for (int i = 0; i < ot.SourceCount; i++) {
479                                         SourceFileEntry source = GetSourceFile (i + 1);
480
481                                         source_name_hash.Add (source.FileName, i);
482                                 }
483                         }
484
485                         object value = source_name_hash [file_name];
486                         if (value == null)
487                                 return -1;
488                         return (int) value;
489                 }
490
491                 internal MyBinaryReader BinaryReader {
492                         get {
493                                 if (reader == null)
494                                         throw new InvalidOperationException ();
495
496                                 return reader;
497                         }
498                 }
499
500                 public void Dispose ()
501                 {
502                         Dispose (true);
503                 }
504
505                 protected virtual void Dispose (bool disposing)
506                 {
507                         if (disposing) {
508                                 if (reader != null) {
509                                         reader.Close ();
510                                         reader = null;
511                                 }
512                         }
513                 }
514         }
515 }