private void FilterVMRegion(ref MINIDUMP_CALLBACK_OUTPUT CallbackOutput)
        {
            if (_dumpType != DumpType.FullMemoryExcludingSafeRegions)
            {
                // No further callbacks of this type are required.
                CallbackOutput.MemoryInfo.Continue = false;
                return;
            }
            _logger.WriteLine("\tWrite VM region @ {0:x16} size {1} {2} {3} {4}",
                              CallbackOutput.MemoryInfo.VmRegion.BaseAddress,
                              CallbackOutput.MemoryInfo.VmRegion.RegionSize,
                              CallbackOutput.MemoryInfo.VmRegion.State,
                              CallbackOutput.MemoryInfo.VmRegion.Type,
                              CallbackOutput.MemoryInfo.VmRegion.Protect);

            // NOTE We can further filter because we don't necessarily need the whole
            // region. We can find the maximum overlapping needed region that is contained
            // within this region, and change the BaseAddress and RegionSize fields to
            // capture only that sub-region.
            if (!IsNeededRegion(
                    CallbackOutput.MemoryInfo.VmRegion.BaseAddress,
                    CallbackOutput.MemoryInfo.VmRegion.BaseAddress + CallbackOutput.MemoryInfo.VmRegion.RegionSize)
                )
            {
                // We do not need this region.
                _logger.WriteLine("\tRegion EXCLUDED from dump");
                CallbackOutput.MemoryInfo.VmRegion.RegionSize = 0;
            }

            // If the region size or base address are modified (as long as they remain a
            // subset of the original region), that's what the dump will contain.
            CallbackOutput.MemoryInfo.Continue = true;
        }
