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; 4981ad6265SDimitry Andric JMCInstrumenter() : ModulePass(ID) { 5081ad6265SDimitry Andric initializeJMCInstrumenterPass(*PassRegistry::getPassRegistry()); 5181ad6265SDimitry Andric } 525f757f3fSDimitry Andric bool runOnModule(Module &M) override { return runImpl(M); } 5381ad6265SDimitry Andric }; 5481ad6265SDimitry Andric char JMCInstrumenter::ID = 0; 5581ad6265SDimitry Andric } // namespace 5681ad6265SDimitry Andric 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 6781ad6265SDimitry Andric ModulePass *llvm::createJMCInstrumenterPass() { return new JMCInstrumenter(); } 6881ad6265SDimitry Andric 6981ad6265SDimitry Andric namespace { 7081ad6265SDimitry Andric const char CheckFunctionName[] = "__CheckForDebuggerJustMyCode"; 7181ad6265SDimitry Andric 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 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 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 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 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