Skip to content

Commit 6820b6f

Browse files
committed
Merge remote-tracking branch 'origin/main' into pr/condbranch
2 parents 2159828 + 5b5e95c commit 6820b6f

File tree

866 files changed

+23433
-10217
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

866 files changed

+23433
-10217
lines changed

.ci/compute_projects.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
DEPENDENT_RUNTIMES_TO_TEST = {
7878
"clang": {"compiler-rt"},
7979
"clang-tools-extra": {"libc"},
80+
"libc": {"libc"},
8081
".ci": {"compiler-rt", "libc"},
8182
}
8283
DEPENDENT_RUNTIMES_TO_TEST_NEEDS_RECONFIG = {

.ci/compute_projects_test.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ def test_top_level_file(self):
187187
self.assertEqual(env_variables["runtimes_check_targets"], "")
188188
self.assertEqual(env_variables["runtimes_check_targets_needs_reconfig"], "")
189189

190-
def test_exclude_runtiems_in_projects(self):
190+
def test_exclude_libcxx_in_projects(self):
191191
env_variables = compute_projects.get_env_variables(
192192
["libcxx/CMakeLists.txt"], "Linux"
193193
)
@@ -197,6 +197,16 @@ def test_exclude_runtiems_in_projects(self):
197197
self.assertEqual(env_variables["runtimes_check_targets"], "")
198198
self.assertEqual(env_variables["runtimes_check_targets_needs_reconfig"], "")
199199

200+
def test_include_libc_in_runtimes(self):
201+
env_variables = compute_projects.get_env_variables(
202+
["libc/CMakeLists.txt"], "Linux"
203+
)
204+
self.assertEqual(env_variables["projects_to_build"], "clang;lld")
205+
self.assertEqual(env_variables["project_check_targets"], "")
206+
self.assertEqual(env_variables["runtimes_to_build"], "libc")
207+
self.assertEqual(env_variables["runtimes_check_targets"], "check-libc")
208+
self.assertEqual(env_variables["runtimes_check_targets_needs_reconfig"], "")
209+
200210
def test_exclude_docs(self):
201211
env_variables = compute_projects.get_env_variables(
202212
["llvm/docs/CIBestPractices.rst"], "Linux"

bolt/include/bolt/Core/BinarySection.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -523,11 +523,6 @@ inline uint8_t *copyByteArray(const uint8_t *Data, uint64_t Size) {
523523
return Array;
524524
}
525525

526-
inline uint8_t *copyByteArray(StringRef Buffer) {
527-
return copyByteArray(reinterpret_cast<const uint8_t *>(Buffer.data()),
528-
Buffer.size());
529-
}
530-
531526
inline uint8_t *copyByteArray(ArrayRef<char> Buffer) {
532527
return copyByteArray(reinterpret_cast<const uint8_t *>(Buffer.data()),
533528
Buffer.size());

bolt/lib/Passes/PAuthGadgetScanner.cpp

Lines changed: 108 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,22 @@ namespace PAuthGadgetScanner {
8282
dbgs() << "\n";
8383
}
8484

85+
// Iterates over BinaryFunction's instructions like a range-based for loop:
86+
//
87+
// iterateOverInstrs(BF, [&](MCInstReference Inst) {
88+
// // loop body
89+
// });
90+
template <typename T> static void iterateOverInstrs(BinaryFunction &BF, T Fn) {
91+
if (BF.hasCFG()) {
92+
for (BinaryBasicBlock &BB : BF)
93+
for (int64_t I = 0, E = BB.size(); I < E; ++I)
94+
Fn(MCInstInBBReference(&BB, I));
95+
} else {
96+
for (auto I : BF.instrs())
97+
Fn(MCInstInBFReference(&BF, I.first));
98+
}
99+
}
100+
85101
// This class represents mapping from a set of arbitrary physical registers to
86102
// consecutive array indexes.
87103
class TrackedRegisters {
@@ -342,6 +358,29 @@ class SrcSafetyAnalysis {
342358
return S;
343359
}
344360

361+
/// Computes a reasonably pessimistic estimation of the register state when
362+
/// the previous instruction is not known for sure. Takes the set of registers
363+
/// which are trusted at function entry and removes all registers that can be
364+
/// clobbered inside this function.
365+
SrcState computePessimisticState(BinaryFunction &BF) {
366+
BitVector ClobberedRegs(NumRegs);
367+
iterateOverInstrs(BF, [&](MCInstReference Inst) {
368+
BC.MIB->getClobberedRegs(Inst, ClobberedRegs);
369+
370+
// If this is a call instruction, no register is safe anymore, unless
371+
// it is a tail call. Ignore tail calls for the purpose of estimating the
372+
// worst-case scenario, assuming no instructions are executed in the
373+
// caller after this point anyway.
374+
if (BC.MIB->isCall(Inst) && !BC.MIB->isTailCall(Inst))
375+
ClobberedRegs.set();
376+
});
377+
378+
SrcState S = createEntryState();
379+
S.SafeToDerefRegs.reset(ClobberedRegs);
380+
S.TrustedRegs.reset(ClobberedRegs);
381+
return S;
382+
}
383+
345384
BitVector getClobberedRegs(const MCInst &Point) const {
346385
BitVector Clobbered(NumRegs);
347386
// Assume a call can clobber all registers, including callee-saved
@@ -545,6 +584,10 @@ class DataflowSrcSafetyAnalysis
545584
using SrcSafetyAnalysis::BC;
546585
using SrcSafetyAnalysis::computeNext;
547586

587+
// Pessimistic initial state for basic blocks without any predecessors
588+
// (not needed for most functions, thus initialized lazily).
589+
SrcState PessimisticState;
590+
548591
public:
549592
DataflowSrcSafetyAnalysis(BinaryFunction &BF,
550593
MCPlusBuilder::AllocatorIdTy AllocId,
@@ -585,6 +628,18 @@ class DataflowSrcSafetyAnalysis
585628
if (BB.isEntryPoint())
586629
return createEntryState();
587630

631+
// If a basic block without any predecessors is found in an optimized code,
632+
// this likely means that some CFG edges were not detected. Pessimistically
633+
// assume any register that can ever be clobbered in this function to be
634+
// unsafe before this basic block.
635+
// Warn about this fact in FunctionAnalysis::findUnsafeUses(), as it likely
636+
// means imprecise CFG information.
637+
if (BB.pred_empty()) {
638+
if (PessimisticState.empty())
639+
PessimisticState = computePessimisticState(*BB.getParent());
640+
return PessimisticState;
641+
}
642+
588643
return SrcState();
589644
}
590645

@@ -682,19 +737,14 @@ template <typename StateTy> class CFGUnawareAnalysis {
682737
//
683738
// Then, a function can be split into a number of disjoint contiguous sequences
684739
// of instructions without labels in between. These sequences can be processed
685-
// the same way basic blocks are processed by data-flow analysis, assuming
686-
// pessimistically that all registers are unsafe at the start of each sequence.
740+
// the same way basic blocks are processed by data-flow analysis, with the same
741+
// pessimistic estimation of the initial state at the start of each sequence
742+
// (except the first instruction of the function).
687743
class CFGUnawareSrcSafetyAnalysis : public SrcSafetyAnalysis,
688744
public CFGUnawareAnalysis<SrcState> {
689745
using SrcSafetyAnalysis::BC;
690746
BinaryFunction &BF;
691747

692-
/// Creates a state with all registers marked unsafe (not to be confused
693-
/// with empty state).
694-
SrcState createUnsafeState() const {
695-
return SrcState(NumRegs, RegsToTrackInstsFor.getNumTrackedRegisters());
696-
}
697-
698748
public:
699749
CFGUnawareSrcSafetyAnalysis(BinaryFunction &BF,
700750
MCPlusBuilder::AllocatorIdTy AllocId,
@@ -704,6 +754,7 @@ class CFGUnawareSrcSafetyAnalysis : public SrcSafetyAnalysis,
704754
}
705755

706756
void run() override {
757+
const SrcState DefaultState = computePessimisticState(BF);
707758
SrcState S = createEntryState();
708759
for (auto &I : BF.instrs()) {
709760
MCInst &Inst = I.second;
@@ -718,7 +769,7 @@ class CFGUnawareSrcSafetyAnalysis : public SrcSafetyAnalysis,
718769
LLVM_DEBUG({
719770
traceInst(BC, "Due to label, resetting the state before", Inst);
720771
});
721-
S = createUnsafeState();
772+
S = DefaultState;
722773
}
723774

724775
// Attach the state *before* this instruction executes.
@@ -1344,17 +1395,6 @@ shouldReportAuthOracle(const BinaryContext &BC, const MCInstReference &Inst,
13441395
return make_gadget_report(AuthOracleKind, Inst, *AuthReg);
13451396
}
13461397

1347-
template <typename T> static void iterateOverInstrs(BinaryFunction &BF, T Fn) {
1348-
if (BF.hasCFG()) {
1349-
for (BinaryBasicBlock &BB : BF)
1350-
for (int64_t I = 0, E = BB.size(); I < E; ++I)
1351-
Fn(MCInstInBBReference(&BB, I));
1352-
} else {
1353-
for (auto I : BF.instrs())
1354-
Fn(MCInstInBFReference(&BF, I.first));
1355-
}
1356-
}
1357-
13581398
static SmallVector<MCPhysReg>
13591399
collectRegsToTrack(ArrayRef<PartialReport<MCPhysReg>> Reports) {
13601400
SmallSet<MCPhysReg, 4> RegsToTrack;
@@ -1375,17 +1415,60 @@ void FunctionAnalysisContext::findUnsafeUses(
13751415
BF.dump();
13761416
});
13771417

1418+
bool UnreachableBBReported = false;
1419+
if (BF.hasCFG()) {
1420+
// Warn on basic blocks being unreachable according to BOLT (at most once
1421+
// per BinaryFunction), as this likely means the CFG reconstructed by BOLT
1422+
// is imprecise. A basic block can be
1423+
// * reachable from an entry basic block - a hopefully correct non-empty
1424+
// state is propagated to that basic block sooner or later. All basic
1425+
// blocks are expected to belong to this category under normal conditions.
1426+
// * reachable from a "directly unreachable" BB (a basic block that has no
1427+
// direct predecessors and this is not because it is an entry BB) - *some*
1428+
// non-empty state is propagated to this basic block sooner or later, as
1429+
// the initial state of directly unreachable basic blocks is
1430+
// pessimistically initialized to "all registers are unsafe"
1431+
// - a warning can be printed for the "directly unreachable" basic block
1432+
// * neither reachable from an entry nor from a "directly unreachable" BB
1433+
// (such as if this BB is in an isolated loop of basic blocks) - the final
1434+
// state is computed to be empty for this basic block
1435+
// - a warning can be printed for this basic block
1436+
for (BinaryBasicBlock &BB : BF) {
1437+
MCInst *FirstInst = BB.getFirstNonPseudoInstr();
1438+
// Skip empty basic block early for simplicity.
1439+
if (!FirstInst)
1440+
continue;
1441+
1442+
bool IsDirectlyUnreachable = BB.pred_empty() && !BB.isEntryPoint();
1443+
bool HasNoStateComputed = Analysis->getStateBefore(*FirstInst).empty();
1444+
if (!IsDirectlyUnreachable && !HasNoStateComputed)
1445+
continue;
1446+
1447+
// Arbitrarily attach the report to the first instruction of BB.
1448+
// This is printed as "[message] in function [name], basic block ...,
1449+
// at address ..." when the issue is reported to the user.
1450+
Reports.push_back(make_generic_report(
1451+
MCInstReference::get(FirstInst, BF),
1452+
"Warning: possibly imprecise CFG, the analysis quality may be "
1453+
"degraded in this function. According to BOLT, unreachable code is "
1454+
"found" /* in function [name]... */));
1455+
UnreachableBBReported = true;
1456+
break; // One warning per function.
1457+
}
1458+
}
1459+
// FIXME: Warn the user about imprecise analysis when the function has no CFG
1460+
// information at all.
1461+
13781462
iterateOverInstrs(BF, [&](MCInstReference Inst) {
13791463
if (BC.MIB->isCFI(Inst))
13801464
return;
13811465

13821466
const SrcState &S = Analysis->getStateBefore(Inst);
1383-
1384-
// If non-empty state was never propagated from the entry basic block
1385-
// to Inst, assume it to be unreachable and report a warning.
13861467
if (S.empty()) {
1387-
Reports.push_back(
1388-
make_generic_report(Inst, "Warning: unreachable instruction found"));
1468+
LLVM_DEBUG(
1469+
{ traceInst(BC, "Instruction has no state, skipping", Inst); });
1470+
assert(UnreachableBBReported && "Should be reported at least once");
1471+
(void)UnreachableBBReported;
13891472
return;
13901473
}
13911474

bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,15 +1081,15 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
10811081

10821082
if (isADR(Inst) || RelType == ELF::R_AARCH64_ADR_PREL_LO21 ||
10831083
RelType == ELF::R_AARCH64_TLSDESC_ADR_PREL21) {
1084-
return MCSpecifierExpr::create(Expr, AArch64MCExpr::VK_ABS, Ctx);
1084+
return MCSpecifierExpr::create(Expr, AArch64::S_ABS, Ctx);
10851085
} else if (isADRP(Inst) || RelType == ELF::R_AARCH64_ADR_PREL_PG_HI21 ||
10861086
RelType == ELF::R_AARCH64_ADR_PREL_PG_HI21_NC ||
10871087
RelType == ELF::R_AARCH64_TLSDESC_ADR_PAGE21 ||
10881088
RelType == ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 ||
10891089
RelType == ELF::R_AARCH64_ADR_GOT_PAGE) {
10901090
// Never emit a GOT reloc, we handled this in
10911091
// RewriteInstance::readRelocations().
1092-
return MCSpecifierExpr::create(Expr, AArch64MCExpr::VK_ABS_PAGE, Ctx);
1092+
return MCSpecifierExpr::create(Expr, AArch64::S_ABS_PAGE, Ctx);
10931093
} else {
10941094
switch (RelType) {
10951095
case ELF::R_AARCH64_ADD_ABS_LO12_NC:
@@ -1103,18 +1103,18 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
11031103
case ELF::R_AARCH64_TLSDESC_LD64_LO12:
11041104
case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
11051105
case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
1106-
return MCSpecifierExpr::create(Expr, AArch64MCExpr::VK_LO12, Ctx);
1106+
return MCSpecifierExpr::create(Expr, AArch64::S_LO12, Ctx);
11071107
case ELF::R_AARCH64_MOVW_UABS_G3:
1108-
return MCSpecifierExpr::create(Expr, AArch64MCExpr::VK_ABS_G3, Ctx);
1108+
return MCSpecifierExpr::create(Expr, AArch64::S_ABS_G3, Ctx);
11091109
case ELF::R_AARCH64_MOVW_UABS_G2:
11101110
case ELF::R_AARCH64_MOVW_UABS_G2_NC:
1111-
return MCSpecifierExpr::create(Expr, AArch64MCExpr::VK_ABS_G2_NC, Ctx);
1111+
return MCSpecifierExpr::create(Expr, AArch64::S_ABS_G2_NC, Ctx);
11121112
case ELF::R_AARCH64_MOVW_UABS_G1:
11131113
case ELF::R_AARCH64_MOVW_UABS_G1_NC:
1114-
return MCSpecifierExpr::create(Expr, AArch64MCExpr::VK_ABS_G1_NC, Ctx);
1114+
return MCSpecifierExpr::create(Expr, AArch64::S_ABS_G1_NC, Ctx);
11151115
case ELF::R_AARCH64_MOVW_UABS_G0:
11161116
case ELF::R_AARCH64_MOVW_UABS_G0_NC:
1117-
return MCSpecifierExpr::create(Expr, AArch64MCExpr::VK_ABS_G0_NC, Ctx);
1117+
return MCSpecifierExpr::create(Expr, AArch64::S_ABS_G0_NC, Ctx);
11181118
default:
11191119
break;
11201120
}
@@ -2028,7 +2028,7 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
20282028
Inst.setOpcode(AArch64::MOVZXi);
20292029
Inst.addOperand(MCOperand::createReg(AArch64::X16));
20302030
Inst.addOperand(MCOperand::createExpr(
2031-
MCSpecifierExpr::create(Target, AArch64MCExpr::VK_ABS_G3, *Ctx)));
2031+
MCSpecifierExpr::create(Target, AArch64::S_ABS_G3, *Ctx)));
20322032
Inst.addOperand(MCOperand::createImm(0x30));
20332033
Seq.emplace_back(Inst);
20342034

@@ -2037,7 +2037,7 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
20372037
Inst.addOperand(MCOperand::createReg(AArch64::X16));
20382038
Inst.addOperand(MCOperand::createReg(AArch64::X16));
20392039
Inst.addOperand(MCOperand::createExpr(
2040-
MCSpecifierExpr::create(Target, AArch64MCExpr::VK_ABS_G2_NC, *Ctx)));
2040+
MCSpecifierExpr::create(Target, AArch64::S_ABS_G2_NC, *Ctx)));
20412041
Inst.addOperand(MCOperand::createImm(0x20));
20422042
Seq.emplace_back(Inst);
20432043

@@ -2046,7 +2046,7 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
20462046
Inst.addOperand(MCOperand::createReg(AArch64::X16));
20472047
Inst.addOperand(MCOperand::createReg(AArch64::X16));
20482048
Inst.addOperand(MCOperand::createExpr(
2049-
MCSpecifierExpr::create(Target, AArch64MCExpr::VK_ABS_G1_NC, *Ctx)));
2049+
MCSpecifierExpr::create(Target, AArch64::S_ABS_G1_NC, *Ctx)));
20502050
Inst.addOperand(MCOperand::createImm(0x10));
20512051
Seq.emplace_back(Inst);
20522052

@@ -2055,7 +2055,7 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
20552055
Inst.addOperand(MCOperand::createReg(AArch64::X16));
20562056
Inst.addOperand(MCOperand::createReg(AArch64::X16));
20572057
Inst.addOperand(MCOperand::createExpr(
2058-
MCSpecifierExpr::create(Target, AArch64MCExpr::VK_ABS_G0_NC, *Ctx)));
2058+
MCSpecifierExpr::create(Target, AArch64::S_ABS_G0_NC, *Ctx)));
20592059
Inst.addOperand(MCOperand::createImm(0));
20602060
Seq.emplace_back(Inst);
20612061

bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ f_callclobbered_calleesaved:
215215
.globl f_unreachable_instruction
216216
.type f_unreachable_instruction,@function
217217
f_unreachable_instruction:
218-
// CHECK-LABEL: GS-PAUTH: Warning: unreachable instruction found in function f_unreachable_instruction, basic block {{[0-9a-zA-Z.]+}}, at address
218+
// CHECK-LABEL: GS-PAUTH: Warning: possibly imprecise CFG, the analysis quality may be degraded in this function. According to BOLT, unreachable code is found in function f_unreachable_instruction, basic block {{[0-9a-zA-Z.]+}}, at address
219219
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: add x0, x1, x2
220220
// CHECK-NOT: instructions that write to the affected registers after any authentication are:
221221
b 1f
@@ -224,20 +224,33 @@ f_unreachable_instruction:
224224
ret
225225
.size f_unreachable_instruction, .-f_unreachable_instruction
226226

227-
// Expected false positive: without CFG, the state is reset to all-unsafe
228-
// after an unconditional branch.
227+
// Without CFG, the state is reset at labels, assuming every register that can
228+
// be clobbered in the function was actually clobbered.
229229

230-
.globl state_is_reset_after_indirect_branch_nocfg
231-
.type state_is_reset_after_indirect_branch_nocfg,@function
232-
state_is_reset_after_indirect_branch_nocfg:
233-
// CHECK-LABEL: GS-PAUTH: non-protected ret found in function state_is_reset_after_indirect_branch_nocfg, at address
234-
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: ret
230+
.globl lr_untouched_nocfg
231+
.type lr_untouched_nocfg,@function
232+
lr_untouched_nocfg:
233+
// CHECK-NOT: lr_untouched_nocfg
234+
adr x2, 1f
235+
br x2
236+
1:
237+
ret
238+
.size lr_untouched_nocfg, .-lr_untouched_nocfg
239+
240+
.globl lr_clobbered_nocfg
241+
.type lr_clobbered_nocfg,@function
242+
lr_clobbered_nocfg:
243+
// CHECK-LABEL: GS-PAUTH: non-protected ret found in function lr_clobbered_nocfg, at address
244+
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: ret
235245
// CHECK-NEXT: The 0 instructions that write to the affected registers after any authentication are:
236246
adr x2, 1f
237247
br x2
238248
1:
249+
b 2f
250+
bl g // never executed, but affects the expected worst-case scenario
251+
2:
239252
ret
240-
.size state_is_reset_after_indirect_branch_nocfg, .-state_is_reset_after_indirect_branch_nocfg
253+
.size lr_clobbered_nocfg, .-lr_clobbered_nocfg
241254

242255
/// Now do a basic sanity check on every different Authentication instruction:
243256

0 commit comments

Comments
 (0)