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 System.Collections;
35 using System.Threading;
38 namespace Mono.CompilerServices.SymbolWriter
40 public class MonoSymbolFileException : Exception
42 public MonoSymbolFileException ()
46 public MonoSymbolFileException (string message, params object[] args)
47 : base (String.Format (message, args))
51 internal class MyMemoryStream : Stream
57 int chunk_size = 4096;
58 ArrayList chunks = new ArrayList ();
60 private struct Chunk {
61 public readonly int Offset;
62 public readonly int Length;
65 public Chunk (int offset, int length)
69 this.Buffer = new Byte [length];
73 public override long Position {
74 get { return position; }
78 throw new ArgumentOutOfRangeException ();
80 position = (int) value;
84 public override long Length {
85 get { return length; }
88 public override bool CanRead {
92 public override bool CanWrite {
96 public override bool CanSeek {
100 public override void SetLength (long new_length)
102 if (new_length < length)
103 throw new ArgumentException ();
105 while (new_length >= real_length) {
106 Chunk new_chunk = new Chunk (real_length, chunk_size);
107 chunks.Add (new_chunk);
108 real_length += chunk_size;
111 length = (int) new_length;
114 public override void Flush ()
117 public override long Seek (long offset, SeekOrigin origin)
122 case SeekOrigin.Begin:
125 case SeekOrigin.Current:
126 ref_point = position;
132 throw new ArgumentException ("Invalid SeekOrigin");
135 if ((ref_point + offset < 0) || (offset > real_length))
136 throw new ArgumentOutOfRangeException ();
138 position = ref_point + (int) offset;
143 Chunk FindChunk (int offset)
145 return (Chunk) chunks [offset / chunk_size];
148 public override int Read (byte[] buffer, int offset, int count)
150 int old_count = count;
153 Chunk chunk = FindChunk (position);
154 int coffset = position - chunk.Offset;
155 int rest = chunk.Length - coffset;
156 int size = System.Math.Min (count, rest);
158 Array.Copy (chunk.Buffer, coffset, buffer, offset, size);
167 public override void Write (byte[] buffer, int offset, int count)
169 if (position + count > length)
170 SetLength (position + count);
173 Chunk chunk = FindChunk (position);
174 int coffset = position - chunk.Offset;
175 int rest = chunk.Length - coffset;
176 int size = System.Math.Min (count, rest);
178 Array.Copy (buffer, offset, chunk.Buffer, coffset, size);
185 public byte[] GetContents ()
187 byte[] retval = new byte [length];
189 Read (retval, 0, length);
194 internal class MyBinaryWriter : BinaryWriter
196 public MyBinaryWriter (Stream stream)
200 public void WriteLeb128 (int value)
202 base.Write7BitEncodedInt (value);
206 internal class MyBinaryReader : BinaryReader
208 public MyBinaryReader (Stream stream)
212 public int ReadLeb128 ()
214 return base.Read7BitEncodedInt ();
218 public class MonoDebuggerSupport
220 static GetTypeFunc get_type;
221 static GetMethodTokenFunc get_method_token;
222 static GetMethodFunc get_method;
223 static GetLocalTypeFromSignatureFunc local_type_from_sig;
224 static GetGuidFunc get_guid;
225 static CheckRuntimeVersionFunc check_runtime_version;
227 delegate Type GetTypeFunc (Assembly assembly, int token);
228 delegate int GetMethodTokenFunc (Assembly assembly, MethodBase method);
229 delegate MethodBase GetMethodFunc (Assembly assembly, int token);
230 delegate Type GetLocalTypeFromSignatureFunc (Assembly assembly, byte[] sig);
231 delegate Guid GetGuidFunc (Module module);
232 delegate string CheckRuntimeVersionFunc (string filename);
234 static Delegate create_delegate (Type type, Type delegate_type, string name)
236 MethodInfo mi = type.GetMethod (name, BindingFlags.Static |
237 BindingFlags.NonPublic);
239 throw new Exception ("Can't find " + name);
241 return Delegate.CreateDelegate (delegate_type, mi);
244 static MonoDebuggerSupport ()
246 get_type = (GetTypeFunc) create_delegate (
247 typeof (Assembly), typeof (GetTypeFunc),
248 "MonoDebugger_GetType");
250 get_method_token = (GetMethodTokenFunc) create_delegate (
251 typeof (Assembly), typeof (GetMethodTokenFunc),
252 "MonoDebugger_GetMethodToken");
254 get_method = (GetMethodFunc) create_delegate (
255 typeof (Assembly), typeof (GetMethodFunc),
256 "MonoDebugger_GetMethod");
258 local_type_from_sig = (GetLocalTypeFromSignatureFunc) create_delegate (
259 typeof (Assembly), typeof (GetLocalTypeFromSignatureFunc),
260 "MonoDebugger_GetLocalTypeFromSignature");
262 get_guid = (GetGuidFunc) create_delegate (
263 typeof (Module), typeof (GetGuidFunc), "Mono_GetGuid");
265 check_runtime_version = (CheckRuntimeVersionFunc) create_delegate (
266 typeof (Assembly), typeof (CheckRuntimeVersionFunc),
267 "MonoDebugger_CheckRuntimeVersion");
270 public static Type GetType (Assembly assembly, int token)
272 return get_type (assembly, token);
275 public static int GetMethodToken (MethodBase method)
277 return get_method_token (method.ReflectedType.Assembly, method);
280 public static MethodBase GetMethod (Assembly assembly, int token)
282 return get_method (assembly, token);
285 public static Type GetLocalTypeFromSignature (Assembly assembly, byte[] sig)
287 return local_type_from_sig (assembly, sig);
290 public static string CheckRuntimeVersion (string filename)
292 return check_runtime_version (filename);
295 public static Guid GetGuid (Module module)
297 return get_guid (module);
301 public class MonoSymbolFile : IDisposable
303 ArrayList methods = new ArrayList ();
304 ArrayList sources = new ArrayList ();
305 Hashtable method_source_hash = new Hashtable ();
306 Hashtable type_hash = new Hashtable ();
310 int last_method_index;
311 int last_source_index;
312 int last_namespace_index;
314 public int NumLineNumbers;
316 public MonoSymbolFile ()
319 internal int AddSource (SourceFileEntry source)
321 sources.Add (source);
322 return ++last_source_index;
325 internal int DefineType (Type type)
327 if (type_hash.Contains (type))
328 return (int) type_hash [type];
330 int index = ++last_type_index;
331 type_hash.Add (type, index);
335 internal void AddMethod (MethodEntry entry)
340 internal int GetNextTypeIndex ()
342 return ++last_type_index;
345 internal int GetNextMethodIndex ()
347 return ++last_method_index;
350 internal int GetNextNamespaceIndex ()
352 return ++last_namespace_index;
355 byte [] stringBuffer;
356 int maxCharsPerRound;
357 static Encoding enc = Encoding.UTF8;
359 internal string ReadString (int offset)
361 int old_pos = (int) reader.BaseStream.Position;
362 reader.BaseStream.Position = offset;
364 string text = reader.ReadString ();
366 reader.BaseStream.Position = old_pos;
370 void Write (MyBinaryWriter bw, Guid guid)
372 // Magic number and file version.
373 bw.Write (OffsetTable.Magic);
374 bw.Write (OffsetTable.Version);
376 bw.Write (guid.ToByteArray ());
379 // Offsets of file sections; we must write this after we're done
380 // writing the whole file, so we just reserve the space for it here.
382 long offset_table_offset = bw.BaseStream.Position;
386 // Sort the methods according to their tokens and update their index.
389 for (int i = 0; i < methods.Count; i++)
390 ((MethodEntry) methods [i]).Index = i + 1;
393 // Write data sections.
395 ot.DataSectionOffset = (int) bw.BaseStream.Position;
396 foreach (SourceFileEntry source in sources)
397 source.WriteData (bw);
398 ot.DataSectionSize = (int) bw.BaseStream.Position - ot.DataSectionOffset;
401 // Write the method index table.
403 ot.MethodTableOffset = (int) bw.BaseStream.Position;
404 for (int i = 0; i < methods.Count; i++) {
405 MethodEntry entry = (MethodEntry) methods [i];
406 entry.WriteIndex (bw);
408 ot.MethodTableSize = (int) bw.BaseStream.Position - ot.MethodTableOffset;
411 // Write source table.
413 ot.SourceTableOffset = (int) bw.BaseStream.Position;
414 for (int i = 0; i < sources.Count; i++) {
415 SourceFileEntry source = (SourceFileEntry) sources [i];
418 ot.SourceTableSize = (int) bw.BaseStream.Position - ot.SourceTableOffset;
421 // Fixup offset table.
423 ot.TypeCount = last_type_index;
424 ot.MethodCount = methods.Count;
425 ot.SourceCount = sources.Count;
428 // Write offset table.
430 ot.TotalFileSize = (int) bw.BaseStream.Position;
431 bw.Seek ((int) offset_table_offset, SeekOrigin.Begin);
433 bw.Seek (0, SeekOrigin.End);
436 public byte[] CreateSymbolFile (Guid guid)
439 throw new InvalidOperationException ();
441 using (MyMemoryStream stream = new MyMemoryStream ()) {
442 Write (new MyBinaryWriter (stream), guid);
443 return stream.GetContents ();
448 MyBinaryReader reader;
449 Hashtable method_hash;
450 Hashtable source_file_hash;
452 Hashtable method_token_hash;
453 Hashtable source_name_hash;
455 protected MonoSymbolFile (string filename, Assembly assembly)
457 this.assembly = assembly;
459 FileStream stream = new FileStream (filename, FileMode.Open, FileAccess.Read);
460 reader = new MyBinaryReader (stream);
465 long magic = reader.ReadInt64 ();
466 long version = reader.ReadInt32 ();
467 if (magic != OffsetTable.Magic)
468 throw new MonoSymbolFileException (
469 "Symbol file `{0}' is not a valid " +
470 "Mono symbol file", filename);
471 if (version != OffsetTable.Version)
472 throw new MonoSymbolFileException (
473 "Symbol file `{0}' has version {1}, " +
474 "but expected {2}", filename, version,
475 OffsetTable.Version);
477 guid = new Guid (reader.ReadBytes (16));
479 ot = new OffsetTable (reader);
481 throw new MonoSymbolFileException (
482 "Cannot read symbol file `{0}'", filename);
485 Module[] modules = assembly.GetModules ();
486 Guid assembly_guid = MonoDebuggerSupport.GetGuid (modules [0]);
488 if (guid != assembly_guid)
489 throw new MonoSymbolFileException (
490 "Symbol file `{0}' does not match assembly `{1}'",
491 filename, assembly.Location);
493 method_hash = new Hashtable ();
494 source_file_hash = new Hashtable ();
497 public static MonoSymbolFile ReadSymbolFile (Assembly assembly)
499 string filename = assembly.Location;
500 string name = filename + ".mdb";
502 return new MonoSymbolFile (name, assembly);
505 public Assembly Assembly {
506 get { return assembly; }
509 public int SourceCount {
510 get { return ot.SourceCount; }
513 public int MethodCount {
514 get { return ot.MethodCount; }
517 public int TypeCount {
518 get { return ot.TypeCount; }
521 public int NamespaceCount {
522 get { return last_namespace_index; }
525 internal int LineNumberCount = 0;
526 internal int LocalCount = 0;
527 internal int StringSize = 0;
529 public SourceFileEntry GetSourceFile (int index)
531 if ((index < 1) || (index > ot.SourceCount))
532 throw new ArgumentException ();
534 throw new InvalidOperationException ();
536 SourceFileEntry source = (SourceFileEntry) source_file_hash [index];
540 reader.BaseStream.Position = ot.SourceTableOffset +
541 SourceFileEntry.Size * (index - 1);
542 source = new SourceFileEntry (this, reader);
543 source_file_hash.Add (index, source);
547 public SourceFileEntry[] Sources {
550 throw new InvalidOperationException ();
552 SourceFileEntry[] retval = new SourceFileEntry [SourceCount];
553 for (int i = 0; i < SourceCount; i++)
554 retval [i] = GetSourceFile (i + 1);
559 public MethodIndexEntry GetMethodIndexEntry (int index)
561 int old_pos = (int) reader.BaseStream.Position;
562 reader.BaseStream.Position = ot.MethodTableOffset +
563 MethodIndexEntry.Size * (index - 1);
564 MethodIndexEntry ie = new MethodIndexEntry (reader);
565 reader.BaseStream.Position = old_pos;
569 public MethodEntry GetMethodByToken (int token)
572 throw new InvalidOperationException ();
574 if (method_token_hash == null) {
575 method_token_hash = new Hashtable ();
577 for (int i = 0; i < MethodCount; i++) {
578 MethodIndexEntry ie = GetMethodIndexEntry (i + 1);
580 method_token_hash.Add (ie.Token, i + 1);
584 object value = method_token_hash [token];
588 return GetMethod ((int) value);
591 public MethodEntry GetMethod (MethodBase method)
594 throw new InvalidOperationException ();
595 int token = MonoDebuggerSupport.GetMethodToken (method);
596 return GetMethodByToken (token);
599 public MethodEntry GetMethod (int index)
601 if ((index < 1) || (index > ot.MethodCount))
602 throw new ArgumentException ();
604 throw new InvalidOperationException ();
606 MethodEntry entry = (MethodEntry) method_hash [index];
610 MethodIndexEntry ie = GetMethodIndexEntry (index);
611 reader.BaseStream.Position = ie.FileOffset;
613 entry = new MethodEntry (this, reader, index);
614 method_hash.Add (index, entry);
618 public MethodEntry[] Methods {
621 throw new InvalidOperationException ();
623 MethodEntry[] retval = new MethodEntry [MethodCount];
624 for (int i = 0; i < MethodCount; i++)
625 retval [i] = GetMethod (i + 1);
630 public MethodSourceEntry GetMethodSource (int index)
632 if ((index < 1) || (index > ot.MethodCount))
633 throw new ArgumentException ();
635 throw new InvalidOperationException ();
637 object entry = method_source_hash [index];
639 return (MethodSourceEntry) entry;
641 MethodEntry method = GetMethod (index);
642 foreach (MethodSourceEntry source in method.SourceFile.Methods) {
643 if (source.Index == index) {
644 method_source_hash.Add (index, source);
649 throw new MonoSymbolFileException ("Internal error.");
652 public int FindSource (string file_name)
655 throw new InvalidOperationException ();
657 if (source_name_hash == null) {
658 source_name_hash = new Hashtable ();
660 for (int i = 0; i < ot.SourceCount; i++) {
661 SourceFileEntry source = GetSourceFile (i + 1);
663 source_name_hash.Add (source.FileName, i);
667 object value = source_name_hash [file_name];
673 internal MyBinaryReader BinaryReader {
676 throw new InvalidOperationException ();
682 void IDisposable.Dispose ()
687 protected virtual void Dispose (bool disposing)
690 if (reader != null) {