Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Parser/mcs/MonoSymbolFile.cs @ 16240

Last change on this file since 16240 was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

File size: 15.8 KB
Line 
1//
2// MonoSymbolFile.cs
3//
4// Authors:
5//   Martin Baulig (martin@ximian.com)
6//   Marek Safar (marek.safar@gmail.com)
7//
8// (C) 2003 Ximian, Inc.  http://www.ximian.com
9// Copyright (C) 2012 Xamarin Inc (http://www.xamarin.com)
10//
11//
12// Permission is hereby granted, free of charge, to any person obtaining
13// a copy of this software and associated documentation files (the
14// "Software"), to deal in the Software without restriction, including
15// without limitation the rights to use, copy, modify, merge, publish,
16// distribute, sublicense, and/or sell copies of the Software, and to
17// permit persons to whom the Software is furnished to do so, subject to
18// the following conditions:
19//
20// The above copyright notice and this permission notice shall be
21// included in all copies or substantial portions of the Software.
22//
23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30//
31
32using System;
33using System.Reflection;
34using System.Collections.Generic;
35using System.IO;
36 
37namespace Mono.CompilerServices.SymbolWriter
38{
39  public class MonoSymbolFileException : Exception
40  {
41    public MonoSymbolFileException ()
42      : base ()
43    { }
44
45    public MonoSymbolFileException (string message, params object[] args)
46      : base (String.Format (message, args))
47    {
48    }
49
50    public MonoSymbolFileException (string message, Exception innerException)
51      : base (message, innerException)
52    {
53    }
54  }
55
56  sealed class MyBinaryWriter : BinaryWriter
57  {
58    public MyBinaryWriter (Stream stream)
59      : base (stream)
60    { }
61
62    public void WriteLeb128 (int value)
63    {
64      base.Write7BitEncodedInt (value);
65    }
66  }
67
68  internal class MyBinaryReader : BinaryReader
69  {
70    public MyBinaryReader (Stream stream)
71      : base (stream)
72    { }
73
74    public int ReadLeb128 ()
75    {
76      return base.Read7BitEncodedInt ();
77    }
78
79    public string ReadString (int offset)
80    {
81      long old_pos = BaseStream.Position;
82      BaseStream.Position = offset;
83
84      string text = ReadString ();
85
86      BaseStream.Position = old_pos;
87      return text;
88    }
89  }
90
91  public interface ISourceFile
92  {
93    SourceFileEntry Entry {
94      get;
95    }
96  }
97
98  public interface ICompileUnit
99  {
100    CompileUnitEntry Entry {
101      get;
102    }
103  }
104
105  public interface IMethodDef
106  {
107    string Name {
108      get;
109    }
110
111    int Token {
112      get;
113    }
114  }
115
116  public class MonoSymbolFile : IDisposable
117  {
118    List<MethodEntry> methods = new List<MethodEntry> ();
119    List<SourceFileEntry> sources = new List<SourceFileEntry> ();
120    List<CompileUnitEntry> comp_units = new List<CompileUnitEntry> ();
121    Dictionary<int, AnonymousScopeEntry> anonymous_scopes;
122
123    OffsetTable ot;
124    int last_type_index;
125    int last_method_index;
126    int last_namespace_index;
127
128    public readonly int MajorVersion = OffsetTable.MajorVersion;
129    public readonly int MinorVersion = OffsetTable.MinorVersion;
130
131    public int NumLineNumbers;
132
133    public MonoSymbolFile ()
134    {
135      ot = new OffsetTable ();
136    }
137
138    public int AddSource (SourceFileEntry source)
139    {
140      sources.Add (source);
141      return sources.Count;
142    }
143
144    public int AddCompileUnit (CompileUnitEntry entry)
145    {
146      comp_units.Add (entry);
147      return comp_units.Count;
148    }
149
150    public void AddMethod (MethodEntry entry)
151    {
152      methods.Add (entry);
153    }
154
155    public MethodEntry DefineMethod (CompileUnitEntry comp_unit, int token,
156             ScopeVariable[] scope_vars, LocalVariableEntry[] locals,
157             LineNumberEntry[] lines, CodeBlockEntry[] code_blocks,
158             string real_name, MethodEntry.Flags flags,
159             int namespace_id)
160    {
161      if (reader != null)
162        throw new InvalidOperationException ();
163
164      MethodEntry method = new MethodEntry (
165        this, comp_unit, token, scope_vars, locals, lines, code_blocks,
166        real_name, flags, namespace_id);
167      AddMethod (method);
168      return method;
169    }
170
171    internal void DefineAnonymousScope (int id)
172    {
173      if (reader != null)
174        throw new InvalidOperationException ();
175
176      if (anonymous_scopes == null)
177        anonymous_scopes = new Dictionary<int, AnonymousScopeEntry>  ();
178
179      anonymous_scopes.Add (id, new AnonymousScopeEntry (id));
180    }
181
182    internal void DefineCapturedVariable (int scope_id, string name, string captured_name,
183                  CapturedVariable.CapturedKind kind)
184    {
185      if (reader != null)
186        throw new InvalidOperationException ();
187
188      AnonymousScopeEntry scope = anonymous_scopes [scope_id];
189      scope.AddCapturedVariable (name, captured_name, kind);
190    }
191
192    internal void DefineCapturedScope (int scope_id, int id, string captured_name)
193    {
194      if (reader != null)
195        throw new InvalidOperationException ();
196
197      AnonymousScopeEntry scope = anonymous_scopes [scope_id];
198      scope.AddCapturedScope (id, captured_name);
199    }
200
201    internal int GetNextTypeIndex ()
202    {
203      return ++last_type_index;
204    }
205
206    internal int GetNextMethodIndex ()
207    {
208      return ++last_method_index;
209    }
210
211    internal int GetNextNamespaceIndex ()
212    {
213      return ++last_namespace_index;
214    }
215   
216    void Write (MyBinaryWriter bw, Guid guid)
217    {
218      // Magic number and file version.
219      bw.Write (OffsetTable.Magic);
220      bw.Write (MajorVersion);
221      bw.Write (MinorVersion);
222
223      bw.Write (guid.ToByteArray ());
224
225      //
226      // Offsets of file sections; we must write this after we're done
227      // writing the whole file, so we just reserve the space for it here.
228      //
229      long offset_table_offset = bw.BaseStream.Position;
230      ot.Write (bw, MajorVersion, MinorVersion);
231
232      //
233      // Sort the methods according to their tokens and update their index.
234      //
235      methods.Sort ();
236      for (int i = 0; i < methods.Count; i++)
237        methods [i].Index = i + 1;
238
239      //
240      // Write data sections.
241      //
242      ot.DataSectionOffset = (int) bw.BaseStream.Position;
243      foreach (SourceFileEntry source in sources)
244        source.WriteData (bw);
245      foreach (CompileUnitEntry comp_unit in comp_units)
246        comp_unit.WriteData (bw);
247      foreach (MethodEntry method in methods)
248        method.WriteData (this, bw);
249      ot.DataSectionSize = (int) bw.BaseStream.Position - ot.DataSectionOffset;
250
251      //
252      // Write the method index table.
253      //
254      ot.MethodTableOffset = (int) bw.BaseStream.Position;
255      for (int i = 0; i < methods.Count; i++) {
256        MethodEntry entry = methods [i];
257        entry.Write (bw);
258      }
259      ot.MethodTableSize = (int) bw.BaseStream.Position - ot.MethodTableOffset;
260
261      //
262      // Write source table.
263      //
264      ot.SourceTableOffset = (int) bw.BaseStream.Position;
265      for (int i = 0; i < sources.Count; i++) {
266        SourceFileEntry source = sources [i];
267        source.Write (bw);
268      }
269      ot.SourceTableSize = (int) bw.BaseStream.Position - ot.SourceTableOffset;
270
271      //
272      // Write compilation unit table.
273      //
274      ot.CompileUnitTableOffset = (int) bw.BaseStream.Position;
275      for (int i = 0; i < comp_units.Count; i++) {
276        CompileUnitEntry unit = comp_units [i];
277        unit.Write (bw);
278      }
279      ot.CompileUnitTableSize = (int) bw.BaseStream.Position - ot.CompileUnitTableOffset;
280
281      //
282      // Write anonymous scope table.
283      //
284      ot.AnonymousScopeCount = anonymous_scopes != null ? anonymous_scopes.Count : 0;
285      ot.AnonymousScopeTableOffset = (int) bw.BaseStream.Position;
286      if (anonymous_scopes != null) {
287        foreach (AnonymousScopeEntry scope in anonymous_scopes.Values)
288          scope.Write (bw);
289      }
290      ot.AnonymousScopeTableSize = (int) bw.BaseStream.Position - ot.AnonymousScopeTableOffset;
291
292      //
293      // Fixup offset table.
294      //
295      ot.TypeCount = last_type_index;
296      ot.MethodCount = methods.Count;
297      ot.SourceCount = sources.Count;
298      ot.CompileUnitCount = comp_units.Count;
299
300      //
301      // Write offset table.
302      //
303      ot.TotalFileSize = (int) bw.BaseStream.Position;
304      bw.Seek ((int) offset_table_offset, SeekOrigin.Begin);
305      ot.Write (bw, MajorVersion, MinorVersion);
306      bw.Seek (0, SeekOrigin.End);
307
308#if false
309      Console.WriteLine ("TOTAL: {0} line numbes, {1} bytes, extended {2} bytes, " +
310             "{3} methods.", NumLineNumbers, LineNumberSize,
311             ExtendedLineNumberSize, methods.Count);
312#endif
313    }
314
315    public void CreateSymbolFile (Guid guid, FileStream fs)
316    {
317      if (reader != null)
318        throw new InvalidOperationException ();
319
320      Write (new MyBinaryWriter (fs), guid);
321    }
322
323    MyBinaryReader reader;
324    Dictionary<int, SourceFileEntry> source_file_hash;
325    Dictionary<int, CompileUnitEntry> compile_unit_hash;
326
327    List<MethodEntry> method_list;
328    Dictionary<int, MethodEntry> method_token_hash;
329    Dictionary<string, int> source_name_hash;
330
331    Guid guid;
332
333    MonoSymbolFile (Stream stream)
334    {
335      reader = new MyBinaryReader (stream);
336
337      try {
338        long magic = reader.ReadInt64 ();
339        int major_version = reader.ReadInt32 ();
340        int minor_version = reader.ReadInt32 ();
341
342        if (magic != OffsetTable.Magic)
343          throw new MonoSymbolFileException ("Symbol file is not a valid");
344        if (major_version != OffsetTable.MajorVersion)
345          throw new MonoSymbolFileException (
346            "Symbol file has version {0} but expected {1}", major_version, OffsetTable.MajorVersion);
347        if (minor_version != OffsetTable.MinorVersion)
348          throw new MonoSymbolFileException ("Symbol file has version {0}.{1} but expected {2}.{3}",
349            major_version, minor_version,
350            OffsetTable.MajorVersion, OffsetTable.MinorVersion);
351
352        MajorVersion = major_version;
353        MinorVersion = minor_version;
354        guid = new Guid (reader.ReadBytes (16));
355
356        ot = new OffsetTable (reader, major_version, minor_version);
357      } catch (Exception e) {
358        throw new MonoSymbolFileException ("Cannot read symbol file", e);
359      }
360
361      source_file_hash = new Dictionary<int, SourceFileEntry> ();
362      compile_unit_hash = new Dictionary<int, CompileUnitEntry> ();
363    }
364
365    public static MonoSymbolFile ReadSymbolFile (Assembly assembly)
366    {
367      string filename = assembly.Location;
368      string name = filename + ".mdb";
369
370      Module[] modules = assembly.GetModules ();
371      Guid assembly_guid = modules[0].ModuleVersionId;
372
373      return ReadSymbolFile (name, assembly_guid);
374    }
375
376    public static MonoSymbolFile ReadSymbolFile (string mdbFilename)
377    {
378      return ReadSymbolFile (new FileStream (mdbFilename, FileMode.Open, FileAccess.Read));
379    }
380
381    public static MonoSymbolFile ReadSymbolFile (string mdbFilename, Guid assemblyGuid)
382    {
383      var sf = ReadSymbolFile (mdbFilename);
384      if (assemblyGuid != sf.guid)
385        throw new MonoSymbolFileException ("Symbol file `{0}' does not match assembly", mdbFilename);
386
387      return sf;
388    }
389
390    public static MonoSymbolFile ReadSymbolFile (Stream stream)
391    {
392      return new MonoSymbolFile (stream);
393    }
394
395    public int CompileUnitCount {
396      get { return ot.CompileUnitCount; }
397    }
398
399    public int SourceCount {
400      get { return ot.SourceCount; }
401    }
402
403    public int MethodCount {
404      get { return ot.MethodCount; }
405    }
406
407    public int TypeCount {
408      get { return ot.TypeCount; }
409    }
410
411    public int AnonymousScopeCount {
412      get { return ot.AnonymousScopeCount; }
413    }
414
415    public int NamespaceCount {
416      get { return last_namespace_index; }
417    }
418
419    public Guid Guid {
420      get { return guid; }
421    }
422
423    public OffsetTable OffsetTable {
424      get { return ot; }
425    }
426
427    internal int LineNumberCount = 0;
428    internal int LocalCount = 0;
429    internal int StringSize = 0;
430
431    internal int LineNumberSize = 0;
432    internal int ExtendedLineNumberSize = 0;
433
434    public SourceFileEntry GetSourceFile (int index)
435    {
436      if ((index < 1) || (index > ot.SourceCount))
437        throw new ArgumentException ();
438      if (reader == null)
439        throw new InvalidOperationException ();
440
441      lock (this) {
442        SourceFileEntry source;
443        if (source_file_hash.TryGetValue (index, out source))
444          return source;
445
446        long old_pos = reader.BaseStream.Position;
447
448        reader.BaseStream.Position = ot.SourceTableOffset +
449          SourceFileEntry.Size * (index - 1);
450        source = new SourceFileEntry (this, reader);
451        source_file_hash.Add (index, source);
452
453        reader.BaseStream.Position = old_pos;
454        return source;
455      }
456    }
457
458    public SourceFileEntry[] Sources {
459      get {
460        if (reader == null)
461          throw new InvalidOperationException ();
462
463        SourceFileEntry[] retval = new SourceFileEntry [SourceCount];
464        for (int i = 0; i < SourceCount; i++)
465          retval [i] = GetSourceFile (i + 1);
466        return retval;
467      }
468    }
469
470    public CompileUnitEntry GetCompileUnit (int index)
471    {
472      if ((index < 1) || (index > ot.CompileUnitCount))
473        throw new ArgumentException ();
474      if (reader == null)
475        throw new InvalidOperationException ();
476
477      lock (this) {
478        CompileUnitEntry unit;
479        if (compile_unit_hash.TryGetValue (index, out unit))
480          return unit;
481
482        long old_pos = reader.BaseStream.Position;
483
484        reader.BaseStream.Position = ot.CompileUnitTableOffset +
485          CompileUnitEntry.Size * (index - 1);
486        unit = new CompileUnitEntry (this, reader);
487        compile_unit_hash.Add (index, unit);
488
489        reader.BaseStream.Position = old_pos;
490        return unit;
491      }
492    }
493
494    public CompileUnitEntry[] CompileUnits {
495      get {
496        if (reader == null)
497          throw new InvalidOperationException ();
498
499        CompileUnitEntry[] retval = new CompileUnitEntry [CompileUnitCount];
500        for (int i = 0; i < CompileUnitCount; i++)
501          retval [i] = GetCompileUnit (i + 1);
502        return retval;
503      }
504    }
505
506    void read_methods ()
507    {
508      lock (this) {
509        if (method_token_hash != null)
510          return;
511
512        method_token_hash = new Dictionary<int, MethodEntry> ();
513        method_list = new List<MethodEntry> ();
514
515        long old_pos = reader.BaseStream.Position;
516        reader.BaseStream.Position = ot.MethodTableOffset;
517
518        for (int i = 0; i < MethodCount; i++) {
519          MethodEntry entry = new MethodEntry (this, reader, i + 1);
520          method_token_hash.Add (entry.Token, entry);
521          method_list.Add (entry);
522        }
523
524        reader.BaseStream.Position = old_pos;
525      }
526    }
527
528    public MethodEntry GetMethodByToken (int token)
529    {
530      if (reader == null)
531        throw new InvalidOperationException ();
532
533      lock (this) {
534        read_methods ();
535        MethodEntry me;
536        method_token_hash.TryGetValue (token, out me);
537        return me;
538      }
539    }
540
541    public MethodEntry GetMethod (int index)
542    {
543      if ((index < 1) || (index > ot.MethodCount))
544        throw new ArgumentException ();
545      if (reader == null)
546        throw new InvalidOperationException ();
547
548      lock (this) {
549        read_methods ();
550        return method_list [index - 1];
551      }
552    }
553
554    public MethodEntry[] Methods {
555      get {
556        if (reader == null)
557          throw new InvalidOperationException ();
558
559        lock (this) {
560          read_methods ();
561          MethodEntry[] retval = new MethodEntry [MethodCount];
562          method_list.CopyTo (retval, 0);
563          return retval;
564        }
565      }
566    }
567
568    public int FindSource (string file_name)
569    {
570      if (reader == null)
571        throw new InvalidOperationException ();
572
573      lock (this) {
574        if (source_name_hash == null) {
575          source_name_hash = new Dictionary<string, int> ();
576
577          for (int i = 0; i < ot.SourceCount; i++) {
578            SourceFileEntry source = GetSourceFile (i + 1);
579            source_name_hash.Add (source.FileName, i);
580          }
581        }
582
583        int value;
584        if (!source_name_hash.TryGetValue (file_name, out value))
585          return -1;
586        return value;
587      }
588    }
589
590    public AnonymousScopeEntry GetAnonymousScope (int id)
591    {
592      if (reader == null)
593        throw new InvalidOperationException ();
594
595      AnonymousScopeEntry scope;
596      lock (this) {
597        if (anonymous_scopes != null) {
598          anonymous_scopes.TryGetValue (id, out scope);
599          return scope;
600        }
601
602        anonymous_scopes = new Dictionary<int, AnonymousScopeEntry> ();
603        reader.BaseStream.Position = ot.AnonymousScopeTableOffset;
604        for (int i = 0; i < ot.AnonymousScopeCount; i++) {
605          scope = new AnonymousScopeEntry (reader);
606          anonymous_scopes.Add (scope.ID, scope);
607        }
608
609        return anonymous_scopes [id];
610      }
611    }
612
613    internal MyBinaryReader BinaryReader {
614      get {
615        if (reader == null)
616          throw new InvalidOperationException ();
617
618        return reader;
619      }
620    }
621
622    public void Dispose ()
623    {
624      Dispose (true);
625    }
626
627    protected virtual void Dispose (bool disposing)
628    {
629      if (disposing) {
630        if (reader != null) {
631          reader.Close ();
632          reader = null;
633        }
634      }
635    }
636  }
637}
Note: See TracBrowser for help on using the repository browser.