2011-05-29 39 views
3

我目前正試圖從IL字節碼和PDB文件檢索源代碼, 我我趕到那裏我可以生成從IL源代碼和反射 點我知道的名字本地變量名稱包含在pdb文件中。 我的問題是我如何找回它?我應該使用什麼庫來處理pdb文件(如果有)或者我應該自己編寫代碼?我在哪裏可以找到關於pdb文件格式的信息? 當前在生成的源代碼我使用自動生成的值爲本地變量,但我想改變,因爲我相信如果您有pdb文件在您的處置可以找到該信息。 我試圖看看谷歌,但我沒有找到任何有用的信息。從PDB文件檢索局部變量名

預先感謝您的答覆;)

回答

0

看看CodePlex上,基於CCI項目。它有一個PDBReader項目。

3

下面介紹如何在System.Diagnostics.SymbolStore使用類型來讀取一個MethodInfo的局部變量名:

public class LocalVariableNameReader 
{ 
    Dictionary<int, string> _names = new Dictionary<int, string>(); 

    public string this [int index] 
    { 
     get 
     { 
      if (!_names.ContainsKey (index)) return null; 
      return _names [index]; 
     } 
    } 

    public LocalVariableNameReader (MethodInfo m) 
    { 
     ISymbolReader symReader = SymUtil.GetSymbolReaderForFile (m.DeclaringType.Assembly.Location, null); 
     ISymbolMethod met = symReader.GetMethod (new SymbolToken (m.MetadataToken)); 
     VisitLocals (met.RootScope); 
    } 

    void VisitLocals (ISymbolScope iSymbolScope) 
    { 
     foreach (var s in iSymbolScope.GetLocals()) _names [s.AddressField1] = s.Name; 
     foreach (var c in iSymbolScope.GetChildren()) VisitLocals (c); 
    } 
} 

SymUtil類來自this example

編輯:上述鏈接已損壞。從谷歌緩存:

很久以前,我一直在尋找如何才能處理PDB文件 獲得額外的信息反映根本無法提供。 現在我難倒了邁克斯托爾的一個5歲的職位 (here) 突然全部變得清晰。我已經整理了一個小例子,其中 使用.net 4.0來讀取方法主體代碼,因爲它是源代碼 ,從編譯程序集的位置開始。請注意,爲了使此 正常工作,您必須具有可用的程序集的pdb。另外 請確保你添加了一個參考ISymWrapper和您的項目 是針對.Net 4.0框架,而不是.Net 4.0客戶端。

using System; 
using System.Diagnostics.SymbolStore; 
using System.IO; 
using System.Reflection; 
using System.Runtime.InteropServices; 

