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