Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/Instrumentation/MemProfInstrumentation.cpp
213799 views
1
//===- MemProfInstrumentation.cpp - memory alloc and access instrumentation ==//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file is a part of MemProf. Memory accesses are instrumented
10
// to increment the access count held in a shadow memory location, or
11
// alternatively to call into the runtime. Memory intrinsic calls (memmove,
12
// memcpy, memset) are changed to call the memory profiling runtime version
13
// instead.
14
//
15
//===----------------------------------------------------------------------===//
16
17
#include "llvm/Transforms/Instrumentation/MemProfInstrumentation.h"
18
#include "llvm/ADT/SmallVector.h"
19
#include "llvm/ADT/Statistic.h"
20
#include "llvm/ADT/StringRef.h"
21
#include "llvm/Analysis/MemoryBuiltins.h"
22
#include "llvm/Analysis/TargetLibraryInfo.h"
23
#include "llvm/Analysis/ValueTracking.h"
24
#include "llvm/IR/Constant.h"
25
#include "llvm/IR/DataLayout.h"
26
#include "llvm/IR/DiagnosticInfo.h"
27
#include "llvm/IR/Function.h"
28
#include "llvm/IR/GlobalValue.h"
29
#include "llvm/IR/IRBuilder.h"
30
#include "llvm/IR/Instruction.h"
31
#include "llvm/IR/IntrinsicInst.h"
32
#include "llvm/IR/Module.h"
33
#include "llvm/IR/Type.h"
34
#include "llvm/IR/Value.h"
35
#include "llvm/ProfileData/InstrProf.h"
36
#include "llvm/ProfileData/MemProf.h"
37
#include "llvm/Support/CommandLine.h"
38
#include "llvm/Support/Debug.h"
39
#include "llvm/TargetParser/Triple.h"
40
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
41
#include "llvm/Transforms/Utils/ModuleUtils.h"
42
43
using namespace llvm;
44
using namespace llvm::memprof;
45
46
#define DEBUG_TYPE "memprof"
47
48
constexpr int LLVM_MEM_PROFILER_VERSION = 1;
49
50
// Size of memory mapped to a single shadow location.
51
constexpr uint64_t DefaultMemGranularity = 64;
52
53
// Size of memory mapped to a single histogram bucket.
54
constexpr uint64_t HistogramGranularity = 8;
55
56
// Scale from granularity down to shadow size.
57
constexpr uint64_t DefaultShadowScale = 3;
58
59
constexpr char MemProfModuleCtorName[] = "memprof.module_ctor";
60
constexpr uint64_t MemProfCtorAndDtorPriority = 1;
61
// On Emscripten, the system needs more than one priorities for constructors.
62
constexpr uint64_t MemProfEmscriptenCtorAndDtorPriority = 50;
63
constexpr char MemProfInitName[] = "__memprof_init";
64
constexpr char MemProfVersionCheckNamePrefix[] =
65
"__memprof_version_mismatch_check_v";
66
67
constexpr char MemProfShadowMemoryDynamicAddress[] =
68
"__memprof_shadow_memory_dynamic_address";
69
70
constexpr char MemProfFilenameVar[] = "__memprof_profile_filename";
71
72
constexpr char MemProfHistogramFlagVar[] = "__memprof_histogram";
73
74
// Command-line flags.
75
76
static cl::opt<bool> ClInsertVersionCheck(
77
"memprof-guard-against-version-mismatch",
78
cl::desc("Guard against compiler/runtime version mismatch."), cl::Hidden,
79
cl::init(true));
80
81
// This flag may need to be replaced with -f[no-]memprof-reads.
82
static cl::opt<bool> ClInstrumentReads("memprof-instrument-reads",
83
cl::desc("instrument read instructions"),
84
cl::Hidden, cl::init(true));
85
86
static cl::opt<bool>
87
ClInstrumentWrites("memprof-instrument-writes",
88
cl::desc("instrument write instructions"), cl::Hidden,
89
cl::init(true));
90
91
static cl::opt<bool> ClInstrumentAtomics(
92
"memprof-instrument-atomics",
93
cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden,
94
cl::init(true));
95
96
static cl::opt<bool> ClUseCalls(
97
"memprof-use-callbacks",
98
cl::desc("Use callbacks instead of inline instrumentation sequences."),
99
cl::Hidden, cl::init(false));
100
101
static cl::opt<std::string>
102
ClMemoryAccessCallbackPrefix("memprof-memory-access-callback-prefix",
103
cl::desc("Prefix for memory access callbacks"),
104
cl::Hidden, cl::init("__memprof_"));
105
106
// These flags allow to change the shadow mapping.
107
// The shadow mapping looks like
108
// Shadow = ((Mem & mask) >> scale) + offset
109
110
static cl::opt<int> ClMappingScale("memprof-mapping-scale",
111
cl::desc("scale of memprof shadow mapping"),
112
cl::Hidden, cl::init(DefaultShadowScale));
113
114
static cl::opt<int>
115
ClMappingGranularity("memprof-mapping-granularity",
116
cl::desc("granularity of memprof shadow mapping"),
117
cl::Hidden, cl::init(DefaultMemGranularity));
118
119
static cl::opt<bool> ClStack("memprof-instrument-stack",
120
cl::desc("Instrument scalar stack variables"),
121
cl::Hidden, cl::init(false));
122
123
// Debug flags.
124
125
static cl::opt<int> ClDebug("memprof-debug", cl::desc("debug"), cl::Hidden,
126
cl::init(0));
127
128
static cl::opt<std::string> ClDebugFunc("memprof-debug-func", cl::Hidden,
129
cl::desc("Debug func"));
130
131
static cl::opt<int> ClDebugMin("memprof-debug-min", cl::desc("Debug min inst"),
132
cl::Hidden, cl::init(-1));
133
134
static cl::opt<int> ClDebugMax("memprof-debug-max", cl::desc("Debug max inst"),
135
cl::Hidden, cl::init(-1));
136
137
static cl::opt<bool> ClHistogram("memprof-histogram",
138
cl::desc("Collect access count histograms"),
139
cl::Hidden, cl::init(false));
140
141
static cl::opt<std::string>
142
MemprofRuntimeDefaultOptions("memprof-runtime-default-options",
143
cl::desc("The default memprof options"),
144
cl::Hidden, cl::init(""));
145
146
// Instrumentation statistics
147
STATISTIC(NumInstrumentedReads, "Number of instrumented reads");
148
STATISTIC(NumInstrumentedWrites, "Number of instrumented writes");
149
STATISTIC(NumSkippedStackReads, "Number of non-instrumented stack reads");
150
STATISTIC(NumSkippedStackWrites, "Number of non-instrumented stack writes");
151
152
namespace {
153
154
/// This struct defines the shadow mapping using the rule:
155
/// shadow = ((mem & mask) >> Scale) ADD DynamicShadowOffset.
156
struct ShadowMapping {
157
ShadowMapping() {
158
Scale = ClMappingScale;
159
Granularity = ClHistogram ? HistogramGranularity : ClMappingGranularity;
160
Mask = ~(Granularity - 1);
161
}
162
163
int Scale;
164
int Granularity;
165
uint64_t Mask; // Computed as ~(Granularity-1)
166
};
167
168
static uint64_t getCtorAndDtorPriority(Triple &TargetTriple) {
169
return TargetTriple.isOSEmscripten() ? MemProfEmscriptenCtorAndDtorPriority
170
: MemProfCtorAndDtorPriority;
171
}
172
173
struct InterestingMemoryAccess {
174
Value *Addr = nullptr;
175
bool IsWrite;
176
Type *AccessTy;
177
Value *MaybeMask = nullptr;
178
};
179
180
/// Instrument the code in module to profile memory accesses.
181
class MemProfiler {
182
public:
183
MemProfiler(Module &M) {
184
C = &(M.getContext());
185
LongSize = M.getDataLayout().getPointerSizeInBits();
186
IntptrTy = Type::getIntNTy(*C, LongSize);
187
PtrTy = PointerType::getUnqual(*C);
188
}
189
190
/// If it is an interesting memory access, populate information
191
/// about the access and return a InterestingMemoryAccess struct.
192
/// Otherwise return std::nullopt.
193
std::optional<InterestingMemoryAccess>
194
isInterestingMemoryAccess(Instruction *I) const;
195
196
void instrumentMop(Instruction *I, const DataLayout &DL,
197
InterestingMemoryAccess &Access);
198
void instrumentAddress(Instruction *OrigIns, Instruction *InsertBefore,
199
Value *Addr, bool IsWrite);
200
void instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask,
201
Instruction *I, Value *Addr, Type *AccessTy,
202
bool IsWrite);
203
void instrumentMemIntrinsic(MemIntrinsic *MI);
204
Value *memToShadow(Value *Shadow, IRBuilder<> &IRB);
205
bool instrumentFunction(Function &F);
206
bool maybeInsertMemProfInitAtFunctionEntry(Function &F);
207
bool insertDynamicShadowAtFunctionEntry(Function &F);
208
209
private:
210
void initializeCallbacks(Module &M);
211
212
LLVMContext *C;
213
int LongSize;
214
Type *IntptrTy;
215
PointerType *PtrTy;
216
ShadowMapping Mapping;
217
218
// These arrays is indexed by AccessIsWrite
219
FunctionCallee MemProfMemoryAccessCallback[2];
220
221
FunctionCallee MemProfMemmove, MemProfMemcpy, MemProfMemset;
222
Value *DynamicShadowOffset = nullptr;
223
};
224
225
class ModuleMemProfiler {
226
public:
227
ModuleMemProfiler(Module &M) { TargetTriple = M.getTargetTriple(); }
228
229
bool instrumentModule(Module &);
230
231
private:
232
Triple TargetTriple;
233
ShadowMapping Mapping;
234
Function *MemProfCtorFunction = nullptr;
235
};
236
237
} // end anonymous namespace
238
239
MemProfilerPass::MemProfilerPass() = default;
240
241
PreservedAnalyses MemProfilerPass::run(Function &F,
242
AnalysisManager<Function> &AM) {
243
assert((!ClHistogram || ClMappingGranularity == DefaultMemGranularity) &&
244
"Memprof with histogram only supports default mapping granularity");
245
Module &M = *F.getParent();
246
MemProfiler Profiler(M);
247
if (Profiler.instrumentFunction(F))
248
return PreservedAnalyses::none();
249
return PreservedAnalyses::all();
250
}
251
252
ModuleMemProfilerPass::ModuleMemProfilerPass() = default;
253
254
PreservedAnalyses ModuleMemProfilerPass::run(Module &M,
255
AnalysisManager<Module> &AM) {
256
257
ModuleMemProfiler Profiler(M);
258
if (Profiler.instrumentModule(M))
259
return PreservedAnalyses::none();
260
return PreservedAnalyses::all();
261
}
262
263
Value *MemProfiler::memToShadow(Value *Shadow, IRBuilder<> &IRB) {
264
// (Shadow & mask) >> scale
265
Shadow = IRB.CreateAnd(Shadow, Mapping.Mask);
266
Shadow = IRB.CreateLShr(Shadow, Mapping.Scale);
267
// (Shadow >> scale) | offset
268
assert(DynamicShadowOffset);
269
return IRB.CreateAdd(Shadow, DynamicShadowOffset);
270
}
271
272
// Instrument memset/memmove/memcpy
273
void MemProfiler::instrumentMemIntrinsic(MemIntrinsic *MI) {
274
IRBuilder<> IRB(MI);
275
if (isa<MemTransferInst>(MI)) {
276
IRB.CreateCall(isa<MemMoveInst>(MI) ? MemProfMemmove : MemProfMemcpy,
277
{MI->getOperand(0), MI->getOperand(1),
278
IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)});
279
} else if (isa<MemSetInst>(MI)) {
280
IRB.CreateCall(
281
MemProfMemset,
282
{MI->getOperand(0),
283
IRB.CreateIntCast(MI->getOperand(1), IRB.getInt32Ty(), false),
284
IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)});
285
}
286
MI->eraseFromParent();
287
}
288
289
std::optional<InterestingMemoryAccess>
290
MemProfiler::isInterestingMemoryAccess(Instruction *I) const {
291
// Do not instrument the load fetching the dynamic shadow address.
292
if (DynamicShadowOffset == I)
293
return std::nullopt;
294
295
InterestingMemoryAccess Access;
296
297
if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
298
if (!ClInstrumentReads)
299
return std::nullopt;
300
Access.IsWrite = false;
301
Access.AccessTy = LI->getType();
302
Access.Addr = LI->getPointerOperand();
303
} else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
304
if (!ClInstrumentWrites)
305
return std::nullopt;
306
Access.IsWrite = true;
307
Access.AccessTy = SI->getValueOperand()->getType();
308
Access.Addr = SI->getPointerOperand();
309
} else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
310
if (!ClInstrumentAtomics)
311
return std::nullopt;
312
Access.IsWrite = true;
313
Access.AccessTy = RMW->getValOperand()->getType();
314
Access.Addr = RMW->getPointerOperand();
315
} else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {
316
if (!ClInstrumentAtomics)
317
return std::nullopt;
318
Access.IsWrite = true;
319
Access.AccessTy = XCHG->getCompareOperand()->getType();
320
Access.Addr = XCHG->getPointerOperand();
321
} else if (auto *CI = dyn_cast<CallInst>(I)) {
322
auto *F = CI->getCalledFunction();
323
if (F && (F->getIntrinsicID() == Intrinsic::masked_load ||
324
F->getIntrinsicID() == Intrinsic::masked_store)) {
325
unsigned OpOffset = 0;
326
if (F->getIntrinsicID() == Intrinsic::masked_store) {
327
if (!ClInstrumentWrites)
328
return std::nullopt;
329
// Masked store has an initial operand for the value.
330
OpOffset = 1;
331
Access.AccessTy = CI->getArgOperand(0)->getType();
332
Access.IsWrite = true;
333
} else {
334
if (!ClInstrumentReads)
335
return std::nullopt;
336
Access.AccessTy = CI->getType();
337
Access.IsWrite = false;
338
}
339
340
auto *BasePtr = CI->getOperand(0 + OpOffset);
341
Access.MaybeMask = CI->getOperand(2 + OpOffset);
342
Access.Addr = BasePtr;
343
}
344
}
345
346
if (!Access.Addr)
347
return std::nullopt;
348
349
// Do not instrument accesses from different address spaces; we cannot deal
350
// with them.
351
Type *PtrTy = cast<PointerType>(Access.Addr->getType()->getScalarType());
352
if (PtrTy->getPointerAddressSpace() != 0)
353
return std::nullopt;
354
355
// Ignore swifterror addresses.
356
// swifterror memory addresses are mem2reg promoted by instruction
357
// selection. As such they cannot have regular uses like an instrumentation
358
// function and it makes no sense to track them as memory.
359
if (Access.Addr->isSwiftError())
360
return std::nullopt;
361
362
// Peel off GEPs and BitCasts.
363
auto *Addr = Access.Addr->stripInBoundsOffsets();
364
365
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Addr)) {
366
// Do not instrument PGO counter updates.
367
if (GV->hasSection()) {
368
StringRef SectionName = GV->getSection();
369
// Check if the global is in the PGO counters section.
370
auto OF = I->getModule()->getTargetTriple().getObjectFormat();
371
if (SectionName.ends_with(
372
getInstrProfSectionName(IPSK_cnts, OF, /*AddSegmentInfo=*/false)))
373
return std::nullopt;
374
}
375
376
// Do not instrument accesses to LLVM internal variables.
377
if (GV->getName().starts_with("__llvm"))
378
return std::nullopt;
379
}
380
381
return Access;
382
}
383
384
void MemProfiler::instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask,
385
Instruction *I, Value *Addr,
386
Type *AccessTy, bool IsWrite) {
387
auto *VTy = cast<FixedVectorType>(AccessTy);
388
unsigned Num = VTy->getNumElements();
389
auto *Zero = ConstantInt::get(IntptrTy, 0);
390
for (unsigned Idx = 0; Idx < Num; ++Idx) {
391
Value *InstrumentedAddress = nullptr;
392
Instruction *InsertBefore = I;
393
if (auto *Vector = dyn_cast<ConstantVector>(Mask)) {
394
// dyn_cast as we might get UndefValue
395
if (auto *Masked = dyn_cast<ConstantInt>(Vector->getOperand(Idx))) {
396
if (Masked->isZero())
397
// Mask is constant false, so no instrumentation needed.
398
continue;
399
// If we have a true or undef value, fall through to instrumentAddress.
400
// with InsertBefore == I
401
}
402
} else {
403
IRBuilder<> IRB(I);
404
Value *MaskElem = IRB.CreateExtractElement(Mask, Idx);
405
Instruction *ThenTerm = SplitBlockAndInsertIfThen(MaskElem, I, false);
406
InsertBefore = ThenTerm;
407
}
408
409
IRBuilder<> IRB(InsertBefore);
410
InstrumentedAddress =
411
IRB.CreateGEP(VTy, Addr, {Zero, ConstantInt::get(IntptrTy, Idx)});
412
instrumentAddress(I, InsertBefore, InstrumentedAddress, IsWrite);
413
}
414
}
415
416
void MemProfiler::instrumentMop(Instruction *I, const DataLayout &DL,
417
InterestingMemoryAccess &Access) {
418
// Skip instrumentation of stack accesses unless requested.
419
if (!ClStack && isa<AllocaInst>(getUnderlyingObject(Access.Addr))) {
420
if (Access.IsWrite)
421
++NumSkippedStackWrites;
422
else
423
++NumSkippedStackReads;
424
return;
425
}
426
427
if (Access.IsWrite)
428
NumInstrumentedWrites++;
429
else
430
NumInstrumentedReads++;
431
432
if (Access.MaybeMask) {
433
instrumentMaskedLoadOrStore(DL, Access.MaybeMask, I, Access.Addr,
434
Access.AccessTy, Access.IsWrite);
435
} else {
436
// Since the access counts will be accumulated across the entire allocation,
437
// we only update the shadow access count for the first location and thus
438
// don't need to worry about alignment and type size.
439
instrumentAddress(I, I, Access.Addr, Access.IsWrite);
440
}
441
}
442
443
void MemProfiler::instrumentAddress(Instruction *OrigIns,
444
Instruction *InsertBefore, Value *Addr,
445
bool IsWrite) {
446
IRBuilder<> IRB(InsertBefore);
447
Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
448
449
if (ClUseCalls) {
450
IRB.CreateCall(MemProfMemoryAccessCallback[IsWrite], AddrLong);
451
return;
452
}
453
454
Type *ShadowTy = ClHistogram ? Type::getInt8Ty(*C) : Type::getInt64Ty(*C);
455
Type *ShadowPtrTy = PointerType::get(*C, 0);
456
457
Value *ShadowPtr = memToShadow(AddrLong, IRB);
458
Value *ShadowAddr = IRB.CreateIntToPtr(ShadowPtr, ShadowPtrTy);
459
Value *ShadowValue = IRB.CreateLoad(ShadowTy, ShadowAddr);
460
// If we are profiling with histograms, add overflow protection at 255.
461
if (ClHistogram) {
462
Value *MaxCount = ConstantInt::get(Type::getInt8Ty(*C), 255);
463
Value *Cmp = IRB.CreateICmpULT(ShadowValue, MaxCount);
464
Instruction *IncBlock =
465
SplitBlockAndInsertIfThen(Cmp, InsertBefore, /*Unreachable=*/false);
466
IRB.SetInsertPoint(IncBlock);
467
}
468
Value *Inc = ConstantInt::get(ShadowTy, 1);
469
ShadowValue = IRB.CreateAdd(ShadowValue, Inc);
470
IRB.CreateStore(ShadowValue, ShadowAddr);
471
}
472
473
// Create the variable for the profile file name.
474
void createProfileFileNameVar(Module &M) {
475
const MDString *MemProfFilename =
476
dyn_cast_or_null<MDString>(M.getModuleFlag("MemProfProfileFilename"));
477
if (!MemProfFilename)
478
return;
479
assert(!MemProfFilename->getString().empty() &&
480
"Unexpected MemProfProfileFilename metadata with empty string");
481
Constant *ProfileNameConst = ConstantDataArray::getString(
482
M.getContext(), MemProfFilename->getString(), true);
483
GlobalVariable *ProfileNameVar = new GlobalVariable(
484
M, ProfileNameConst->getType(), /*isConstant=*/true,
485
GlobalValue::WeakAnyLinkage, ProfileNameConst, MemProfFilenameVar);
486
const Triple &TT = M.getTargetTriple();
487
if (TT.supportsCOMDAT()) {
488
ProfileNameVar->setLinkage(GlobalValue::ExternalLinkage);
489
ProfileNameVar->setComdat(M.getOrInsertComdat(MemProfFilenameVar));
490
}
491
}
492
493
// Set MemprofHistogramFlag as a Global veriable in IR. This makes it accessible
494
// to the runtime, changing shadow count behavior.
495
void createMemprofHistogramFlagVar(Module &M) {
496
const StringRef VarName(MemProfHistogramFlagVar);
497
Type *IntTy1 = Type::getInt1Ty(M.getContext());
498
auto MemprofHistogramFlag = new GlobalVariable(
499
M, IntTy1, true, GlobalValue::WeakAnyLinkage,
500
Constant::getIntegerValue(IntTy1, APInt(1, ClHistogram)), VarName);
501
const Triple &TT = M.getTargetTriple();
502
if (TT.supportsCOMDAT()) {
503
MemprofHistogramFlag->setLinkage(GlobalValue::ExternalLinkage);
504
MemprofHistogramFlag->setComdat(M.getOrInsertComdat(VarName));
505
}
506
appendToCompilerUsed(M, MemprofHistogramFlag);
507
}
508
509
void createMemprofDefaultOptionsVar(Module &M) {
510
Constant *OptionsConst = ConstantDataArray::getString(
511
M.getContext(), MemprofRuntimeDefaultOptions, /*AddNull=*/true);
512
GlobalVariable *OptionsVar =
513
new GlobalVariable(M, OptionsConst->getType(), /*isConstant=*/true,
514
GlobalValue::WeakAnyLinkage, OptionsConst,
515
memprof::getMemprofOptionsSymbolName());
516
const Triple &TT = M.getTargetTriple();
517
if (TT.supportsCOMDAT()) {
518
OptionsVar->setLinkage(GlobalValue::ExternalLinkage);
519
OptionsVar->setComdat(M.getOrInsertComdat(OptionsVar->getName()));
520
}
521
}
522
523
bool ModuleMemProfiler::instrumentModule(Module &M) {
524
525
// Create a module constructor.
526
std::string MemProfVersion = std::to_string(LLVM_MEM_PROFILER_VERSION);
527
std::string VersionCheckName =
528
ClInsertVersionCheck ? (MemProfVersionCheckNamePrefix + MemProfVersion)
529
: "";
530
std::tie(MemProfCtorFunction, std::ignore) =
531
createSanitizerCtorAndInitFunctions(M, MemProfModuleCtorName,
532
MemProfInitName, /*InitArgTypes=*/{},
533
/*InitArgs=*/{}, VersionCheckName);
534
535
const uint64_t Priority = getCtorAndDtorPriority(TargetTriple);
536
appendToGlobalCtors(M, MemProfCtorFunction, Priority);
537
538
createProfileFileNameVar(M);
539
540
createMemprofHistogramFlagVar(M);
541
542
createMemprofDefaultOptionsVar(M);
543
544
return true;
545
}
546
547
void MemProfiler::initializeCallbacks(Module &M) {
548
IRBuilder<> IRB(*C);
549
550
for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {
551
const std::string TypeStr = AccessIsWrite ? "store" : "load";
552
const std::string HistPrefix = ClHistogram ? "hist_" : "";
553
554
SmallVector<Type *, 2> Args1{1, IntptrTy};
555
MemProfMemoryAccessCallback[AccessIsWrite] = M.getOrInsertFunction(
556
ClMemoryAccessCallbackPrefix + HistPrefix + TypeStr,
557
FunctionType::get(IRB.getVoidTy(), Args1, false));
558
}
559
MemProfMemmove = M.getOrInsertFunction(
560
ClMemoryAccessCallbackPrefix + "memmove", PtrTy, PtrTy, PtrTy, IntptrTy);
561
MemProfMemcpy = M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + "memcpy",
562
PtrTy, PtrTy, PtrTy, IntptrTy);
563
MemProfMemset =
564
M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + "memset", PtrTy,
565
PtrTy, IRB.getInt32Ty(), IntptrTy);
566
}
567
568
bool MemProfiler::maybeInsertMemProfInitAtFunctionEntry(Function &F) {
569
// For each NSObject descendant having a +load method, this method is invoked
570
// by the ObjC runtime before any of the static constructors is called.
571
// Therefore we need to instrument such methods with a call to __memprof_init
572
// at the beginning in order to initialize our runtime before any access to
573
// the shadow memory.
574
// We cannot just ignore these methods, because they may call other
575
// instrumented functions.
576
if (F.getName().contains(" load]")) {
577
FunctionCallee MemProfInitFunction =
578
declareSanitizerInitFunction(*F.getParent(), MemProfInitName, {});
579
IRBuilder<> IRB(&F.front(), F.front().begin());
580
IRB.CreateCall(MemProfInitFunction, {});
581
return true;
582
}
583
return false;
584
}
585
586
bool MemProfiler::insertDynamicShadowAtFunctionEntry(Function &F) {
587
IRBuilder<> IRB(&F.front().front());
588
Value *GlobalDynamicAddress = F.getParent()->getOrInsertGlobal(
589
MemProfShadowMemoryDynamicAddress, IntptrTy);
590
if (F.getParent()->getPICLevel() == PICLevel::NotPIC)
591
cast<GlobalVariable>(GlobalDynamicAddress)->setDSOLocal(true);
592
DynamicShadowOffset = IRB.CreateLoad(IntptrTy, GlobalDynamicAddress);
593
return true;
594
}
595
596
bool MemProfiler::instrumentFunction(Function &F) {
597
if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage)
598
return false;
599
if (ClDebugFunc == F.getName())
600
return false;
601
if (F.getName().starts_with("__memprof_"))
602
return false;
603
604
bool FunctionModified = false;
605
606
// If needed, insert __memprof_init.
607
// This function needs to be called even if the function body is not
608
// instrumented.
609
if (maybeInsertMemProfInitAtFunctionEntry(F))
610
FunctionModified = true;
611
612
LLVM_DEBUG(dbgs() << "MEMPROF instrumenting:\n" << F << "\n");
613
614
initializeCallbacks(*F.getParent());
615
616
SmallVector<Instruction *, 16> ToInstrument;
617
618
// Fill the set of memory operations to instrument.
619
for (auto &BB : F) {
620
for (auto &Inst : BB) {
621
if (isInterestingMemoryAccess(&Inst) || isa<MemIntrinsic>(Inst))
622
ToInstrument.push_back(&Inst);
623
}
624
}
625
626
if (ToInstrument.empty()) {
627
LLVM_DEBUG(dbgs() << "MEMPROF done instrumenting: " << FunctionModified
628
<< " " << F << "\n");
629
630
return FunctionModified;
631
}
632
633
FunctionModified |= insertDynamicShadowAtFunctionEntry(F);
634
635
int NumInstrumented = 0;
636
for (auto *Inst : ToInstrument) {
637
if (ClDebugMin < 0 || ClDebugMax < 0 ||
638
(NumInstrumented >= ClDebugMin && NumInstrumented <= ClDebugMax)) {
639
std::optional<InterestingMemoryAccess> Access =
640
isInterestingMemoryAccess(Inst);
641
if (Access)
642
instrumentMop(Inst, F.getDataLayout(), *Access);
643
else
644
instrumentMemIntrinsic(cast<MemIntrinsic>(Inst));
645
}
646
NumInstrumented++;
647
}
648
649
if (NumInstrumented > 0)
650
FunctionModified = true;
651
652
LLVM_DEBUG(dbgs() << "MEMPROF done instrumenting: " << FunctionModified << " "
653
<< F << "\n");
654
655
return FunctionModified;
656
}
657
658