namespace PdbTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Assembly ass = Assembly.GetExecutingAssembly(); 
      ISymbolReader symreader = SymUtil.GetSymbolReaderForFile(ass.Location, null); 

      MethodInfo m = ass.GetType("PdbTest.TestClass").GetMethod("GetStringRepresentation"); 
      ISymbolMethod met = symreader.GetMethod(new SymbolToken(m.MetadataToken)); 

      int count = met.SequencePointCount; 

      ISymbolDocument[] docs = new ISymbolDocument[count]; 
      int[] offsets = new int[count]; 
      int[] lines = new int[count]; 
      int[] columns = new int[count]; 
      int[] endlines = new int[count]; 
      int[] endcolumns = new int[count]; 

      met.GetSequencePoints(offsets, docs, lines, columns, endlines, endcolumns); 

      StreamReader reader = new StreamReader(docs[0].URL); 
      string[] linesOfCode = reader.ReadToEnd().Split('n'); 
      reader.Close(); 

      Console.WriteLine("The content of method PdbTest.TestClass.GetStringRepresentation"); 
      for (int i = lines[0]; i < endlines[count - 1] - 1; i++) 
      { 
       Console.WriteLine(linesOfCode[i]); 
      } 
     } 
    } 


    #region test class 

    public enum MyEnum 
    { 
     Apples, 
     Oranges 
    } 

    public partial class TestClass 
    { 
     public string GetStringRepresentation(MyEnum e) 
     { 
      MyEnum e2 = MyEnum.Apples; 
      return e.ToString() + e2.ToString(); 
     } 
    } 

    #endregion test class 

    #region Get a symbol reader for the given module 

    // Encapsulate a set of helper classes to get a symbol reader from a file. 
    // The symbol interfaces require an unmanaged metadata interface. 
    static class SymUtil 
    { 
     static class NativeMethods 
     { 
      [DllImport("ole32.dll")] 
      public 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); 
     } 

     // Wrapper. 
     public static ISymbolReader GetSymbolReaderForFile(string pathModule, string searchPath) 
     { 
      return SymUtil.GetSymbolReaderForFile(
       new System.Diagnostics.SymbolStore.SymBinder(), pathModule, searchPath); 
     } 

     // We demand Unmanaged code permissions because we're reading from the file 
     // system and calling out to the Symbol Reader 
     // @TODO - make this more specific. 
     [System.Security.Permissions.SecurityPermission(
      System.Security.Permissions.SecurityAction.Demand, 
      Flags = System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)] 
     public static ISymbolReader GetSymbolReaderForFile(
      System.Diagnostics.SymbolStore.SymBinder binder, string pathModule, string searchPath) 
     { 
      // Guids for imported metadata interfaces. 
      Guid dispenserClassID = new Guid(0xe5cb7a31, 0x7512, 0x11d2, 0x89, 
       0xce, 0x00, 0x80, 0xc7, 0x92, 0xe5, 0xd8); // CLSID_CorMetaDataDispenser 
      Guid dispenserIID = new Guid(0x809c652e, 0x7396, 0x11d2, 0x97, 0x71, 
       0x00, 0xa0, 0xc9, 0xb4, 0xd5, 0x0c); // IID_IMetaDataDispenser 
      Guid importerIID = new Guid(0x7dac8207, 0xd3ae, 0x4c75, 0x9b, 0x67, 
       0x92, 0x80, 0x1a, 0x49, 0x7d, 0x44); // IID_IMetaDataImport 

      // First create the Metadata dispenser. 
      object objDispenser; 
      NativeMethods.CoCreateInstance(ref dispenserClassID, null, 1, 
       ref dispenserIID, out objDispenser); 

      // Now open an Importer on the given filename. We'll end up passing this importer 
      // straight through to the Binder. 
      object objImporter; 
      IMetaDataDispenser dispenser = (IMetaDataDispenser)objDispenser; 
      dispenser.OpenScope(pathModule, 0, ref importerIID, out objImporter); 

      IntPtr importerPtr = IntPtr.Zero; 
      ISymbolReader reader; 
      try 
      { 
       // This will manually AddRef the underlying object, so we need to 
       // be very careful to Release it. 
       importerPtr = Marshal.GetComInterfaceForObject(objImporter, 
        typeof(IMetadataImport)); 

       reader = binder.GetReader(importerPtr, pathModule, searchPath); 
      } 
      finally 
      { 
       if (importerPtr != IntPtr.Zero) 
       { 
        Marshal.Release(importerPtr); 
       } 
      } 
      return reader; 
     } 
    } 
    #region Metadata Imports 

    // We can use reflection-only load context to use reflection to query for 
    // metadata information rather 
    // than painfully import the com-classic metadata interfaces. 
    [Guid("809c652e-7396-11d2-9771-00a0c9b4d50c"), 
     InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    [ComVisible(true)] 
    interface IMetaDataDispenser 
    { 
     // We need to be able to call OpenScope, which is the 2nd vtable slot. 
     // Thus we need this one placeholder here to occupy the first slot.. 
     void DefineScope_Placeholder(); 

     //STDMETHOD(OpenScope)(     // Return code. 
     //LPCWSTR  szScope,    // [in] The scope to open. 
     // DWORD  dwOpenFlags,   // [in] Open mode flags. 
     // REFIID  riid,     // [in] The interface desired. 
     // IUnknown **ppIUnk) PURE;   // [out] Return interface on success. 
     void OpenScope([In, MarshalAs(UnmanagedType.LPWStr)] String szScope, 
      [In] Int32 dwOpenFlags, [In] ref Guid riid, 
      [Out, MarshalAs(UnmanagedType.IUnknown)] out Object punk); 

     // Don't need any other methods. 
    } 

    // Since we're just blindly passing this interface through managed code to the Symbinder, 
    // we don't care about actually importing the specific methods. 
    // This needs to be public so that we can call Marshal.GetComInterfaceForObject() on 
    // it to get the underlying metadata pointer. 
    [Guid("7DAC8207-D3AE-4c75-9B67-92801A497D44"), 
     InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    [ComVisible(true)] 
    [CLSCompliant(true)] 
    public interface IMetadataImport 
    { 
     // Just need a single placeholder method so that it doesn't complain 
     // about an empty interface. 
     void Placeholder(); 
    } 
    #endregion 

    #endregion Get a symbol reader for the given module 
}