diff options
10 files changed, 809 insertions, 0 deletions
diff --git a/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/ChangeLog b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/ChangeLog new file mode 100644 index 00000000000..6cefb798b89 --- /dev/null +++ b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/ChangeLog @@ -0,0 +1,31 @@ +2007-02-21 Jb Evain <jb@nurv.fr> + + * Start working on local var debug infos emitting. + +2007-02-21 Jb Evain <jbevain@gmail.com> + + * Mono.Cecil.Pdb/PdbReader.cs + Mono.Cecil.Pdb/PdbHelper.cs + Mono.Cecil.Pdb/IMetaDataDispenser.cs: + Refactor patches from: + Sverre Boschman <s.r.boschman@iego-development.nl> + + - Force the release of the lock on the pdb on reading + - Implement the ability to read a pdb in memory + +2006-09-24 Jb Evain <jbevain@gmail.com> + + * Handle the fact that a scope end points outside the cil stream. + +2006-09-20 Jb Evain <jbevain@gmail.com> + + * implement somes bits of the writing stuff. + +2006-09-19 Jb Evain <jbevain@gmail.com> + + * first checkin in SVN: + This is the assembly to support reading and writing + from Microsoft's pdb symbols store. + + It will only work on Windows until Microsoft release + the spec for the pdb files. diff --git a/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb.csproj b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb.csproj new file mode 100644 index 00000000000..738160c65fa --- /dev/null +++ b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb.csproj @@ -0,0 +1,61 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>8.0.50727</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{4FEBBB25-D5C0-48F0-A822-2E0D6F3D777E}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>Mono.Cecil.Pdb</RootNamespace> + <AssemblyName>Mono.Cecil.Pdb</AssemblyName> + <StartupObject> + </StartupObject> + <SignAssembly>true</SignAssembly> + <AssemblyOriginatorKeyFile>..\..\mcs\class\mono.snk</AssemblyOriginatorKeyFile> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> + <ItemGroup> + <Compile Include="Mono.Cecil.Pdb\AssemblyInfo.cs" /> + <Compile Include="Mono.Cecil.Pdb\IMetadataDispenser.cs" /> + <Compile Include="Mono.Cecil.Pdb\IMetadataImport.cs" /> + <Compile Include="Mono.Cecil.Pdb\PdbFactory.cs" /> + <Compile Include="Mono.Cecil.Pdb\PdbReader.cs" /> + <Compile Include="Mono.Cecil.Pdb\PdbWriter.cs" /> + <Compile Include="Mono.Cecil.Pdb\PdbHelper.cs" /> + </ItemGroup> + <ItemGroup> + <Reference Include="ISymWrapper" /> + <Reference Include="System" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\mcs\class\Mono.Cecil\Mono.Cecil.csproj"> + <Project>{D8F63DFF-5230-43E4-9AB2-DA6E721A1FAE}</Project> + <Name>Mono.Cecil</Name> + </ProjectReference> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/AssemblyInfo.cs b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/AssemblyInfo.cs new file mode 100644 index 00000000000..5bdef131cca --- /dev/null +++ b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/AssemblyInfo.cs @@ -0,0 +1,43 @@ +// +// AssemblyInfo.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// (C) 2006 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle ("Mono.Cecil.Pdb")] +[assembly: AssemblyDescription ("Support for the pdb symbols store in Cecil")] +[assembly: AssemblyConfiguration ("")] +[assembly: AssemblyProduct ("Mono.Cecil")] +[assembly: AssemblyCopyright ("(C) 2006, Jb Evain")] +[assembly: AssemblyCulture ("")] + +[assembly: CLSCompliant (false)] +[assembly: ComVisible (false)] + +[assembly: AssemblyVersion ("0.2.0.0")] diff --git a/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/IMetadataDispenser.cs b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/IMetadataDispenser.cs new file mode 100644 index 00000000000..7f41d0e3520 --- /dev/null +++ b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/IMetadataDispenser.cs @@ -0,0 +1,56 @@ +// +// IMetadataImport.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// (C) 2006 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +// from: http://blogs.msdn.com/jmstall/articles/sample_pdb2xml.aspx + +namespace Mono.Cecil.Pdb { + + using System; + using System.Runtime.InteropServices; + + [Guid ("809c652e-7396-11d2-9771-00a0c9b4d50c")] + [InterfaceType (ComInterfaceType.InterfaceIsIUnknown)] + [ComVisible (true)] + interface IMetaDataDispenser { + + void DefineScope_Placeholder(); + + void OpenScope ( + [In, MarshalAs (UnmanagedType.LPWStr)] string szScope, + [In] int dwOpenFlags, + [In] ref Guid riid, + [Out, MarshalAs (UnmanagedType.IUnknown)] out object punk); + + void OpenScopeOnMemory ( + [In] IntPtr pData, + [In] uint cbData, + [In] uint dwOpenFlags, + [In] ref Guid riid, + [Out, MarshalAs (UnmanagedType.Interface)] out object punk); + } +} diff --git a/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/IMetadataImport.cs b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/IMetadataImport.cs new file mode 100644 index 00000000000..71e8d622750 --- /dev/null +++ b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/IMetadataImport.cs @@ -0,0 +1,43 @@ +// +// IMetadataImport.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// (C) 2006 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +// from: http://blogs.msdn.com/jmstall/articles/sample_pdb2xml.aspx + +namespace Mono.Cecil.Pdb { + + using System; + using System.Runtime.InteropServices; + + [Guid ("7DAC8207-D3AE-4c75-9B67-92801A497D44")] + [InterfaceType (ComInterfaceType.InterfaceIsIUnknown)] + [ComVisible (true)] + [CLSCompliant (true)] + public interface IMetadataImport { + void Placeholder(); + } +} diff --git a/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/PdbFactory.cs b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/PdbFactory.cs new file mode 100644 index 00000000000..99a4f446d82 --- /dev/null +++ b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/PdbFactory.cs @@ -0,0 +1,46 @@ +// +// PdbFactory.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// (C) 2006 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil.Pdb { + + using Mono.Cecil.Cil; + + public class PdbFactory : ISymbolStoreFactory { + + public ISymbolReader CreateReader (ModuleDefinition module, string assembly) + { + return new PdbReader (PdbHelper.CreateReader (assembly)); + } + + public ISymbolWriter CreateWriter (ModuleDefinition module, string assembly) + { + string pdb = string.Concat(assembly.Substring(0, assembly.LastIndexOf(".")), ".pdb"); + return new PdbWriter (PdbHelper.CreateWriter (assembly, pdb), module, pdb); + } + } +} diff --git a/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/PdbHelper.cs b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/PdbHelper.cs new file mode 100644 index 00000000000..79a15d71e6f --- /dev/null +++ b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/PdbHelper.cs @@ -0,0 +1,130 @@ +// +// PdbHelper.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// (C) 2006 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +// from: http://blogs.msdn.com/jmstall/articles/sample_pdb2xml.aspx + +namespace Mono.Cecil.Pdb { + + using System; + using System.Diagnostics.SymbolStore; + using System.IO; + using System.Runtime.InteropServices; + + internal class PdbHelper { + + [DllImport("ole32.dll")] + static extern int CoCreateInstance ( + [In] ref Guid rclsid, + [In, MarshalAs (UnmanagedType.IUnknown)] object pUnkOuter, + [In] uint dwClsContext, + [In] ref Guid riid, + [Out, MarshalAs(UnmanagedType.Interface)] out object ppv); + + static Guid s_dispenserClassID = new Guid (0xe5cb7a31, 0x7512, 0x11d2, 0x89, 0xce, 0x00, 0x80, 0xc7, 0x92, 0xe5, 0xd8); + static Guid s_dispenserIID = new Guid (0x809c652e, 0x7396, 0x11d2, 0x97, 0x71, 0x00, 0xa0, 0xc9, 0xb4, 0xd5, 0x0c); + static Guid s_importerIID = new Guid (0x7dac8207, 0xd3ae, 0x4c75, 0x9b, 0x67, 0x92, 0x80, 0x1a, 0x49, 0x7d, 0x44); + + public static ISymbolReader CreateReader (string filename) + { + SymBinder binder; + object objImporter; + + IMetaDataDispenser dispenser = InstantiateDispenser (out binder); + dispenser.OpenScope (filename, 0, ref s_importerIID, out objImporter); + + return InstantiateReader (binder, filename, objImporter); + } + + public static ISymbolReader CreateReader (string filename, byte [] binaryFile) + { + SymBinder binder; + object objImporter; + + IntPtr filePtr = Marshal.AllocHGlobal (binaryFile.Length); + Marshal.Copy (binaryFile, 0, filePtr, binaryFile.Length); + + IMetaDataDispenser dispenser = InstantiateDispenser (out binder); + dispenser.OpenScopeOnMemory (filePtr, (uint) binaryFile.Length, 0, ref s_importerIID, out objImporter); + + return InstantiateReader (binder, filename, objImporter); + } + + static IMetaDataDispenser InstantiateDispenser (out SymBinder binder) + { + binder = new SymBinder (); + object dispenser; + CoCreateInstance (ref s_dispenserClassID, null, 1, ref s_dispenserIID, out dispenser); + return (IMetaDataDispenser) dispenser; + } + + static ISymbolReader InstantiateReader (SymBinder binder, string filename, object objImporter) + { + IntPtr importerPtr = IntPtr.Zero; + ISymbolReader reader; + try { + importerPtr = Marshal.GetComInterfaceForObject (objImporter, typeof (IMetadataImport)); + + reader = binder.GetReader (importerPtr, filename, null); + } finally { + if (importerPtr != IntPtr.Zero) + Marshal.Release (importerPtr); + } + + return reader; + } + + public static ISymbolWriter CreateWriter (string assembly, string pdb) + { + SymWriter writer = new SymWriter (false); + + object objDispenser, objImporter; + CoCreateInstance (ref s_dispenserClassID, null, 1, ref s_dispenserIID, out objDispenser); + + IMetaDataDispenser dispenser = (IMetaDataDispenser) objDispenser; + dispenser.OpenScope (assembly, 1, ref s_importerIID, out objImporter); + + IntPtr importerPtr = Marshal.GetComInterfaceForObject (objImporter, typeof (IMetadataImport)); + + try { + if (File.Exists (pdb)) + File.Delete (pdb); + + writer.Initialize (importerPtr, pdb, false); + } finally { + if (importerPtr != IntPtr.Zero) { + Marshal.Release (importerPtr); + Marshal.ReleaseComObject (objDispenser); + Marshal.ReleaseComObject (objImporter); + Marshal.ReleaseComObject (dispenser); + } + } + + return writer; + } + } +} diff --git a/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/PdbReader.cs b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/PdbReader.cs new file mode 100644 index 00000000000..43ef718df81 --- /dev/null +++ b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/PdbReader.cs @@ -0,0 +1,148 @@ +// +// PdbReader.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// (C) 2006 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Cecil.Pdb { + + using System; + using System.Collections; + using System.Diagnostics.SymbolStore; + using System.Runtime.InteropServices; + + public class PdbReader : Cil.ISymbolReader { + + ISymbolReader m_reader; + + Hashtable m_documents; + + internal PdbReader (ISymbolReader reader) + { + m_reader = reader; + m_documents = new Hashtable (); + } + + public void Read (Cil.MethodBody body) + { + try { + ISymbolMethod method = m_reader.GetMethod (new SymbolToken ((int) body.Method.MetadataToken.ToUInt ())); + Hashtable instructions = GetInstructions (body); + + ReadSequencePoints (method, instructions); + ReadScopeAndLocals (method.RootScope, null, body, instructions); + } catch (COMException) {} + } + + static Hashtable GetInstructions (Cil.MethodBody body) + { + Hashtable instructions = new Hashtable (body.Instructions.Count); + foreach (Cil.Instruction i in body.Instructions) + instructions.Add (i.Offset, i); + + return instructions; + } + + static Cil.Instruction GetInstruction (Cil.MethodBody body, Hashtable instructions, int offset) + { + Cil.Instruction instr = (Cil.Instruction) instructions [offset]; + if (instr != null) + return instr; + + return body.Instructions.Outside; + } + + static void ReadScopeAndLocals (ISymbolScope scope, Cil.Scope parent, Cil.MethodBody body, Hashtable instructions) + { + Cil.Scope s = new Cil.Scope (); + s.Start = GetInstruction (body, instructions, scope.StartOffset); + s.End = GetInstruction (body, instructions, scope.EndOffset); + + if (parent != null) + parent.Scopes.Add (s); + else + body.Scopes.Add (s); + + foreach (ISymbolVariable local in scope.GetLocals ()) { + Cil.VariableDefinition variable = body.Variables [local.AddressField1]; + variable.Name = local.Name; + + s.Variables.Add (variable); + } + + foreach (ISymbolScope child in scope.GetChildren ()) + ReadScopeAndLocals (child, s, body, instructions); + } + + void ReadSequencePoints(ISymbolMethod method, Hashtable instructions) + { + int count = method.SequencePointCount; + int [] offsets = new int [count]; + ISymbolDocument [] docs = new ISymbolDocument [count]; + int [] startColumn = new int [count]; + int [] endColumn = new int [count]; + int [] startRow = new int [count]; + int [] endRow = new int [count]; + method.GetSequencePoints (offsets, docs, startRow, startColumn, endRow, endColumn); + + for (int i = 0; i < offsets.Length; i++) { + Cil.Instruction instr = (Cil.Instruction) instructions [offsets [i]]; + + Cil.SequencePoint sp = new Cil.SequencePoint (GetDocument (docs [i])); + sp.StartLine = startRow [i]; + sp.StartColumn = startColumn [i]; + sp.EndLine = endRow [i]; + sp.EndColumn = endColumn [i]; + + instr.SequencePoint = sp; + } + } + + Cil.Document GetDocument (ISymbolDocument document) + { + Cil.Document doc = m_documents [document.URL] as Cil.Document; + if (doc != null) + return doc; + + doc = new Cil.Document (document.URL); + doc.Type = (Cil.DocumentType) Cil.GuidAttribute.GetValueFromGuid ( + document.DocumentType, typeof (Cil.DocumentType)); + doc.Language = (Cil.DocumentLanguage) Cil.GuidAttribute.GetValueFromGuid ( + document.Language, typeof (Cil.DocumentLanguage)); + doc.LanguageVendor = (Cil.DocumentLanguageVendor) Cil.GuidAttribute.GetValueFromGuid ( + document.LanguageVendor, typeof (Cil.DocumentLanguageVendor)); + + m_documents [doc.Url] = doc; + return doc; + } + + public void Dispose () + { + m_reader = null; + // force the release of the pdb lock + GC.Collect (); + } + } +} diff --git a/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/PdbWriter.cs b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/PdbWriter.cs new file mode 100644 index 00000000000..881a04d2c1e --- /dev/null +++ b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/Mono.Cecil.Pdb/PdbWriter.cs @@ -0,0 +1,202 @@ +// +// PdbWriter.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// (C) 2006 Jb Evain +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using Mono.Cecil.Cil; + +namespace Mono.Cecil.Pdb { + + using System; + using System.Collections; + using System.Diagnostics.SymbolStore; + using System.IO; + + public class PdbWriter : Cil.ISymbolWriter { + + ModuleDefinition m_module; + ISymbolWriter m_writer; + Hashtable m_documents; + string m_pdb; + + internal PdbWriter (ISymbolWriter writer, ModuleDefinition module, string pdb) + { + m_writer = writer; + m_module = module; + m_documents = new Hashtable (); + m_pdb = pdb; + } + + public void Write (MethodBody body, byte [][] variables) + { + CreateDocuments (body); + m_writer.OpenMethod (new SymbolToken ((int) body.Method.MetadataToken.ToUInt ())); + CreateScopes (body, body.Scopes, variables); + m_writer.CloseMethod (); + } + + void CreateScopes (MethodBody body, ScopeCollection scopes, byte [][] variables) + { + 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; + + m_writer.OpenScope (startOffset); + m_writer.UsingNamespace (body.Method.DeclaringType.Namespace); + m_writer.OpenNamespace (body.Method.DeclaringType.Namespace); + + int start = body.Instructions.IndexOf (s.Start); + int end = s.End == body.Instructions.Outside ? + body.Instructions.Count - 1 : + body.Instructions.IndexOf (s.End); + + ArrayList instructions = new ArrayList(); + for (int i = start; i <= end; i++) + if (body.Instructions [i].SequencePoint != null) + instructions.Add (body.Instructions [i]); + + Document doc = null; + + 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]; + + for (int i = 0; i < instructions.Count; i++) { + Instruction instr = (Instruction) instructions [i]; + offsets [i] = instr.Offset; + + if (doc == null) + doc = instr.SequencePoint.Document; + + startRows [i] = instr.SequencePoint.StartLine; + startCols [i] = instr.SequencePoint.StartColumn; + endRows [i] = instr.SequencePoint.EndLine; + endCols [i] = instr.SequencePoint.EndColumn; + } + + m_writer.DefineSequencePoints (GetDocument (doc), + offsets, startRows, startCols, endRows, endCols); + + CreateLocalVariable (s, startOffset, endOffset, variables); + + CreateScopes (body, s.Scopes, variables); + m_writer.CloseNamespace (); + + m_writer.CloseScope (endOffset); + } + } + + void CreateLocalVariable (IVariableDefinitionProvider provider, int startOffset, int endOffset, byte [][] variables) + { + for (int i = 0; i < provider.Variables.Count; i++) { + VariableDefinition var = provider.Variables [i]; + m_writer.DefineLocalVariable ( + var.Name, + 0, + variables [i], + SymAddressKind.ILOffset, + i, + 0, + 0, + startOffset, + endOffset); + } + } + + void CreateDocuments (MethodBody body) + { + foreach (Instruction instr in body.Instructions) { + if (instr.SequencePoint == null) + continue; + + GetDocument (instr.SequencePoint.Document); + } + } + + ISymbolDocumentWriter GetDocument (Document document) + { + if (document == null) + return null; + + ISymbolDocumentWriter docWriter = m_documents [document.Url] as 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; + } + + public void Dispose () + { + m_writer.Close (); + Patch (); + } + + void Patch () + { + FileStream fs = new FileStream (m_pdb, FileMode.Open, FileAccess.ReadWrite); + uint age = m_module.Image.DebugHeader.Age; + Guid g = m_module.Image.DebugHeader.Signature; + + BinaryReader reader = new BinaryReader (fs); + reader.BaseStream.Position = 32; + + uint pageSize = reader.ReadUInt32 (); + reader.BaseStream.Position += 4; + + uint pageCount = reader.ReadUInt32 (); + reader.BaseStream.Position += pageSize - 44; + + uint magic = 0x1312e94; + int page = 0; + for (int i = 1; i < pageCount; i++) { + if (magic == reader.ReadUInt32 ()) { + page = i; + break; + } + reader.BaseStream.Position += pageSize - 4; + } + + BinaryWriter writer = new BinaryWriter (fs); + writer.BaseStream.Position = page * pageSize + 8; + + writer.Write (age); + writer.Write (g.ToByteArray ()); + + fs.Close (); + } + } +} diff --git a/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/default.build b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/default.build new file mode 100644 index 00000000000..94d81e83fbc --- /dev/null +++ b/mcs/class/Mono.Cecil/Mono.Cecil.Pdb/default.build @@ -0,0 +1,49 @@ +<?xml version="1.0"?>
+<project name="Mono.Cecil.Pdb" default="build">
+
+ <!-- allow properties to be customized in external file" -->
+ <include buildfile="build.properties" if="${file::exists('build.properties')}" />
+
+ <property name="Mono.Cecil.dll" value="../../mcs/class/Mono.Cecil/bin/Mono.Cecil.dll" />
+ <property name="build.dir" value="bin" />
+ <property name="optimize" value="false" />
+ <property name="debug" value="true" />
+ <property name="keyfile" value="../../mcs/class/mono.snk" />
+ <property name="csc.defines" value="NO_DEFINE" />
+
+ <target name="release" depends="clean, set-release, build">
+ </target>
+
+ <target name="set-release">
+ <property name="optimize" value="true" />
+ <property name="debug" value="false" />
+ </target>
+
+ <target name="build" depends="init">
+ <csc
+ target="library"
+ output="${build.dir}/Mono.Cecil.Pdb.dll"
+ debug="${debug}"
+ optimize="${optimize}"
+ keyfile="${keyfile}"
+ define="${csc.defines}">
+ <sources basedir="Mono.Cecil.Pdb">
+ <include name="**/*.cs" />
+ </sources>
+ <references basedir="${build.dir}">
+ <include name="Mono.Cecil.dll" />
+ <include name="ISymWrapper.dll" />
+ </references>
+ </csc>
+ </target>
+
+ <target name="init">
+ <mkdir dir="${build.dir}" unless="${directory::exists(build.dir)}" />
+ <copy todir="${build.dir}" file="${Mono.Cecil.dll}" />
+ </target>
+
+ <target name="clean">
+ <delete dir="${build.dir}" if="${directory::exists(build.dir)}" />
+ </target>
+
+</project>
|