SlideShare a Scribd company logo
C++ exception handling
C++ exception handling
MaskRay
https://maskray.me
MaskRay (https://maskray.me) C++ exception handling 1 / 22
C++ exception handling
1 Recent work
2 C++ exceptions
3 Exception handling ABI
4 Personality
5 .gcc_except_table
6 End
MaskRay (https://maskray.me) C++ exception handling 2 / 22
C++ exception handling
MaskRay
LLVM contributor
MaskRay (https://maskray.me) C++ exception handling 3 / 22
C++ exception handling
MaskRay
LLVM contributor
https://github.com/MaskRay/ccls (C++ language server)
MaskRay (https://maskray.me) C++ exception handling 3 / 22
C++ exception handling
MaskRay
LLVM contributor
https://github.com/MaskRay/ccls (C++ language server)
Retired Algo/HPC/CTF player
MaskRay (https://maskray.me) C++ exception handling 3 / 22
C++ exception handling
Recent work
Recent work (2020-08-01 to now)
gcov (code coverage)
LLD (linker)
-gz, -cc1as
integrated assembler
debug information
llvm-objcopy --only-keep-debug for Android bionic
profile-guided optimization
language-specific data area (LSDA)
MaskRay (https://maskray.me) C++ exception handling 4 / 22
C++ exception handling
Recent work
gcov
-m: demangled function names
--relative: skip system headers (and other files with absolute
paths)
--source-only prefix
Interaction with -fsanitize=thread: gcov is very early in the
pipeline, Thread Sanitizer is much late.
Optimization: Kirchhoff’s circuit law
https://maskray.me/blog/2020-09-27-gcov-and-llvm
MaskRay (https://maskray.me) C++ exception handling 5 / 22
C++ exception handling
C++ exceptions
C++ exceptions
Non-local jump to an exception handler in an ancestor call frame
The control flow continues to unwind the stack (destructors are called
for all fully-constructed non-static members and base classes)
std::terminate() if no handler exists
MaskRay (https://maskray.me) C++ exception handling 6 / 22
C++ exception handling
C++ exceptions
void foo() { throw 0xB612; }
void bar() { B b; foo(); }
void qux() { try { A a; bar(); } catch (int x) {} }
MaskRay (https://maskray.me) C++ exception handling 7 / 22
C++ exception handling
Exception handling ABI
Itanium C++ ABI: Exception Handling
2 parts: Level 1 Base ABI and Level 2 C++ ABI
Base ABI: stack unwinding, common to all languages
- _Unwind_* (_Unwind_RaiseException (two-phase process),
_Unwind_Resume)
- Impl: .eh_frame_hdr, .eh_frame,
libgcc_s.so.1/libgcc_eh.a/libunwind (--
unwindlib=libunwind)
C++ ABI: interoperability of C++ implementations
- __cxa_* (__cxa_allocate_exception, __cxa_throw,
__cxa_begin_catch), personality, language-specific data area
- Impl: .gcc_except_table, libsupc++, libc++abi.(a|so)
MaskRay (https://maskray.me) C++ exception handling 8 / 22
C++ exception handling
Exception handling ABI
Section representation
.eh_frame
FDE0
initial_location .cfi_personality .cfi_lsda
FDE1
initial_location .cfi_personality .cfi_lsda
FDE2
initial_location
.text._Z1av .text._Z1bv
.text._Z1cv.text.__gxx_personality_v0 .gcc_except_table
.eh_frame contains CIE (Common Information Entry) and FDE
(Frame Description Entry)
CIE references a personality routine in .text
FDE references language-specific data area in .gcc_except_table
Dotted edges are present only if basic block sections or RISC-V
-mrelax, i.e. LSDA normally has no relocation
MaskRay (https://maskray.me) C++ exception handling 9 / 22
C++ exception handling
Exception handling ABI
Walk-through
static _Unwind_Reason_Code unwind_phase1(unw_context_t *uc, _Unwind_Context *ctx,
_Unwind_Exception *obj) {
// Search phase: unwind and call personality with _UA_SEARCH_PHASE for each frame
// until a handler (catch block) is found.
}
static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, _Unwind_Context *ctx,
_Unwind_Exception *obj) {
// Cleanup phase: unwind and call personality with _UA_CLEANUP_PHASE for each frame
// until reaching the handler. Restore the register state and transfer control.
}
_Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception *obj) {
unw_context_t uc; __unw_getcontext(&uc);
_Unwind_Context ctx;
_Unwind_Reason_Code phase1 = unwind_phase1(&uc, &ctx, obj);
if (phase1 != _URC_NO_REASON) return phase1;
unwind_phase2(&uc, &ctx, obj);
}
void __cxa_throw(void *thrown, std::type_info *tinfo, void (*destructor)(void *)) {
uncaughtExceptions++;
__cxa_exception *hdr = (__cxa_exception *)thrown - 1;
hdr->exceptionType = tinfo; hdr->destructor = destructor;
_Unwind_RaiseException(&hdr->unwindHeader);
// Failed to unwind, e.g. the .eh_frame FDE is absent.
__cxa_begin_catch(&hdr->unwindHeader); std::terminate();
}
void foo() { __cxa_exception *thrown = __cxa_allocate_exception(4); *thrown = 42;
__cxa_throw(thrown, &typeid(int), /*destructor=*/nullptr); }
void bar() { B b; qux(); return; landing_pad: b.~B(); _Unwind_Resume(); }
// void qux() { try { A a; bar(); } catch (int x) {} }
void qux() { A a; bar(); return; landing_pad: __cxa_begin_catch(obj); __cxa_end_catch(obj); }
MaskRay (https://maskray.me) C++ exception handling 10 / 22
C++ exception handling
Exception handling ABI
Walk-through
Life of an exception
foo allocates a __cxa_exception object, sets the thrown value, and
calls __cxa_throw
__cxa_throw sets fields in the header (type info, destructor, etc) and
call Base ABI specified _Unwind_RaiseException (on error:
std::terminate())
_Unwind_RaiseException calls unw_phase1 and then unw_phase2
unw_phase1 locates the matching catch block
unw_phase2 transfers control to a cleanup handler
The handler performs cleanup and jumps back via _Unwind_Resume
unw_phase2 eventually transfers control to the matching catch block
The final landing pad returns the exception object via
__cxa_begin_catch
MaskRay (https://maskray.me) C++ exception handling 11 / 22
C++ exception handling
Exception handling ABI
Level 1: Base ABI
// Find .eh_frame CIE/FDE associated with the IP stored in ctx.
// Get personality and LSDA from CIE and FDE.
static void unw_init_local(unw_context_t *uc, _Unwind_Context *ctx) {
Iterate PT_GNU_EH_FRAME (.eh_frame_hdr) and find the one defining IP.
Find the .eh_frame FDE referenced by the .eh_frame_hdr entry.
Find the .eh_frame CIE referenced by the CIE.
ctx->start_ip = fdeInfo.pcStart; ctx->end_ip = fdeInfo.pcEnd;
ctx->lsda = fdeInfo.lsda; ctx->personality = cieInfo.personality;
}
// Execute .cfi_* to restore PC, SP, and other callee-saved registers in ctx
static bool step(_Unwind_Context *ctx) { ... }
static _Unwind_Reason_Code unwind_phase1(unw_context_t *uc, _Unwind_Context *ctx,
_Unwind_Exception *obj) {
unw_init_local(uc, ctx);
for(;;) {
if (ctx->fdeMissing) return _URC_END_OF_STACK;
if (!step(ctx)) return _URC_FATAL_PHASE1_ERROR;
ctx->getFdeAndCieFromIP();
if (!ctx->personality) continue;
switch (ctx->personality(1, _UA_SEARCH_PHASE, obj->exception_class, obj, ctx)) {
case _URC_CONTINUE_UNWIND: break;
case _URC_HANDLER_FOUND:
unw_get_reg(ctx, UNW_REG_SP, &obj->private_2);
return _URC_NO_REASON;
default: return _URC_FATAL_PHASE1_ERROR; // e.g. stack corruption
}
}
return _URC_NO_REASON;
}
MaskRay (https://maskray.me) C++ exception handling 12 / 22
C++ exception handling
Exception handling ABI
Level 1: Base ABI
static void unw_resume(_Unwind_Exception *ctx) {
Jump to a landing pad (cleanup or the matching catch block).
Similar to longjmp: set callee-saved registers, SP and IP.
}
static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, _Unwind_Context *ctx,
_Unwind_Exception *obj) {
unw_init_local(uc, ctx);
for(;;) {
if (ctx->fdeMissing) return _URC_END_OF_STACK;
if (!step(ctx)) return _URC_FATAL_PHASE2_ERROR;
ctx->getFdeAndCieFromIP();
if (!ctx->personality) continue;
_Unwind_Action action = _UA_CLEANUP_PHASE;
size_t sp;
unw_get_reg(ctx, UNW_REG_SP, &sp);
if (sp == obj->private_2) action |= _UA_HANDLER_FRAME;
switch (ctx->personality(1, action, obj->exception_class, obj, ctx)) {
case _URC_CONTINUE_UNWIND:
break;
case _URC_INSTALL_CONTEXT:
unw_resume(ctx); // Return if there is an error
return _URC_FATAL_PHASE2_ERROR;
default: return _URC_FATAL_PHASE2_ERROR; // Unknown result code
}
}
return _URC_FATAL_PHASE2_ERROR;
}
MaskRay (https://maskray.me) C++ exception handling 13 / 22
C++ exception handling
Personality
Personality
Bridge between Level 1 Base ABI and Level 2 C++ ABI
In C++, usually __gxx_personality_v0 (sjlj:
__gxx_personality_sj0)
GCC libstdc++-v3/libsupc++/eh_personality.cc and libc+
+abi, defined in src/cxa_personality.cpp
__gxx_personality_v0 parses the referenced .gcc_except_table
piece, locates the call-site code range, and executes specified actions
(e.g. jump to a label).
Roughly, the function is partitioned by try into multiple code ranges.
MaskRay (https://maskray.me) C++ exception handling 14 / 22
C++ exception handling
.gcc_except_table
.gcc_except_table
Interpreted by __gxx_personality_v0
For each code range, describe the landing pad (catch block) and
actions (e.g. skip if type mismatch)
Header + call-site records + action records
call-site record: call site, landing pad, action record (1 indicates the
start)
action record: type filter, next action record
MaskRay (https://maskray.me) C++ exception handling 15 / 22
C++ exception handling
.gcc_except_table
main: # @main
.Lfunc_begin0:
.cfi_startproc
.cfi_personality 3, __gxx_personality_v0
.cfi_lsda 3, .Lexception0
# %bb.0: # %entry
pushq %rax
.cfi_def_cfa_offset 16
.Ltmp0:
callq _Z2fbv # try region
.Ltmp1:
.LBB0_2:
xorl %eax, %eax
popq %rcx
.cfi_def_cfa_offset 8
retq
.LBB0_1: # landing pad
.cfi_def_cfa_offset 16
.Ltmp2:
movq %rax, %rdi
callq __cxa_begin_catch
movl (%rax), %esi
movl $.L.str, %edi
xorl %eax, %eax
callq printf
callq __cxa_end_catch
jmp .LBB0_2
.Lfunc_end0:
.size main, .Lfunc_end0-main
.cfi_endproc
MaskRay (https://maskray.me) C++ exception handling 16 / 22
C++ exception handling
.gcc_except_table
.section .gcc_except_table,"a",@progbits
.p2align 2
GCC_except_table0:
.Lexception0:
.byte 255 # @LPStart Encoding = omit
.byte 3 # @TType Encoding = udata4
.uleb128 .Lttbase0-.Lttbaseref0 # The start of action records
.Lttbaseref0:
.byte 1 # Call site Encoding = uleb128
.uleb128 .Lcst_end0-.Lcst_begin0
.Lcst_begin0: # 2 call site code ranges
.uleb128 .Ltmp0-.Lfunc_begin0 # >> Call Site 1 <<
.uleb128 .Ltmp1-.Ltmp0 # Call between .Ltmp0 and .Ltmp1
.uleb128 .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2
.byte 1 # On action: 1
.uleb128 .Ltmp1-.Lfunc_begin0 # >> Call Site 2 <<
.uleb128 .Lfunc_end0-.Ltmp1 # Call between .Ltmp1 and .Lfunc_end0
.byte 0 # has no landing pad
.byte 0 # On action: cleanup
.Lcst_end0:
.byte 1 # >> Action Record 1 <<
# Catch TypeInfo 1
.byte 0 # No further actions
.p2align 2
# >> Catch TypeInfos <<
.long _ZTIi # TypeInfo 1
.Lttbase0:
MaskRay (https://maskray.me) C++ exception handling 17 / 22
C++ exception handling
.gcc_except_table
Monolithic .gcc_except_table
As of Clang 11, there is one monolithic .gcc_except_table
Linker --gc-sections: input sections are atoms
Unused .gcc_except_table (the ”referenced” .text sections are
discarded) cannot be discarded
.eh_frame
FDE0
initial_location .cfi_personality .cfi_lsda
FDE1
initial_location .cfi_personality .cfi_lsda
FDE2
initial_location
.text._Z1av .text._Z1bv
.text._Z1cv.text.__gxx_personality_v0 .gcc_except_table
Edges represent relocations
unused
.eh_frame FDE0
.gcc_except_table
lsda_a lsda_b
.eh_frame FDE1
MaskRay (https://maskray.me) C++ exception handling 18 / 22
C++ exception handling
.gcc_except_table
Fragmented .gcc_except_table
https://reviews.llvm.org/D83655: Split up
.gcc_except_table
Edges represent relocations
unused
.eh_frame FDE0
.gcc_except_table
lsda_a lsda_b
.eh_frame FDE1
Edges represent relocations
unused
.eh_frame FDE0
.gcc_except_table._Z1av
.eh_frame FDE1
.gcc_except_table._Z1bv
MaskRay (https://maskray.me) C++ exception handling 19 / 22
C++ exception handling
.gcc_except_table
Is that so simple?
No! .text.* in COMDAT groups cannot be GCed with fragmented
.gcc_except_table.* (code size increase)
LLD handles --gc-sections before GCing .eh_frame
During GC, all pieces in .eh_frame are live (GC root). They mark all
.gcc_except_table.* live
A .gcc_except_table.* marks other members (.text.*) in the
same group live (linker rule)
Edges represent GC references
.eh_frame (GC root)
.gcc_except_table .gcc_except_table._Z1av .gcc_except_table._Z1bv
.text._Z1av .text._Z1bv
MaskRay (https://maskray.me) C++ exception handling 20 / 22
C++ exception handling
.gcc_except_table
Let’s fix LLD!
https://reviews.llvm.org/D91579: for .eh_frame, don’t mark
.gcc_except_table within a COMDAT group
Edges represent GC references
.eh_frame (GC root)
.gcc_except_table
.text._Z1av
.gcc_except_table._Z1av
.text._Z1bv
.gcc_except_table._Z1bv
MaskRay (https://maskray.me) C++ exception handling 21 / 22
C++ exception handling
End
Future work
Clang .gcc_except_table is inefficient for pass-through purposes.
GCC produces header-only LSDA (4 bytes).
Clang/LLD interop: garbage collect unused .gcc_except_table not
within COMDAT groups
Efficient (space/performance) .eh_frame (very difficult; (current)
compact unwinding has lots of limitations;
https://maskray.me/blog/2020-11-08-stack-unwinding)
MaskRay (https://maskray.me) C++ exception handling 22 / 22

More Related Content

PDF
EXCEPTION HANDLING in C++
PDF
Exception Handling
PPT
Handling Exceptions In C &amp; C++[Part A]
PDF
Exception Handling in the C++ Constructor
PPS
Exception handling in c programming
PPTX
exception handling in cpp
PPT
Handling Exceptions In C &amp; C++ [Part B] Ver 2
PPT
Exceptions in c++
EXCEPTION HANDLING in C++
Exception Handling
Handling Exceptions In C &amp; C++[Part A]
Exception Handling in the C++ Constructor
Exception handling in c programming
exception handling in cpp
Handling Exceptions In C &amp; C++ [Part B] Ver 2
Exceptions in c++

What's hot (20)

PPTX
Exception handling chapter15
PPT
Exception handling and templates
PPT
Week7 exception handling
PPT
Exception handling
PPT
Unit iii
PPTX
Exception handling c++
PDF
Exception handling
PPT
Exception handling in c++ by manoj vasava
PPT
Exception handling
PPTX
Exception handling in c++
PDF
Exception handling
PPTX
CodeChecker summary 21062021
PPT
Exception handling
PDF
Exceptions and Exception Handling in C++
PPT
F6dc1 session6 c++
PPT
Exception Handling
PPTX
Java exception handling
PPT
Exceptions in java
PPTX
130410107010 exception handling
PPT
Exception Handling in JAVA
Exception handling chapter15
Exception handling and templates
Week7 exception handling
Exception handling
Unit iii
Exception handling c++
Exception handling
Exception handling in c++ by manoj vasava
Exception handling
Exception handling in c++
Exception handling
CodeChecker summary 21062021
Exception handling
Exceptions and Exception Handling in C++
F6dc1 session6 c++
Exception Handling
Java exception handling
Exceptions in java
130410107010 exception handling
Exception Handling in JAVA
Ad

Similar to C++ exception handling (20)

PPTX
Дмитрий Демчук. Кроссплатформенный краш-репорт
PDF
Part II: LLVM Intermediate Representation
PPTX
Building Efficient and Highly Run-Time Adaptable Virtual Machines
PDF
ceph::errorator<> throw/catch-free, compile time-checked exceptions for seast...
KEY
Post Exploitation Bliss: Loading Meterpreter on a Factory iPhone, Black Hat U...
PDF
Bytes in the Machine: Inside the CPython interpreter
PDF
ClojureScript loves React, DomCode May 26 2015
PPTX
6-Exception Handling and Templates.pptx
PDF
Crash_Report_Mechanism_In_Tizen
PDF
Message in a bottle
KEY
DjangoCon US 2011 - Monkeying around at New Relic
KEY
Djangocon11: Monkeying around at New Relic
PDF
掀起 Swift 的面紗
PDF
Deterministic simulation testing
PDF
Boosting Developer Productivity with Clang
DOCX
2.1 ### uVision Project, (C) Keil Software .docx
PPTX
Things about Functional JavaScript
PPT
Deuce STM - CMP'09
PDF
Linux seccomp(2) vs OpenBSD pledge(2)
KEY
What's New In Python 2.6
Дмитрий Демчук. Кроссплатформенный краш-репорт
Part II: LLVM Intermediate Representation
Building Efficient and Highly Run-Time Adaptable Virtual Machines
ceph::errorator<> throw/catch-free, compile time-checked exceptions for seast...
Post Exploitation Bliss: Loading Meterpreter on a Factory iPhone, Black Hat U...
Bytes in the Machine: Inside the CPython interpreter
ClojureScript loves React, DomCode May 26 2015
6-Exception Handling and Templates.pptx
Crash_Report_Mechanism_In_Tizen
Message in a bottle
DjangoCon US 2011 - Monkeying around at New Relic
Djangocon11: Monkeying around at New Relic
掀起 Swift 的面紗
Deterministic simulation testing
Boosting Developer Productivity with Clang
2.1 ### uVision Project, (C) Keil Software .docx
Things about Functional JavaScript
Deuce STM - CMP'09
Linux seccomp(2) vs OpenBSD pledge(2)
What's New In Python 2.6
Ad

More from Ray Song (9)

PDF
RISC-V Linker Relaxation and LLD
PDF
gcov和clang中的实现
PDF
r2con 2017 r2cLEMENCy
PDF
Cyber Grand Challenge及DEFCON 24 CTF决赛介绍
PDF
OI算法竞赛中树形数据结构
PDF
Implementing a Simple Interpreter
PDF
2011年信息学竞赛冬令营《星际探险》
PDF
8门编程语言的设计思考
PDF
Introduction to makefile
RISC-V Linker Relaxation and LLD
gcov和clang中的实现
r2con 2017 r2cLEMENCy
Cyber Grand Challenge及DEFCON 24 CTF决赛介绍
OI算法竞赛中树形数据结构
Implementing a Simple Interpreter
2011年信息学竞赛冬令营《星际探险》
8门编程语言的设计思考
Introduction to makefile

Recently uploaded (20)

PDF
Design an Analysis of Algorithms I-SECS-1021-03
PDF
System and Network Administration Chapter 2
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PDF
Understanding Forklifts - TECH EHS Solution
PDF
Softaken Excel to vCard Converter Software.pdf
PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 41
PPTX
CHAPTER 2 - PM Management and IT Context
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PPTX
Introduction to Artificial Intelligence
PDF
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
PPTX
VVF-Customer-Presentation2025-Ver1.9.pptx
PPTX
Odoo POS Development Services by CandidRoot Solutions
PDF
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
PPTX
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PDF
Adobe Illustrator 28.6 Crack My Vision of Vector Design
Design an Analysis of Algorithms I-SECS-1021-03
System and Network Administration Chapter 2
Wondershare Filmora 15 Crack With Activation Key [2025
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
Understanding Forklifts - TECH EHS Solution
Softaken Excel to vCard Converter Software.pdf
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
Internet Downloader Manager (IDM) Crack 6.42 Build 41
CHAPTER 2 - PM Management and IT Context
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
Introduction to Artificial Intelligence
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
VVF-Customer-Presentation2025-Ver1.9.pptx
Odoo POS Development Services by CandidRoot Solutions
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
Design an Analysis of Algorithms II-SECS-1021-03
Adobe Illustrator 28.6 Crack My Vision of Vector Design

C++ exception handling

  • 1. C++ exception handling C++ exception handling MaskRay https://maskray.me MaskRay (https://maskray.me) C++ exception handling 1 / 22
  • 2. C++ exception handling 1 Recent work 2 C++ exceptions 3 Exception handling ABI 4 Personality 5 .gcc_except_table 6 End MaskRay (https://maskray.me) C++ exception handling 2 / 22
  • 3. C++ exception handling MaskRay LLVM contributor MaskRay (https://maskray.me) C++ exception handling 3 / 22
  • 4. C++ exception handling MaskRay LLVM contributor https://github.com/MaskRay/ccls (C++ language server) MaskRay (https://maskray.me) C++ exception handling 3 / 22
  • 5. C++ exception handling MaskRay LLVM contributor https://github.com/MaskRay/ccls (C++ language server) Retired Algo/HPC/CTF player MaskRay (https://maskray.me) C++ exception handling 3 / 22
  • 6. C++ exception handling Recent work Recent work (2020-08-01 to now) gcov (code coverage) LLD (linker) -gz, -cc1as integrated assembler debug information llvm-objcopy --only-keep-debug for Android bionic profile-guided optimization language-specific data area (LSDA) MaskRay (https://maskray.me) C++ exception handling 4 / 22
  • 7. C++ exception handling Recent work gcov -m: demangled function names --relative: skip system headers (and other files with absolute paths) --source-only prefix Interaction with -fsanitize=thread: gcov is very early in the pipeline, Thread Sanitizer is much late. Optimization: Kirchhoff’s circuit law https://maskray.me/blog/2020-09-27-gcov-and-llvm MaskRay (https://maskray.me) C++ exception handling 5 / 22
  • 8. C++ exception handling C++ exceptions C++ exceptions Non-local jump to an exception handler in an ancestor call frame The control flow continues to unwind the stack (destructors are called for all fully-constructed non-static members and base classes) std::terminate() if no handler exists MaskRay (https://maskray.me) C++ exception handling 6 / 22
  • 9. C++ exception handling C++ exceptions void foo() { throw 0xB612; } void bar() { B b; foo(); } void qux() { try { A a; bar(); } catch (int x) {} } MaskRay (https://maskray.me) C++ exception handling 7 / 22
  • 10. C++ exception handling Exception handling ABI Itanium C++ ABI: Exception Handling 2 parts: Level 1 Base ABI and Level 2 C++ ABI Base ABI: stack unwinding, common to all languages - _Unwind_* (_Unwind_RaiseException (two-phase process), _Unwind_Resume) - Impl: .eh_frame_hdr, .eh_frame, libgcc_s.so.1/libgcc_eh.a/libunwind (-- unwindlib=libunwind) C++ ABI: interoperability of C++ implementations - __cxa_* (__cxa_allocate_exception, __cxa_throw, __cxa_begin_catch), personality, language-specific data area - Impl: .gcc_except_table, libsupc++, libc++abi.(a|so) MaskRay (https://maskray.me) C++ exception handling 8 / 22
  • 11. C++ exception handling Exception handling ABI Section representation .eh_frame FDE0 initial_location .cfi_personality .cfi_lsda FDE1 initial_location .cfi_personality .cfi_lsda FDE2 initial_location .text._Z1av .text._Z1bv .text._Z1cv.text.__gxx_personality_v0 .gcc_except_table .eh_frame contains CIE (Common Information Entry) and FDE (Frame Description Entry) CIE references a personality routine in .text FDE references language-specific data area in .gcc_except_table Dotted edges are present only if basic block sections or RISC-V -mrelax, i.e. LSDA normally has no relocation MaskRay (https://maskray.me) C++ exception handling 9 / 22
  • 12. C++ exception handling Exception handling ABI Walk-through static _Unwind_Reason_Code unwind_phase1(unw_context_t *uc, _Unwind_Context *ctx, _Unwind_Exception *obj) { // Search phase: unwind and call personality with _UA_SEARCH_PHASE for each frame // until a handler (catch block) is found. } static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, _Unwind_Context *ctx, _Unwind_Exception *obj) { // Cleanup phase: unwind and call personality with _UA_CLEANUP_PHASE for each frame // until reaching the handler. Restore the register state and transfer control. } _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception *obj) { unw_context_t uc; __unw_getcontext(&uc); _Unwind_Context ctx; _Unwind_Reason_Code phase1 = unwind_phase1(&uc, &ctx, obj); if (phase1 != _URC_NO_REASON) return phase1; unwind_phase2(&uc, &ctx, obj); } void __cxa_throw(void *thrown, std::type_info *tinfo, void (*destructor)(void *)) { uncaughtExceptions++; __cxa_exception *hdr = (__cxa_exception *)thrown - 1; hdr->exceptionType = tinfo; hdr->destructor = destructor; _Unwind_RaiseException(&hdr->unwindHeader); // Failed to unwind, e.g. the .eh_frame FDE is absent. __cxa_begin_catch(&hdr->unwindHeader); std::terminate(); } void foo() { __cxa_exception *thrown = __cxa_allocate_exception(4); *thrown = 42; __cxa_throw(thrown, &typeid(int), /*destructor=*/nullptr); } void bar() { B b; qux(); return; landing_pad: b.~B(); _Unwind_Resume(); } // void qux() { try { A a; bar(); } catch (int x) {} } void qux() { A a; bar(); return; landing_pad: __cxa_begin_catch(obj); __cxa_end_catch(obj); } MaskRay (https://maskray.me) C++ exception handling 10 / 22
  • 13. C++ exception handling Exception handling ABI Walk-through Life of an exception foo allocates a __cxa_exception object, sets the thrown value, and calls __cxa_throw __cxa_throw sets fields in the header (type info, destructor, etc) and call Base ABI specified _Unwind_RaiseException (on error: std::terminate()) _Unwind_RaiseException calls unw_phase1 and then unw_phase2 unw_phase1 locates the matching catch block unw_phase2 transfers control to a cleanup handler The handler performs cleanup and jumps back via _Unwind_Resume unw_phase2 eventually transfers control to the matching catch block The final landing pad returns the exception object via __cxa_begin_catch MaskRay (https://maskray.me) C++ exception handling 11 / 22
  • 14. C++ exception handling Exception handling ABI Level 1: Base ABI // Find .eh_frame CIE/FDE associated with the IP stored in ctx. // Get personality and LSDA from CIE and FDE. static void unw_init_local(unw_context_t *uc, _Unwind_Context *ctx) { Iterate PT_GNU_EH_FRAME (.eh_frame_hdr) and find the one defining IP. Find the .eh_frame FDE referenced by the .eh_frame_hdr entry. Find the .eh_frame CIE referenced by the CIE. ctx->start_ip = fdeInfo.pcStart; ctx->end_ip = fdeInfo.pcEnd; ctx->lsda = fdeInfo.lsda; ctx->personality = cieInfo.personality; } // Execute .cfi_* to restore PC, SP, and other callee-saved registers in ctx static bool step(_Unwind_Context *ctx) { ... } static _Unwind_Reason_Code unwind_phase1(unw_context_t *uc, _Unwind_Context *ctx, _Unwind_Exception *obj) { unw_init_local(uc, ctx); for(;;) { if (ctx->fdeMissing) return _URC_END_OF_STACK; if (!step(ctx)) return _URC_FATAL_PHASE1_ERROR; ctx->getFdeAndCieFromIP(); if (!ctx->personality) continue; switch (ctx->personality(1, _UA_SEARCH_PHASE, obj->exception_class, obj, ctx)) { case _URC_CONTINUE_UNWIND: break; case _URC_HANDLER_FOUND: unw_get_reg(ctx, UNW_REG_SP, &obj->private_2); return _URC_NO_REASON; default: return _URC_FATAL_PHASE1_ERROR; // e.g. stack corruption } } return _URC_NO_REASON; } MaskRay (https://maskray.me) C++ exception handling 12 / 22
  • 15. C++ exception handling Exception handling ABI Level 1: Base ABI static void unw_resume(_Unwind_Exception *ctx) { Jump to a landing pad (cleanup or the matching catch block). Similar to longjmp: set callee-saved registers, SP and IP. } static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, _Unwind_Context *ctx, _Unwind_Exception *obj) { unw_init_local(uc, ctx); for(;;) { if (ctx->fdeMissing) return _URC_END_OF_STACK; if (!step(ctx)) return _URC_FATAL_PHASE2_ERROR; ctx->getFdeAndCieFromIP(); if (!ctx->personality) continue; _Unwind_Action action = _UA_CLEANUP_PHASE; size_t sp; unw_get_reg(ctx, UNW_REG_SP, &sp); if (sp == obj->private_2) action |= _UA_HANDLER_FRAME; switch (ctx->personality(1, action, obj->exception_class, obj, ctx)) { case _URC_CONTINUE_UNWIND: break; case _URC_INSTALL_CONTEXT: unw_resume(ctx); // Return if there is an error return _URC_FATAL_PHASE2_ERROR; default: return _URC_FATAL_PHASE2_ERROR; // Unknown result code } } return _URC_FATAL_PHASE2_ERROR; } MaskRay (https://maskray.me) C++ exception handling 13 / 22
  • 16. C++ exception handling Personality Personality Bridge between Level 1 Base ABI and Level 2 C++ ABI In C++, usually __gxx_personality_v0 (sjlj: __gxx_personality_sj0) GCC libstdc++-v3/libsupc++/eh_personality.cc and libc+ +abi, defined in src/cxa_personality.cpp __gxx_personality_v0 parses the referenced .gcc_except_table piece, locates the call-site code range, and executes specified actions (e.g. jump to a label). Roughly, the function is partitioned by try into multiple code ranges. MaskRay (https://maskray.me) C++ exception handling 14 / 22
  • 17. C++ exception handling .gcc_except_table .gcc_except_table Interpreted by __gxx_personality_v0 For each code range, describe the landing pad (catch block) and actions (e.g. skip if type mismatch) Header + call-site records + action records call-site record: call site, landing pad, action record (1 indicates the start) action record: type filter, next action record MaskRay (https://maskray.me) C++ exception handling 15 / 22
  • 18. C++ exception handling .gcc_except_table main: # @main .Lfunc_begin0: .cfi_startproc .cfi_personality 3, __gxx_personality_v0 .cfi_lsda 3, .Lexception0 # %bb.0: # %entry pushq %rax .cfi_def_cfa_offset 16 .Ltmp0: callq _Z2fbv # try region .Ltmp1: .LBB0_2: xorl %eax, %eax popq %rcx .cfi_def_cfa_offset 8 retq .LBB0_1: # landing pad .cfi_def_cfa_offset 16 .Ltmp2: movq %rax, %rdi callq __cxa_begin_catch movl (%rax), %esi movl $.L.str, %edi xorl %eax, %eax callq printf callq __cxa_end_catch jmp .LBB0_2 .Lfunc_end0: .size main, .Lfunc_end0-main .cfi_endproc MaskRay (https://maskray.me) C++ exception handling 16 / 22
  • 19. C++ exception handling .gcc_except_table .section .gcc_except_table,"a",@progbits .p2align 2 GCC_except_table0: .Lexception0: .byte 255 # @LPStart Encoding = omit .byte 3 # @TType Encoding = udata4 .uleb128 .Lttbase0-.Lttbaseref0 # The start of action records .Lttbaseref0: .byte 1 # Call site Encoding = uleb128 .uleb128 .Lcst_end0-.Lcst_begin0 .Lcst_begin0: # 2 call site code ranges .uleb128 .Ltmp0-.Lfunc_begin0 # >> Call Site 1 << .uleb128 .Ltmp1-.Ltmp0 # Call between .Ltmp0 and .Ltmp1 .uleb128 .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2 .byte 1 # On action: 1 .uleb128 .Ltmp1-.Lfunc_begin0 # >> Call Site 2 << .uleb128 .Lfunc_end0-.Ltmp1 # Call between .Ltmp1 and .Lfunc_end0 .byte 0 # has no landing pad .byte 0 # On action: cleanup .Lcst_end0: .byte 1 # >> Action Record 1 << # Catch TypeInfo 1 .byte 0 # No further actions .p2align 2 # >> Catch TypeInfos << .long _ZTIi # TypeInfo 1 .Lttbase0: MaskRay (https://maskray.me) C++ exception handling 17 / 22
  • 20. C++ exception handling .gcc_except_table Monolithic .gcc_except_table As of Clang 11, there is one monolithic .gcc_except_table Linker --gc-sections: input sections are atoms Unused .gcc_except_table (the ”referenced” .text sections are discarded) cannot be discarded .eh_frame FDE0 initial_location .cfi_personality .cfi_lsda FDE1 initial_location .cfi_personality .cfi_lsda FDE2 initial_location .text._Z1av .text._Z1bv .text._Z1cv.text.__gxx_personality_v0 .gcc_except_table Edges represent relocations unused .eh_frame FDE0 .gcc_except_table lsda_a lsda_b .eh_frame FDE1 MaskRay (https://maskray.me) C++ exception handling 18 / 22
  • 21. C++ exception handling .gcc_except_table Fragmented .gcc_except_table https://reviews.llvm.org/D83655: Split up .gcc_except_table Edges represent relocations unused .eh_frame FDE0 .gcc_except_table lsda_a lsda_b .eh_frame FDE1 Edges represent relocations unused .eh_frame FDE0 .gcc_except_table._Z1av .eh_frame FDE1 .gcc_except_table._Z1bv MaskRay (https://maskray.me) C++ exception handling 19 / 22
  • 22. C++ exception handling .gcc_except_table Is that so simple? No! .text.* in COMDAT groups cannot be GCed with fragmented .gcc_except_table.* (code size increase) LLD handles --gc-sections before GCing .eh_frame During GC, all pieces in .eh_frame are live (GC root). They mark all .gcc_except_table.* live A .gcc_except_table.* marks other members (.text.*) in the same group live (linker rule) Edges represent GC references .eh_frame (GC root) .gcc_except_table .gcc_except_table._Z1av .gcc_except_table._Z1bv .text._Z1av .text._Z1bv MaskRay (https://maskray.me) C++ exception handling 20 / 22
  • 23. C++ exception handling .gcc_except_table Let’s fix LLD! https://reviews.llvm.org/D91579: for .eh_frame, don’t mark .gcc_except_table within a COMDAT group Edges represent GC references .eh_frame (GC root) .gcc_except_table .text._Z1av .gcc_except_table._Z1av .text._Z1bv .gcc_except_table._Z1bv MaskRay (https://maskray.me) C++ exception handling 21 / 22
  • 24. C++ exception handling End Future work Clang .gcc_except_table is inefficient for pass-through purposes. GCC produces header-only LSDA (4 bytes). Clang/LLD interop: garbage collect unused .gcc_except_table not within COMDAT groups Efficient (space/performance) .eh_frame (very difficult; (current) compact unwinding has lots of limitations; https://maskray.me/blog/2020-11-08-stack-unwinding) MaskRay (https://maskray.me) C++ exception handling 22 / 22