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