private static ThreadInfo GetThreadInfo(ClrThread thread, DataTarget dataTarget, ClrRuntime runtime, StringBuilder sb, bool includeStackObjects) { var hasStackTrace = thread.StackTrace.Count > 0; var threadInfo = new ThreadInfo { OSThreadId = thread.OSThreadId, ManagedThreadId = thread.ManagedThreadId, IsNative = hasStackTrace == false, ThreadType = thread.IsGC ? ThreadType.GC : thread.IsFinalizer ? ThreadType.Finalizer : hasStackTrace == false ? ThreadType.Native : ThreadType.Other }; if (hasStackTrace) { foreach (var frame in thread.StackTrace) { if (frame.DisplayString.Equals("GCFrame", StringComparison.OrdinalIgnoreCase) || frame.DisplayString.Equals("DebuggerU2MCatchHandlerFrame", StringComparison.OrdinalIgnoreCase)) { continue; } threadInfo.StackTrace.Add(frame.DisplayString); } } else if (dataTarget.DebuggerInterface != null) { var control = (IDebugControl)dataTarget.DebuggerInterface; var sysObjs = (IDebugSystemObjects)dataTarget.DebuggerInterface; var nativeFrames = new DEBUG_STACK_FRAME[100]; var sybSymbols = (IDebugSymbols)dataTarget.DebuggerInterface; threadInfo.IsNative = true; sysObjs.SetCurrentThreadId(threadInfo.OSThreadId); control.GetStackTrace(0, 0, 0, nativeFrames, 100, out var frameCount); for (var i = 0; i < frameCount; i++) { sb.Clear(); sybSymbols.GetNameByOffset(nativeFrames[i].InstructionOffset, sb, sb.Capacity, out _, out _); threadInfo.StackTrace.Add(sb.ToString()); } } if (includeStackObjects) { threadInfo.StackObjects = GetStackObjects(runtime, thread); } return(threadInfo); }
private static void ShowStackTrace(int processId, uint attachTimeout, string outputPath) { if (processId == -1) { throw new InvalidOperationException("Uninitialized process id parameter"); } var threadInfoList = new List <ThreadInfo>(); using (DataTarget dataTarget = DataTarget.AttachToProcess(processId, attachTimeout)) { var clrInfo = dataTarget.ClrVersions[0]; var runtime = clrInfo.CreateRuntime(); var control = (IDebugControl)dataTarget.DebuggerInterface; var sysObjs = (IDebugSystemObjects)dataTarget.DebuggerInterface; var nativeFrames = new DEBUG_STACK_FRAME[100]; var sybSymbols = (IDebugSymbols)dataTarget.DebuggerInterface; var sb = new StringBuilder(1024 * 1024); foreach (ClrThread thread in runtime.Threads) { var threadInfo = new ThreadInfo { OSThreadId = thread.OSThreadId }; if (thread.StackTrace.Count > 0) { foreach (ClrStackFrame frame in thread.StackTrace) { if (frame.DisplayString.Equals("GCFrame") || frame.DisplayString.Equals("DebuggerU2MCatchHandlerFrame")) { continue; } threadInfo.StackTrace.Add(frame.DisplayString); } } else { threadInfo.IsNative = true; sysObjs.SetCurrentThreadId(threadInfo.OSThreadId); uint frameCount; control.GetStackTrace(0, 0, 0, nativeFrames, 100, out frameCount); for (int i = 0; i < frameCount; i++) { uint nameSize; ulong dis; sb.Clear(); sybSymbols.GetNameByOffset(nativeFrames[i].InstructionOffset, sb, sb.Capacity, out nameSize, out dis); threadInfo.StackTrace.Add(sb.ToString()); } } threadInfoList.Add(threadInfo); } } var mergedStackTraces = new List <StackInfo>(); foreach (var threadInfo in threadInfoList) { bool merged = false; foreach (var mergedStack in mergedStackTraces) { if (threadInfo.IsNative != mergedStack.NativeThreads) { continue; } if (threadInfo.StackTrace.SequenceEqual(mergedStack.StackTrace, StringComparer.InvariantCultureIgnoreCase) == false) { continue; } if (mergedStack.ThreadIds.Contains(threadInfo.OSThreadId) == false) { mergedStack.ThreadIds.Add(threadInfo.OSThreadId); } merged = true; break; } if (merged) { continue; } mergedStackTraces.Add(new StackInfo() { ThreadIds = new List <uint>() { threadInfo.OSThreadId }, StackTrace = threadInfo.StackTrace, NativeThreads = threadInfo.IsNative }); } var jsonSerializer = new JsonSerializer { Formatting = Formatting.Indented }; if (outputPath != null) { using (var output = File.Create(outputPath)) using (var streamWriter = new StreamWriter(output)) { jsonSerializer.Serialize(streamWriter, mergedStackTraces); } } else { jsonSerializer.Serialize(Console.Out, mergedStackTraces); } }
private static void ShowStackTrace(int processId, uint attachTimeout, string outputPath) { if (processId == -1) throw new InvalidOperationException("Uinitialized process id parameter"); var threadInfoList = new List<ThreadInfo>(); using (DataTarget dataTarget = DataTarget.AttachToProcess(processId, attachTimeout)) { var dacLocation = dataTarget.ClrVersions[0].TryGetDacLocation(); var runtime = dataTarget.CreateRuntime(dacLocation); var control = (IDebugControl)dataTarget.DebuggerInterface; var sysObjs = (IDebugSystemObjects)dataTarget.DebuggerInterface; var nativeFrames = new DEBUG_STACK_FRAME[100]; var sybSymbols = (IDebugSymbols)dataTarget.DebuggerInterface; var sb = new StringBuilder(1024 * 1024); foreach (ClrThread thread in runtime.Threads) { var threadInfo = new ThreadInfo { OSThreadId = thread.OSThreadId }; if (thread.StackTrace.Count > 0) { foreach (ClrStackFrame frame in thread.StackTrace) { if (frame.DisplayString.Equals("GCFrame") || frame.DisplayString.Equals("DebuggerU2MCatchHandlerFrame")) continue; threadInfo.StackTrace.Add(frame.DisplayString); } } else { threadInfo.IsNative = true; sysObjs.SetCurrentThreadId(threadInfo.OSThreadId); uint frameCount; control.GetStackTrace(0, 0, 0, nativeFrames, 100, out frameCount); for (int i = 0; i < frameCount; i++) { uint nameSize; ulong dis; sb.Clear(); sybSymbols.GetNameByOffset(nativeFrames[i].InstructionOffset, sb, sb.Capacity, out nameSize, out dis); threadInfo.StackTrace.Add(sb.ToString()); } } threadInfoList.Add(threadInfo); } } var mergedStackTraces = new List<StackInfo>(); foreach (var threadInfo in threadInfoList) { bool merged = false; foreach (var mergedStack in mergedStackTraces) { if (threadInfo.IsNative != mergedStack.NativeThreads) continue; if (threadInfo.StackTrace.SequenceEqual(mergedStack.StackTrace, StringComparer.InvariantCultureIgnoreCase) == false) continue; if (mergedStack.ThreadIds.Contains(threadInfo.OSThreadId) == false) mergedStack.ThreadIds.Add(threadInfo.OSThreadId); merged = true; break; } if (merged) continue; mergedStackTraces.Add(new StackInfo() { ThreadIds = new List<uint>() { threadInfo.OSThreadId }, StackTrace = threadInfo.StackTrace, NativeThreads = threadInfo.IsNative }); } var jsonSerializer = new JsonSerializer { Formatting = Formatting.Indented }; if (outputPath != null) { using (var output = File.Create(outputPath)) using (var streamWriter = new StreamWriter(output)) { jsonSerializer.Serialize(streamWriter, mergedStackTraces); } } else { jsonSerializer.Serialize(Console.Out, mergedStackTraces); } }