Exemple #2
0
        private void FilterVMRegion(ref MINIDUMP_CALLBACK_OUTPUT CallbackOutput)
        {
            if (_dumpType != DumpType.FullMemoryExcludingSafeRegions)
            {
                // No further callbacks of this type are required.
                CallbackOutput.MemoryInfo.Continue = false;
                return;
            }
            _logger.WriteLine("\tWrite VM region @ {0:x16} size {1} {2} {3} {4}",
                CallbackOutput.MemoryInfo.VmRegion.BaseAddress,
                CallbackOutput.MemoryInfo.VmRegion.RegionSize,
                CallbackOutput.MemoryInfo.VmRegion.State,
                CallbackOutput.MemoryInfo.VmRegion.Type,
                CallbackOutput.MemoryInfo.VmRegion.Protect);

            // NOTE We can further filter because we don't necessarily need the whole
            // region. We can find the maximum overlapping needed region that is contained
            // within this region, and change the BaseAddress and RegionSize fields to
            // capture only that sub-region.
            if (!IsNeededRegion(
                CallbackOutput.MemoryInfo.VmRegion.BaseAddress,
                CallbackOutput.MemoryInfo.VmRegion.BaseAddress + CallbackOutput.MemoryInfo.VmRegion.RegionSize)
                )
            {
                // We do not need this region.
                _logger.WriteLine("\tRegion EXCLUDED from dump");
                CallbackOutput.MemoryInfo.VmRegion.RegionSize = 0;
            }

            // If the region size or base address are modified (as long as they remain a
            // subset of the original region), that's what the dump will contain.
            CallbackOutput.MemoryInfo.Continue = true;
        }
        private bool CallbackRoutine(
            IntPtr CallbackParam,
            ref MINIDUMP_CALLBACK_INPUT CallbackInput,
            ref MINIDUMP_CALLBACK_OUTPUT CallbackOutput
            )
        {
            _logger.WriteLine("Callback type: " + CallbackInput.CallbackType);

            if ((int)CallbackInput.CallbackType < 0 ||
                (int)CallbackInput.CallbackType > (int)MINIDUMP_CALLBACK_TYPE.SecondaryFlagsCallback)
            {
                // We don't know what these numbers mean. They aren't in the SDK headers,
                // but we are getting them when the dump generation begins (16, 17).
                _logger.WriteLine("\tThis callback type is not recognized");
                return(false);
            }

            switch (CallbackInput.CallbackType)
            {
            // I/O callbacks
            case MINIDUMP_CALLBACK_TYPE.IoWriteAllCallback:
                _logger.WriteLine("\tIOWriteAll: offset = {0:x8} buffer = {1:x16} size = {2:x8}",
                                  CallbackInput.Io.Offset, CallbackInput.Io.Buffer, CallbackInput.Io.BufferBytes);
                var segment = new DumpedSegment
                {
                    Offset = CallbackInput.Io.Offset,
                    Data   = new byte[CallbackInput.Io.BufferBytes]
                };
                Marshal.Copy(CallbackInput.Io.Buffer, segment.Data, 0, segment.Data.Length);
                _dumpedSegments.Add(segment);
                CallbackOutput.Status = 0;
                break;

            case MINIDUMP_CALLBACK_TYPE.IoFinishCallback:
                _logger.WriteLine("\tIOFinish");
                _dumpedSegments.CompleteAdding();
                CallbackOutput.Status = 0;
                break;

            case MINIDUMP_CALLBACK_TYPE.IoStartCallback:
                _logger.WriteLine("\tIOStart: handle = {0}", CallbackInput.Io.Handle);
                if (_spillSegmentsAsynchronously)
                {
                    // Providing S_FALSE (1) as the status here instructs dbghelp to send all
                    // I/O through the callback (IoWriteAllCallback).
                    CallbackOutput.Status = 1;
                    _segmentSpillingTask  = Task.Factory.StartNew(SpillDumpSegmentsToDisk, TaskCreationOptions.LongRunning);
                }
                else
                {
                    CallbackOutput.Status = 0;
                }
                if (_needMemoryCallbacks)
                {
                    DetermineNeededRegions();
                }
                break;

            // Cancel callback
            case MINIDUMP_CALLBACK_TYPE.CancelCallback:
                _logger.WriteLine("\tCancel callback invoked, asking for no further cancel checks");
                CallbackOutput.Cancel.CheckCancel = false;
                CallbackOutput.Cancel.Cancel      = false;
                break;

            // Thread callbacks
            case MINIDUMP_CALLBACK_TYPE.IncludeThreadCallback:
                _logger.WriteLine("\tDefault include thread flags for thread {0} = {1}",
                                  CallbackInput.IncludeThread.ThreadId,
                                  CallbackOutput.ThreadWriteFlags);
                break;

            case MINIDUMP_CALLBACK_TYPE.ThreadCallback:
            case MINIDUMP_CALLBACK_TYPE.ThreadExCallback:
                _logger.WriteLine("\tWriting thread {0} handle {1:x} stack {2:x16} - {3:x16}",
                                  CallbackInput.Thread.ThreadId, CallbackInput.Thread.ThreadHandle,
                                  CallbackInput.Thread.StackBase, CallbackInput.Thread.StackEnd);
                break;

            default:
                break;

            // Module callbacks
            case MINIDUMP_CALLBACK_TYPE.IncludeModuleCallback:
                _logger.WriteLine("\tDefault include module flags for module @ {0:x16} = {1}",
                                  CallbackInput.IncludeModule.BaseOfImage,
                                  CallbackOutput.ModuleWriteFlags);
                break;

            case MINIDUMP_CALLBACK_TYPE.ModuleCallback:
                string moduleName = Marshal.PtrToStringUni(CallbackInput.Module.FullPath);
                _logger.WriteLine("\tWriting module @ {0:x16} {1}",
                                  CallbackInput.Module.BaseOfImage,
                                  moduleName);
                break;

            // Memory callbacks
            case MINIDUMP_CALLBACK_TYPE.MemoryCallback:
                if (!_needMemoryCallbacks)
                {
                    break;
                }
                if (_regionEnumerator == null)
                {
                    _regionEnumerator = EnumerateAllNeededRegions().GetEnumerator();
                }
                if (_regionEnumerator.MoveNext())
                {
                    var region = _regionEnumerator.Current;
                    CallbackOutput.Memory.MemoryBase = region.Key;
                    CallbackOutput.Memory.MemorySize = (uint)(region.Value - region.Key);
                }
                _logger.WriteLine("\tRequesting memory region @ {0:x16} size {1}",
                                  CallbackOutput.Memory.MemoryBase,
                                  CallbackOutput.Memory.MemorySize);
                // If this callback produces a non-zero value, it will be included in the
                // dump and the callback will be invoked again. This is only relevant when
                // not capturing a full memory dump.
                break;

            case MINIDUMP_CALLBACK_TYPE.IncludeVmRegionCallback:
                if (!_needMemoryCallbacks)
                {
                    break;
                }
                FilterVMRegion(ref CallbackOutput);
                break;

            // Other callbacks
            case MINIDUMP_CALLBACK_TYPE.KernelMinidumpStatusCallback:
            case MINIDUMP_CALLBACK_TYPE.WriteKernelMinidumpCallback:
            case MINIDUMP_CALLBACK_TYPE.SecondaryFlagsCallback:
            case MINIDUMP_CALLBACK_TYPE.RemoveMemoryCallback:
                break;

            // Memory error callback
            case MINIDUMP_CALLBACK_TYPE.ReadMemoryFailureCallback:
                _logger.WriteLine("\tFailed to read memory @ {0} size {1} error {2:x8}",
                                  CallbackInput.ReadMemoryFailure.Offset,
                                  CallbackInput.ReadMemoryFailure.Bytes,
                                  CallbackInput.ReadMemoryFailure.FailureStatus);
                break;
            }

            return(true);
        }
