private MemoryAnalyzer(DataTarget dataTarget) { // TODO: Exit gracefully for memory dumps from different platforms m_dataTarget = dataTarget; string dacLocation = m_dataTarget.ClrVersions[0].TryGetDacLocation(); if (String.IsNullOrEmpty(dacLocation)) throw new ArgumentException("Cannot find DAC location for process"); m_runtime = m_dataTarget.CreateRuntime(dacLocation); m_heap = m_runtime.GetHeap(); }
internal List<UnifiedBlockingObject> GetManagedBlockingObjects(ClrThread thread, List<UnifiedStackFrame> unmanagedStack, ClrRuntime runtime) { List<UnifiedBlockingObject> result = new List<UnifiedBlockingObject>(); if (thread.BlockingObjects?.Count > 0) { foreach (var item in thread.BlockingObjects) { result.Add(new UnifiedBlockingObject(item)); } } CheckForCriticalSections(result, unmanagedStack, runtime); foreach (var frame in unmanagedStack) { if (frame?.Handles?.Count > 0) { foreach (var handle in frame.Handles) { result.Add(new UnifiedBlockingObject(handle.Id, handle.ObjectName, handle.Type)); } } } return result; }
private ProcessAnalyzer(DataTarget dataTarget, ClrRuntime runtime) { _debugClient = dataTarget.DebuggerInterface; _dataReader = dataTarget.DataReader; _runtime = runtime; _globalConfig = Config.GetInstance(); _isDisposed = false; }
public override async Task<List<UnifiedBlockingObject>> GetUnmanagedBlockingObjects(ThreadInfo thread, List<UnifiedStackFrame> unmanagedStack, ClrRuntime runtime) { return await Task<List<UnifiedBlockingObject>>.Run(() => { ThreadWCTInfo wct_threadInfo = _wctApi.GetBlockingObjects(thread.OSThreadId); return _unmanagedBlockingObjectsHandler.GetUnmanagedBlockingObjects(wct_threadInfo, unmanagedStack); }); }
internal void CheckForCriticalSections(List<UnifiedBlockingObject> list, List<UnifiedStackFrame> stack, ClrRuntime runtime) { var criticalSectionObjects = GetCriticalSectionBlockingObjects(stack, runtime); if (criticalSectionObjects.Any()) { if (list == null) list = new List<UnifiedBlockingObject>(); list.AddRange(criticalSectionObjects); } }
public ClrMDSession(DataTarget target, ClrRuntime runtime) { ClrMDSession.Detach(); Target = target; Runtime = runtime; Heap = Runtime.GetHeap(); m_allObjects = new Lazy<List<ClrObject>>(() => Heap.EnumerateClrObjects().ToList()); s_currentSession = this; }
private static bool InitApi(IntPtr ptrClient) { // On our first call to the API: // 1. Store a copy of IDebugClient in DebugClient. // 2. Replace Console's output stream to be the debugger window. // 3. Create an instance of DataTarget using the IDebugClient. if (DebugClient == null) { object client = Marshal.GetUniqueObjectForIUnknown(ptrClient); DebugClient = (IDebugClient)client; var stream = new StreamWriter(new DbgEngStream(DebugClient)); stream.AutoFlush = true; Console.SetOut(stream); DataTarget = Microsoft.Diagnostics.Runtime.DataTarget.CreateFromDebuggerInterface(DebugClient); } // If our ClrRuntime instance is null, it means that this is our first call, or // that the dac wasn't loaded on any previous call. Find the dac loaded in the // process (the user must use .cordll), then construct our runtime from it. if (Runtime == null) { // Just find a module named mscordacwks and assume it's the one the user // loaded into windbg. Process p = Process.GetCurrentProcess(); foreach (ProcessModule module in p.Modules) { if (module.FileName.ToLower().Contains("mscordacwks")) { // TODO: This does not support side-by-side CLRs. Runtime = DataTarget.ClrVersions.Single().CreateRuntime(module.FileName); break; } } // Otherwise, the user didn't run .cordll. if (Runtime == null) { Console.WriteLine("Mscordacwks.dll not loaded into the debugger."); Console.WriteLine("Run .cordll to load the dac before running this command."); } } else { // If we already had a runtime, flush it for this use. This is ONLY required // for a live process or iDNA trace. If you use the IDebug* apis to detect // that we are debugging a crash dump you may skip this call for better perf. Runtime.Flush(); } return Runtime != null; }
public virtual IEnumerable<UnifiedBlockingObject> GetCriticalSectionBlockingObjects(List<UnifiedStackFrame> unmanagedStack, ClrRuntime runtime) { foreach (var item in unmanagedStack) { UnifiedBlockingObject blockObject; if (_unmanagedStackWalkerStrategy.GetCriticalSectionBlockingObject(item, runtime, out blockObject)) { yield return blockObject; } } }
public ClrHeapDecorator(ClrRuntime clrRuntime, ThreadDispatcher threadDispatcher) { _threadDispatcher = threadDispatcher; _clrHeap = threadDispatcher.Process(() => clrRuntime.GetHeap()); _threadDispatcher.Process(()=> { objectIndex = IndexBuilder.Build(_clrHeap); GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; }); }
private static IEnumerable<ThreadAndStack> GetManagedStacks(ClrRuntime runtime) { var allStacks = from thread in runtime.Threads let frames = from frame in thread.StackTrace where frame.Kind == ClrStackFrameType.ManagedMethod select String.Format("{0}!{1}", frame.ModuleName, frame.Method) select new ThreadAndStack { ManagedThreadId = thread.ManagedThreadId, Stack = frames.Reverse().ToList() }; return allStacks.ToList(); }
private static IEnumerable<TypeHeapStat> GetHeapStatsByTypeForObjectSet(ClrRuntime clrRuntime, IEnumerable<ulong> objectIdSet) { ClrHeap heap = clrRuntime.GetHeap(); return from oid in objectIdSet let ot = heap.GetObjectType(oid) group oid by ot into objectTypeGroup let otSize = objectTypeGroup.Sum(oid => (uint)objectTypeGroup.Key.GetSize(oid)) select new TypeHeapStat { TypeName = objectTypeGroup.Key.Name, TotalHeapSize = otSize, NumberOfInstances = objectTypeGroup.Count() }; }
internal bool GetCriticalSectionBlockingObject(UnifiedStackFrame frame, ClrRuntime runtime, out UnifiedBlockingObject blockingObject) { bool result = false; if (frame.Handles != null && frame.Method.Contains(ENTER_CRITICAL_SECTION_FUNCTION_NAME)) { blockingObject = GetCriticalSectionBlockingObject(frame, runtime); result = blockingObject != null; } else { blockingObject = null; } return result; }
public BlockingObjectsStrategy( ClrRuntime runtime, UnifiedStackTraces unifiedStackTraces = null, DataTarget dataTarget = null) { _runtime = runtime; _unifiedStackTraces = unifiedStackTraces; _dataTarget = dataTarget; if (_dataTarget != null) { if (_dataTarget.Architecture == Architecture.X86) { _stackWalker = new StackWalkerStrategy_x86(_runtime); } _dataReader = _dataTarget.DataReader; _debugClient = _dataTarget.DebuggerInterface; } }
public DumpAnalyzer(string dumpPath) { _target = DataTarget.LoadCrashDump(dumpPath); _target.SymbolLocator.SymbolPath = Environment.GetEnvironmentVariable("_NT_SYMBOL_PATH"); if (_target.Architecture == Architecture.Amd64 && !Environment.Is64BitProcess) { throw new ApplicationException("Architecture doesn't match. Run this with X64 version."); } if (_target.ClrVersions.Count > 0) { ClrInfo dacVersion = _target.ClrVersions[0]; _runtime = dacVersion.CreateRuntime(); // CreateRuntime() tries to find the DAC on disk and then consults // the symbol server if necessary. If all fails, it throws an exception. } }
public ProcessQuerierStrategy(IDebugClient debugClient, IDataReader dataReader, ClrRuntime runtime) { _isDispsed = false; _runtime = runtime; _dataReader = dataReader; _debugClient = debugClient; if (dataReader.GetArchitecture() == Architecture.Amd64)//Environment.Is64BitProcess { _unmanagedStackWalkerStrategy = new Unmanaged_x64_StackWalkerStrategy(_runtime); _threadContextStrategy = new ThreadContext_x64_Strategy(); } else { _unmanagedStackWalkerStrategy = new Unmanaged_x86_StackWalkerStrategy(); _threadContextStrategy = new ThreadContext_x86_Strategy(); } _unmanagedBlockingObjectsHandler = new UnmanagedBlockingObjectsHandler(_unmanagedStackWalkerStrategy); }
internal List<UnifiedStackFrame> ConvertToUnified(IEnumerable<DEBUG_STACK_FRAME> stackFrames, ClrRuntime runtime, IDebugClient debugClient, ThreadInfo info, uint pid = Constants.INVALID_PID) { bool waitFound = false; var reversed = stackFrames.Reverse(); List<UnifiedStackFrame> stackTrace = new List<UnifiedStackFrame>(); foreach (var frame in reversed) { var unified_frame = new UnifiedStackFrame(frame, (IDebugSymbols2)debugClient); unified_frame.ThreadContext = info.ContextStruct; if (!waitFound) { waitFound = Inpsect(unified_frame, runtime, pid); } stackTrace.Add(unified_frame); } return stackTrace; }
private void TouchOtherRegions(DumpReaderLogger readerLogger, ClrRuntime runtime) { // Touch all threads, stacks, frames foreach (var t in runtime.Threads) { foreach (var f in t.StackTrace) { try { f.GetFileAndLineNumber(); } catch (Exception) { } } } // Touch all modules runtime.EnumerateModules().Count(); // Touch all heap regions, roots, types var heap = runtime.GetHeap(); heap.EnumerateRoots(enumerateStatics: false).Count(); heap.EnumerateTypes().Count(); // TODO Check if it's faster to construct sorted inside ReaderWrapper foreach (var kvp in readerLogger.Ranges) _otherClrRegions.Add(kvp.Key, kvp.Value); }
internal List<UnifiedBlockingObject> GetUnmanagedBlockingObjects(ThreadInfo thread, List<UnifiedStackFrame> unmanagedStack, ClrRuntime runtime, List<MiniDumpHandle> DumpHandles) { List<UnifiedBlockingObject> result = new List<UnifiedBlockingObject>(); result.AddRange(GetUnmanagedBlockingObjects(unmanagedStack)); foreach (var item in DumpHandles) { result.Add(new UnifiedBlockingObject(item)); } CheckForCriticalSections(result, unmanagedStack, runtime); return result; }
public virtual List<UnifiedBlockingObject> GetManagedBlockingObjects(ClrThread thread, List<UnifiedStackFrame> unmanagedStack, ClrRuntime runtime) { return _unmanagedBlockingObjectsHandler.GetManagedBlockingObjects(thread, unmanagedStack, runtime); }
public virtual IEnumerable<UnifiedBlockingObject> GetCriticalSectionBlockingObjects(List<UnifiedStackFrame> unmanagedStack, ClrRuntime runtime) { return _unmanagedBlockingObjectsHandler.GetCriticalSectionBlockingObjects(unmanagedStack, runtime); }
public List<UnifiedStackFrame> ConvertToUnified(IEnumerable<DEBUG_STACK_FRAME> stackFrames, ClrRuntime runtime, ThreadInfo info, uint pID) { var result = _unmanagedStackWalkerStrategy.ConvertToUnified(stackFrames, runtime, _debugClient, info, pID); return result; }
public abstract Task<List<UnifiedBlockingObject>> GetUnmanagedBlockingObjects(ThreadInfo thread, List<UnifiedStackFrame> unmanagedStack, ClrRuntime runtime);
/// <summary> /// Original Function call example: /// void WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); /// </summary> protected override UnifiedBlockingObject GetCriticalSectionBlockingObject(UnifiedStackFrame frame, ClrRuntime runtime) { UnifiedBlockingObject result = null; var paramz = Strategy.GetEnterCriticalSectionParam(frame); result = new UnifiedBlockingObject(paramz.First, UnifiedBlockingType.CriticalSectionObject); return result; }
/// <summary> /// Original Function call example: /// DWORD WINAPI WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds); /// </summary> protected override void DealWithSingle(UnifiedStackFrame frame, ClrRuntime runtime, uint pid) { var paramz = Strategy.GetWaitForSingleObjectParams(frame); EnrichUnifiedStackFrame(frame, paramz.First, pid); }
/// <summary> /// Original Function call example: /// DWORD WaitForMultipleObjects(DWORD nCount,HANDLE* lpHandles,BOOL bWaitAll,DWORD dwMilliseconds); /// </summary> protected override void DealWithMultiple(UnifiedStackFrame frame, ClrRuntime runtime, uint pid) { var paramz = Strategy.GetWaitForMultipleObjectsParams(frame); EnrichUnifiedStackFrame(frame, runtime, pid, paramz.First, paramz.Second); }
/// <summary> /// Original Function call example: /// void WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); /// </summary> protected override void DealWithCriticalSection(UnifiedStackFrame frame, ClrRuntime runtime, uint pid) { var paramz = Strategy.GetEnterCriticalSectionParam(frame); EnrichUnifiedStackFrame(frame, paramz.First, pid); }
public Unmanaged_x64_StackWalkerStrategy(ClrRuntime runtime) { _globalConfigs = Config.GetInstance(); _runtime = runtime; }
/// <summary> /// See https://github.com/goldshtn/msos/commit/705d3758d15835d2520b31fcf3028353bdbca73b#commitcomment-12499813 /// and https://github.com/Microsoft/dotnetsamples/blob/master/Microsoft.Diagnostics.Runtime/CLRMD/ClrMemDiag/Debugger/IDebugControl.cs#L126-L156 /// </summary> private void PrintAssemblyCode(ClrMethod method, IList<ILToNativeMap> ilMaps, ClrRuntime runtime, IDebugControl debugControl) { // This is the first instruction of the JIT'ed (or NGEN'ed) machine code. ulong startAddress = ilMaps.Select(entry => entry.StartAddress).Min(); // Unfortunately there's not a great way to get the size of the code, or the end address. // You are supposed to do code flow analysis like "uf" in windbg to find the size, but // in practice you can use the IL to native mapping: ulong endAddress = ilMaps.Select(entry => entry.EndAddress).Max(); var bufferSize = 500; // per-line var lineOfAssembly = new StringBuilder(bufferSize); ulong startOffset = startAddress, endOffset; uint disassemblySize; do { var flags = DEBUG_DISASM.EFFECTIVE_ADDRESS; var result = debugControl.Disassemble(startOffset, flags, lineOfAssembly, bufferSize, out disassemblySize, out endOffset); startOffset = endOffset; logger?.Write(lineOfAssembly.ToString()); if (lineOfAssembly.ToString().Contains(" call ") == false) continue; var methodCallInfo = GetCalledMethodFromAssemblyOutput(runtime, lineOfAssembly.ToString()); if (string.IsNullOrWhiteSpace(methodCallInfo) == false) logger?.WriteLine(LogKind.Info, $" {methodCallInfo}"); } while (disassemblySize > 0 && endOffset <= endAddress); logger?.WriteLine(); }
private string GetCalledMethodFromAssemblyOutput(ClrRuntime runtime, string assemblyString) { string hexAddressText = ""; var callLocation = assemblyString.LastIndexOf("call"); var qwordPtrLocation = assemblyString.IndexOf("qword ptr"); var openBracket = assemblyString.IndexOf('('); var closeBracket = assemblyString.IndexOf(')'); if (openBracket != -1 && closeBracket != -1 && closeBracket > openBracket) { // 000007fe`979171fb e800261b5e call mscorlib_ni+0x499800 (000007fe`f5ac9800) hexAddressText = assemblyString.Substring(openBracket, closeBracket - openBracket) .Replace("(", "") .Replace(")", "") .Replace("`", ""); } else if (callLocation != -1 && qwordPtrLocation != -1) { // TODO have to also deal with: // 000007fe`979f666f 41ff13 call qword ptr [r11] ds:000007fe`978e0050=000007fe978ed260 } else if (callLocation != -1) { // 000007fe`979e6721 e8e2b5ffff call 000007fe`979e1d08 var endOfCallLocation = callLocation + 4; hexAddressText = assemblyString.Substring(endOfCallLocation, assemblyString.Length - endOfCallLocation) .Replace("`", "") .Trim(' '); } ulong actualAddress; if (ulong.TryParse(hexAddressText, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out actualAddress)) { ClrMethod method = runtime.GetMethodByAddress(actualAddress); if (method != null) { return $"Call: {method.GetFullSignature()}"; } else return $"Call: {actualAddress:x16} -> No matching method found"; } return $"\"{hexAddressText}\" -> Not a valid hex value"; }
private void PrintRuntimeDiagnosticInfo(DataTarget dataTarget, ClrRuntime runtime) { logger?.WriteLine(LogKind.Header, "\nRuntime Diagnostic Information"); logger?.WriteLine(LogKind.Header, "------------------------------"); logger?.WriteLine(LogKind.Header, "\nDataTarget Info:"); logger?.WriteLine(LogKind.Info, " ClrVersion{0}: {1}", dataTarget.ClrVersions.Count > 1 ? "s" : "", string.Join(", ", dataTarget.ClrVersions)); logger?.WriteLine(LogKind.Info, " Architecture: " + dataTarget.Architecture); logger?.WriteLine(LogKind.Info, " PointerSize: {0} ({1}-bit)", dataTarget.PointerSize, dataTarget.PointerSize == 8 ? 64 : 32); logger?.WriteLine(LogKind.Info, " SymbolPath: " + dataTarget.GetSymbolPath()); logger?.WriteLine(LogKind.Header, "\nClrRuntime Info:"); logger?.WriteLine(LogKind.Info, " ServerGC: " + runtime.ServerGC); logger?.WriteLine(LogKind.Info, " HeapCount: " + runtime.HeapCount); logger?.WriteLine(LogKind.Info, " Thread Count: " + runtime.Threads.Count); logger?.WriteLine(LogKind.Header, "\nClrRuntime Modules:"); foreach (var module in runtime.EnumerateModules()) { logger?.WriteLine(LogKind.Info, " {0,36} Id:{1} - {2,10:N0} bytes @ 0x{3:X16}", Path.GetFileName(module.FileName), module.AssemblyId.ToString().PadRight(10), module.Size, module.ImageBase); } ClrHeap heap = runtime.GetHeap(); logger?.WriteLine(LogKind.Header, "\nClrHeap Info:"); logger?.WriteLine(LogKind.Info, " TotalHeapSize: {0:N0} bytes ({1:N2} MB)", heap.TotalHeapSize, heap.TotalHeapSize / 1024.0 / 1024.0); logger?.WriteLine(LogKind.Info, " Gen0: {0,10:N0} bytes", heap.GetSizeByGen(0)); logger?.WriteLine(LogKind.Info, " Gen1: {0,10:N0} bytes", heap.GetSizeByGen(1)); logger?.WriteLine(LogKind.Info, " Gen2: {0,10:N0} bytes", heap.GetSizeByGen(2)); logger?.WriteLine(LogKind.Info, " LOH: {0,10:N0} bytes", heap.GetSizeByGen(3)); logger?.WriteLine(LogKind.Info, " Segments: " + heap.Segments.Count); foreach (var segment in heap.Segments) { logger?.WriteLine(LogKind.Info, " Segment: {0,10:N0} bytes, {1,10}, Gen0: {2,10:N0} bytes, Gen1: {3,10:N0} bytes, Gen2: {4,10:N0} bytes", segment.Length, segment.IsLarge ? "Large" : (segment.IsEphemeral ? "Ephemeral" : "Unknown"), segment.Gen0Length, segment.Gen1Length, segment.Gen2Length); } logger?.WriteLine(); }