Skip to content

Commit dbbea3c

Browse files
bgergely0Honey Goyal
authored andcommitted
[BOLT][PAC] Warn about synchronous unwind tables (llvm#165227)
BOLT currently ignores functions with synchronous PAuth DWARF info. If more than 10% of functions get ignored for inconsistencies, we should emit a warning to only use asynchronous unwind tables. See related issue: llvm#165215
1 parent f580a05 commit dbbea3c

File tree

3 files changed

+73
-12
lines changed

3 files changed

+73
-12
lines changed

bolt/lib/Passes/PointerAuthCFIAnalyzer.cpp

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828

2929
using namespace llvm;
3030

31+
namespace opts {
32+
extern llvm::cl::opt<unsigned> Verbosity;
33+
} // namespace opts
34+
3135
namespace llvm {
3236
namespace bolt {
3337

@@ -43,9 +47,10 @@ bool PointerAuthCFIAnalyzer::runOnFunction(BinaryFunction &BF) {
4347
// Not all functions have .cfi_negate_ra_state in them. But if one does,
4448
// we expect psign/pauth instructions to have the hasNegateRAState
4549
// annotation.
46-
BC.outs() << "BOLT-INFO: inconsistent RAStates in function "
47-
<< BF.getPrintName()
48-
<< ": ptr sign/auth inst without .cfi_negate_ra_state\n";
50+
if (opts::Verbosity >= 1)
51+
BC.outs() << "BOLT-INFO: inconsistent RAStates in function "
52+
<< BF.getPrintName()
53+
<< ": ptr sign/auth inst without .cfi_negate_ra_state\n";
4954
std::lock_guard<std::mutex> Lock(IgnoreMutex);
5055
BF.setIgnored();
5156
return false;
@@ -65,20 +70,22 @@ bool PointerAuthCFIAnalyzer::runOnFunction(BinaryFunction &BF) {
6570
if (BC.MIB->isPSignOnLR(Inst)) {
6671
if (RAState) {
6772
// RA signing instructions should only follow unsigned RA state.
68-
BC.outs() << "BOLT-INFO: inconsistent RAStates in function "
69-
<< BF.getPrintName()
70-
<< ": ptr signing inst encountered in Signed RA state\n";
73+
if (opts::Verbosity >= 1)
74+
BC.outs() << "BOLT-INFO: inconsistent RAStates in function "
75+
<< BF.getPrintName()
76+
<< ": ptr signing inst encountered in Signed RA state\n";
7177
std::lock_guard<std::mutex> Lock(IgnoreMutex);
7278
BF.setIgnored();
7379
return false;
7480
}
7581
} else if (BC.MIB->isPAuthOnLR(Inst)) {
7682
if (!RAState) {
7783
// RA authenticating instructions should only follow signed RA state.
78-
BC.outs() << "BOLT-INFO: inconsistent RAStates in function "
79-
<< BF.getPrintName()
80-
<< ": ptr authenticating inst encountered in Unsigned RA "
81-
"state\n";
84+
if (opts::Verbosity >= 1)
85+
BC.outs() << "BOLT-INFO: inconsistent RAStates in function "
86+
<< BF.getPrintName()
87+
<< ": ptr authenticating inst encountered in Unsigned RA "
88+
"state\n";
8289
std::lock_guard<std::mutex> Lock(IgnoreMutex);
8390
BF.setIgnored();
8491
return false;
@@ -130,14 +137,35 @@ Error PointerAuthCFIAnalyzer::runOnFunctions(BinaryContext &BC) {
130137
return P.second.containedNegateRAState() && !P.second.isIgnored();
131138
});
132139

140+
if (Total == 0)
141+
return Error::success();
142+
133143
ParallelUtilities::runOnEachFunction(
134144
BC, ParallelUtilities::SchedulingPolicy::SP_INST_LINEAR, WorkFun,
135145
SkipPredicate, "PointerAuthCFIAnalyzer");
146+
147+
float IgnoredPercent = (100.0 * FunctionsIgnored) / Total;
136148
BC.outs() << "BOLT-INFO: PointerAuthCFIAnalyzer ran on " << Total
137149
<< " functions. Ignored " << FunctionsIgnored << " functions "
138-
<< format("(%.2lf%%)", (100.0 * FunctionsIgnored) / Total)
150+
<< format("(%.2lf%%)", IgnoredPercent)
139151
<< " because of CFI inconsistencies\n";
140152

153+
// Errors in the input are expected from two sources:
154+
// - compilers emitting incorrect CFIs. This happens more frequently with
155+
// older compiler versions, but it should not account for a large
156+
// percentage.
157+
// - input binary is using synchronous unwind tables. This means that after
158+
// call sites, the unwind CFIs are dropped: the pass sees missing
159+
// .cfi_negate_ra_state from autiasp instructions. If this is the case, a
160+
// larger percentage of functions will be ignored.
161+
//
162+
// This is why the 10% threshold was chosen: we should not warn about
163+
// synchronous unwind tables if only a few % are ignored.
164+
if (IgnoredPercent >= 10.0)
165+
BC.outs() << "BOLT-WARNING: PointerAuthCFIAnalyzer only supports "
166+
"asynchronous unwind tables. For C compilers, see "
167+
"-fasynchronous-unwind-tables.\n";
168+
141169
return Error::success();
142170
}
143171

bolt/test/AArch64/pacret-cfi-incorrect.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o
1010
# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q
11-
# RUN: llvm-bolt %t.exe -o %t.exe.bolt --no-threads | FileCheck %s --check-prefix=CHECK-BOLT
11+
# RUN: llvm-bolt %t.exe -o %t.exe.bolt -v=1 --no-threads | FileCheck %s --check-prefix=CHECK-BOLT
1212

1313
# CHECK-BOLT: BOLT-INFO: inconsistent RAStates in function foo: ptr authenticating inst encountered in Unsigned RA state
1414
# CHECK-BOLT: BOLT-INFO: inconsistent RAStates in function bar: ptr signing inst encountered in Signed RA state
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Test to demonstrate that functions compiled with synchronous unwind tables
2+
// are ignored by the PointerAuthCFIAnalyzer.
3+
// Exception handling is needed to have _any_ unwind tables, otherwise the
4+
// PointerAuthCFIAnalyzer does not run on these functions, so it does not ignore
5+
// any function.
6+
//
7+
// REQUIRES: system-linux,bolt-runtime
8+
//
9+
// RUN: %clangxx --target=aarch64-unknown-linux-gnu \
10+
// RUN: -mbranch-protection=pac-ret \
11+
// RUN: -fno-asynchronous-unwind-tables \
12+
// RUN: %s -o %t.exe -Wl,-q
13+
// RUN: llvm-bolt %t.exe -o %t.bolt | FileCheck %s --check-prefix=CHECK
14+
//
15+
// CHECK: PointerAuthCFIAnalyzer ran on 3 functions. Ignored
16+
// CHECK-NOT: 0 functions (0.00%) because of CFI inconsistencies
17+
// CHECK-SAME: 1 functions (33.33%) because of CFI inconsistencies
18+
// CHECK-NEXT: BOLT-WARNING: PointerAuthCFIAnalyzer only supports asynchronous
19+
// CHECK-SAME: unwind tables. For C compilers, see -fasynchronous-unwind-tables.
20+
21+
#include <cstdio>
22+
#include <stdexcept>
23+
24+
void foo() { throw std::runtime_error("Exception from foo()."); }
25+
26+
int main() {
27+
try {
28+
foo();
29+
} catch (const std::exception &e) {
30+
printf("Exception caught: %s\n", e.what());
31+
}
32+
return 0;
33+
}

0 commit comments

Comments
 (0)