信号处理函数中的异常
当程序因未处理C++异常而终止时,有时候可以使用调试器查找抛出异常的位置。但是如果异常是在信号处理函数中抛出的,这将会比平常困难的多。
本小节组要介绍使用gdb调试器在Linux系统上调试异常。
首先让我们看一个简单的示例,其中的一个普通函数(非信号处理函数)抛出异常:
// without_signal.cc #include <gtkmm.h> bool throwSomething() { throw "Something"; return true; } int main(int argc, char** argv) { throwSomething(); auto app = Gtk::Application::create("org.gtkmm.without_signal"); return app->run(); }
这是gdb会话的摘要。只显示输出中最有趣的部分:
> gdb without_signal (gdb) run terminate called after throwing an instance of 'char const*' Program received signal SIGABRT, Aborted. (gdb) backtrace #7 0x08048864 in throwSomething () at without_signal.cc:6 #8 0x0804887d in main (argc=1, argv=0xbfffecd4) at without_signal.cc:12
现在,让我们看看从信号处理函数中抛出异常会发生什么。这是源代码:
// with_signal.cc #include <gtkmm.h> bool throwSomething() { throw "Something"; return true; } int main(int argc, char** argv) { Glib::signal_timeout().connect(sigc::ptr_fun(throwSomething), 500); auto app = Gtk::Application::create("org.gtkmm.with_signal"); app->hold(); return app->run(); }
这是gdb会话的摘录:
> gdb with_signal (gdb) run (with_signal:2703): glibmm-ERROR **: unhandled exception (type unknown) in signal handler Program received signal SIGTRAP, Trace/breakpoint trap. (gdb) backtrace #2 0x0063c6ab in glibmm_unexpected_exception () at exceptionhandler.cc:77 #3 Glib::exception_handlers_invoke () at exceptionhandler.cc:150 #4 0x0063d370 in glibmm_source_callback (data=0x804d620) at main.cc:212 #13 0x002e1b31 in Gtk::Application::run (this=0x804f300) at application.cc:178 #14 0x08048ccc in main (argc=1, argv=0xbfffecd4) at with_signal.cc:16
要查看哪里抛出了异常,你可以使用gdb的catch throw命令。
> gdb with_signal (gdb) catch throw Catchpoint 1 (throw) (gdb) run Catchpoint 1 (exception thrown), 0x00714ff0 in __cxa_throw () (gdb) backtrace #0 0x00714ff0 in __cxa_throw () from /usr/lib/i386-linux-gnu/libstdc++.so.6 #1 0x08048bd4 in throwSomething () at with_signal.cc:6 (gdb) continue Continuing. (with_signal:2375): glibmm-ERROR ** unhandled exception (type unknown) in signal handler Program received signal SIGTRAP, Trace/breakpoint trap.
如果在感兴趣的未捕获异常之前有多个捕获异常,这个方法将会非常的枯燥。可以使用以下gdb命令自动化进行这个工作。
(gdb) catch throw (gdb) commands (gdb) backtrace (gdb) continue (gdb) end (gdb) set pagination off (gdb) run