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 = 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 = 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 source_hash = new Hashtable ();
178 Hashtable type_hash = new Hashtable ();
182 int last_method_index;
184 public MonoSymbolFile ()
187 public SourceFileEntry DefineSource (string source_file)
190 throw new InvalidOperationException ();
192 SourceFileEntry source = (SourceFileEntry) source_hash [source_file];
193 if (source == null) {
194 source = new SourceFileEntry (this, source_file, sources.Count + 1);
195 source_hash.Add (source_file, source);
196 sources.Add (source);
201 internal int DefineType (Type type)
203 if (type_hash.Contains (type))
204 return (int) type_hash [type];
206 int index = ++last_type_index;
207 type_hash.Add (type, index);
211 internal void AddMethod (MethodEntry entry)
216 internal int GetNextTypeIndex ()
218 return ++last_type_index;
221 internal int GetNextMethodIndex ()
223 return ++last_method_index;
226 internal void WriteString (BinaryWriter bw, string text)
228 byte[] data = Encoding.UTF8.GetBytes (text);
229 bw.Write ((int) data.Length);
231 StringSize += data.Length;
234 internal string ReadString (int offset)
236 int old_pos = (int) reader.BaseStream.Position;
237 reader.BaseStream.Position = offset;
238 int length = reader.ReadInt32 ();
240 byte[] data = reader.ReadBytes (length);
241 string text = Encoding.UTF8.GetString (data);
242 reader.BaseStream.Position = old_pos;
246 void Write (BinaryWriter bw)
248 // Magic number and file version.
249 bw.Write (OffsetTable.Magic);
250 bw.Write (OffsetTable.Version);
253 // Offsets of file sections; we must write this after we're done
254 // writing the whole file, so we just reserve the space for it here.
256 long offset_table_offset = bw.BaseStream.Position;
260 // Write data sections.
262 ot.DataSectionOffset = (int) bw.BaseStream.Position;
263 foreach (SourceFileEntry source in sources)
264 source.WriteData (bw);
265 ot.DataSectionSize = (int) bw.BaseStream.Position - ot.DataSectionOffset;
268 // Write method table.
270 ot.MethodTableOffset = (int) bw.BaseStream.Position;
271 for (int i = 0; i < methods.Count; i++) {
272 MethodEntry entry = (MethodEntry) methods [i];
273 entry.WriteIndex (bw);
275 ot.MethodTableSize = (int) bw.BaseStream.Position - ot.MethodTableOffset;
278 // Write source table.
280 ot.SourceTableOffset = (int) bw.BaseStream.Position;
281 for (int i = 0; i < sources.Count; i++) {
282 SourceFileEntry source = (SourceFileEntry) sources [i];
285 ot.SourceTableSize = (int) bw.BaseStream.Position - ot.SourceTableOffset;
288 // Fixup offset table.
290 ot.TypeCount = last_type_index;
291 ot.MethodCount = methods.Count;
292 ot.SourceCount = sources.Count;
295 // Write offset table.
297 ot.TotalFileSize = (int) bw.BaseStream.Position;
298 bw.Seek ((int) offset_table_offset, SeekOrigin.Begin);
300 bw.Seek (0, SeekOrigin.End);
303 public byte[] CreateSymbolFile ()
306 throw new InvalidOperationException ();
308 using (MyMemoryStream stream = new MyMemoryStream ()) {
309 Write (new BinaryWriter (stream));
310 Console.WriteLine ("WROTE SYMFILE: {0} sources, {1} methods, {2} types, " +
311 "{3} line numbers, {4} locals, {5} bytes of string data",
312 SourceCount, MethodCount, TypeCount, LineNumberCount,
313 LocalCount, StringSize);
314 Console.WriteLine (ot);
315 return stream.GetContents ();
321 Hashtable method_hash;
322 Hashtable source_file_hash;
324 Hashtable method_name_hash;
325 Hashtable source_name_hash;
327 protected MonoSymbolFile (Stream stream)
329 reader = new BinaryReader (stream);
332 long magic = reader.ReadInt64 ();
333 long version = reader.ReadInt32 ();
334 if ((magic != OffsetTable.Magic) || (version != OffsetTable.Version))
335 throw new MonoSymbolFileException ();
336 ot = new OffsetTable (reader);
338 throw new MonoSymbolFileException ();
341 method_hash = new Hashtable ();
342 source_file_hash = new Hashtable ();
345 public static MonoSymbolFile ReadSymbolFile (Assembly assembly)
347 Stream stream = assembly.GetManifestResourceStream ("MonoSymbolFile");
351 return new MonoSymbolFile (stream);
354 public int SourceCount {
355 get { return ot.SourceCount; }
358 public int MethodCount {
359 get { return ot.MethodCount; }
362 public int TypeCount {
363 get { return ot.TypeCount; }
366 internal int LineNumberCount = 0;
367 internal int LocalCount = 0;
368 internal int StringSize = 0;
370 public SourceFileEntry GetSourceFile (int index)
372 if ((index < 1) || (index > ot.SourceCount))
373 throw new ArgumentException ();
375 throw new InvalidOperationException ();
377 SourceFileEntry source = (SourceFileEntry) source_file_hash [index];
381 reader.BaseStream.Position = ot.SourceTableOffset +
382 SourceFileEntry.Size * (index - 1);
383 source = new SourceFileEntry (this, reader);
384 source_file_hash.Add (index, source);
388 public MethodEntry GetMethod (int index)
390 if ((index < 1) || (index > ot.MethodCount))
391 throw new ArgumentException ();
393 throw new InvalidOperationException ();
395 MethodEntry entry = (MethodEntry) method_hash [index];
399 reader.BaseStream.Position = ot.MethodTableOffset + 8 * (index - 1);
400 reader.BaseStream.Position = reader.ReadInt32 ();
402 entry = new MethodEntry (this, reader, index);
403 method_hash.Add (index, entry);
407 public int FindMethod (string full_name)
410 throw new InvalidOperationException ();
412 if (method_name_hash == null) {
413 method_name_hash = new Hashtable ();
415 for (int i = 0; i < ot.MethodCount; i++) {
416 reader.BaseStream.Position = ot.MethodTableOffset + 8 * i;
418 int offset = reader.ReadInt32 ();
419 int name_offset = reader.ReadInt32 ();
420 string name = ReadString (name_offset);
422 method_name_hash.Add (name, i);
426 object value = method_name_hash [full_name];
432 public int FindSource (string file_name)
435 throw new InvalidOperationException ();
437 if (source_name_hash == null) {
438 source_name_hash = new Hashtable ();
440 for (int i = 0; i < ot.SourceCount; i++) {
441 SourceFileEntry source = GetSourceFile (i + 1);
443 source_name_hash.Add (source.FileName, i);
447 object value = source_name_hash [file_name];
453 internal BinaryReader BinaryReader {
456 throw new InvalidOperationException ();
462 void IDisposable.Dispose ()
467 protected virtual void Dispose (bool disposing)
470 if (reader != null) {