Effective minidump (b)

Function MiniDumpCallback

If you want to customize the type of content MINIDUMP sign inaccessible MINIDUMP, you can use MiniDumpCallback function. This is a user-defined callback when MiniDumpWriteDump requires the user to decide whether or not to include certain data to the minidump, it will be called. With this feature, we can accomplish the following tasks:

  • Negative executable module (wholly or partially) from the module information in the minidump
  • Negative thread (wholly or partially) from the thread information minidump
  • The user-specified range of memory contents included in the mini-dump

Let us look at the function declaration MiniDumpCallback

BOOL CALLBACK MiniDumpCallback(
  PVOID CallbackParam, 
  const PMINIDUMP_CALLBACK_INPUT CallbackInput, 
  PMINIDUMP_CALLBACK_OUTPUT CallbackOutput
);

Function takes three parameters. The first parameter ( CallbackParam ) is a user-defined context callback function (e.g., point C ++ object pointer). The second parameter (CallbackInput) comprising MiniDumpWriteDump passed to the callback data. The third parameter (CallbackOutput) comprising call back return to MiniDumpWriteDump data (typically the data to be specified in the information contained in the minidump).

Now let's look at what MINIDUMP_CALLBACK_INPUT and MINIDUMP_CALLBACK_OUTPUT structure

typedef struct _MINIDUMP_CALLBACK_INPUT {
    ULONG ProcessId;
    HANDLE ProcessHandle;
    ULONG CallbackType;
    union {
        HRESULT Status;
        MINIDUMP_THREAD_CALLBACK Thread;
        MINIDUMP_THREAD_EX_CALLBACK ThreadEx;
        MINIDUMP_MODULE_CALLBACK Module;
        MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread;
        MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule;
    };
} MINIDUMP_CALLBACK_INPUT, *PMINIDUMP_CALLBACK_INPUT;

typedef struct _MINIDUMP_CALLBACK_OUTPUT {
    union {
        ULONG ModuleWriteFlags;
        ULONG ThreadWriteFlags;
        struct {
            ULONG64 MemoryBase;
            ULONG MemorySize;
        };
        struct {
            BOOL CheckCancel;
            BOOL Cancel;
        };
        HANDLE Handle;
    };
} MINIDUMP_CALLBACK_OUTPUT, *PMINIDUMP_CALLBACK_OUTPUT;

typedef enum _MINIDUMP_CALLBACK_TYPE {
    ModuleCallback,
    ThreadCallback,
    ThreadExCallback,
    IncludeThreadCallback,
    IncludeModuleCallback,
    MemoryCallback,
    CancelCallback,
    WriteKernelMinidumpCallback,
    KernelMinidumpStatusCallback,
} MINIDUMP_CALLBACK_TYPE;

MiniDumpWriteDump formulate a request for a callback function by MINIDUMP_CALLBACK_INPUT structure. The first two members of the meaning is obvious - they contain the id and handle to create a mini dump process. The third member (callback type) contains the type of request, naturally called the callback type. CallbackType all possible values ​​are collected in MINIDUMP_CALLBACK_TYPE enumeration, we will soon them more in-depth study. It is the fourth member of the structure union, whose meaning varies depending on the value of CallbackType. United MiniDumpWriteDump contain other data related to the request.

MINIDUMP_CALLBACK_OUTPUT slightly simpler structure. It is composed of a union, union explanations also depends MINIDUMP_CALLBACK_INPUT.CallbackType value. Union members included MiniDumpWriteDump callback response to the request.
Now is the most important browse list request (by the callback type identifier) and see how to respond to their callback time. But before we begin, consider the following code, which shows the problem of how to tell MiniDumpWriteDump --- user-defined callback function and should be called.
void CreateMiniDump( EXCEPTION_POINTERS* pep ) 
{
  // Open the file 

  HANDLE hFile = CreateFile( _T("MiniDump.dmp"), GENERIC_READ | GENERIC_WRITE, 
    0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); 

  if( ( hFile != NULL ) && ( hFile != INVALID_HANDLE_VALUE ) ) 
  {
    // Create the minidump 

    MINIDUMP_EXCEPTION_INFORMATION mdei; 

    mdei.ThreadId           = GetCurrentThreadId(); 
    mdei.ExceptionPointers  = pep; 
    mdei.ClientPointers     = FALSE; 

    MINIDUMP_CALLBACK_INFORMATION mci; 

    mci.CallbackRoutine     = (MINIDUMP_CALLBACK_ROUTINE)MyMiniDumpCallback; 
    mci.CallbackParam       = 0;     // this example does not use the context

    MINIDUMP_TYPE mdt       = MiniDumpNormal; 

    BOOL rv = MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(), 
      hFile, mdt, (pep != 0) ? &mdei : 0, 0, &mci ); 

    if( !rv ) 
      _tprintf( _T("MiniDumpWriteDump failed. Error: %u \n"), GetLastError() ); 
    else 
      _tprintf( _T("Minidump created.\n") ); 

    // Close the file 

    CloseHandle( hFile ); 

  }
  else 
  {
    _tprintf( _T("CreateFile failed. Error: %u \n"), GetLastError() ); 
  }

}