Exemple #4
0
        private bool CallbackRoutine(
            IntPtr CallbackParam,
            ref MINIDUMP_CALLBACK_INPUT CallbackInput,
            ref MINIDUMP_CALLBACK_OUTPUT CallbackOutput
            )
        {
            _logger.WriteLine("Callback type: " + CallbackInput.CallbackType);

            if ((int)CallbackInput.CallbackType < 0 ||
                (int)CallbackInput.CallbackType > (int)MINIDUMP_CALLBACK_TYPE.SecondaryFlagsCallback)
            {
                // We don't know what these numbers mean. They aren't in the SDK headers,
                // but we are getting them when the dump generation begins (16, 17).
                _logger.WriteLine("\tThis callback type is not recognized");
                return false;
            }

            switch (CallbackInput.CallbackType)
            {
                // I/O callbacks
                case MINIDUMP_CALLBACK_TYPE.IoWriteAllCallback:
                    _logger.WriteLine("\tIOWriteAll: offset = {0:x8} buffer = {1:x16} size = {2:x8}",
                        CallbackInput.Io.Offset, CallbackInput.Io.Buffer, CallbackInput.Io.BufferBytes);
                    var segment = new DumpedSegment
                    {
                        Offset = CallbackInput.Io.Offset,
                        Data = new byte[CallbackInput.Io.BufferBytes]
                    };
                    Marshal.Copy(CallbackInput.Io.Buffer, segment.Data, 0, segment.Data.Length);
                    _dumpedSegments.Add(segment);
                    CallbackOutput.Status = 0;
                    break;
                case MINIDUMP_CALLBACK_TYPE.IoFinishCallback:
                    _logger.WriteLine("\tIOFinish");
                    _dumpedSegments.CompleteAdding();
                    CallbackOutput.Status = 0;
                    break;
                case MINIDUMP_CALLBACK_TYPE.IoStartCallback:
                    _logger.WriteLine("\tIOStart: handle = {0}", CallbackInput.Io.Handle);
                    if (_spillSegmentsAsynchronously)
                    {
                        // Providing S_FALSE (1) as the status here instructs dbghelp to send all
                        // I/O through the callback (IoWriteAllCallback).
                        CallbackOutput.Status = 1;
                        _segmentSpillingTask = Task.Factory.StartNew(SpillDumpSegmentsToDisk, TaskCreationOptions.LongRunning);
                    }
                    else
                    {
                        CallbackOutput.Status = 0;
                    }
                    if (_needMemoryCallbacks)
                    {
                        DetermineNeededRegions();
                    }
                    break;

                // Cancel callback
                case MINIDUMP_CALLBACK_TYPE.CancelCallback:
                    _logger.WriteLine("\tCancel callback invoked, asking for no further cancel checks");
                    CallbackOutput.Cancel.CheckCancel = false;
                    CallbackOutput.Cancel.Cancel = false;
                    break;

                // Thread callbacks
                case MINIDUMP_CALLBACK_TYPE.IncludeThreadCallback:
                    _logger.WriteLine("\tDefault include thread flags for thread {0} = {1}",
                        CallbackInput.IncludeThread.ThreadId,
                        CallbackOutput.ThreadWriteFlags);
                    break;
                case MINIDUMP_CALLBACK_TYPE.ThreadCallback:
                case MINIDUMP_CALLBACK_TYPE.ThreadExCallback:
                    _logger.WriteLine("\tWriting thread {0} handle {1:x} stack {2:x16} - {3:x16}",
                        CallbackInput.Thread.ThreadId, CallbackInput.Thread.ThreadHandle,
                        CallbackInput.Thread.StackBase, CallbackInput.Thread.StackEnd);
                    break;
                default:
                    break;

                // Module callbacks
                case MINIDUMP_CALLBACK_TYPE.IncludeModuleCallback:
                    _logger.WriteLine("\tDefault include module flags for module @ {0:x16} = {1}",
                        CallbackInput.IncludeModule.BaseOfImage,
                        CallbackOutput.ModuleWriteFlags);
                    break;
                case MINIDUMP_CALLBACK_TYPE.ModuleCallback:
                    string moduleName = Marshal.PtrToStringUni(CallbackInput.Module.FullPath);
                    _logger.WriteLine("\tWriting module @ {0:x16} {1}",
                        CallbackInput.Module.BaseOfImage,
                        moduleName);
                    break;

                // Memory callbacks
                case MINIDUMP_CALLBACK_TYPE.MemoryCallback:
                    if (!_needMemoryCallbacks)
                        break;
                    if (_regionEnumerator == null)
                    {
                        _regionEnumerator = EnumerateAllNeededRegions().GetEnumerator();
                    }
                    if (_regionEnumerator.MoveNext())
                    {
                        var region = _regionEnumerator.Current;
                        CallbackOutput.Memory.MemoryBase = region.Key;
                        CallbackOutput.Memory.MemorySize = (uint)(region.Value - region.Key);
                    }
                    _logger.WriteLine("\tRequesting memory region @ {0:x16} size {1}",
                        CallbackOutput.Memory.MemoryBase,
                        CallbackOutput.Memory.MemorySize);
                    // If this callback produces a non-zero value, it will be included in the
                    // dump and the callback will be invoked again. This is only relevant when
                    // not capturing a full memory dump.
                    break;
                case MINIDUMP_CALLBACK_TYPE.IncludeVmRegionCallback:
                    if (!_needMemoryCallbacks)
                        break;
                    FilterVMRegion(ref CallbackOutput);
                    break;

                // Other callbacks
                case MINIDUMP_CALLBACK_TYPE.KernelMinidumpStatusCallback:
                case MINIDUMP_CALLBACK_TYPE.WriteKernelMinidumpCallback:
                case MINIDUMP_CALLBACK_TYPE.SecondaryFlagsCallback:
                case MINIDUMP_CALLBACK_TYPE.RemoveMemoryCallback:
                    break;

                // Memory error callback
                case MINIDUMP_CALLBACK_TYPE.ReadMemoryFailureCallback:
                    _logger.WriteLine("\tFailed to read memory @ {0} size {1} error {2:x8}",
                        CallbackInput.ReadMemoryFailure.Offset,
                        CallbackInput.ReadMemoryFailure.Bytes,
                        CallbackInput.ReadMemoryFailure.FailureStatus);
                    break;
            }

            return true;
        }