2009-09-01 12 views
5

私はMiniDumpWriteDump関数を使用してカスタムダンプファイルを作成したい(主に、スレッドコールストアの最小限の情報を含むダンプファイルをエクスポートしたい)が、コールバック関数にパラメータとして渡される必要がある構造コールバックでMiniDumpWriteDumpを呼び出す

[StructLayout(LayoutKind.Explicit)] 
internal struct MINIDUMP_CALLBACK_OUTPUT 
{ 
    [FieldOffset(0)] 
    public ulong ModuleWriteFlags; 
    [FieldOffset(0)] 
    public ulong ThreadWriteFlags; 
} 

public struct MINIDUMP_CALLBACK_INFORMATION 
    { 
     public IntPtr CallbackRoutine; 
     public IntPtr CallbackParam; 
    } 

public delegate bool MINIDUMP_CALLBACK_ROUTINE(
     IntPtr CallBackParam, 
     MINIDUMP_CALLBACK_INPUT input, 
     MINIDUMP_CALLBACK_OUTPUT output); 

[DllImport("dbghelp.dll")] 
public static extern bool MiniDumpWriteDump(IntPtr hProcess, Int32 ProcessId, IntPtr hFile, int DumpType, 
    IntPtr ExceptionParam, IntPtr UserStreamParam, IntPtr CallStackParam); 

、コールは次のようになります。

MINIDUMP_CALLBACK_INFORMATION mci; 
MINIDUMP_CALLBACK_ROUTINE r = new MINIDUMP_CALLBACK_ROUTINE(MyCallback); 
GC.KeepAlive(r); 
mci.CallbackRoutine = Marshal.GetFunctionPointerForDelegate(r); 
mci.CallbackParam = IntPtr.Zero;  
IntPtr structPointer = Marshal.AllocHGlobal(Marshal.SizeOf(mci));  
Marshal.StructureToPtr(mci, structPointer, true);  
MiniDumpWriteDump(process[0].Handle, process[0].Id, 
         fs.SafeFileHandle.DangerousGetHandle(), 
         (int)MINIDUMP_TYPE.MiniDumpNormal, 
         Marshal.GetExceptionPointers(), 
         IntPtr.Zero, 
         structPointer); 

Marshal.FreeHGlobal(structPointer); 

だから私の質問はMINIDUMP_CALLBACK_INPUTを定義する方法です。

問題を提起Cにおける構造体の定義は以下のとおりです。

typedef struct _MINIDUMP_CALLBACK_INPUT 
{ 
    ULONG      ProcessId; 
    HANDLE      ProcessHandle; 
    ULONG      CallbackType; 
    union 
    { 
     MINIDUMP_THREAD_CALLBACK  Thread; 
     MINIDUMP_THREAD_EX_CALLBACK  ThreadEx; 
     MINIDUMP_MODULE_CALLBACK  Module; 
     MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread; 
     MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule; 
    } u; 
} MINIDUMP_CALLBACK_INPUT 

typedef struct _MINIDUMP_MODULE_CALLBACK 
{ 
    PWCHAR      FullPath; 
    ULONGLONG     BaseOfImage; 
    ULONG      SizeOfImage; 
    ULONG      CheckSum; 
    ULONG      TimeDateStamp; 
    VS_FIXEDFILEINFO   VersionInfo; 
    PVOID      CvRecord; 
    ULONG      SizeOfCvRecord; 
    PVOID      MiscRecord; 
    ULONG      SizeOfMiscRecord; 
} MINIDUMP_MODULE_CALLBACK 

答えて

2

それはあなたの質問の直接の答えが、回避策はありません...

あなたは何をしClrDump libが知っていますか必要なの?私は数年前にそれをプロジェクトのために使ってきました。


作者コメントへの回答:サイト上

読む:

ClrDumpは内のすべてのスレッドのコールスタックを回復するのに十分な情報が含まれている小さなミニダンプを生成することができます応用。

私は以下のクラスでAPIをラップ:

