2 // Mono.CSharp.Debugger/MonoSymbolFile.cs
5 // Martin Baulig (martin@ximian.com)
7 // (C) 2003 Ximian, Inc. http://www.ximian.com
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:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
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.
32 using System.Reflection;
33 using SRE = System.Reflection.Emit;
34 using System.Collections;
36 using System.Threading;
39 namespace Mono.CompilerServices.SymbolWriter
41 public class MonoSymbolFileException : Exception
43 public MonoSymbolFileException ()
47 public MonoSymbolFileException (string message, params object[] args)
48 : base (String.Format (message, args))
52 internal class MyBinaryWriter : BinaryWriter
54 public MyBinaryWriter (Stream stream)
58 public void WriteLeb128 (int value)
60 base.Write7BitEncodedInt (value);
64 internal class MyBinaryReader : BinaryReader
66 public MyBinaryReader (Stream stream)
70 public int ReadLeb128 ()
72 return base.Read7BitEncodedInt ();
76 internal class MonoDebuggerSupport
78 static GetMethodTokenFunc get_method_token;
79 static GetGuidFunc get_guid;
80 static GetLocalIndexFunc get_local_index;
82 delegate int GetMethodTokenFunc (MethodBase method);
83 delegate Guid GetGuidFunc (Module module);
84 delegate int GetLocalIndexFunc (SRE.LocalBuilder local);
86 static Delegate create_delegate (Type type, Type delegate_type, string name)
88 MethodInfo mi = type.GetMethod (name, BindingFlags.Static |
89 BindingFlags.NonPublic);
91 throw new Exception ("Can't find " + name);
93 return Delegate.CreateDelegate (delegate_type, mi);
96 static MonoDebuggerSupport ()
98 get_method_token = (GetMethodTokenFunc) create_delegate (
99 typeof (Assembly), typeof (GetMethodTokenFunc),
100 "MonoDebugger_GetMethodToken");
102 get_guid = (GetGuidFunc) create_delegate (
103 typeof (Module), typeof (GetGuidFunc), "Mono_GetGuid");
105 get_local_index = (GetLocalIndexFunc) create_delegate (
106 typeof (SRE.LocalBuilder), typeof (GetLocalIndexFunc),
107 "Mono_GetLocalIndex");
110 public static int GetMethodToken (MethodBase method)
112 return get_method_token (method);
115 public static Guid GetGuid (Module module)
117 return get_guid (module);
120 public static int GetLocalIndex (SRE.LocalBuilder local)
122 return get_local_index (local);
126 public class MonoSymbolFile : IDisposable
128 ArrayList methods = new ArrayList ();
129 ArrayList sources = new ArrayList ();
130 Hashtable method_source_hash = new Hashtable ();
131 Hashtable type_hash = new Hashtable ();
135 int last_method_index;
136 int last_source_index;
137 int last_namespace_index;
139 public int NumLineNumbers;
141 public MonoSymbolFile ()
144 internal int AddSource (SourceFileEntry source)
146 sources.Add (source);
147 return ++last_source_index;
150 internal int DefineType (Type type)
152 if (type_hash.Contains (type))
153 return (int) type_hash [type];
155 int index = ++last_type_index;
156 type_hash.Add (type, index);
160 internal void AddMethod (MethodEntry entry)
165 internal int GetNextTypeIndex ()
167 return ++last_type_index;
170 internal int GetNextMethodIndex ()
172 return ++last_method_index;
175 internal int GetNextNamespaceIndex ()
177 return ++last_namespace_index;
180 internal string ReadString (int offset)
182 int old_pos = (int) reader.BaseStream.Position;
183 reader.BaseStream.Position = offset;
185 string text = reader.ReadString ();
187 reader.BaseStream.Position = old_pos;
191 void Write (MyBinaryWriter bw, Guid guid)
193 // Magic number and file version.
194 bw.Write (OffsetTable.Magic);
195 bw.Write (OffsetTable.Version);
197 bw.Write (guid.ToByteArray ());
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.
203 long offset_table_offset = bw.BaseStream.Position;
207 // Sort the methods according to their tokens and update their index.
210 for (int i = 0; i < methods.Count; i++)
211 ((MethodEntry) methods [i]).Index = i + 1;
214 // Write data sections.
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;
222 // Write the method index table.
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);
229 ot.MethodTableSize = (int) bw.BaseStream.Position - ot.MethodTableOffset;
232 // Write source table.
234 ot.SourceTableOffset = (int) bw.BaseStream.Position;
235 for (int i = 0; i < sources.Count; i++) {
236 SourceFileEntry source = (SourceFileEntry) sources [i];
239 ot.SourceTableSize = (int) bw.BaseStream.Position - ot.SourceTableOffset;
242 // Fixup offset table.
244 ot.TypeCount = last_type_index;
245 ot.MethodCount = methods.Count;
246 ot.SourceCount = sources.Count;
249 // Write offset table.
251 ot.TotalFileSize = (int) bw.BaseStream.Position;
252 bw.Seek ((int) offset_table_offset, SeekOrigin.Begin);
254 bw.Seek (0, SeekOrigin.End);
257 public void CreateSymbolFile (Guid guid, FileStream fs)
260 throw new InvalidOperationException ();
262 Write (new MyBinaryWriter (fs), guid);
266 MyBinaryReader reader;
267 Hashtable method_hash;
268 Hashtable source_file_hash;
270 Hashtable method_token_hash;
271 Hashtable source_name_hash;
273 protected MonoSymbolFile (string filename, Assembly assembly)
275 this.assembly = assembly;
277 FileStream stream = new FileStream (filename, FileMode.Open, FileAccess.Read);
278 reader = new MyBinaryReader (stream);
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);
295 guid = new Guid (reader.ReadBytes (16));
297 ot = new OffsetTable (reader);
299 throw new MonoSymbolFileException (
300 "Cannot read symbol file `{0}'", filename);
303 Module[] modules = assembly.GetModules ();
304 Guid assembly_guid = MonoDebuggerSupport.GetGuid (modules [0]);
306 if (guid != assembly_guid)
307 throw new MonoSymbolFileException (
308 "Symbol file `{0}' does not match assembly `{1}'",
309 filename, assembly.Location);
311 method_hash = new Hashtable ();
312 source_file_hash = new Hashtable ();
315 public static MonoSymbolFile ReadSymbolFile (Assembly assembly)
317 string filename = assembly.Location;
318 string name = filename + ".mdb";
320 return new MonoSymbolFile (name, assembly);
323 public Assembly Assembly {
324 get { return assembly; }
327 public int SourceCount {
328 get { return ot.SourceCount; }
331 public int MethodCount {
332 get { return ot.MethodCount; }
335 public int TypeCount {
336 get { return ot.TypeCount; }
339 public int NamespaceCount {
340 get { return last_namespace_index; }
343 internal int LineNumberCount = 0;
344 internal int LocalCount = 0;
345 internal int StringSize = 0;
347 public SourceFileEntry GetSourceFile (int index)
349 if ((index < 1) || (index > ot.SourceCount))
350 throw new ArgumentException ();
352 throw new InvalidOperationException ();
354 SourceFileEntry source = (SourceFileEntry) source_file_hash [index];
358 reader.BaseStream.Position = ot.SourceTableOffset +
359 SourceFileEntry.Size * (index - 1);
360 source = new SourceFileEntry (this, reader);
361 source_file_hash.Add (index, source);
365 public SourceFileEntry[] Sources {
368 throw new InvalidOperationException ();
370 SourceFileEntry[] retval = new SourceFileEntry [SourceCount];
371 for (int i = 0; i < SourceCount; i++)
372 retval [i] = GetSourceFile (i + 1);
377 public MethodIndexEntry GetMethodIndexEntry (int index)
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;
387 public MethodEntry GetMethodByToken (int token)
390 throw new InvalidOperationException ();
392 if (method_token_hash == null) {
393 method_token_hash = new Hashtable ();
395 for (int i = 0; i < MethodCount; i++) {
396 MethodIndexEntry ie = GetMethodIndexEntry (i + 1);
398 method_token_hash.Add (ie.Token, i + 1);
402 object value = method_token_hash [token];
406 return GetMethod ((int) value);
409 public MethodEntry GetMethod (MethodBase method)
412 throw new InvalidOperationException ();
413 int token = MonoDebuggerSupport.GetMethodToken (method);
414 return GetMethodByToken (token);
417 public MethodEntry GetMethod (int index)
419 if ((index < 1) || (index > ot.MethodCount))
420 throw new ArgumentException ();
422 throw new InvalidOperationException ();
424 MethodEntry entry = (MethodEntry) method_hash [index];
428 MethodIndexEntry ie = GetMethodIndexEntry (index);
429 reader.BaseStream.Position = ie.FileOffset;
431 entry = new MethodEntry (this, reader, index);
432 method_hash.Add (index, entry);
436 public MethodEntry[] Methods {
439 throw new InvalidOperationException ();
441 MethodEntry[] retval = new MethodEntry [MethodCount];
442 for (int i = 0; i < MethodCount; i++)
443 retval [i] = GetMethod (i + 1);
448 public MethodSourceEntry GetMethodSource (int index)
450 if ((index < 1) || (index > ot.MethodCount))
451 throw new ArgumentException ();
453 throw new InvalidOperationException ();
455 object entry = method_source_hash [index];
457 return (MethodSourceEntry) entry;
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);
467 throw new MonoSymbolFileException ("Internal error.");
470 public int FindSource (string file_name)
473 throw new InvalidOperationException ();
475 if (source_name_hash == null) {
476 source_name_hash = new Hashtable ();
478 for (int i = 0; i < ot.SourceCount; i++) {
479 SourceFileEntry source = GetSourceFile (i + 1);
481 source_name_hash.Add (source.FileName, i);
485 object value = source_name_hash [file_name];
491 internal MyBinaryReader BinaryReader {
494 throw new InvalidOperationException ();
500 public void Dispose ()
505 protected virtual void Dispose (bool disposing)
508 if (reader != null) {