BOOL CALLBACK MyMiniDumpCallback(
  PVOID                            pParam, 
  const PMINIDUMP_CALLBACK_INPUT   pInput, 
  PMINIDUMP_CALLBACK_OUTPUT        pOutput 
) 
{
    // Callback implementation 
    …
}

Under the following talk MINIDUMP_CALLBACK_TYPE enumeration:

  • IncludeModuleCallback
    When the callback type is set to IncludeModuleCallback, MiniDumpWriteDump should be asked whether the callback information about a particular executable module contained in the minidump. Callback make decisions based on the content MINIDUMP_CALLBACK_INPUT structure, union members interpreted as MINIDUMP_INCLUDE_MODULE_ CALLBACK :
    typedef struct _MINIDUMP_INCLUDE_MODULE_CALLBACK {
        ULONG64 BaseOfImage;
    } MINIDUMP_INCLUDE_MODULE_CALLBACK, *PMINIDUMP_INCLUDE_MODULE_CALLBACK;

    Here, BaseOfImage is the base address of the memory modules, which can be used to obtain more information about the module, and decide whether to use it in a small dump. The callback function uses its return value will be passed decisions to MiniDumpWriteDump. If the callback returns TRUE, the information about the module will be included in the minidump (you can further customize the exact content of this information in a subsequent call to the callback function). If the callback returns FALSE, the information about the module will be discarded, and will not be seen in the presence of traces of MIDIDUMP the module. MINIDUMP_CALLBACK_OUTPUT structure not used for this type of callback.

  • ModuleCallback
    When a module and survive the test by IncludeModuleCallback it when entering the mini dump will face another obstacle. This obstacle is ModuleCallback, where the callback function can decide what types of information should be included modules. This time, the callback function's return value must be TRUE (so that MiniDumpWriteDump continue), MINIDUMP_CALLBACK_OUTPUT used to determine the structure passed to the callback MiniDumpWriteDump. The union structure is interpreted as beneficial ModuleWriteFlags member, the member contains a set of flags by the MiniDumpWriteDump initialized. The flags indicate the information may comprise various modules in MIDIDUMP, and the current is collected in the presence of a flag MODULE_WRITE_FLAGS enumeration.
    typedef enum _MODULE_WRITE_FLAGS {
        ModuleWriteModule        = 0x0001,
        ModuleWriteDataSeg       = 0x0002,
        ModuleWriteMiscRecord    = 0x0004,
        ModuleWriteCvRecord      = 0x0008,
        ModuleReferencedByMemory = 0x0010,
        ModuleWriteTlsData       = 0x0020,
        ModuleWriteCodeSegs      = 0x0040,
    } MODULE_WRITE_FLAGS;

    When MiniDumpWriteDump use ModuleCallback type of callback callback function, it will set some flag that tells the callback module which types of information can be included in the minidump. The callback function can analyze these flags and decided to clear some of them (or even all), and then tell MiniDumpWriteDump what types of information should not be included. The following table lists the flag currently available, and describes the type of information that they represent:

    Note, ModuleCallback only allow us to exclude certain parts of the module information, but not allowed to add new data. This means that if the mark is not set by MiniDumpWriteDump, set in the callback function it has no effect. For example, if we do not MiniDumpWithDataSegs flag to MiniDumpWriteDump, it will not set ModuleWriteDataSeg flag to any module. Then, even if the callback function module will set ModuleWriteDataSeg flag content module data section will not be included in the mini-dump.
    After the contents MINIDUMP_CALLBACK_OUTPUT structure of an exploration carried out so long, let's focus on MINIDUMP_CALLBACK_INPUT. Interestingly, this union is interpreted as MINIDUMP_MODULE_CALLBACK structure that contains a rich set of information (such as name and path, size, version information) for modules, as follows:

    typedef struct _MINIDUMP_MODULE_CALLBACK {
        PWCHAR FullPath;
        ULONG64 BaseOfImage;
        ULONG SizeOfImage;
        ULONG CheckSum;
        ULONG TimeDateStamp;
        VS_FIXEDFILEINFO VersionInfo;
        PVOID CvRecord; 
        ULONG SizeOfCvRecord;
        PVOID MiscRecord;
        ULONG SizeOfMiscRecord;
    } MINIDUMP_MODULE_CALLBACK, *PMINIDUMP_MODULE_CALLBACK;
  •  IncludeThreadCallback
    this type of action callback module for the same role and IncludeModuleCallback thread, it gives us the opportunity to decide whether it should be included in the information on the thread of the minidump. And IncludeModuleCallback as the callback function should return TRUE to include information about the thread to the mini-dump, or return FALSE to completely discard this information. Threads can be identified by its system identifier that is stored in the union MINIDUMP_CALLBACK_INPUT, as follows:
    typedef struct _MINIDUMP_INCLUDE_THREAD_CALLBACK {
        ULONG ThreadId;
    } MINIDUMP_INCLUDE_THREAD_CALLBACK, *PMINIDUMP_INCLUDE_THREAD_CALLBACK;

    MINIDUMP_CALLBACK_OUTPUT structure is not used.

  • ThreadCallback
    this type of action callback module for the same role and ModuleCallback thread, the basic principles of the two types of callback behind the same. MINIDUMP_CALLBACK_OUTPUT structure is interpreted as a union set of flags (ThreadWriteFlags), wherein the callback function can remove the part (or all) of the negative thread portion of a corresponding information from the MINIDUMP.
    It provides a wealth of information about the thread in MINIDUMP_CALLBACK_INPUT structure in which the joint is interpreted as MINIDUMP_THREAD_CALLBACK. The boundary information includes a thread identifier and a handle, and a thread context of the thread stacks. The callback function must return TRUE to make MiniDumpWriteDump continue.
    typedef struct _MINIDUMP_THREAD_CALLBACK {
        ULONG ThreadId;
        HANDLE ThreadHandle;
        CONTEXT Context;
        ULONG SizeOfContext;
        ULONG64 StackBase;
        ULONG64 StackEnd;
    } MINIDUMP_THREAD_CALLBACK, *PMINIDUMP_THREAD_CALLBACK;

    The following table lists the most important sign, and describes the type of information they represent

  • MemoryCallback
    Sometimes we want to keep some content to the additional memory region that contains a small dump. For example, if we are allocated on the heap some data (or only through VirtualAlloc), and we want to see these data when debugging mini dump. We can do it in MemoryCallback callback type of help, MiniDumpWriteDump calls the callback type after using the callback type collection thread and module information. When used as a callback type MemoryCallback callback function, MINIDUMP_CALLBACK_OUTPUT union structure is interpreted as:
    struct {
      ULONG64 MemoryBase; 
      ULONG MemorySize;
    };

    If the callback function member of this structure is filled with the address and size of the readable memory block and returns TRUE, then the contents of the memory block is stored in the mini dump. A plurality of blocks can be specified, because if the callback function returns TRUE, it will be invoked again (using, of course MemoryCallback callback type). MiniDumpWriteDump only after it returns FALSE will stop calling the callback function.

  • CancelCallback
    This callback type (call on a regular basis by the MiniDumpWriteDump) allows you to cancel the process of creating minidump, which is very useful GUI applications. MINIDUMP_CALLBACK_OUTPUT structure is interpreted as a union of two values: Cancel and CheckCancel:
    struct {
        BOOL CheckCancel;
        BOOL Cancel;
    };

    If you want to create a mini-dump completely cancel, cancel should be set to TRUE. If we do not want to cancel, but hope to receive CancelCallback callback, then CheckCancel should be set to TRUE. If two members are set to FALSE, MiniDumpWriteDump will no longer call CancelCallback type of callback callback function. Callback function should return TRUE to confirm that the value set in MINIDUMP_CALLBACK_OUTPUT structure.

