47

One of our users having an Exception on our product startup. She has sent us the following error message from Windows:

  Problem Event Name:                        APPCRASH
  Application Name:                          program.exe
  Application Version:                       1.0.0.1
  Application Timestamp:                     4ba62004
  Fault Module Name:                         agcutils.dll
  Fault Module Version:                      1.0.0.1
  Fault Module Timestamp:                    48dbd973
  Exception Code:                            c0000005
  Exception Offset:                          000038d7
  OS Version:                                6.0.6002.2.2.0.768.2
  Locale ID:                                 1033
  Additional Information 1:                  381d
  Additional Information 2:                  fdf78cd6110fd6ff90e9fff3d6ab377d
  Additional Information 3:                  b2df
  Additional Information 4:                  a3da65b92a4f9b2faa205d199b0aa9ef

Is it possible to locate the exact place in the source code where the exception has occured having this information?

What is the common technique for C++ programmers on Windows to locate the place of an error that has occured on user computer?

Our project is compiled with Release configuration, PDB file is generated.

I hope my question is not too naive.

Pavel
  • 2,610
  • 3
  • 31
  • 50

5 Answers5

70

Yes, that's possible. Start debugging with the exact same binaries as ran by your user, make sure the DLL is loaded and you've got a matching PDB file for it. Look in Debug + Windows + Modules for the DLL base address. Add the offset. Debug + Windows + Disassembly and enter the calculated address in the Address field (prefix with 0x). That shows you the exact machine code instruction that caused the exception. Right-click + Go To Source code to see the matching source code line.

While that shows you the statement, this isn't typically good enough to diagnose the cause. The 0xc0000005 exception is an access violation, it has many possible causes. Often you don't even get any code, the program may have jumped into oblivion due to a corrupted stack. Or the real problem is located far away, some pointer manipulation that corrupted the heap. You also typically really need a stack trace that shows you how the program ended up at the statement that bombed.

What you need is a minidump. You can easily get one from your user if she runs Vista or Win7. Start TaskMgr.exe, Processes tab, select the bombed program while it is still displaying the crash dialog. Right-click it and Create Dump File.

To make this smooth, you really want to automate this procedure. You'll find hints in my answer in this thread.

Community
  • 1
  • 1
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • 7
    A good way to make minidump when the problem actually occurs you can use "SetUnhandledExceptionFilter()" to tell the operating system to call another function you define is case of "catasrophic event, such as access violation. In this function you can load (dynamically using LoadLibrary/GetProcAdderss) the function MiniDumpWriteDump() from dbghelp.dll and write the minidump before the application dies a horribly :-). Later on you can load the minidump. Its an amazing help!!! – TCS May 17 '13 at 20:46
  • 1
    offtopic - In C# Dll I've used `ildasm` as described [here](http://social.msdn.microsoft.com/Forums/en-US/3807a476-8f2f-42c4-a8ec-08c1434de7ab/il-offset-to-source-code-line-numbers?forum=netfxtoolsdev) (while Pdb file is in same directory) – itsho Apr 29 '14 at 12:40
4

If you have a minidump, open it in Visual Studio, set MODPATH to the appropriate folders with the original binaries and PDBs, and tell it to "run". You may also need to tell it to load symbols from the Microsoft symbol servers. It will display the call stack at the error location. If you try to look at the source code for a particular stack location, it may ask you where the source is; if so, select the appropriate source folder. MODPATH is set in the debug command-line properties for the "project" that has the name of the minidump file.

Permaquid
  • 1,950
  • 1
  • 14
  • 15
3

I know this thread is very old, but this was a top Google response, so I wanted to add my $.02.

Although a mini-dump is most helpful, as long as you have compiled your code with symbols enabled (just send the file without the .pdb, and keep the .pdb!) you can look up what line this was using the MSVC Debugger or Windows Debugger. MSN article on that:

http://blogs.msdn.com/b/danielvl/archive/2010/03/03/getting-the-line-number-for-a-faulting-application-error.aspx

std''OrgnlDave
  • 3,912
  • 1
  • 25
  • 34
1

Source code information isn't preserved in compiled C++ code, unlike in runtime-based metadata-aware languages (such as .NET or Java). The PDB file is a symbol index which can help a debugger map compiled code backwards to source, but it has to be done during program execution, not from a crash dump. Even with a PDB, Release-compiled code is subject to a number of optimizations that can prevent the debugger from identifying the source code.

Debugging problems which only manifest on end-user machines is usually a matter of careful state logging and a lot of detail-oriented time and effort combing over the source. Depending on your relationship with the user (for example, if you're internal corporate IT development), you may be able to make a virtual machine image of the user's machine and use it for debugging, which can help speed the process tremendously by precisely replicating the installed software and standard running processes on the user's workstation.

Dan Story
  • 9,985
  • 1
  • 23
  • 27
  • If your software goes to end-users, then you will have to think about logging and crash-dumping mechanism. – Björn Pollex Mar 27 '10 at 10:57
  • 4
    -1 I've never really had a problem debugging code when all I receive is the "PC" (though a full list of all return addresses helps a lot more). As long as you back up your pdb file for each release you do, then you can always get some useful info out of a crash report like this (though a mini/full-dump will always be a LOT better). Your statement that it "has to be done during program execution" is totally wrong. – Grant Peters Nov 25 '10 at 04:18
1

There are several ways to find the crash location after the fact.

  1. Use a minidump. See the answers above.
  2. Use the existing executable in a debugger. See the answers above.
  3. If you have PDB files (Visual Studio, Visual Basic 6), use DbgHelpBrowser to load the PDB file and query it for the crash location.
  4. If you have TDS files (separate TDS file, or embedded in the exe, Delphi, C++ Builder 32 bit), use TDS Browser to load the TDS/DLL/EXE file and query it for the crash location.
  5. If you have DWARF symbols (embedded in the EXE, C++ Builder 64 bit, gcc, g++), use DWARF Browser to load the DLL/EXE and query it for the crash location.
  6. If you have MAP files, use MAP File Browser to load the MAP file and query it for the crash location.

I wrote these tools for use in house. We've made them available for free.

Stephen Kellett
  • 3,078
  • 1
  • 22
  • 25
  • Thank you for making your tools available! The only hiccup I ran into is that the exception offset provided by Windows is hexadecimal without the 0x prefix, so if you copy-paste that into the query by DLL relative address offset without adding the prefix, you get the wrong result. Just mentioning it in case someone else gets a lookup that doesn't make sense. – Raptor007 Aug 29 '23 at 06:40