gdb - Prevent losing backtrace in a catch/rethrow situation - c++

Is it possible to re-throw an exception without losing the back-trace in gdb? Or is there a way in gdb to "back up' a few lines and back trace from there? I'm on GDB 7.7.1, the most recent.
I sometimes find myself running into situations like this, needing a back trace from the original throw of the exception, and needing to comment out the try/catch parts, recompiling, and re-running in gdb.
try {
someFuncThatCanThrowException();
} catch(exceptionType& exception) {
if(#CAN_RECOVER#) {
...
} else {
throw;
}
}
----OR----
try {
someFuncThatCanThrowException();
} catch(exceptionType& exception) {
exception.printMessageToCout();
throw;
}

needing a back trace from the original throw of the exception,
Is it OK to use a simple approach of printing all backtraces of all throws and then when it is necessary to find a backtrace of a particular exception just find it by the address of the exception. Something like this sequence of gdb commands:
set pagination off
catch throw
commands
info args
bt
c
end
When you need to find backtrace of an exception, first print its address, like this:
print &exception
And find its address in the gdb output. It must be printed by info args. As soon as you find address there will be backtrace of this exception after info args output.

Related

How to get CLion to show exceptions?

I have CLion installed with presumably default configuration. I think something is wrong with it, because I can't see exceptions. For example, this code:
int main(){ throw 5; }
Prints only Process finished with exit code 0
Why doesn't it print the exception?
Why does it print 0 instead of 1?
For comparison:
int main(){try { throw 5; } catch(int x) { std::cout << x << '\n'; }}
This prints 5, so it looks like code is correctly run and the exception is correctly thrown. It's just hidden by CLion somehow.
Edit: This is not a duplicate of "not seeing any console output". I made extremely clear in my question that I was indeed seeing console output for prints. My issue concerns exceptions specifically, not console output generally.
In your first piece of code you have not caught the exception, so it is handled by the default handler. You therefore have no control over the return code from the executable. Operation is as expected.
If you would like CLion to display the exception you can configure it to do so. Note that this will only apply when CLion is debugging your executable, outside of CLion your executable will continue to behave as you have already seen.
Go to run then view breakpoints.
Go to exception breakpoints and when any is thrown.
To display the stack trace when the exception is thrown check stack trace
If you would like your program to stop for your intervention, check enabled and when thrown.
Make sure to use Run/Debug and not Run/Run to launch your program.

Print thread id at breakpoint

I am debugging some C++ code. When I am paused at breakpoint, if I do info thread, gdb shows me a list of all the threads in my process, and puts an asterisk next to the thread under execution at breakpoint. Is there a gdb command which makes gdb tell you the thread id when at breakpoint?
I am doing catch throw and catch catch, to debug around the time an exception is thrown on thread 1. But, thread 2 is simultaneously also throwing and catching exceptions. Since, I am only interested in throw and catch on thread1, I plan to ask gdb for threadid, and script the breakpoint to continue if threadid is 2.
(gdb) catch throw
Catchpoint 7 (throw)
(gdb) catch catch
Catchpoint 8 (catch)
(gdb) command 8
> if threadid == 2
> c
> end
Can you please show me how to write this line if threadid == 2?
Using the built-in $_thread convenience variable:
The debugger convenience variables $_thread and $_gthread contain,
respectively, the per-inferior thread number and the global thread
number of the current thread. You may find this useful in writing
breakpoint conditional expressions, command scripts, and so forth. See
Convenience Variables, for general information on convenience
variables.
catch catch if $_thread == 1
Using the Python API:
— Function: gdb.selected_thread () This function returns the thread
object for the selected thread. If there is no selected thread, this
will return None.
catch catch
command
python
if gdb.selected_thread() != 1:
gdb.execute('continue');
end
end
Generally speaking, when GDB lacks a feature, it's very unlikely you cannot implement it using the Python API since it allows you to explore your running program and context.

How to set breakpoint in catch block? (c++)

