// MdbWriter.cs
//
// Author:
-// Jb Evain (jbevain@gmail.com)
+// Jb Evain (jbevain@novell.com)
//
-// (C) 2006 Jb Evain
+// (C) 2007 Novell, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
+// Inspired by the pdb2mdb tool written by Robert Jordan, thanks Robert!
+
namespace Mono.Cecil.Mdb {
+ using System;
using System.Collections;
- using SDS = System.Diagnostics.SymbolStore;
+
using Mono.CompilerServices.SymbolWriter;
+
+ using Mono.Cecil;
using Mono.Cecil.Cil;
class MdbWriter : ISymbolWriter {
- SymbolWriterImpl m_writer;
+ Guid m_mvid;
+ MonoSymbolWriter m_writer;
+
Hashtable m_documents;
- public MdbWriter (SymbolWriterImpl writer)
+ public MdbWriter (Guid mvid, string assembly)
{
- m_writer = writer;
+ m_mvid = mvid;
+ m_writer = new MonoSymbolWriter (assembly);
m_documents = new Hashtable ();
}
- public void Write (MethodBody body, byte [][] variables)
+ static Instruction [] GetInstructions (MethodBody body)
{
- Document document = CreateDocuments (body);
- if (document != null) {
- SDS.ISymbolDocumentWriter docWriter = GetDocument (document);
- m_writer.SetMethodSourceRange (docWriter, 1, 1, docWriter, int.MaxValue, int.MaxValue);
- }
+ ArrayList list = new ArrayList ();
+ foreach (Instruction instruction in body.Instructions)
+ if (instruction.SequencePoint != null)
+ list.Add (instruction);
- m_writer.OpenMethod (new SDS.SymbolToken ((int) body.Method.MetadataToken.ToUInt ()));
- m_writer.SetSymAttribute (new SDS.SymbolToken (), "__name", System.Text.Encoding.UTF8.GetBytes (body.Method.Name));
+ return list.ToArray (typeof (Instruction)) as Instruction [];
+ }
- CreateScopes (body, body.Scopes, variables);
- m_writer.CloseMethod ();
+ SourceFile GetSourceFile (Document document)
+ {
+ string url = document.Url;
+ SourceFile file = m_documents [url] as SourceFile;
+ if (file != null)
+ return file;
+
+ file = new SourceFile (m_writer.DefineDocument (url));
+ m_documents [url] = file;
+ return file;
}
- void CreateScopes (MethodBody body, ScopeCollection scopes, byte [][] variables)
+ void Populate (Instruction [] instructions, int [] offsets,
+ int [] startRows, int [] startCols, int [] endRows, int [] endCols,
+ out SourceFile file)
{
- foreach (Scope s in scopes) {
- int startOffset = s.Start.Offset;
- int endOffset = s.End == body.Instructions.Outside ?
- body.Instructions[body.Instructions.Count - 1].Offset + 1 :
- s.End.Offset;
+ SourceFile document = null;
+
+ for (int i = 0; i < instructions.Length; i++) {
+ Instruction instr = (Instruction) instructions [i];
+ offsets [i] = instr.Offset;
- m_writer.OpenScope (startOffset);
- //m_writer.UsingNamespace (body.Method.DeclaringType.Namespace);
- //m_writer.OpenNamespace (body.Method.DeclaringType.Namespace);
+ if (document == null)
+ document = GetSourceFile (instr.SequencePoint.Document);
- int start = body.Instructions.IndexOf (s.Start);
- int end = s.End == body.Instructions.Outside ?
- body.Instructions.Count - 1 :
- body.Instructions.IndexOf (s.End);
+ startRows [i] = instr.SequencePoint.StartLine;
+ startCols [i] = instr.SequencePoint.StartColumn;
+ endRows [i] = instr.SequencePoint.EndLine;
+ endCols [i] = instr.SequencePoint.EndColumn;
+ }
- ArrayList instructions = new ArrayList();
- for (int i = start; i <= end; i++)
- if (body.Instructions [i].SequencePoint != null)
- instructions.Add (body.Instructions [i]);
+ file = document;
+ }
- Document doc = null;
+ public void Write (MethodBody body, byte [][] variables)
+ {
+ SourceMethod meth = new SourceMethod (body.Method);
- int [] offsets = new int [instructions.Count];
- int [] startRows = new int [instructions.Count];
- int [] startCols = new int [instructions.Count];
- int [] endRows = new int [instructions.Count];
- int [] endCols = new int [instructions.Count];
+ SourceFile file;
- for (int i = 0; i < instructions.Count; i++) {
- Instruction instr = (Instruction) instructions [i];
- offsets [i] = instr.Offset;
+ Instruction [] instructions = GetInstructions (body);
+ int length = instructions.Length;
+ if (length == 0)
+ return;
- if (doc == null)
- doc = instr.SequencePoint.Document;
+ int [] offsets = new int [length];
+ int [] startRows = new int [length];
+ int [] startCols = new int [length];
+ int [] endRows = new int [length];
+ int [] endCols = new int [length];
- startRows [i] = instr.SequencePoint.StartLine;
- startCols [i] = instr.SequencePoint.StartColumn;
- endRows [i] = instr.SequencePoint.EndLine;
- endCols [i] = instr.SequencePoint.EndColumn;
- }
+ Populate (instructions, offsets, startRows, startCols, endRows, endCols, out file);
- m_writer.DefineSequencePoints (GetDocument (doc),
- offsets, startRows, startCols, endRows, endCols);
+ m_writer.OpenMethod (file, meth,
+ startRows [0], startCols [0],
+ endRows [length - 1], endCols [length - 1]);
- CreateLocalVariables (s, startOffset, endOffset, variables);
+ for (int i = 0; i < length; i++)
+ m_writer.MarkSequencePoint (offsets [i], startRows [i], startCols [i]);
- CreateScopes (body, s.Scopes, variables);
- m_writer.CloseNamespace ();
+ MarkVariables (body, variables);
- m_writer.CloseScope (endOffset);
- }
+ m_writer.CloseMethod ();
}
- void CreateLocalVariables (Scope s, int startOffset, int endOffset, byte [][] variables)
+ void MarkVariables (MethodBody body, byte [][] variables)
{
- for (int i = 0; i < s.Variables.Count; i++) {
- VariableDefinition var = s.Variables [i];
- m_writer.DefineLocalVariable (
- var.Name,
- 0,
- variables [var.Index],
- 0,
- 0,
- 0,
- 0,
- startOffset,
- endOffset);
+ for (int i = 0; i < body.Variables.Count; i++) {
+ VariableDefinition var = body.Variables [i];
+ m_writer.DefineLocalVariable (i, var.Name, variables [i]);
}
}
- Document CreateDocuments (MethodBody body)
+ public void Dispose ()
{
- Document doc = null;
- foreach (Instruction instr in body.Instructions) {
- if (instr.SequencePoint == null)
- continue;
+ m_writer.WriteSymbolFile (m_mvid);
+ }
- if (doc == null)
- doc = instr.SequencePoint.Document;
+ class SourceFile : ISourceFile {
- GetDocument (instr.SequencePoint.Document);
+ SourceFileEntry m_entry;
+
+ public SourceFileEntry Entry {
+ get { return m_entry; }
}
- return doc;
+ public SourceFile (SourceFileEntry entry)
+ {
+ m_entry = entry;
+ }
}
- SDS.ISymbolDocumentWriter GetDocument (Document document)
- {
- SDS.ISymbolDocumentWriter docWriter = m_documents [document.Url] as SDS.ISymbolDocumentWriter;
- if (docWriter != null)
- return docWriter;
-
- docWriter = m_writer.DefineDocument (
- document.Url,
- GuidAttribute.GetGuidFromValue ((int) document.Language, typeof (DocumentLanguage)),
- GuidAttribute.GetGuidFromValue ((int) document.LanguageVendor, typeof (DocumentLanguageVendor)),
- GuidAttribute.GetGuidFromValue ((int) document.Type, typeof (DocumentType)));
-
- m_documents [document.Url] = docWriter;
- return docWriter;
- }
+ class SourceMethod : ISourceMethod {
- public void Dispose ()
- {
- m_writer.Close ();
+ MethodDefinition m_method;
+
+ public string Name {
+ get { return m_method.Name; }
+ }
+
+ public int NamespaceID {
+ get { return 0; }
+ }
+
+ public int Token {
+ get { return (int) m_method.MetadataToken.ToUInt (); }
+ }
+
+ public SourceMethod (MethodDefinition method)
+ {
+ m_method = method;
+ }
}
}
}