Callback order

After we discussed the callback type, it can be very interesting to see MiniDumpWriteDump order to use them:

  • IncludeThreadCallback - once during each thread
  • IncludeModuleCallback - during each of the first executable module
  • ModuleCallback - each module to perform a non-excluded IncludeModuleCallback
  • ThreadCallback - each thread of execution once IncludeThreadCallback not excluded
  • MemoryCallback is to call one or more times, until the callback function returns FALSE

In addition, the use of cancelcallback type on a regular basis in between other types of callbacks, so that you can cancel the mini dump creation process if necessary.

MiniDump Wizard

You can use MiniDump wizard application MiniDump to try a variety of options, and see how they affect MiniDump size and content. Minidumps wizard can create a mini-dump any process, you can also simulate an exception for small and create mini-dump dump wizard itself. You can choose which mini-dump pass type flag to minidumps writedump function, and response callback request in a series of dialog.
After you create a mini-dump, load it into the debugger and check the type of information available. You can also use MiniDumpView application to obtain a list of various information minidump available.

User data stream

Although MiniDumpWriteDump capture application debugging is critical to the success of the state, but we often need additional information about the application operating environment. For example, view the contents of the configuration file or check the registry application-specific settings may be useful. MiniDumpWriteDump allows us to use this information as an additional data stream included in minidump.

