PDBファイルへのアクセス。

GotDotNetを見ていたら、DIA(Debug Interface Access SDK)というキーワードが紹介されていました。うーむ、これ使うとPDBから情報引っこ抜けるのか・・・知らなかったです。と、いうことで、C#で簡単なサンプルをこさえてみました。

// ConsoleApp.cs

using System;
using Dia2Lib;

// 今回は使用していない
public enum NameSearchOptions : uint {
  nsNone  = 0,
  nsfCaseSensitive  = 0x1,
  nsfCaseInsensitive  = 0x2,
  nsfFNameExt  = 0x4,
  nsfRegularExpression  = 0x8,
  nsfUndecoratedName  = 0x10,
  nsCaseSensitive  = nsfCaseSensitive,
  nsCaseInsensitive  = nsfCaseInsensitive,
  nsFNameExt  = nsfCaseInsensitive | nsfFNameExt,
  nsRegularExpression  = nsfRegularExpression | nsfCaseSensitive,
  nsCaseInRegularExpression  = nsfRegularExpression | nsfCaseInsensitive
}

public class ConsoleApp {

  public void SayHello() {
    Console.WriteLine("Hello World.");
  }

  static void GetSourcePosition(IDiaSession session, IDiaSymbol symbol) 
  {
    if (symbol.addressSection != 0 && symbol.length > 0) {
      IDiaEnumLineNumbers lineNums;
      session.findLinesByAddr(symbol.addressSection, 
        (uint)symbol.addressOffset, (uint)symbol.length, out lineNums);
      if (lineNums != null) {
        uint celt;
        IDiaLineNumber lineNum;
        lineNums.Next(1, out lineNum, out celt);
        if (celt != 1)
          return;
        // メソッド名:ソースファイル(行番号)を出力
        Console.WriteLine("Method:{0} - {1}({2})", 
          symbol.name, lineNum.sourceFile.fileName, lineNum.lineNumber);
      }

    }
  }

  [STAThread]
  static void Main(string[] args) {
    if (args.Length != 1) {
      Console.WriteLine("usage app.exe pdbfile");
      return;
    }

    DiaSourceClass dia = new DiaSourceClass();
    // pdbファイルを読み込む
    dia.loadDataFromPdb(args[0]);
    IDiaSession session;
    dia.openSession(out session);

    IDiaSymbol symbol = session.globalScope;
    uint id = symbol.symIndexId;
    if (id == 0) {
      return;
    }

    IDiaEnumTables tabs;
    session.getEnumTables(out tabs);
    IDiaTable symtab = tabs.Item(0);
    foreach (IDiaSymbol s in symtab) {
      // メソッドのみを対象とする
      if (s.symTag == (uint)SymTagEnum.SymTagFunction) {
        GetSourcePosition(session, s);
      }
    }
  }
}

/* 結果
Method:SayHello - c:\home\projects\consoleapp\consoleapp.cs(24)
Method:GetSourcePosition - c:\home\projects\consoleapp\consoleapp.cs(29)
Method:Main - c:\home\projects\consoleapp\consoleapp.cs(49) */

自分自身のPDBファイルを食わせた結果ですが、メソッドのソースファイル上での位置が取ってこれています。もっと色々出来そうですが、ちょっと疲れたのでこの辺で。

symbol.addressOffsetを渡すところをsymbol.offsetにしていて1時間くらい嵌っていました。(^^;