diff --git a/bolt/include/bolt/Passes/PAuthGadgetScanner.h b/bolt/include/bolt/Passes/PAuthGadgetScanner.h index ccfe632889c7a..98a49df862ebd 100644 --- a/bolt/include/bolt/Passes/PAuthGadgetScanner.h +++ b/bolt/include/bolt/Passes/PAuthGadgetScanner.h @@ -196,73 +196,148 @@ raw_ostream &operator<<(raw_ostream &OS, const MCInstReference &); namespace PAuthGadgetScanner { +// The report classes are designed to be used in an immutable manner. +// When an issue report is constructed in multiple steps, an attempt is made +// to distinguish intermediate and final results at the type level. +// +// Here is an overview of issue life-cycle: +// * an analysis (SrcSafetyAnalysis at now, DstSafetyAnalysis will be added +// later to support the detection of authentication oracles) computes register +// state for each instruction in the function. +// * for each instruction, it is checked whether it is a gadget of some kind, +// taking the computed state into account. If a gadget is found, its kind +// and location are stored into a subclass of Diagnostic wrapped into +// PartialReport. +// * if any issue is to be reported for the function, the same analysis is +// re-run to collect extra information to provide to the user. Which extra +// information can be requested depends on the particular analysis (for +// example, SrcSafetyAnalysis is able to compute the set of instructions +// clobbering the particular register, thus ReqT is MCPhysReg). At this stage, +// `FinalReport`s are created. +// +// Here, the subclasses of Diagnostic store the pieces of information which +// are kept unchanged since they are collected on the first run of the analysis. +// PartialReport::RequestedDetails, on the other hand, is replaced with +// FinalReport::Details computed by the second run of the analysis. + /// Description of a gadget kind that can be detected. Intended to be -/// statically allocated to be attached to reports by reference. +/// statically allocated and attached to reports by reference. class GadgetKind { const char *Description; public: + /// Wraps a description string which must be a string literal. GadgetKind(const char *Description) : Description(Description) {} StringRef getDescription() const { return Description; } }; -/// Base report located at some instruction, without any additional information. -struct Report { +/// Basic diagnostic information, which is kept unchanged since it is collected +/// on the first run of the analysis. +struct Diagnostic { MCInstReference Location; - Report(MCInstReference Location) : Location(Location) {} - virtual ~Report() {} + Diagnostic(MCInstReference Location) : Location(Location) {} + virtual ~Diagnostic() {} virtual void generateReport(raw_ostream &OS, const BinaryContext &BC) const = 0; - // The two methods below are called by Analysis::computeDetailedInfo when - // iterating over the reports. - virtual ArrayRef getAffectedRegisters() const { return {}; } - virtual void setOverwritingInstrs(ArrayRef Instrs) {} - void printBasicInfo(raw_ostream &OS, const BinaryContext &BC, StringRef IssueKind) const; }; -struct GadgetReport : public Report { +struct GadgetDiagnostic : public Diagnostic { // The particular kind of gadget that is detected. const GadgetKind &Kind; - // The set of registers related to this gadget report (possibly empty). - SmallVector AffectedRegisters; - // The instructions that clobber the affected registers. - // There is no one-to-one correspondence with AffectedRegisters: for example, - // the same register can be overwritten by different instructions in different - // preceding basic blocks. - SmallVector OverwritingInstrs; - - GadgetReport(const GadgetKind &Kind, MCInstReference Location, - MCPhysReg AffectedRegister) - : Report(Location), Kind(Kind), AffectedRegisters({AffectedRegister}) {} - void generateReport(raw_ostream &OS, const BinaryContext &BC) const override; + GadgetDiagnostic(const GadgetKind &Kind, MCInstReference Location) + : Diagnostic(Location), Kind(Kind) {} - ArrayRef getAffectedRegisters() const override { - return AffectedRegisters; - } - - void setOverwritingInstrs(ArrayRef Instrs) override { - OverwritingInstrs.assign(Instrs.begin(), Instrs.end()); - } + void generateReport(raw_ostream &OS, const BinaryContext &BC) const override; }; /// Report with a free-form message attached. -struct GenericReport : public Report { +struct GenericDiagnostic : public Diagnostic { std::string Text; - GenericReport(MCInstReference Location, StringRef Text) - : Report(Location), Text(Text) {} + GenericDiagnostic(MCInstReference Location, StringRef Text) + : Diagnostic(Location), Text(Text) {} virtual void generateReport(raw_ostream &OS, const BinaryContext &BC) const override; }; +/// Extra information about an issue collected on the slower, detailed, +/// run of the analysis. +class ExtraInfo { +public: + virtual void print(raw_ostream &OS, const MCInstReference Location) const = 0; + + virtual ~ExtraInfo() {} +}; + +class ClobberingInfo : public ExtraInfo { + SmallVector ClobberingInstrs; + +public: + ClobberingInfo(ArrayRef Instrs) : ClobberingInstrs(Instrs) {} + + void print(raw_ostream &OS, const MCInstReference Location) const override; +}; + +/// A brief version of a report that can be further augmented with the details. +/// +/// A half-baked report produced on the first run of the analysis. An extra, +/// analysis-specific information may be requested to be collected on the +/// second run. +template struct PartialReport { + PartialReport(std::shared_ptr Issue, + const std::optional RequestedDetails) + : Issue(Issue), RequestedDetails(RequestedDetails) {} + + std::shared_ptr Issue; + std::optional RequestedDetails; +}; + +/// A final version of the report. +struct FinalReport { + FinalReport(std::shared_ptr Issue, + std::shared_ptr Details) + : Issue(Issue), Details(Details) {} + + std::shared_ptr Issue; + std::shared_ptr Details; +}; + struct FunctionAnalysisResult { - std::vector> Diagnostics; + std::vector Diagnostics; +}; + +/// A helper class storing per-function context to be instantiated by Analysis. +class FunctionAnalysisContext { + BinaryContext &BC; + BinaryFunction &BF; + MCPlusBuilder::AllocatorIdTy AllocatorId; + FunctionAnalysisResult Result; + + bool PacRetGadgetsOnly; + + void findUnsafeUses(SmallVector> &Reports); + void augmentUnsafeUseReports(ArrayRef> Reports); + + /// Process the reports which do not have to be augmented, and remove them + /// from Reports. + void handleSimpleReports(SmallVector> &Reports); + +public: + FunctionAnalysisContext(BinaryFunction &BF, + MCPlusBuilder::AllocatorIdTy AllocatorId, + bool PacRetGadgetsOnly) + : BC(BF.getBinaryContext()), BF(BF), AllocatorId(AllocatorId), + PacRetGadgetsOnly(PacRetGadgetsOnly) {} + + void run(); + + const FunctionAnalysisResult &getResult() const { return Result; } }; class Analysis : public BinaryFunctionPass { @@ -271,12 +346,6 @@ class Analysis : public BinaryFunctionPass { void runOnFunction(BinaryFunction &Function, MCPlusBuilder::AllocatorIdTy AllocatorId); - FunctionAnalysisResult findGadgets(BinaryFunction &BF, - MCPlusBuilder::AllocatorIdTy AllocatorId); - - void computeDetailedInfo(BinaryFunction &BF, - MCPlusBuilder::AllocatorIdTy AllocatorId, - FunctionAnalysisResult &Result); std::map AnalysisResults; std::mutex AnalysisResultsMutex; diff --git a/bolt/lib/Passes/PAuthGadgetScanner.cpp b/bolt/lib/Passes/PAuthGadgetScanner.cpp index 92608aebce3ee..25a3153759a58 100644 --- a/bolt/lib/Passes/PAuthGadgetScanner.cpp +++ b/bolt/lib/Passes/PAuthGadgetScanner.cpp @@ -517,18 +517,11 @@ class SrcSafetyAnalysis { public: std::vector getLastClobberingInsts(const MCInst &Inst, BinaryFunction &BF, - ArrayRef UsedDirtyRegs) const { - if (RegsToTrackInstsFor.empty()) - return {}; + MCPhysReg ClobberedReg) const { const SrcState &S = getStateBefore(Inst); - // Due to aliasing registers, multiple registers may have been tracked. - std::set LastWritingInsts; - for (MCPhysReg TrackedReg : UsedDirtyRegs) { - for (const MCInst *Inst : lastWritingInsts(S, TrackedReg)) - LastWritingInsts.insert(Inst); - } + std::vector Result; - for (const MCInst *Inst : LastWritingInsts) { + for (const MCInst *Inst : lastWritingInsts(S, ClobberedReg)) { MCInstReference Ref = MCInstReference::get(Inst, BF); assert(Ref && "Expected Inst to be found"); Result.push_back(Ref); @@ -720,16 +713,32 @@ SrcSafetyAnalysis::create(BinaryFunction &BF, RegsToTrackInstsFor); } -static std::shared_ptr +// This function could return PartialReport, but currently T is always +// MCPhysReg, even though it is an implementation detail. +static PartialReport make_generic_report(MCInstReference Location, + StringRef Text) { + auto Report = std::make_shared(Location, Text); + return PartialReport(Report, std::nullopt); +} + +template +static PartialReport make_gadget_report(const GadgetKind &Kind, + MCInstReference Location, + T RequestedDetails) { + auto Report = std::make_shared(Kind, Location); + return PartialReport(Report, RequestedDetails); +} + +static std::optional> shouldReportReturnGadget(const BinaryContext &BC, const MCInstReference &Inst, const SrcState &S) { static const GadgetKind RetKind("non-protected ret found"); if (!BC.MIB->isReturn(Inst)) - return nullptr; + return std::nullopt; ErrorOr MaybeRetReg = BC.MIB->getRegUsedAsRetDest(Inst); if (MaybeRetReg.getError()) { - return std::make_shared( + return make_generic_report( Inst, "Warning: pac-ret analysis could not analyze this return " "instruction"); } @@ -740,26 +749,26 @@ shouldReportReturnGadget(const BinaryContext &BC, const MCInstReference &Inst, traceReg(BC, "Authenticated reg", BC.MIB->getAuthenticatedReg(Inst)); }); if (BC.MIB->isAuthenticationOfReg(Inst, RetReg)) - return nullptr; + return std::nullopt; LLVM_DEBUG({ traceRegMask(BC, "SafeToDerefRegs", S.SafeToDerefRegs); }); if (S.SafeToDerefRegs[RetReg]) - return nullptr; + return std::nullopt; - return std::make_shared(RetKind, Inst, RetReg); + return make_gadget_report(RetKind, Inst, RetReg); } -static std::shared_ptr +static std::optional> shouldReportCallGadget(const BinaryContext &BC, const MCInstReference &Inst, const SrcState &S) { static const GadgetKind CallKind("non-protected call found"); if (!BC.MIB->isIndirectCall(Inst) && !BC.MIB->isIndirectBranch(Inst)) - return nullptr; + return std::nullopt; bool IsAuthenticated = false; MCPhysReg DestReg = BC.MIB->getRegUsedAsIndirectBranchDest(Inst, IsAuthenticated); if (IsAuthenticated) - return nullptr; + return std::nullopt; assert(DestReg != BC.MIB->getNoRegister()); LLVM_DEBUG({ @@ -768,19 +777,19 @@ shouldReportCallGadget(const BinaryContext &BC, const MCInstReference &Inst, traceRegMask(BC, "SafeToDerefRegs", S.SafeToDerefRegs); }); if (S.SafeToDerefRegs[DestReg]) - return nullptr; + return std::nullopt; - return std::make_shared(CallKind, Inst, DestReg); + return make_gadget_report(CallKind, Inst, DestReg); } -static std::shared_ptr +static std::optional> shouldReportSigningOracle(const BinaryContext &BC, const MCInstReference &Inst, const SrcState &S) { static const GadgetKind SigningOracleKind("signing oracle found"); MCPhysReg SignedReg = BC.MIB->getSignedReg(Inst); if (SignedReg == BC.MIB->getNoRegister()) - return nullptr; + return std::nullopt; LLVM_DEBUG({ traceInst(BC, "Found sign inst", Inst); @@ -788,9 +797,9 @@ shouldReportSigningOracle(const BinaryContext &BC, const MCInstReference &Inst, traceRegMask(BC, "TrustedRegs", S.TrustedRegs); }); if (S.TrustedRegs[SignedReg]) - return nullptr; + return std::nullopt; - return std::make_shared(SigningOracleKind, Inst, SignedReg); + return make_gadget_report(SigningOracleKind, Inst, SignedReg); } template static void iterateOverInstrs(BinaryFunction &BF, T Fn) { @@ -804,11 +813,18 @@ template static void iterateOverInstrs(BinaryFunction &BF, T Fn) { } } -FunctionAnalysisResult -Analysis::findGadgets(BinaryFunction &BF, - MCPlusBuilder::AllocatorIdTy AllocatorId) { - FunctionAnalysisResult Result; +static SmallVector +collectRegsToTrack(ArrayRef> Reports) { + SmallSet RegsToTrack; + for (auto Report : Reports) + if (Report.RequestedDetails) + RegsToTrack.insert(*Report.RequestedDetails); + + return SmallVector(RegsToTrack.begin(), RegsToTrack.end()); +} +void FunctionAnalysisContext::findUnsafeUses( + SmallVector> &Reports) { auto Analysis = SrcSafetyAnalysis::create(BF, AllocatorId, {}); LLVM_DEBUG({ dbgs() << "Running src register safety analysis...\n"; }); Analysis->run(); @@ -817,45 +833,35 @@ Analysis::findGadgets(BinaryFunction &BF, BF.dump(); }); - BinaryContext &BC = BF.getBinaryContext(); iterateOverInstrs(BF, [&](MCInstReference Inst) { const SrcState &S = Analysis->getStateBefore(Inst); // If non-empty state was never propagated from the entry basic block // to Inst, assume it to be unreachable and report a warning. if (S.empty()) { - Result.Diagnostics.push_back(std::make_shared( - Inst, "Warning: unreachable instruction found")); + Reports.push_back( + make_generic_report(Inst, "Warning: unreachable instruction found")); return; } if (auto Report = shouldReportReturnGadget(BC, Inst, S)) - Result.Diagnostics.push_back(Report); + Reports.push_back(*Report); if (PacRetGadgetsOnly) return; if (auto Report = shouldReportCallGadget(BC, Inst, S)) - Result.Diagnostics.push_back(Report); + Reports.push_back(*Report); if (auto Report = shouldReportSigningOracle(BC, Inst, S)) - Result.Diagnostics.push_back(Report); + Reports.push_back(*Report); }); - return Result; } -void Analysis::computeDetailedInfo(BinaryFunction &BF, - MCPlusBuilder::AllocatorIdTy AllocatorId, - FunctionAnalysisResult &Result) { - BinaryContext &BC = BF.getBinaryContext(); - - // Collect the affected registers across all gadgets found in this function. - SmallSet RegsToTrack; - for (auto Report : Result.Diagnostics) - RegsToTrack.insert_range(Report->getAffectedRegisters()); - std::vector RegsToTrackVec(RegsToTrack.begin(), RegsToTrack.end()); - +void FunctionAnalysisContext::augmentUnsafeUseReports( + ArrayRef> Reports) { + SmallVector RegsToTrack = collectRegsToTrack(Reports); // Re-compute the analysis with register tracking. - auto Analysis = SrcSafetyAnalysis::create(BF, AllocatorId, RegsToTrackVec); + auto Analysis = SrcSafetyAnalysis::create(BF, AllocatorId, RegsToTrack); LLVM_DEBUG( { dbgs() << "\nRunning detailed src register safety analysis...\n"; }); Analysis->run(); @@ -865,32 +871,51 @@ void Analysis::computeDetailedInfo(BinaryFunction &BF, }); // Augment gadget reports. - for (auto Report : Result.Diagnostics) { - LLVM_DEBUG( - { traceInst(BC, "Attaching clobbering info to", Report->Location); }); - (void)BC; - Report->setOverwritingInstrs(Analysis->getLastClobberingInsts( - Report->Location, BF, Report->getAffectedRegisters())); + for (auto &Report : Reports) { + MCInstReference Location = Report.Issue->Location; + LLVM_DEBUG({ traceInst(BC, "Attaching clobbering info to", Location); }); + assert(Report.RequestedDetails && + "Should be removed by handleSimpleReports"); + auto DetailedInfo = + std::make_shared(Analysis->getLastClobberingInsts( + Location, BF, *Report.RequestedDetails)); + Result.Diagnostics.emplace_back(Report.Issue, DetailedInfo); } } -void Analysis::runOnFunction(BinaryFunction &BF, - MCPlusBuilder::AllocatorIdTy AllocatorId) { +void FunctionAnalysisContext::handleSimpleReports( + SmallVector> &Reports) { + // Before re-running the detailed analysis, process the reports which do not + // need any additional details to be attached. + for (auto &Report : Reports) { + if (!Report.RequestedDetails) + Result.Diagnostics.emplace_back(Report.Issue, nullptr); + } + llvm::erase_if(Reports, [](const auto &R) { return !R.RequestedDetails; }); +} + +void FunctionAnalysisContext::run() { LLVM_DEBUG({ - dbgs() << "Analyzing in function " << BF.getPrintName() << ", AllocatorId " - << AllocatorId << "\n"; + dbgs() << "Analyzing function " << BF.getPrintName() + << ", AllocatorId = " << AllocatorId << "\n"; BF.dump(); }); - FunctionAnalysisResult FAR = findGadgets(BF, AllocatorId); - if (FAR.Diagnostics.empty()) - return; + SmallVector> UnsafeUses; + findUnsafeUses(UnsafeUses); + handleSimpleReports(UnsafeUses); + if (!UnsafeUses.empty()) + augmentUnsafeUseReports(UnsafeUses); +} - // Redo the analysis, but now also track which instructions last wrote - // to any of the registers in RetRegsWithGadgets, so that better - // diagnostics can be produced. +void Analysis::runOnFunction(BinaryFunction &BF, + MCPlusBuilder::AllocatorIdTy AllocatorId) { + FunctionAnalysisContext FA(BF, AllocatorId, PacRetGadgetsOnly); + FA.run(); - computeDetailedInfo(BF, AllocatorId, FAR); + const FunctionAnalysisResult &FAR = FA.getResult(); + if (FAR.Diagnostics.empty()) + return; // `runOnFunction` is typically getting called from multiple threads in // parallel. Therefore, use a lock to avoid data races when storing the @@ -918,23 +943,21 @@ static void printBB(const BinaryContext &BC, const BinaryBasicBlock *BB, } } -static void reportFoundGadgetInSingleBBSingleOverwInst( - raw_ostream &OS, const BinaryContext &BC, const MCInstReference OverwInst, +static void reportFoundGadgetInSingleBBSingleRelatedInst( + raw_ostream &OS, const BinaryContext &BC, const MCInstReference RelatedInst, const MCInstReference Location) { BinaryBasicBlock *BB = Location.getBasicBlock(); - assert(OverwInst.ParentKind == MCInstReference::BasicBlockParent); + assert(RelatedInst.ParentKind == MCInstReference::BasicBlockParent); assert(Location.ParentKind == MCInstReference::BasicBlockParent); - MCInstInBBReference OverwInstBB = OverwInst.U.BBRef; - if (BB == OverwInstBB.BB) { - // overwriting inst and ret instruction are in the same basic block. - assert(OverwInstBB.BBIndex < Location.U.BBRef.BBIndex); + MCInstInBBReference RelatedInstBB = RelatedInst.U.BBRef; + if (BB == RelatedInstBB.BB) { OS << " This happens in the following basic block:\n"; printBB(BC, BB); } } -void Report::printBasicInfo(raw_ostream &OS, const BinaryContext &BC, - StringRef IssueKind) const { +void Diagnostic::printBasicInfo(raw_ostream &OS, const BinaryContext &BC, + StringRef IssueKind) const { BinaryFunction *BF = Location.getFunction(); BinaryBasicBlock *BB = Location.getBasicBlock(); @@ -947,36 +970,47 @@ void Report::printBasicInfo(raw_ostream &OS, const BinaryContext &BC, BC.printInstruction(OS, Location, Location.getAddress(), BF); } -void GadgetReport::generateReport(raw_ostream &OS, - const BinaryContext &BC) const { +void GadgetDiagnostic::generateReport(raw_ostream &OS, + const BinaryContext &BC) const { printBasicInfo(OS, BC, Kind.getDescription()); +} + +static void printRelatedInstrs(raw_ostream &OS, const MCInstReference Location, + ArrayRef RelatedInstrs) { + const BinaryFunction &BF = *Location.getFunction(); + const BinaryContext &BC = BF.getBinaryContext(); - BinaryFunction *BF = Location.getFunction(); - OS << " The " << OverwritingInstrs.size() - << " instructions that write to the affected registers after any " - "authentication are:\n"; // Sort by address to ensure output is deterministic. - SmallVector OI = OverwritingInstrs; - llvm::sort(OI, [](const MCInstReference &A, const MCInstReference &B) { + SmallVector RI(RelatedInstrs); + llvm::sort(RI, [](const MCInstReference &A, const MCInstReference &B) { return A.getAddress() < B.getAddress(); }); - for (unsigned I = 0; I < OI.size(); ++I) { - MCInstReference InstRef = OI[I]; + for (unsigned I = 0; I < RI.size(); ++I) { + MCInstReference InstRef = RI[I]; OS << " " << (I + 1) << ". "; - BC.printInstruction(OS, InstRef, InstRef.getAddress(), BF); + BC.printInstruction(OS, InstRef, InstRef.getAddress(), &BF); }; - if (OverwritingInstrs.size() == 1) { - const MCInstReference OverwInst = OverwritingInstrs[0]; + if (RelatedInstrs.size() == 1) { + const MCInstReference RelatedInst = RelatedInstrs[0]; // Printing the details for the MCInstReference::FunctionParent case // is not implemented not to overcomplicate the code, as most functions // are expected to have CFG information. - if (OverwInst.ParentKind == MCInstReference::BasicBlockParent) - reportFoundGadgetInSingleBBSingleOverwInst(OS, BC, OverwInst, Location); + if (RelatedInst.ParentKind == MCInstReference::BasicBlockParent) + reportFoundGadgetInSingleBBSingleRelatedInst(OS, BC, RelatedInst, + Location); } } -void GenericReport::generateReport(raw_ostream &OS, - const BinaryContext &BC) const { +void ClobberingInfo::print(raw_ostream &OS, + const MCInstReference Location) const { + OS << " The " << ClobberingInstrs.size() + << " instructions that write to the affected registers after any " + "authentication are:\n"; + printRelatedInstrs(OS, Location, ClobberingInstrs); +} + +void GenericDiagnostic::generateReport(raw_ostream &OS, + const BinaryContext &BC) const { printBasicInfo(OS, BC, Text); } @@ -994,11 +1028,15 @@ Error Analysis::runOnFunctions(BinaryContext &BC) { BC, ParallelUtilities::SchedulingPolicy::SP_INST_LINEAR, WorkFun, SkipFunc, "PAuthGadgetScanner"); - for (BinaryFunction *BF : BC.getAllBinaryFunctions()) - if (AnalysisResults.count(BF) > 0) { - for (const std::shared_ptr &R : AnalysisResults[BF].Diagnostics) - R->generateReport(outs(), BC); + for (BinaryFunction *BF : BC.getAllBinaryFunctions()) { + if (!AnalysisResults.count(BF)) + continue; + for (const FinalReport &R : AnalysisResults[BF].Diagnostics) { + R.Issue->generateReport(outs(), BC); + if (R.Details) + R.Details->print(outs(), R.Issue->Location); } + } return Error::success(); } diff --git a/bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s b/bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s index 2193d40131478..284f0bea607a5 100644 --- a/bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s +++ b/bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s @@ -217,6 +217,7 @@ f_callclobbered_calleesaved: f_unreachable_instruction: // CHECK-LABEL: GS-PAUTH: Warning: unreachable instruction found in function f_unreachable_instruction, basic block {{[0-9a-zA-Z.]+}}, at address // CHECK-NEXT: The instruction is {{[0-9a-f]+}}: add x0, x1, x2 +// CHECK-NOT: instructions that write to the affected registers after any authentication are: b 1f add x0, x1, x2 1: diff --git a/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s b/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s index e0e8471c36a7e..078a8aca72d9c 100644 --- a/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s +++ b/bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s @@ -24,7 +24,7 @@ simple: ret .size simple, .-simple -// CHECK-LABEL:Analyzing in function simple, AllocatorId 1 +// CHECK-LABEL:Analyzing function simple, AllocatorId = 1 // CHECK-NEXT: Binary Function "simple" { // CHECK-NEXT: Number : 1 // CHECK-NEXT: State : CFG constructed @@ -129,7 +129,7 @@ clobber: ret .size clobber, .-clobber -// CHECK-LABEL:Analyzing in function clobber, AllocatorId 1 +// CHECK-LABEL:Analyzing function clobber, AllocatorId = 1 // ... // CHECK: Running src register safety analysis... // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( mov w30, #0x0, src-state) @@ -174,7 +174,7 @@ nocfg: ret .size nocfg, .-nocfg -// CHECK-LABEL:Analyzing in function nocfg, AllocatorId 1 +// CHECK-LABEL:Analyzing function nocfg, AllocatorId = 1 // CHECK-NEXT: Binary Function "nocfg" { // CHECK-NEXT: Number : 3 // CHECK-NEXT: State : disassembled @@ -254,7 +254,7 @@ nocfg: // CHECK-EMPTY: // CHECK-NEXT: Attaching clobbering info to: 00000000: ret # Offset: 8 # CFGUnawareSrcSafetyAnalysis: src-state -// CHECK-LABEL:Analyzing in function main, AllocatorId 1 +// CHECK-LABEL:Analyzing function main, AllocatorId = 1 .globl main .type main,@function main: