How to Print the Current Stack Trace in .Net Without Any Exception

How to print the current Stack Trace in .NET without any exception?

Have a look at the System.Diagnostics namespace. Lots of goodies in there!

System.Diagnostics.StackTrace t = new System.Diagnostics.StackTrace();

This is really good to have a poke around in to learn what's going on under the hood.

I'd recommend that you have a look into logging solutions (Such as NLog, log4net or the Microsoft patterns and practices Enterprise Library) which may achieve your purposes and then some.

Print stack trace with line numbers

You need to pass true to the constructor to instruct it to capture file/line information.

Alternatively, use Environment.StackTrace, if you just need the textual representation of the stack trace.

Additionally, the matching .pdb file must be in the expected location (usually next to the binary).

Print stack trace information from C#

You should be able to get a StackTrace object instead of a string by saying

var trace = new System.Diagnostics.StackTrace(exception);

You can then look at the frames yourself without relying on the framework's formatting.

See also: StackTrace reference

How to print full stack trace in exception?

I usually use the .ToString() method on exceptions to present the full exception information (including the inner stack trace) in text:

catch (MyCustomException ex)
{
Debug.WriteLine(ex.ToString());
}

Sample output:

ConsoleApplication1.MyCustomException: some message .... ---> System.Exception: Oh noes!
at ConsoleApplication1.SomeObject.OtherMethod() in C:\ConsoleApplication1\SomeObject.cs:line 24
at ConsoleApplication1.SomeObject..ctor() in C:\ConsoleApplication1\SomeObject.cs:line 14
--- End of inner exception stack trace ---
at ConsoleApplication1.SomeObject..ctor() in C:\ConsoleApplication1\SomeObject.cs:line 18
at ConsoleApplication1.Program.DoSomething() in C:\ConsoleApplication1\Program.cs:line 23
at ConsoleApplication1.Program.Main(String[] args) in C:\ConsoleApplication1\Program.cs:line 13

Attach StackTrace To Exception Without Throwing in C# / .NET

There is an even more sophisticated solution that avoids any runtime overhead of the reflection part:

public static class ExceptionExtensions
{
public static Exception SetStackTrace(this Exception target, StackTrace stack) => _SetStackTrace(target, stack);

private static readonly Func<Exception, StackTrace, Exception> _SetStackTrace = new Func<Func<Exception, StackTrace, Exception>>(() =>
{
ParameterExpression target = Expression.Parameter(typeof(Exception));
ParameterExpression stack = Expression.Parameter(typeof(StackTrace));
Type traceFormatType = typeof(StackTrace).GetNestedType("TraceFormat", BindingFlags.NonPublic);
MethodInfo toString = typeof(StackTrace).GetMethod("ToString", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { traceFormatType }, null);
object normalTraceFormat = Enum.GetValues(traceFormatType).GetValue(0);
MethodCallExpression stackTraceString = Expression.Call(stack, toString, Expression.Constant(normalTraceFormat, traceFormatType));
FieldInfo stackTraceStringField = typeof(Exception).GetField("_stackTraceString", BindingFlags.NonPublic | BindingFlags.Instance);
BinaryExpression assign = Expression.Assign(Expression.Field(target, stackTraceStringField), stackTraceString);
return Expression.Lambda<Func<Exception, StackTrace, Exception>>(Expression.Block(assign, target), target, stack).Compile();
})();
}

How to hide the current method from exception stack trace in .NET?

Maybe you could derive your own exception type and override the StackTrace property getter to exclude your method:

using System;
using System.Collections.Generic;

class MyException : Exception {

string _excludeFromStackTrace;

public MyException(string excludeFromStackTrace) {
_excludeFromStackTrace = excludeFromStackTrace;
}

public override string StackTrace {
get {
List<string> stackTrace = new List<string>();
stackTrace.AddRange(base.StackTrace.Split(new string[] {Environment.NewLine},StringSplitOptions.None));
stackTrace.RemoveAll(x => x.Contains(_excludeFromStackTrace));
return string.Join(Environment.NewLine, stackTrace.ToArray());
}
}
}

class Program {

static void TestExc() {
throw new MyException("Program.TestExc");
}

static void foo() {
TestExc();
}

static void Main(params string[] args) {
try{
foo();
} catch (Exception exc){
Console.WriteLine(exc.StackTrace);
}
}

}

How to enable stack trace output for JakartaEE/Glassfish application?

First you tell the web-server that you want to us a custom error page by specifying it in your web.xml:

web.xml:

