原文地址:https://monoinfinito.wordpress.com/2013/04/02/c-exceptions-under-the-hood-9-catching-our-first-exception/
作者:nicolasbrailo
在上一章我们添加一个_Unwind_可以调用的personality函数,并分析这个personality函数接受的参数。现在是时候向__gxx_personality_v0添加某些真实的行为:在调用__gxx_personality_v0时,我们应该说“是的,这个栈帧确实能够处理这个异常”。
到目前为止,我们已经积累了相当多的经验:我们第一次可以实现一个能够检测何时抛出异常,并宣称“是的,我将处理这个异常”的personality函数。为此,我们必须学习两阶段查找如何工作,因此现在我们可以重新实现我们的personality函数以及我们的抛出测试文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #include <stdio.h> #include "throw.h" struct Fake_Exception {}; void raise() { throw Exception(); } void try_but_dont_catch() { try { raise(); } catch(Fake_Exception&) { printf("Caught a Fake_Exception!\n"); } printf("try_but_dont_catch handled the exception\n"); } void catchit() { try { try_but_dont_catch(); } catch(Exception&) { printf("Caught an Exception!\n"); } printf("catchit handled the exception\n"); } extern "C" { void seppuku() { catchit(); } } |
我们的personality函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | _Unwind_Reason_Code __gxx_personality_v0 ( int version, _Unwind_Action actions, uint64_t exceptionClass, _Unwind_Exception* unwind_exception, _Unwind_Context* context) { if (actions & _UA_SEARCH_PHASE) { printf("Personality function, lookup phase\n"); return _URC_HANDLER_FOUND; } else if (actions & _UA_CLEANUP_PHASE) { printf("Personality function, cleanup\n"); return _URC_INSTALL_CONTEXT; } else { printf("Personality function, error\n"); return _URC_FATAL_PHASE1_ERROR; } } |
备注:你可以从我的github repo下载完整的源代码。
让我们运行看发生什么:
1 2 3 4 5 6 | alloc ex 1 __cxa_throw called Personality function, lookup phase Personality function, cleanup try_but_dont_catch handled the exception catchit handled the exception |
它能工作,但缺少一些东西:在catch/try块里的catch没有执行!这是因为personality函数告诉Unwind“安装一个上下文”(即重新执行),但它从不说是哪个上下文。在这个情形里,在着陆垫后恢复执行是可能的。下次我们将看到我们如何可以使用.gcc_except_table里的信息(我们的老朋友,LSDA)从指定着陆垫恢复执行。