2828
2929using namespace llvm ;
3030
31+ namespace opts {
32+ extern llvm::cl::opt<unsigned > Verbosity;
33+ } // namespace opts
34+
3135namespace llvm {
3236namespace 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
0 commit comments