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