|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
Disclaimer
I am not MS certified developer and my opinion and code may have some bugs. Introduction
After familiarization with .NET Framework and System.Exception Object everyone can exclaim
"Wow, it's really cool to be able to trace a call stack via a single call of MainEvery programmer sometimes errs and tries to work with a wrong pointer. And it's real headache to detect the line of code with the bug. Look at this example of code with just such an annoying "access violation" error try { char * p = 0; printf("%u", strlen(p)); // oops } catch(se_translator::access_violation& ex) { sym_engine::stack_trace(os, ex.info()->ContextRecord); } But now have a look at this screenshot from VC IDE output window. First-chance exception in Exception.exe: 0xC0000005: Access Violation. First-chance exception in Exception.exe (KERNEL32.DLL): 0xE06D7363: Microsoft C++ Exception. intel\strlen.asm(78) : Exception.exe at strlen() D:\Exception\Exception.cpp(185) : Exception.exe at foo() D:\Exception\Exception.cpp(65) : Exception.exe at main() crt0.c(206) : Exception.exe at mainCRTStartup() (0) : KERNEL32.dll at GlobalGetAtomNameA()
Just double click and it point you to a bug's code directly. It's magic, isn't it ? Ok, Let's be deep in a subject and familiarize with source code. There are two main parts of magic:
The int exception_filter(std::ostream& os, EXCEPTION_POINTERS * pex) { sym_engine::stack_trace(os, pex->ContextRecord); return EXCEPTION_EXECUTE_HANDLER ; } void foo (std::ostream& os) { __try { // any buggy code here } __except(exception_filter(os, GetExceptionInformation())) { } }
For obtaining a stack trace we need a CONTEXT structure. And we can get it
via call GetExceptionInformation() in the filter expression of an SEH exception handler.
Ok. But we can't get such info in C++ catch(...) block. So, then we have to call the
The se_translator translator; // install a new translator function void foo(std::ostream& os) { try { // force to install a exception frame WORKAROUND_VCPP_SYNCHRONOUS_EXCEPTION char * p = 0; printf("%u", strlen(p)); // oops } catch(se_translator::access_violation& ex) { sym_engine::stack_trace(os, ex.info()->ContextRecord); } }
At first, I've installed a new translator function and now I can handle structured exception like C++ exception.
I've wrapped every structured exception into C++ class. The base class is
Yes, now we've grasped the way to obtaining stack for Win32 structured exception.
But interesting, is there any way for obtaining similar info for native C++ exception like std::exception and so on ?
Hm, I can't achieve it, but can propose a workaround.
We can define the new exception class derived from std::exception which will hold the class stack's info.
Let's name it
try
{
throw exception2("my exception"); // stores the stack info here
}
catch(exception2& ex)
{
os << ex.what() << std::endl;
os << ex.stack_trace() << std::endl;
}
At last the final class which I want to present it's exception_trap<> trap;Enjoy :) Some trapsAs any programmer knows, any good idea always has a some traps. In that case it's in synchronous exception model (/EHs compiler option) and _set_se_translator API. Sometimes due to optimization reasons the compiler can avoid to generate code for try\catch block. See MSDN article for more info. Hence if access violation or another exceptions will be occured nobody can catch it and tricks with SE translator will useless here. I know two ways for avoiding such ugly scenario.
I can't name it the best solution but it's working. Project's settingsMake sure what you set a next options:
If you want to use the symbol engine in your release version too
and don't forget to place the .pdb file in the same folder with your .exe or .dll file (see MSDN topic SymInitialize for more info) ThanksSven Axelsson for "Using an output stream for debugging"Rostislav Sharafutdinov for some correction
|
||||||||||||||||||||||