LLDB mainline
IRDynamicChecks.cpp
Go to the documentation of this file.
1//===-- IRDynamicChecks.cpp -----------------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/IR/Constants.h"
10#include "llvm/IR/DataLayout.h"
11#include "llvm/IR/Function.h"
12#include "llvm/IR/Instructions.h"
13#include "llvm/IR/Module.h"
14#include "llvm/IR/Value.h"
15#include "llvm/Support/raw_ostream.h"
16
17#include "IRDynamicChecks.h"
18
21#include "lldb/Target/Process.h"
23#include "lldb/Target/Target.h"
26#include "lldb/Utility/Log.h"
27
29
30using namespace llvm;
31using namespace lldb_private;
32
33static char ID;
34
35#define VALID_POINTER_CHECK_NAME "_$__lldb_valid_pointer_check"
36#define VALID_OBJC_OBJECT_CHECK_NAME "$__lldb_objc_object_check"
37
38static const char g_valid_pointer_check_text[] =
39 "extern \"C\" void\n"
40 "_$__lldb_valid_pointer_check (unsigned char *$__lldb_arg_ptr)\n"
41 "{\n"
42 " unsigned char $__lldb_local_val = *$__lldb_arg_ptr;\n"
43 "}";
44
46 : DynamicCheckerFunctions(DCF_Clang) {}
47
49
51 DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) {
52 auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction(
54 lldb::eLanguageTypeC, exe_ctx);
55 if (!utility_fn_or_error) {
56 llvm::consumeError(utility_fn_or_error.takeError());
57 return false;
58 }
59 m_valid_pointer_check = std::move(*utility_fn_or_error);
60
61 if (Process *process = exe_ctx.GetProcessPtr()) {
62 ObjCLanguageRuntime *objc_language_runtime =
64
65 if (objc_language_runtime) {
66 auto utility_fn_or_error = objc_language_runtime->CreateObjectChecker(
68 if (!utility_fn_or_error) {
69 llvm::consumeError(utility_fn_or_error.takeError());
70 return false;
71 }
72 m_objc_object_check = std::move(*utility_fn_or_error);
73 }
74 }
75
76 return true;
77}
78
80 Stream &message) {
81 // FIXME: We have to get the checkers to know why they scotched the call in
82 // more detail,
83 // so we can print a better message here.
84 if (m_valid_pointer_check && m_valid_pointer_check->ContainsAddress(addr)) {
85 message.Printf("Attempted to dereference an invalid pointer.");
86 return true;
87 } else if (m_objc_object_check &&
88 m_objc_object_check->ContainsAddress(addr)) {
89 message.Printf("Attempted to dereference an invalid ObjC Object or send it "
90 "an unrecognized selector");
91 return true;
92 }
93 return false;
94}
95
96static std::string PrintValue(llvm::Value *V, bool truncate = false) {
97 std::string s;
98 raw_string_ostream rso(s);
99 V->print(rso);
100 rso.flush();
101 if (truncate)
102 s.resize(s.length() - 1);
103 return s;
104}
105
106/// \class Instrumenter IRDynamicChecks.cpp
107/// Finds and instruments individual LLVM IR instructions
108///
109/// When instrumenting LLVM IR, it is frequently desirable to first search for
110/// instructions, and then later modify them. This way iterators remain
111/// intact, and multiple passes can look at the same code base without
112/// treading on each other's toes.
113///
114/// The Instrumenter class implements this functionality. A client first
115/// calls Inspect on a function, which populates a list of instructions to be
116/// instrumented. Then, later, when all passes' Inspect functions have been
117/// called, the client calls Instrument, which adds the desired
118/// instrumentation.
119///
120/// A subclass of Instrumenter must override InstrumentInstruction, which
121/// is responsible for adding whatever instrumentation is necessary.
122///
123/// A subclass of Instrumenter may override:
124///
125/// - InspectInstruction [default: does nothing]
126///
127/// - InspectBasicBlock [default: iterates through the instructions in a
128/// basic block calling InspectInstruction]
129///
130/// - InspectFunction [default: iterates through the basic blocks in a
131/// function calling InspectBasicBlock]
133public:
134 /// Constructor
135 ///
136 /// \param[in] module
137 /// The module being instrumented.
138 Instrumenter(llvm::Module &module,
139 std::shared_ptr<UtilityFunction> checker_function)
140 : m_module(module), m_checker_function(checker_function) {}
141
142 virtual ~Instrumenter() = default;
143
144 /// Inspect a function to find instructions to instrument
145 ///
146 /// \param[in] function
147 /// The function to inspect.
148 ///
149 /// \return
150 /// True on success; false on error.
151 bool Inspect(llvm::Function &function) { return InspectFunction(function); }
152
153 /// Instrument all the instructions found by Inspect()
154 ///
155 /// \return
156 /// True on success; false on error.
157 bool Instrument() {
158 for (InstIterator ii = m_to_instrument.begin(),
159 last_ii = m_to_instrument.end();
160 ii != last_ii; ++ii) {
161 if (!InstrumentInstruction(*ii))
162 return false;
163 }
164
165 return true;
166 }
167
168protected:
169 /// Add instrumentation to a single instruction
170 ///
171 /// \param[in] inst
172 /// The instruction to be instrumented.
173 ///
174 /// \return
175 /// True on success; false otherwise.
176 virtual bool InstrumentInstruction(llvm::Instruction *inst) = 0;
177
178 /// Register a single instruction to be instrumented
179 ///
180 /// \param[in] inst
181 /// The instruction to be instrumented.
182 void RegisterInstruction(llvm::Instruction &inst) {
183 m_to_instrument.push_back(&inst);
184 }
185
186 /// Determine whether a single instruction is interesting to instrument,
187 /// and, if so, call RegisterInstruction
188 ///
189 /// \param[in] i
190 /// The instruction to be inspected.
191 ///
192 /// \return
193 /// False if there was an error scanning; true otherwise.
194 virtual bool InspectInstruction(llvm::Instruction &i) { return true; }
195
196 /// Scan a basic block to see if any instructions are interesting
197 ///
198 /// \param[in] bb
199 /// The basic block to be inspected.
200 ///
201 /// \return
202 /// False if there was an error scanning; true otherwise.
203 virtual bool InspectBasicBlock(llvm::BasicBlock &bb) {
204 for (llvm::BasicBlock::iterator ii = bb.begin(), last_ii = bb.end();
205 ii != last_ii; ++ii) {
206 if (!InspectInstruction(*ii))
207 return false;
208 }
209
210 return true;
211 }
212
213 /// Scan a function to see if any instructions are interesting
214 ///
215 /// \param[in] f
216 /// The function to be inspected.
217 ///
218 /// \return
219 /// False if there was an error scanning; true otherwise.
220 virtual bool InspectFunction(llvm::Function &f) {
221 for (llvm::Function::iterator bbi = f.begin(), last_bbi = f.end();
222 bbi != last_bbi; ++bbi) {
223 if (!InspectBasicBlock(*bbi))
224 return false;
225 }
226
227 return true;
228 }
229
230 /// Build a function pointer for a function with signature void
231 /// (*)(uint8_t*) with a given address
232 ///
233 /// \param[in] start_address
234 /// The address of the function.
235 ///
236 /// \return
237 /// The function pointer, for use in a CallInst.
238 llvm::FunctionCallee BuildPointerValidatorFunc(lldb::addr_t start_address) {
239 llvm::Type *param_array[1];
240
241 param_array[0] = const_cast<llvm::PointerType *>(GetI8PtrTy());
242
243 ArrayRef<llvm::Type *> params(param_array, 1);
244
245 FunctionType *fun_ty = FunctionType::get(
246 llvm::Type::getVoidTy(m_module.getContext()), params, true);
247 PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty);
248 Constant *fun_addr_int =
249 ConstantInt::get(GetIntptrTy(), start_address, false);
250 return {fun_ty, ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty)};
251 }
252
253 /// Build a function pointer for a function with signature void
254 /// (*)(uint8_t*, uint8_t*) with a given address
255 ///
256 /// \param[in] start_address
257 /// The address of the function.
258 ///
259 /// \return
260 /// The function pointer, for use in a CallInst.
261 llvm::FunctionCallee BuildObjectCheckerFunc(lldb::addr_t start_address) {
262 llvm::Type *param_array[2];
263
264 param_array[0] = const_cast<llvm::PointerType *>(GetI8PtrTy());
265 param_array[1] = const_cast<llvm::PointerType *>(GetI8PtrTy());
266
267 ArrayRef<llvm::Type *> params(param_array, 2);
268
269 FunctionType *fun_ty = FunctionType::get(
270 llvm::Type::getVoidTy(m_module.getContext()), params, true);
271 PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty);
272 Constant *fun_addr_int =
273 ConstantInt::get(GetIntptrTy(), start_address, false);
274 return {fun_ty, ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty)};
275 }
276
277 PointerType *GetI8PtrTy() {
278 if (!m_i8ptr_ty)
279 m_i8ptr_ty = llvm::Type::getInt8PtrTy(m_module.getContext());
280
281 return m_i8ptr_ty;
282 }
283
284 IntegerType *GetIntptrTy() {
285 if (!m_intptr_ty) {
286 llvm::DataLayout data_layout(&m_module);
287
288 m_intptr_ty = llvm::Type::getIntNTy(m_module.getContext(),
289 data_layout.getPointerSizeInBits());
290 }
291
292 return m_intptr_ty;
293 }
294
295 typedef std::vector<llvm::Instruction *> InstVector;
296 typedef InstVector::iterator InstIterator;
297
298 InstVector m_to_instrument; ///< List of instructions the inspector found
299 llvm::Module &m_module; ///< The module which is being instrumented
300 std::shared_ptr<UtilityFunction>
301 m_checker_function; ///< The dynamic checker function for the process
302
303private:
304 PointerType *m_i8ptr_ty = nullptr;
305 IntegerType *m_intptr_ty = nullptr;
306};
307
309public:
310 ValidPointerChecker(llvm::Module &module,
311 std::shared_ptr<UtilityFunction> checker_function)
312 : Instrumenter(module, checker_function),
313 m_valid_pointer_check_func(nullptr) {}
314
315 ~ValidPointerChecker() override = default;
316
317protected:
318 bool InstrumentInstruction(llvm::Instruction *inst) override {
319 Log *log = GetLog(LLDBLog::Expressions);
320
321 LLDB_LOGF(log, "Instrumenting load/store instruction: %s\n",
322 PrintValue(inst).c_str());
323
324 if (!m_valid_pointer_check_func)
325 m_valid_pointer_check_func =
326 BuildPointerValidatorFunc(m_checker_function->StartAddress());
327
328 llvm::Value *dereferenced_ptr = nullptr;
329
330 if (llvm::LoadInst *li = dyn_cast<llvm::LoadInst>(inst))
331 dereferenced_ptr = li->getPointerOperand();
332 else if (llvm::StoreInst *si = dyn_cast<llvm::StoreInst>(inst))
333 dereferenced_ptr = si->getPointerOperand();
334 else
335 return false;
336
337 // Insert an instruction to call the helper with the result
338 CallInst::Create(m_valid_pointer_check_func, dereferenced_ptr, "", inst);
339
340 return true;
341 }
342
343 bool InspectInstruction(llvm::Instruction &i) override {
344 if (isa<llvm::LoadInst>(&i) || isa<llvm::StoreInst>(&i))
345 RegisterInstruction(i);
346
347 return true;
348 }
349
350private:
351 llvm::FunctionCallee m_valid_pointer_check_func;
352};
353
355public:
356 ObjcObjectChecker(llvm::Module &module,
357 std::shared_ptr<UtilityFunction> checker_function)
358 : Instrumenter(module, checker_function),
359 m_objc_object_check_func(nullptr) {}
360
361 ~ObjcObjectChecker() override = default;
362
364 eMsgSend = 0,
368 eMsgSend_stret
369 };
370
371 std::map<llvm::Instruction *, msgSend_type> msgSend_types;
372
373protected:
374 bool InstrumentInstruction(llvm::Instruction *inst) override {
375 CallInst *call_inst = dyn_cast<CallInst>(inst);
376
377 if (!call_inst)
378 return false; // call_inst really shouldn't be nullptr, because otherwise
379 // InspectInstruction wouldn't have registered it
380
381 if (!m_objc_object_check_func)
382 m_objc_object_check_func =
383 BuildObjectCheckerFunc(m_checker_function->StartAddress());
384
385 // id objc_msgSend(id theReceiver, SEL theSelector, ...)
386
387 llvm::Value *target_object;
388 llvm::Value *selector;
389
390 switch (msgSend_types[inst]) {
391 case eMsgSend:
392 case eMsgSend_fpret:
393 // On arm64, clang uses objc_msgSend for scalar and struct return
394 // calls. The call instruction will record which was used.
395 if (call_inst->hasStructRetAttr()) {
396 target_object = call_inst->getArgOperand(1);
397 selector = call_inst->getArgOperand(2);
398 } else {
399 target_object = call_inst->getArgOperand(0);
400 selector = call_inst->getArgOperand(1);
401 }
402 break;
403 case eMsgSend_stret:
404 target_object = call_inst->getArgOperand(1);
405 selector = call_inst->getArgOperand(2);
406 break;
407 case eMsgSendSuper:
408 case eMsgSendSuper_stret:
409 return true;
410 }
411
412 // These objects should always be valid according to Sean Calannan
413 assert(target_object);
414 assert(selector);
415
416 // Insert an instruction to call the helper with the result
417
418 llvm::Value *arg_array[2];
419
420 arg_array[0] = target_object;
421 arg_array[1] = selector;
422
423 ArrayRef<llvm::Value *> args(arg_array, 2);
424
425 CallInst::Create(m_objc_object_check_func, args, "", inst);
426
427 return true;
428 }
429
430 static llvm::Function *GetFunction(llvm::Value *value) {
431 if (llvm::Function *function = llvm::dyn_cast<llvm::Function>(value)) {
432 return function;
433 }
434
435 if (llvm::ConstantExpr *const_expr =
436 llvm::dyn_cast<llvm::ConstantExpr>(value)) {
437 switch (const_expr->getOpcode()) {
438 default:
439 return nullptr;
440 case llvm::Instruction::BitCast:
441 return GetFunction(const_expr->getOperand(0));
442 }
443 }
444
445 return nullptr;
446 }
447
448 static llvm::Function *GetCalledFunction(llvm::CallInst *inst) {
449 return GetFunction(inst->getCalledOperand());
450 }
451
452 bool InspectInstruction(llvm::Instruction &i) override {
453 Log *log = GetLog(LLDBLog::Expressions);
454
455 CallInst *call_inst = dyn_cast<CallInst>(&i);
456
457 if (call_inst) {
458 const llvm::Function *called_function = GetCalledFunction(call_inst);
459
460 if (!called_function)
461 return true;
462
463 std::string name_str = called_function->getName().str();
464 const char *name_cstr = name_str.c_str();
465
466 LLDB_LOGF(log, "Found call to %s: %s\n", name_cstr,
467 PrintValue(call_inst).c_str());
468
469 if (name_str.find("objc_msgSend") == std::string::npos)
470 return true;
471
472 if (!strcmp(name_cstr, "objc_msgSend")) {
473 RegisterInstruction(i);
474 msgSend_types[&i] = eMsgSend;
475 return true;
476 }
477
478 if (!strcmp(name_cstr, "objc_msgSend_stret")) {
479 RegisterInstruction(i);
480 msgSend_types[&i] = eMsgSend_stret;
481 return true;
482 }
483
484 if (!strcmp(name_cstr, "objc_msgSend_fpret")) {
485 RegisterInstruction(i);
486 msgSend_types[&i] = eMsgSend_fpret;
487 return true;
488 }
489
490 if (!strcmp(name_cstr, "objc_msgSendSuper")) {
491 RegisterInstruction(i);
492 msgSend_types[&i] = eMsgSendSuper;
493 return true;
494 }
495
496 if (!strcmp(name_cstr, "objc_msgSendSuper_stret")) {
497 RegisterInstruction(i);
498 msgSend_types[&i] = eMsgSendSuper_stret;
499 return true;
500 }
501
502 LLDB_LOGF(log,
503 "Function name '%s' contains 'objc_msgSend' but is not handled",
504 name_str.c_str());
505
506 return true;
507 }
508
509 return true;
510 }
511
512private:
513 llvm::FunctionCallee m_objc_object_check_func;
514};
515
517 ClangDynamicCheckerFunctions &checker_functions, const char *func_name)
518 : ModulePass(ID), m_func_name(func_name),
519 m_checker_functions(checker_functions) {}
520
522
523bool IRDynamicChecks::runOnModule(llvm::Module &M) {
525
526 llvm::Function *function = M.getFunction(StringRef(m_func_name));
527
528 if (!function) {
529 LLDB_LOGF(log, "Couldn't find %s() in the module", m_func_name.c_str());
530
531 return false;
532 }
533
536
537 if (!vpc.Inspect(*function))
538 return false;
539
540 if (!vpc.Instrument())
541 return false;
542 }
543
546
547 if (!ooc.Inspect(*function))
548 return false;
549
550 if (!ooc.Instrument())
551 return false;
552 }
553
554 if (log && log->GetVerbose()) {
555 std::string s;
556 raw_string_ostream oss(s);
557
558 M.print(oss, nullptr);
559
560 oss.flush();
561
562 LLDB_LOGF(log, "Module after dynamic checks: \n%s", s.c_str());
563 }
564
565 return true;
566}
567
568void IRDynamicChecks::assignPassManager(PMStack &PMS, PassManagerType T) {}
569
571 return PMT_ModulePassManager;
572}
#define VALID_OBJC_OBJECT_CHECK_NAME
static char ID
static const char g_valid_pointer_check_text[]
#define VALID_POINTER_CHECK_NAME
static std::string PrintValue(const Value *value, bool truncate=false)
#define LLDB_LOGF(log,...)
Definition: Log.h:344
Finds and instruments individual LLVM IR instructions.
llvm::Module & m_module
The module which is being instrumented.
virtual bool InspectInstruction(llvm::Instruction &i)
Determine whether a single instruction is interesting to instrument, and, if so, call RegisterInstruc...
IntegerType * GetIntptrTy()
virtual bool InstrumentInstruction(llvm::Instruction *inst)=0
Add instrumentation to a single instruction.
std::shared_ptr< UtilityFunction > m_checker_function
The dynamic checker function for the process.
Instrumenter(llvm::Module &module, std::shared_ptr< UtilityFunction > checker_function)
Constructor.
InstVector m_to_instrument
List of instructions the inspector found.
llvm::FunctionCallee BuildPointerValidatorFunc(lldb::addr_t start_address)
Build a function pointer for a function with signature void (*)(uint8_t*) with a given address.
PointerType * GetI8PtrTy()
bool Inspect(llvm::Function &function)
Inspect a function to find instructions to instrument.
virtual ~Instrumenter()=default
std::vector< llvm::Instruction * > InstVector
bool Instrument()
Instrument all the instructions found by Inspect()
virtual bool InspectBasicBlock(llvm::BasicBlock &bb)
Scan a basic block to see if any instructions are interesting.
virtual bool InspectFunction(llvm::Function &f)
Scan a function to see if any instructions are interesting.
void RegisterInstruction(llvm::Instruction &inst)
Register a single instruction to be instrumented.
llvm::FunctionCallee BuildObjectCheckerFunc(lldb::addr_t start_address)
Build a function pointer for a function with signature void (*)(uint8_t*, uint8_t*) with a given addr...
InstVector::iterator InstIterator
std::map< llvm::Instruction *, msgSend_type > msgSend_types
bool InspectInstruction(llvm::Instruction &i) override
Determine whether a single instruction is interesting to instrument, and, if so, call RegisterInstruc...
static llvm::Function * GetCalledFunction(llvm::CallInst *inst)
~ObjcObjectChecker() override=default
llvm::FunctionCallee m_objc_object_check_func
bool InstrumentInstruction(llvm::Instruction *inst) override
Add instrumentation to a single instruction.
static llvm::Function * GetFunction(llvm::Value *value)
ObjcObjectChecker(llvm::Module &module, std::shared_ptr< UtilityFunction > checker_function)
bool InstrumentInstruction(llvm::Instruction *inst) override
Add instrumentation to a single instruction.
ValidPointerChecker(llvm::Module &module, std::shared_ptr< UtilityFunction > checker_function)
llvm::FunctionCallee m_valid_pointer_check_func
bool InspectInstruction(llvm::Instruction &i) override
Determine whether a single instruction is interesting to instrument, and, if so, call RegisterInstruc...
~ValidPointerChecker() override=default
bool DoCheckersExplainStop(lldb::addr_t addr, Stream &message) override
std::shared_ptr< UtilityFunction > m_objc_object_check
bool Install(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) override
Install the utility functions into a process.
std::shared_ptr< UtilityFunction > m_valid_pointer_check
~ClangDynamicCheckerFunctions() override
Destructor.
Encapsulates dynamic check functions used by expressions.
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
Target & GetTargetRef() const
Returns a reference to the target object.
Process * GetProcessPtr() const
Returns a pointer to the process object.
~IRDynamicChecks() override
Destructor.
ClangDynamicCheckerFunctions & m_checker_functions
The checker functions for the process.
bool runOnModule(llvm::Module &M) override
Run this IR transformer on a single module.
std::string m_func_name
The name of the function to add checks to.
IRDynamicChecks(ClangDynamicCheckerFunctions &checker_functions, const char *func_name="$__lldb_expr")
Constructor.
llvm::PassManagerType getPotentialPassManagerType() const override
Returns PMT_ModulePassManager.
void assignPassManager(llvm::PMStack &PMS, llvm::PassManagerType T=llvm::PMT_ModulePassManager) override
Interface stub.
bool GetVerbose() const
Definition: Log.cpp:301
static ObjCLanguageRuntime * Get(Process &process)
virtual llvm::Expected< std::unique_ptr< UtilityFunction > > CreateObjectChecker(std::string name, ExecutionContext &exe_ctx)=0
A plug-in interface definition class for debugging a process.
Definition: Process.h:343
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:107
llvm::Expected< std::unique_ptr< UtilityFunction > > CreateUtilityFunction(std::string expression, std::string name, lldb::LanguageType language, ExecutionContext &exe_ctx)
Creates and installs a UtilityFunction for the given language.
Definition: Target.cpp:2477
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:309
@ eLanguageTypeC
Non-standardized C, such as K&R.
uint64_t addr_t
Definition: lldb-types.h:83
Definition: Debugger.h:52