How do I get a string description of a Win32 crash while in Top level filter (I am looking for the address of the instruction at the top of the stack)
If I use a class/method like the one described here how can I get the description/address of the call at the top of the stack?
Basically I want some value I can use in a call to our bug tracking system. I want to "uniquely" identify based on the address of the instruction that caused the exception.
(It is usually something of the form of mydll.dll!1234ABDC())
EDIT:
Some background information:
I am creating a minidump to email to a defect tracking system (fogbugz). In order to reduce duplicates I am trying to come up with a reasonable "signature" for the crash. I know there is an xml PI for FB, but it requires a user logon and we are not sure yet that we can afford to have people sniffing our traffic and getting user information. Emailing is also simpler for now to implement. Later on 开发者_C百科we will use the XML API to submit minidumps.
You need to put the code to do this in your exception filter, by the time you get to the exception handler much of the context information for the exception has been lost.
try
{
// whatever
}
except (MyExceptionFilter(GetExceptionInformation()))
{
}
Your filter will look something like this
LONG WINAPI MyExceptionFilter (
EXCEPTION_POINTERS * pExcept,
BOOL fPassOn)
{
EXCEPTION_RECORD * pER = pExcept->ExceptionRecord;
DWORD dwExceptionCode = pER->ExceptionCode;
TCHAR szOut[MAX_PATH*4]; // exception output goes here.
szOut[0] = 0;
MEMORY_BASIC_INFORMATION mbi;
DWORD cb = VirtualQuery (pER->ExceptionAddress, &mbi, sizeof(mbi));
if (cb == sizeof(mbi))
{
TCHAR szModule[MAX_PATH];
if (GetModuleFileName ((HMODULE)mbi.AllocationBase, szModule, MAX_PATH))
{
wsprintf(szOut, "Exception at '%s' + 0x%X", szModule,
(ULONG_PTR)pER->ExceptionAddress - (ULONG_PTR)mbi.AllocationBase);
}
}
return EXCEPTION_EXECUTE_HANDLER;
}
Of course, you will need to adjust your output a bit for 64 bit architectures, since the ExceptionAddress and AllocationBase will be 64 bit quantities in that case.
The EXCEPTION_POINTERS
struct which is sent to TopLevelFilter()
contains an EXCEPTION_RECORD
struct which contains the ExceptionAddress
. Which this address you can figure out in which DLL the offending opcode is by enumerating the modules with CreateToolhelp32Snapshot. You can also use the functions in dbghelp.dll
to find the symbol which correspond to the address (the function it is in)
GetExceptionInformation will return the EXCEPTION_POINTERS struct which contains information about the exception. The ExceptionRecord member contains an ExceptionAddress member, which is the address of the exception.
You'll need to map this address to a module relative location in your code to be useful. You can use GetModuleHandleEx with the GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS to get the HMODULE (which is also the base address of the module). GetModuleInformation can then be used to get the actual name of the module that the exception occurred in.
This may not be that helpful to you if the fault is actually inside of a system DLL. A more sophisticated scheme would be to generate a stack trace (using Stackwalk64 in dbghelp), and ignoring the topmost frames that are not in your code.
You can avoid the pain of printing a string for the exception (what happens if you can save the minidump but can't format a string without crashing?) by saving the minidump instead and using cdb.exe or windbg.exe to extract the exception information.
精彩评论