Free cookie consent management tool by TermsFeed Policy Generator

source: branches/RemoveBackwardsCompatibility/HeuristicLab.ExtLibs/HeuristicLab.Cecil/0.9.5/Mono.Cecil-0.9.5/Symbols/Mono.Cecil.Mdb/Mono.CompilerServices.SymbolWriter/MonoSymbolFile.cs @ 16724

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

#2077: created branch and added first version

File size: 18.3 KB
Line 
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
31using System;
32using System.Reflection;
33using SRE = System.Reflection.Emit;
34using System.Collections.Generic;
35using System.Text;
36using System.Threading;
37using System.IO;
38
39namespace 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    public string ReadString (int offset)
76    {
77      long old_pos = BaseStream.Position;
78      BaseStream.Position = offset;
79
80      string text = ReadString ();
81
82      BaseStream.Position = old_pos;
83      return text;
84    }
85  }
86
87  public interface ISourceFile
88  {
89    SourceFileEntry Entry {
90      get;
91    }
92  }
93
94  public interface ICompileUnit
95  {
96    CompileUnitEntry Entry {
97      get;
98    }
99  }
100
101  public interface IMethodDef
102  {
103    string Name {
104      get;
105    }
106
107    int Token {
108      get;
109    }
110  }
111
112#if !CECIL
113  internal class MonoDebuggerSupport
114  {
115    static GetMethodTokenFunc get_method_token;
116    static GetGuidFunc get_guid;
117    static GetLocalIndexFunc get_local_index;
118
119    delegate int GetMethodTokenFunc (MethodBase method);
120    delegate Guid GetGuidFunc (Module module);
121    delegate int GetLocalIndexFunc (SRE.LocalBuilder local);
122
123    static Delegate create_delegate (Type type, Type delegate_type, string name)
124    {
125      MethodInfo mi = type.GetMethod (name, BindingFlags.Static |
126              BindingFlags.NonPublic);
127      if (mi == null)
128        throw new Exception ("Can't find " + name);
129
130      return Delegate.CreateDelegate (delegate_type, mi);
131    }
132
133    static MonoDebuggerSupport ()
134    {
135      get_method_token = (GetMethodTokenFunc) create_delegate (
136        typeof (Assembly), typeof (GetMethodTokenFunc),
137        "MonoDebugger_GetMethodToken");
138
139      get_guid = (GetGuidFunc) create_delegate (
140        typeof (Module), typeof (GetGuidFunc), "Mono_GetGuid");
141
142      get_local_index = (GetLocalIndexFunc) create_delegate (
143        typeof (SRE.LocalBuilder), typeof (GetLocalIndexFunc),
144        "Mono_GetLocalIndex");
145    }
146
147    public static int GetMethodToken (MethodBase method)
148    {
149      return get_method_token (method);
150    }
151
152    public static Guid GetGuid (Module module)
153    {
154      return get_guid (module);
155    }
156
157    public static int GetLocalIndex (SRE.LocalBuilder local)
158    {
159      return get_local_index (local);
160    }
161  }
162#endif
163
164  public class MonoSymbolFile : IDisposable
165  {
166    List<MethodEntry> methods = new List<MethodEntry> ();
167    List<SourceFileEntry> sources = new List<SourceFileEntry> ();
168    List<CompileUnitEntry> comp_units = new List<CompileUnitEntry> ();
169    Dictionary<Type, int> type_hash = new Dictionary<Type, int> ();
170    Dictionary<int, AnonymousScopeEntry> anonymous_scopes;
171
172    OffsetTable ot;
173    int last_type_index;
174    int last_method_index;
175    int last_namespace_index;
176
177    public readonly string FileName = "<dynamic>";
178    public readonly int MajorVersion = OffsetTable.MajorVersion;
179    public readonly int MinorVersion = OffsetTable.MinorVersion;
180
181    public int NumLineNumbers;
182
183    internal MonoSymbolFile ()
184    {
185      ot = new OffsetTable ();
186    }
187
188    internal int AddSource (SourceFileEntry source)
189    {
190      sources.Add (source);
191      return sources.Count;
192    }
193
194    internal int AddCompileUnit (CompileUnitEntry entry)
195    {
196      comp_units.Add (entry);
197      return comp_units.Count;
198    }
199
200    internal int DefineType (Type type)
201    {
202      int index;
203      if (type_hash.TryGetValue (type, out index))
204        return index;
205
206      index = ++last_type_index;
207      type_hash.Add (type, index);
208      return index;
209    }
210
211    internal void AddMethod (MethodEntry entry)
212    {
213      methods.Add (entry);
214    }
215
216    public MethodEntry DefineMethod (CompileUnitEntry comp_unit, int token,
217             ScopeVariable[] scope_vars, LocalVariableEntry[] locals,
218             LineNumberEntry[] lines, CodeBlockEntry[] code_blocks,
219             string real_name, MethodEntry.Flags flags,
220             int namespace_id)
221    {
222      if (reader != null)
223        throw new InvalidOperationException ();
224
225      MethodEntry method = new MethodEntry (
226        this, comp_unit, token, scope_vars, locals, lines, code_blocks,
227        real_name, flags, namespace_id);
228      AddMethod (method);
229      return method;
230    }
231
232    internal void DefineAnonymousScope (int id)
233    {
234      if (reader != null)
235        throw new InvalidOperationException ();
236
237      if (anonymous_scopes == null)
238        anonymous_scopes = new Dictionary<int, AnonymousScopeEntry>  ();
239
240      anonymous_scopes.Add (id, new AnonymousScopeEntry (id));
241    }
242
243    internal void DefineCapturedVariable (int scope_id, string name, string captured_name,
244                  CapturedVariable.CapturedKind kind)
245    {
246      if (reader != null)
247        throw new InvalidOperationException ();
248
249      AnonymousScopeEntry scope = anonymous_scopes [scope_id];
250      scope.AddCapturedVariable (name, captured_name, kind);
251    }
252
253    internal void DefineCapturedScope (int scope_id, int id, string captured_name)
254    {
255      if (reader != null)
256        throw new InvalidOperationException ();
257
258      AnonymousScopeEntry scope = anonymous_scopes [scope_id];
259      scope.AddCapturedScope (id, captured_name);
260    }
261
262    internal int GetNextTypeIndex ()
263    {
264      return ++last_type_index;
265    }
266
267    internal int GetNextMethodIndex ()
268    {
269      return ++last_method_index;
270    }
271
272    internal int GetNextNamespaceIndex ()
273    {
274      return ++last_namespace_index;
275    }
276
277    void Write (MyBinaryWriter bw, Guid guid)
278    {
279      // Magic number and file version.
280      bw.Write (OffsetTable.Magic);
281      bw.Write (MajorVersion);
282      bw.Write (MinorVersion);
283
284      bw.Write (guid.ToByteArray ());
285
286      //
287      // Offsets of file sections; we must write this after we're done
288      // writing the whole file, so we just reserve the space for it here.
289      //
290      long offset_table_offset = bw.BaseStream.Position;
291      ot.Write (bw, MajorVersion, MinorVersion);
292
293      //
294      // Sort the methods according to their tokens and update their index.
295      //
296      methods.Sort ();
297      for (int i = 0; i < methods.Count; i++)
298        ((MethodEntry) methods [i]).Index = i + 1;
299
300      //
301      // Write data sections.
302      //
303      ot.DataSectionOffset = (int) bw.BaseStream.Position;
304      foreach (SourceFileEntry source in sources)
305        source.WriteData (bw);
306      foreach (CompileUnitEntry comp_unit in comp_units)
307        comp_unit.WriteData (bw);
308      foreach (MethodEntry method in methods)
309        method.WriteData (this, bw);
310      ot.DataSectionSize = (int) bw.BaseStream.Position - ot.DataSectionOffset;
311
312      //
313      // Write the method index table.
314      //
315      ot.MethodTableOffset = (int) bw.BaseStream.Position;
316      for (int i = 0; i < methods.Count; i++) {
317        MethodEntry entry = (MethodEntry) methods [i];
318        entry.Write (bw);
319      }
320      ot.MethodTableSize = (int) bw.BaseStream.Position - ot.MethodTableOffset;
321
322      //
323      // Write source table.
324      //
325      ot.SourceTableOffset = (int) bw.BaseStream.Position;
326      for (int i = 0; i < sources.Count; i++) {
327        SourceFileEntry source = (SourceFileEntry) sources [i];
328        source.Write (bw);
329      }
330      ot.SourceTableSize = (int) bw.BaseStream.Position - ot.SourceTableOffset;
331
332      //
333      // Write compilation unit table.
334      //
335      ot.CompileUnitTableOffset = (int) bw.BaseStream.Position;
336      for (int i = 0; i < comp_units.Count; i++) {
337        CompileUnitEntry unit = (CompileUnitEntry) comp_units [i];
338        unit.Write (bw);
339      }
340      ot.CompileUnitTableSize = (int) bw.BaseStream.Position - ot.CompileUnitTableOffset;
341
342      //
343      // Write anonymous scope table.
344      //
345      ot.AnonymousScopeCount = anonymous_scopes != null ? anonymous_scopes.Count : 0;
346      ot.AnonymousScopeTableOffset = (int) bw.BaseStream.Position;
347      if (anonymous_scopes != null) {
348        foreach (AnonymousScopeEntry scope in anonymous_scopes.Values)
349          scope.Write (bw);
350      }
351      ot.AnonymousScopeTableSize = (int) bw.BaseStream.Position - ot.AnonymousScopeTableOffset;
352
353      //
354      // Fixup offset table.
355      //
356      ot.TypeCount = last_type_index;
357      ot.MethodCount = methods.Count;
358      ot.SourceCount = sources.Count;
359      ot.CompileUnitCount = comp_units.Count;
360
361      //
362      // Write offset table.
363      //
364      ot.TotalFileSize = (int) bw.BaseStream.Position;
365      bw.Seek ((int) offset_table_offset, SeekOrigin.Begin);
366      ot.Write (bw, MajorVersion, MinorVersion);
367      bw.Seek (0, SeekOrigin.End);
368
369#if false
370      Console.WriteLine ("TOTAL: {0} line numbes, {1} bytes, extended {2} bytes, " +
371             "{3} methods.", NumLineNumbers, LineNumberSize,
372             ExtendedLineNumberSize, methods.Count);
373#endif
374    }
375
376    public void CreateSymbolFile (Guid guid, FileStream fs)
377    {
378      if (reader != null)
379        throw new InvalidOperationException ();
380
381      Write (new MyBinaryWriter (fs), guid);
382    }
383
384    MyBinaryReader reader;
385    Dictionary<int, SourceFileEntry> source_file_hash;
386    Dictionary<int, CompileUnitEntry> compile_unit_hash;
387
388    List<MethodEntry> method_list;
389    Dictionary<int, MethodEntry> method_token_hash;
390    Dictionary<string, int> source_name_hash;
391
392    Guid guid;
393
394    MonoSymbolFile (string filename)
395    {
396      this.FileName = filename;
397      FileStream stream = new FileStream (filename, FileMode.Open, FileAccess.Read);
398      reader = new MyBinaryReader (stream);
399
400      try {
401        long magic = reader.ReadInt64 ();
402        int major_version = reader.ReadInt32 ();
403        int minor_version = reader.ReadInt32 ();
404
405        if (magic != OffsetTable.Magic)
406          throw new MonoSymbolFileException (
407            "Symbol file `{0}' is not a valid " +
408            "Mono symbol file", filename);
409        if (major_version != OffsetTable.MajorVersion)
410          throw new MonoSymbolFileException (
411            "Symbol file `{0}' has version {1}, " +
412            "but expected {2}", filename, major_version,
413            OffsetTable.MajorVersion);
414        if (minor_version != OffsetTable.MinorVersion)
415          throw new MonoSymbolFileException (
416            "Symbol file `{0}' has version {1}.{2}, " +
417            "but expected {3}.{4}", filename, major_version,
418            minor_version, OffsetTable.MajorVersion,
419            OffsetTable.MinorVersion);
420
421        MajorVersion = major_version;
422        MinorVersion = minor_version;
423        guid = new Guid (reader.ReadBytes (16));
424
425        ot = new OffsetTable (reader, major_version, minor_version);
426      } catch {
427        throw new MonoSymbolFileException (
428          "Cannot read symbol file `{0}'", filename);
429      }
430
431      source_file_hash = new Dictionary<int, SourceFileEntry> ();
432      compile_unit_hash = new Dictionary<int, CompileUnitEntry> ();
433    }
434
435    void CheckGuidMatch (Guid other, string filename, string assembly)
436    {
437      if (other == guid)
438        return;
439
440      throw new MonoSymbolFileException (
441        "Symbol file `{0}' does not match assembly `{1}'",
442        filename, assembly);
443    }
444
445#if CECIL
446    protected MonoSymbolFile (string filename, Mono.Cecil.ModuleDefinition module)
447      : this (filename)
448    {
449      CheckGuidMatch (module.Mvid, filename, module.FullyQualifiedName);
450    }
451
452    public static MonoSymbolFile ReadSymbolFile (Mono.Cecil.ModuleDefinition module)
453    {
454      return ReadSymbolFile (module, module.FullyQualifiedName);
455    }
456
457    public static MonoSymbolFile ReadSymbolFile (Mono.Cecil.ModuleDefinition module, string filename)
458    {
459      string name = filename + ".mdb";
460
461      return new MonoSymbolFile (name, module);
462    }
463#else
464    protected MonoSymbolFile (string filename, Assembly assembly) : this (filename)
465    {
466      // Check that the MDB file matches the assembly, if we have been
467      // passed an assembly.
468      if (assembly == null)
469        return;
470
471      Module[] modules = assembly.GetModules ();
472      Guid assembly_guid = MonoDebuggerSupport.GetGuid (modules [0]);
473
474      CheckGuidMatch (assembly_guid, filename, assembly.Location);
475    }
476
477    public static MonoSymbolFile ReadSymbolFile (Assembly assembly)
478    {
479      string filename = assembly.Location;
480      string name = filename + ".mdb";
481
482      return new MonoSymbolFile (name, assembly);
483    }
484#endif
485
486    public static MonoSymbolFile ReadSymbolFile (string mdbFilename)
487    {
488      return new MonoSymbolFile (mdbFilename, null);
489    }
490
491    public int CompileUnitCount {
492      get { return ot.CompileUnitCount; }
493    }
494
495    public int SourceCount {
496      get { return ot.SourceCount; }
497    }
498
499    public int MethodCount {
500      get { return ot.MethodCount; }
501    }
502
503    public int TypeCount {
504      get { return ot.TypeCount; }
505    }
506
507    public int AnonymousScopeCount {
508      get { return ot.AnonymousScopeCount; }
509    }
510
511    public int NamespaceCount {
512      get { return last_namespace_index; }
513    }
514
515    public Guid Guid {
516      get { return guid; }
517    }
518
519    public OffsetTable OffsetTable {
520      get { return ot; }
521    }
522
523    internal int LineNumberCount = 0;
524    internal int LocalCount = 0;
525    internal int StringSize = 0;
526
527    internal int LineNumberSize = 0;
528    internal int ExtendedLineNumberSize = 0;
529
530    public SourceFileEntry GetSourceFile (int index)
531    {
532      if ((index < 1) || (index > ot.SourceCount))
533        throw new ArgumentException ();
534      if (reader == null)
535        throw new InvalidOperationException ();
536
537      lock (this) {
538        SourceFileEntry source;
539        if (source_file_hash.TryGetValue (index, out source))
540          return source;
541
542        long old_pos = reader.BaseStream.Position;
543
544        reader.BaseStream.Position = ot.SourceTableOffset +
545          SourceFileEntry.Size * (index - 1);
546        source = new SourceFileEntry (this, reader);
547        source_file_hash.Add (index, source);
548
549        reader.BaseStream.Position = old_pos;
550        return source;
551      }
552    }
553
554    public SourceFileEntry[] Sources {
555      get {
556        if (reader == null)
557          throw new InvalidOperationException ();
558
559        SourceFileEntry[] retval = new SourceFileEntry [SourceCount];
560        for (int i = 0; i < SourceCount; i++)
561          retval [i] = GetSourceFile (i + 1);
562        return retval;
563      }
564    }
565
566    public CompileUnitEntry GetCompileUnit (int index)
567    {
568      if ((index < 1) || (index > ot.CompileUnitCount))
569        throw new ArgumentException ();
570      if (reader == null)
571        throw new InvalidOperationException ();
572
573      lock (this) {
574        CompileUnitEntry unit;
575        if (compile_unit_hash.TryGetValue (index, out unit))
576          return unit;
577
578        long old_pos = reader.BaseStream.Position;
579
580        reader.BaseStream.Position = ot.CompileUnitTableOffset +
581          CompileUnitEntry.Size * (index - 1);
582        unit = new CompileUnitEntry (this, reader);
583        compile_unit_hash.Add (index, unit);
584
585        reader.BaseStream.Position = old_pos;
586        return unit;
587      }
588    }
589
590    public CompileUnitEntry[] CompileUnits {
591      get {
592        if (reader == null)
593          throw new InvalidOperationException ();
594
595        CompileUnitEntry[] retval = new CompileUnitEntry [CompileUnitCount];
596        for (int i = 0; i < CompileUnitCount; i++)
597          retval [i] = GetCompileUnit (i + 1);
598        return retval;
599      }
600    }
601
602    void read_methods ()
603    {
604      lock (this) {
605        if (method_token_hash != null)
606          return;
607
608        method_token_hash = new Dictionary<int, MethodEntry> ();
609        method_list = new List<MethodEntry> ();
610
611        long old_pos = reader.BaseStream.Position;
612        reader.BaseStream.Position = ot.MethodTableOffset;
613
614        for (int i = 0; i < MethodCount; i++) {
615          MethodEntry entry = new MethodEntry (this, reader, i + 1);
616          method_token_hash.Add (entry.Token, entry);
617          method_list.Add (entry);
618        }
619
620        reader.BaseStream.Position = old_pos;
621      }
622    }
623
624    public MethodEntry GetMethodByToken (int token)
625    {
626      if (reader == null)
627        throw new InvalidOperationException ();
628
629      lock (this) {
630        read_methods ();
631        MethodEntry me;
632        method_token_hash.TryGetValue (token, out me);
633        return me;
634      }
635    }
636
637    public MethodEntry GetMethod (int index)
638    {
639      if ((index < 1) || (index > ot.MethodCount))
640        throw new ArgumentException ();
641      if (reader == null)
642        throw new InvalidOperationException ();
643
644      lock (this) {
645        read_methods ();
646        return (MethodEntry) method_list [index - 1];
647      }
648    }
649
650    public MethodEntry[] Methods {
651      get {
652        if (reader == null)
653          throw new InvalidOperationException ();
654
655        lock (this) {
656          read_methods ();
657          MethodEntry[] retval = new MethodEntry [MethodCount];
658          method_list.CopyTo (retval, 0);
659          return retval;
660        }
661      }
662    }
663
664    public int FindSource (string file_name)
665    {
666      if (reader == null)
667        throw new InvalidOperationException ();
668
669      lock (this) {
670        if (source_name_hash == null) {
671          source_name_hash = new Dictionary<string, int> ();
672
673          for (int i = 0; i < ot.SourceCount; i++) {
674            SourceFileEntry source = GetSourceFile (i + 1);
675            source_name_hash.Add (source.FileName, i);
676          }
677        }
678
679        int value;
680        if (!source_name_hash.TryGetValue (file_name, out value))
681          return -1;
682        return value;
683      }
684    }
685
686    public AnonymousScopeEntry GetAnonymousScope (int id)
687    {
688      if (reader == null)
689        throw new InvalidOperationException ();
690
691      AnonymousScopeEntry scope;
692      lock (this) {
693        if (anonymous_scopes != null) {
694          anonymous_scopes.TryGetValue (id, out scope);
695          return scope;
696        }
697
698        anonymous_scopes = new Dictionary<int, AnonymousScopeEntry> ();
699        reader.BaseStream.Position = ot.AnonymousScopeTableOffset;
700        for (int i = 0; i < ot.AnonymousScopeCount; i++) {
701          scope = new AnonymousScopeEntry (reader);
702          anonymous_scopes.Add (scope.ID, scope);
703        }
704
705        return anonymous_scopes [id];
706      }
707    }
708
709    internal MyBinaryReader BinaryReader {
710      get {
711        if (reader == null)
712          throw new InvalidOperationException ();
713
714        return reader;
715      }
716    }
717
718    public void Dispose ()
719    {
720      Dispose (true);
721    }
722
723    protected virtual void Dispose (bool disposing)
724    {
725      if (disposing) {
726        if (reader != null) {
727          reader.Close ();
728          reader = null;
729        }
730      }
731    }
732  }
733}
Note: See TracBrowser for help on using the repository browser.