I am using Windbg to load a crash dump from managed code (C#, a console application built for Any CPU), and crash dump is created on x64 platform. I am debugging on x64 platform.
I have using the following command to load private symbol of my application. Here are what the commands I am using in Windbg.
(set symbol path and copy FooService.pdb pdb file to local symbol path D:\Debug)
0:016> .reload /f
.*** WARNING: Unable to verify checksum for FooService.exe
DBGHELP: FooService.pdb- private symbols & lines
D:\Debug\FooService.pdb
0:016> lm
start end module name
00000000`00400000 00000000`0041c000 FooService C (private pdb symbols) D:\Debug\FooService.pdb
My confusion is, when using the following command, no line number information is showed in stack trace. Any ideas what is wrong? Do I need to set source path?
0:016> ~6 e!clrstack
EDIT 1: I met with some issues with using !pe and !U to find stack trace where the exception is thrown.
Here is my debug process. At first I use !pe to print stack trace for the exception object, when I use !U to diassemble the code. The issue I find is !U will diassemble all function code of FooService.ProcessOrders(), and I want to find the exact place where in function FooService.ProcessOrders the crash happens. I also find the diassembled annotated IL code only contains function calls I made (for non-function call C# code, for example a=a*2, only assembly language is shown), not exactly IL mapped to each line of C# code, (1) is that the correct expected behavior? (2) what is the solution or further suggestion to find the exact failed C# code from my analysis posted here?
!pe 0000064280155325
StackTrace (generated):
SP IP Function
000000001A56DA70 00000642B74E3B7A System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(System.Data.Common.DbAsyncResult, System.String, Boolean)
000000001A56DB10 00000642B74E3FCC System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
000000001A56DB90 0000064280155325 FooService.ProcessOrders()
000000001A56F3E0 0000064280153A21 FooService.RountineJob()
!U 0000064280155325
thank in advance,
George
WinDbg/SOS doesn't map line numbers to the output of !clrstack. So as long as lm tells you that you have private pdb symbols for your own assemblies you setup is correct. Unfortuntately the current versions of WinDbg/SOS doesn't support source level debugging to the same extend as for native code.
EDIT: Regarding exceptions. When you do a !pe, it will tell you the call stack as well as offsets into the relevant methods. If you take the address from the IP column of the !pe output and do a !U on that, you will see the JITTED code for the relevant method. The IP column will be the last address of the code that generated the exception (so you have to do a little counting to find the correct instruction).
The disassembled output is annotated with .NET calls so it is no hard to map this against the IL or source code. That should help you identify exactly which throw statement you're looking for.
That being said, you will make debugging a lot easier if you split methods into a number of smaller methods. If you do that, the method name is usually enough to pinpoint the location of the exception. I realize that is not always an option, but it is worth considering.
Related
I have a WPF application that has started failing with the following error at start:
System.InvalidOperationException: ''{DependencyProperty.UnsetValue}' is not a valid value for property 'BorderBrush'.'
This exception was originally thrown at this call stack:
[External Code]
This is not very forthcoming about what has caused the error. I have tried turning on the CLR Exceptions and restarting as per This Page, but it did not give any more information; I turned on the disassembly, but don't understand what it means. Turning on "Just My Code" debugging and all the Exception Settings as per this page got slightly more in the exception stack trace:
System.InvalidOperationException
HResult=0x80131509
Message='{DependencyProperty.UnsetValue}' is not a valid value for property 'BorderBrush'.
Source=WindowsBase
StackTrace: at System.Windows.DependencyObject.GetEffectiveValue(EntryIndex entryIndex, DependencyProperty dp,
RequestFlags requests)
This exception was originally thrown at this call stack:
System.Windows.DependencyObject.GetEffectiveValue(System.Windows.EntryIndex, System.Windows.DependencyProperty, System.Windows.RequestFlags)
but none of this gives me (that I can see) any information about what code is failing. I have got down to deleting various bits and re-starting the app, but it is extremely time-consuming and I can't help but wonder - is there something else I should be doing.
Is there any way I can find out which bit of code is failing, or any clues (e.g. search terms to look for in my code, clues as to whether it would be a .xaml or a .cs page, places to look in the Exception details, anything) that might help narrow down the location? For instance, is this something that would only be returned by a failed attempt to override the template defaults in wpf, or might it be caused by one of my windows - Is it likely to have come from a style maybe?
Basically, other than seeing that there seems to be a place where I should be setting the BorderBrush and am not, I have no idea how to find what error I need to fix - and since it is a missing thing, I don't know how to find it. Any leads, hunches or advice will be greatly received!
This is a WPF Windows Application, writing in Visual Studio 2019 using .NET 4.8
So it turns out that there really is no way to find out clearly where the error was, but through a process of deleting files, clearing out references and reinstating, I was able to find the problem.
There was a reference to a static resource in a connected .DLL that no longer existing since the .DLL was republished without checking. The change in name there meant that a resource was not found and the unset value was sent to the Dependency Property. It would be lovely if Microsoft were able to provide some sort of check on the location of problematic resources.
I am compiling a project using csc.exe, with the /analyzer: flag pointing to the paths of ErrorProne.Net.CoreAnalyzers.dll and ErrorProne.Net.Core.dll, which are built from my clone of the library here.
However, I see several error messages like these:
"warning CS8032: An instance of analyzer
ErrorProne.NET.AsyncAnalyzers.ConcurrentCollectionAnalyzer cannot be
created from
C:\Repos\RoslynExample\RoslynExample\ErrorProne.Net.CoreAnalyzers.dll
: Exception has been thrown by the target of an invocation."
"warning CS8032: An instance of analyzer
ErrorProne.NET.AsyncAnalyzers.AddConfigureAwaitAnalyzer cannot be
created from
C:\Repos\RoslynExample\RoslynExample\ErrorProne.Net.CoreAnalyzers.dll
: Exception has been thrown by the target of an invocation."
etc.
I would like to get more debug information, so that I know exactly when and where these errors are thrown, as well as their inner exceptions. As of now, these error messages on their own are useless.
It is important that I am able to print the stack traces (especially the inner exceptions) to console, or write it to file.
How can I get a copy of the stack trace?
UPDATE:
I figured out the cause of these errors by 1) creating a console application which runs the analyzers built from my clone of the Error.Net source code, 2) disabling Just My Code, and 3) breaking on all exceptions. While it is great to finally figure out what the problem is, it still leaves my original question unanswered: How can I get access to the inner exceptions (so that I can display them later) just by running csc.exe?
did you try to turn on Trace output?
csc -r:System.dll -d:TRACE -d:DEBUG=FALSE MyApplication.cs
Maybe this article will be usefull for you How to: Compile Conditionally with Trace and Debug
I decompiled a release assembly using ILSPy and I got code like below. When I open the decompiled project in VS 2013, I get an error for each of these statements.
using #j;//this line shows up as an error in VS2013
using System;
The error is:
Preprocessor directives must appear as the first non-whitespace character on a line
I get a similar error at following line also.
string path = #db.#ab(HttpUtility.UrlDecode(text));
Question : What is the meaning of using # and how can I correct these errors?
I have also noticed that some decompiled classes have names starting with # and so do some namespaces and method names. I have never used such a naming convention, so it's very confusing how 'ILSpy` came up with such code.
No, it's not valid C#. Chances are it's decompiled code that was obfuscated to start with, so using identifiers that are valid in IL but not in C#.
Typically, if you're decompiling obfuscated code, you're doing something against the wishes of the original authors of the code - so I'd suggest just not doing that. If you think you have a legitimate reason for getting the source code for something, ask the author.
Could you convert this into valid C#? Sure - just take every #-prefixed identifier, and map it (consistently) onto something else, e.g.
using hashj;
...
string path = hashdb.hashab(HttpUtility.UrlDecode(text));
... and eventually you'll run across a class called #db which you'd then rename to hashdb etc. But the point of the obfuscation is to make this a painful process.
I'm really stumped by this one!
The StackFrame object (MSDN Link) has a GetFileName method that returns the original path of the source file that compiled the executing method (provided symbols were generated and included with the executing assemblies). It looks like this information is used to generate full exception text.
I'm trying to find a way to get at this information if the method isn't currently executing. I've been poking around the reflection API and haven't seen a way to get at this information. I assume it must be in there somewhere.
Does anyone else know of a reflection based method (or indeed any other method) that can get me the code file name?
Any ideas, comments or abuse gratefully accepted.
Many thanks!
Reflection can only provide type information from the assembly metadata. Getting the address requires the .pdb debugging file and the address of the function in memory, as compiled by the JIT compiler. You can't get the address without the StackFrame.GetNativeOffset() method or the debugger interfaces, assuming the method is even compiled. The latter approach can't work in-process, a program cannot debug itself.
The CLR doesn't have any trouble because it can retrieve the method address from the stack frames when it processes the exception. That's still an imperfect art, it cannot see addresses of methods that were inlined. Having those stack frames is the required first step.
You can read the information from the .pdb file and evaluate it yourself. It contains all the data you need. I haven't finished reading the code but my understanding is this:
You get the metadata token from the method in question through reflection
You query the pdb data for that token
The pdb entry contains the source file name and line number
A metadata token is a 32 bit number that consists of a type byte and a serial number. That token describes every single entity in a .NET assembly file: types, type references, methods, fields, and so on. That number is worth more than the full namespace, type, method name and signature of a method, and it's easier to handle. But be aware that it's generated by the compiler and may be different in every build, so you always need the .pdb file from the same build.
The pdb file contains entries about which IL offset in what method comes from which source location. If you don't have a StackFrame but only a method, you'll probably find multiple entries about the method so you can either use the one with the smallest offset, or describe the entire range in the source code that defines the method.
Here are some links for further reading, the search term is "pdb2xml" which is an old code sample by Microsoft:
http://blogs.msdn.com/b/jmstall/archive/2005/08/25/pdb2xml.aspx
http://blogs.msdn.com/b/jmstall/archive/2005/08/25/sample-pdb2xml.aspx
Since the .NET API for reading .pdb files requires to have the assembly files available, this conversion should be done directly after the build to keep the generated XML file really portable.
I'm actually building this method in my .NET logging solution, FieldLog, to allow source location resolution from crash logs from release builds, and to de-obfuscate stack traces from obfuscated assemblies.
Use RedGate Reflector decompiler to inspect the assembly containing the class.
Other than reading the GetFileName() file and reading to line GetFileLineNumber() of a stackframe from
new StackTrace(exception).GetFrame(x)
is there a way to get the actual line of code (as a string) which caused an exception?
Thanks
I don't think so. The code is compiled, therefore it is no longer available.
However, if you also have the source code available, there may be a few workarounds.
No, that's your only option as far as I know. In order to get the original line of code that caused the exception, then it's necessary to have the source available. That the StackFrame already enables you to get the line number (via the debug symbols - the PDB file in most cases), makes it straightforward enough, I'd say.
Is there any particular problem with the method you suggested?
There is no reliable way to do this because line information is not stored in DLL files. The information which maps blocks of IL into source code lines is stored within the PDB file. You'd need to access the PDB in order to get the line information for an exception.
There is sufficient information on the StackFrame class to get the appropriate ISymUnmanagedMethod class if the PDB is available. Mainly you just need the method token and the current offset into the method. This does require you to understand the internal structure of the PDB and I'm not sure if it's documented anywhere.
PDB API: http://msdn.microsoft.com/en-us/library/ms233503.aspx
It would be compiled, so at run time you would only have the IL. At best, you could get the IL and decompile it back to C#, much like reflector does.
Post moretem debugging is difficult, but not impossible. There are tools you can use (here and here for example) as well as techniques.
You can get line using a try catch block:
catch(Exception exception) {
//exception.StackTrace at the first line has the line you are looking for
}