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.isNVPTX() || TargetTriple.isAMDGPU()) &&

137 "Device targets are not supported");

138 }

139

140 bool run();

141

142private:

143 uint32_t getVersion() const {

144 uint32_t Version = kVersionBase;

145 const auto CM = Mod.getCodeModel();

147 Version |= kVersionPtrSizeRel;

148 return Version;

149 }

150

151 void runOn(Function &F, MetadataInfoSet &MIS);

152

153

154

155

156

157

158

159

162

163

165

166

168

169

171

172

174

175

176 bool pretendAtomicAccess(const Value *Addr);

177

180 std::unique_ptr Ignorelist;

181 const Triple TargetTriple;

182 const std::string VersionStr;

186};

187

188bool SanitizerBinaryMetadata::run() {

189 MetadataInfoSet MIS;

190

192 runOn(F, MIS);

193

194 if (MIS.empty())

195 return false;

196

197

198

199

200

201

202 auto *PtrTy = IRB.getPtrTy();

203 auto *Int32Ty = IRB.getInt32Ty();

204 const std::array<Type *, 3> InitTypes = {Int32Ty, PtrTy, PtrTy};

205 auto *Version = ConstantInt::get(Int32Ty, getVersion());

206

207 for (const MetadataInfo *MI : MIS) {

208 const std::array<Value *, InitTypes.size()> InitArgs = {

209 Version,

210 getSectionMarker(getSectionStart(MI->SectionSuffix), PtrTy),

211 getSectionMarker(getSectionEnd(MI->SectionSuffix), PtrTy),

212 };

213

214

215

216

217 const std::string StructorPrefix = (MI->FunctionPrefix + VersionStr).str();

218

219

220

221

222

225 Mod, StructorPrefix + ".module_ctor",

226 (MI->FunctionPrefix + "_add").str(), InitTypes, InitArgs,

227 StringRef(), ClWeakCallbacks)

228 .first;

231 Mod, StructorPrefix + ".module_dtor",

232 (MI->FunctionPrefix + "_del").str(), InitTypes, InitArgs,

233 StringRef(), ClWeakCallbacks)

234 .first;

235 Constant *CtorComdatKey = nullptr;

236 Constant *DtorComdatKey = nullptr;

237 if (TargetTriple.supportsCOMDAT()) {

238

239

244

247 CtorComdatKey = Ctor;

248 DtorComdatKey = Dtor;

249 }

252 }

253

254 return true;

255}

256

257void SanitizerBinaryMetadata::runOn(Function &F, MetadataInfoSet &MIS) {

258 if (F.empty())

259 return;

260

261 if (F.hasFnAttribute(Attribute::Naked))

262 return;

263 if (F.hasFnAttribute(Attribute::DisableSanitizerInstrumentation))

264 return;

265 if (Ignorelist && Ignorelist->inSection("metadata", "fun", F.getName()))

266 return;

267

269 return;

270

272

273

274

276

277 bool RequiresCovered = false;

278

282 RequiresCovered |= runOn(I, MIS, MDB, FeatureMask);

283 }

284

285 if (ClNoSanitize && F.hasFnAttribute("no_sanitize_thread"))

286 FeatureMask &= ~kSanitizerBinaryMetadataAtomics;

287 if (F.isVarArg())

288 FeatureMask &= ~kSanitizerBinaryMetadataUAR;

290 RequiresCovered = true;

291 NumMetadataUAR++;

292 }

293

294

295

296

297 if (Options.Covered || (FeatureMask && RequiresCovered)) {

298 NumMetadataCovered++;

299 const auto *MI = &MetadataInfo::Covered;

300 MIS.insert(MI);

302

303 Constant *CFM = IRB.getInt64(FeatureMask);

304 F.setMetadata(LLVMContext::MD_pcsections,

306 }

307}

308

309bool isUARSafeCall(CallInst *CI) {

311

312

313

314

315

316

317 return F && (F->isIntrinsic() || F->doesNotReturn() ||

318 F->getName().starts_with("__asan_") ||

319 F->getName().starts_with("__hwsan_") ||

320 F->getName().starts_with("__ubsan_") ||

321 F->getName().starts_with("__msan_") ||

322 F->getName().starts_with("__tsan_"));

323}

324

325bool hasUseAfterReturnUnsafeUses(Value &V) {

326 for (User *U : V.users()) {

327 if (auto *I = dyn_cast(U)) {

328 if (I->isLifetimeStartOrEnd() || I->isDroppable())

329 continue;

330 if (auto *CI = dyn_cast(U)) {

331 if (isUARSafeCall(CI))

332 continue;

333 }

334 if (isa(U))

335 continue;

336 if (auto *SI = dyn_cast(U)) {

337

338 if (SI->getOperand(1) == &V)

339 continue;

340 }

341 if (auto *GEPI = dyn_cast(U)) {

342 if (!hasUseAfterReturnUnsafeUses(*GEPI))

343 continue;

344 } else if (auto *BCI = dyn_cast(U)) {

345 if (!hasUseAfterReturnUnsafeUses(*BCI))

346 continue;

347 }

348 }

349 return true;

350 }

351 return false;

352}

