1 //===- JMCInstrumenter.cpp - JMC 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 // JMCInstrumenter pass: 10 // - instrument each function with a call to __CheckForDebuggerJustMyCode. The 11 // sole argument should be defined in .msvcjmc. Each flag is 1 byte initilized 12 // to 1. 13 // - create the dummy COMDAT function __JustMyCode_Default to prevent linking 14 // error if __CheckForDebuggerJustMyCode is not available. 15 // - For MSVC: 16 // add "/alternatename:__CheckForDebuggerJustMyCode=__JustMyCode_Default" to 17 // "llvm.linker.options" 18 // For ELF: 19 // Rename __JustMyCode_Default to __CheckForDebuggerJustMyCode and mark it as 20 // weak symbol. 21 //===----------------------------------------------------------------------===// 22 23 #include "llvm/ADT/SmallString.h" 24 #include "llvm/ADT/StringExtras.h" 25 #include "llvm/CodeGen/Passes.h" 26 #include "llvm/IR/DIBuilder.h" 27 #include "llvm/IR/DebugInfoMetadata.h" 28 #include "llvm/IR/DerivedTypes.h" 29 #include "llvm/IR/Function.h" 30 #include "llvm/IR/Instructions.h" 31 #include "llvm/IR/LLVMContext.h" 32 #include "llvm/IR/Module.h" 33 #include "llvm/IR/Type.h" 34 #include "llvm/InitializePasses.h" 35 #include "llvm/Pass.h" 36 #include "llvm/Support/DJB.h" 37 #include "llvm/Support/Path.h" 38 #include "llvm/Transforms/Utils/ModuleUtils.h" 39 40 using namespace llvm; 41 42 #define DEBUG_TYPE "jmc-instrument" 43 44 namespace { 45 struct JMCInstrumenter : public ModulePass { 46 static char ID; 47 JMCInstrumenter() : ModulePass(ID) { 48 initializeJMCInstrumenterPass(*PassRegistry::getPassRegistry()); 49 } 50 bool runOnModule(Module &M) override; 51 }; 52 char JMCInstrumenter::ID = 0; 53 } // namespace 54 55 INITIALIZE_PASS( 56 JMCInstrumenter, DEBUG_TYPE, 57 "Instrument function entry with call to __CheckForDebuggerJustMyCode", 58 false, false) 59 60 ModulePass *llvm::createJMCInstrumenterPass() { return new JMCInstrumenter(); } 61 62 namespace { 63 const char CheckFunctionName[] = "__CheckForDebuggerJustMyCode"; 64 65 std::string getFlagName(DISubprogram &SP, bool UseX86FastCall) { 66 // Best effort path normalization. This is to guarantee an unique flag symbol 67 // is produced for the same directory. Some builds may want to use relative 68 // paths, or paths with a specific prefix (see the -fdebug-compilation-dir 69 // flag), so only hash paths in debuginfo. Don't expand them to absolute 70 // paths. 71 SmallString<256> FilePath(SP.getDirectory()); 72 sys::path::append(FilePath, SP.getFilename()); 73 sys::path::native(FilePath); 74 sys::path::remove_dots(FilePath, /*remove_dot_dot=*/true); 75 76 // The naming convention for the flag name is __<hash>_<file name> with '.' in 77 // <file name> replaced with '@'. For example C:\file.any.c would have a flag 78 // __D032E919_file@any@c. The naming convention match MSVC's format however 79 // the match is not required to make JMC work. The hashing function used here 80 // is different from MSVC's. 81 82 std::string Suffix; 83 for (auto C : sys::path::filename(FilePath)) 84 Suffix.push_back(C == '.' ? '@' : C); 85 86 sys::path::remove_filename(FilePath); 87 return (UseX86FastCall ? "_" : "__") + 88 utohexstr(djbHash(FilePath), /*LowerCase=*/false, 89 /*Width=*/8) + 90 "_" + Suffix; 91 } 92 93 void attachDebugInfo(GlobalVariable &GV, DISubprogram &SP) { 94 Module &M = *GV.getParent(); 95 DICompileUnit *CU = SP.getUnit(); 96 assert(CU); 97 DIBuilder DB(M, false, CU); 98 99 auto *DType = 100 DB.createBasicType("unsigned char", 8, dwarf::DW_ATE_unsigned_char, 101 llvm::DINode::FlagArtificial); 102 103 auto *DGVE = DB.createGlobalVariableExpression( 104 CU, GV.getName(), /*LinkageName=*/StringRef(), SP.getFile(), 105 /*LineNo=*/0, DType, /*IsLocalToUnit=*/true, /*IsDefined=*/true); 106 GV.addMetadata(LLVMContext::MD_dbg, *DGVE); 107 DB.finalize(); 108 } 109 110 FunctionType *getCheckFunctionType(LLVMContext &Ctx) { 111 Type *VoidTy = Type::getVoidTy(Ctx); 112 PointerType *VoidPtrTy = Type::getInt8PtrTy(Ctx); 113 return FunctionType::get(VoidTy, VoidPtrTy, false); 114 } 115 116 Function *createDefaultCheckFunction(Module &M, bool UseX86FastCall) { 117 LLVMContext &Ctx = M.getContext(); 118 const char *DefaultCheckFunctionName = 119 UseX86FastCall ? "_JustMyCode_Default" : "__JustMyCode_Default"; 120 // Create the function. 121 Function *DefaultCheckFunc = 122 Function::Create(getCheckFunctionType(Ctx), GlobalValue::ExternalLinkage, 123 DefaultCheckFunctionName, &M); 124 DefaultCheckFunc->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); 125 DefaultCheckFunc->addParamAttr(0, Attribute::NoUndef); 126 if (UseX86FastCall) 127 DefaultCheckFunc->addParamAttr(0, Attribute::InReg); 128 129 BasicBlock *EntryBB = BasicBlock::Create(Ctx, "", DefaultCheckFunc); 130 ReturnInst::Create(Ctx, EntryBB); 131 return DefaultCheckFunc; 132 } 133 } // namespace 134 135 bool JMCInstrumenter::runOnModule(Module &M) { 136 bool Changed = false; 137 LLVMContext &Ctx = M.getContext(); 138 Triple ModuleTriple(M.getTargetTriple()); 139 bool IsMSVC = ModuleTriple.isKnownWindowsMSVCEnvironment(); 140 bool IsELF = ModuleTriple.isOSBinFormatELF(); 141 assert((IsELF || IsMSVC) && "Unsupported triple for JMC"); 142 bool UseX86FastCall = IsMSVC && ModuleTriple.getArch() == Triple::x86; 143 const char *const FlagSymbolSection = IsELF ? ".just.my.code" : ".msvcjmc"; 144 145 GlobalValue *CheckFunction = nullptr; 146 DenseMap<DISubprogram *, Constant *> SavedFlags(8); 147 for (auto &F : M) { 148 if (F.isDeclaration()) 149 continue; 150 auto *SP = F.getSubprogram(); 151 if (!SP) 152 continue; 153 154 Constant *&Flag = SavedFlags[SP]; 155 if (!Flag) { 156 std::string FlagName = getFlagName(*SP, UseX86FastCall); 157 IntegerType *FlagTy = Type::getInt8Ty(Ctx); 158 Flag = M.getOrInsertGlobal(FlagName, FlagTy, [&] { 159 // FIXME: Put the GV in comdat and have linkonce_odr linkage to save 160 // .msvcjmc section space? maybe not worth it. 161 GlobalVariable *GV = new GlobalVariable( 162 M, FlagTy, /*isConstant=*/false, GlobalValue::InternalLinkage, 163 ConstantInt::get(FlagTy, 1), FlagName); 164 GV->setSection(FlagSymbolSection); 165 GV->setAlignment(Align(1)); 166 GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); 167 attachDebugInfo(*GV, *SP); 168 return GV; 169 }); 170 } 171 172 if (!CheckFunction) { 173 Function *DefaultCheckFunc = 174 createDefaultCheckFunction(M, UseX86FastCall); 175 if (IsELF) { 176 DefaultCheckFunc->setName(CheckFunctionName); 177 DefaultCheckFunc->setLinkage(GlobalValue::WeakAnyLinkage); 178 CheckFunction = DefaultCheckFunc; 179 } else { 180 assert(!M.getFunction(CheckFunctionName) && 181 "JMC instrument more than once?"); 182 auto *CheckFunc = cast<Function>( 183 M.getOrInsertFunction(CheckFunctionName, getCheckFunctionType(Ctx)) 184 .getCallee()); 185 CheckFunc->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); 186 CheckFunc->addParamAttr(0, Attribute::NoUndef); 187 if (UseX86FastCall) { 188 CheckFunc->setCallingConv(CallingConv::X86_FastCall); 189 CheckFunc->addParamAttr(0, Attribute::InReg); 190 } 191 CheckFunction = CheckFunc; 192 193 StringRef DefaultCheckFunctionName = DefaultCheckFunc->getName(); 194 appendToUsed(M, {DefaultCheckFunc}); 195 Comdat *C = M.getOrInsertComdat(DefaultCheckFunctionName); 196 C->setSelectionKind(Comdat::Any); 197 DefaultCheckFunc->setComdat(C); 198 // Add a linker option /alternatename to set the default implementation 199 // for the check function. 200 // https://devblogs.microsoft.com/oldnewthing/20200731-00/?p=104024 201 std::string AltOption = std::string("/alternatename:") + 202 CheckFunctionName + "=" + 203 DefaultCheckFunctionName.str(); 204 llvm::Metadata *Ops[] = {llvm::MDString::get(Ctx, AltOption)}; 205 MDTuple *N = MDNode::get(Ctx, Ops); 206 M.getOrInsertNamedMetadata("llvm.linker.options")->addOperand(N); 207 } 208 } 209 // FIXME: it would be nice to make CI scheduling boundary, although in 210 // practice it does not matter much. 211 auto *CI = CallInst::Create(getCheckFunctionType(Ctx), CheckFunction, 212 {Flag}, "", &*F.begin()->getFirstInsertionPt()); 213 CI->addParamAttr(0, Attribute::NoUndef); 214 if (UseX86FastCall) { 215 CI->setCallingConv(CallingConv::X86_FastCall); 216 CI->addParamAttr(0, Attribute::InReg); 217 } 218 219 Changed = true; 220 } 221 return Changed; 222 } 223