gdb allows one to catch exceptions when they're thrown, and when they're caught. But sometimes the line an exception is thrown has no symbols, or a breakpoint is triggered during exception handling. How do I inspect the value of the current exception?
问题:
回答1:
Updated
Here's some info from the GDB Manual
There are currently some limitations to C++ exception handling (catch throw and catch catch) in gdb:
If you call a function interactively, gdb normally returns control to you when the function has finished executing. If the call raises an exception, however, the call may bypass the mechanism that returns control to you and cause your program either to abort or to simply continue running until it hits a breakpoint, catches a signal that gdb is listening for, or exits. This is the case even if you set a catchpoint for the exception; catchpoints on exceptions are disabled within interactive calls. You cannot raise an exception interactively. You cannot install an exception handler interactively. Sometimes catch is not the best way to debug exception handling: if you need to know exactly where an exception is raised, it is better to stop before the exception handler is called, since that way you can see the stack before any unwinding takes place. If you set a breakpoint in an exception handler instead, it may not be easy to find out where the exception was raised.
To stop just before an exception handler is called, you need some knowledge of the implementation. In the case of gnu C++, exceptions are raised by calling a library function named __raise_exception which has the following ANSI C interface:
/* addr is where the exception identifier is stored. id is the exception identifier. */ void __raise_exception (void **addr, void *id); To make the debugger catch all exceptions before any stack unwinding takes place,
set a breakpoint on __raise_exception (see Breakpoints; Watchpoints; and Exceptions).
That said
It depends on the code and where you are in the stack. If you actually caught the exception as in :
try { .... } catch (std::exception &e) {
//do stuff
}
You could probably try printing e.what()
, or look at the members of the exception. If you just caught it as (...) then I'm not sure what you'd be able to gather.
Another handling thing you could do is to catch 'throw' in gdb and catch 'catch' as well if you really want to follow the whole flow.
gdb> catch catch
gdb> catch throw
This way you will get a breakpoints right before exceptions are thrown and right as they are caught, you could then walk the stack to gain more information about what was going on. Even if you are in another break point you should be able to walk up the stack (using up or down) to get the frame in which the exception is visible.
回答2:
Earlier answers were correct when written (in 2013), but since then gdb and libstdc++ have changed.
libstdc++ now has some hooks that let gdb interact more nicely with the exception system. In particular, there is now enough information exposed for gdb to provide a $_exception
convenience variable to the user. This variable holds the exception being thrown. It is only valid at exactly the spot where the exception is being caught; which you can stop at using catch catch
.
See the page from the manual for details.
回答3:
Short answer: you can't because most work of exception handling is done outside of your program, and is therefore outside of gdb's scope.
Explained answer:
sometimes the line an exception is thrown has no symbols
If the binary you're debugging has no debug symbols then the binary is probably stripped and you won't be able to find much at all about the types/values of anything at all.
How do I inspect the value of the current exception?
I think you're assuming here that an exception is a language feature that gdb can inspect; in fact an exception in C++ is a combination of features from C++ as a language, of libc++ and the ABI. And there might even be more than a single active current exception.
Like UpAndAdam points out you can set a breakpoint in a catch block with a type specifier, and then inspect that element, but I suspect your problem is in cases where you find a "catch (...)". In those cases you won't be able to learn much about the current exception unless you go digging into the implementation of exception handling.
With a very short and incomplete description we could say that to throw an exception:
- Your program will call libc++ to raise an exception
- libc++ will call "unwind" in glibc to start the stack unwinding
- unwind will call back a "personality function" from libc++ for each stack frame (each function call in the stack, basically)
- the personality function will somehow decide if the current stack frame can or can't handle this exception
- if the exception can be handled the catch block will be executed
Now, it's difficult to talk about details because a lot of exception handling depends on your toolchain (compiler, platform, architecture, libc++, etc) but in most cases a "catch (...)" won't even receive the original exception as an argument. In any case, to somehow answer your question: in gcc with gnu's libc++ you could try something like this:
- Get a libc++ with debugging symbols
- Set a breakpoint in __gxx_personality_v0 (that's called the personality function). This function will get called to determine whether a stack frame (a function call, basically) has a suitable catch block to handle the exception
- In the personality function you'll be able to find a pointer to _Unwind_Exception, which is a wrapper to your real exception
- Get the type info for your exception like this: __cxa_exception *exception_header = (__cxa_exception*)(unwind_exception+1)-1; std::type_info *thrown_exception_type = exception_header->exceptionType;
- You'll get an exception type which you can then lookup with the rest of the RTTI defined for your code
In any case, you'll probably need to spend quite a bit of time trying to understand how exception handling is implemented in your platform. If you want to read a bit more about exception handling I spent some time in the past writing about the topic @ http://monoinfinito.wordpress.com/series/exception-handling-in-c/. It's not an official source but it does have links to the specs of each part involved in handling an exception.