353

355 if (isa(I))

356 return hasUseAfterReturnUnsafeUses(I);

357

358

359

360 else if (auto *CI = dyn_cast(&I))

361 return CI->isTailCall() && !isUARSafeCall(CI);

362 return false;

363}

364

365bool SanitizerBinaryMetadata::pretendAtomicAccess(const Value *Addr) {

367 return false;

368

369 Addr = Addr->stripInBoundsOffsets();

370 auto *GV = dyn_cast(Addr);

371 if (!GV)

372 return false;

373

374

375

376 if (GV->hasSection()) {

378 const auto ProfSec =

380 if (GV->getSection().ends_with(ProfSec))

381 return true;

382 }

383 if (GV->getName().starts_with("__llvm_gcov") ||

384 GV->getName().starts_with("__llvm_gcda"))

385 return true;

386

387 return false;

388}

389

390

391bool maybeSharedMutable(const Value *Addr) {

392

394 return true;

395

398 return false;

399

400 Addr = Addr->stripInBoundsOffsets();

401 if (auto *GV = dyn_cast(Addr)) {

402 if (GV->isConstant())

403 return false;

404 }

405

406 return true;

407}

408

409bool SanitizerBinaryMetadata::runOn(Instruction &I, MetadataInfoSet &MIS,

412 bool RequiresCovered = false;

413

414

416

418 if (useAfterReturnUnsafe(I))

420 }

421

424 if (auto *SI = dyn_cast(&I))

425 Addr = SI->getPointerOperand();

426 else if (auto *LI = dyn_cast(&I))

427 Addr = LI->getPointerOperand();

428

429 if (I.mayReadOrWriteMemory() && maybeSharedMutable(Addr)) {

432 pretendAtomicAccess(Addr)) {

433 NumMetadataAtomics++;

434 InstMetadata.push_back(&MetadataInfo::Atomics);

435 }

437 RequiresCovered = true;

438 }

439 }

440

441

442 if (!InstMetadata.empty()) {

443 MIS.insert(InstMetadata.begin(), InstMetadata.end());

445 for (const auto &MI : InstMetadata)

447 I.setMetadata(LLVMContext::MD_pcsections, MDB.createPCSections(Sections));

448 }

449

450 return RequiresCovered;

451}

452

454SanitizerBinaryMetadata::getSectionMarker(const Twine &MarkerName, Type *Ty) {

455

456

458 GlobalVariable::ExternalWeakLinkage,

459 nullptr, MarkerName);

461 return Marker;

462}

463

464StringRef SanitizerBinaryMetadata::getSectionName(StringRef SectionSuffix) {

465

466

467 return StringPool.save(SectionSuffix + VersionStr + "!C");

468}

469

470StringRef SanitizerBinaryMetadata::getSectionStart(StringRef SectionSuffix) {

471

472

473

474

475 return StringPool.save("__start_" + SectionSuffix + VersionStr);

476}

477

478StringRef SanitizerBinaryMetadata::getSectionEnd(StringRef SectionSuffix) {

479 return StringPool.save("__stop_" + SectionSuffix + VersionStr);

480}

481

482}

483

487

490 std::unique_ptr Ignorelist;

491 if (!IgnorelistFiles.empty()) {

494 if (Ignorelist->inSection("metadata", "src", M.getSourceFileName()))

496 }

497

498 SanitizerBinaryMetadata Pass(M, Options, std::move(Ignorelist));

499 if (Pass.run())

502}

This file defines the BumpPtrAllocator interface.

Module.h This file contains the declarations for the Module class.

if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod

assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())

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),...

bool empty() const

empty - Check if the array is empty.

LLVM Basic Block Representation.

Allocate memory in an ever growing pool, as if by bump-pointer.

Function * getCalledFunction() const

Returns the function called, or null if this is an indirect function invocation or the function signa...

This class represents a function call, abstracting a target machine's calling convention.

This is an important base class in LLVM.

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.

This provides a uniform API for creating instructions and inserting them into a basic block: either a...

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)

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

static 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.

ObjectFormatType getObjectFormat() const

Get the object format for this triple.

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.

LLVM Value Representation.

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.

IntrusiveRefCntPtr< FileSystem > getRealFileSystem()

Gets an vfs::FileSystem for the 'real' file system, as seen by the operating system.

This is an optimization pass for GlobalISel generic memory operations.

const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=6)

This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....

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

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...

bool PointerMayBeCaptured(const Value *V, bool ReturnCaptures, bool StoreCaptures, unsigned MaxUsesToExplore=0)

PointerMayBeCaptured - Return true if this pointer value may be captured by the enclosing function (w...

constexpr uint64_t kSanitizerBinaryMetadataAtomics

constexpr char kSanitizerBinaryMetadataCoveredSection[]

OutputIt move(R &&Range, OutputIt Out)

Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.

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[]

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.