There is something strange happening when I try to debug application. Simply the debugger does not stop on breakpoints when I set breakpoints in catch portion of try-catch block.
Here is an example.
try {
throw std::overflow_error("test");
} catch (...) {
qDebug() << "caught"; // HERE, I SET BREAKPOINT ON THIS LINE
}
It prints the "caught" on screen when exception occurs but it does not stop on this line. (If you ever wonder; Yes, I'm building app in Debug mode and running in Debug mode)
Am I suffering from lack of fundamental knowledge about how gdb works? (I mean maybe it does not stop because breakpoints in catch portion does not work)
Any help would be greatly appreciated.
Thanks.
To catch an exception in IDE, you need issue gdb commands directly in gdb console.
Here's link how to get into gdb console in Qt Create IDE:
Accessing gdb console in Qt-Creator
Once you're the type
catch throw
to stop when your program throws an exception or
catch catch
to stop in the catch block.
If you need to catch a specific library exception, read this thread: GDB: How to break when a specific exception type is thrown?
for people using LLDB,
# set on both throw and catch
breakpoint set -E C++ -h true
# or on catch
b __cxa_begin_catch
# or on throw
b __cxa_throw
while will set breakpoints on throw and catch.
#ben sen, I guess any opinization may result in such a behavior. There are many ways how those options can be specified (via environment variables aka CFLAGS or via IDE options to the project), but they all result to some particular -O option given to the compiller command line. Even if nothing is given at all, please check what is the default optimization for your compiller. My proposal would be to explicitely give -O0 to the compiller and check that no other -O options are supplied.

Throw Causes Program to Crash Instead of going to the Catch Block

I am using NetBeans 7.0.1 on Ubuntu 11.10.
I set set up a
try
{
int error;
// Code
if (error) throw error;
}
catch(int errorNumber)
{
// Error handling
}
block. However, when an exception is thrown, I get the following "Signal Caught" box instead of the program going to my catch block.
Signal received: SIGABRT (?) with sigcode ? (?)
From process: ?
For program celltowebimage, pid 30,222
You may discard the signal or forward it and you may continue or pause the process
To control which signals are caught or ignored use Debug->Dbx Configure
Every other time a program I write throws an exception, it goes to the catch block. Why is NetBeans crashing the program instead? An example of the exception number that is thrown is -23. However they are all small, negative numbers and all result in the same problem.

How to break when a specific exception type is thrown in GDB?

According to the documentation I can break on specific exception type by using conditional breakpoints. However the syntax for the condition isn't very clear to me:
condition bnum <expression>
Looking at the expression syntax I think this is the pattern I need:
{type} addr
However, I don't know what I should pass for the addr argument. I tried the following:
(gdb) catch throw
(gdb) condition 1 boost::bad_function_call *
But it doesn't work (gdb breaks on all exception types).
Can anyone help?
Update
I also tried #Adam's suggestion, but it results in an error message:
(gdb) catch throw boost::bad_function_call
Junk at end of arguments.
Without boost:: namespace:
(gdb) catch throw bad_function_call
Junk at end of arguments.
Workaround
Breaking in the constructor of bad_function_call works.
EDIT
The documentation suggests that catch throw <exceptname> can be used to break whenever an exception of type <exceptname> is thrown; however, that doesn't seem to work in practice.
(gdb) help catch
Set catchpoints to catch events.
Raised signals may be caught:
catch signal - all signals
catch signal <signame> - a particular signal
Raised exceptions may be caught:
catch throw - all exceptions, when thrown
catch throw <exceptname> - a particular exception, when thrown
catch catch - all exceptions, when caught
catch catch <exceptname> - a particular exception, when caught
Thread or process events may be caught:
catch thread_start - any threads, just after creation
catch thread_exit - any threads, just before expiration
catch thread_join - any threads, just after joins
Process events may be caught:
catch start - any processes, just after creation
catch exit - any processes, just before expiration
catch fork - calls to fork()
catch vfork - calls to vfork()
catch exec - calls to exec()
Dynamically-linked library events may be caught:
catch load - loads of any library
catch load <libname> - loads of a particular library
catch unload - unloads of any library
catch unload <libname> - unloads of a particular library
The act of your program's execution stopping may also be caught:
catch stop
C++ exceptions may be caught:
catch throw - all exceptions, when thrown
catch catch - all exceptions, when caught
Ada exceptions may be caught:
catch exception - all exceptions, when raised
catch exception <name> - a particular exception, when raised
catch exception unhandled - all unhandled exceptions, when raised
catch assert - all failed assertions, when raised
Do "help set follow-fork-mode" for info on debugging your program
after a fork or vfork is caught.
Do "help breakpoints" for info on other commands dealing with breakpoints.
When gdb command 'catch throw' fails, try this workaround :
(tested with Linux g++ 4.4.5/gdb 6.6)
1/ Add this code anywhere in the program to debug :
#include <stdexcept>
#include <exception>
#include <typeinfo>
struct __cxa_exception {
std::type_info *inf;
};
struct __cxa_eh_globals {
__cxa_exception *exc;
};
extern "C" __cxa_eh_globals* __cxa_get_globals();
const char* what_exc() {
__cxa_eh_globals* eh = __cxa_get_globals();
if (eh && eh->exc && eh->exc->inf)
return eh->exc->inf->name();
return NULL;
}
2/ In gdb you will then be able to filter exceptions with :
(gdb) break __cxa_begin_catch
(gdb) cond N (what_exc()?strstr(what_exc(),"exception_name"):0!=0)
where N is the breakpoint number, and exception_name is the name of exception for which we wish to break.
From what I have understood from the question here, you want to break when a specific exception boost::bad_function_call is thrown in your application.
$> gdb /path/to/binary
(gdb) break boost::bad_function_call::bad_function_call()
(gdb) run --some-cli-options
So when the temporary object boost::bad_function_call is constructed in preparation for the throw; gdb will break out!
I have tested this and it does work. If you precisely know the way the exception object is being constructed then you can set breakpoint on the specific constructor, otherwise as shown in the example below, you can omit the arguments prototype list, and gdb will set break points on all different flavours of the constructor.
$ gdb /path/to/binary
(gdb) break boost::bad_function_call::bad_function_call
Breakpoint 1 at 0x850f7bf: boost::bad_function_call::bad_function_call. (4 locations)
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y <MULTIPLE>
1.1 y 0x0850f7bf in boost::bad_function_call::bad_function_call() at /usr/include/boost/function/function_base.hpp:742
1.2 y 0x0850fdd5 in boost::bad_function_call::bad_function_call(boost::bad_function_call const&) at /usr/include/boost/function/function_base.hpp:739
1.3 y 0x0863b7d2 <boost::bad_function_call::bad_function_call()+4>
1.4 y 0x086490ee <boost::bad_function_call::bad_function_call(boost::bad_function_call const&)+6>
Another approach is to rely on the tinfo argument available when the catch point is triggered, which is a pointer to the object returned by typeid(type).
So say if I want to catch exception std::bad_alloc being thrown, I could just do:
> p &typeid(std::bad_alloc)
> $1 = (__cxxabiv1::__si_class_type_info *) 0x8c6db60 <typeinfo for std::bad_alloc>
> catch throw if tinfo == 0x8c6db60
Let's assume you have the following code.cpp with a thread that throws an exception:
#include <iostream>
#include <thread>
void thr()
{
while (true) {
new int[1000000000000ul];
}
}
int main(int argc, char* argv[]) {
std::thread t(thr);
t.join();
std::cout << "Hello, World!" << std::endl;
return 0;
}
Compile it with using the following CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(tutorial)
set(CMAKE_CXX_STANDARD 11)
add_executable(test_exceptions main.cpp)
target_link_libraries(test stdc++ pthread)
Now you can play with, running it will give you an abort because of bad_alloc.
Before going on, it's better if you install libstd debug symbols, sudo apt-get install libstdc++6-5-dbg or whatever version you have.
Debug compilation
If you are compiling in Debug you can follow this answer https://stackoverflow.com/a/12434170/5639395 because constructors are usually defined.
Release compilation
If you are compiling in DebWithRelInfo you may not be able to find a proper constructor where to put your breakpoint because of the compiler optimization. In this case, you have some other options. Let's continue.
Source code change solution
If you can change the source code easily, this will work https://stackoverflow.com/a/9363680/5639395
Gdb catch throw easy solution
If you don't want to change the code, you can try to see if catch throw bad_alloc or in general catch throw exception_name works.
Gdb catch throw workaround
I will build on top of this answer https://stackoverflow.com/a/6849989/5639395
We will add a breakpoint in gdb in the function __cxxabiv1::__cxa_throw . This function takes a parameter called tinfo that has the information we need to conditionally check for the exception we care about.
We want something like catch throw if exception==bad_alloc, so how to find the proper comparison?
It turns out that tinfo is a pointer to a structure that has a variable called __name inside. This variable has a string with the mangled name of the exception type.
So we can do something like: catch throw if tinfo->__name == mangled_exception_name
We are almost there!
We need a way to do string comparison, and it turns out gdb has a built-in function $_streq(str1,str2) that does exactly what we need.
The mangled name of the exception is a little harder to find, but you can try to guess it or check the Appendix of this answer. Let's assume for now it is "St9bad_alloc".
The final instruction is:
catch throw if $_streq(tinfo->__name , "St9bad_alloc")
or equivalent
break __cxxabiv1::__cxa_throw if $_streq(tinfo->__name , "St9bad_alloc")
How to find the name of your exception
You have two options
Look for the symbol in the library
Assuming that you installed the libstd debug symbols, you can find the library name like this:
apt search libstd | grep dbg | grep installed
The name is something like this libstdc++6-5-dbg
Now check the files installed:
dpkg -L libstdc++6-5-dbg
Look for something that has a debug in the path, and a .so extension. In my pc I have /usr/lib/x86_64-linux-gnu/debug/libstdc++.so.6.0.21.
Finally, look for the exception you want in there.
nm /usr/lib/x86_64-linux-gnu/debug/libstdc++.so.6.0.21 | grep -i bad_alloc
Or
nm /usr/lib/x86_64-linux-gnu/debug/libstdc++.so.6.0.21 | grep -i runtime_error
etc.
In my case I found something like 00000000003a4b20 V _ZTISt9bad_alloc which suggested me to use "St9bad_alloc" as the name.
Throw it in gdb and inspect the name in there
This is easy, just start gdb, catch throw everything and run the small executable I wrote before. When you are inside gdb, you can issue a p *tinfo and look for the __name description from gdb.
gdb -ex 'file test_exceptions' -ex 'catch throw' -ex 'run'
(gdb) p *tinfo
$1 = {_vptr.type_info = 0x406260 <vtable for __cxxabiv1::__si_class_type_info+16>,
__name = 0x7ffff7b8ae78 <typeinfo name for std::bad_alloc> "St9bad_alloc"}
As others already mentioned this functionality doesn't work in practice. But as workaround you can put condition on catch throw. When exception is thrown we come to __cxa_throw function. It has several parameters pointing to exception class, so we can set condition on one of them. In the sample gdb session below, I put condition on dest parameter of __cxa_throw. The only problem is that value of dest (0x80486ec in this case) is unknown in advance. It can be known, for example, by first running gdb without condition on breakpoint.
[root#localhost ~]#
[root#localhost ~]# gdb ./a.out
GNU gdb (GDB) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/a.out...done.
(gdb) catch throw
Catchpoint 1 (throw)
(gdb) condition 1 dest==0x80486ec
No symbol "dest" in current context.
(gdb) r
warning: failed to reevaluate condition for breakpoint 1: No symbol "dest" in current context.
warning: failed to reevaluate condition for breakpoint 1: No symbol "dest" in current context.
warning: failed to reevaluate condition for breakpoint 1: No symbol "dest" in current context.
Catchpoint 1 (exception thrown), __cxxabiv1::__cxa_throw (obj=0x804a080, tinfo=0x8049ca0, dest=0x80486ec <_ZNSt13runtime_errorD1Ev#plt>) at ../../../../gcc-4.4.3/libstdc++-v3/libsupc++/eh_throw.cc:68
68 ../../../../gcc-4.4.3/libstdc++-v3/libsupc++/eh_throw.cc: No such file or directory.
in ../../../../gcc-4.4.3/libstdc++-v3/libsupc++/eh_throw.cc
(gdb) bt
#0 __cxxabiv1::__cxa_throw (obj=0x804a080, tinfo=0x8049ca0, dest=0x80486ec <_ZNSt13runtime_errorD1Ev#plt>) at ../../../../gcc-4.4.3/libstdc++-v3/libsupc++/eh_throw.cc:68
#1 0x08048940 in main () at test.cpp:14
(gdb) i b
Num Type Disp Enb Address What
1 breakpoint keep y 0x008d9ddb exception throw
stop only if dest==0x80486ec
breakpoint already hit 1 time
(gdb)
Update
You must also load debug info for libstdc++ for this workaround to work.
I'm not sure if this is a recent fix, but with GDB GNU gdb (Debian 9.1-2) 9.1, I have used catch throw std::logical_error successfully. I would hate to generalise prematurely, but it is possible this now works correctly in GDB (April 2020).
I think I can answer the part about setting conditional breaks. I won't answer question regarding exceptions as __raise_exception seems to not exist in g++ 4.5.2 (?)
Let's assume that you have following code (I use void to get something similar to __raise_exception from gdb doc)
void foo(void* x) {
}
int main() {
foo((void*)1);
foo((void*)2);
}
to break at foo(2) you use following commands
(gdb) break foo
Breakpoint 1 at 0x804851c: file q.cpp, line 20.
(gdb) condition 1 x == 2
If you run with
(gdb) r
you will see that it stops on the second foo call, but not on the first one
I think, what they meant in docs is that you set break on function __raise_exception (very implementation dependent)
/* addr is where the exception identifier is stored
id is the exception identifier. */
void __raise_exception (void **addr, void *id);
and then set conditional break on id as described above (you have to somehow determine what is id for yours exception type).
Unfortunately
(gdb) break __raise_exception
results with (g++ 4.5.2)
Function "__raise_exception" not defined.
In case the problem is that there is no valid stack trace (not breaking in raise), it seems to be a problem when re-compiling without re-starting gdb.
( i.e. calling "make" inside the gdb console).
After having re-started gdb, it breaks correctly in raise.c
(my versions : GNU gdb 8.1.0.20180409-git, gcc 7.4.0, GNU make 4.1)