https://github.com/matthewlevy97 created 
https://github.com/llvm/llvm-project/pull/177390

RFC: 
https://discourse.llvm.org/t/rfc-implement-analysis-for-exploit-mitigation-coverage/84326

The goal of this stack is to provide a metric to audit the deployed mitigations 
in a binary and where they are enabled at function level granularity. This will 
enable tracking of where we do and don't have mitigations, versus the current 
approach of tracking where flags are passed. This is useful for several reasons 
including:

Providing assertions on mitigation deployment. For example, tools like checksec 
can alert of stack protector usage but cannot state which functions are enabled 
and why ("normal", "strong", or "all" option). The alternative to this method 
is binary analysis which has its own pros/cons.

Tracking of partial mitigation enablement. Some large projects might not want a 
boolean enablement of mitigations for multiple reasons (e.g., performance, 
size, etc), and so partial enablement is desired. This should provide accurate 
tracking over which functions have a given mitigation to better support 
incremental approaches.

Two flags are added to control this behavior:

Compile time -fmitigation-analysis to generate the metadata pertaining to 
mitigation enablement/disablement
Link time -mitigation-summary allows JSON output or embedding of custom section 
during LTO

>From 60233da47ed9760e68231c1e47c42c5e1712f204 Mon Sep 17 00:00:00 2001
From: Matthew Levy <[email protected]>
Date: Fri, 5 Dec 2025 16:13:26 -0500
Subject: [PATCH 1/2] [SoftwareBillOfMitigations] Add Metadata Insertion Logic

This diff is the start of a stack to enable tracking of security control
deployments in a binary. The metadata added by this diff tracks if something
is available and can be enabled. The "can be" enabled is important as there
are no guarantees that during IR codegen/optimizations the logic can be removed.

Add logic to attach metadata for functions (if the `-fmitigation-analysis` 
compiler flag
is set) for the following mitigations/preventions:
- Stack Clash Protection
- Stack Protector/Strong/All
- CFI-ICall, CFI-VCall, CFI-NVCall
- Auto Variable Initialization
---
 clang/include/clang/Basic/CodeGenOptions.def  |   1 +
 .../include/clang/CodeGen/MitigationTagging.h |  35 +++
 clang/include/clang/Options/Options.td        |   9 +
 clang/lib/CodeGen/CGBuiltin.cpp               |  12 +-
 clang/lib/CodeGen/CGClass.cpp                 |  13 +
 clang/lib/CodeGen/CGDecl.cpp                  |   7 +
 clang/lib/CodeGen/CGExpr.cpp                  |   6 +
 clang/lib/CodeGen/CGExprCXX.cpp               |   7 +
 clang/lib/CodeGen/CMakeLists.txt              |   1 +
 clang/lib/CodeGen/CodeGenModule.cpp           |  23 ++
 clang/lib/CodeGen/MitigationTagging.cpp       |  67 ++++
 clang/lib/Driver/ToolChains/Clang.cpp         |   3 +
 clang/unittests/CodeGen/CMakeLists.txt        |   1 +
 .../CodeGen/MitigationTaggingTest.cpp         | 287 ++++++++++++++++++
 llvm/include/llvm/Support/MitigationMarker.h  |  42 +++
 llvm/lib/Support/CMakeLists.txt               |   1 +
 llvm/lib/Support/MitigationMarker.cpp         |  25 ++
 17 files changed, 539 insertions(+), 1 deletion(-)
 create mode 100644 clang/include/clang/CodeGen/MitigationTagging.h
 create mode 100644 clang/lib/CodeGen/MitigationTagging.cpp
 create mode 100644 clang/unittests/CodeGen/MitigationTaggingTest.cpp
 create mode 100644 llvm/include/llvm/Support/MitigationMarker.h
 create mode 100644 llvm/lib/Support/MitigationMarker.cpp

diff --git a/clang/include/clang/Basic/CodeGenOptions.def 
b/clang/include/clang/Basic/CodeGenOptions.def
index 76a6463881c6f..fae379ace9068 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -187,6 +187,7 @@ CODEGENOPT(NoTypeCheck       , 1, 0, Benign) ///< Set when 
-Wa,--no-type-check i
 CODEGENOPT(MisExpect         , 1, 0, Benign) ///< Set when -Wmisexpect is 
enabled
 CODEGENOPT(EnableSegmentedStacks , 1, 0, Benign) ///< Set when -fsplit-stack 
is enabled.
 CODEGENOPT(StackClashProtector, 1, 0, Benign) ///< Set when 
-fstack-clash-protection is enabled.
+CODEGENOPT(MitigationAnalysis, 1, 0, Benign) ///< Set when 
-fmitigation-analysis is enabled.
 CODEGENOPT(NoImplicitFloat   , 1, 0, Benign) ///< Set when -mno-implicit-float 
is enabled.
 CODEGENOPT(NullPointerIsValid , 1, 0, Benign) ///< Assume Null pointer 
deference is defined.
 CODEGENOPT(OpenCLCorrectlyRoundedDivSqrt, 1, 0, Benign) ///< 
-cl-fp32-correctly-rounded-divide-sqrt
diff --git a/clang/include/clang/CodeGen/MitigationTagging.h 
b/clang/include/clang/CodeGen/MitigationTagging.h
new file mode 100644
index 0000000000000..3ccafdf8fa87a
--- /dev/null
+++ b/clang/include/clang/CodeGen/MitigationTagging.h
@@ -0,0 +1,35 @@
+//===--- MitigationTagging.h - Emit LLVM Code from ASTs for a Module 
------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This enables tagging functions with metadata to indicate mitigations are
+// applied to them.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_CODEGEN_MITIGATIONTAGGING_H
+#define LLVM_CLANG_LIB_CODEGEN_MITIGATIONTAGGING_H
+
+#include "llvm/IR/Function.h"
+#include "llvm/Support/MitigationMarker.h"
+
+namespace clang {
+namespace CodeGen {
+
+class CodeGenFunction;
+
+void AttachMitigationMetadataToFunction(llvm::Function &F,
+                                        enum llvm::MitigationKey Key,
+                                        bool MitigationEnable);
+void AttachMitigationMetadataToFunction(CodeGenFunction &CGF,
+                                        enum llvm::MitigationKey Key,
+                                        bool MitigationEnable);
+
+} // namespace CodeGen
+} // namespace clang
+
+#endif
diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index c6841937c8d39..77572c95b32e5 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -4207,6 +4207,15 @@ def ftrivial_auto_var_init_max_size : Joined<["-"], 
"ftrivial-auto-var-init-max-
   Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>,
   HelpText<"Stop initializing trivial automatic stack variables if var size 
exceeds the specified number of instances (in bytes)">,
   MarshallingInfoInt<LangOpts<"TrivialAutoVarInitMaxSize">>;
+defm mitigation_analysis
+    : BoolFOption<"mitigation-analysis", CodeGenOpts<"MitigationAnalysis">,
+                  DefaultFalse,
+                  PosFlag<SetTrue, [], [ClangOption, CC1Option], "Enable">,
+                  NegFlag<SetFalse, [], [ClangOption], "Disable">,
+                  BothFlags<[], [ClangOption], " mitigation analysis">>,
+      DocBrief<"Instrument mitigations/preventions (Stack Protectors, "
+               "Auto-Var-Init, StackClashProtection, etc.) to analyze their "
+               "coverage">;
 def fstandalone_debug : Flag<["-"], "fstandalone-debug">, Group<f_Group>,
   Visibility<[ClangOption, CLOption, DXCOption]>,
   HelpText<"Emit full debug info for all types used by the program">;
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 01be374422d93..845a167a5d159 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -28,6 +28,7 @@
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Basic/TargetInfo.h"
+#include "clang/CodeGen/MitigationTagging.h"
 #include "llvm/IR/InlineAsm.h"
 #include "llvm/IR/Instruction.h"
 #include "llvm/IR/Intrinsics.h"
@@ -154,6 +155,9 @@ static void initializeAlloca(CodeGenFunction &CGF, 
AllocaInst *AI, Value *Size,
   switch (CGF.getLangOpts().getTrivialAutoVarInit()) {
   case LangOptions::TrivialAutoVarInitKind::Uninitialized:
     // Nothing to initialize.
+    if (CGF.CGM.getCodeGenOpts().MitigationAnalysis)
+      AttachMitigationMetadataToFunction(CGF, MitigationKey::AUTO_VAR_INIT,
+                                         false);
     return;
   case LangOptions::TrivialAutoVarInitKind::Zero:
     Byte = CGF.Builder.getInt8(0x00);
@@ -165,8 +169,14 @@ static void initializeAlloca(CodeGenFunction &CGF, 
AllocaInst *AI, Value *Size,
     break;
   }
   }
-  if (CGF.CGM.stopAutoInit())
+
+  if (CGF.CGM.getCodeGenOpts().MitigationAnalysis)
+    AttachMitigationMetadataToFunction(CGF, MitigationKey::AUTO_VAR_INIT,
+                                       !CGF.CGM.stopAutoInit());
+
+  if (CGF.CGM.stopAutoInit()) {
     return;
+  }
   auto *I = CGF.Builder.CreateMemSet(AI, Byte, Size, AlignmentInBytes);
   I->addAnnotationMetadata("auto-init");
 }
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index f782b0cd17da4..8697a6ec8c8b9 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -26,6 +26,7 @@
 #include "clang/AST/StmtCXX.h"
 #include "clang/Basic/CodeGenOptions.h"
 #include "clang/CodeGen/CGFunctionInfo.h"
