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 MonoSymbolFile : IDisposable
175 ArrayList methods = new ArrayList ();
176 ArrayList sources = new ArrayList ();
177 Hashtable method_source_hash = new Hashtable ();
178 Hashtable type_hash = new Hashtable ();
182 int last_method_index;
183 int last_source_index;
184 int last_namespace_index;
186 public MonoSymbolFile ()
189 internal int AddSource (SourceFileEntry source)
191 sources.Add (source);
192 return ++last_source_index;
195 internal int DefineType (Type type)
197 if (type_hash.Contains (type))
198 return (int) type_hash [type];
200 int index = ++last_type_index;
201 type_hash.Add (type, index);
205 internal void AddMethod (MethodEntry entry)
210 internal int GetNextTypeIndex ()
212 return ++last_type_index;
215 internal int GetNextMethodIndex ()
217 return ++last_method_index;
220 internal int GetNextNamespaceIndex ()
222 return ++last_namespace_index;
225 byte [] stringBuffer;
226 int maxCharsPerRound;
227 static Encoding enc = Encoding.UTF8;
229 internal void WriteString (BinaryWriter bw, string s)
231 int len = enc.GetByteCount (s);
235 if (stringBuffer == null) {
236 stringBuffer = new byte [512];
237 maxCharsPerRound = 512 / enc.GetMaxByteCount (1);
241 int chrem = s.Length;
243 int cch = (chrem > maxCharsPerRound) ? maxCharsPerRound : chrem;
244 int blen = enc.GetBytes (s, chpos, cch, stringBuffer, 0);
245 bw.Write (stringBuffer, 0, blen);
252 internal string ReadString (int offset)
254 int old_pos = (int) reader.BaseStream.Position;
255 reader.BaseStream.Position = offset;
256 int length = reader.ReadInt32 ();
258 byte[] data = reader.ReadBytes (length);
259 string text = Encoding.UTF8.GetString (data);
260 reader.BaseStream.Position = old_pos;
264 void Write (BinaryWriter bw)
266 // Magic number and file version.
267 bw.Write (OffsetTable.Magic);
268 bw.Write (OffsetTable.Version);
271 // Offsets of file sections; we must write this after we're done
272 // writing the whole file, so we just reserve the space for it here.
274 long offset_table_offset = bw.BaseStream.Position;
278 // Write data sections.
280 ot.DataSectionOffset = (int) bw.BaseStream.Position;
281 foreach (SourceFileEntry source in sources)
282 source.WriteData (bw);
283 ot.DataSectionSize = (int) bw.BaseStream.Position - ot.DataSectionOffset;
286 // Write method table.
288 ot.MethodTableOffset = (int) bw.BaseStream.Position;
289 for (int i = 0; i < methods.Count; i++) {
290 MethodEntry entry = (MethodEntry) methods [i];
291 entry.WriteIndex (bw);
293 ot.MethodTableSize = (int) bw.BaseStream.Position - ot.MethodTableOffset;
296 // Write source table.
298 ot.SourceTableOffset = (int) bw.BaseStream.Position;
299 for (int i = 0; i < sources.Count; i++) {
300 SourceFileEntry source = (SourceFileEntry) sources [i];
303 ot.SourceTableSize = (int) bw.BaseStream.Position - ot.SourceTableOffset;
306 // Fixup offset table.
308 ot.TypeCount = last_type_index;
309 ot.MethodCount = methods.Count;
310 ot.SourceCount = sources.Count;
313 // Write offset table.
315 ot.TotalFileSize = (int) bw.BaseStream.Position;
316 bw.Seek ((int) offset_table_offset, SeekOrigin.Begin);
318 bw.Seek (0, SeekOrigin.End);
321 public byte[] CreateSymbolFile ()
324 throw new InvalidOperationException ();
326 using (MyMemoryStream stream = new MyMemoryStream ()) {
327 Write (new BinaryWriter (stream));
328 return stream.GetContents ();
334 Hashtable method_hash;
335 Hashtable source_file_hash;
337 Hashtable method_token_hash;
338 Hashtable method_name_hash;
339 Hashtable method_full_name_hash;
340 Hashtable source_name_hash;
342 protected MonoSymbolFile (Assembly assembly, Stream stream)
344 this.assembly = assembly;
346 reader = new BinaryReader (stream);
349 long magic = reader.ReadInt64 ();
350 long version = reader.ReadInt32 ();
351 if ((magic != OffsetTable.Magic) || (version != OffsetTable.Version))
352 throw new MonoSymbolFileException ();
353 ot = new OffsetTable (reader);
355 throw new MonoSymbolFileException ();
358 method_hash = new Hashtable ();
359 source_file_hash = new Hashtable ();
362 public static MonoSymbolFile ReadSymbolFile (Assembly assembly)
364 Stream stream = assembly.GetManifestResourceStream ("MonoSymbolFile");
368 return new MonoSymbolFile (assembly, stream);
371 public Assembly Assembly {
372 get { return assembly; }
375 public int SourceCount {
376 get { return ot.SourceCount; }
379 public int MethodCount {
380 get { return ot.MethodCount; }
383 public int TypeCount {
384 get { return ot.TypeCount; }
387 public int NamespaceCount {
388 get { return last_namespace_index; }
391 internal int LineNumberCount = 0;
392 internal int LocalCount = 0;
393 internal int StringSize = 0;
395 public SourceFileEntry GetSourceFile (int index)
397 if ((index < 1) || (index > ot.SourceCount))
398 throw new ArgumentException ();
400 throw new InvalidOperationException ();
402 SourceFileEntry source = (SourceFileEntry) source_file_hash [index];
406 reader.BaseStream.Position = ot.SourceTableOffset +
407 SourceFileEntry.Size * (index - 1);
408 source = new SourceFileEntry (this, reader);
409 source_file_hash.Add (index, source);
413 public SourceFileEntry[] Sources {
416 throw new InvalidOperationException ();
418 SourceFileEntry[] retval = new SourceFileEntry [SourceCount];
419 for (int i = 0; i < SourceCount; i++)
420 retval [i] = GetSourceFile (i + 1);
425 public MethodIndexEntry GetMethodIndexEntry (int index)
427 int old_pos = (int) reader.BaseStream.Position;
428 reader.BaseStream.Position = ot.MethodTableOffset +
429 MethodIndexEntry.Size * (index - 1);
430 MethodIndexEntry ie = new MethodIndexEntry (reader);
431 reader.BaseStream.Position = old_pos;
435 public MethodEntry GetMethodByToken (int token)
438 throw new InvalidOperationException ();
440 if (method_token_hash == null) {
441 method_token_hash = new Hashtable ();
443 for (int i = 0; i < MethodCount; i++) {
444 MethodIndexEntry ie = GetMethodIndexEntry (i + 1);
446 method_token_hash.Add (ie.Token, i + 1);
450 object value = method_token_hash [token];
454 return GetMethod ((int) value);
457 public MethodEntry GetMethod (MethodBase method)
460 throw new InvalidOperationException ();
461 int token = assembly.MonoDebugger_GetMethodToken (method);
462 return GetMethodByToken (token);
465 public MethodEntry GetMethod (int index)
467 if ((index < 1) || (index > ot.MethodCount))
468 throw new ArgumentException ();
470 throw new InvalidOperationException ();
472 MethodEntry entry = (MethodEntry) method_hash [index];
476 MethodIndexEntry ie = GetMethodIndexEntry (index);
477 reader.BaseStream.Position = ie.FileOffset;
479 entry = new MethodEntry (this, reader, index);
480 method_hash.Add (index, entry);
484 public MethodEntry[] Methods {
487 throw new InvalidOperationException ();
489 MethodEntry[] retval = new MethodEntry [MethodCount];
490 for (int i = 0; i < MethodCount; i++)
491 retval [i] = GetMethod (i + 1);
496 public MethodSourceEntry GetMethodSource (int index)
498 if ((index < 1) || (index > ot.MethodCount))
499 throw new ArgumentException ();
501 throw new InvalidOperationException ();
503 object entry = method_source_hash [index];
505 return (MethodSourceEntry) entry;
507 MethodEntry method = GetMethod (index);
508 foreach (MethodSourceEntry source in method.SourceFile.Methods) {
509 if (source.Index == index) {
510 method_source_hash.Add (index, source);
515 throw new MonoSymbolFileException ("Internal error.");
518 public int FindMethod (string full_name)
521 throw new InvalidOperationException ();
523 if (method_full_name_hash == null) {
524 method_full_name_hash = new Hashtable ();
526 for (int i = 0; i < ot.MethodCount; i++) {
527 MethodIndexEntry ie = GetMethodIndexEntry (i + 1);
528 string name = ReadString (ie.FullNameOffset);
530 method_full_name_hash.Add (name, i + 1);
534 object value = method_full_name_hash [full_name];
540 public int[] MethodLookup (string query)
543 throw new InvalidOperationException ();
546 if (method_name_hash == null) {
547 method_name_hash = new Hashtable ();
549 for (int i = 0; i < ot.MethodCount; i++) {
550 MethodIndexEntry ie = GetMethodIndexEntry (i + 1);
551 string full_name = ReadString (ie.FullNameOffset);
553 int pos = full_name.IndexOf ('(');
554 string name = full_name.Substring (0, pos);
556 list = method_name_hash [name] as ArrayList;
558 list = new ArrayList ();
559 method_name_hash.Add (name, list);
566 list = method_name_hash [query] as ArrayList;
570 int[] retval = new int [list.Count];
571 list.CopyTo (retval, 0);
575 public int FindSource (string file_name)
578 throw new InvalidOperationException ();
580 if (source_name_hash == null) {
581 source_name_hash = new Hashtable ();
583 for (int i = 0; i < ot.SourceCount; i++) {
584 SourceFileEntry source = GetSourceFile (i + 1);
586 source_name_hash.Add (source.FileName, i);
590 object value = source_name_hash [file_name];
596 internal BinaryReader BinaryReader {
599 throw new InvalidOperationException ();
605 void IDisposable.Dispose ()
610 protected virtual void Dispose (bool disposing)
613 if (reader != null) {