#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/Analysis/DomTreeUpdater.h"
#include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Analysis/StackSafetyAnalysis.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/RandomNumberGenerator.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Triple.h"
#include "llvm/Transforms/Instrumentation/AddressSanitizerCommon.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Instrumentation.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/MemoryTaggingSupport.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include "llvm/Transforms/Utils/PromoteMemToReg.h"
#include <optional>
#include <random>
usingnamespacellvm;
#define DEBUG_TYPE …
const char kHwasanModuleCtorName[] = …;
const char kHwasanNoteName[] = …;
const char kHwasanInitName[] = …;
const char kHwasanPersonalityThunkName[] = …;
const char kHwasanShadowMemoryDynamicAddress[] = …;
static const size_t kNumberOfAccessSizes = …;
static const size_t kDefaultShadowScale = …;
static const unsigned kShadowBaseAlignment = …;
namespace {
enum class OffsetKind { … };
}
static cl::opt<std::string>
ClMemoryAccessCallbackPrefix("hwasan-memory-access-callback-prefix",
cl::desc("Prefix for memory access callbacks"),
cl::Hidden, cl::init("__hwasan_"));
static cl::opt<bool> ClKasanMemIntrinCallbackPrefix(
"hwasan-kernel-mem-intrinsic-prefix",
cl::desc("Use prefix for memory intrinsics in KASAN mode"), cl::Hidden,
cl::init(false));
static cl::opt<bool> ClInstrumentWithCalls(
"hwasan-instrument-with-calls",
cl::desc("instrument reads and writes with callbacks"), cl::Hidden,
cl::init(false));
static cl::opt<bool> ClInstrumentReads("hwasan-instrument-reads",
cl::desc("instrument read instructions"),
cl::Hidden, cl::init(true));
static cl::opt<bool>
ClInstrumentWrites("hwasan-instrument-writes",
cl::desc("instrument write instructions"), cl::Hidden,
cl::init(true));
static cl::opt<bool> ClInstrumentAtomics(
"hwasan-instrument-atomics",
cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden,
cl::init(true));
static cl::opt<bool> ClInstrumentByval("hwasan-instrument-byval",
cl::desc("instrument byval arguments"),
cl::Hidden, cl::init(true));
static cl::opt<bool>
ClRecover("hwasan-recover",
cl::desc("Enable recovery mode (continue-after-error)."),
cl::Hidden, cl::init(false));
static cl::opt<bool> ClInstrumentStack("hwasan-instrument-stack",
cl::desc("instrument stack (allocas)"),
cl::Hidden, cl::init(true));
static cl::opt<bool>
ClUseStackSafety("hwasan-use-stack-safety", cl::Hidden, cl::init(true),
cl::Hidden, cl::desc("Use Stack Safety analysis results"),
cl::Optional);
static cl::opt<size_t> ClMaxLifetimes(
"hwasan-max-lifetimes-for-alloca", cl::Hidden, cl::init(3),
cl::ReallyHidden,
cl::desc("How many lifetime ends to handle for a single alloca."),
cl::Optional);
static cl::opt<bool>
ClUseAfterScope("hwasan-use-after-scope",
cl::desc("detect use after scope within function"),
cl::Hidden, cl::init(true));
static cl::opt<bool> ClGenerateTagsWithCalls(
"hwasan-generate-tags-with-calls",
cl::desc("generate new tags with runtime library calls"), cl::Hidden,
cl::init(false));
static cl::opt<bool> ClGlobals("hwasan-globals", cl::desc("Instrument globals"),
cl::Hidden, cl::init(false));
static cl::opt<int> ClMatchAllTag(
"hwasan-match-all-tag",
cl::desc("don't report bad accesses via pointers with this tag"),
cl::Hidden, cl::init(-1));
static cl::opt<bool>
ClEnableKhwasan("hwasan-kernel",
cl::desc("Enable KernelHWAddressSanitizer instrumentation"),
cl::Hidden, cl::init(false));
static cl::opt<uint64_t>
ClMappingOffset("hwasan-mapping-offset",
cl::desc("HWASan shadow mapping offset [EXPERIMENTAL]"),
cl::Hidden);
static cl::opt<OffsetKind> ClMappingOffsetDynamic(
"hwasan-mapping-offset-dynamic",
cl::desc("HWASan shadow mapping dynamic offset location"), cl::Hidden,
cl::values(clEnumValN(OffsetKind::kGlobal, "global", "Use global"),
clEnumValN(OffsetKind::kIfunc, "ifunc", "Use ifunc global"),
clEnumValN(OffsetKind::kTls, "tls", "Use TLS")));
static cl::opt<bool>
ClFrameRecords("hwasan-with-frame-record",
cl::desc("Use ring buffer for stack allocations"),
cl::Hidden);
static cl::opt<int> ClHotPercentileCutoff("hwasan-percentile-cutoff-hot",
cl::desc("Hot percentile cuttoff."));
static cl::opt<float>
ClRandomSkipRate("hwasan-random-rate",
cl::desc("Probability value in the range [0.0, 1.0] "
"to keep instrumentation of a function."));
STATISTIC(NumTotalFuncs, "Number of total funcs");
STATISTIC(NumInstrumentedFuncs, "Number of instrumented funcs");
STATISTIC(NumNoProfileSummaryFuncs, "Number of funcs without PS");
enum RecordStackHistoryMode { … };
static cl::opt<RecordStackHistoryMode> ClRecordStackHistory(
"hwasan-record-stack-history",
cl::desc("Record stack frames with tagged allocations in a thread-local "
"ring buffer"),
cl::values(clEnumVal(none, "Do not record stack ring history"),
clEnumVal(instr, "Insert instructions into the prologue for "
"storing into the stack ring buffer directly"),
clEnumVal(libcall, "Add a call to __hwasan_add_frame_record for "
"storing into the stack ring buffer")),
cl::Hidden, cl::init(instr));
static cl::opt<bool>
ClInstrumentMemIntrinsics("hwasan-instrument-mem-intrinsics",
cl::desc("instrument memory intrinsics"),
cl::Hidden, cl::init(true));
static cl::opt<bool>
ClInstrumentLandingPads("hwasan-instrument-landing-pads",
cl::desc("instrument landing pads"), cl::Hidden,
cl::init(false));
static cl::opt<bool> ClUseShortGranules(
"hwasan-use-short-granules",
cl::desc("use short granules in allocas and outlined checks"), cl::Hidden,
cl::init(false));
static cl::opt<bool> ClInstrumentPersonalityFunctions(
"hwasan-instrument-personality-functions",
cl::desc("instrument personality functions"), cl::Hidden);
static cl::opt<bool> ClInlineAllChecks("hwasan-inline-all-checks",
cl::desc("inline all checks"),
cl::Hidden, cl::init(false));
static cl::opt<bool> ClInlineFastPathChecks("hwasan-inline-fast-path-checks",
cl::desc("inline all checks"),
cl::Hidden, cl::init(false));
static cl::opt<bool> ClUsePageAliases("hwasan-experimental-use-page-aliases",
cl::desc("Use page aliasing in HWASan"),
cl::Hidden, cl::init(false));
namespace {
template <typename T> T optOr(cl::opt<T> &Opt, T Other) { … }
bool shouldUsePageAliases(const Triple &TargetTriple) { … }
bool shouldInstrumentStack(const Triple &TargetTriple) { … }
bool shouldInstrumentWithCalls(const Triple &TargetTriple) { … }
bool mightUseStackSafetyAnalysis(bool DisableOptimization) { … }
bool shouldUseStackSafetyAnalysis(const Triple &TargetTriple,
bool DisableOptimization) { … }
bool shouldDetectUseAfterScope(const Triple &TargetTriple) { … }
class HWAddressSanitizer { … };
}
PreservedAnalyses HWAddressSanitizerPass::run(Module &M,
ModuleAnalysisManager &MAM) { … }
void HWAddressSanitizerPass::printPipeline(
raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) { … }
void HWAddressSanitizer::createHwasanCtorComdat() { … }
void HWAddressSanitizer::removeFnAttributes(Function *F) { … }
void HWAddressSanitizer::initializeModule() { … }
void HWAddressSanitizer::initializeCallbacks(Module &M) { … }
Value *HWAddressSanitizer::getOpaqueNoopCast(IRBuilder<> &IRB, Value *Val) { … }
Value *HWAddressSanitizer::getDynamicShadowIfunc(IRBuilder<> &IRB) { … }
Value *HWAddressSanitizer::getShadowNonTls(IRBuilder<> &IRB) { … }
bool HWAddressSanitizer::ignoreAccessWithoutRemark(Instruction *Inst,
Value *Ptr) { … }
bool HWAddressSanitizer::ignoreAccess(OptimizationRemarkEmitter &ORE,
Instruction *Inst, Value *Ptr) { … }
void HWAddressSanitizer::getInterestingMemoryOperands(
OptimizationRemarkEmitter &ORE, Instruction *I,
const TargetLibraryInfo &TLI,
SmallVectorImpl<InterestingMemoryOperand> &Interesting) { … }
static unsigned getPointerOperandIndex(Instruction *I) { … }
static size_t TypeSizeToSizeIndex(uint32_t TypeSize) { … }
void HWAddressSanitizer::untagPointerOperand(Instruction *I, Value *Addr) { … }
Value *HWAddressSanitizer::memToShadow(Value *Mem, IRBuilder<> &IRB) { … }
int64_t HWAddressSanitizer::getAccessInfo(bool IsWrite,
unsigned AccessSizeIndex) { … }
HWAddressSanitizer::ShadowTagCheckInfo
HWAddressSanitizer::insertShadowTagCheck(Value *Ptr, Instruction *InsertBefore,
DomTreeUpdater &DTU, LoopInfo *LI) { … }
void HWAddressSanitizer::instrumentMemAccessOutline(Value *Ptr, bool IsWrite,
unsigned AccessSizeIndex,
Instruction *InsertBefore,
DomTreeUpdater &DTU,
LoopInfo *LI) { … }
void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite,
unsigned AccessSizeIndex,
Instruction *InsertBefore,
DomTreeUpdater &DTU,
LoopInfo *LI) { … }
bool HWAddressSanitizer::ignoreMemIntrinsic(OptimizationRemarkEmitter &ORE,
MemIntrinsic *MI) { … }
void HWAddressSanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) { … }
bool HWAddressSanitizer::instrumentMemAccess(InterestingMemoryOperand &O,
DomTreeUpdater &DTU,
LoopInfo *LI) { … }
void HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag,
size_t Size) { … }
unsigned HWAddressSanitizer::retagMask(unsigned AllocaNo) { … }
Value *HWAddressSanitizer::applyTagMask(IRBuilder<> &IRB, Value *OldTag) { … }
Value *HWAddressSanitizer::getNextTagWithCall(IRBuilder<> &IRB) { … }
Value *HWAddressSanitizer::getStackBaseTag(IRBuilder<> &IRB) { … }
Value *HWAddressSanitizer::getAllocaTag(IRBuilder<> &IRB, Value *StackTag,
unsigned AllocaNo) { … }
Value *HWAddressSanitizer::getUARTag(IRBuilder<> &IRB) { … }
Value *HWAddressSanitizer::tagPointer(IRBuilder<> &IRB, Type *Ty,
Value *PtrLong, Value *Tag) { … }
Value *HWAddressSanitizer::untagPointer(IRBuilder<> &IRB, Value *PtrLong) { … }
Value *HWAddressSanitizer::getHwasanThreadSlotPtr(IRBuilder<> &IRB) { … }
Value *HWAddressSanitizer::getCachedFP(IRBuilder<> &IRB) { … }
Value *HWAddressSanitizer::getFrameRecordInfo(IRBuilder<> &IRB) { … }
void HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord) { … }
bool HWAddressSanitizer::instrumentLandingPads(
SmallVectorImpl<Instruction *> &LandingPadVec) { … }
bool HWAddressSanitizer::instrumentStack(memtag::StackInfo &SInfo,
Value *StackTag, Value *UARTag,
const DominatorTree &DT,
const PostDominatorTree &PDT,
const LoopInfo &LI) { … }
static void emitRemark(const Function &F, OptimizationRemarkEmitter &ORE,
bool Skip) { … }
bool HWAddressSanitizer::selectiveInstrumentationShouldSkip(
Function &F, FunctionAnalysisManager &FAM) const { … }
void HWAddressSanitizer::sanitizeFunction(Function &F,
FunctionAnalysisManager &FAM) { … }
void HWAddressSanitizer::instrumentGlobal(GlobalVariable *GV, uint8_t Tag) { … }
void HWAddressSanitizer::instrumentGlobals() { … }
void HWAddressSanitizer::instrumentPersonalityFunctions() { … }
void HWAddressSanitizer::ShadowMapping::init(Triple &TargetTriple,
bool InstrumentWithCalls) { … }