internal class ClrDump 
{ 
    [return: MarshalAs(UnmanagedType.Bool)] 
    [DllImport("clrdump.dll", CharSet=CharSet.Unicode, SetLastError=true)] 
    public static extern bool CreateDump(uint ProcessId, string FileName, MINIDUMP_TYPE DumpType, uint ExcThreadId, IntPtr ExtPtrs); 

    [return: MarshalAs(UnmanagedType.Bool)] 
    [DllImport("clrdump.dll", CharSet=CharSet.Unicode, SetLastError=true)] 
    public static extern bool RegisterFilter(string FileName, MINIDUMP_TYPE DumpType); 

    [DllImport("clrdump.dll")] 
    public static extern FILTER_OPTIONS SetFilterOptions(FILTER_OPTIONS Options); 

    [return: MarshalAs(UnmanagedType.Bool)] 
    [DllImport("clrdump.dll", SetLastError=true)] 
    public static extern bool UnregisterFilter(); 


    [Flags] 
    public enum FILTER_OPTIONS 
    { 
    CLRDMP_OPT_CALLDEFAULTHANDLER = 1 
    } 

    [Flags] 
    public enum MINIDUMP_TYPE 
    { 
    MiniDumpFilterMemory = 8, 
    MiniDumpFilterModulePaths = 0x80, 
    MiniDumpNormal = 0, 
    MiniDumpScanMemory = 0x10, 
    MiniDumpWithCodeSegs = 0x2000, 
    MiniDumpWithDataSegs = 1, 
    MiniDumpWithFullMemory = 2, 
    MiniDumpWithFullMemoryInfo = 0x800, 
    MiniDumpWithHandleData = 4, 
    MiniDumpWithIndirectlyReferencedMemory = 0x40, 
    MiniDumpWithoutManagedState = 0x4000, 
    MiniDumpWithoutOptionalData = 0x400, 
    MiniDumpWithPrivateReadWriteMemory = 0x200, 
    MiniDumpWithProcessThreadData = 0x100, 
    MiniDumpWithThreadInfo = 0x1000, 
    MiniDumpWithUnloadedModules = 0x20 
    } 
} 

をしてから、どこかで私の初期化コードでは、私は、現在のプロセスで未処理の例外のための内部フィルタを登録する方法のRegisterFilterと呼ばれます。プロセスが処理されない例外(ネイティブまたは管理された例外の可能性があります)でクラッシュした場合、フィルタはそれをキャッチし、(指定されたファイル名で)ミニダンプを作成します。ここでは、このためのサンプルコードは、次のとおりです。

StringBuilder sb = new StringBuilder(); 
sb.Append(Path.GetFileNameWithoutExtension(Application.ExecutablePath)); 
sb.Append("_"); 
sb.Append(DateTime.Now.ToString("yyyyMMddHHmmssFF")); 
sb.Append(".dmp"); 
string dmpFilePath = Path.Combine(Path.GetTempPath(), sb.ToString()); 
ClrDump.RegisterFilter(_dmpFilePath, ClrDump.MINIDUMP_TYPE.MiniDumpNormal); 

さまざまMINIDUMP_TYPEオプションを理解するためにthis articleを読むことができますが、私は基本的なもの(MiniDumpNormal)は、あなたのニーズに合うことができると思います。

+0

はい、私はclrdump libにについて少し読んで、どのように私ができる私は明確ではないです私がそれで欲しいものを手に入れよう。スレッドコールスタックの情報量を最小限に抑えるにはどうすればよいですか?フィルタを使用しますか?コードサンプルを教えてください。 – anchandra

0

私はそれがあなたに困っている組合だと思っていますか?

CallbackType == KernelMinidumpStatusCallback場合、CALLBACK_INPUT構造は次のように定義される:それは、CallbackType == ThreadCallback場合

ULONG ProcessId; 
HANDLE ProcessHandle; 
ULONG CallbackType; 
HRESULT Status; 

ULONG ProcessId; 
HANDLE ProcessHandle; 
ULONG CallbackType; 
MINIDUMP_THREAD_CALLBACK Thread; 

CallbackType == ThreadExCallback場合、それ:

