2009-09-01 15 views
5

Chcę użyć funkcji MiniDumpWriteDump do utworzenia niestandardowych plików zrzutu (głównie chcę wyeksportować plik zrzutu, który zawiera minimalną ilość informacji dla blokad wątków), ale mam trudności z określeniem struktury, które muszą być przekazane jako parametr do funkcji zwrotnejZadzwoń do MiniDumpWriteDump z funkcją oddzwaniania

[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); 

I wywołanie wygląda tak:

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); 

Więc moje pytanie brzmi: w jaki sposób zdefiniować MINIDUMP_CALLBACK_INPUT:

Definicja struktury w języku C, które stwarzają problemy to:

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 

Odpowiedz

2

Nie jest to bezpośrednia odpowiedź na swoje pytanie, ale obejście ...

Znasz ClrDump lib, który robi to, co potrzebujesz? Używałem go do projektu kilka lat temu i działa mi dobrze.


odpowiedzi do autora komentarza:

przeczytać na stronie:

ClrDump może produkować małe minizrzuty które zawierają wystarczającą ilość informacji, aby odzyskać stosy wezwanie wszystkich wątków w podanie.

ja owinięty API w poniższej klasy:

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 
    } 
} 

a potem, gdzieś w moim kodzie inicjującym, zadzwoniłem do RegisterFilter metoda, która rejestruje filtra wewnętrznego nieobsłużonych wyjątków w obecnym procesie. Jeśli proces ulega awarii z nieobsługiwanym wyjątkiem (może to być wyjątek natywny lub zarządzany), filtr przechwytuje go i tworzy minizrzutu (o podanej nazwie pliku). Oto przykładowy kod do tego:

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); 

Możesz przeczytać this article zrozumieć różne opcje MINIDUMP_TYPE, ale myślę, że jeden podstawowy (MiniDumpNormal) mogłyby pasować do Twoich potrzeb.

+0

Tak, czytałem trochę o clrdump lib, ale nie jestem jasne, jak mogę zdobądź to, co chcę z tym. Jak mogę uzyskać minimalną ilość informacji dla pakietów zwrotnych wątku? Używasz filtrów? Czy możesz dać mi próbkę kodu? – anchandra

0

Uważam, że to związek daje ci kłopoty?

Jeśli CallbackType == KernelMinidumpStatusCallback, wówczas struktura CALLBACK_INPUT jest zdefiniowany jako:

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

Jeśli CallbackType == ThreadCallback, to jest:

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

Jeśli CallbackType == ThreadExCallback, to jest:

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

I tak dalej (jest to od MSDN) - wygląda na to, że czwarty element może być jednym z 8 różnych typów, w zależności od tego, jaki jest typ CallbackType.Wewnętrznie system Windows użyje tego samego kawałka pamięci dla wszystkich tych struktur (wypełniając mniejsze do największego rozmiaru). W C++ jest to łatwy typecast, aby uzyskać odpowiedni typ.

Nie jestem pewien, jak to zrobić w języku C#. Użyłem MiniDumpWriteDump w C++, ale nigdy nie użyłem funkcji wywołania zwrotnego. Jeśli możesz być pewien, że CallbackType był zawsze jedną wartością, możesz po prostu zakodować tę jedną strukturę, ale nie wiem, czy tak jest.

Niestety, nie mogę podać więcej informacji, ale może to pomoże w opisaniu problemu.

+0

Tak, mam problemy definiujące część związkową. Niestety, nie mogę zdefiniować struktury tylko dla jednego konkretnego typu wywołania, ponieważ wszystkie zostaną wywołane. Mimo to dziękuję – anchandra

+1

Jedynym sposobem na portowanie w strukturze C# a C ze złączem jest użycie opcji StructLayoutAttribute z opcją LayoutKind.Explicit i wyraźne zapisanie przesunięcia każdego pola za pomocą FieldOffsetAttribute. Podam przykład w innej odpowiedzi. – cedrou

0

wykorzystania tego do określenia struktury oraz związki w 32 bitów:

[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; 
}; 

ja że na platformie 64 bitów, przesunięcia powinny być odpowiednio {0, 8, 16, 24} lub {0 , 4, 12, 16} czy ULONG ma 64 lub 32 bity.


Edit

myślę, że można użyć MarshalAsAttribute specjalnie przekonwertować pola:

[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 ma również 32 bity na Win64. –

+0

To nie jest takie proste, ponieważ MINIDUMP_MODULE_CALLBACK jest samą strukturą zawierającą PWCHAR. Jak to zdefiniujesz? – anchandra

Powiązane problemy