I have found no way of dumping the stack on all threads in .NET. Neither a signal to be send to the process nor programatic access to all the threads. I can only get access to t
I wrote a dumper for a project i worked on in the past:
void CrashHandler::WriteThreadInfo(StringWriter* sw, ArrayList* threads, String* type)
{
sw->WriteLine(type);
IEnumerator* ie = threads->GetEnumerator();
while(ie->MoveNext())
{
botNETThread* bnt = static_cast<botNETThread*>(ie->Current);
if(!bnt->IsAlive) continue;
sw->WriteLine(String::Concat(S"ORIGIN ASSEMBLY: ", bnt->Assembly->FullName));
sw->WriteLine(String::Concat(S"THREAD NAME: ", (bnt->Name && bnt->Name->Length)?bnt->Name:S"Unnamed thread"));
sw->Write(GetStackTrace(bnt->_thread));
sw->WriteLine();
sw->WriteLine();
}
}
String* CrashHandler::GetStackTrace(Thread* t)
{
System::Diagnostics::StackTrace __gc * trace1 = __gc new System::Diagnostics::StackTrace(t, true);
System::String __gc * text1 = System::Environment::NewLine;
System::Text::StringBuilder __gc * builder1 = __gc new System::Text::StringBuilder(255);
for (System::Int32 num1 = 0; (num1 < trace1->FrameCount); num1++)
{
System::Diagnostics::StackFrame __gc * frame1 = trace1->GetFrame(num1);
builder1->Append(S" at ");
System::Reflection::MethodBase __gc * base1 = frame1->GetMethod();
System::Type __gc * type1 = base1->DeclaringType;
if (type1 != 0)
{
System::String __gc * text2 = type1->Namespace;
if (text2 != 0)
{
builder1->Append(text2);
if (builder1 != 0)
{
builder1->Append(S".");
}
}
builder1->Append(type1->Name);
builder1->Append(S".");
}
builder1->Append(base1->Name);
builder1->Append(S"(");
System::Reflection::ParameterInfo __gc * infoArray1 __gc [] = base1->GetParameters();
for (System::Int32 num2 = 0; (num2 < infoArray1->Length); num2++)
{
System::String __gc * text3 = S"<UnknownType>";
if (infoArray1[num2]->ParameterType != 0)
{
text3 = infoArray1[num2]->ParameterType->Name;
}
builder1->Append(System::String::Concat(((num2 != 0) ? S", " : S""), text3, S" ", infoArray1[num2]->Name));
}
builder1->Append(S")");
if (frame1->GetILOffset() != -1)
{
System::String __gc * text4 = 0;
try
{
text4 = frame1->GetFileName();
}
catch (System::Security::SecurityException*)
{
}
if (text4 != 0)
{
builder1->Append(System::String::Concat(S" in ", text4, S":line ", frame1->GetFileLineNumber().ToString()));
}
}
if (num1 != (trace1->FrameCount - 1))
{
builder1->Append(text1);
}
}
return builder1->ToString();
}
You can use Process.GetCurrentProcess().Threads to get threads
And I know i spasted Managed C++ but its easy enough to follow. I take an arraylist of threads because for my purpose I had catagorized my threads. And yes i used previously written stack frame code as I was new to MC++ at the time :)
The entire file is here. This was for a Diablo II botting engine I wrote some time ago.
If you're trying to get a stack dump while the process is already running (a la jstack), there are two methods as described here:
There is a little-known but effective tool called the Managed Stack Explorer. Although it features a basic GUI, it can effectively be a .NET equivalent of jstack if you add to the path; then it’s just a question of typing:
mse /s /p <pid>
I just found it necessary to take a production thread dump and this worked for me. Hope it helps :-)
There is a variety of handy classes in the System.Diagnostics that can help you with debugging and gathering various tracking information, i.e. StackTrace.
There is a wonky Process class that can be used to get the number of executing threads but very few details. Use the following Snippet:
Using System.Diagnostics;
var threads = Process.GetCurrentProcess().Threads;
Okay after looking a little bit more it appears the easiest way to capture all the current stacks is through a mini dump and a tool like SOS or if you are running vista this.
Good luck.
Just to save anyone else the bother here's the port of the above to c#:
static void WriteThreadInfo(StringBuilder sw, IEnumerable<Thread> threads)
{
foreach(Thread thread in threads)
{
if(!thread.IsAlive) continue;
sw.Append(String.Concat("THREAD NAME: ", thread.Name));
sw.Append(GetStackTrace(thread));
sw.AppendLine();
sw.AppendLine();
}
}
static String GetStackTrace(Thread t)
{
t.Suspend();
var trace1 = new StackTrace(t, true);
t.Resume();
String text1 = System.Environment.NewLine;
var builder1 = new StringBuilder(255);
for (Int32 num1 = 0; (num1 < trace1.FrameCount); num1++)
{
StackFrame frame1 = trace1.GetFrame(num1);
builder1.Append(" at ");
System.Reflection.MethodBase base1 = frame1.GetMethod();
Type type1 = base1.DeclaringType;
if (type1 != null)
{
String text2 = type1.Namespace;
if (text2 != null)
{
builder1.Append(text2);
builder1.Append(".");
}
builder1.Append(type1.Name);
builder1.Append(".");
}
builder1.Append(base1.Name);
builder1.Append("(");
System.Reflection.ParameterInfo [] infoArray1 = base1.GetParameters();
for (Int32 num2 = 0; (num2 < infoArray1.Length); num2++)
{
String text3 = "<UnknownType>";
if (infoArray1[num2].ParameterType != null)
{
text3 = infoArray1[num2].ParameterType.Name;
}
builder1.Append(String.Concat(((num2 != 0) ? ", " : ""), text3, " ", infoArray1[num2].Name));
}
builder1.Append(")");
if (frame1.GetILOffset() != -1)
{
String text4 = null;
try
{
text4 = frame1.GetFileName();
}
catch (System.Security.SecurityException)
{
}
if (text4 != null)
{
builder1.Append(String.Concat(" in ", text4, ":line ", frame1.GetFileLineNumber().ToString()));
}
}
if (num1 != (trace1.FrameCount - 1))
{
builder1.Append(text1);
}
}
return builder1.ToString();
}
I've not found a way to get a list of all managed threads in C# (only ProcessThreads), so it does look like you need to maintain the list of threads your interested in yourself.
Also I found I couldn't call new Stacktrace(t,true) on a running thread, so have added pause and resumes. Obviously you'll need to consider whether this could cause problems were you to thread dump your production app.
btw, we've put this call on our apps wcf rest interface so it's easy to do.
The best tool I have seen at this point to generate thread dumps for the .NET CLR is DebugDiag. This tool will generate a very detailed report (using the Crash/Hang analyzer) of the active CLR threads along with recommendations.
I recommend to review the following .NET DebugDiag tutorial as it is showing the analysis process in action following a production problem. The steps are as per below:
If you need to do this programmatically (maybe you want automatic dumps during your CI process), you can use the info from this answer to a different question.
Basically, attach to your own process using CLR MD:
using Microsoft.Diagnostics.Runtime;
using (DataTarget target = DataTarget.AttachToProcess(
Process.GetCurrentProcess().Id, 5000, AttachFlag.Passive))
{
ClrRuntime runtime = target.ClrVersions.First().CreateRuntime();
foreach (ClrThread thread in runtime.Threads)
{
IList<ClrStackFrame> stackFrames = thread.StackTrace;
PrintStackTrace(stackFrames);
}
}
Here PrintStackTrace is left as an exercise for the reader.