[llvm] [BOLT] Fix C++ exceptions when LPStart is specified (PR #72737)

Maksim Panchenko via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 20 10:40:42 PST 2023


https://github.com/maksfb updated https://github.com/llvm/llvm-project/pull/72737

>From 5f84266b4ba1878d373b6347f52a80a6453cd3da Mon Sep 17 00:00:00 2001
From: Maksim Panchenko <maks at fb.com>
Date: Fri, 17 Nov 2023 16:15:28 -0800
Subject: [PATCH 1/2] [BOLT] Fix C++ exceptions when LPStart is specified

Whenever LPStartEncoding was different from DW_EH_PE_omit, we used to
miscalculate LPStart. As a result, landing pads were assigned wrong
addresses. Fix that.
---
 bolt/lib/Core/Exceptions.cpp                  |  61 +++++-----
 .../runtime/X86/exceptions-lpstart-zero.s     | 107 ++++++++++++++++++
 2 files changed, 140 insertions(+), 28 deletions(-)
 create mode 100644 bolt/test/runtime/X86/exceptions-lpstart-zero.s

diff --git a/bolt/lib/Core/Exceptions.cpp b/bolt/lib/Core/Exceptions.cpp
index 657c3137ae9d62c..993f3a7770aa817 100644
--- a/bolt/lib/Core/Exceptions.cpp
+++ b/bolt/lib/Core/Exceptions.cpp
@@ -112,13 +112,18 @@ void BinaryFunction::parseLSDA(ArrayRef<uint8_t> LSDASectionData,
   uint64_t Offset = getLSDAAddress() - LSDASectionAddress;
   assert(Data.isValidOffset(Offset) && "wrong LSDA address");
 
-  uint8_t LPStartEncoding = Data.getU8(&Offset);
-  uint64_t LPStart = 0;
-  // Convert to offset if LPStartEncoding is typed absptr DW_EH_PE_absptr
-  if (std::optional<uint64_t> MaybeLPStart = Data.getEncodedPointer(
-          &Offset, LPStartEncoding, Offset + LSDASectionAddress))
-    LPStart = (LPStartEncoding && 0xFF == 0) ? *MaybeLPStart
-                                             : *MaybeLPStart - Address;
+  const uint8_t LPStartEncoding = Data.getU8(&Offset);
+  uint64_t LPStart = Address;
+  if (LPStartEncoding != dwarf::DW_EH_PE_omit) {
+    std::optional<uint64_t> MaybeLPStart = Data.getEncodedPointer(
+        &Offset, LPStartEncoding, Offset + LSDASectionAddress);
+    if (!MaybeLPStart) {
+      errs() << "BOLT-ERROR: unsupported LPStartEncoding: "
+             << (unsigned)LPStartEncoding << '\n';
+      exit(1);
+    }
+    LPStart = *MaybeLPStart;
+  }
 
   const uint8_t TTypeEncoding = Data.getU8(&Offset);
   LSDATypeEncoding = TTypeEncoding;
@@ -175,30 +180,13 @@ void BinaryFunction::parseLSDA(ArrayRef<uint8_t> LSDASectionData,
     uint64_t LandingPad = *Data.getEncodedPointer(
         &CallSitePtr, CallSiteEncoding, CallSitePtr + LSDASectionAddress);
     uint64_t ActionEntry = Data.getULEB128(&CallSitePtr);
-
-    uint64_t LPOffset = LPStart + LandingPad;
-    uint64_t LPAddress = Address + LPOffset;
-
-    // Verify if landing pad code is located outside current function
-    // Support landing pad to builtin_unreachable
-    if (LPAddress < Address || LPAddress > Address + getSize()) {
-      BinaryFunction *Fragment =
-          BC.getBinaryFunctionContainingAddress(LPAddress);
-      assert(Fragment != nullptr &&
-             "BOLT-ERROR: cannot find landing pad fragment");
-      BC.addInterproceduralReference(this, Fragment->getAddress());
-      BC.processInterproceduralReferences();
-      assert(isParentOrChildOf(*Fragment) &&
-             "BOLT-ERROR: cannot have landing pads in different functions");
-      setHasIndirectTargetToSplitFragment(true);
-      BC.addFragmentsToSkip(this);
-      return;
-    }
+    if (LandingPad)
+      LandingPad += LPStart;
 
     if (opts::PrintExceptions) {
       outs() << "Call Site: [0x" << Twine::utohexstr(RangeBase + Start)
              << ", 0x" << Twine::utohexstr(RangeBase + Start + Length)
-             << "); landing pad: 0x" << Twine::utohexstr(LPOffset)
+             << "); landing pad: 0x" << Twine::utohexstr(LandingPad)
              << "; action entry: 0x" << Twine::utohexstr(ActionEntry) << "\n";
       outs() << "  current offset is " << (CallSitePtr - CallSiteTableStart)
              << '\n';
@@ -206,7 +194,24 @@ void BinaryFunction::parseLSDA(ArrayRef<uint8_t> LSDASectionData,
 
     // Create a handler entry if necessary.
     MCSymbol *LPSymbol = nullptr;
-    if (LPOffset) {
+    if (LandingPad) {
+      // Verify if landing pad code is located outside current function
+      // Support landing pad to builtin_unreachable
+      if (LandingPad < Address || LandingPad > Address + getSize()) {
+        BinaryFunction *Fragment =
+            BC.getBinaryFunctionContainingAddress(LandingPad);
+        assert(Fragment != nullptr &&
+               "BOLT-ERROR: cannot find landing pad fragment");
+        BC.addInterproceduralReference(this, Fragment->getAddress());
+        BC.processInterproceduralReferences();
+        assert(isParentOrChildOf(*Fragment) &&
+               "BOLT-ERROR: cannot have landing pads in different functions");
+        setHasIndirectTargetToSplitFragment(true);
+        BC.addFragmentsToSkip(this);
+        return;
+      }
+
+      const uint64_t LPOffset = LandingPad - getAddress();
       if (!getInstructionAtOffset(LPOffset)) {
         if (opts::Verbosity >= 1)
           errs() << "BOLT-WARNING: landing pad " << Twine::utohexstr(LPOffset)
diff --git a/bolt/test/runtime/X86/exceptions-lpstart-zero.s b/bolt/test/runtime/X86/exceptions-lpstart-zero.s
new file mode 100644
index 000000000000000..9221c4ec0db9dc8
--- /dev/null
+++ b/bolt/test/runtime/X86/exceptions-lpstart-zero.s
@@ -0,0 +1,107 @@
+# RUN: %clangxx %cflags -no-pie %s -o %t.exe -Wl,-q
+# RUN: llvm-bolt %t.exe -o %t.exe.bolt
+# RUN: %t.exe.bolt
+
+# REQUIRES: system-linux
+
+## Test that BOLT properly handles LPStart when LPStartEncoding is different
+## from DW_EH_PE_omit.
+
+# Test case compiled from:
+#
+# int main() {
+#   try {
+#     throw 42;
+#   } catch (...) {
+#     return 0;
+#   }
+#   return 1;
+# }
+#
+# The exception table was modified with a different LPStartEncoding and
+# CallSiteEncoding.
+
+	.text
+	.globl	main                            # -- Begin function main
+	.p2align	4, 0x90
+	.type	main, at function
+main:                                   # @main
+.Lfunc_begin0:
+	.cfi_startproc
+	.globl __gxx_personality_v0
+	.cfi_personality 3, __gxx_personality_v0
+	.cfi_lsda 27, .Lexception0
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+	subq	$32, %rsp
+	movl	$0, -4(%rbp)
+	movl	$4, %edi
+	callq	__cxa_allocate_exception at PLT
+	movq	%rax, %rdi
+	movl	$42, (%rdi)
+.Ltmp0:
+	movq	_ZTIi at GOTPCREL(%rip), %rsi
+	xorl	%eax, %eax
+	movl	%eax, %edx
+	callq	__cxa_throw at PLT
+.Ltmp1:
+	jmp	.LBB0_4
+.LBB0_1:                                # %lpad
+.Ltmp2:
+	movq	%rax, %rcx
+	movl	%edx, %eax
+	movq	%rcx, -16(%rbp)
+	movl	%eax, -20(%rbp)
+# %bb.2:                                # %catch
+	movq	-16(%rbp), %rdi
+	callq	__cxa_begin_catch at PLT
+	movl	$0, -4(%rbp)
+	callq	__cxa_end_catch at PLT
+# %bb.3:                                # %return
+	movl	-4(%rbp), %eax
+	addq	$32, %rsp
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.LBB0_4:                                # %unreachable
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-main
+	.cfi_endproc
+	.section	.gcc_except_table,"a", at progbits
+	.p2align	2, 0x0
+GCC_except_table0:
+.Lexception0:
+	.byte	3                               # @LPStart Encoding = udata4
+  .long 0
+	.byte	155                             # @TType Encoding = indirect pcrel sdata4
+	.uleb128 .Lttbase0-.Lttbaseref0
+.Lttbaseref0:
+	.byte	11                              # Call site Encoding = udata4
+	.uleb128 .Lcst_end0-.Lcst_begin0
+.Lcst_begin0:
+	.long .Lfunc_begin0-.Lfunc_begin0    # >> Call Site 1 <<
+	.long .Ltmp0-.Lfunc_begin0           #   Call between .Lfunc_begin0 and .Ltmp0
+	.long	0                               #     has no landing pad
+	.byte	0                               #   On action: cleanup
+	.long .Ltmp0-.Lfunc_begin0           # >> Call Site 2 <<
+	.long .Ltmp1-.Ltmp0                  #   Call between .Ltmp0 and .Ltmp1
+  .long .Ltmp2
+	.byte	1                               #   On action: 1
+	.long .Ltmp1-.Lfunc_begin0           # >> Call Site 3 <<
+	.long .Lfunc_end0-.Ltmp1             #   Call between .Ltmp1 and .Lfunc_end0
+	.long	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, 0x0
+                                        # >> Catch TypeInfos <<
+	.long	0                               # TypeInfo 1
+.Lttbase0:
+	.p2align	2, 0x0
+                                        # -- End function

>From e205342b8e9b2eb7cb82ae41803534d5ee68c765 Mon Sep 17 00:00:00 2001
From: Maksim Panchenko <maks at fb.com>
Date: Mon, 20 Nov 2023 10:40:04 -0800
Subject: [PATCH 2/2] fixup! [BOLT] Fix C++ exceptions when LPStart is
 specified

---
 .../runtime/X86/exceptions-lpstart-zero.s     | 66 +++++++------------
 1 file changed, 25 insertions(+), 41 deletions(-)

diff --git a/bolt/test/runtime/X86/exceptions-lpstart-zero.s b/bolt/test/runtime/X86/exceptions-lpstart-zero.s
index 9221c4ec0db9dc8..b487ff0fa2f5911 100644
--- a/bolt/test/runtime/X86/exceptions-lpstart-zero.s
+++ b/bolt/test/runtime/X86/exceptions-lpstart-zero.s
@@ -7,7 +7,7 @@
 ## Test that BOLT properly handles LPStart when LPStartEncoding is different
 ## from DW_EH_PE_omit.
 
-# Test case compiled from:
+# The test case compiled with -O1 from:
 #
 # int main() {
 #   try {
@@ -18,7 +18,7 @@
 #   return 1;
 # }
 #
-# The exception table was modified with a different LPStartEncoding and
+# The exception table was modified with udata4 LPStartEncoding and sdata4
 # CallSiteEncoding.
 
 	.text
@@ -28,59 +28,43 @@
 main:                                   # @main
 .Lfunc_begin0:
 	.cfi_startproc
-	.globl __gxx_personality_v0
 	.cfi_personality 3, __gxx_personality_v0
-	.cfi_lsda 27, .Lexception0
-# %bb.0:                                # %entry
-	pushq	%rbp
+	.cfi_lsda 3, .Lexception0
+# %bb.0:
+	pushq	%rax
 	.cfi_def_cfa_offset 16
-	.cfi_offset %rbp, -16
-	movq	%rsp, %rbp
-	.cfi_def_cfa_register %rbp
-	subq	$32, %rsp
-	movl	$0, -4(%rbp)
 	movl	$4, %edi
-	callq	__cxa_allocate_exception at PLT
-	movq	%rax, %rdi
-	movl	$42, (%rdi)
+	callq	__cxa_allocate_exception
+	movl	$42, (%rax)
 .Ltmp0:
-	movq	_ZTIi at GOTPCREL(%rip), %rsi
-	xorl	%eax, %eax
-	movl	%eax, %edx
-	callq	__cxa_throw at PLT
+	movl	$_ZTIi, %esi
+	movq	%rax, %rdi
+	xorl	%edx, %edx
+	callq	__cxa_throw
 .Ltmp1:
-	jmp	.LBB0_4
-.LBB0_1:                                # %lpad
+# %bb.1:
+.LBB0_2:
 .Ltmp2:
-	movq	%rax, %rcx
-	movl	%edx, %eax
-	movq	%rcx, -16(%rbp)
-	movl	%eax, -20(%rbp)
-# %bb.2:                                # %catch
-	movq	-16(%rbp), %rdi
-	callq	__cxa_begin_catch at PLT
-	movl	$0, -4(%rbp)
-	callq	__cxa_end_catch at PLT
-# %bb.3:                                # %return
-	movl	-4(%rbp), %eax
-	addq	$32, %rsp
-	popq	%rbp
-	.cfi_def_cfa %rsp, 8
+	movq	%rax, %rdi
+	callq	__cxa_begin_catch
+	callq	__cxa_end_catch
+	xorl	%eax, %eax
+	popq	%rcx
+	.cfi_def_cfa_offset 8
 	retq
-.LBB0_4:                                # %unreachable
 .Lfunc_end0:
 	.size	main, .Lfunc_end0-main
 	.cfi_endproc
 	.section	.gcc_except_table,"a", at progbits
-	.p2align	2, 0x0
+	.p2align	2
 GCC_except_table0:
 .Lexception0:
 	.byte	3                               # @LPStart Encoding = udata4
   .long 0
-	.byte	155                             # @TType Encoding = indirect pcrel sdata4
+	.byte	3                               # @TType Encoding = udata4
 	.uleb128 .Lttbase0-.Lttbaseref0
 .Lttbaseref0:
-	.byte	11                              # Call site Encoding = udata4
+	.byte	11                              # Call site Encoding = sdata4
 	.uleb128 .Lcst_end0-.Lcst_begin0
 .Lcst_begin0:
 	.long .Lfunc_begin0-.Lfunc_begin0    # >> Call Site 1 <<
@@ -89,7 +73,7 @@ GCC_except_table0:
 	.byte	0                               #   On action: cleanup
 	.long .Ltmp0-.Lfunc_begin0           # >> Call Site 2 <<
 	.long .Ltmp1-.Ltmp0                  #   Call between .Ltmp0 and .Ltmp1
-  .long .Ltmp2
+	.long .Ltmp2                         #     jumps to .Ltmp2
 	.byte	1                               #   On action: 1
 	.long .Ltmp1-.Lfunc_begin0           # >> Call Site 3 <<
 	.long .Lfunc_end0-.Ltmp1             #   Call between .Ltmp1 and .Lfunc_end0
@@ -99,9 +83,9 @@ GCC_except_table0:
 	.byte	1                               # >> Action Record 1 <<
                                         #   Catch TypeInfo 1
 	.byte	0                               #   No further actions
-	.p2align	2, 0x0
+	.p2align	2
                                         # >> Catch TypeInfos <<
 	.long	0                               # TypeInfo 1
 .Lttbase0:
-	.p2align	2, 0x0
+	.p2align	2
                                         # -- End function



More information about the llvm-commits mailing list