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