LLVM: lib/Transforms/Instrumentation/SanitizerBinaryMetadata.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
44
45#include
46#include
47#include
48
49using namespace llvm;
50
51#define DEBUG_TYPE "sanmd"
52
53namespace {
54
55
56
57constexpr uint32_t kVersionBase = 2;
58constexpr uint32_t kVersionPtrSizeRel = (1u << 16);
59constexpr int kCtorDtorPriority = 2;
60
61
62
63class MetadataInfo {
64public:
67
68 static const MetadataInfo Covered;
69 static const MetadataInfo Atomics;
70
71private:
72
73 explicit constexpr MetadataInfo(StringRef FunctionPrefix,
75 : FunctionPrefix(FunctionPrefix), SectionSuffix(SectionSuffix) {}
76};
77const MetadataInfo MetadataInfo::Covered{
79const MetadataInfo MetadataInfo::Atomics{
81
82
83
84
86
87
88
90 "sanitizer-metadata-weak-callbacks",
91 cl::desc("Declare callbacks extern weak, and only call if non-null."),
94 ClNoSanitize("sanitizer-metadata-nosanitize-attr",
95 cl::desc("Mark some metadata features uncovered in functions "
96 "with associated no_sanitize attributes."),
98
99cl::opt ClEmitCovered("sanitizer-metadata-covered",
100 cl::desc("Emit PCs for covered functions."),
102cl::opt ClEmitAtomics("sanitizer-metadata-atomics",
103 cl::desc("Emit PCs for atomic operations."),
106 cl::desc("Emit PCs for start of functions that are "
107 "subject for use-after-return checking"),
109
110
111
112STATISTIC(NumMetadataCovered, "Metadata attached to covered functions");
113STATISTIC(NumMetadataAtomics, "Metadata attached to atomics");
114STATISTIC(NumMetadataUAR, "Metadata attached to UAR functions");
115
116
117
118
121 Opts.Covered |= ClEmitCovered;
122 Opts.Atomics |= ClEmitAtomics;
123 Opts.UAR |= ClEmitUAR;
124 return std::move(Opts);
125}
126
127class SanitizerBinaryMetadata {
128public:
130 std::unique_ptr Ignorelist)
131 : Mod(M), Options(transformOptionsFromCl(std::move(Opts))),
132 Ignorelist(std::move(Ignorelist)), TargetTriple(M.getTargetTriple()),
133 VersionStr(utostr(getVersion())), IRB(M.getContext()) {
134
135 assert(TargetTriple.isOSBinFormatELF() && "ELF only");
136 assert(!TargetTriple.isGPU() && "Device targets are not supported");
137 }
138
139 bool run();
140
141private:
142 uint32_t getVersion() const {
143 uint32_t Version = kVersionBase;
144 const auto CM = Mod.getCodeModel();
146 Version |= kVersionPtrSizeRel;
147 return Version;
148 }
149
150 void runOn(Function &F, MetadataInfoSet &MIS);
151
152
153
154
155
156
157
158
161
162
164
165
167
168
170
171
173
174
175 bool pretendAtomicAccess(const Value *Addr);
176
179 std::unique_ptr Ignorelist;
180 const Triple TargetTriple;
181 const std::string VersionStr;
185};
186
187bool SanitizerBinaryMetadata::run() {
188 MetadataInfoSet MIS;
189
191 runOn(F, MIS);
192
193 if (MIS.empty())
194 return false;
195
196
197
198
199
200
201 auto *PtrTy = IRB.getPtrTy();
203 const std::array<Type *, 3> InitTypes = {Int32Ty, PtrTy, PtrTy};
204 auto *Version = ConstantInt::get(Int32Ty, getVersion());
205
206 for (const MetadataInfo *MI : MIS) {
207 const std::array<Value *, InitTypes.size()> InitArgs = {
208 Version,
209 getSectionMarker(getSectionStart(MI->SectionSuffix), PtrTy),
210 getSectionMarker(getSectionEnd(MI->SectionSuffix), PtrTy),
211 };
212
213
214
215
216 const std::string StructorPrefix = (MI->FunctionPrefix + VersionStr).str();
217
218
219
220
221
224 Mod, StructorPrefix + ".module_ctor",
225 (MI->FunctionPrefix + "_add").str(), InitTypes, InitArgs,
226 StringRef(), ClWeakCallbacks)
227 .first;
230 Mod, StructorPrefix + ".module_dtor",
231 (MI->FunctionPrefix + "_del").str(), InitTypes, InitArgs,
232 StringRef(), ClWeakCallbacks)
233 .first;
234 Constant *CtorComdatKey = nullptr;
235 Constant *DtorComdatKey = nullptr;
237
238
243
246 CtorComdatKey = Ctor;
247 DtorComdatKey = Dtor;
248 }
251 }
252
253 return true;
254}
255
256void SanitizerBinaryMetadata::runOn(Function &F, MetadataInfoSet &MIS) {
257 if (F.empty())
258 return;
259
260 if (F.hasFnAttribute(Attribute::Naked))
261 return;
262 if (F.hasFnAttribute(Attribute::DisableSanitizerInstrumentation))
263 return;
264 if (Ignorelist && Ignorelist->inSection("metadata", "fun", F.getName()))
265 return;
266
268 return;
269
271
272
273
275
276 bool RequiresCovered = false;
277
281 RequiresCovered |= runOn(I, MIS, MDB, FeatureMask);
282 }
283
284 if (ClNoSanitize && F.hasFnAttribute("no_sanitize_thread"))
286 if (F.isVarArg())
289 RequiresCovered = true;
290 NumMetadataUAR++;
291 }
292
293
294
295
296 if (Options.Covered || (FeatureMask && RequiresCovered)) {
297 NumMetadataCovered++;
298 const auto *MI = &MetadataInfo::Covered;
299 MIS.insert(MI);
301
303 F.setMetadata(LLVMContext::MD_pcsections,
305 }
306}
307
308bool isUARSafeCall(CallInst *CI) {
310
311
312
313
314
315
316 return F && (F->isIntrinsic() || F->doesNotReturn() ||
317 F->getName().starts_with("__asan_") ||
318 F->getName().starts_with("__hwsan_") ||
319 F->getName().starts_with("__ubsan_") ||
320 F->getName().starts_with("__msan_") ||
321 F->getName().starts_with("__tsan_"));
322}
323
324bool hasUseAfterReturnUnsafeUses(Value &V) {
325 for (User *U : V.users()) {
327 if (I->isLifetimeStartOrEnd() || I->isDroppable())
328 continue;
330 if (isUARSafeCall(CI))
331 continue;
332 }
334 continue;
336
337 if (SI->getOperand(1) == &V)
338 continue;
339 }
341 if (!hasUseAfterReturnUnsafeUses(*GEPI))
342 continue;
344 if (!hasUseAfterReturnUnsafeUses(*BCI))
345 continue;
346 }
347 }
348 return true;
349 }
350 return false;
351}
352
353bool useAfterReturnUnsafe(Instruction &I) {
355 return hasUseAfterReturnUnsafeUses(I);
356
357
358
360 return CI->isTailCall() && !isUARSafeCall(CI);
361 return false;
362}
363
364bool SanitizerBinaryMetadata::pretendAtomicAccess(const Value *Addr) {
365 if (!Addr)
366 return false;
367
370 if (!GV)
371 return false;
372
373
374
375 if (GV->hasSection()) {
376 const auto OF = Mod.getTargetTriple().getObjectFormat();
377 const auto ProfSec =
379 if (GV->getSection().ends_with(ProfSec))
380 return true;
381 }
382 if (GV->getName().starts_with("__llvm_gcov") ||
383 GV->getName().starts_with("__llvm_gcda"))
384 return true;
385
386 return false;
387}
388
389
390bool maybeSharedMutable(const Value *Addr) {
391
392 if (!Addr)
393 return true;
394
397 return false;
398
401 if (GV->isConstant())
402 return false;
403 }
404
405 return true;
406}
407
408bool SanitizerBinaryMetadata::runOn(Instruction &I, MetadataInfoSet &MIS,
409 MDBuilder &MDB, uint64_t &FeatureMask) {
411 bool RequiresCovered = false;
412
413
415
417 if (useAfterReturnUnsafe(I))
419 }
420
422 const Value *Addr = nullptr;
424 Addr = SI->getPointerOperand();
426 Addr = LI->getPointerOperand();
427
428 if (I.mayReadOrWriteMemory() && maybeSharedMutable(Addr)) {
431 pretendAtomicAccess(Addr)) {
432 NumMetadataAtomics++;
433 InstMetadata.push_back(&MetadataInfo::Atomics);
434 }
436 RequiresCovered = true;
437 }
438 }
439
440
441 if (!InstMetadata.empty()) {
442 MIS.insert_range(InstMetadata);
444 for (const auto &MI : InstMetadata)
446 I.setMetadata(LLVMContext::MD_pcsections, MDB.createPCSections(Sections));
447 }
448
449 return RequiresCovered;
450}
451
452GlobalVariable *
453SanitizerBinaryMetadata::getSectionMarker(const Twine &MarkerName, Type *Ty) {
454
455
456 auto *Marker = new GlobalVariable(Mod, Ty, false,
457 GlobalVariable::ExternalWeakLinkage,
458 nullptr, MarkerName);
460 return Marker;
461}
462
463StringRef SanitizerBinaryMetadata::getSectionName(StringRef SectionSuffix) {
464
465
466 return StringPool.save(SectionSuffix + VersionStr + "!C");
467}
468
469StringRef SanitizerBinaryMetadata::getSectionStart(StringRef SectionSuffix) {
470
471
472
473
474 return StringPool.save("__start_" + SectionSuffix + VersionStr);
475}
476
477StringRef SanitizerBinaryMetadata::getSectionEnd(StringRef SectionSuffix) {
478 return StringPool.save("__stop_" + SectionSuffix + VersionStr);
479}
480
481}
482
487 : Options(std::move(Opts)),
488 VFS(VFS ? std::move(VFS) : vfs::getRealFileSystem()),
489 IgnorelistFiles(std::move(IgnorelistFiles)) {}
490
493 std::unique_ptr Ignorelist;
494 if (!IgnorelistFiles.empty()) {
496 if (Ignorelist->inSection("metadata", "src", M.getSourceFileName()))
498 }
499
500 SanitizerBinaryMetadata Pass(M, Options, std::move(Ignorelist));
501 if (Pass.run())
504}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Prepare AGPR Alloc
This file defines the BumpPtrAllocator interface.
Module.h This file contains the declarations for the Module class.
print mir2vec MIR2Vec Vocabulary Printer Pass
if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Defines the virtual file system interface vfs::FileSystem.
A container for analyses that lazily runs them and caches their results.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
LLVM Basic Block Representation.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
This is an important base class in LLVM.
LLVM_ABI void setComdat(Comdat *C)
void setLinkage(LinkageTypes LT)
@ HiddenVisibility
The GV is hidden.
void setVisibility(VisibilityTypes V)
@ ExternalLinkage
Externally visible function.
@ AvailableExternallyLinkage
Available for inspection, not emission.
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
ConstantInt * getInt64(uint64_t C)
Get a constant 64-bit value.
PointerType * getPtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
A smart pointer to a reference-counted object that inherits from RefCountedBase or ThreadSafeRefCount...
LLVM_ABI MDNode * createPCSections(ArrayRef< PCSection > Sections)
Return metadata for PC sections.
A Module instance is used to store all the information related to an LLVM module.
Pass interface - Implemented by all 'passes'.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
A vector that has set insertion semantics.
void push_back(const T &Elt)
static LLVM_ABI std::unique_ptr< SpecialCaseList > createOrDie(const std::vector< std::string > &Paths, llvm::vfs::FileSystem &FS)
Parses the special case list entries from files.
StringRef - Represent a constant reference to a string, i.e.
Triple - Helper class for working with autoconf configuration names.
bool supportsCOMDAT() const
Tests whether the target supports comdat.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
Saves strings in the provided stable storage and returns a StringRef with a stable character pointer.
StringRef save(const char *S)
LLVM Value Representation.
LLVM_ABI const Value * stripInBoundsOffsets(function_ref< void(const Value *)> Func=[](const Value *) {}) const
Strip off pointer casts and inbounds GEPs.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
initializer< Ty > init(const Ty &Val)
static constexpr const StringLiteral & getSectionName(DebugSectionKind SectionKind)
Return the name of the section.
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
LLVM_ABI AllocaInst * findAllocaForValue(Value *V, bool OffsetZero=false)
Returns unique alloca where the value comes from, or nullptr.
decltype(auto) dyn_cast(const From &Val)
dyn_cast - Return the argument parameter cast to the specified type.
FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty
std::string utostr(uint64_t X, bool isNeg=false)
LLVM_ABI std::string getInstrProfSectionName(InstrProfSectKind IPSK, Triple::ObjectFormatType OF, bool AddSegmentInfo=true)
Return the name of the profile section corresponding to IPSK.
constexpr uint64_t kSanitizerBinaryMetadataUAR
LLVM_ABI std::pair< Function *, FunctionCallee > createSanitizerCtorAndInitFunctions(Module &M, StringRef CtorName, StringRef InitName, ArrayRef< Type * > InitArgTypes, ArrayRef< Value * > InitArgs, StringRef VersionCheckName=StringRef(), bool Weak=false)
Creates sanitizer constructor function, and calls sanitizer's init function from it.
std::optional< SyncScope::ID > getAtomicSyncScopeID(const Instruction *I)
A helper function that returns an atomic operation's sync scope; returns std::nullopt if it is not an...
constexpr uint64_t kSanitizerBinaryMetadataAtomics
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa - Return true if the parameter to the template is an instance of one of the template type argu...
constexpr char kSanitizerBinaryMetadataCoveredSection[]
@ Mod
The access may modify the value stored in memory.
LLVM_ABI bool PointerMayBeCaptured(const Value *V, bool ReturnCaptures, unsigned MaxUsesToExplore=0)
PointerMayBeCaptured - Return true if this pointer value may be captured by the enclosing function (w...
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI void appendToGlobalCtors(Module &M, Function *F, int Priority, Constant *Data=nullptr)
Append F to the list of global ctors of module M with the given Priority.
constexpr char kSanitizerBinaryMetadataAtomicsSection[]
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
LLVM_ABI void appendToGlobalDtors(Module &M, Function *F, int Priority, Constant *Data=nullptr)
Same as appendToGlobalCtors(), but for global dtors.
Implement std::hash so that hash_code can be used in STL containers.