1/**
2 * Copyright (c) Glow Contributors. See CONTRIBUTORS file.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "glow/LLVMIRCodeGen/CommandLine.h"
18#include "glow/LLVMIRCodeGen/LLVMIRGen.h"
19#include "glow/Support/Debug.h"
20#include "llvm/Support/Regex.h"
21
22#define DEBUG_TYPE "debug-instrumentation"
23
24using namespace glow;
25
26using llvm::cast;
27using llvm::dyn_cast;
28using llvm::isa;
29
30namespace {
31
32/// Supported types of instrumentations.
33enum FunctionInstrumentationType {
34 // Every single LLVM IR instruction
35 // of selected functions will be instrumented.
36 BODY = 1,
37 // Function calls will be wrapped in traces.
38 CALL = 2,
39};
40
41/// Metadata about instrumentation.
42struct InstrumentationMetaInformation {
43 // Regular expression of function.
44 llvm::Regex funcReg;
45 // Instrumentation style.
46 FunctionInstrumentationType style;
47 // If instrumentation style is CALL, then
48 // it allows to specify funciton to call before
49 llvm::Function *callBefore;
50 // and after.
51 llvm::Function *callAfter;
52};
53
54/// Perform code instrumentation for selected functions.
55/// The syntax is array of sections separated by coma ",".
56/// Every section starts with function regex, then body/call clause.
57/// PE Ex: "func1*:body,func2:call[:before_func2[:after_func2]];..."
58static llvm::cl::list<std::string> llvmIrInstrumentation(
59 "llvm-code-debug-trace-instrumentation",
60 llvm::cl::desc(
61 "Create trace instructions for functions bodies or function calls"),
62 llvm::cl::ZeroOrMore, llvm::cl::CommaSeparated,
63 llvm::cl::cat(getLLVMBackendCat()));
64
65static llvm::cl::opt<std::string> llvmIrInstrPrintoutFuncName(
66 "llvm-debug-trace-print-function-name",
67 llvm::cl::desc("Select function that will do prints, function must be with "
68 "signature int f(const char *)"),
69 llvm::cl::init("printf"), llvm::cl::cat(getLLVMBackendCat()));
70
71/// Inserts code to generate logs or traces into the generated LLVM IR to make
72/// debugging easier.
73class DebugInstrumentation {
74public:
75 explicit DebugInstrumentation(LLVMIRGen &irgen) : irgen_{irgen} {
76 // Bail if there is nothing to be instrumented.
77 if (llvmIrInstrumentation.empty()) {
78 return;
79 }
80
81 formatInstrArgD_ = irgen_.emitStringConst(
82 irgen_.getBuilder(), "Instruction number %u ,stored value %d\n");
83 formatInstrArgP_ = irgen_.emitStringConst(
84 irgen_.getBuilder(), "Instruction number %u ,stored value %p\n");
85 formatFuncInArg_ =
86 irgen_.emitStringConst(irgen_.getBuilder(), "Function called %s\n");
87 formatFuncOutArg_ =
88 irgen_.emitStringConst(irgen_.getBuilder(), "Function exited %s\n");
89
90 // Parse input llvm-code-instrumentation option and convert it to
91 // InstrumentationMetaInformation vector.
92 for (auto &section : llvmIrInstrumentation) {
93 llvm::SmallVector<llvm::StringRef, 4> elements;
94 llvm::StringRef(section).split(elements, ":");
95 InstrumentationMetaInformation funcToInstrument{
96 llvm::Regex(elements[0]), (elements[1] == "body" ? BODY : CALL),
97 nullptr, nullptr};
98
99 if (funcToInstrument.style == CALL) {
100 if (elements.size() >= 3) {
101 funcToInstrument.callBefore =
102 irgen_.getModule().getFunction(elements[3]);
103 CHECK(funcToInstrument.callBefore)
104 << "Cannot find " << elements[3].data() << " function";
105 }
106 if (elements.size() >= 4) {
107 funcToInstrument.callAfter =
108 irgen_.getModule().getFunction(elements[3]);
109 CHECK(funcToInstrument.callAfter)
110 << "Cannot find " << elements[3].data() << " function";
111 }
112 }
113 funcsToInstrument_.emplace_back(std::move(funcToInstrument));
114 }
115 }
116
117 void run() {
118 // Bail if there is nothing to be instrumented.
119 if (llvmIrInstrumentation.empty()) {
120 return;
121 }
122
123 auto *printfF =
124 irgen_.getModule().getFunction(llvmIrInstrPrintoutFuncName.getValue());
125 CHECK(printfF) << "Cannot find " << llvmIrInstrPrintoutFuncName.getValue()
126 << " function";
127
128 int64_t traceCounter = 0;
129 // Iterating over all functions in the module.
130 for (auto &F : irgen_.getModule().functions()) {
131 bool instrumentFunctionBody = false;
132 // Checking if function's body is requested to be instrumented.
133 for (auto &funcToInstrument : funcsToInstrument_) {
134 if (!funcToInstrument.funcReg.match(F.getName()) ||
135 funcToInstrument.style != BODY) {
136 continue;
137 }
138 instrumentFunctionBody = true;
139 }
140
141 // Getting down to LLVM IR instruction to insert
142 // instrumentation traces.
143 for (auto &BB : F) {
144 for (auto &I : BB) {
145 // Skipping instruction that doesn't change memory.
146 if (I.getOpcode() == llvm::Instruction::Alloca ||
147 I.getOpcode() == llvm::Instruction::Ret ||
148 I.getOpcode() == llvm::Instruction::Unreachable ||
149 I.getOpcode() == llvm::Instruction::Br) {
150 continue;
151 }
152 // If function body matched to be instrumented above
153 // then we iterated over its body adding traces otherwise
154 // checking if current instuction is a call and matching
155 // on of the function calls to be instrumented.
156 if (instrumentFunctionBody && !isa<llvm::CallInst>(&I)) {
157 llvm::IRBuilder<> builder(&I);
158 if (isa<llvm::StoreInst>(&I)) {
159 builder.SetInsertPoint(&BB, ++builder.GetInsertPoint());
160 auto *traceCounterValue =
161 builder.getInt64(static_cast<int64_t>(traceCounter++));
162 builder.CreateCall(
163 printfF->getFunctionType(), printfF,
164 {formatInstrArgP_, traceCounterValue,
165 llvm::cast<llvm::StoreInst>(&I)->getPointerOperand()});
166 } else {
167 builder.SetInsertPoint(&BB, ++builder.GetInsertPoint());
168 auto *traceCounterValue =
169 builder.getInt64(static_cast<int64_t>(traceCounter++));
170 builder.CreateCall(printfF->getFunctionType(), printfF,
171 {formatInstrArgD_, traceCounterValue,
172 llvm::cast<llvm::Value>(&I)});
173 }
174 } else if (auto *CI = llvm::dyn_cast<llvm::CallInst>(&I)) {
175 // If current LLVM IR instruction is not a call or the
176 // instruction/call name doesn't match requested set of function
177 // calls to be instrumented, skipping instrumentation, otherwise
178 // wrap function call in traces.
179 auto funcToInstrument = std::find_if(
180 funcsToInstrument_.begin(), funcsToInstrument_.end(),
181 [&](auto &fi) {
182 if (CI->getCalledFunction() == nullptr ||
183 !fi.funcReg.match(CI->getCalledFunction()->getName()) ||
184 fi.style != CALL) {
185 return false;
186 }
187 return true;
188 });
189
190 // If function is in the list to be instumented and
191 // custom functions before (and after specified) use them.
192 if (funcToInstrument != funcsToInstrument_.end() &&
193 funcToInstrument->callBefore) {
194 llvm::IRBuilder<> builder(CI);
195
196 // Args to be used for calling the specialized function.
197 llvm::SmallVector<llvm::Value *, 16> argsForInstr;
198 for (auto &arg : CI->arg_operands()) {
199 argsForInstr.push_back(arg);
200 }
201
202 builder.CreateCall(
203 funcToInstrument->callBefore->getFunctionType(),
204 funcToInstrument->callBefore, argsForInstr);
205 if (funcToInstrument->callAfter) {
206 builder.SetInsertPoint(&BB, ++builder.GetInsertPoint());
207 builder.CreateCall(
208 funcToInstrument->callAfter->getFunctionType(),
209 funcToInstrument->callAfter, argsForInstr);
210 }
211 // Otherwise check if function body instrumentation is going
212 // or default wrappers for function requested, wrap the
213 // function.
214 } else if (instrumentFunctionBody ||
215 funcToInstrument != funcsToInstrument_.end()) {
216 instrumentFuntionCall(CI, printfF);
217 }
218 }
219 }
220 }
221 }
222
223 DEBUG_GLOW(llvm::outs() << "LLVM module after instrumentation:\n");
224 DEBUG_GLOW(irgen_.getModule().print(llvm::outs(), nullptr));
225 }
226
227private:
228 // Prints function input parameter values.
229 void instrumentFuntionCall(llvm::CallInst *CI, llvm::Function *printfF) {
230 if (CI->getCalledFunction() == nullptr ||
231 (CI->getCalledFunction()->getName() == printfF->getName())) {
232 return;
233 }
234
235 llvm::IRBuilder<> builder(CI);
236
237 auto *functionName = irgen_.emitStringConst(
238 irgen_.getBuilder(), CI->getCalledFunction()->getName());
239 builder.CreateCall(printfF->getFunctionType(), printfF,
240 {formatFuncInArg_, functionName});
241
242 // Iterating over all function args. First agr is function output
243 // if function signature is not void.
244#if LLVM_VERSION_MAJOR >= 8
245 for (auto &op : CI->args()) {
246#else
247 for (auto &op : CI->arg_operands()) {
248#endif
249 llvm::Value *argFormat = nullptr;
250 auto type = op.get()->getType();
251
252 // Printing interger values with %d symbol.
253 if (type->isIntegerTy() ||
254 (type->isPointerTy() && dyn_cast<llvm::PointerType>(type)
255 ->getElementType()
256 ->isIntegerTy())) {
257 auto *value = op.get();
258 // If arg is a pointer to integer value get value and print it.
259 if (type->isPointerTy()) {
260 value = builder.CreateLoad(op.get());
261 }
262
263 argFormat = irgen_.emitStringConst(irgen_.getBuilder(), "\targ: %d\n");
264 builder.CreateCall(printfF->getFunctionType(), printfF,
265 {argFormat, value});
266 continue;
267 }
268
269 // Processing pointers to structure values.
270 if (type->isPointerTy()) {
271 auto *structType = dyn_cast<llvm::StructType>(
272 dyn_cast<llvm::PointerType>(type)->getElementType());
273 if (structType) {
274 std::string printStructFuncName = "pretty_print_";
275 llvm::StringRef structName;
276 // Structure types usually start either from struct. or class.
277 // stripping it from a name.
278 if (structType->getName().startswith("struct.")) {
279 structName = structType->getName().slice(
280 std::string("struct.").length(), structType->getName().size());
281 } else if (structType->getName().startswith("class.")) {
282 structName = structType->getName().slice(
283 std::string("class.").length(), structType->getName().size());
284 }
285 printStructFuncName += structName;
286 // Checking if module has print_<Struct\Class name> function to
287 // print arg. If not then just jumpring to default printout - ...
288 if (auto *printStruct =
289 irgen_.getModule().getFunction(printStructFuncName)) {
290 builder.CreateCall(printStruct->getFunctionType(), printStruct,
291 {op.get()});
292 continue;
293 }
294 }
295 }
296
297 argFormat = irgen_.emitStringConst(irgen_.getBuilder(), "\targ: ...\n");
298 builder.CreateCall(printfF->getFunctionType(), printfF, {argFormat});
299 }
300
301 builder.SetInsertPoint(CI->getParent(), ++builder.GetInsertPoint());
302 builder.CreateCall(printfF->getFunctionType(), printfF,
303 {formatFuncOutArg_, functionName});
304 }
305
306 // Parsed metadata about instrumentation types.
307 std::vector<InstrumentationMetaInformation> funcsToInstrument_;
308
309 /// LLVMIRGen to be used.
310 LLVMIRGen &irgen_;
311
312 // Format string for simple line instumentation.
313 llvm::Value *formatInstrArgD_ = nullptr;
314 // Format string for simple line instumentation.
315 llvm::Value *formatInstrArgP_ = nullptr;
316 // Format string for trace before function call.
317 llvm::Value *formatFuncInArg_ = nullptr;
318 // Format string for simple after function call.
319 llvm::Value *formatFuncOutArg_ = nullptr;
320};
321
322} // namespace
323
324void LLVMIRGen::performDebugInstrumentation() {
325 DebugInstrumentation debugInstrumentation(*this);
326 debugInstrumentation.run();
327}
328