public void WritePdb(SymbolData symData) { m_docWriters = new Dictionary<int, ISymbolDocumentWriter>(); ImageDebugDirectory debugDirectory; byte[] debugInfo = null; // Rather than use the emitter here, we are just careful enough to emit pdb metadata that // matches what is already in the assembly image. object emitter = null; // We must be careful to close the writer before updating the debug headers. The writer has an // open file handle on the assembly we want to update. m_writer = SymbolAccess.GetWriterForFile(m_symFormat, m_outputAssembly, ref emitter); // We don't actually need the emitter in managed code at all, so release the CLR reference on it Marshal.FinalReleaseComObject(emitter); try { WriteEntryPoint(symData.entryPointToken); WriteFiles(symData.sourceFiles); WriteMethods(symData.methods); debugInfo = m_writer.GetDebugInfo(out debugDirectory); } finally { m_writer.Close(); ((IDisposable)m_writer).Dispose(); m_writer = null; m_docWriters.Clear(); } UpdatePEDebugHeaders(debugInfo); }
public void WritePdb(SymbolData symData) { m_docWriters = new Dictionary <int, ISymbolDocumentWriter>(); ImageDebugDirectory debugDirectory; byte[] debugInfo = null; // Rather than use the emitter here, we are just careful enough to emit pdb metadata that // matches what is already in the assembly image. object emitter = null; // We must be careful to close the writer before updating the debug headers. The writer has an // open file handle on the assembly we want to update. m_writer = SymbolAccess.GetWriterForFile(m_symFormat, m_outputAssembly, ref emitter); // We don't actually need the emitter in managed code at all, so release the CLR reference on it Marshal.FinalReleaseComObject(emitter); try { WriteEntryPoint(symData.entryPointToken); WriteFiles(symData.sourceFiles); WriteMethods(symData.methods); debugInfo = m_writer.GetDebugInfo(out debugDirectory); } finally { m_writer.Close(); ((IDisposable)m_writer).Dispose(); m_writer = null; m_docWriters.Clear(); } UpdatePEDebugHeaders(debugInfo); }
/* * This function (UpdatePEDebugHeaders) represents a bit of a hack. * * When a debugger attempts to find debug information (pdb) * for an image file (dll or exe), it uses a data-blob in the * image file to decide if the debug info "matches" this version. * * Modifying the pdb without updating the image file would cause * a debugger to not load this new pdb due to mismatched information. * * In most situations when somebody emits debug info, they are also * emitting metadata and an assembly, so they can just include the * results of ISymUnmanagedWriter.GetDebugInfo in that new image file. * * The intent of this sample is to demonstrate managed symbol reading * and writing without too much extra stuff. For this reason, I didn't * include a full implementation of PEFile manipulation because it's * not really the point of this sample. The code that does the PE File * manipulation was thrown together to get a specific job done and not * to be a good demonstration of how a compiler should deal with this. * Managed data structures to mirror the native format would be a better * approach if you needed more functionality out of the PEFile class. */ private void UpdatePEDebugHeaders() { if (File.Exists(m_outputAssembly)) { ImageDebugDirectory DebugDirectory; byte[] DebugInfo = m_writer.GetDebugInfo(out DebugDirectory); var file = new PEFile(m_outputAssembly); file.UpdateHeader(DebugInfo); } else { Console.WriteLine("Warning: Assembly couldn't be found to update."); Console.WriteLine("New pdb won't \"match\" any assembly and will thus not be useful to a debugger."); } }
/// <summary> /// Gets the <see cref="IMAGE_DEBUG_DIRECTORY"/> and debug data that should be written to /// the PE file. /// </summary> /// <param name="idd">Updated with new values</param> /// <returns>Debug data</returns> public byte[] GetDebugInfo(out IMAGE_DEBUG_DIRECTORY idd) { return(writer.GetDebugInfo(out idd)); }