/// <summary> /// Constructor. /// </summary> /// <param name="start">The start of the memory range.</param> /// <param name="end">The end of the memory range.</param> public MemoryRange(ulong start, ulong end) { Start = start; End = end; DebugOnly.Assert(start <= end); }
public DbgEngDataReader(string dumpFile) { if (!File.Exists(dumpFile)) { throw new FileNotFoundException(dumpFile); } DisplayName = dumpFile; IntPtr pClient = CreateIDebugClient(); CreateClient(pClient); HResult hr = _client.OpenDumpFile(dumpFile); if (hr != 0) { const int STATUS_MAPPED_FILE_SIZE_ZERO = unchecked ((int)0xC000011E); if (hr == HResult.E_INVALIDARG || hr == (STATUS_MAPPED_FILE_SIZE_ZERO | 0x10000000)) { throw new InvalidDataException($"'{dumpFile}' is not a crash dump."); } throw new ClrDiagnosticsException($"Could not load crash dump, HRESULT: {hr}", hr).AddData("DumpFile", dumpFile); } // This actually "attaches" to the crash dump. HResult result = _control.WaitForEvent(0xffffffff); _systemObjects.Init(); DebugOnly.Assert(result); }
public bool ReadDword(ulong addr, out uint value) { uint size = 4; // Is addr on the current page? If not read the page of memory addr is on. // If this fails, we will fall back to a raw read out of the process (which // is what MisalignedRead does). if (addr < _currPageStart || addr >= _currPageStart + (uint)_currPageSize) { if (!MoveToPage(addr)) { return(MisalignedRead(addr, out value)); } } // If MoveToPage succeeds, we MUST be on the right page. DebugOnly.Assert(addr >= _currPageStart); // However, the amount of data requested may fall off of the page. In that case, // fall back to MisalignedRead. ulong offset = addr - _currPageStart; if (offset + size > (uint)_currPageSize) { return(MisalignedRead(addr, out value)); } // If we reach here we know we are on the right page of memory in the cache, and // that the read won't fall off of the end of the page. value = BitConverter.ToUInt32(_data, (int)offset); return(true); }
public IEnumerable <ModuleInfo> EnumerateModules() { EnumProcessModules(_process, null, 0, out uint needed); IntPtr[] modules = new IntPtr[needed / IntPtr.Size]; if (!EnumProcessModules(_process, modules, needed, out _)) { throw new InvalidOperationException("Unable to get process modules."); } List <ModuleInfo> result = new List <ModuleInfo>(modules.Length); for (int i = 0; i < modules.Length; i++) { IntPtr ptr = modules[i]; StringBuilder sb = new StringBuilder(1024); uint res = GetModuleFileNameEx(_process, ptr, sb, sb.Capacity); DebugOnly.Assert(res != 0); ulong baseAddr = (ulong)ptr.ToInt64(); GetFileProperties(baseAddr, out int filesize, out int timestamp); string fileName = sb.ToString(); ModuleInfo module = new ModuleInfo(baseAddr, fileName, true, filesize, timestamp, ImmutableArray <byte> .Empty); result.Add(module); } return(result); }
private void Dispose(bool _) { if (!_disposed) { _suspension?.Dispose(); if (_originalPid != 0) { // We don't want to throw an exception when we fail to free a snapshot. In practice we never expect this to fail. // If we were able to create a snapshot we should be able to free it. Throwing an exception here means that our // DataTarget.Dispose call (normally at the end of a using statement) will throw, and that is really annoying // to code around. Instead we'll log a message to any Trace listener, but otherwise continue on. int hr = PssFreeSnapshot(Process.GetCurrentProcess().Handle, _snapshotHandle); DebugOnly.Assert(hr == 0); if (hr != 0) { Trace.WriteLine($"Unable to free the snapshot of the process we took: hr={hr}"); } } if (_process != IntPtr.Zero) { WindowsFunctions.NativeMethods.CloseHandle(_process); } _disposed = true; } }
private IntPtr CreateIDebugClient() { Guid guid = new Guid("27fe5639-8407-4f47-8364-ee118fb08ac8"); int hr = DebugCreate(ref guid, out IntPtr ptr); DebugOnly.Assert(hr == 0); return ptr; }
public static unsafe ulong AsPointer(this Span <byte> span) { DebugOnly.Assert(span.Length >= IntPtr.Size); DebugOnly.Assert(unchecked ((int)Unsafe.AsPointer(ref MemoryMarshal.GetReference(span))) % IntPtr.Size == 0); return(IntPtr.Size == 4 ? Unsafe.As <byte, uint>(ref MemoryMarshal.GetReference(span)) : Unsafe.As <byte, ulong>(ref MemoryMarshal.GetReference(span))); }
internal ClrValueType(ulong address, ClrType type, bool interior) { Address = address; Type = type; _interior = interior; DebugOnly.Assert(type.IsValueType); }
/// <summary> /// Constructor. /// </summary> /// <param name="address">The address of the object.</param> /// <param name="type">The concrete type of the object.</param> public ClrObject(ulong address, ClrType?type) { Address = address; Type = type; DebugOnly.Assert(address == 0 || type != null); DebugOnly.Assert(address == 0 || (type != null && type.Heap.GetObjectType(address) == type)); }
public IEnumerable <(ulong ReferencedObject, int Offset)> WalkObject(byte[] buffer, int size) { DebugOnly.Assert(size >= IntPtr.Size); int series = GetNumSeries(); int highest = GetHighestSeries(); int curr = highest; if (series > 0) { int lowest = GetLowestSeries(); do { long offset = GetSeriesOffset(curr); long stop = offset + GetSeriesSize(curr) + size; while (offset < stop) { ulong ret = new Span <byte>(buffer).AsPointer((int)offset); if (ret != 0) { yield return(ret, (int)offset); } offset += IntPtr.Size; } curr -= s_GCDescSize; } while (curr >= lowest); } else { long offset = GetSeriesOffset(curr); while (offset < size - IntPtr.Size) { for (int i = 0; i > series; i--) { int nptrs = GetPointers(curr, i); int skip = GetSkip(curr, i); long stop = offset + (nptrs * IntPtr.Size); do { ulong ret = new Span <byte>(buffer).AsPointer((int)offset); if (ret != 0) { yield return(ret, (int)offset); } offset += IntPtr.Size; } while (offset < stop); offset += skip; } } } }
public IEnumerable <(ulong, int)> WalkObject(ulong addr, ulong size, Func <ulong, ulong> readPointer) { DebugOnly.Assert(size >= (ulong)IntPtr.Size); int series = GetNumSeries(); int highest = GetHighestSeries(); int curr = highest; if (series > 0) { int lowest = GetLowestSeries(); do { ulong ptr = addr + GetSeriesOffset(curr); ulong stop = (ulong)((long)ptr + GetSeriesSize(curr) + (long)size); while (ptr < stop) { ulong ret = readPointer(ptr); if (ret != 0) { yield return(ret, (int)(ptr - addr)); } ptr += (ulong)IntPtr.Size; } curr -= s_GCDescSize; } while (curr >= lowest); } else { ulong ptr = addr + GetSeriesOffset(curr); while (ptr < addr + size - (ulong)IntPtr.Size) { for (int i = 0; i > series; i--) { uint nptrs = GetPointers(curr, i); uint skip = GetSkip(curr, i); ulong stop = ptr + (ulong)(nptrs * IntPtr.Size); do { ulong ret = readPointer(ptr); if (ret != 0) { yield return(ret, (int)(ptr - addr)); } ptr += (ulong)IntPtr.Size; } while (ptr < stop); ptr += skip; } } } }
public void GetVersionInfo(ulong addr, out VersionInfo version) { StringBuilder fileName = new StringBuilder(1024); uint res = GetModuleFileNameEx(_process, addr.AsIntPtr(), fileName, fileName.Capacity); DebugOnly.Assert(res != 0); if (DataTarget.PlatformFunctions.GetFileVersion(fileName.ToString(), out int major, out int minor, out int revision, out int patch)) { version = new VersionInfo(major, minor, revision, patch, true); }
public static ulong AsPointer(this Span <byte> span, int index = 0) { if (index != 0) { span = span.Slice(index * IntPtr.Size, IntPtr.Size); } DebugOnly.Assert(span.Length >= IntPtr.Size); return(IntPtr.Size == 4 ? MemoryMarshal.Read <uint>(span) : MemoryMarshal.Read <ulong>(span)); }
public bool Read(ulong address, Span <byte> buffer, out int bytesRead) { DebugOnly.Assert(!buffer.IsEmpty); if (address > long.MaxValue) { bytesRead = 0; return(false); } bytesRead = _core.ReadMemory((long)address, buffer); return(bytesRead > 0); }
public ClrException(IExceptionHelpers helpers, ClrThread?thread, ClrObject obj) { if (obj.IsNull) { throw new InvalidOperationException($"Cannot construct a ClrException from a null object."); } _helpers = helpers ?? throw new ArgumentNullException(nameof(helpers)); _object = obj; Thread = thread; DebugOnly.Assert(obj.IsException); }
public override int Read(ulong address, ref byte buffer, uint length) { DebugOnly.Assert(length != 0); try { fixed(byte *ptr = &buffer) { int res = ReadProcessMemory(_process, new IntPtr((nint)address), ptr, new IntPtr(length), out var read); return((int)read); } } catch (OverflowException) { return(0); } }
public bool GetVersionInfo(ulong addr, out Version version) { var fileName = new StringBuilder(1024); uint res = GetModuleFileNameEx(_process, new IntPtr((nint)addr), fileName, fileName.Capacity); DebugOnly.Assert(res != 0); if (DataTarget.PlatformFunctions.GetFileVersion(fileName.ToString(), out int major, out int minor, out int build, out int revision)) { version = new Version(major, minor, build, revision); return(true); } version = new Version(0, 0, 0, 0); return(false); }
/// <summary> /// Creates a ClrFieldReference from an actual field. /// </summary> /// <param name="reference">The object referenced.</param> /// <param name="containingType">The type of the object which points to <paramref name="reference"/>.</param> /// <param name="offset">The offset within the source object where <paramref name="reference"/> was located.</param> public static ClrReference CreateFromFieldOrArray(ClrObject reference, ClrType containingType, int offset) { if (containingType == null) { throw new ArgumentNullException(nameof(containingType)); } offset -= IntPtr.Size; DebugOnly.Assert(offset >= 0); ClrInstanceField?field = containingType.IsArray ? null : containingType.Fields.First(f => f.Offset <= offset && offset < f.Offset + f.Size); unchecked { return(new ClrReference(reference, field, OffsetFlag | (uint)offset)); } }
public override int Read(ulong address, Span <byte> buffer) { DebugOnly.Assert(!buffer.IsEmpty); try { fixed(byte *ptr = buffer) { int res = ReadProcessMemory(_process, address.AsIntPtr(), ptr, new IntPtr(buffer.Length), out IntPtr read); return((int)read); } } catch (OverflowException) { return(0); } }
public DbgEngDataReader(string dumpFile) { if (!File.Exists(dumpFile)) throw new FileNotFoundException(dumpFile); IntPtr pClient = CreateIDebugClient(); CreateClient(pClient); int hr = _client.OpenDumpFile(dumpFile); if (hr != 0) { var kind = (uint)hr == 0x80004005 ? ClrDiagnosticsExceptionKind.CorruptedFileOrUnknownFormat : ClrDiagnosticsExceptionKind.DebuggerError; throw new ClrDiagnosticsException($"Could not load crash dump, HRESULT: 0x{hr:x8}", kind, hr).AddData("DumpFile", dumpFile); } // This actually "attaches" to the crash dump. bool result = _control.WaitForEvent(0xffffffff); DebugOnly.Assert(result); }
public bool Read(ulong address, Span <byte> buffer, out int bytesRead) { DebugOnly.Assert(!buffer.IsEmpty); try { fixed(byte *ptr = buffer) { int res = ReadProcessMemory(_process, address.AsIntPtr(), ptr, new IntPtr(buffer.Length), out IntPtr read); bytesRead = (int)read; return(res != 0); } } catch { bytesRead = 0; return(false); } }
/// <summary> /// Creates a ClrFieldReference from an actual field. /// </summary> /// <param name="reference">The object referenced.</param> /// <param name="containingType">The type of the object which points to <paramref name="reference"/>.</param> /// <param name="offset">The offset within the source object where <paramref name="reference"/> was located.</param> public static ClrReference CreateFromFieldOrArray(ClrObject reference, ClrType containingType, int offset) { if (containingType == null) { throw new ArgumentNullException(nameof(containingType)); } offset -= IntPtr.Size; DebugOnly.Assert(offset >= 0); ClrInstanceField?field = null; foreach (ClrInstanceField curr in containingType.Fields) { // If we found the correct field, stop searching if (curr.Offset <= offset && offset <= curr.Offset + curr.Size) { field = curr; break; } // Sometimes .Size == 0 if we failed to properly determine the type of the field, // instead search for the field closest to the offset we are searching for. if (curr.Offset <= offset) { if (field == null) { field = curr; } else if (field.Offset < curr.Offset) { field = curr; } } } unchecked { return(new ClrReference(reference, field, OffsetFlag | (uint)offset)); } }
public IEnumerable <ModuleInfo> EnumerateModules() { EnumProcessModules(_process, null, 0, out uint needed); IntPtr[] modules = new IntPtr[needed / IntPtr.Size]; if (!EnumProcessModules(_process, modules, needed, out _)) { throw new InvalidOperationException("Unable to get process modules."); } List <ModuleInfo> result = new List <ModuleInfo>(modules.Length); for (int i = 0; i < modules.Length; i++) { IntPtr ptr = modules[i]; StringBuilder sb = new StringBuilder(1024); uint res = GetModuleFileNameEx(_process, ptr, sb, sb.Capacity); DebugOnly.Assert(res != 0); ulong baseAddr = (ulong)ptr.ToInt64(); GetFileProperties(baseAddr, out int filesize, out int timestamp); string fileName = sb.ToString(); Version?version = null; if (DataTarget.PlatformFunctions.GetFileVersion(fileName, out int major, out int minor, out int revision, out int patch)) { version = new Version(major, minor, revision, patch); } ModuleInfo module = new PEModuleInfo(this, baseAddr, fileName, true, timestamp, filesize, version); result.Add(module); } return(result); }
public IEnumerable <ModuleInfo> EnumerateModules() { List <ModuleInfo> result = new List <ModuleInfo>(); EnumProcessModules(_process, null, 0, out uint needed); IntPtr[] modules = new IntPtr[needed / 4]; uint size = (uint)modules.Length * sizeof(uint); if (!EnumProcessModules(_process, modules, size, out _)) { throw new ClrDiagnosticsException("Unable to get process modules.", ClrDiagnosticsExceptionKind.DataRequestError); } for (int i = 0; i < modules.Length; i++) { IntPtr ptr = modules[i]; if (ptr == IntPtr.Zero) { break; } StringBuilder sb = new StringBuilder(1024); uint res = GetModuleFileNameExA(_process, ptr, sb, sb.Capacity); DebugOnly.Assert(res != 0); ulong baseAddr = (ulong)ptr.ToInt64(); GetFileProperties(baseAddr, out int filesize, out int timestamp); string fileName = sb.ToString(); ModuleInfo module = new ModuleInfo(this, baseAddr, filesize, timestamp, fileName); result.Add(module); } return(result); }
private void GetFileProperties(ulong moduleBase, out int filesize, out int timestamp) { filesize = 0; timestamp = 0; Span <byte> buffer = stackalloc byte[sizeof(uint)]; if (Read(moduleBase + 0x3c, buffer) == buffer.Length) { uint sigOffset = buffer.AsUInt32(); int sigLength = 4; if (Read(moduleBase + sigOffset, buffer) == buffer.Length) { uint header = buffer.AsUInt32(); // Ensure the module contains the magic "PE" value at the offset it says it does. This check should // never fail unless we have the wrong base address for CLR. DebugOnly.Assert(header == 0x4550); if (header == 0x4550) { const int timeDataOffset = 4; const int imageSizeOffset = 0x4c; if (Read(moduleBase + sigOffset + (ulong)sigLength + timeDataOffset, buffer) == buffer.Length) { timestamp = buffer.AsInt32(); } if (Read(moduleBase + sigOffset + (ulong)sigLength + imageSizeOffset, buffer) == buffer.Length) { filesize = buffer.AsInt32(); } } } } }
public static unsafe uint AsUInt32(this Span <byte> span) { DebugOnly.Assert(span.Length >= sizeof(uint)); DebugOnly.Assert(unchecked ((int)Unsafe.AsPointer(ref MemoryMarshal.GetReference(span))) % sizeof(uint) == 0); return(Unsafe.As <byte, uint>(ref MemoryMarshal.GetReference(span))); }
public override int Read(ulong address, Span <byte> buffer) { DebugOnly.Assert(!buffer.IsEmpty); return(address > long.MaxValue ? 0 : _core.ReadMemory(address, buffer)); }
/// <summary> /// Constructs a <see cref="ClrDelegate"/> from a <see cref="ClrObject"/>. Note that obj.IsDelegate /// must be true. /// </summary> /// <param name="obj">A delegate object</param> public ClrDelegate(ClrObject obj) { DebugOnly.Assert(obj.IsDelegate); Object = obj; }
public static uint AsUInt32(this Span <byte> span) { DebugOnly.Assert(span.Length >= sizeof(uint)); return(MemoryMarshal.Read <uint>(span)); }
public static ulong AsUInt64(this Span <byte> span) { DebugOnly.Assert(span.Length >= sizeof(ulong)); return(MemoryMarshal.Read <ulong>(span)); }