在一个大项目中,很多地方会throw异常,当碰到crash或者抛出异常时,我们需要解决两个问题:
第一:异常的源头:究竟哪里抛出了异常
第二:异常的处理:捕获异常位置
对于异常来说,可能是有我们自己编写的throw触发,也可能是底层库的throw,所以到底是哪里触发的非常难以确认。
所以我们需要解决上述两个问题。
好在,gdb给我们提供了两个重要的命令。
第一个可以使用:
catch throw
第二个可以使用:
catch catch
这样的话,我们便可以处理上述两种场景,快速依据堆栈分析出问题!
除了上述命令,我们可以用help catch列出所有的命令:
catch assert -- Catch failed Ada assertions, when raised.
catch catch -- Catch an exception, when caught.
catch exception -- Catch Ada exceptions, when raised.
catch exec -- Catch calls to exec.
catch fork -- Catch calls to fork.
catch handlers -- Catch Ada exceptions, when handled.
catch load -- Catch loads of shared libraries.
catch rethrow -- Catch an exception, when rethrown.
catch signal -- Catch signals by their names and/or numbers.
catch syscall -- Catch system calls by their names, groups and/or numbers.
catch throw -- Catch an exception, when thrown.
catch unload -- Catch unloads of shared libraries.
catch vfork -- Catch calls to vfork.
值得注意的是,我们可以在上面catch/throw后面加上异常类型。
下面以一个实际的例子来说明:
class MyException : public std::exception {
public:
virtual const char* what() const noexcept { return "This is a custom exception!"; }
};
int main() {
try {
throw MyException();
} catch (const MyException& e) {
std::cerr << "Caught custom exception: " << e.what() << std::endl;
} catch (const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << std::endl;
}
return 0;
}
在这段代码中,我在try里面直接抛出了异常,这里项目中可能是一个函数调用,然后函数的函数里面才会去throw,所以比较难以发现,这里就不模拟的,直接throw,那么如何让gdb停在throw这一行一集catch这一行呢?
这就是上面要说的两个场景调试!
gdb之后,输入:
catch throw
然后允许程序即可,可以看到下面断点到了想要的位置
catch throw MyException
可以只捕获我们期望的类型。
另外,还可以断点__cxa_throw
同理,gdb之后,输入:
catch catch
也可以:
catch catch MyException
__cxa_begin_catch