MINIDUMP_USER_STREAM_INFORMATION we should state variable of type pointer and filled with its contents and the number of points the user data stream flow array. Each user data stream is described by MINIDUMP_USER_STREAM structure, which comprises a stream type (stream which serves as a unique identifier, and must be greater than LastReservedStream constant), the size and orientation of the pointer data stream. Structure shown below.

typedef struct _MINIDUMP_USER_STREAM_INFORMATION {
    ULONG UserStreamCount;
    PMINIDUMP_USER_STREAM UserStreamArray;
} MINIDUMP_USER_STREAM_INFORMATION, *PMINIDUMP_USER_STREAM_INFORMATION;

typedef struct _MINIDUMP_USER_STREAM {
    ULONG32 Type;
    ULONG BufferSize;
    PVOID Buffer;
} MINIDUMP_USER_STREAM, *PMINIDUMP_USER_STREAM;

After the user data stream to the minidump, it can be read by means of MiniDumpReadDumpStream function.

Tactics

MiniDumpWriteDump feature-rich and a large number of available options makes it difficult to choose a variety of applications are equally effective strategy. In each particular case, the application developer must decide which option is useful for debugging their mission. Here I will try to describe some basic strategies, demonstrate how to apply the knowledge MiniDumpWriteDump configuration options in the actual scene. We will study used four different methods MiniDumpWriteDump data collection, and see how they affect the size and the possibility of effective minidump debugging.

TinyDump

This is actually not a real scene. Instead, the method may comprise displaying a minimum in a small set of possible data dump, at least slightly so as to be useful. MiniDumpWriteDump configuration options are summarized in the table below.

 

If you try to load the dump into WinDbg or small VS.NET debugger, you will see the debugger can not load it. But the mini-dump is not completely useless, because it still contains information about the exception. We can read this information manually (using MiniDumpReadDumpStream function), and view the address exception occurs, thread context, exception code when an exception occurs, even disassembly. You can use MiniDumpView tool to display this information (except for disassembly, to keep it simple).

MiniDump

And TinyDump, this approach can be used in the actual scene to collect enough debugging information, and still keep the minimum size of the dump as small as possible. The following table describes the MiniDumpWriteDump configuration options.

 

The sample application can be found here. Generated minidump still small (on my system is between 40-50 kilobytes), but it is definitely more than minidump using standard methods (MiniDumpNormal + no MiniDumpCallback) created more informative, because it allows you to view from the stack referenced data. As optimize the size, we exclude all modules that are not referenced from thread stack dump from small (on my system, excluding the following modules -advapi32.dll and rpcrt4.dll). But still they lack important information. For example, we can not see the value of a global variable, can not check the data allocated in the heap and TLS (unless it is quoted from the thread's stack).

MidiDump

This method will generate a very large amount of information the mini-dump, its size will remain away from becoming huge. The following table describes this configuration.

On my system, the size of the mini-dump about 1350 kilobytes. When it is loaded into the debugger, we can get almost all the information about the application, including the values of global variables, stack and TLS, PEB, TEBs content. We can even get a handle information and check the virtual memory layout. A very useful garbage dump, in fact, it is not too much, because we are still concerned about the size of it - does not include the following information:

  • All modules of code segment (because if we can get the module itself, you do not need them)
  • Some modules of the data segment (we only for those who really want to see us in the debugger global variable module contains the data segment)

MaxiDump

Create a mini dump contains all possible information sets. The following table shows how to achieve this.

 

Even for a simple application, a mini dump is great. But it gives us access to all possible information that may be contained in a small landfills.

Guess you like

Origin www.cnblogs.com/yilang/p/11897664.html