<web-app>
<!-- Any unhandled (i.e. Throwable) errors, display the page ysod.jsp (rather than the built-in default -->
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/ysod.jsp</location>
</error-page>
</web-app>

And then you create a new Yellow Screen of Death JSP file:

ysod.jsp

<!DOCTYPE html>
<%@page import="java.io.PrintWriter"%>
<%@page import="java.io.StringWriter"%>
<%@page import="java.io.StringWriter"%>
<%@page isErrorPage="true" %>
<%!
public String htmlEncode(String s)
{
//Java does not have any htmlEncode or escapeHtml (https://stackoverflow.com/a/1400705/12597)
return s;
}
%>

<%
Throwable cause = exception;
while (cause.getCause() != null)
{
cause = cause.getCause();
}

String path = "/";
String message = cause.getMessage(); //e.g ."Division by zero error";
String exceptionClassName = exception.getClass().getName(); // e.g. "EOverflow";
String sourceFile = "$(sourceFile:C:\\website\\WebSite\\src\\FrobTheGrobber.java)";
String sourceLine = "$(sourceLine:619)";
String serverInfo = getServletContext().getServerInfo().trim(); //e.g. "Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.34209"
String javaVersion = System.getProperty("java.version");

StringWriter sw = new StringWriter();
exception.printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();

StackTraceElement[] stes = exception.getStackTrace();
if (stes.length > 0)
{
StackTraceElement st = stes[0];
sourceFile = st.getFileName();
sourceLine = Integer.valueOf(st.getLineNumber()).toString();
}

%>
<html>
<head>
<title><%= htmlEncode(message)%></title>
<meta name='viewport' content='width=device-width' />
<style>
body {
font-family:'Verdana';
font-weight:normal;
font-size: .7em;
color:black;
}
p {
font-family:'Verdana';
font-weight:normal;
color:black;
margin-top: -5px;
}
b {
font-family:'Verdana';
font-weight:bold;
color:black;
margin-top: -5px;
}
H1 {
font-family:'Verdana';
font-weight:normal;
font-size:18pt;
color:red;
}
H2 {
font-family:'Verdana';
font-weight:normal;
font-size:14pt;
color:maroon;
}
pre {
font-family:'Consolas','Lucida Console',Monospace;
font-size:11pt;
margin:0;
padding:0.5em;
line-height:14pt;
}
.marker {
font-weight: bold;
color: black;
text-decoration: none;
}
.version {
color: gray;
}
.error {
margin-bottom: 10px;
}
.expandable {
text-decoration:underline;
font-weight:bold;
color:navy;
cursor: grab;
}
@media screen and (max-width: 639px) {
pre {
width: 440px;
overflow: auto;
white-space: pre-wrap;
word-wrap: break-word;
}
}
@media screen and (max-width: 479px) {
pre {
width: 280px;
}
}
</style>
</head>

<body bgcolor='white'>
<span><H1>Server Error in '<%=htmlEncode(path)%>' Application.<hr width=100% size=1 color=silver></H1>

<h2> <i><%=htmlEncode(message)%></i> </h2></span>

<font face='Arial, Helvetica, Geneva, SunSans-Regular, sans-serif'>

<b> Description: </b>An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

<br><br>

<b> Exception Details: </b><%=htmlEncode(exceptionClassName)%>: <%=htmlEncode(message)%><br><br>
<br>

<!--
<b> Source Error: </b>
<table width=100% bgcolor='#ffffcc'>
<tr>
<td>
<code><pre>
</pre></code>

</td>
</tr>
</table>
-->

<b> Source File: </b> <%=htmlEncode(sourceFile)%><b>    Line: </b> <%=htmlEncode(sourceLine)%>
<br><br>

<b>Stack Trace:</b> <br><br>

<table width=100% bgcolor='#ffffcc'>
<tr>
<td>
<code><pre>
<%=htmlEncode(stackTrace)%>
</pre></code>

</td>
</tr>
</table>

<br>

<hr width=100% size=1 color=silver>

<b>Version Information:</b> <%=htmlEncode(serverInfo)%>; Java Version: <%=htmlEncode(javaVersion)%>

</font>

</body>
</html>

And Bob's your uncle - a useful error page:

Sample Image

How to get full stack trace from exception object, when debugging in windbg?

TLDR;

You can show the stack trace of a thrown exception using !pe. In probably more than 90% of the cases that's all you need.

Simple and complete example

Here's a minimal reproducible example:

using System;

namespace ConsoleNetFramework
{
class Program
{
static void Main()
{
throw new ApplicationException("An exception");
}
}
}

and the debugging session:

0:000> .loadby sos clr
0:000> !pe
Exception object: 0335246c
Exception type: System.ApplicationException
Message: An exception
InnerException: <none>
StackTrace (generated):
SP IP Function
012FEFB0 01720897 ConsoleNetFramework!ConsoleNetFramework.Program.Main()+0x4f

StackTraceString: <none>
HResult: 80131600

Complex example

Since I considered the answer to be too simple, I felt free to make it more interesting by adding more seldom cases to the example like so:

static void Main()
{
var b = new BadImageFormatException("Bad exception");
ApplicationException a;
try
{
throw new ApplicationException("An exception");
}
catch (ApplicationException aex)
{
a = aex;
}

var t = new Thread(ThrowAnotherException);
t.Start();
throw new DataException("Data exception");

Console.WriteLine(b.Message);
Console.WriteLine(a.Message);
}

private static void ThrowAnotherException()
{
throw new ConfigurationException("Config exception");
}

In the end we'll have 4 exception objects in memory:

  • A...Exception
  • B...Exception
  • C...Exception
  • D...Exception

and we can have a look at all of them.

The debugging session is:

0:000> .loadby sos clr
0:000> !pe
Exception object: 02eb2ca8
Exception type: System.Data.DataException
Message: Data exception
[...]

So far so normal, we stopped at the first exception that was thrown and we can have a look at that exception with !pe.

If we switch to another thread, we can see that the exception is indicated with a # in the list of threads, as long as it's not overwritten by the . (current thread).

0:000> ~1s
0:001> ~
# 0 Id: 28a8.501c Suspend: 1 Teb: 00cc6000 Unfrozen
. 1 Id: 28a8.1044 Suspend: 1 Teb: 00cc9000 Unfrozen
[...]

Here's an interesting part: let's freeze thread 0 and run the application so that a second exception is thrown.

0:001> ~0f
0:001> g
System 0: 1 of 7 threads are frozen
WARNING: Continuing a non-continuable exception
System 0: 1 of 8 threads were frozen
System 0: 1 of 8 threads are frozen
(28a8.4228): CLR exception - code e0434352 (!!! second chance !!!)
System 0: 1 of 8 threads were frozen
[...]

Now we have another exception that caused the debugger to stop.

0:006> ~1s
[...]
0:001> ~
0 Id: 28a8.501c Suspend: 1 Teb: 00cc6000 Frozen
. 1 Id: 28a8.1044 Suspend: 1 Teb: 00cc9000 Unfrozen
2 Id: 28a8.1a2c Suspend: 1 Teb: 00ccc000 Unfrozen
3 Id: 28a8.5cfc Suspend: 1 Teb: 00ccf000 Unfrozen
4 Id: 28a8.490 Suspend: 1 Teb: 00cd2000 Unfrozen
5 Id: 28a8.2b60 Suspend: 1 Teb: 00cd5000 Unfrozen
# 6 Id: 28a8.4228 Suspend: 1 Teb: 00cd8000 Unfrozen
[...]

That exception happened on thread 6. We can also see that we only have one # mark in that list, not two.

On the correct thread, we can print the exception:

0:006> !pe
Exception object: 02eb3ff4
Exception type: System.Configuration.ConfigurationException
Message: Config exception
[...]

On the wrong thread, we can't:

0:006> ~1s
[...]
0:001> !pe
The current thread is unmanaged

Lesson learned: the !pe command is thread sensitive.

Now, what about the other two exceptions, A... and B...? We can find them on the heap:

0:000> !dumpheap -type BadImageFormatException
Address MT Size
02eb2a6c 6e3983c4 92
[...]
Fields:
MT Field Offset Type VT Attr Value Name
[...]
6e342734 40002ab 20 System.Object 0 instance 00000000 _stackTrace
[...]

The exception that was not thrown at all, does not have a stack trace. It's null.

0:000> !dumpheap -type ApplicationException
Address MT Size
02eb2ae4 6e388090 84

Statistics:
MT Count TotalSize Class Name
6e388090 1 84 System.ApplicationException
Total 1 objects
0:000> !DumpObj /d 02eb2ae4
Name: System.ApplicationException
[...]
Fields:
MT Field Offset Type VT Attr Value Name
[...]
6e342734 40002ab 20 System.Object 0 instance 02eb2b7c _stackTrace
[...]

The exception that was thrown but caught, still has its stack trace.

0:000> !pe 02eb2ae4
Exception object: 02eb2ae4
Exception type: System.ApplicationException
Message: An exception
InnerException: <none>
StackTrace (generated):
SP IP Function
00EFEEA0 052F08D2 ConsoleNetFramework!ConsoleNetFramework.Program.Main()+0x8a

StackTraceString: <none>
HResult: 80131600

Lesson learned: !pe can take an arbitrary exception as parameter and print the exception with its call stack.

Looking at the output of the managed !threads, both exceptions will be listed (unlike ~ which shows only one #):

0:001> !threads
ThreadCount: 3
UnstartedThread: 0
BackgroundThread: 1
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
Lock
ID OSID ThreadOBJ State GC Mode GC Alloc Context Domain Count Apt Exception
0 1 501c 00fb99c0 2a020 Preemptive 02EC0714:00000000 00f815a0 0 MTA System.Data.DataException 02eb2ca8
5 2 2b60 00fc4728 2b220 Preemptive 00000000:00000000 00f815a0 0 MTA (Finalizer)
6 3 4228 00fec9a0 2b020 Preemptive 02EC5B70:00000000 00f815a0 0 MTA System.Configuration.ConfigurationException 02eb3ff4

what steps can I take to find out the origin of NullReferenceException?

With the call stack and symbols you should be able to identify a single line of code. Next step is to do a code review there. Figure out which variable is null. Write a unit test to reproduce the issue. Then fix the bug. Like in red/green refactoring.



Related Topics



Leave a reply



Submit