+#include "clang/CodeGen/MitigationTagging.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/Support/SaveAndRestore.h"
@@ -2846,6 +2847,10 @@ void CodeGenFunction::EmitTypeMetadataCodeForVCall(const 
CXXRecordDecl *RD,
     llvm::Value *TypeTest =
         Builder.CreateCall(CGM.getIntrinsic(IID), {VTable, TypeId});
     Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::assume), TypeTest);
+
+    if (CGM.getCodeGenOpts().MitigationAnalysis)
+      AttachMitigationMetadataToFunction(*this, llvm::MitigationKey::CFI_VCALL,
+                                         SanOpts.has(SanitizerKind::CFIVCall));
   }
 }
 
@@ -3033,6 +3038,14 @@ llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
     EmitCheck(std::make_pair(CheckResult, CheckOrdinal), CheckHandler, {}, {});
   }
 
+  if (CGM.getCodeGenOpts().MitigationAnalysis) {
+    auto CFIVCallEnabled = SanOpts.has(SanitizerKind::CFIVCall) &&
+                           !getContext().getNoSanitizeList().containsType(
+                               SanitizerKind::CFIVCall, TypeName);
+    AttachMitigationMetadataToFunction(*this, llvm::MitigationKey::CFI_VCALL,
+                                       CFIVCallEnabled);
+  }
+
   return Builder.CreateBitCast(Builder.CreateExtractValue(CheckedLoad, 0),
                                VTableTy);
 }
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 8b1cd83af2396..8e984332334fc 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -33,6 +33,7 @@
 #include "clang/Basic/CodeGenOptions.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/CodeGen/CGFunctionInfo.h"
+#include "clang/CodeGen/MitigationTagging.h"
 #include "clang/Sema/Sema.h"
 #include "llvm/Analysis/ConstantFolding.h"
 #include "llvm/Analysis/ValueTracking.h"
@@ -1988,6 +1989,12 @@ void CodeGenFunction::EmitAutoVarInit(const 
AutoVarEmission &emission) {
            ? LangOptions::TrivialAutoVarInitKind::Uninitialized
            : getContext().getLangOpts().getTrivialAutoVarInit());
 
