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