2 // System.Diagnostics.SymbolStore/MonoSymbolFile.cs
5 // Martin Baulig (martin@gnome.org)
7 // (C) 2003 Ximian, Inc. http://www.ximian.com
11 using System.Reflection;
12 using System.Reflection.Emit;
13 using System.Collections;
17 namespace Mono.CSharp.Debugger
19 public class MonoSymbolFileException : Exception
21 public MonoSymbolFileException ()
25 public MonoSymbolFileException (string message, params object[] args)
26 : base (String.Format (message, args))
30 internal class MyMemoryStream : Stream
36 int chunk_size = 4096;
37 ArrayList chunks = new ArrayList ();
39 private struct Chunk {
40 public readonly int Offset;
41 public readonly int Length;
44 public Chunk (int offset, int length)
48 this.Buffer = new Byte [length];
52 public override long Position {
53 get { return position; }
57 throw new ArgumentOutOfRangeException ();
59 position = (int) value;
63 public override long Length {
64 get { return length; }
67 public override bool CanRead {
71 public override bool CanWrite {
75 public override bool CanSeek {
79 public override void SetLength (long new_length)
81 if (new_length < length)
82 throw new ArgumentException ();
84 while (new_length >= real_length) {
85 Chunk new_chunk = new Chunk (real_length, chunk_size);
86 chunks.Add (new_chunk);
87 real_length += chunk_size;
90 length = (int) new_length;
93 public override void Flush ()
96 public override long Seek (long offset, SeekOrigin origin)
101 case SeekOrigin.Begin:
104 case SeekOrigin.Current:
105 ref_point = position;
111 throw new ArgumentException ("Invalid SeekOrigin");
114 if ((ref_point + offset < 0) || (offset > real_length))
115 throw new ArgumentOutOfRangeException ();
117 position = ref_point + (int) offset;
122 Chunk FindChunk (int offset)
124 return (Chunk) chunks [offset / chunk_size];
127 public override int Read (byte[] buffer, int offset, int count)
129 int old_count = count;
132 Chunk chunk = FindChunk (position);
133 int coffset = position - chunk.Offset;
134 int rest = chunk.Length - coffset;
135 int size = System.Math.Min (count, rest);
137 Array.Copy (chunk.Buffer, coffset, buffer, offset, size);
146 public override void Write (byte[] buffer, int offset, int count)
148 if (position + count > length)
149 SetLength (position + count);
152 Chunk chunk = FindChunk (position);
153 int coffset = position - chunk.Offset;
154 int rest = chunk.Length - coffset;
155 int size = System.Math.Min (count, rest);
157 Array.Copy (buffer, offset, chunk.Buffer, coffset, size);
164 public byte[] GetContents ()
166 byte[] retval = new byte [length];
168 Read (retval, 0, length);
173 public class MonoDebuggerSupport
175 static GetTypeFunc get_type;
176 static GetMethodTokenFunc get_method_token;
177 static GetMethodFunc get_method;
178 static GetLocalTypeFromSignatureFunc local_type_from_sig;
180 delegate Type GetTypeFunc (Assembly assembly, int token);
181 delegate int GetMethodTokenFunc (Assembly assembly, MethodBase method);
182 delegate MethodBase GetMethodFunc (Assembly assembly, int token);
183 delegate Type GetLocalTypeFromSignatureFunc (Assembly assembly, byte[] sig);
185 static Delegate create_delegate (Type delegate_type, string name)
187 Type type = typeof (Assembly);
189 MethodInfo mi = type.GetMethod (name, BindingFlags.Static |
190 BindingFlags.NonPublic);
192 throw new Exception ("Can't find " + name);
194 return Delegate.CreateDelegate (delegate_type, mi);
197 static MonoDebuggerSupport ()
199 get_type = (GetTypeFunc) create_delegate (
200 typeof (GetTypeFunc), "MonoDebugger_GetType");
202 get_method_token = (GetMethodTokenFunc) create_delegate (
203 typeof (GetMethodTokenFunc), "MonoDebugger_GetMethodToken");
205 get_method = (GetMethodFunc) create_delegate (
206 typeof (GetMethodFunc), "MonoDebugger_GetMethod");
208 local_type_from_sig = (GetLocalTypeFromSignatureFunc) create_delegate (
209 typeof (GetLocalTypeFromSignatureFunc),
210 "MonoDebugger_GetLocalTypeFromSignature");
213 public static Type GetType (Assembly assembly, int token)
215 return get_type (assembly, token);
218 public static int GetMethodToken (MethodBase method)
220 return get_method_token (method.ReflectedType.Assembly, method);
223 public static MethodBase GetMethod (Assembly assembly, int token)
225 return get_method (assembly, token);
228 public static Type GetLocalTypeFromSignature (Assembly assembly, byte[] sig)
230 return local_type_from_sig (assembly, sig);
234 public class MonoSymbolFile : IDisposable
236 ArrayList methods = new ArrayList ();
237 ArrayList sources = new ArrayList ();
238 Hashtable method_source_hash = new Hashtable ();
239 Hashtable type_hash = new Hashtable ();
243 int last_method_index;
244 int last_source_index;
245 int last_namespace_index;
247 public MonoSymbolFile ()
250 internal int AddSource (SourceFileEntry source)
252 sources.Add (source);
253 return ++last_source_index;
256 internal int DefineType (Type type)
258 if (type_hash.Contains (type))
259 return (int) type_hash [type];
261 int index = ++last_type_index;
262 type_hash.Add (type, index);
266 internal void AddMethod (MethodEntry entry)
271 internal int GetNextTypeIndex ()
273 return ++last_type_index;
276 internal int GetNextMethodIndex ()
278 return ++last_method_index;
281 internal int GetNextNamespaceIndex ()
283 return ++last_namespace_index;
286 byte [] stringBuffer;
287 int maxCharsPerRound;
288 static Encoding enc = Encoding.UTF8;
290 internal void WriteString (BinaryWriter bw, string s)
292 int len = enc.GetByteCount (s);
296 if (stringBuffer == null) {
297 stringBuffer = new byte [512];
298 maxCharsPerRound = 512 / enc.GetMaxByteCount (1);
302 int chrem = s.Length;
304 int cch = (chrem > maxCharsPerRound) ? maxCharsPerRound : chrem;
305 int blen = enc.GetBytes (s, chpos, cch, stringBuffer, 0);
306 bw.Write (stringBuffer, 0, blen);
313 internal string ReadString (int offset)
315 int old_pos = (int) reader.BaseStream.Position;
316 reader.BaseStream.Position = offset;
317 int length = reader.ReadInt32 ();
319 byte[] data = reader.ReadBytes (length);
320 string text = Encoding.UTF8.GetString (data);
321 reader.BaseStream.Position = old_pos;
325 void Write (BinaryWriter bw)
327 // Magic number and file version.
328 bw.Write (OffsetTable.Magic);
329 bw.Write (OffsetTable.Version);
332 // Offsets of file sections; we must write this after we're done
333 // writing the whole file, so we just reserve the space for it here.
335 long offset_table_offset = bw.BaseStream.Position;
339 // Write data sections.
341 ot.DataSectionOffset = (int) bw.BaseStream.Position;
342 foreach (SourceFileEntry source in sources)
343 source.WriteData (bw);
344 ot.DataSectionSize = (int) bw.BaseStream.Position - ot.DataSectionOffset;
347 // Write method table.
349 ot.MethodTableOffset = (int) bw.BaseStream.Position;
350 for (int i = 0; i < methods.Count; i++) {
351 MethodEntry entry = (MethodEntry) methods [i];
352 entry.WriteIndex (bw);
354 ot.MethodTableSize = (int) bw.BaseStream.Position - ot.MethodTableOffset;
357 // Write source table.
359 ot.SourceTableOffset = (int) bw.BaseStream.Position;
360 for (int i = 0; i < sources.Count; i++) {
361 SourceFileEntry source = (SourceFileEntry) sources [i];
364 ot.SourceTableSize = (int) bw.BaseStream.Position - ot.SourceTableOffset;
367 // Fixup offset table.
369 ot.TypeCount = last_type_index;
370 ot.MethodCount = methods.Count;
371 ot.SourceCount = sources.Count;
374 // Write offset table.
376 ot.TotalFileSize = (int) bw.BaseStream.Position;
377 bw.Seek ((int) offset_table_offset, SeekOrigin.Begin);
379 bw.Seek (0, SeekOrigin.End);
382 public byte[] CreateSymbolFile ()
385 throw new InvalidOperationException ();
387 using (MyMemoryStream stream = new MyMemoryStream ()) {
388 Write (new BinaryWriter (stream));
389 return stream.GetContents ();
395 Hashtable method_hash;
396 Hashtable source_file_hash;
398 Hashtable method_token_hash;
399 Hashtable source_name_hash;
401 protected MonoSymbolFile (Assembly assembly, Stream stream)
403 this.assembly = assembly;
405 reader = new BinaryReader (stream);
408 long magic = reader.ReadInt64 ();
409 long version = reader.ReadInt32 ();
410 if ((magic != OffsetTable.Magic) || (version != OffsetTable.Version))
411 throw new MonoSymbolFileException ();
412 ot = new OffsetTable (reader);
414 throw new MonoSymbolFileException ();
417 method_hash = new Hashtable ();
418 source_file_hash = new Hashtable ();
421 public static MonoSymbolFile ReadSymbolFile (Assembly assembly)
423 Stream stream = assembly.GetManifestResourceStream ("MonoSymbolFile");
427 return new MonoSymbolFile (assembly, stream);
430 public Assembly Assembly {
431 get { return assembly; }
434 public int SourceCount {
435 get { return ot.SourceCount; }
438 public int MethodCount {
439 get { return ot.MethodCount; }
442 public int TypeCount {
443 get { return ot.TypeCount; }
446 public int NamespaceCount {
447 get { return last_namespace_index; }
450 internal int LineNumberCount = 0;
451 internal int LocalCount = 0;
452 internal int StringSize = 0;
454 public SourceFileEntry GetSourceFile (int index)
456 if ((index < 1) || (index > ot.SourceCount))
457 throw new ArgumentException ();
459 throw new InvalidOperationException ();
461 SourceFileEntry source = (SourceFileEntry) source_file_hash [index];
465 reader.BaseStream.Position = ot.SourceTableOffset +
466 SourceFileEntry.Size * (index - 1);
467 source = new SourceFileEntry (this, reader);
468 source_file_hash.Add (index, source);
472 public SourceFileEntry[] Sources {
475 throw new InvalidOperationException ();
477 SourceFileEntry[] retval = new SourceFileEntry [SourceCount];
478 for (int i = 0; i < SourceCount; i++)
479 retval [i] = GetSourceFile (i + 1);
484 public MethodIndexEntry GetMethodIndexEntry (int index)
486 int old_pos = (int) reader.BaseStream.Position;
487 reader.BaseStream.Position = ot.MethodTableOffset +
488 MethodIndexEntry.Size * (index - 1);
489 MethodIndexEntry ie = new MethodIndexEntry (reader);
490 reader.BaseStream.Position = old_pos;
494 public MethodEntry GetMethodByToken (int token)
497 throw new InvalidOperationException ();
499 if (method_token_hash == null) {
500 method_token_hash = new Hashtable ();
502 for (int i = 0; i < MethodCount; i++) {
503 MethodIndexEntry ie = GetMethodIndexEntry (i + 1);
505 method_token_hash.Add (ie.Token, i + 1);
509 object value = method_token_hash [token];
513 return GetMethod ((int) value);
516 public MethodEntry GetMethod (MethodBase method)
519 throw new InvalidOperationException ();
520 int token = MonoDebuggerSupport.GetMethodToken (method);
521 return GetMethodByToken (token);
524 public MethodEntry GetMethod (int index)
526 if ((index < 1) || (index > ot.MethodCount))
527 throw new ArgumentException ();
529 throw new InvalidOperationException ();
531 MethodEntry entry = (MethodEntry) method_hash [index];
535 MethodIndexEntry ie = GetMethodIndexEntry (index);
536 reader.BaseStream.Position = ie.FileOffset;
538 entry = new MethodEntry (this, reader, index);
539 method_hash.Add (index, entry);
543 public MethodEntry[] Methods {
546 throw new InvalidOperationException ();
548 MethodEntry[] retval = new MethodEntry [MethodCount];
549 for (int i = 0; i < MethodCount; i++)
550 retval [i] = GetMethod (i + 1);
555 public MethodSourceEntry GetMethodSource (int index)
557 if ((index < 1) || (index > ot.MethodCount))
558 throw new ArgumentException ();
560 throw new InvalidOperationException ();
562 object entry = method_source_hash [index];
564 return (MethodSourceEntry) entry;
566 MethodEntry method = GetMethod (index);
567 foreach (MethodSourceEntry source in method.SourceFile.Methods) {
568 if (source.Index == index) {
569 method_source_hash.Add (index, source);
574 throw new MonoSymbolFileException ("Internal error.");
577 public int FindSource (string file_name)
580 throw new InvalidOperationException ();
582 if (source_name_hash == null) {
583 source_name_hash = new Hashtable ();
585 for (int i = 0; i < ot.SourceCount; i++) {
586 SourceFileEntry source = GetSourceFile (i + 1);
588 source_name_hash.Add (source.FileName, i);
592 object value = source_name_hash [file_name];
598 internal BinaryReader BinaryReader {
601 throw new InvalidOperationException ();
607 void IDisposable.Dispose ()
612 protected virtual void Dispose (bool disposing)
615 if (reader != null) {