xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/JMCInstrumenter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
181ad6265SDimitry Andric //===- JMCInstrumenter.cpp - JMC Instrumentation --------------------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // JMCInstrumenter pass:
1081ad6265SDimitry Andric // - instrument each function with a call to __CheckForDebuggerJustMyCode. The
1181ad6265SDimitry Andric //   sole argument should be defined in .msvcjmc. Each flag is 1 byte initilized
1281ad6265SDimitry Andric //   to 1.
1381ad6265SDimitry Andric // - create the dummy COMDAT function __JustMyCode_Default to prevent linking
1481ad6265SDimitry Andric //   error if __CheckForDebuggerJustMyCode is not available.
1581ad6265SDimitry Andric // - For MSVC:
1681ad6265SDimitry Andric //   add "/alternatename:__CheckForDebuggerJustMyCode=__JustMyCode_Default" to
1781ad6265SDimitry Andric //   "llvm.linker.options"
1881ad6265SDimitry Andric //   For ELF:
1981ad6265SDimitry Andric //   Rename __JustMyCode_Default to __CheckForDebuggerJustMyCode and mark it as
2081ad6265SDimitry Andric //   weak symbol.
2181ad6265SDimitry Andric //===----------------------------------------------------------------------===//
2281ad6265SDimitry Andric 
235f757f3fSDimitry Andric #include "llvm/CodeGen/JMCInstrumenter.h"
2481ad6265SDimitry Andric #include "llvm/ADT/SmallString.h"
2581ad6265SDimitry Andric #include "llvm/ADT/StringExtras.h"
2681ad6265SDimitry Andric #include "llvm/CodeGen/Passes.h"
2781ad6265SDimitry Andric #include "llvm/IR/DIBuilder.h"
2881ad6265SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h"
2981ad6265SDimitry Andric #include "llvm/IR/DerivedTypes.h"
3081ad6265SDimitry Andric #include "llvm/IR/Function.h"
3181ad6265SDimitry Andric #include "llvm/IR/Instructions.h"
3281ad6265SDimitry Andric #include "llvm/IR/LLVMContext.h"
3381ad6265SDimitry Andric #include "llvm/IR/Module.h"
3481ad6265SDimitry Andric #include "llvm/IR/Type.h"
3581ad6265SDimitry Andric #include "llvm/InitializePasses.h"
3681ad6265SDimitry Andric #include "llvm/Pass.h"
3781ad6265SDimitry Andric #include "llvm/Support/DJB.h"
3881ad6265SDimitry Andric #include "llvm/Support/Path.h"
3981ad6265SDimitry Andric #include "llvm/Transforms/Utils/ModuleUtils.h"
4081ad6265SDimitry Andric 
4181ad6265SDimitry Andric using namespace llvm;
4281ad6265SDimitry Andric 
435f757f3fSDimitry Andric #define DEBUG_TYPE "jmc-instrumenter"
4481ad6265SDimitry Andric 
455f757f3fSDimitry Andric static bool runImpl(Module &M);
4681ad6265SDimitry Andric namespace {
4781ad6265SDimitry Andric struct JMCInstrumenter : public ModulePass {
4881ad6265SDimitry Andric   static char ID;
JMCInstrumenter__anon8384c81e0111::JMCInstrumenter4981ad6265SDimitry Andric   JMCInstrumenter() : ModulePass(ID) {
5081ad6265SDimitry Andric     initializeJMCInstrumenterPass(*PassRegistry::getPassRegistry());
5181ad6265SDimitry Andric   }
runOnModule__anon8384c81e0111::JMCInstrumenter525f757f3fSDimitry Andric   bool runOnModule(Module &M) override { return runImpl(M); }
5381ad6265SDimitry Andric };
5481ad6265SDimitry Andric char JMCInstrumenter::ID = 0;
5581ad6265SDimitry Andric } // namespace
5681ad6265SDimitry Andric 
run(Module & M,ModuleAnalysisManager &)575f757f3fSDimitry Andric PreservedAnalyses JMCInstrumenterPass::run(Module &M, ModuleAnalysisManager &) {
585f757f3fSDimitry Andric   bool Changed = runImpl(M);
595f757f3fSDimitry Andric   return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
605f757f3fSDimitry Andric }
615f757f3fSDimitry Andric 
6281ad6265SDimitry Andric INITIALIZE_PASS(
6381ad6265SDimitry Andric     JMCInstrumenter, DEBUG_TYPE,
6481ad6265SDimitry Andric     "Instrument function entry with call to __CheckForDebuggerJustMyCode",
6581ad6265SDimitry Andric     false, false)
6681ad6265SDimitry Andric 
createJMCInstrumenterPass()6781ad6265SDimitry Andric ModulePass *llvm::createJMCInstrumenterPass() { return new JMCInstrumenter(); }
6881ad6265SDimitry Andric 
6981ad6265SDimitry Andric namespace {
7081ad6265SDimitry Andric const char CheckFunctionName[] = "__CheckForDebuggerJustMyCode";
7181ad6265SDimitry Andric 
getFlagName(DISubprogram & SP,bool UseX86FastCall)7281ad6265SDimitry Andric std::string getFlagName(DISubprogram &SP, bool UseX86FastCall) {
7381ad6265SDimitry Andric   // absolute windows path:           windows_backslash
7481ad6265SDimitry Andric   // relative windows backslash path: windows_backslash
7581ad6265SDimitry Andric   // relative windows slash path:     posix
7681ad6265SDimitry Andric   // absolute posix path:             posix
7781ad6265SDimitry Andric   // relative posix path:             posix
7881ad6265SDimitry Andric   sys::path::Style PathStyle =
7981ad6265SDimitry Andric       has_root_name(SP.getDirectory(), sys::path::Style::windows_backslash) ||
8081ad6265SDimitry Andric               SP.getDirectory().contains("\\") ||
8181ad6265SDimitry Andric               SP.getFilename().contains("\\")
8281ad6265SDimitry Andric           ? sys::path::Style::windows_backslash
8381ad6265SDimitry Andric           : sys::path::Style::posix;
8481ad6265SDimitry Andric   // Best effort path normalization. This is to guarantee an unique flag symbol
8581ad6265SDimitry Andric   // is produced for the same directory. Some builds may want to use relative
8681ad6265SDimitry Andric   // paths, or paths with a specific prefix (see the -fdebug-compilation-dir
8781ad6265SDimitry Andric   // flag), so only hash paths in debuginfo. Don't expand them to absolute
8881ad6265SDimitry Andric   // paths.
8981ad6265SDimitry Andric   SmallString<256> FilePath(SP.getDirectory());
9081ad6265SDimitry Andric   sys::path::append(FilePath, PathStyle, SP.getFilename());
9181ad6265SDimitry Andric   sys::path::native(FilePath, PathStyle);
9281ad6265SDimitry Andric   sys::path::remove_dots(FilePath, /*remove_dot_dot=*/true, PathStyle);
9381ad6265SDimitry Andric 
9481ad6265SDimitry Andric   // The naming convention for the flag name is __<hash>_<file name> with '.' in
9581ad6265SDimitry Andric   // <file name> replaced with '@'. For example C:\file.any.c would have a flag
9681ad6265SDimitry Andric   // __D032E919_file@any@c. The naming convention match MSVC's format however
9781ad6265SDimitry Andric   // the match is not required to make JMC work. The hashing function used here
9881ad6265SDimitry Andric   // is different from MSVC's.
9981ad6265SDimitry Andric 
10081ad6265SDimitry Andric   std::string Suffix;
10181ad6265SDimitry Andric   for (auto C : sys::path::filename(FilePath, PathStyle))
10281ad6265SDimitry Andric     Suffix.push_back(C == '.' ? '@' : C);
10381ad6265SDimitry Andric 
10481ad6265SDimitry Andric   sys::path::remove_filename(FilePath, PathStyle);
10581ad6265SDimitry Andric   return (UseX86FastCall ? "_" : "__") +
10681ad6265SDimitry Andric          utohexstr(djbHash(FilePath), /*LowerCase=*/false,
10781ad6265SDimitry Andric                    /*Width=*/8) +
10881ad6265SDimitry Andric          "_" + Suffix;
10981ad6265SDimitry Andric }
11081ad6265SDimitry Andric 
attachDebugInfo(GlobalVariable & GV,DISubprogram & SP)11181ad6265SDimitry Andric void attachDebugInfo(GlobalVariable &GV, DISubprogram &SP) {
11281ad6265SDimitry Andric   Module &M = *GV.getParent();
11381ad6265SDimitry Andric   DICompileUnit *CU = SP.getUnit();
11481ad6265SDimitry Andric   assert(CU);
11581ad6265SDimitry Andric   DIBuilder DB(M, false, CU);
11681ad6265SDimitry Andric 
11781ad6265SDimitry Andric   auto *DType =
11881ad6265SDimitry Andric       DB.createBasicType("unsigned char", 8, dwarf::DW_ATE_unsigned_char,
11981ad6265SDimitry Andric                          llvm::DINode::FlagArtificial);
12081ad6265SDimitry Andric 
12181ad6265SDimitry Andric   auto *DGVE = DB.createGlobalVariableExpression(
12281ad6265SDimitry Andric       CU, GV.getName(), /*LinkageName=*/StringRef(), SP.getFile(),
12381ad6265SDimitry Andric       /*LineNo=*/0, DType, /*IsLocalToUnit=*/true, /*IsDefined=*/true);
12481ad6265SDimitry Andric   GV.addMetadata(LLVMContext::MD_dbg, *DGVE);
12581ad6265SDimitry Andric   DB.finalize();
12681ad6265SDimitry Andric }
12781ad6265SDimitry Andric 
getCheckFunctionType(LLVMContext & Ctx)12881ad6265SDimitry Andric FunctionType *getCheckFunctionType(LLVMContext &Ctx) {
12981ad6265SDimitry Andric   Type *VoidTy = Type::getVoidTy(Ctx);
1305f757f3fSDimitry Andric   PointerType *VoidPtrTy = PointerType::getUnqual(Ctx);
13181ad6265SDimitry Andric   return FunctionType::get(VoidTy, VoidPtrTy, false);
13281ad6265SDimitry Andric }
13381ad6265SDimitry Andric 
createDefaultCheckFunction(Module & M,bool UseX86FastCall)13481ad6265SDimitry Andric Function *createDefaultCheckFunction(Module &M, bool UseX86FastCall) {
13581ad6265SDimitry Andric   LLVMContext &Ctx = M.getContext();
13681ad6265SDimitry Andric   const char *DefaultCheckFunctionName =
13781ad6265SDimitry Andric       UseX86FastCall ? "_JustMyCode_Default" : "__JustMyCode_Default";
13881ad6265SDimitry Andric   // Create the function.
13981ad6265SDimitry Andric   Function *DefaultCheckFunc =
14081ad6265SDimitry Andric       Function::Create(getCheckFunctionType(Ctx), GlobalValue::ExternalLinkage,
14181ad6265SDimitry Andric                        DefaultCheckFunctionName, &M);
14281ad6265SDimitry Andric   DefaultCheckFunc->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
14381ad6265SDimitry Andric   DefaultCheckFunc->addParamAttr(0, Attribute::NoUndef);
14481ad6265SDimitry Andric   if (UseX86FastCall)
14581ad6265SDimitry Andric     DefaultCheckFunc->addParamAttr(0, Attribute::InReg);
14681ad6265SDimitry Andric 
14781ad6265SDimitry Andric   BasicBlock *EntryBB = BasicBlock::Create(Ctx, "", DefaultCheckFunc);
14881ad6265SDimitry Andric   ReturnInst::Create(Ctx, EntryBB);
14981ad6265SDimitry Andric   return DefaultCheckFunc;
15081ad6265SDimitry Andric }
15181ad6265SDimitry Andric } // namespace
15281ad6265SDimitry Andric 
runImpl(Module & M)1535f757f3fSDimitry Andric bool runImpl(Module &M) {
15481ad6265SDimitry Andric   bool Changed = false;
15581ad6265SDimitry Andric   LLVMContext &Ctx = M.getContext();
15681ad6265SDimitry Andric   Triple ModuleTriple(M.getTargetTriple());
15781ad6265SDimitry Andric   bool IsMSVC = ModuleTriple.isKnownWindowsMSVCEnvironment();
15881ad6265SDimitry Andric   bool IsELF = ModuleTriple.isOSBinFormatELF();
15981ad6265SDimitry Andric   assert((IsELF || IsMSVC) && "Unsupported triple for JMC");
16081ad6265SDimitry Andric   bool UseX86FastCall = IsMSVC && ModuleTriple.getArch() == Triple::x86;
161bdd1243dSDimitry Andric   const char *const FlagSymbolSection = IsELF ? ".data.just.my.code" : ".msvcjmc";
16281ad6265SDimitry Andric 
16381ad6265SDimitry Andric   GlobalValue *CheckFunction = nullptr;
16481ad6265SDimitry Andric   DenseMap<DISubprogram *, Constant *> SavedFlags(8);
16581ad6265SDimitry Andric   for (auto &F : M) {
16681ad6265SDimitry Andric     if (F.isDeclaration())
16781ad6265SDimitry Andric       continue;
16881ad6265SDimitry Andric     auto *SP = F.getSubprogram();
16981ad6265SDimitry Andric     if (!SP)
17081ad6265SDimitry Andric       continue;
17181ad6265SDimitry Andric 
17281ad6265SDimitry Andric     Constant *&Flag = SavedFlags[SP];
17381ad6265SDimitry Andric     if (!Flag) {
17481ad6265SDimitry Andric       std::string FlagName = getFlagName(*SP, UseX86FastCall);
17581ad6265SDimitry Andric       IntegerType *FlagTy = Type::getInt8Ty(Ctx);
17681ad6265SDimitry Andric       Flag = M.getOrInsertGlobal(FlagName, FlagTy, [&] {
17781ad6265SDimitry Andric         // FIXME: Put the GV in comdat and have linkonce_odr linkage to save
17881ad6265SDimitry Andric         //        .msvcjmc section space? maybe not worth it.
17981ad6265SDimitry Andric         GlobalVariable *GV = new GlobalVariable(
18081ad6265SDimitry Andric             M, FlagTy, /*isConstant=*/false, GlobalValue::InternalLinkage,
18181ad6265SDimitry Andric             ConstantInt::get(FlagTy, 1), FlagName);
18281ad6265SDimitry Andric         GV->setSection(FlagSymbolSection);
18381ad6265SDimitry Andric         GV->setAlignment(Align(1));
18481ad6265SDimitry Andric         GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
18581ad6265SDimitry Andric         attachDebugInfo(*GV, *SP);
18681ad6265SDimitry Andric         return GV;
18781ad6265SDimitry Andric       });
18881ad6265SDimitry Andric     }
18981ad6265SDimitry Andric 
19081ad6265SDimitry Andric     if (!CheckFunction) {
19181ad6265SDimitry Andric       Function *DefaultCheckFunc =
19281ad6265SDimitry Andric           createDefaultCheckFunction(M, UseX86FastCall);
19381ad6265SDimitry Andric       if (IsELF) {
19481ad6265SDimitry Andric         DefaultCheckFunc->setName(CheckFunctionName);
19581ad6265SDimitry Andric         DefaultCheckFunc->setLinkage(GlobalValue::WeakAnyLinkage);
19681ad6265SDimitry Andric         CheckFunction = DefaultCheckFunc;
19781ad6265SDimitry Andric       } else {
19881ad6265SDimitry Andric         assert(!M.getFunction(CheckFunctionName) &&
19981ad6265SDimitry Andric                "JMC instrument more than once?");
20081ad6265SDimitry Andric         auto *CheckFunc = cast<Function>(
20181ad6265SDimitry Andric             M.getOrInsertFunction(CheckFunctionName, getCheckFunctionType(Ctx))
20281ad6265SDimitry Andric                 .getCallee());
20381ad6265SDimitry Andric         CheckFunc->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
20481ad6265SDimitry Andric         CheckFunc->addParamAttr(0, Attribute::NoUndef);
20581ad6265SDimitry Andric         if (UseX86FastCall) {
20681ad6265SDimitry Andric           CheckFunc->setCallingConv(CallingConv::X86_FastCall);
20781ad6265SDimitry Andric           CheckFunc->addParamAttr(0, Attribute::InReg);
20881ad6265SDimitry Andric         }
20981ad6265SDimitry Andric         CheckFunction = CheckFunc;
21081ad6265SDimitry Andric 
21181ad6265SDimitry Andric         StringRef DefaultCheckFunctionName = DefaultCheckFunc->getName();
21281ad6265SDimitry Andric         appendToUsed(M, {DefaultCheckFunc});
21381ad6265SDimitry Andric         Comdat *C = M.getOrInsertComdat(DefaultCheckFunctionName);
21481ad6265SDimitry Andric         C->setSelectionKind(Comdat::Any);
21581ad6265SDimitry Andric         DefaultCheckFunc->setComdat(C);
21681ad6265SDimitry Andric         // Add a linker option /alternatename to set the default implementation
21781ad6265SDimitry Andric         // for the check function.
21881ad6265SDimitry Andric         // https://devblogs.microsoft.com/oldnewthing/20200731-00/?p=104024
21981ad6265SDimitry Andric         std::string AltOption = std::string("/alternatename:") +
22081ad6265SDimitry Andric                                 CheckFunctionName + "=" +
22181ad6265SDimitry Andric                                 DefaultCheckFunctionName.str();
22281ad6265SDimitry Andric         llvm::Metadata *Ops[] = {llvm::MDString::get(Ctx, AltOption)};
22381ad6265SDimitry Andric         MDTuple *N = MDNode::get(Ctx, Ops);
22481ad6265SDimitry Andric         M.getOrInsertNamedMetadata("llvm.linker.options")->addOperand(N);
22581ad6265SDimitry Andric       }
22681ad6265SDimitry Andric     }
22781ad6265SDimitry Andric     // FIXME: it would be nice to make CI scheduling boundary, although in
22881ad6265SDimitry Andric     //        practice it does not matter much.
22981ad6265SDimitry Andric     auto *CI = CallInst::Create(getCheckFunctionType(Ctx), CheckFunction,
230*0fca6ea1SDimitry Andric                                 {Flag}, "", F.begin()->getFirstInsertionPt());
23181ad6265SDimitry Andric     CI->addParamAttr(0, Attribute::NoUndef);
23281ad6265SDimitry Andric     if (UseX86FastCall) {
23381ad6265SDimitry Andric       CI->setCallingConv(CallingConv::X86_FastCall);
23481ad6265SDimitry Andric       CI->addParamAttr(0, Attribute::InReg);
23581ad6265SDimitry Andric     }
23681ad6265SDimitry Andric 
23781ad6265SDimitry Andric     Changed = true;
23881ad6265SDimitry Andric   }
23981ad6265SDimitry Andric   return Changed;
24081ad6265SDimitry Andric }
241