2 // System.Diagnostics.SymbolStore/MonoSymbolFile.cs
5 // Martin Baulig (martin@gnome.org)
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.Reflection.Emit;
34 using System.Collections;
38 namespace Mono.CSharp.Debugger
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 public class MonoDebuggerSupport
196 static GetTypeFunc get_type;
197 static GetMethodTokenFunc get_method_token;
198 static GetMethodFunc get_method;
199 static GetLocalTypeFromSignatureFunc local_type_from_sig;
201 delegate Type GetTypeFunc (Assembly assembly, int token);
202 delegate int GetMethodTokenFunc (Assembly assembly, MethodBase method);
203 delegate MethodBase GetMethodFunc (Assembly assembly, int token);
204 delegate Type GetLocalTypeFromSignatureFunc (Assembly assembly, byte[] sig);
206 static Delegate create_delegate (Type delegate_type, string name)
208 Type type = typeof (Assembly);
210 MethodInfo mi = type.GetMethod (name, BindingFlags.Static |
211 BindingFlags.NonPublic);
213 throw new Exception ("Can't find " + name);
215 return Delegate.CreateDelegate (delegate_type, mi);
218 static MonoDebuggerSupport ()
220 get_type = (GetTypeFunc) create_delegate (
221 typeof (GetTypeFunc), "MonoDebugger_GetType");
223 get_method_token = (GetMethodTokenFunc) create_delegate (
224 typeof (GetMethodTokenFunc), "MonoDebugger_GetMethodToken");
226 get_method = (GetMethodFunc) create_delegate (
227 typeof (GetMethodFunc), "MonoDebugger_GetMethod");
229 local_type_from_sig = (GetLocalTypeFromSignatureFunc) create_delegate (
230 typeof (GetLocalTypeFromSignatureFunc),
231 "MonoDebugger_GetLocalTypeFromSignature");
234 public static Type GetType (Assembly assembly, int token)
236 return get_type (assembly, token);
239 public static int GetMethodToken (MethodBase method)
241 return get_method_token (method.ReflectedType.Assembly, method);
244 public static MethodBase GetMethod (Assembly assembly, int token)
246 return get_method (assembly, token);
249 public static Type GetLocalTypeFromSignature (Assembly assembly, byte[] sig)
251 return local_type_from_sig (assembly, sig);
255 public class MonoSymbolFile : IDisposable
257 ArrayList methods = new ArrayList ();
258 ArrayList sources = new ArrayList ();
259 Hashtable method_source_hash = new Hashtable ();
260 Hashtable type_hash = new Hashtable ();
264 int last_method_index;
265 int last_source_index;
266 int last_namespace_index;
268 public MonoSymbolFile ()
271 internal int AddSource (SourceFileEntry source)
273 sources.Add (source);
274 return ++last_source_index;
277 internal int DefineType (Type type)
279 if (type_hash.Contains (type))
280 return (int) type_hash [type];
282 int index = ++last_type_index;
283 type_hash.Add (type, index);
287 internal void AddMethod (MethodEntry entry)
292 internal int GetNextTypeIndex ()
294 return ++last_type_index;
297 internal int GetNextMethodIndex ()
299 return ++last_method_index;
302 internal int GetNextNamespaceIndex ()
304 return ++last_namespace_index;
307 byte [] stringBuffer;
308 int maxCharsPerRound;
309 static Encoding enc = Encoding.UTF8;
311 internal void WriteString (BinaryWriter bw, string s)
313 int len = enc.GetByteCount (s);
317 if (stringBuffer == null) {
318 stringBuffer = new byte [512];
319 maxCharsPerRound = 512 / enc.GetMaxByteCount (1);
323 int chrem = s.Length;
325 int cch = (chrem > maxCharsPerRound) ? maxCharsPerRound : chrem;
326 int blen = enc.GetBytes (s, chpos, cch, stringBuffer, 0);
327 bw.Write (stringBuffer, 0, blen);
334 internal string ReadString (int offset)
336 int old_pos = (int) reader.BaseStream.Position;
337 reader.BaseStream.Position = offset;
339 string text = ReadString ();
341 reader.BaseStream.Position = old_pos;
345 internal string ReadString ()
347 int length = reader.ReadInt32 ();
348 byte[] data = reader.ReadBytes (length);
349 return Encoding.UTF8.GetString (data);
352 void Write (BinaryWriter bw)
354 // Magic number and file version.
355 bw.Write (OffsetTable.Magic);
356 bw.Write (OffsetTable.Version);
359 // Offsets of file sections; we must write this after we're done
360 // writing the whole file, so we just reserve the space for it here.
362 long offset_table_offset = bw.BaseStream.Position;
366 // Write data sections.
368 ot.DataSectionOffset = (int) bw.BaseStream.Position;
369 foreach (SourceFileEntry source in sources)
370 source.WriteData (bw);
371 ot.DataSectionSize = (int) bw.BaseStream.Position - ot.DataSectionOffset;
374 // Write method table.
376 ot.MethodTableOffset = (int) bw.BaseStream.Position;
377 for (int i = 0; i < methods.Count; i++) {
378 MethodEntry entry = (MethodEntry) methods [i];
379 entry.WriteIndex (bw);
381 ot.MethodTableSize = (int) bw.BaseStream.Position - ot.MethodTableOffset;
384 // Write source table.
386 ot.SourceTableOffset = (int) bw.BaseStream.Position;
387 for (int i = 0; i < sources.Count; i++) {
388 SourceFileEntry source = (SourceFileEntry) sources [i];
391 ot.SourceTableSize = (int) bw.BaseStream.Position - ot.SourceTableOffset;
394 // Fixup offset table.
396 ot.TypeCount = last_type_index;
397 ot.MethodCount = methods.Count;
398 ot.SourceCount = sources.Count;
401 // Write offset table.
403 ot.TotalFileSize = (int) bw.BaseStream.Position;
404 bw.Seek ((int) offset_table_offset, SeekOrigin.Begin);
406 bw.Seek (0, SeekOrigin.End);
409 public byte[] CreateSymbolFile ()
412 throw new InvalidOperationException ();
414 using (MyMemoryStream stream = new MyMemoryStream ()) {
415 Write (new BinaryWriter (stream));
416 return stream.GetContents ();
422 Hashtable method_hash;
423 Hashtable source_file_hash;
425 Hashtable method_token_hash;
426 Hashtable source_name_hash;
428 protected MonoSymbolFile (Assembly assembly, Stream stream)
430 this.assembly = assembly;
432 reader = new BinaryReader (stream);
435 long magic = reader.ReadInt64 ();
436 long version = reader.ReadInt32 ();
437 if ((magic != OffsetTable.Magic) || (version != OffsetTable.Version))
438 throw new MonoSymbolFileException ();
439 ot = new OffsetTable (reader);
441 throw new MonoSymbolFileException ();
444 method_hash = new Hashtable ();
445 source_file_hash = new Hashtable ();
448 public static MonoSymbolFile ReadSymbolFile (Assembly assembly)
450 Stream stream = assembly.GetManifestResourceStream ("MonoSymbolFile");
454 return new MonoSymbolFile (assembly, stream);
457 public Assembly Assembly {
458 get { return assembly; }
461 public int SourceCount {
462 get { return ot.SourceCount; }
465 public int MethodCount {
466 get { return ot.MethodCount; }
469 public int TypeCount {
470 get { return ot.TypeCount; }
473 public int NamespaceCount {
474 get { return last_namespace_index; }
477 internal int LineNumberCount = 0;
478 internal int LocalCount = 0;
479 internal int StringSize = 0;
481 public SourceFileEntry GetSourceFile (int index)
483 if ((index < 1) || (index > ot.SourceCount))
484 throw new ArgumentException ();
486 throw new InvalidOperationException ();
488 SourceFileEntry source = (SourceFileEntry) source_file_hash [index];
492 reader.BaseStream.Position = ot.SourceTableOffset +
493 SourceFileEntry.Size * (index - 1);
494 source = new SourceFileEntry (this, reader);
495 source_file_hash.Add (index, source);
499 public SourceFileEntry[] Sources {
502 throw new InvalidOperationException ();
504 SourceFileEntry[] retval = new SourceFileEntry [SourceCount];
505 for (int i = 0; i < SourceCount; i++)
506 retval [i] = GetSourceFile (i + 1);
511 public MethodIndexEntry GetMethodIndexEntry (int index)
513 int old_pos = (int) reader.BaseStream.Position;
514 reader.BaseStream.Position = ot.MethodTableOffset +
515 MethodIndexEntry.Size * (index - 1);
516 MethodIndexEntry ie = new MethodIndexEntry (reader);
517 reader.BaseStream.Position = old_pos;
521 public MethodEntry GetMethodByToken (int token)
524 throw new InvalidOperationException ();
526 if (method_token_hash == null) {
527 method_token_hash = new Hashtable ();
529 for (int i = 0; i < MethodCount; i++) {
530 MethodIndexEntry ie = GetMethodIndexEntry (i + 1);
532 method_token_hash.Add (ie.Token, i + 1);
536 object value = method_token_hash [token];
540 return GetMethod ((int) value);
543 public MethodEntry GetMethod (MethodBase method)
546 throw new InvalidOperationException ();
547 int token = MonoDebuggerSupport.GetMethodToken (method);
548 return GetMethodByToken (token);
551 public MethodEntry GetMethod (int index)
553 if ((index < 1) || (index > ot.MethodCount))
554 throw new ArgumentException ();
556 throw new InvalidOperationException ();
558 MethodEntry entry = (MethodEntry) method_hash [index];
562 MethodIndexEntry ie = GetMethodIndexEntry (index);
563 reader.BaseStream.Position = ie.FileOffset;
565 entry = new MethodEntry (this, reader, index);
566 method_hash.Add (index, entry);
570 public MethodEntry[] Methods {
573 throw new InvalidOperationException ();
575 MethodEntry[] retval = new MethodEntry [MethodCount];
576 for (int i = 0; i < MethodCount; i++)
577 retval [i] = GetMethod (i + 1);
582 public MethodSourceEntry GetMethodSource (int index)
584 if ((index < 1) || (index > ot.MethodCount))
585 throw new ArgumentException ();
587 throw new InvalidOperationException ();
589 object entry = method_source_hash [index];
591 return (MethodSourceEntry) entry;
593 MethodEntry method = GetMethod (index);
594 foreach (MethodSourceEntry source in method.SourceFile.Methods) {
595 if (source.Index == index) {
596 method_source_hash.Add (index, source);
601 throw new MonoSymbolFileException ("Internal error.");
604 public int FindSource (string file_name)
607 throw new InvalidOperationException ();
609 if (source_name_hash == null) {
610 source_name_hash = new Hashtable ();
612 for (int i = 0; i < ot.SourceCount; i++) {
613 SourceFileEntry source = GetSourceFile (i + 1);
615 source_name_hash.Add (source.FileName, i);
619 object value = source_name_hash [file_name];
625 internal BinaryReader BinaryReader {
628 throw new InvalidOperationException ();
634 void IDisposable.Dispose ()
639 protected virtual void Dispose (bool disposing)
642 if (reader != null) {