+  if (CGM.getCodeGenOpts().MitigationAnalysis)
+    AttachMitigationMetadataToFunction(
+        *this, llvm::MitigationKey::AUTO_VAR_INIT,
+        trivialAutoVarInit !=
+            LangOptions::TrivialAutoVarInitKind::Uninitialized);
+
   auto initializeWhatIsTechnicallyUninitialized = [&](Address Loc) {
     if (trivialAutoVarInit ==
         LangOptions::TrivialAutoVarInitKind::Uninitialized)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 3bde8e1fa2ac3..2fe16eb85abff 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -37,6 +37,7 @@
 #include "clang/Basic/CodeGenOptions.h"
 #include "clang/Basic/Module.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/CodeGen/MitigationTagging.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/StringExtras.h"
@@ -6603,6 +6604,11 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
 
   bool CFIUnchecked = CalleeType->hasPointeeToCFIUncheckedCalleeFunctionType();
 
+  if (CGM.getCodeGenOpts().MitigationAnalysis &&
+      (!TargetDecl || !isa<FunctionDecl>(TargetDecl)))
+    AttachMitigationMetadataToFunction(*this, llvm::MitigationKey::CFI_ICALL,
+                                       SanOpts.has(SanitizerKind::CFIICall));
+
   // If we are checking indirect calls and this call is indirect, check that 
the
   // function pointer is a member of the bit set for the function type.
   if (SanOpts.has(SanitizerKind::CFIICall) &&
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index ce2ed9026fa1f..6b1b1be2e56ae 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -19,6 +19,7 @@
 #include "TargetInfo.h"
 #include "clang/Basic/CodeGenOptions.h"
 #include "clang/CodeGen/CGFunctionInfo.h"
+#include "clang/CodeGen/MitigationTagging.h"
 #include "llvm/IR/Intrinsics.h"
 
 using namespace clang;
@@ -416,6 +417,12 @@ RValue 
CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
       EmitVTablePtrCheckForCall(RD, VTable, CFITCK_NVCall, CE->getBeginLoc());
     }
 
+    if (CGM.getCodeGenOpts().MitigationAnalysis &&
+        MD->getParent()->isDynamicClass()) {
+      AttachMitigationMetadataToFunction(*this, 
llvm::MitigationKey::CFI_NVCALL,
+                                         
SanOpts.has(SanitizerKind::CFINVCall));
+    }
+
     if (getLangOpts().AppleKext && MD->isVirtual() && HasQualifier)
       Callee = BuildAppleKextVirtualCall(MD, Qualifier, Ty);
     else if (!DevirtualizedMethod)
diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt
index ad9ef91c781a8..459f483d86d7b 100644
--- a/clang/lib/CodeGen/CMakeLists.txt
+++ b/clang/lib/CodeGen/CMakeLists.txt
@@ -112,6 +112,7 @@ add_clang_library(clangCodeGen
   LinkInModulesPass.cpp
   MacroPPCallbacks.cpp
   MicrosoftCXXABI.cpp
+  MitigationTagging.cpp
   ModuleBuilder.cpp
   ObjectFilePCHContainerWriter.cpp
   PatternInit.cpp
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp 
b/clang/lib/CodeGen/CodeGenModule.cpp
index 1dcf94fc35e07..98518bbb60222 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -47,6 +47,7 @@
 #include "clang/Basic/Version.h"
 #include "clang/CodeGen/BackendUtil.h"
 #include "clang/CodeGen/ConstantInitBuilder.h"
+#include "clang/CodeGen/MitigationTagging.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringSwitch.h"
@@ -2747,6 +2748,28 @@ void 
CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
   else if (isStackProtectorOn(LangOpts, getTriple(), LangOptions::SSPReq))
     B.addAttribute(llvm::Attribute::StackProtectReq);
 
+  if (CodeGenOpts.MitigationAnalysis) {
+    AttachMitigationMetadataToFunction(
+        *F, llvm::MitigationKey::STACK_CLASH_PROTECTION,
+        CodeGenOpts.StackClashProtector);
+
+    if (!(D && D->hasAttr<NoStackProtectorAttr>())) {
+      bool stackProtectOn =
+          isStackProtectorOn(LangOpts, getTriple(), LangOptions::SSPOn);
+      bool stackProtectStrong =
+          isStackProtectorOn(LangOpts, getTriple(), LangOptions::SSPStrong);
+      bool stackProtectAll =
+          isStackProtectorOn(LangOpts, getTriple(), LangOptions::SSPReq);
+
+      AttachMitigationMetadataToFunction(
+          *F, llvm::MitigationKey::STACK_PROTECTOR, stackProtectOn);
+      AttachMitigationMetadataToFunction(
+          *F, llvm::MitigationKey::STACK_PROTECTOR_STRONG, stackProtectStrong);
+      AttachMitigationMetadataToFunction(
+          *F, llvm::MitigationKey::STACK_PROTECTOR_ALL, stackProtectAll);
+    }
+  }
+
   if (!D) {
     // Non-entry HLSL functions must always be inlined.
     if (getLangOpts().HLSL && !F->hasFnAttribute(llvm::Attribute::NoInline))
diff --git a/clang/lib/CodeGen/MitigationTagging.cpp 
b/clang/lib/CodeGen/MitigationTagging.cpp
new file mode 100644
index 0000000000000..e009d90a788a6
--- /dev/null
+++ b/clang/lib/CodeGen/MitigationTagging.cpp
@@ -0,0 +1,67 @@
+//===--- MitigationTagging.cpp - Emit LLVM Code from ASTs for a Module 
----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This enables tagging functions with metadata to indicate mitigations are
+// applied to them.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/CodeGen/MitigationTagging.h"
+#include "CodeGenFunction.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/Support/FormatVariadic.h"
+
+namespace clang {
+namespace CodeGen {
+
+///
+/// Store metadata (tied to the function) related to enablement of mitigations.
+/// @param Key - identifier for the mitigation
+/// @param MitigationEnable - if the mitigation is enabled for the target
+/// function
+///
+void AttachMitigationMetadataToFunction(llvm::Function &F,
+                                        enum llvm::MitigationKey Key,
+                                        bool MitigationEnable) {
+  llvm::LLVMContext &Context = F.getContext();
+
+  const auto &MitigationToString = llvm::GetMitigationMetadataMapping();
+  auto KV = MitigationToString.find(Key);
+  if (KV == MitigationToString.end())
+    return;
+
+  unsigned KindID = Context.getMDKindID(KV->second);
+
+  // Only set once
+  if (!F.getMetadata(KindID)) {
+    llvm::Metadata *ValueMD =
+        llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+            llvm::Type::getInt1Ty(Context), MitigationEnable));
+    F.setMetadata(KindID, llvm::MDNode::get(Context, ValueMD));
+  }
+}
+
+///
+/// Store metadata (tied to the function) related to enablement of mitigations.
+/// Checks if MitigationAnalysis CodeGenOpt is set first and is a no-op if
+/// unset.
+/// @param Key - identifier for the mitigation
+/// @param MitigationEnable - if the mitigation is enabled for the target
+/// function
+///
+void AttachMitigationMetadataToFunction(CodeGenFunction &CGF,
+                                        enum llvm::MitigationKey Key,
+                                        bool MitigationEnable) {
+  if (CGF.CGM.getCodeGenOpts().MitigationAnalysis)
+    AttachMitigationMetadataToFunction(*(CGF.CurFn), Key, MitigationEnable);
+}
+
+} // namespace CodeGen
+} // namespace clang
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index 0380568412e62..86f52df6bdc21 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6826,6 +6826,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
   RenderSCPOptions(TC, Args, CmdArgs);
   RenderTrivialAutoVarInitOptions(D, TC, Args, CmdArgs);
 
+  Args.addOptInFlag(CmdArgs, options::OPT_fmitigation_analysis,
+                    options::OPT_fno_mitigation_analysis);
+
   Args.AddLastArg(CmdArgs, options::OPT_fswift_async_fp_EQ);
 
   Args.addOptInFlag(CmdArgs, options::OPT_mstackrealign,
diff --git a/clang/unittests/CodeGen/CMakeLists.txt 
b/clang/unittests/CodeGen/CMakeLists.txt
index d4efb2230a054..3c36430e72550 100644
--- a/clang/unittests/CodeGen/CMakeLists.txt
+++ b/clang/unittests/CodeGen/CMakeLists.txt
@@ -4,6 +4,7 @@ add_clang_unittest(ClangCodeGenTests
   DemangleTrapReasonInDebugInfo.cpp
   TBAAMetadataTest.cpp
   CheckTargetFeaturesTest.cpp
+  MitigationTaggingTest.cpp
   CLANG_LIBS
   clangAST
   clangBasic
diff --git a/clang/unittests/CodeGen/MitigationTaggingTest.cpp 
b/clang/unittests/CodeGen/MitigationTaggingTest.cpp
new file mode 100644
index 0000000000000..b9bb7c19f495d
--- /dev/null
+++ b/clang/unittests/CodeGen/MitigationTaggingTest.cpp
@@ -0,0 +1,287 @@
+#include "TestCompiler.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/CodeGen/MitigationTagging.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/ParseAST.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/MitigationMarker.h"
+#include "llvm/TargetParser/Host.h"
+#include "llvm/TargetParser/Triple.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+using namespace clang::CodeGen;
+
+namespace {
+static const char TestProgram[] = "void SomeTestFunction(int x, int y)  "
+                                  "{                                    "
+                                  "   char buf[x];                      "
+                                  "   while(y)                          "
+                                  "      buf[y--] = 0;                  "
+                                  "}                                    ";
+static constexpr char TestFunctionMangledName[] = "_Z16SomeTestFunctionii";
+
+static int GetEnablementForMitigation(llvm::Function *FuncPtr,
+                                      StringRef MitigationStr) {
+  auto *MD = FuncPtr->getMetadata(MitigationStr);
+  // If not found, it just means the mitigation is likely not available
+  if (!MD)
+    return 0;
+
+  if (MD->getNumOperands() != 1)
+    return -1;
+
+  auto *ConstAsMeta = dyn_cast<ConstantAsMetadata>(MD->getOperand(0));
+  if (!ConstAsMeta)
+    return -2;
+
+  auto *Value = ConstAsMeta->getValue();
+
+  return Value->isOneValue();
+}
+
+TEST(MitigationTaggingTest, FlagDisabled) {
+  clang::LangOptions LO;
+  LO.CPlusPlus = 1;
+  LO.CPlusPlus11 = 1;
+
+  clang::CodeGenOptions CGO;
+
+  TestCompiler Compiler(LO, CGO);
+  Compiler.init(TestProgram);
+
+  clang::ParseAST(Compiler.compiler.getSema(), false, false);
+  auto M =
+      static_cast<clang::CodeGenerator &>(Compiler.compiler.getASTConsumer())
+          .GetModule();
+  auto FuncPtr = M->getFunction(TestFunctionMangledName);
+  ASSERT_TRUE(FuncPtr != nullptr);
+
+  auto Mapping = GetMitigationMetadataMapping();
+  auto *MD =
+      FuncPtr->getMetadata(Mapping[MitigationKey::STACK_CLASH_PROTECTION]);
+  ASSERT_TRUE(MD == nullptr);
+}
+
+TEST(MitigationTaggingTest, MetadataEnabledOnly) {
+  clang::CodeGenOptions CGO;
+  CGO.MitigationAnalysis = true;
+
+  clang::LangOptions LO;
+  LO.CPlusPlus = 1;
+  LO.CPlusPlus11 = 1;
+
+  TestCompiler Compiler(LO, CGO);
+  Compiler.init(TestProgram);
+
+  clang::ParseAST(Compiler.compiler.getSema(), false, false);
+  auto M =
+      static_cast<clang::CodeGenerator &>(Compiler.compiler.getASTConsumer())
+          .GetModule();
+  auto FuncPtr = M->getFunction(TestFunctionMangledName);
+  ASSERT_TRUE(FuncPtr != nullptr);
+
+  // Check that all mitigations disabled
+  for (const auto &[MitigationKey, MitigationStr] :
+       GetMitigationMetadataMapping()) {
+    EXPECT_EQ(GetEnablementForMitigation(FuncPtr, MitigationStr), 0);
+  }
+}
+
+TEST(MitigationTaggingTest, AutoVarInitZeroEnabled) {
+  clang::CodeGenOptions CGO;
+  CGO.MitigationAnalysis = true;
+
+  clang::LangOptions LO;
+  LO.CPlusPlus = 1;
+  LO.CPlusPlus11 = 1;
+  LO.setTrivialAutoVarInit(LangOptions::TrivialAutoVarInitKind::Zero);
+
+  TestCompiler Compiler(LO, CGO);
+  Compiler.init(TestProgram);
+
+  clang::ParseAST(Compiler.compiler.getSema(), false, false);
+  auto M =
+      static_cast<clang::CodeGenerator &>(Compiler.compiler.getASTConsumer())
+          .GetModule();
+  auto FuncPtr = M->getFunction(TestFunctionMangledName);
+  ASSERT_TRUE(FuncPtr != nullptr);
+
+  // Check that the correct mitigations are enabled
+  auto mitigationMetadataMapping = GetMitigationMetadataMapping();
+  for (const auto &[MitigationKey, MitigationStr] : mitigationMetadataMapping) 
{
+    if (MitigationKey == MitigationKey::AUTO_VAR_INIT)
+      EXPECT_EQ(GetEnablementForMitigation(FuncPtr, MitigationStr), 1);
+    else
+      EXPECT_EQ(GetEnablementForMitigation(FuncPtr, MitigationStr), 0);
+  }
+  EXPECT_NE(mitigationMetadataMapping.find(MitigationKey::AUTO_VAR_INIT),
+            mitigationMetadataMapping.end());
+}
+
+TEST(MitigationTaggingTest, StackClashEnabled) {
+  clang::CodeGenOptions CGO;
+  CGO.MitigationAnalysis = true;
+  CGO.StackClashProtector = true;
+
+  clang::LangOptions LO;
+  LO.CPlusPlus = 1;
+  LO.CPlusPlus11 = 1;
+
+  TestCompiler Compiler(LO, CGO);
+  Compiler.init(TestProgram);
+
+  clang::ParseAST(Compiler.compiler.getSema(), false, false);
+  auto M =
+      static_cast<clang::CodeGenerator &>(Compiler.compiler.getASTConsumer())
+          .GetModule();
+  auto FuncPtr = M->getFunction(TestFunctionMangledName);
+  ASSERT_TRUE(FuncPtr != nullptr);
+
+  // Check that the correct mitigations are enabled
+  auto mitigationMetadataMapping = GetMitigationMetadataMapping();
+  for (const auto &[MitigationKey, MitigationStr] : mitigationMetadataMapping) 
{
+    if (MitigationKey == MitigationKey::STACK_CLASH_PROTECTION)
+      EXPECT_EQ(GetEnablementForMitigation(FuncPtr, MitigationStr), 1);
+    else
+      EXPECT_EQ(GetEnablementForMitigation(FuncPtr, MitigationStr), 0);
+  }
+  EXPECT_NE(
+      mitigationMetadataMapping.find(MitigationKey::STACK_CLASH_PROTECTION),
+      mitigationMetadataMapping.end());
+}
+
+TEST(MitigationTaggingTest, StackProtectorDisabled) {
+  clang::CodeGenOptions CGO;
+  CGO.MitigationAnalysis = true;
+
+  clang::LangOptions LO;
+  LO.CPlusPlus = 1;
+  LO.CPlusPlus11 = 1;
+  LO.setStackProtector(LangOptions::SSPOff);
+
+  TestCompiler Compiler(LO, CGO);
+  Compiler.init(TestProgram);
+
+  clang::ParseAST(Compiler.compiler.getSema(), false, false);
+  auto M =
+      static_cast<clang::CodeGenerator &>(Compiler.compiler.getASTConsumer())
+          .GetModule();
+  auto FuncPtr = M->getFunction(TestFunctionMangledName);
+  ASSERT_TRUE(FuncPtr != nullptr);
+
+  // Check that the correct mitigations are enabled
+  auto mitigationMetadataMapping = GetMitigationMetadataMapping();
+  for (const auto &[MitigationKey, MitigationStr] : mitigationMetadataMapping) 
{
+    if (MitigationKey == MitigationKey::STACK_PROTECTOR)
+      EXPECT_EQ(GetEnablementForMitigation(FuncPtr, MitigationStr), 0);
+    else
+      EXPECT_EQ(GetEnablementForMitigation(FuncPtr, MitigationStr), 0);
+  }
+  EXPECT_NE(mitigationMetadataMapping.find(MitigationKey::STACK_PROTECTOR),
+            mitigationMetadataMapping.end());
+}
+
+TEST(MitigationTaggingTest, StackProtectorEnabled) {
+  clang::CodeGenOptions CGO;
+  CGO.MitigationAnalysis = true;
+
+  clang::LangOptions LO;
+  LO.CPlusPlus = 1;
+  LO.CPlusPlus11 = 1;
+  LO.setStackProtector(LangOptions::SSPOn);
+
+  TestCompiler Compiler(LO, CGO);
+  Compiler.init(TestProgram);
+
+  clang::ParseAST(Compiler.compiler.getSema(), false, false);
+  auto M =
+      static_cast<clang::CodeGenerator &>(Compiler.compiler.getASTConsumer())
+          .GetModule();
+  auto FuncPtr = M->getFunction(TestFunctionMangledName);
+  ASSERT_TRUE(FuncPtr != nullptr);
+
+  // Check that the correct mitigations are enabled
+  auto mitigationMetadataMapping = GetMitigationMetadataMapping();
+  for (const auto &[MitigationKey, MitigationStr] : mitigationMetadataMapping) 
{
+    if (MitigationKey == MitigationKey::STACK_PROTECTOR)
+      EXPECT_EQ(GetEnablementForMitigation(FuncPtr, MitigationStr), 1);
+    else
+      EXPECT_EQ(GetEnablementForMitigation(FuncPtr, MitigationStr), 0);
+  }
+  EXPECT_NE(mitigationMetadataMapping.find(MitigationKey::STACK_PROTECTOR),
+            mitigationMetadataMapping.end());
+}
+
+TEST(MitigationTaggingTest, StackProtectorStrongEnabled) {
+  clang::CodeGenOptions CGO;
+  CGO.MitigationAnalysis = true;
+
+  clang::LangOptions LO;
+  LO.CPlusPlus = 1;
+  LO.CPlusPlus11 = 1;
+  LO.setStackProtector(LangOptions::SSPStrong);
+
+  TestCompiler Compiler(LO, CGO);
+  Compiler.init(TestProgram);
+
+  clang::ParseAST(Compiler.compiler.getSema(), false, false);
+  auto M =
+      static_cast<clang::CodeGenerator &>(Compiler.compiler.getASTConsumer())
+          .GetModule();
+  auto FuncPtr = M->getFunction(TestFunctionMangledName);
+  ASSERT_TRUE(FuncPtr != nullptr);
+
+  // Check that the correct mitigations are enabled
+  auto mitigationMetadataMapping = GetMitigationMetadataMapping();
+  for (const auto &[MitigationKey, MitigationStr] : mitigationMetadataMapping) 
{
+    if (MitigationKey == MitigationKey::STACK_PROTECTOR_STRONG)
+      EXPECT_EQ(GetEnablementForMitigation(FuncPtr, MitigationStr), 1);
+    else
+      EXPECT_EQ(GetEnablementForMitigation(FuncPtr, MitigationStr), 0);
+  }
+  EXPECT_NE(
+      mitigationMetadataMapping.find(MitigationKey::STACK_PROTECTOR_STRONG),
+      mitigationMetadataMapping.end());
+}
+
+TEST(MitigationTaggingTest, StackProtectorAllEnabled) {
+  clang::CodeGenOptions CGO;
+  CGO.MitigationAnalysis = true;
+
+  clang::LangOptions LO;
+  LO.CPlusPlus = 1;
+  LO.CPlusPlus11 = 1;
+  LO.setStackProtector(LangOptions::SSPReq);
+
+  TestCompiler Compiler(LO, CGO);
+  Compiler.init(TestProgram);
+
+  clang::ParseAST(Compiler.compiler.getSema(), false, false);
+  auto M =
+      static_cast<clang::CodeGenerator &>(Compiler.compiler.getASTConsumer())
+          .GetModule();
+  auto FuncPtr = M->getFunction(TestFunctionMangledName);
+  ASSERT_TRUE(FuncPtr != nullptr);
+
+  // Check that the correct mitigations are enabled
+  auto mitigationMetadataMapping = GetMitigationMetadataMapping();
+  for (const auto &[MitigationKey, MitigationStr] : mitigationMetadataMapping) 
{
+    if (MitigationKey == MitigationKey::STACK_PROTECTOR_ALL)
+      EXPECT_EQ(GetEnablementForMitigation(FuncPtr, MitigationStr), 1);
+    else
+      EXPECT_EQ(GetEnablementForMitigation(FuncPtr, MitigationStr), 0);
+  }
+  EXPECT_NE(mitigationMetadataMapping.find(MitigationKey::STACK_PROTECTOR_ALL),
+            mitigationMetadataMapping.end());
+}
+
+} // end anonymous namespace
diff --git a/llvm/include/llvm/Support/MitigationMarker.h 
b/llvm/include/llvm/Support/MitigationMarker.h
new file mode 100644
index 0000000000000..5c110c9e96bb2
--- /dev/null
+++ b/llvm/include/llvm/Support/MitigationMarker.h
@@ -0,0 +1,42 @@
+//===---- MitigationMarker.h - Emit LLVM Code from ASTs for a Module 
------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This enables tagging functions with metadata to indicate mitigations are
+// applied to them.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_MITIGATIONMARKER_H
+#define LLVM_SUPPORT_MITIGATIONMARKER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+
+#include <unordered_map>
+
+namespace llvm {
+
+enum class MitigationKey {
+  AUTO_VAR_INIT = 0,
+
+  STACK_CLASH_PROTECTION = 1,
+
+  STACK_PROTECTOR = 2,
+  STACK_PROTECTOR_STRONG = 3,
+  STACK_PROTECTOR_ALL = 4,
+
+  CFI_ICALL = 5,
+  CFI_VCALL = 6,
+  CFI_NVCALL = 7,
+};
+
+const llvm::DenseMap<MitigationKey, StringRef> &GetMitigationMetadataMapping();
+
+} // namespace llvm
+
+#endif // PIKA_SUPPORT_MITIGATIONMARKER_H
diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
index 1c397e8c0b766..064503b77dcc3 100644
--- a/llvm/lib/Support/CMakeLists.txt
+++ b/llvm/lib/Support/CMakeLists.txt
@@ -222,6 +222,7 @@ add_llvm_component_library(LLVMSupport
   MemAlloc.cpp
   MemoryBuffer.cpp
   MemoryBufferRef.cpp
+  MitigationMarker.cpp
   ModRef.cpp
   MD5.cpp
   MSP430Attributes.cpp
diff --git a/llvm/lib/Support/MitigationMarker.cpp 
b/llvm/lib/Support/MitigationMarker.cpp
new file mode 100644
index 0000000000000..f07bdab968aab
--- /dev/null
+++ b/llvm/lib/Support/MitigationMarker.cpp
@@ -0,0 +1,25 @@
+#include "llvm/Support/MitigationMarker.h"
+
+namespace llvm {
+
+///
+/// Map a MitigationKey to a string
+///
+const llvm::DenseMap<MitigationKey, StringRef> &GetMitigationMetadataMapping() 
{
+  static const llvm::DenseMap<MitigationKey, StringRef> MitigationToString = {
+      {MitigationKey::AUTO_VAR_INIT, "security_mitigation_auto-var-init"},
+      {MitigationKey::STACK_CLASH_PROTECTION,
+       "security_mitigation_stack-clash-protection"},
+      {MitigationKey::STACK_PROTECTOR, "security_mitigation_stack-protector"},
+      {MitigationKey::STACK_PROTECTOR_STRONG,
+       "security_mitigation_stack-protector-strong"},
+      {MitigationKey::STACK_PROTECTOR_ALL,
+       "security_mitigation_stack-protector-all"},
+      {MitigationKey::CFI_ICALL, "security_mitigation_cfi-icall"},
+      {MitigationKey::CFI_VCALL, "security_mitigation_cfi-vcall"},
+      {MitigationKey::CFI_NVCALL, "security_mitigation_cfi-nvcall"},
+  };
+  return MitigationToString;
+}
+
+} // namespace llvm

>From 227ce893984c21ebd2951b956b5d1c3a9612a781 Mon Sep 17 00:00:00 2001
From: Matthew Levy <[email protected]>
Date: Mon, 8 Dec 2025 17:27:20 -0500
Subject: [PATCH 2/2] [SoftwareBillOfMitigations] Analysis Pass

This adds the analysis pass that gathers the security control metadata for each
function and outputs either a summary (JSON) or a per-function mitigation 
enablement (EMBED).
The metadata previously added is parsed and used to generate these build 
outputs.

There is also logic to loosely detect LibCXX hardening enablement in functions 
via:
Target Function -> `LibCXXPrefix...operator[]` -> trap
This heuristic is rough, but has been show to closely match expectations in 
testing.

This adds a few new LLVM options:
- mitigation-summary: Select between NONE, JSON, and EMBED
- mitigation-analysis-output-root: Where to store the per-module JSON output
- output-unit-name: Used to differentiate multiple modules during build with 
unique names
- mitigation-libcxx-prefix: The prefix to use for the LibCXX hardening 
detection heuristic (default: `std::`)

The format for EMBED is inline and requires extra logic to parse and process. 
This format was
designed to be easy to expand in the future to support more 
mitigations/preventions
(e.g., `fbounds-safety` and UBSan instrumentation).
---
 .../llvm/Analysis/MitigationAnalysis.h        |  80 +++
 llvm/include/llvm/Support/MitigationMarker.h  |   2 +
 llvm/lib/Analysis/CMakeLists.txt              |   1 +
 llvm/lib/Analysis/MitigationAnalysis.cpp      | 654 ++++++++++++++++++
 llvm/lib/Passes/PassBuilder.cpp               |   1 +
 llvm/lib/Passes/PassBuilderPipelines.cpp      |  12 +
 llvm/lib/Passes/PassRegistry.def              |   1 +
 7 files changed, 751 insertions(+)
 create mode 100644 llvm/include/llvm/Analysis/MitigationAnalysis.h
 create mode 100644 llvm/lib/Analysis/MitigationAnalysis.cpp

diff --git a/llvm/include/llvm/Analysis/MitigationAnalysis.h 
b/llvm/include/llvm/Analysis/MitigationAnalysis.h
new file mode 100644
index 0000000000000..50703b96f403d
--- /dev/null
+++ b/llvm/include/llvm/Analysis/MitigationAnalysis.h
@@ -0,0 +1,80 @@
+//===--- MitigationAnalysis.h - Emit LLVM Code from ASTs for a Module 
-----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This processes mitigation metadata to create a report on enablement
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ANALYSIS_MITIGATIONANALYSIS_H
+#define LLVM_ANALYSIS_MITIGATIONANALYSIS_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/InstrTypes.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/IR/ValueHandle.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/JSON.h"
+
+#include <string>
+
+namespace llvm {
+
+enum class MitigationAnalysisSummaryType {
+  NONE = 0,
+  EMBED = 1 << 0,
+  JSON = 1 << 1,
+};
+
+struct MitigationAnalysisOptions {
+  MitigationAnalysisSummaryType SummaryType =
+      MitigationAnalysisSummaryType::NONE;
+  std::string OutputRoot = "/tmp";
+  std::string OutputUnitName;
+  std::string LibCXXPrefix = "std::";
+
+  MitigationAnalysisOptions() = default;
+  MitigationAnalysisOptions(MitigationAnalysisSummaryType ST, StringRef Root,
+                            StringRef UnitName, StringRef Prefix)
+      : SummaryType(ST), OutputRoot(Root), OutputUnitName(UnitName),
+        LibCXXPrefix(Prefix) {}
+
+  StringRef getOutputRoot() const { return OutputRoot; }
+  StringRef getOutputUnitName() const { return OutputUnitName; }
+  StringRef getLibCXXPrefix() const { return LibCXXPrefix; }
+};
+
+class MitigationAnalysisPass
+    : public AnalysisInfoMixin<MitigationAnalysisPass> {
+  friend AnalysisInfoMixin<MitigationAnalysisPass>;
+  static AnalysisKey Key;
+
+  static constexpr const char *kMitigationAnalysisDebugType =
+      "mitigation_analysis";
+
+public:
+  MitigationAnalysisPass(MitigationAnalysisOptions Opts = {}) : Options(Opts) 
{}
+
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
+
+private:
+  MitigationAnalysisOptions Options;
+
+  void writeJsonToFile(const llvm::json::Value &JsonValue);
+  void getHardenedAccessFunctions(Module &M,
+                                  StringMap<bool> &HardenedCXXFunctions);
+  bool compareDemangledFunctionName(StringRef MangledName,
+                                    StringRef CompareName);
+};
+
+MitigationAnalysisOptions getMitigationAnalysisOptions();
+
+} // end namespace llvm
+
+#endif // LLVM_ANALYSIS_MITIGATIONANALYSIS_H
diff --git a/llvm/include/llvm/Support/MitigationMarker.h 
b/llvm/include/llvm/Support/MitigationMarker.h
index 5c110c9e96bb2..4eb7d0b723497 100644
--- a/llvm/include/llvm/Support/MitigationMarker.h
+++ b/llvm/include/llvm/Support/MitigationMarker.h
@@ -33,6 +33,8 @@ enum class MitigationKey {
   CFI_ICALL = 5,
   CFI_VCALL = 6,
   CFI_NVCALL = 7,
+
+  MITIGATION_KEY_MAX
 };
 
 const llvm::DenseMap<MitigationKey, StringRef> &GetMitigationMetadataMapping();
diff --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt
index 9abdca099d9fe..226689af55f54 100644
--- a/llvm/lib/Analysis/CMakeLists.txt
+++ b/llvm/lib/Analysis/CMakeLists.txt
@@ -117,6 +117,7 @@ add_llvm_component_library(LLVMAnalysis
   MemoryProfileInfo.cpp
   MemorySSA.cpp
   MemorySSAUpdater.cpp
+  MitigationAnalysis.cpp
   ModelUnderTrainingRunner.cpp
   ModuleDebugInfoPrinter.cpp
   ModuleSummaryAnalysis.cpp
diff --git a/llvm/lib/Analysis/MitigationAnalysis.cpp 
b/llvm/lib/Analysis/MitigationAnalysis.cpp
new file mode 100644
index 0000000000000..dc0bf057ac565
--- /dev/null
+++ b/llvm/lib/Analysis/MitigationAnalysis.cpp
@@ -0,0 +1,654 @@
+//===--- MitigationAnalysis.cpp - Emit LLVM Code from ASTs for a Module 
---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This processes mitigation metadata to create a report on enablement
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/MitigationAnalysis.h"
+#include "llvm/Support/MitigationMarker.h"
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Demangle/Demangle.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/SHA1.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Triple.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
+
+using namespace llvm;
+
+static cl::opt<MitigationAnalysisSummaryType> MitigationAnalysisSummary(
+    "mitigation-summary", cl::Hidden,
+    cl::init(MitigationAnalysisSummaryType::NONE),
+    cl::desc("Enable exporting mitigation analysis information"),
+    cl::values(
+        clEnumValN(MitigationAnalysisSummaryType::NONE, "none",
+                   "Do not export mitigation analysis information"),
+        clEnumValN(MitigationAnalysisSummaryType::JSON, "json",
+                   "Export mitigation analysis information in JSON format"),
+        clEnumValN(MitigationAnalysisSummaryType::EMBED, "embed",
+                   "Embed mitigation analysis information in the binary")));
+
+static cl::opt<std::string> MitigationAnalysisOutputRoot(
+    "mitigation-analysis-output-root",
+    cl::desc("Folder to write mitigation analysis outputs"),
+    cl::value_desc("MitigationOutputDirectory"), cl::init("/tmp"));
+
+static cl::opt<std::string> OutputUnitName("output-unit-name", cl::init(""),
+                                           cl::ZeroOrMore,
+                                           cl::value_desc("OutputUnitName"),
+                                           cl::desc("Output unit name"),
+                                           cl::Hidden);
+
+static cl::opt<std::string>
+    LibCXXPrefix("mitigation-libcxx-prefix", cl::init("std::"),
+                 cl::value_desc("LibCXXPrefix"),
+                 cl::desc("Namespace prefix for LibC++ hardening functions"),
+                 cl::Hidden);
+
+MitigationAnalysisOptions llvm::getMitigationAnalysisOptions() {
+  return MitigationAnalysisOptions(MitigationAnalysisSummary.getValue(),
+                                   StringRef(MitigationAnalysisOutputRoot),
+                                   StringRef(OutputUnitName.empty()
+                                                 ? std::string("unknown")
+                                                 : OutputUnitName),
+                                   StringRef(LibCXXPrefix));
+}
+
+/**
+ *
+ * Mitigation metadata is stored in 2 sections: __mitigation and 
__mitigationstr
+ *
+ * Mitigation Section contains arrays of Packed Mitigation Data
+ *   [0xFFFF][MitigationBits:uint16]
+ *   [FUNC_HASH:20 bytes]
+ *   [SRC_HASH:20 bytes]
+ *
+ * Mitigation String Section contains arrays of Packed Mitigation String
+ *   [HASH:20 bytes]
+ *   [NULL-TERMINATED STRING:var-length]
+ *
+ * Since this pass is expected to run for multiple modules during LTO,
+ * each array is prefixed with a header. The BufferSize is the length
+ * of the header (8-bytes) + length of array in bytes
+ *   [0xDEADBEEF][BufferSize:uint32]
+ *
+ * The metadata leads to the following size regressions.
+ *   44-bytes for the function's data
+ *   20-bytes for the function hash + X-bytes for string
+ *   20-bytes for the source path + Y-bytes for string
+ */
+static constexpr uint32_t kMitigationTag = 0xDEADBEEF;
+static constexpr size_t kMitigationHashBytes = 20;
+static_assert(kMitigationHashBytes <= 20,
+              "kMitigationHashBytes must be <= 20 since it holds SHA1 hash");
+
+AnalysisKey MitigationAnalysisPass::Key;
+
+enum class MitigationState { NotAvailable, Disabled, Enabled };
+
+static const std::unordered_map<MitigationState, std::string> mapStateToString 
=
+    {
+        {MitigationState::NotAvailable, "N/A"},
+        {MitigationState::Disabled, "Disabled"},
+        {MitigationState::Enabled, "Enabled"},
+};
+
+class MitigationInfo {
+public:
+  llvm::DenseMap<MitigationKey, MitigationState> Enablement;
+
+  // This is not included in the MitigationKey list since determined during 
this
+  // pass
+  MitigationState LibCppHardeningMode = MitigationState::NotAvailable;
+
+  std::string SourceMapping;
+  std::string TypeSignature;
+  uint64_t TypeId = 0;
+  std::string Function;
+  std::string Module;
+
+  MitigationInfo() {
+    // Initialize all mitigation states to NotAvailable
+    for (size_t Mitigation = 0;
+         Mitigation <
+         static_cast<size_t>(llvm::MitigationKey::MITIGATION_KEY_MAX);
+         ++Mitigation) {
+      Enablement[MitigationKey(Mitigation)] = MitigationState::NotAvailable;
+    }
+  }
+
+  void Pack(std::vector<uint8_t> &MitigationPacked,
+            std::map<std::string, std::array<uint8_t, kMitigationHashBytes>>
+                &Hashes) const noexcept {
+    // Bit 0-1: Auto Var Init
+    std::uint16_t Packed =
+        MitigationStateToPacked(llvm::MitigationKey::AUTO_VAR_INIT, 0);
+    // Bit 2-3: Stack Clash
+    Packed |=
+        MitigationStateToPacked(llvm::MitigationKey::STACK_CLASH_PROTECTION, 
2);
+    // Bit 4-5: Stack Protector
+    Packed |= MitigationStateToPacked(llvm::MitigationKey::STACK_PROTECTOR, 4);
+    // Bit 6-7: Stack Protector Strong
+    Packed |=
+        MitigationStateToPacked(llvm::MitigationKey::STACK_PROTECTOR_STRONG, 
6);
+    // Bit 8-9: LibCXX Hardening
+    Packed |= MitigationStateToPacked(LibCppHardeningMode, 8);
+    // Bit 10-11: CFI ICall
+    Packed |= MitigationStateToPacked(llvm::MitigationKey::CFI_ICALL, 10);
+    // Bit 12-13: CFI VCall
+    Packed |= MitigationStateToPacked(llvm::MitigationKey::CFI_VCALL, 12);
+    // Bit 14-15: Reserved
+
+    auto MitigationPackedOldSize = MitigationPacked.size();
+    MitigationPacked.resize(MitigationPackedOldSize + sizeof(uint16_t) * 2);
+    // 0xFFFF represents the reserved bits for future use
+    support::endian::write16(MitigationPacked.data() + MitigationPackedOldSize,
+                             0xFFFF, llvm::endianness::little);
+    support::endian::write16(MitigationPacked.data() + MitigationPackedOldSize 
+
+                                 sizeof(uint16_t),
+                             Packed, llvm::endianness::little);
+
+    SHA1 Hasher;
+    Hasher.update(Function);
+    auto FuncDigest = Hasher.final();
+    for (size_t i = 0; i < kMitigationHashBytes; ++i)
+      MitigationPacked.push_back(FuncDigest[i]);
+
+    Hasher.init();
+    Hasher.update(SourceMapping);
+    auto SrcDigest = Hasher.final();
+    for (size_t i = 0; i < kMitigationHashBytes; ++i)
+      MitigationPacked.push_back(SrcDigest[i]);
+
+    // Export string -> hash mappings
+    Hashes[Function] = FuncDigest;
+    Hashes[SourceMapping] = SrcDigest;
+  }
+
+private:
+  std::uint16_t MitigationStateToPacked(llvm::MitigationKey key,
+                                        size_t offset) const {
+    auto it = Enablement.find(key);
+    return it != Enablement.end()
+               ? MitigationStateToPacked(it->second, offset)
+               : MitigationStateToPacked(MitigationState::NotAvailable, 
offset);
+  }
+
+  std::uint16_t MitigationStateToPacked(MitigationState state,
+                                        size_t offset) const {
+    switch (state) {
+    case MitigationState::NotAvailable:
+      return uint16_t(0b00) << offset;
+    case MitigationState::Disabled:
+      return uint16_t(0b01) << offset;
+    case MitigationState::Enabled:
+      return uint16_t(0b10) << offset;
+    }
+  }
+};
+
+class ModuleMitigationInfo {
+public:
+  struct MitigationEligibility {
+    std::size_t Eligible;
+    std::size_t Enabled;
+  };
+
+  llvm::DenseMap<MitigationKey, MitigationEligibility> Eligibility;
+  MitigationEligibility LibCppHardeningMode;
+  std::size_t TotalFunctions;
+
+  ModuleMitigationInfo() : TotalFunctions(0) {
+    for (size_t Mitigation = 0;
+         Mitigation <
+         static_cast<size_t>(llvm::MitigationKey::MITIGATION_KEY_MAX);
+         ++Mitigation) {
+      Eligibility[MitigationKey(Mitigation)] = {0, 0};
+    }
+    LibCppHardeningMode = {0, 0};
+  }
+
+  /// Convert a ModuleMitigationInfo struct to a JSON object.
+  json::Object ModuleInfoToJson(StringRef ModuleName) const noexcept {
+    json::Object Object;
+
+    WriteMitigationToJSON(Object, "eligible_auto_var_init",
+                          "enabled_auto_var_init",
+                          llvm::MitigationKey::AUTO_VAR_INIT);
+    WriteMitigationToJSON(Object, "eligible_stack_clash_protection",
+                          "enabled_stack_clash_protection",
+                          llvm::MitigationKey::STACK_CLASH_PROTECTION);
+    WriteMitigationToJSON(Object, "eligible_stack_protector",
+                          "enabled_stack_protector",
+                          llvm::MitigationKey::STACK_PROTECTOR);
+    WriteMitigationToJSON(Object, "eligible_stack_protector_strong",
+                          "enabled_stack_protector_strong",
+                          llvm::MitigationKey::STACK_PROTECTOR_STRONG);
+    WriteMitigationToJSON(Object, "eligible_stack_protector_all",
+                          "enabled_stack_protector_all",
+                          llvm::MitigationKey::STACK_PROTECTOR_ALL);
+    WriteMitigationToJSON(Object, "eligible_cfi_icall", "enabled_cfi_icall",
+                          llvm::MitigationKey::CFI_ICALL);
+    WriteMitigationToJSON(Object, "eligible_cfi_vcall", "enabled_cfi_vcall",
+                          llvm::MitigationKey::CFI_VCALL);
+    WriteMitigationToJSON(Object, "eligible_cfi_nvcall", "enabled_cfi_nvcall",
+                          llvm::MitigationKey::CFI_NVCALL);
+
+    Object["eligible_libcpp_hardening"] = LibCppHardeningMode.Eligible;
+    Object["enabled_libcpp_hardening"] = LibCppHardeningMode.Enabled;
+
+    Object["total_functions"] = TotalFunctions;
+    Object["module"] = ModuleName;
+    return Object;
+  }
+
+  void UpdateModuleInfo(const MitigationInfo &Info) noexcept {
+    TotalFunctions++;
+
+    UpdateModuleInfoEligibility(Info, MitigationKey::AUTO_VAR_INIT);
+    UpdateModuleInfoEligibility(Info, MitigationKey::STACK_CLASH_PROTECTION);
+    UpdateModuleInfoEligibility(Info, MitigationKey::STACK_PROTECTOR);
+    UpdateModuleInfoEligibility(Info, MitigationKey::STACK_PROTECTOR_STRONG);
+    UpdateModuleInfoEligibility(Info, MitigationKey::STACK_PROTECTOR_ALL);
+    UpdateModuleInfoEligibility(Info, MitigationKey::CFI_ICALL);
+    UpdateModuleInfoEligibility(Info, MitigationKey::CFI_VCALL);
+    UpdateModuleInfoEligibility(Info, MitigationKey::CFI_NVCALL);
+
+    LibCppHardeningMode.Eligible +=
+        (Info.LibCppHardeningMode != MitigationState::NotAvailable);
+    LibCppHardeningMode.Enabled +=
+        (Info.LibCppHardeningMode == MitigationState::Enabled);
+  }
+
+private:
+  void WriteMitigationToJSON(json::Object &Object,
+                             const llvm::StringRef Eligible,
+                             const llvm::StringRef Enabled,
+                             llvm::MitigationKey Key) const noexcept {
+    auto it = Eligibility.find(Key);
+    if (it != Eligibility.end()) {
+      Object[Eligible] = it->second.Eligible;
+      Object[Enabled] = it->second.Enabled;
+    } else {
+      Object[Eligible] = 0;
+      Object[Enabled] = 0;
+    }
+  }
+
+  void UpdateModuleInfoEligibility(const MitigationInfo &Info,
+                                   llvm::MitigationKey Key) noexcept {
+    auto it = Info.Enablement.find(Key);
+    if (it != Info.Enablement.end()) {
+      Eligibility[Key].Eligible +=
+          (it->second != MitigationState::NotAvailable);
+      Eligibility[Key].Enabled += (it->second == MitigationState::Enabled);
+    }
+  }
+};
+
+/// Retrieve the first valid source path for the given function.
+inline static std::string getFunctionSourcePath(const Function &F) {
+  if (const DISubprogram *SP = F.getSubprogram()) {
+    StringRef Dir = SP->getDirectory();
+    StringRef File = SP->getFilename();
+    if (!Dir.empty() && !File.empty())
+      return (Twine(Dir) + "/" + File).str();
+  }
+  return "(unknown)";
+}
+
+/// Extract the first function type signature (that doesn't end with
+/// .generalized) from metadata in Function F.
+static std::string getFirstFunctionTypeSignature(Function &F) {
+  SmallVector<std::pair<unsigned, MDNode *>, 4> MDs;
+  F.getAllMetadata(MDs);
+
+  for (const auto &MD : MDs) {
+    if (MD.first != LLVMContext::MD_type)
+      continue;
+
+    if (MDNode *Node = MD.second) {
+      if (Node->getNumOperands() <= 1)
+        continue;
+
+      auto *Str = dyn_cast<MDString>(Node->getOperand(1));
+      if (!Str)
+        continue;
+
+      StringRef Signature = Str->getString();
+      if (!Signature.ends_with(".generalized"))
+        return Signature.str();
+    }
+  }
+  return "";
+}
+
+/// Extract a type ID from MD_type metadata in Function F (0 if not found).
+static uint64_t getFunctionTypeId(Function &F) {
+  SmallVector<std::pair<unsigned, MDNode *>, 4> MDs;
+  F.getAllMetadata(MDs);
+
+  for (const auto &MD : MDs) {
+    if (MD.first != LLVMContext::MD_type)
+      continue;
+
+    MDNode *Node = MD.second;
+    if (!Node || Node->getNumOperands() <= 1)
+      continue;
+
+    auto *MDInt = dyn_cast<ConstantAsMetadata>(Node->getOperand(1));
+    if (!MDInt)
+      continue;
+
+    if (auto *CI = dyn_cast<ConstantInt>(MDInt->getValue()))
+      return CI->getZExtValue();
+  }
+  return 0;
+}
+
+/// Detect the libcpp hardening mode from calls in the given function.
+static MitigationState
+detectCXXHardeningMode(Function &F, StringMap<bool> HardenedCXXFunctions) {
+  for (Instruction &I : instructions(F)) {
+    auto *CallInstruct = dyn_cast<CallInst>(&I);
+    if (!CallInstruct)
+      continue;
+
+    Function *CalledFunction = CallInstruct->getCalledFunction();
+    if (!CalledFunction)
+      continue;
+
+    auto Iter = HardenedCXXFunctions.find(CalledFunction->getName());
+    if (Iter != HardenedCXXFunctions.end())
+      return Iter->second ? MitigationState::Enabled
+                          : MitigationState::Disabled;
+  }
+  return MitigationState::NotAvailable;
+}
+
+static inline StringRef getMitigationSectionName(const Module &M) noexcept {
+  Triple T(M.getTargetTriple());
+  return T.isOSBinFormatMachO() ? "__DATA,__mitigation" : ".mitigation";
+}
+
+static inline StringRef getMitigationStrsSectionName(const Module &M) noexcept 
{
+  Triple T(M.getTargetTriple());
+  return T.isOSBinFormatMachO() ? "__DATA,__mitigationstr" : ".mitigationstr";
+}
+
+static void writeMitigationMetadataSection(
+    Module &M, std::vector<uint8_t> &PackedMitigationData,
+    std::map<std::string, std::array<uint8_t, kMitigationHashBytes>>
+        &MitigationHashes) noexcept {
+  LLVMContext &Context = M.getContext();
+
+  // Update PackedMitigationData with header
+  support::endian::write32(PackedMitigationData.data(), kMitigationTag,
+                           llvm::endianness::little);
+  uint32_t MitigationDataSize = PackedMitigationData.size();
+  support::endian::write32(PackedMitigationData.data() + 
sizeof(kMitigationTag),
+                           MitigationDataSize, llvm::endianness::little);
+
+  auto *Int8Ty = Type::getInt8Ty(Context);
+  auto *MitigationArrTy = ArrayType::get(Int8Ty, PackedMitigationData.size());
+  auto *MitigationArrConst =
+      ConstantDataArray::get(Context, PackedMitigationData);
+  auto *GV =
+      new GlobalVariable(M, MitigationArrTy, true, GlobalValue::PrivateLinkage,
+                         MitigationArrConst, "mitigationdata");
+  GV->setSection(getMitigationSectionName(M));
+  GV->setAlignment(Align(1));
+  GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
+  appendToUsed(M, {GV});
+
+  // Add string map
+  std::vector<uint8_t> MitigationHashArr;
+
+  // Include length of header
+  uint32_t MitHashArrSize = sizeof(kMitigationTag) + sizeof(MitHashArrSize);
+  for (const auto &[Str, Hash] : MitigationHashes) {
+    MitHashArrSize += kMitigationHashBytes + Str.size() + 1;
+  }
+  MitigationHashArr.reserve(sizeof(kMitigationTag) + sizeof(MitHashArrSize) +
+                            MitHashArrSize);
+
+  // Marker + Length
+  MitigationHashArr.resize(sizeof(kMitigationTag) + sizeof(MitHashArrSize));
+  support::endian::write32(MitigationHashArr.data(), kMitigationTag,
+                           llvm::endianness::little);
+  support::endian::write32(MitigationHashArr.data() + sizeof(kMitigationTag),
+                           MitHashArrSize, llvm::endianness::little);
+
+  for (const auto &[Str, Hash] : MitigationHashes) {
+    for (size_t i = 0; i < kMitigationHashBytes; ++i)
+      MitigationHashArr.push_back(Hash[i]);
+
+    for (size_t i = 0; i < Str.size(); i++)
+      MitigationHashArr.push_back(Str[i]);
+    MitigationHashArr.push_back('\0'); // Ensure NULL terminated
+  }
+  auto *StrMapArrTy = ArrayType::get(Int8Ty, MitigationHashArr.size());
+  auto *StrMapArrConst = ConstantDataArray::get(Context, MitigationHashArr);
+  GV = new GlobalVariable(M, StrMapArrTy, true, GlobalValue::PrivateLinkage,
+                          StrMapArrConst, "mitigationdata.strs");
+  GV->setSection(getMitigationStrsSectionName(M));
+  GV->setAlignment(MaybeAlign(1));
+  GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
+  appendToUsed(M, {GV});
+}
+
+PreservedAnalyses MitigationAnalysisPass::run(Module &M,
+                                              ModuleAnalysisManager &AM) {
+  if (Options.SummaryType == MitigationAnalysisSummaryType::NONE)
+    return PreservedAnalyses::all();
+
+  ModuleMitigationInfo ModuleInfo;
+  std::vector<uint8_t> PackedMitigationData(8);
+  std::map<std::string, std::array<uint8_t, kMitigationHashBytes>>
+      PackedMitigationStrings;
+
+  StringMap<bool> HardenedCXXFunctions;
+  getHardenedAccessFunctions(M, HardenedCXXFunctions);
+
+  const auto &MitigationToString = GetMitigationMetadataMapping();
+
+  LLVMContext &Context = M.getContext();
+  for (Function &F : M) {
+    // If not defined in this module or part of LLVM, skip
+    if (F.isDeclaration() || F.isIntrinsic())
+      continue;
+
+    MitigationInfo Info;
+    Info.Module = Options.OutputUnitName;
+    Info.Function = F.getName();
+
+    for (const auto &[MitigationKey, MitigationValue] : MitigationToString) {
+      unsigned KindID = Context.getMDKindID(MitigationValue);
+
+      MDNode *MD = F.getMetadata(KindID);
+      if (!MD)
+        continue;
+
+      if (MD->getNumOperands() != 1)
+        continue;
+
+      auto *ConstAsMeta = dyn_cast<ConstantAsMetadata>(MD->getOperand(0));
+      if (!ConstAsMeta)
+        continue;
+
+      auto *Value = ConstAsMeta->getValue();
+      auto ValueToState = Value->isOneValue() == 1 ? MitigationState::Enabled
+                                                   : MitigationState::Disabled;
+      Info.Enablement[MitigationKey] = ValueToState;
+    }
+
+    Info.LibCppHardeningMode = detectCXXHardeningMode(F, HardenedCXXFunctions);
+
+    Info.SourceMapping = getFunctionSourcePath(F);
+    Info.TypeSignature = getFirstFunctionTypeSignature(F);
+    Info.TypeId = getFunctionTypeId(F);
+
+    switch (MitigationAnalysisSummary) {
+    case MitigationAnalysisSummaryType::EMBED:
+      Info.Pack(PackedMitigationData, PackedMitigationStrings);
+      break;
+    case MitigationAnalysisSummaryType::JSON:
+      ModuleInfo.UpdateModuleInfo(Info);
+      break;
+    case MitigationAnalysisSummaryType::NONE:
+      // No-Op
+      break;
+    }
+  }
+
+  switch (MitigationAnalysisSummary) {
+  case MitigationAnalysisSummaryType::EMBED:
+    writeMitigationMetadataSection(M, PackedMitigationData,
+                                   PackedMitigationStrings);
+    break;
+  case MitigationAnalysisSummaryType::JSON:
+    writeJsonToFile(
+        json::Value(ModuleInfo.ModuleInfoToJson(Options.OutputUnitName)));
+    break;
+  case MitigationAnalysisSummaryType::NONE:
+    llvm_unreachable("Pass should early exit if summary type is None");
+  }
+  return PreservedAnalyses::all();
+}
+
+/// Write the given JSON string to file with a lock. On error, prints to 
stderr.
+void MitigationAnalysisPass::writeJsonToFile(
+    const llvm::json::Value &JsonValue) {
+  std::string JsonString = formatv("{0:2}\n", JsonValue);
+  if (JsonString.size() == 1)
+    return;
+
+  // Create output directory if it doesn't exist.
+  sys::fs::create_directories(Options.OutputRoot, true);
+
+  std::string FileName =
+      Options.OutputUnitName == "unknown"
+          ? std::string("mitigation_info.json")
+          : formatv("mitigation_info-{0}.json", Options.OutputUnitName);
+
+  std::string FilePath = Options.OutputRoot + "/" + FileName;
+
+  std::error_code ErrCode;
+  raw_fd_ostream OutputStream(FilePath, ErrCode, sys::fs::CD_OpenAlways,
+                              sys::fs::FA_Read | sys::fs::FA_Write,
+                              sys::fs::OF_Text | sys::fs::OF_UpdateAtime |
+                                  sys::fs::OF_Append);
+  if (ErrCode) {
+    errs() << formatv("Couldn't write to {0}: {1}\n", FilePath,
+                      ErrCode.message());
+    return;
+  }
+
+  if (auto Lock = OutputStream.lock()) {
+    OutputStream << JsonString;
+    if (OutputStream.has_error())
+      errs() << formatv("Couldn't write to {0}: Failed writing JSON\n",
+                        FilePath);
+
+  } else {
+    errs() << formatv("Couldn't write to {0}: Couldn't acquire lock\n",
+                      FilePath);
+  }
+}
+
+void MitigationAnalysisPass::getHardenedAccessFunctions(
+    Module &M, StringMap<bool> &HardenedCXXFunctions) {
+  static StringRef OperatorFuncName = "operator[]";
+  static StringRef SizeFuncName = "size";
+  static StringRef TrapFuncName = "llvm.trap";
+
+  for (Function &F : M) {
+    StringRef Name = F.getName();
+
+    // Screen for functions with parameters: `(ptr, size_t)`
+    auto *FType = F.getFunctionType();
+    if (FType->getNumParams() != 2)
+      continue;
+    auto *ParamType = FType->getParamType(1);
+    if (!ParamType->isIntegerTy(sizeof(size_t) * 8))
+      continue;
+    auto *ThisType = dyn_cast<PointerType>(FType->getParamType(0));
+    if (!ThisType)
+      continue;
+
+    // Demangle the base name of the function
+    if (!compareDemangledFunctionName(Name, OperatorFuncName))
+      continue;
+
+    // Be pessimistic about checking size
+    HardenedCXXFunctions[Name.str()] = false;
+
+    for (Instruction &I : instructions(F)) {
+      auto *CallInstruct = dyn_cast<CallInst>(&I);
+      if (!CallInstruct)
+        continue;
+
+      Function *CalledFunction = CallInstruct->getCalledFunction();
+      if (!CalledFunction)
+        continue;
+
+      bool IsTrapBuiltin =
+          strncmp(TrapFuncName.data(), CalledFunction->getName().data(),
+                  TrapFuncName.size()) == 0;
+
+      // Check if `size()` or `llvm.trap` called
+      if (IsTrapBuiltin || compareDemangledFunctionName(
+                               CalledFunction->getName(), SizeFuncName)) {
+        HardenedCXXFunctions[Name.str()] = true;
+        break;
+      }
+    }
+  }
+}
+
+bool MitigationAnalysisPass::compareDemangledFunctionName(
+    StringRef MangledName, StringRef CompareName) {
+  llvm::ItaniumPartialDemangler Demangler;
+  if (Demangler.partialDemangle(MangledName.data()))
+    return false;
+  if (!Demangler.isFunction())
+    return false;
+
+  size_t DemangleBufLen = 0;
+  char *DemangleBuf = Demangler.getFunctionBaseName(nullptr, &DemangleBufLen);
+  if (DemangleBuf == nullptr || DemangleBufLen == 0)
+    return false;
+
+  bool CompareResult =
+      strncmp(CompareName.data(), DemangleBuf, CompareName.size()) == 0;
+
+  free(DemangleBuf);
+
+  if (CompareResult && !Options.LibCXXPrefix.empty()) {
+    char *DemangleBuf = Demangler.getFunctionName(nullptr, &DemangleBufLen);
+    if (DemangleBuf == nullptr || DemangleBufLen == 0)
+      return false;
+
+    // Check if the function name starts with LibCXXPrefix
+    CompareResult = strncmp(Options.LibCXXPrefix.data(), DemangleBuf,
+                            Options.LibCXXPrefix.size()) == 0;
+
+    free(DemangleBuf);
+  }
+
+  return CompareResult;
+}
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index f5281ea69b512..3b7e21b72f7b5 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -58,6 +58,7 @@
 #include "llvm/Analysis/MemDerefPrinter.h"
 #include "llvm/Analysis/MemoryDependenceAnalysis.h"
 #include "llvm/Analysis/MemorySSA.h"
+#include "llvm/Analysis/MitigationAnalysis.h"
 #include "llvm/Analysis/ModuleDebugInfoPrinter.h"
 #include "llvm/Analysis/ModuleSummaryAnalysis.h"
 #include "llvm/Analysis/MustExecute.h"
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp 
b/llvm/lib/Passes/PassBuilderPipelines.cpp
index c6beb3fdf09bd..b5c2612414261 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -21,6 +21,7 @@
 #include "llvm/Analysis/CtxProfAnalysis.h"
 #include "llvm/Analysis/GlobalsModRef.h"
 #include "llvm/Analysis/InlineAdvisor.h"
+#include "llvm/Analysis/MitigationAnalysis.h"
 #include "llvm/Analysis/ProfileSummaryInfo.h"
 #include "llvm/Analysis/ScopedNoAliasAA.h"
 #include "llvm/Analysis/TypeBasedAliasAnalysis.h"
@@ -1703,6 +1704,10 @@ 
PassBuilder::buildPerModuleDefaultPipeline(OptimizationLevel Level,
 
   if (isLTOPreLink(Phase))
     addRequiredLTOPreLinkPasses(MPM);
+
+  if (Phase == ThinOrFullLTOPhase::None)
+    MPM.addPass(llvm::MitigationAnalysisPass(getMitigationAnalysisOptions()));
+
   return MPM;
 }
 
@@ -1853,6 +1858,8 @@ ModulePassManager 
PassBuilder::buildThinLTODefaultPipeline(
     MPM.addPass(LowerTypeTestsPass(nullptr, ImportSummary));
   }
 
+  MPM.addPass(llvm::MitigationAnalysisPass(getMitigationAnalysisOptions()));
+
   if (Level == OptimizationLevel::O0) {
     // Run a second time to clean up any type tests left behind by WPD for use
     // in ICP.
@@ -1913,6 +1920,8 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel 
Level,
   // in the current module.
   MPM.addPass(CrossDSOCFIPass());
 
+  MPM.addPass(llvm::MitigationAnalysisPass(getMitigationAnalysisOptions()));
+
   if (Level == OptimizationLevel::O0) {
     // The WPD and LowerTypeTest passes need to run at -O0 to lower type
     // metadata and intrinsics.
@@ -2386,6 +2395,9 @@ PassBuilder::buildO0DefaultPipeline(OptimizationLevel 
Level,
 
   MPM.addPass(createModuleToFunctionPassAdaptor(AnnotationRemarksPass()));
 
+  if (Phase == ThinOrFullLTOPhase::None)
+    MPM.addPass(llvm::MitigationAnalysisPass(getMitigationAnalysisOptions()));
+
   return MPM;
 }
 
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index cf998f29ef38c..3951ed9517013 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -179,6 +179,7 @@ MODULE_PASS("tysan", TypeSanitizerPass())
 MODULE_PASS("verify", VerifierPass())
 MODULE_PASS("view-callgraph", CallGraphViewerPass())
 MODULE_PASS("wholeprogramdevirt", WholeProgramDevirtPass())
+MODULE_PASS("mitigation-analysis", 
MitigationAnalysisPass(getMitigationAnalysisOptions()))
 #undef MODULE_PASS
 
 #ifndef MODULE_PASS_WITH_PARAMS

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to