Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/llvm/lib/Transforms/Utils/ModuleUtils.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- ModuleUtils.cpp - Functions to manipulate Modules -----------------===//
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 family of functions perform manipulations on Modules.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "llvm/Transforms/Utils/ModuleUtils.h"
14
#include "llvm/Analysis/VectorUtils.h"
15
#include "llvm/ADT/SmallString.h"
16
#include "llvm/IR/DerivedTypes.h"
17
#include "llvm/IR/Function.h"
18
#include "llvm/IR/IRBuilder.h"
19
#include "llvm/IR/MDBuilder.h"
20
#include "llvm/IR/Module.h"
21
#include "llvm/Support/raw_ostream.h"
22
#include "llvm/Support/xxhash.h"
23
24
using namespace llvm;
25
26
#define DEBUG_TYPE "moduleutils"
27
28
static void appendToGlobalArray(StringRef ArrayName, Module &M, Function *F,
29
0
                                int Priority, Constant *Data) {
30
0
  IRBuilder<> IRB(M.getContext());
31
0
  FunctionType *FnTy = FunctionType::get(IRB.getVoidTy(), false);
32
33
  // Get the current set of static global constructors and add the new ctor
34
  // to the list.
35
0
  SmallVector<Constant *, 16> CurrentCtors;
36
0
  StructType *EltTy;
37
0
  if (GlobalVariable *GVCtor = M.getNamedGlobal(ArrayName)) {
38
0
    EltTy = cast<StructType>(GVCtor->getValueType()->getArrayElementType());
39
0
    if (Constant *Init = GVCtor->getInitializer()) {
40
0
      unsigned n = Init->getNumOperands();
41
0
      CurrentCtors.reserve(n + 1);
42
0
      for (unsigned i = 0; i != n; ++i)
43
0
        CurrentCtors.push_back(cast<Constant>(Init->getOperand(i)));
44
0
    }
45
0
    GVCtor->eraseFromParent();
46
0
  } else {
47
0
    EltTy = StructType::get(IRB.getInt32Ty(),
48
0
                            PointerType::get(FnTy, F->getAddressSpace()),
49
0
                            IRB.getPtrTy());
50
0
  }
51
52
  // Build a 3 field global_ctor entry.  We don't take a comdat key.
53
0
  Constant *CSVals[3];
54
0
  CSVals[0] = IRB.getInt32(Priority);
55
0
  CSVals[1] = F;
56
0
  CSVals[2] = Data ? ConstantExpr::getPointerCast(Data, IRB.getPtrTy())
57
0
                   : Constant::getNullValue(IRB.getPtrTy());
58
0
  Constant *RuntimeCtorInit =
59
0
      ConstantStruct::get(EltTy, ArrayRef(CSVals, EltTy->getNumElements()));
60
61
0
  CurrentCtors.push_back(RuntimeCtorInit);
62
63
  // Create a new initializer.
64
0
  ArrayType *AT = ArrayType::get(EltTy, CurrentCtors.size());
65
0
  Constant *NewInit = ConstantArray::get(AT, CurrentCtors);
66
67
  // Create the new global variable and replace all uses of
68
  // the old global variable with the new one.
69
0
  (void)new GlobalVariable(M, NewInit->getType(), false,
70
0
                           GlobalValue::AppendingLinkage, NewInit, ArrayName);
71
0
}
72
73
0
void llvm::appendToGlobalCtors(Module &M, Function *F, int Priority, Constant *Data) {
74
0
  appendToGlobalArray("llvm.global_ctors", M, F, Priority, Data);
75
0
}
76
77
0
void llvm::appendToGlobalDtors(Module &M, Function *F, int Priority, Constant *Data) {
78
0
  appendToGlobalArray("llvm.global_dtors", M, F, Priority, Data);
79
0
}
80
81
static void collectUsedGlobals(GlobalVariable *GV,
82
0
                               SmallSetVector<Constant *, 16> &Init) {
83
0
  if (!GV || !GV->hasInitializer())
84
0
    return;
85
86
0
  auto *CA = cast<ConstantArray>(GV->getInitializer());
87
0
  for (Use &Op : CA->operands())
88
0
    Init.insert(cast<Constant>(Op));
89
0
}
90
91
0
static void appendToUsedList(Module &M, StringRef Name, ArrayRef<GlobalValue *> Values) {
92
0
  GlobalVariable *GV = M.getGlobalVariable(Name);
93
94
0
  SmallSetVector<Constant *, 16> Init;
95
0
  collectUsedGlobals(GV, Init);
96
0
  if (GV)
97
0
    GV->eraseFromParent();
98
99
0
  Type *ArrayEltTy = llvm::PointerType::getUnqual(M.getContext());
100
0
  for (auto *V : Values)
101
0
    Init.insert(ConstantExpr::getPointerBitCastOrAddrSpaceCast(V, ArrayEltTy));
102
103
0
  if (Init.empty())
104
0
    return;
105
106
0
  ArrayType *ATy = ArrayType::get(ArrayEltTy, Init.size());
107
0
  GV = new llvm::GlobalVariable(M, ATy, false, GlobalValue::AppendingLinkage,
108
0
                                ConstantArray::get(ATy, Init.getArrayRef()),
109
0
                                Name);
110
0
  GV->setSection("llvm.metadata");
111
0
}
112
113
0
void llvm::appendToUsed(Module &M, ArrayRef<GlobalValue *> Values) {
114
0
  appendToUsedList(M, "llvm.used", Values);
115
0
}
116
117
0
void llvm::appendToCompilerUsed(Module &M, ArrayRef<GlobalValue *> Values) {
118
0
  appendToUsedList(M, "llvm.compiler.used", Values);
119
0
}
120
121
static void removeFromUsedList(Module &M, StringRef Name,
122
0
                               function_ref<bool(Constant *)> ShouldRemove) {
123
0
  GlobalVariable *GV = M.getNamedGlobal(Name);
124
0
  if (!GV)
125
0
    return;
126
127
0
  SmallSetVector<Constant *, 16> Init;
128
0
  collectUsedGlobals(GV, Init);
129
130
0
  Type *ArrayEltTy = cast<ArrayType>(GV->getValueType())->getElementType();
131
132
0
  SmallVector<Constant *, 16> NewInit;
133
0
  for (Constant *MaybeRemoved : Init) {
134
0
    if (!ShouldRemove(MaybeRemoved->stripPointerCasts()))
135
0
      NewInit.push_back(MaybeRemoved);
136
0
  }
137
138
0
  if (!NewInit.empty()) {
139
0
    ArrayType *ATy = ArrayType::get(ArrayEltTy, NewInit.size());
140
0
    GlobalVariable *NewGV =
141
0
        new GlobalVariable(M, ATy, false, GlobalValue::AppendingLinkage,
142
0
                           ConstantArray::get(ATy, NewInit), "", GV,
143
0
                           GV->getThreadLocalMode(), GV->getAddressSpace());
144
0
    NewGV->setSection(GV->getSection());
145
0
    NewGV->takeName(GV);
146
0
  }
147
148
0
  GV->eraseFromParent();
149
0
}
150
151
void llvm::removeFromUsedLists(Module &M,
152
0
                               function_ref<bool(Constant *)> ShouldRemove) {
153
0
  removeFromUsedList(M, "llvm.used", ShouldRemove);
154
0
  removeFromUsedList(M, "llvm.compiler.used", ShouldRemove);
155
0
}
156
157
0
void llvm::setKCFIType(Module &M, Function &F, StringRef MangledType) {
158
0
  if (!M.getModuleFlag("kcfi"))
159
0
    return;
160
  // Matches CodeGenModule::CreateKCFITypeId in Clang.
161
0
  LLVMContext &Ctx = M.getContext();
162
0
  MDBuilder MDB(Ctx);
163
0
  F.setMetadata(
164
0
      LLVMContext::MD_kcfi_type,
165
0
      MDNode::get(Ctx, MDB.createConstant(ConstantInt::get(
166
0
                           Type::getInt32Ty(Ctx),
167
0
                           static_cast<uint32_t>(xxHash64(MangledType))))));
168
  // If the module was compiled with -fpatchable-function-entry, ensure
169
  // we use the same patchable-function-prefix.
170
0
  if (auto *MD = mdconst::extract_or_null<ConstantInt>(
171
0
          M.getModuleFlag("kcfi-offset"))) {
172
0
    if (unsigned Offset = MD->getZExtValue())
173
0
      F.addFnAttr("patchable-function-prefix", std::to_string(Offset));
174
0
  }
175
0
}
176
177
FunctionCallee llvm::declareSanitizerInitFunction(Module &M, StringRef InitName,
178
                                                  ArrayRef<Type *> InitArgTypes,
179
0
                                                  bool Weak) {
180
0
  assert(!InitName.empty() && "Expected init function name");
181
0
  auto *VoidTy = Type::getVoidTy(M.getContext());
182
0
  auto *FnTy = FunctionType::get(VoidTy, InitArgTypes, false);
183
0
  auto FnCallee = M.getOrInsertFunction(InitName, FnTy);
184
0
  auto *Fn = cast<Function>(FnCallee.getCallee());
185
0
  if (Weak && Fn->isDeclaration())
186
0
    Fn->setLinkage(Function::ExternalWeakLinkage);
187
0
  return FnCallee;
188
0
}
189
190
0
Function *llvm::createSanitizerCtor(Module &M, StringRef CtorName) {
191
0
  Function *Ctor = Function::createWithDefaultAttr(
192
0
      FunctionType::get(Type::getVoidTy(M.getContext()), false),
193
0
      GlobalValue::InternalLinkage, M.getDataLayout().getProgramAddressSpace(),
194
0
      CtorName, &M);
195
0
  Ctor->addFnAttr(Attribute::NoUnwind);
196
0
  setKCFIType(M, *Ctor, "_ZTSFvvE"); // void (*)(void)
197
0
  BasicBlock *CtorBB = BasicBlock::Create(M.getContext(), "", Ctor);
198
0
  ReturnInst::Create(M.getContext(), CtorBB);
199
  // Ensure Ctor cannot be discarded, even if in a comdat.
200
0
  appendToUsed(M, {Ctor});
201
0
  return Ctor;
202
0
}
203
204
std::pair<Function *, FunctionCallee> llvm::createSanitizerCtorAndInitFunctions(
205
    Module &M, StringRef CtorName, StringRef InitName,
206
    ArrayRef<Type *> InitArgTypes, ArrayRef<Value *> InitArgs,
207
0
    StringRef VersionCheckName, bool Weak) {
208
0
  assert(!InitName.empty() && "Expected init function name");
209
0
  assert(InitArgs.size() == InitArgTypes.size() &&
210
0
         "Sanitizer's init function expects different number of arguments");
211
0
  FunctionCallee InitFunction =
212
0
      declareSanitizerInitFunction(M, InitName, InitArgTypes, Weak);
213
0
  Function *Ctor = createSanitizerCtor(M, CtorName);
214
0
  IRBuilder<> IRB(M.getContext());
215
216
0
  BasicBlock *RetBB = &Ctor->getEntryBlock();
217
0
  if (Weak) {
218
0
    RetBB->setName("ret");
219
0
    auto *EntryBB = BasicBlock::Create(M.getContext(), "entry", Ctor, RetBB);
220
0
    auto *CallInitBB =
221
0
        BasicBlock::Create(M.getContext(), "callfunc", Ctor, RetBB);
222
0
    auto *InitFn = cast<Function>(InitFunction.getCallee());
223
0
    auto *InitFnPtr =
224
0
        PointerType::get(InitFn->getType(), InitFn->getAddressSpace());
225
0
    IRB.SetInsertPoint(EntryBB);
226
0
    Value *InitNotNull =
227
0
        IRB.CreateICmpNE(InitFn, ConstantPointerNull::get(InitFnPtr));
228
0
    IRB.CreateCondBr(InitNotNull, CallInitBB, RetBB);
229
0
    IRB.SetInsertPoint(CallInitBB);
230
0
  } else {
231
0
    IRB.SetInsertPoint(RetBB->getTerminator());
232
0
  }
233
234
0
  IRB.CreateCall(InitFunction, InitArgs);
235
0
  if (!VersionCheckName.empty()) {
236
0
    FunctionCallee VersionCheckFunction = M.getOrInsertFunction(
237
0
        VersionCheckName, FunctionType::get(IRB.getVoidTy(), {}, false),
238
0
        AttributeList());
239
0
    IRB.CreateCall(VersionCheckFunction, {});
240
0
  }
241
242
0
  if (Weak)
243
0
    IRB.CreateBr(RetBB);
244
245
0
  return std::make_pair(Ctor, InitFunction);
246
0
}
247
248
std::pair<Function *, FunctionCallee>
249
llvm::getOrCreateSanitizerCtorAndInitFunctions(
250
    Module &M, StringRef CtorName, StringRef InitName,
251
    ArrayRef<Type *> InitArgTypes, ArrayRef<Value *> InitArgs,
252
    function_ref<void(Function *, FunctionCallee)> FunctionsCreatedCallback,
253
0
    StringRef VersionCheckName, bool Weak) {
254
0
  assert(!CtorName.empty() && "Expected ctor function name");
255
256
0
  if (Function *Ctor = M.getFunction(CtorName))
257
    // FIXME: Sink this logic into the module, similar to the handling of
258
    // globals. This will make moving to a concurrent model much easier.
259
0
    if (Ctor->arg_empty() ||
260
0
        Ctor->getReturnType() == Type::getVoidTy(M.getContext()))
261
0
      return {Ctor,
262
0
              declareSanitizerInitFunction(M, InitName, InitArgTypes, Weak)};
263
264
0
  Function *Ctor;
265
0
  FunctionCallee InitFunction;
266
0
  std::tie(Ctor, InitFunction) = llvm::createSanitizerCtorAndInitFunctions(
267
0
      M, CtorName, InitName, InitArgTypes, InitArgs, VersionCheckName, Weak);
268
0
  FunctionsCreatedCallback(Ctor, InitFunction);
269
0
  return std::make_pair(Ctor, InitFunction);
270
0
}
271
272
void llvm::filterDeadComdatFunctions(
273
0
    SmallVectorImpl<Function *> &DeadComdatFunctions) {
274
0
  SmallPtrSet<Function *, 32> MaybeDeadFunctions;
275
0
  SmallPtrSet<Comdat *, 32> MaybeDeadComdats;
276
0
  for (Function *F : DeadComdatFunctions) {
277
0
    MaybeDeadFunctions.insert(F);
278
0
    if (Comdat *C = F->getComdat())
279
0
      MaybeDeadComdats.insert(C);
280
0
  }
281
282
  // Find comdats for which all users are dead now.
283
0
  SmallPtrSet<Comdat *, 32> DeadComdats;
284
0
  for (Comdat *C : MaybeDeadComdats) {
285
0
    auto IsUserDead = [&](GlobalObject *GO) {
286
0
      auto *F = dyn_cast<Function>(GO);
287
0
      return F && MaybeDeadFunctions.contains(F);
288
0
    };
289
0
    if (all_of(C->getUsers(), IsUserDead))
290
0
      DeadComdats.insert(C);
291
0
  }
292
293
  // Only keep functions which have no comdat or a dead comdat.
294
0
  erase_if(DeadComdatFunctions, [&](Function *F) {
295
0
    Comdat *C = F->getComdat();
296
0
    return C && !DeadComdats.contains(C);
297
0
  });
298
0
}
299
300
0
std::string llvm::getUniqueModuleId(Module *M) {
301
0
  MD5 Md5;
302
0
  bool ExportsSymbols = false;
303
0
  auto AddGlobal = [&](GlobalValue &GV) {
304
0
    if (GV.isDeclaration() || GV.getName().starts_with("llvm.") ||
305
0
        !GV.hasExternalLinkage() || GV.hasComdat())
306
0
      return;
307
0
    ExportsSymbols = true;
308
0
    Md5.update(GV.getName());
309
0
    Md5.update(ArrayRef<uint8_t>{0});
310
0
  };
311
312
0
  for (auto &F : *M)
313
0
    AddGlobal(F);
314
0
  for (auto &GV : M->globals())
315
0
    AddGlobal(GV);
316
0
  for (auto &GA : M->aliases())
317
0
    AddGlobal(GA);
318
0
  for (auto &IF : M->ifuncs())
319
0
    AddGlobal(IF);
320
321
0
  if (!ExportsSymbols)
322
0
    return "";
323
324
0
  MD5::MD5Result R;
325
0
  Md5.final(R);
326
327
0
  SmallString<32> Str;
328
0
  MD5::stringifyResult(R, Str);
329
0
  return ("." + Str).str();
330
0
}
331
332
void VFABI::setVectorVariantNames(CallInst *CI,
333
0
                                  ArrayRef<std::string> VariantMappings) {
334
0
  if (VariantMappings.empty())
335
0
    return;
336
337
0
  SmallString<256> Buffer;
338
0
  llvm::raw_svector_ostream Out(Buffer);
339
0
  for (const std::string &VariantMapping : VariantMappings)
340
0
    Out << VariantMapping << ",";
341
  // Get rid of the trailing ','.
342
0
  assert(!Buffer.str().empty() && "Must have at least one char.");
343
0
  Buffer.pop_back();
344
345
0
  Module *M = CI->getModule();
346
0
#ifndef NDEBUG
347
0
  for (const std::string &VariantMapping : VariantMappings) {
348
0
    LLVM_DEBUG(dbgs() << "VFABI: adding mapping '" << VariantMapping << "'\n");
349
0
    std::optional<VFInfo> VI =
350
0
        VFABI::tryDemangleForVFABI(VariantMapping, CI->getFunctionType());
351
0
    assert(VI && "Cannot add an invalid VFABI name.");
352
0
    assert(M->getNamedValue(VI->VectorName) &&
353
0
           "Cannot add variant to attribute: "
354
0
           "vector function declaration is missing.");
355
0
  }
356
0
#endif
357
0
  CI->addFnAttr(
358
0
      Attribute::get(M->getContext(), MappingsAttrName, Buffer.str()));
359
0
}
360
361
void llvm::embedBufferInModule(Module &M, MemoryBufferRef Buf,
362
0
                               StringRef SectionName, Align Alignment) {
363
  // Embed the memory buffer into the module.
364
0
  Constant *ModuleConstant = ConstantDataArray::get(
365
0
      M.getContext(), ArrayRef(Buf.getBufferStart(), Buf.getBufferSize()));
366
0
  GlobalVariable *GV = new GlobalVariable(
367
0
      M, ModuleConstant->getType(), true, GlobalValue::PrivateLinkage,
368
0
      ModuleConstant, "llvm.embedded.object");
369
0
  GV->setSection(SectionName);
370
0
  GV->setAlignment(Alignment);
371
372
0
  LLVMContext &Ctx = M.getContext();
373
0
  NamedMDNode *MD = M.getOrInsertNamedMetadata("llvm.embedded.objects");
374
0
  Metadata *MDVals[] = {ConstantAsMetadata::get(GV),
375
0
                        MDString::get(Ctx, SectionName)};
376
377
0
  MD->addOperand(llvm::MDNode::get(Ctx, MDVals));
378
0
  GV->setMetadata(LLVMContext::MD_exclude, llvm::MDNode::get(Ctx, {}));
379
380
0
  appendToCompilerUsed(M, GV);
381
0
}
382
383
bool llvm::lowerGlobalIFuncUsersAsGlobalCtor(
384
0
    Module &M, ArrayRef<GlobalIFunc *> FilteredIFuncsToLower) {
385
0
  SmallVector<GlobalIFunc *, 32> AllIFuncs;
386
0
  ArrayRef<GlobalIFunc *> IFuncsToLower = FilteredIFuncsToLower;
387
0
  if (FilteredIFuncsToLower.empty()) { // Default to lowering all ifuncs
388
0
    for (GlobalIFunc &GI : M.ifuncs())
389
0
      AllIFuncs.push_back(&GI);
390
0
    IFuncsToLower = AllIFuncs;
391
0
  }
392
393
0
  bool UnhandledUsers = false;
394
0
  LLVMContext &Ctx = M.getContext();
395
0
  const DataLayout &DL = M.getDataLayout();
396
397
0
  PointerType *TableEntryTy =
398
0
      PointerType::get(Ctx, DL.getProgramAddressSpace());
399
400
0
  ArrayType *FuncPtrTableTy =
401
0
      ArrayType::get(TableEntryTy, IFuncsToLower.size());
402
403
0
  Align PtrAlign = DL.getABITypeAlign(TableEntryTy);
404
405
  // Create a global table of function pointers we'll initialize in a global
406
  // constructor.
407
0
  auto *FuncPtrTable = new GlobalVariable(
408
0
      M, FuncPtrTableTy, false, GlobalValue::InternalLinkage,
409
0
      PoisonValue::get(FuncPtrTableTy), "", nullptr,
410
0
      GlobalVariable::NotThreadLocal, DL.getDefaultGlobalsAddressSpace());
411
0
  FuncPtrTable->setAlignment(PtrAlign);
412
413
  // Create a function to initialize the function pointer table.
414
0
  Function *NewCtor = Function::Create(
415
0
      FunctionType::get(Type::getVoidTy(Ctx), false), Function::InternalLinkage,
416
0
      DL.getProgramAddressSpace(), "", &M);
417
418
0
  BasicBlock *BB = BasicBlock::Create(Ctx, "", NewCtor);
419
0
  IRBuilder<> InitBuilder(BB);
420
421
0
  size_t TableIndex = 0;
422
0
  for (GlobalIFunc *GI : IFuncsToLower) {
423
0
    Function *ResolvedFunction = GI->getResolverFunction();
424
425
    // We don't know what to pass to a resolver function taking arguments
426
    //
427
    // FIXME: Is this even valid? clang and gcc don't complain but this
428
    // probably should be invalid IR. We could just pass through undef.
429
0
    if (!std::empty(ResolvedFunction->getFunctionType()->params())) {
430
0
      LLVM_DEBUG(dbgs() << "Not lowering ifunc resolver function "
431
0
                        << ResolvedFunction->getName() << " with parameters\n");
432
0
      UnhandledUsers = true;
433
0
      continue;
434
0
    }
435
436
    // Initialize the function pointer table.
437
0
    CallInst *ResolvedFunc = InitBuilder.CreateCall(ResolvedFunction);
438
0
    Value *Casted = InitBuilder.CreatePointerCast(ResolvedFunc, TableEntryTy);
439
0
    Constant *GEP = cast<Constant>(InitBuilder.CreateConstInBoundsGEP2_32(
440
0
        FuncPtrTableTy, FuncPtrTable, 0, TableIndex++));
441
0
    InitBuilder.CreateAlignedStore(Casted, GEP, PtrAlign);
442
443
    // Update all users to load a pointer from the global table.
444
0
    for (User *User : make_early_inc_range(GI->users())) {
445
0
      Instruction *UserInst = dyn_cast<Instruction>(User);
446
0
      if (!UserInst) {
447
        // TODO: Should handle constantexpr casts in user instructions. Probably
448
        // can't do much about constant initializers.
449
0
        UnhandledUsers = true;
450
0
        continue;
451
0
      }
452
453
0
      IRBuilder<> UseBuilder(UserInst);
454
0
      LoadInst *ResolvedTarget =
455
0
          UseBuilder.CreateAlignedLoad(TableEntryTy, GEP, PtrAlign);
456
0
      Value *ResolvedCast =
457
0
          UseBuilder.CreatePointerCast(ResolvedTarget, GI->getType());
458
0
      UserInst->replaceUsesOfWith(GI, ResolvedCast);
459
0
    }
460
461
    // If we handled all users, erase the ifunc.
462
0
    if (GI->use_empty())
463
0
      GI->eraseFromParent();
464
0
  }
465
466
0
  InitBuilder.CreateRetVoid();
467
468
0
  PointerType *ConstantDataTy = PointerType::get(Ctx, 0);
469
470
  // TODO: Is this the right priority? Probably should be before any other
471
  // constructors?
472
0
  const int Priority = 10;
473
0
  appendToGlobalCtors(M, NewCtor, Priority,
474
0
                      ConstantPointerNull::get(ConstantDataTy));
475
0
  return UnhandledUsers;
476
0
}