ULONG ProcessId; 
HANDLE ProcessHandle; 
ULONG CallbackType; 
MINIDUMP_THREAD_EX_CALLBACK ThreadEx; 

など(これはです) - 4番目のメンバーは、CallbackTypeが等しいかどうかに応じて、8つの異なるタイプのうちの1つになるように見えます。内部的には、Windowsはこれらの構造すべてに対して同じメモリチャンクを使用します(サイズの小さいものから大きなものにパディングする)。 C++では、必要な型を取得するのが簡単な型キャストです。

C#でこれを行う方法がわかりません。私はC++でMiniDumpWriteDumpを使用しましたが、コールバック関数は使用しませんでした。 CallbackTypeが常に1つの値であることを確認できれば、その構造体をコーディングできますが、これが当てはまるかどうかはわかりません。

申し訳ありませんより多くの情報を提供することはできませんが、これは問題の説明に役立ちます。 32ビットで組合と構造を定義する

+0

はい、私はユニオン部分を定義する際に問題があります。残念ながら、特定のコールバックタイプのためだけに構造体を定義することはできません。なぜならそれらのすべてが呼び出されるからです。とにかくありがとう – anchandra

+1

C#で構造体を使用してC構造体を移植する唯一の方法は、LayoutKind.ExplicitオプションでStructLayoutAttributeを使用し、各フィールドのオフセットをFieldOffsetAttributeで明示的に書き込むことです。別の答えに例を挙げます。 – cedrou

0

使用このコード:

[StructLayout(LayoutKind.Explicit)] 
internal struct MINIDUMP_CALLBACK_INPUT 
{ 
    [FieldOffset(0)] 
    UInt32 ProcessId; 

    [FieldOffset(4)] 
    IntPtr ProcessHandle; 

    [FieldOffset(8)] 
    UInt32 CallbackType; 

    [FieldOffset(12)] 
    MINIDUMP_THREAD_CALLBACK Thread; 
    [FieldOffset(12)] 
    MINIDUMP_THREAD_EX_CALLBACK ThreadEx; 
    [FieldOffset(12)] 
    MINIDUMP_MODULE_CALLBACK Module; 
    [FieldOffset(12)] 
    MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread; 
    [FieldOffset(12)] 
    MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule; 
}; 

Iが64ビットプラットフォーム上で、オフセットはそれぞれ{0、8、16、24}または{0であるべきだと思います、4,12,16} ULONGが64または32ビットであるかどうか。


編集

私はあなたが、具体的フィールドを変換するためにMarshalAsAttributeを使用することができると思う:

[StructLayout(LayoutKind.Sequential)] 
    struct VS_FIXEDFILEINFO 
    { 
    UInt32 dwSignature; 
    UInt32 dwStrucVersion; 
    UInt32 dwFileVersionMS; 
    UInt32 dwFileVersionLS; 
    UInt32 dwProductVersionMS; 
    UInt32 dwProductVersionLS; 
    UInt32 dwFileFlagsMask; 
    UInt32 dwFileFlags; 
    UInt32 dwFileOS; 
    UInt32 dwFileType; 
    UInt32 dwFileSubtype; 
    UInt32 dwFileDateMS; 
    UInt32 dwFileDateLS; 
    } 

    [StructLayout (LayoutKind.Sequential)] 
    struct MINIDUMP_MODULE_CALLBACK 
    { 
    [MarshalAs(UnmanagedType.LPWStr)] 
    String      FullPath; 
    UInt64      BaseOfImage; 
    UInt32      SizeOfImage; 
    UInt32      CheckSum; 
    UInt32      TimeDateStamp; 
    VS_FIXEDFILEINFO   VersionInfo; 
    IntPtr      CvRecord; 
    UInt32      SizeOfCvRecord; 
    IntPtr      MiscRecord; 
    UInt32      SizeOfMiscRecord; 
    } 
+0

ULONGはWin64でも32ビットです。 –

+0

MINIDUMP_MODULE_CALLBACKは構造体そのものであり、PWCHARを含むので、それほど簡単ではありません。どのように定義するのですか? – anchandra

関連する問題