xref: /freebsd/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
19 #include "lldb/Expression/UtilityFunction.h"
20 #include "lldb/Target/ExecutionContext.h"
21 #include "lldb/Target/Language.h"
22 #include "lldb/Target/Process.h"
23 #include "lldb/Target/StackFrame.h"
24 #include "lldb/Target/Target.h"
25 #include "lldb/Utility/ConstString.h"
26 #include "lldb/Utility/LLDBLog.h"
27 #include "lldb/Utility/Log.h"
28 
29 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
30 
31 using namespace llvm;
32 using namespace lldb_private;
33 
34 static char ID;
35 
36 #define VALID_OBJC_OBJECT_CHECK_NAME "$__lldb_objc_object_check"
37 
ClangDynamicCheckerFunctions()38 ClangDynamicCheckerFunctions::ClangDynamicCheckerFunctions()
39     : DynamicCheckerFunctions(DCF_Clang) {}
40 
41 ClangDynamicCheckerFunctions::~ClangDynamicCheckerFunctions() = default;
42 
43 llvm::Error
Install(DiagnosticManager & diagnostic_manager,ExecutionContext & exe_ctx)44 ClangDynamicCheckerFunctions::Install(DiagnosticManager &diagnostic_manager,
45                                       ExecutionContext &exe_ctx) {
46   if (Process *process = exe_ctx.GetProcessPtr()) {
47     ObjCLanguageRuntime *objc_language_runtime =
48         ObjCLanguageRuntime::Get(*process);
49 
50     SourceLanguage lang = process->GetTarget().GetLanguage();
51     if (!lang)
52       if (auto *frame = exe_ctx.GetFramePtr())
53         lang = frame->GetLanguage();
54 
55     if (objc_language_runtime &&
56         Language::LanguageIsObjC(lang.AsLanguageType())) {
57       Expected<std::unique_ptr<UtilityFunction>> checker_fn =
58           objc_language_runtime->CreateObjectChecker(VALID_OBJC_OBJECT_CHECK_NAME, exe_ctx);
59       if (!checker_fn)
60         return checker_fn.takeError();
61       m_objc_object_check = std::move(*checker_fn);
62     }
63   }
64 
65   return Error::success();
66 }
67 
DoCheckersExplainStop(lldb::addr_t addr,Stream & message)68 bool ClangDynamicCheckerFunctions::DoCheckersExplainStop(lldb::addr_t addr,
69                                                          Stream &message) {
70   // FIXME: We have to get the checkers to know why they scotched the call in
71   // more detail,
72   // so we can print a better message here.
73   if (m_objc_object_check && m_objc_object_check->ContainsAddress(addr)) {
74     message.Printf("Attempted to dereference an invalid ObjC Object or send it "
75                    "an unrecognized selector");
76     return true;
77   }
78   return false;
79 }
80 
PrintValue(llvm::Value * V,bool truncate=false)81 static std::string PrintValue(llvm::Value *V, bool truncate = false) {
82   std::string s;
83   raw_string_ostream rso(s);
84   V->print(rso);
85   if (truncate)
86     s.resize(s.length() - 1);
87   return s;
88 }
89 
90 /// \class Instrumenter IRDynamicChecks.cpp
91 /// Finds and instruments individual LLVM IR instructions
92 ///
93 /// When instrumenting LLVM IR, it is frequently desirable to first search for
94 /// instructions, and then later modify them.  This way iterators remain
95 /// intact, and multiple passes can look at the same code base without
96 /// treading on each other's toes.
97 ///
98 /// The Instrumenter class implements this functionality.  A client first
99 /// calls Inspect on a function, which populates a list of instructions to be
100 /// instrumented.  Then, later, when all passes' Inspect functions have been
101 /// called, the client calls Instrument, which adds the desired
102 /// instrumentation.
103 ///
104 /// A subclass of Instrumenter must override InstrumentInstruction, which
105 /// is responsible for adding whatever instrumentation is necessary.
106 ///
107 /// A subclass of Instrumenter may override:
108 ///
109 /// - InspectInstruction [default: does nothing]
110 ///
111 /// - InspectBasicBlock [default: iterates through the instructions in a
112 ///   basic block calling InspectInstruction]
113 ///
114 /// - InspectFunction [default: iterates through the basic blocks in a
115 ///   function calling InspectBasicBlock]
116 class Instrumenter {
117 public:
118   /// Constructor
119   ///
120   /// \param[in] module
121   ///     The module being instrumented.
Instrumenter(llvm::Module & module,std::shared_ptr<UtilityFunction> checker_function)122   Instrumenter(llvm::Module &module,
123                std::shared_ptr<UtilityFunction> checker_function)
124       : m_module(module), m_checker_function(checker_function) {}
125 
126   virtual ~Instrumenter() = default;
127 
128   /// Inspect a function to find instructions to instrument
129   ///
130   /// \param[in] function
131   ///     The function to inspect.
132   ///
133   /// \return
134   ///     True on success; false on error.
Inspect(llvm::Function & function)135   bool Inspect(llvm::Function &function) { return InspectFunction(function); }
136 
137   /// Instrument all the instructions found by Inspect()
138   ///
139   /// \return
140   ///     True on success; false on error.
Instrument()141   bool Instrument() {
142     for (InstIterator ii = m_to_instrument.begin(),
143                       last_ii = m_to_instrument.end();
144          ii != last_ii; ++ii) {
145       if (!InstrumentInstruction(*ii))
146         return false;
147     }
148 
149     return true;
150   }
151 
152 protected:
153   /// Add instrumentation to a single instruction
154   ///
155   /// \param[in] inst
156   ///     The instruction to be instrumented.
157   ///
158   /// \return
159   ///     True on success; false otherwise.
160   virtual bool InstrumentInstruction(llvm::Instruction *inst) = 0;
161 
162   /// Register a single instruction to be instrumented
163   ///
164   /// \param[in] inst
165   ///     The instruction to be instrumented.
RegisterInstruction(llvm::Instruction & inst)166   void RegisterInstruction(llvm::Instruction &inst) {
167     m_to_instrument.push_back(&inst);
168   }
169 
170   /// Determine whether a single instruction is interesting to instrument,
171   /// and, if so, call RegisterInstruction
172   ///
173   /// \param[in] i
174   ///     The instruction to be inspected.
175   ///
176   /// \return
177   ///     False if there was an error scanning; true otherwise.
InspectInstruction(llvm::Instruction & i)178   virtual bool InspectInstruction(llvm::Instruction &i) { return true; }
179 
180   /// Scan a basic block to see if any instructions are interesting
181   ///
182   /// \param[in] bb
183   ///     The basic block to be inspected.
184   ///
185   /// \return
186   ///     False if there was an error scanning; true otherwise.
InspectBasicBlock(llvm::BasicBlock & bb)187   virtual bool InspectBasicBlock(llvm::BasicBlock &bb) {
188     for (llvm::BasicBlock::iterator ii = bb.begin(), last_ii = bb.end();
189          ii != last_ii; ++ii) {
190       if (!InspectInstruction(*ii))
191         return false;
192     }
193 
194     return true;
195   }
196 
197   /// Scan a function to see if any instructions are interesting
198   ///
199   /// \param[in] f
200   ///     The function to be inspected.
201   ///
202   /// \return
203   ///     False if there was an error scanning; true otherwise.
InspectFunction(llvm::Function & f)204   virtual bool InspectFunction(llvm::Function &f) {
205     for (llvm::Function::iterator bbi = f.begin(), last_bbi = f.end();
206          bbi != last_bbi; ++bbi) {
207       if (!InspectBasicBlock(*bbi))
208         return false;
209     }
210 
211     return true;
212   }
213 
214   /// Build a function pointer for a function with signature void
215   /// (*)(uint8_t*, uint8_t*) with a given address
216   ///
217   /// \param[in] start_address
218   ///     The address of the function.
219   ///
220   /// \return
221   ///     The function pointer, for use in a CallInst.
BuildObjectCheckerFunc(lldb::addr_t start_address)222   llvm::FunctionCallee BuildObjectCheckerFunc(lldb::addr_t start_address) {
223     llvm::Type *param_array[2];
224 
225     param_array[0] = const_cast<llvm::PointerType *>(GetI8PtrTy());
226     param_array[1] = const_cast<llvm::PointerType *>(GetI8PtrTy());
227 
228     ArrayRef<llvm::Type *> params(param_array, 2);
229 
230     FunctionType *fun_ty = FunctionType::get(
231         llvm::Type::getVoidTy(m_module.getContext()), params, true);
232     PointerType *fun_ptr_ty = PointerType::getUnqual(m_module.getContext());
233     Constant *fun_addr_int =
234         ConstantInt::get(GetIntptrTy(), start_address, false);
235     return {fun_ty, ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty)};
236   }
237 
GetI8PtrTy()238   PointerType *GetI8PtrTy() {
239     if (!m_i8ptr_ty)
240       m_i8ptr_ty = llvm::PointerType::getUnqual(m_module.getContext());
241 
242     return m_i8ptr_ty;
243   }
244 
GetIntptrTy()245   IntegerType *GetIntptrTy() {
246     if (!m_intptr_ty) {
247       m_intptr_ty = llvm::Type::getIntNTy(
248           m_module.getContext(),
249           m_module.getDataLayout().getPointerSizeInBits());
250     }
251 
252     return m_intptr_ty;
253   }
254 
255   typedef std::vector<llvm::Instruction *> InstVector;
256   typedef InstVector::iterator InstIterator;
257 
258   InstVector m_to_instrument; ///< List of instructions the inspector found
259   llvm::Module &m_module;     ///< The module which is being instrumented
260   std::shared_ptr<UtilityFunction>
261       m_checker_function; ///< The dynamic checker function for the process
262 
263 private:
264   PointerType *m_i8ptr_ty = nullptr;
265   IntegerType *m_intptr_ty = nullptr;
266 };
267 
268 class ObjcObjectChecker : public Instrumenter {
269 public:
ObjcObjectChecker(llvm::Module & module,std::shared_ptr<UtilityFunction> checker_function)270   ObjcObjectChecker(llvm::Module &module,
271                     std::shared_ptr<UtilityFunction> checker_function)
272       : Instrumenter(module, checker_function),
273         m_objc_object_check_func(nullptr) {}
274 
275   ~ObjcObjectChecker() override = default;
276 
277   enum msgSend_type {
278     eMsgSend = 0,
279     eMsgSendSuper,
280     eMsgSendSuper_stret,
281     eMsgSend_fpret,
282     eMsgSend_stret
283   };
284 
285   std::map<llvm::Instruction *, msgSend_type> msgSend_types;
286 
287 protected:
InstrumentInstruction(llvm::Instruction * inst)288   bool InstrumentInstruction(llvm::Instruction *inst) override {
289     CallInst *call_inst = dyn_cast<CallInst>(inst);
290 
291     if (!call_inst)
292       return false; // call_inst really shouldn't be nullptr, because otherwise
293                     // InspectInstruction wouldn't have registered it
294 
295     if (!m_objc_object_check_func)
296       m_objc_object_check_func =
297           BuildObjectCheckerFunc(m_checker_function->StartAddress());
298 
299     // id objc_msgSend(id theReceiver, SEL theSelector, ...)
300 
301     llvm::Value *target_object;
302     llvm::Value *selector;
303 
304     switch (msgSend_types[inst]) {
305     case eMsgSend:
306     case eMsgSend_fpret:
307       // On arm64, clang uses objc_msgSend for scalar and struct return
308       // calls.  The call instruction will record which was used.
309       if (call_inst->hasStructRetAttr()) {
310         target_object = call_inst->getArgOperand(1);
311         selector = call_inst->getArgOperand(2);
312       } else {
313         target_object = call_inst->getArgOperand(0);
314         selector = call_inst->getArgOperand(1);
315       }
316       break;
317     case eMsgSend_stret:
318       target_object = call_inst->getArgOperand(1);
319       selector = call_inst->getArgOperand(2);
320       break;
321     case eMsgSendSuper:
322     case eMsgSendSuper_stret:
323       return true;
324     }
325 
326     // These objects should always be valid according to Sean Calannan
327     assert(target_object);
328     assert(selector);
329 
330     // Insert an instruction to call the helper with the result
331 
332     llvm::Value *arg_array[2];
333 
334     arg_array[0] = target_object;
335     arg_array[1] = selector;
336 
337     ArrayRef<llvm::Value *> args(arg_array, 2);
338 
339     CallInst::Create(m_objc_object_check_func, args, "", inst->getIterator());
340 
341     return true;
342   }
343 
GetFunction(llvm::Value * value)344   static llvm::Function *GetFunction(llvm::Value *value) {
345     if (llvm::Function *function = llvm::dyn_cast<llvm::Function>(value)) {
346       return function;
347     }
348 
349     if (llvm::ConstantExpr *const_expr =
350             llvm::dyn_cast<llvm::ConstantExpr>(value)) {
351       switch (const_expr->getOpcode()) {
352       default:
353         return nullptr;
354       case llvm::Instruction::BitCast:
355         return GetFunction(const_expr->getOperand(0));
356       }
357     }
358 
359     return nullptr;
360   }
361 
GetCalledFunction(llvm::CallInst * inst)362   static llvm::Function *GetCalledFunction(llvm::CallInst *inst) {
363     return GetFunction(inst->getCalledOperand());
364   }
365 
InspectInstruction(llvm::Instruction & i)366   bool InspectInstruction(llvm::Instruction &i) override {
367     Log *log = GetLog(LLDBLog::Expressions);
368 
369     CallInst *call_inst = dyn_cast<CallInst>(&i);
370 
371     if (call_inst) {
372       const llvm::Function *called_function = GetCalledFunction(call_inst);
373 
374       if (!called_function)
375         return true;
376 
377       std::string name_str = called_function->getName().str();
378       const char *name_cstr = name_str.c_str();
379 
380       LLDB_LOGF(log, "Found call to %s: %s\n", name_cstr,
381                 PrintValue(call_inst).c_str());
382 
383       if (name_str.find("objc_msgSend") == std::string::npos)
384         return true;
385 
386       if (!strcmp(name_cstr, "objc_msgSend")) {
387         RegisterInstruction(i);
388         msgSend_types[&i] = eMsgSend;
389         return true;
390       }
391 
392       if (!strcmp(name_cstr, "objc_msgSend_stret")) {
393         RegisterInstruction(i);
394         msgSend_types[&i] = eMsgSend_stret;
395         return true;
396       }
397 
398       if (!strcmp(name_cstr, "objc_msgSend_fpret")) {
399         RegisterInstruction(i);
400         msgSend_types[&i] = eMsgSend_fpret;
401         return true;
402       }
403 
404       if (!strcmp(name_cstr, "objc_msgSendSuper")) {
405         RegisterInstruction(i);
406         msgSend_types[&i] = eMsgSendSuper;
407         return true;
408       }
409 
410       if (!strcmp(name_cstr, "objc_msgSendSuper_stret")) {
411         RegisterInstruction(i);
412         msgSend_types[&i] = eMsgSendSuper_stret;
413         return true;
414       }
415 
416       LLDB_LOGF(log,
417                 "Function name '%s' contains 'objc_msgSend' but is not handled",
418                 name_str.c_str());
419 
420       return true;
421     }
422 
423     return true;
424   }
425 
426 private:
427   llvm::FunctionCallee m_objc_object_check_func;
428 };
429 
IRDynamicChecks(ClangDynamicCheckerFunctions & checker_functions,const char * func_name)430 IRDynamicChecks::IRDynamicChecks(
431     ClangDynamicCheckerFunctions &checker_functions, const char *func_name)
432     : ModulePass(ID), m_func_name(func_name),
433       m_checker_functions(checker_functions) {}
434 
435 IRDynamicChecks::~IRDynamicChecks() = default;
436 
runOnModule(llvm::Module & M)437 bool IRDynamicChecks::runOnModule(llvm::Module &M) {
438   Log *log = GetLog(LLDBLog::Expressions);
439 
440   llvm::Function *function = M.getFunction(StringRef(m_func_name));
441 
442   if (!function) {
443     LLDB_LOGF(log, "Couldn't find %s() in the module", m_func_name.c_str());
444 
445     return false;
446   }
447 
448   if (m_checker_functions.m_objc_object_check) {
449     ObjcObjectChecker ooc(M, m_checker_functions.m_objc_object_check);
450 
451     if (!ooc.Inspect(*function))
452       return false;
453 
454     if (!ooc.Instrument())
455       return false;
456   }
457 
458   if (log && log->GetVerbose()) {
459     std::string s;
460     raw_string_ostream oss(s);
461 
462     M.print(oss, nullptr);
463 
464     LLDB_LOGF(log, "Module after dynamic checks: \n%s", s.c_str());
465   }
466 
467   return true;
468 }
469 
assignPassManager(PMStack & PMS,PassManagerType T)470 void IRDynamicChecks::assignPassManager(PMStack &PMS, PassManagerType T) {}
471 
getPotentialPassManagerType() const472 PassManagerType IRDynamicChecks::getPotentialPassManagerType() const {
473   return PMT_ModulePassManager;
474 }
475