-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[BOLT][AArch64] Allow binary-analysis and heatmap tool to run with pac-ret binaries #136664
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BOLT][AArch64] Allow binary-analysis and heatmap tool to run with pac-ret binaries #136664
Conversation
|
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
|
PTAL @kbeyls, @paschalis-mpeis |
|
@llvm/pr-subscribers-bolt Author: Gergely Bálint (bgergely0) ChangesQuoting For pac-ret analysis to work, we don't actually need the whole work in #120064 to be merged. Some contextThe BOLT codebase holds different tools: BOLT itself is used to optimize the layout of a binary, while other tools only need to generate the same internal representation to aid in that process, for example The This is important, because the This means, that for all other tools, we don't actually have to read it from the binary! SolutionThe solution is fairly simple: we need to pass the if (getToolName() == "llvm-bolt") {
BC.errs() << "BOLT-ERROR: pointer authentication is not supported "
"yet. Please compile "
"your target binary using '-mbranch-protection=none'.\n";
exit(1);
}This is a two-bird-one-stone solution: it also adds a user-friendly error message about the lack of PAC support. Previously, users got a fairly arcane error about a Full diff: https://github.com/llvm/llvm-project/pull/136664.diff 5 Files Affected:
diff --git a/bolt/docs/BinaryAnalysis.md b/bolt/docs/BinaryAnalysis.md
index 9f0f018980517..b13410cd96355 100644
--- a/bolt/docs/BinaryAnalysis.md
+++ b/bolt/docs/BinaryAnalysis.md
@@ -180,12 +180,6 @@ The following are current known cases of false negatives:
[prototype branch](
https://github.com/llvm/llvm-project/compare/main...kbeyls:llvm-project:bolt-gadget-scanner-prototype).
-BOLT cannot currently handle functions with `cfi_negate_ra_state` correctly,
-i.e. any binaries built with `-mbranch-protection=pac-ret`. The scanner is meant
-to be used on specifically such binaries, so this is a major limitation! Work is
-going on in PR [#120064](https://github.com/llvm/llvm-project/pull/120064) to
-fix this.
-
## How to add your own binary analysis
_TODO: this section needs to be written. Ideally, we should have a simple
diff --git a/bolt/include/bolt/Core/Exceptions.h b/bolt/include/bolt/Core/Exceptions.h
index f10cf776f0943..54e7fc50078da 100644
--- a/bolt/include/bolt/Core/Exceptions.h
+++ b/bolt/include/bolt/Core/Exceptions.h
@@ -37,7 +37,8 @@ class BinaryFunction;
/// BinaryFunction, as well as rewriting CFI sections.
class CFIReaderWriter {
public:
- explicit CFIReaderWriter(BinaryContext &BC, const DWARFDebugFrame &EHFrame);
+ explicit CFIReaderWriter(BinaryContext &BC, const DWARFDebugFrame &EHFrame,
+ StringRef ToolName);
bool fillCFIInfoFor(BinaryFunction &Function) const;
@@ -56,9 +57,12 @@ class CFIReaderWriter {
const FDEsMap &getFDEs() const { return FDEs; }
+ StringRef getToolName() const { return ToolName; }
+
private:
BinaryContext &BC;
FDEsMap FDEs;
+ StringRef ToolName;
};
/// Parse an existing .eh_frame and invoke the callback for each
diff --git a/bolt/lib/Core/Exceptions.cpp b/bolt/lib/Core/Exceptions.cpp
index 0b2e63b8ca6a7..cbb29a05bee20 100644
--- a/bolt/lib/Core/Exceptions.cpp
+++ b/bolt/lib/Core/Exceptions.cpp
@@ -463,8 +463,10 @@ void BinaryFunction::updateEHRanges() {
const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0;
CFIReaderWriter::CFIReaderWriter(BinaryContext &BC,
- const DWARFDebugFrame &EHFrame)
+ const DWARFDebugFrame &EHFrame,
+ StringRef ToolName)
: BC(BC) {
+ this->ToolName = ToolName;
// Prepare FDEs for fast lookup
for (const dwarf::FrameEntry &Entry : EHFrame.entries()) {
const auto *CurFDE = dyn_cast<dwarf::FDE>(&Entry);
@@ -632,8 +634,15 @@ bool CFIReaderWriter::fillCFIInfoFor(BinaryFunction &Function) const {
// DW_CFA_GNU_window_save and DW_CFA_GNU_NegateRAState just use the same
// id but mean different things. The latter is used in AArch64.
if (Function.getBinaryContext().isAArch64()) {
- Function.addCFIInstruction(
- Offset, MCCFIInstruction::createNegateRAState(nullptr));
+ // .cfi_negate_ra_state is only needed for tools producing binaries (so
+ // BOLT itself). Other BOLT-based tools (perf2bolt, merge-fdata,
+ // llvm-bolt-binary-analysis, etc.) can safely drop this CFI.
+ if (getToolName() == "llvm-bolt") {
+ BC.errs() << "BOLT-ERROR: pointer authentication is not supported "
+ "yet. Please compile "
+ "your target binary using '-mbranch-protection=none'.\n";
+ exit(1);
+ }
break;
}
if (opts::Verbosity >= 1)
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 69fb736d7bde0..6dc7cad4f538c 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -2048,7 +2048,8 @@ Error RewriteInstance::readSpecialSections() {
Expected<const DWARFDebugFrame *> EHFrameOrError = BC->DwCtx->getEHFrame();
if (!EHFrameOrError)
report_error("expected valid eh_frame section", EHFrameOrError.takeError());
- CFIRdWrt.reset(new CFIReaderWriter(*BC, *EHFrameOrError.get()));
+ StringRef ToolName = llvm::sys::path::stem(Argv[0]);
+ CFIRdWrt.reset(new CFIReaderWriter(*BC, *EHFrameOrError.get(), ToolName));
processSectionMetadata();
diff --git a/bolt/test/AArch64/dw_cfa_gnu_window_save.test b/bolt/test/AArch64/dw_cfa_gnu_window_save.test
index 2e044b399720a..97b257ee04666 100644
--- a/bolt/test/AArch64/dw_cfa_gnu_window_save.test
+++ b/bolt/test/AArch64/dw_cfa_gnu_window_save.test
@@ -1,8 +1,8 @@
-# Check that llvm-bolt can handle DW_CFA_GNU_window_save on AArch64.
+# Check that llvm-bolt refuses binaries with DW_CFA_GNU_window_save on AArch64.
RUN: yaml2obj %p/Inputs/dw_cfa_gnu_window_save.yaml &> %t.exe
-RUN: llvm-bolt %t.exe -o %t.bolt 2>&1 | FileCheck %s
+RUN not: llvm-bolt %t.exe -o %t.bolt 2>&1 | FileCheck %s
CHECK-NOT: paciasp
CHECK-NOT: autiasp
-CHECK-NOT: ERROR: unable to fill CFI.
+CHECK: BOLT-ERROR: pointer authentication is not supported yet.
|
|
also tagging @atrosinenko as I see you are very active on the pac-ret gadget scanner :) |
atrosinenko
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much for unblocking gadget scanner - I think it is a good idea to first fix the "read only mode" and then discuss the general case which is much more complex.
I am rather cautious about matching executable name (though I'm not very familiar with BOLT's core). Maybe it is better to choose the mode of operation based on opts::BinaryAnalysisMode and other such options, see these lines for example. Then, instead of assigning this->ToolName, you could compute this property in constructor and assign it to a boolean field.
|
@atrosinenko Thanks for the review.
Good point, probably better to only change the behaviour for the binary-analysis tool, because the current way it allows all tools besides BOLT. Doing |
paschalis-mpeis
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey Gergely,
Thanks for your work. I think it should be OK to restrict this to both llvm-bolt and perf2bolt. As said, the latter is not affected, but then llvm-bolt won't be able to run regardless.
paschalis-mpeis
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, thanks!
Let's allow 1-2 days in case there are additional comments.
atrosinenko
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bgergely0 Thank you for the updates! I have no more comments except for one minor nit-picking (feel free to ignore).
I agree with @paschalis-mpeis, let's wait 1-2 days for others to comment.
|
Could also rename the title to something like:
|
kbeyls
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, this mostly looks good to me!
I just had one nit-pick comment.
I would also improve the title of this PR/commit message to be more descriptive, as @paschalis-mpeis recommended.
paschalis-mpeis
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noting that this new behavior is triggered on 39 tests on AArch64, causing all to fail.
It will have to be addressed before proceeding.
Total Discovered Tests: 547
Skipped : 13 (2.38%)
Unsupported : 81 (14.81%)
Passed : 413 (75.50%)
Expectedly Failed: 1 (0.18%)
Failed : 39 (7.13%)
|
Looks like many unittest binaries have |
103692f to
15bc0cb
Compare
|
With the new commit I do the check "later", e.g. not in |
paschalis-mpeis
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey Gergely,
Thanks for fixing the tests. Essentially now the error handling of OpNegateRAState is explicit. And your upcoming work will add support through a flag:
|
Thanks for the approval @paschalis-mpeis! |
atrosinenko
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The patch looks good to me (though I'm not very familiar with BOLT's handling of CFI), with a trivial nit-picking. Thank you!
pac-ret binaries
- OpNegateRAState support is only needed for tools that
produce binaries.
15bc0cb to
86bc38c
Compare
Sure. I see you addressed the nits too, so I proceed now with merging. Thanks! |
|
@bgergely0 Congratulations on having your first Pull Request (PR) merged into the LLVM Project! Your changes will be combined with recent changes from other authors, then tested by our build bots. If there is a problem with a build, you may receive a report in an email or a comment on this PR. Please check whether problems have been caused by your change specifically, as the builds can include changes from many authors. It is not uncommon for your change to be included in a build that fails due to someone else's changes, or infrastructure issues. How to do this, and the rest of the post-merge process, is covered in detail here. If your change does cause a problem, it may be reverted, or you can revert it yourself. This is a normal part of LLVM development. You can fix your changes and open a new PR to merge them again. If you don't get any reports, no action is required from you. Your changes are working as expected, well done! |
…c-ret binaries (llvm#136664) OpNegateRAState support is only needed for tools that produce binaries.
…c-ret binaries (llvm#136664) OpNegateRAState support is only needed for tools that produce binaries.
Quoting
bolt/docs/BinaryAnalysis.md:For pac-ret analysis to work, we don't actually need the whole work in #120064 to be merged.
Some context
The BOLT codebase holds different tools: BOLT itself is used to optimize the layout of a binary, while other tools only need to generate the same internal representation to aid in that process.
The
.cfi_negate_ra_stateCall Frame Instruction needs to be read, tracked, and eventually emitted by tools that produce a binary: this CFI signals to the unwinder if it needs to strip the PAC bits from pointers or not.This means we can ignore these CFIs in
llvm-bolt-binary-analysisand theheatmaptool.Solution
In places where previously BOLT would run to an
llvm_unreachable("Unsupported CFI opcode")forOpNegateRAState, we first check from options which tool is running, and only crash with unreachable when needed.