Path: blob/main/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp
39648 views
//===-- IRDynamicChecks.cpp -----------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/IR/Constants.h"9#include "llvm/IR/DataLayout.h"10#include "llvm/IR/Function.h"11#include "llvm/IR/Instructions.h"12#include "llvm/IR/Module.h"13#include "llvm/IR/Value.h"14#include "llvm/Support/raw_ostream.h"1516#include "IRDynamicChecks.h"1718#include "lldb/Expression/UtilityFunction.h"19#include "lldb/Target/ExecutionContext.h"20#include "lldb/Target/Process.h"21#include "lldb/Target/StackFrame.h"22#include "lldb/Target/Target.h"23#include "lldb/Utility/ConstString.h"24#include "lldb/Utility/LLDBLog.h"25#include "lldb/Utility/Log.h"2627#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"2829using namespace llvm;30using namespace lldb_private;3132static char ID;3334#define VALID_POINTER_CHECK_NAME "_$__lldb_valid_pointer_check"35#define VALID_OBJC_OBJECT_CHECK_NAME "$__lldb_objc_object_check"3637static const char g_valid_pointer_check_text[] =38"extern \"C\" void\n"39"_$__lldb_valid_pointer_check (unsigned char *$__lldb_arg_ptr)\n"40"{\n"41" unsigned char $__lldb_local_val = *$__lldb_arg_ptr;\n"42"}";4344ClangDynamicCheckerFunctions::ClangDynamicCheckerFunctions()45: DynamicCheckerFunctions(DCF_Clang) {}4647ClangDynamicCheckerFunctions::~ClangDynamicCheckerFunctions() = default;4849llvm::Error ClangDynamicCheckerFunctions::Install(50DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) {51Expected<std::unique_ptr<UtilityFunction>> utility_fn =52exe_ctx.GetTargetRef().CreateUtilityFunction(53g_valid_pointer_check_text, VALID_POINTER_CHECK_NAME,54lldb::eLanguageTypeC, exe_ctx);55if (!utility_fn)56return utility_fn.takeError();57m_valid_pointer_check = std::move(*utility_fn);5859if (Process *process = exe_ctx.GetProcessPtr()) {60ObjCLanguageRuntime *objc_language_runtime =61ObjCLanguageRuntime::Get(*process);6263if (objc_language_runtime) {64Expected<std::unique_ptr<UtilityFunction>> checker_fn =65objc_language_runtime->CreateObjectChecker(VALID_OBJC_OBJECT_CHECK_NAME, exe_ctx);66if (!checker_fn)67return checker_fn.takeError();68m_objc_object_check = std::move(*checker_fn);69}70}7172return Error::success();73}7475bool ClangDynamicCheckerFunctions::DoCheckersExplainStop(lldb::addr_t addr,76Stream &message) {77// FIXME: We have to get the checkers to know why they scotched the call in78// more detail,79// so we can print a better message here.80if (m_valid_pointer_check && m_valid_pointer_check->ContainsAddress(addr)) {81message.Printf("Attempted to dereference an invalid pointer.");82return true;83} else if (m_objc_object_check &&84m_objc_object_check->ContainsAddress(addr)) {85message.Printf("Attempted to dereference an invalid ObjC Object or send it "86"an unrecognized selector");87return true;88}89return false;90}9192static std::string PrintValue(llvm::Value *V, bool truncate = false) {93std::string s;94raw_string_ostream rso(s);95V->print(rso);96rso.flush();97if (truncate)98s.resize(s.length() - 1);99return s;100}101102/// \class Instrumenter IRDynamicChecks.cpp103/// Finds and instruments individual LLVM IR instructions104///105/// When instrumenting LLVM IR, it is frequently desirable to first search for106/// instructions, and then later modify them. This way iterators remain107/// intact, and multiple passes can look at the same code base without108/// treading on each other's toes.109///110/// The Instrumenter class implements this functionality. A client first111/// calls Inspect on a function, which populates a list of instructions to be112/// instrumented. Then, later, when all passes' Inspect functions have been113/// called, the client calls Instrument, which adds the desired114/// instrumentation.115///116/// A subclass of Instrumenter must override InstrumentInstruction, which117/// is responsible for adding whatever instrumentation is necessary.118///119/// A subclass of Instrumenter may override:120///121/// - InspectInstruction [default: does nothing]122///123/// - InspectBasicBlock [default: iterates through the instructions in a124/// basic block calling InspectInstruction]125///126/// - InspectFunction [default: iterates through the basic blocks in a127/// function calling InspectBasicBlock]128class Instrumenter {129public:130/// Constructor131///132/// \param[in] module133/// The module being instrumented.134Instrumenter(llvm::Module &module,135std::shared_ptr<UtilityFunction> checker_function)136: m_module(module), m_checker_function(checker_function) {}137138virtual ~Instrumenter() = default;139140/// Inspect a function to find instructions to instrument141///142/// \param[in] function143/// The function to inspect.144///145/// \return146/// True on success; false on error.147bool Inspect(llvm::Function &function) { return InspectFunction(function); }148149/// Instrument all the instructions found by Inspect()150///151/// \return152/// True on success; false on error.153bool Instrument() {154for (InstIterator ii = m_to_instrument.begin(),155last_ii = m_to_instrument.end();156ii != last_ii; ++ii) {157if (!InstrumentInstruction(*ii))158return false;159}160161return true;162}163164protected:165/// Add instrumentation to a single instruction166///167/// \param[in] inst168/// The instruction to be instrumented.169///170/// \return171/// True on success; false otherwise.172virtual bool InstrumentInstruction(llvm::Instruction *inst) = 0;173174/// Register a single instruction to be instrumented175///176/// \param[in] inst177/// The instruction to be instrumented.178void RegisterInstruction(llvm::Instruction &inst) {179m_to_instrument.push_back(&inst);180}181182/// Determine whether a single instruction is interesting to instrument,183/// and, if so, call RegisterInstruction184///185/// \param[in] i186/// The instruction to be inspected.187///188/// \return189/// False if there was an error scanning; true otherwise.190virtual bool InspectInstruction(llvm::Instruction &i) { return true; }191192/// Scan a basic block to see if any instructions are interesting193///194/// \param[in] bb195/// The basic block to be inspected.196///197/// \return198/// False if there was an error scanning; true otherwise.199virtual bool InspectBasicBlock(llvm::BasicBlock &bb) {200for (llvm::BasicBlock::iterator ii = bb.begin(), last_ii = bb.end();201ii != last_ii; ++ii) {202if (!InspectInstruction(*ii))203return false;204}205206return true;207}208209/// Scan a function to see if any instructions are interesting210///211/// \param[in] f212/// The function to be inspected.213///214/// \return215/// False if there was an error scanning; true otherwise.216virtual bool InspectFunction(llvm::Function &f) {217for (llvm::Function::iterator bbi = f.begin(), last_bbi = f.end();218bbi != last_bbi; ++bbi) {219if (!InspectBasicBlock(*bbi))220return false;221}222223return true;224}225226/// Build a function pointer for a function with signature void227/// (*)(uint8_t*) with a given address228///229/// \param[in] start_address230/// The address of the function.231///232/// \return233/// The function pointer, for use in a CallInst.234llvm::FunctionCallee BuildPointerValidatorFunc(lldb::addr_t start_address) {235llvm::Type *param_array[1];236237param_array[0] = const_cast<llvm::PointerType *>(GetI8PtrTy());238239ArrayRef<llvm::Type *> params(param_array, 1);240241FunctionType *fun_ty = FunctionType::get(242llvm::Type::getVoidTy(m_module.getContext()), params, true);243PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty);244Constant *fun_addr_int =245ConstantInt::get(GetIntptrTy(), start_address, false);246return {fun_ty, ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty)};247}248249/// Build a function pointer for a function with signature void250/// (*)(uint8_t*, uint8_t*) with a given address251///252/// \param[in] start_address253/// The address of the function.254///255/// \return256/// The function pointer, for use in a CallInst.257llvm::FunctionCallee BuildObjectCheckerFunc(lldb::addr_t start_address) {258llvm::Type *param_array[2];259260param_array[0] = const_cast<llvm::PointerType *>(GetI8PtrTy());261param_array[1] = const_cast<llvm::PointerType *>(GetI8PtrTy());262263ArrayRef<llvm::Type *> params(param_array, 2);264265FunctionType *fun_ty = FunctionType::get(266llvm::Type::getVoidTy(m_module.getContext()), params, true);267PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty);268Constant *fun_addr_int =269ConstantInt::get(GetIntptrTy(), start_address, false);270return {fun_ty, ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty)};271}272273PointerType *GetI8PtrTy() {274if (!m_i8ptr_ty)275m_i8ptr_ty = llvm::PointerType::getUnqual(m_module.getContext());276277return m_i8ptr_ty;278}279280IntegerType *GetIntptrTy() {281if (!m_intptr_ty) {282llvm::DataLayout data_layout(&m_module);283284m_intptr_ty = llvm::Type::getIntNTy(m_module.getContext(),285data_layout.getPointerSizeInBits());286}287288return m_intptr_ty;289}290291typedef std::vector<llvm::Instruction *> InstVector;292typedef InstVector::iterator InstIterator;293294InstVector m_to_instrument; ///< List of instructions the inspector found295llvm::Module &m_module; ///< The module which is being instrumented296std::shared_ptr<UtilityFunction>297m_checker_function; ///< The dynamic checker function for the process298299private:300PointerType *m_i8ptr_ty = nullptr;301IntegerType *m_intptr_ty = nullptr;302};303304class ValidPointerChecker : public Instrumenter {305public:306ValidPointerChecker(llvm::Module &module,307std::shared_ptr<UtilityFunction> checker_function)308: Instrumenter(module, checker_function),309m_valid_pointer_check_func(nullptr) {}310311~ValidPointerChecker() override = default;312313protected:314bool InstrumentInstruction(llvm::Instruction *inst) override {315Log *log = GetLog(LLDBLog::Expressions);316317LLDB_LOGF(log, "Instrumenting load/store instruction: %s\n",318PrintValue(inst).c_str());319320if (!m_valid_pointer_check_func)321m_valid_pointer_check_func =322BuildPointerValidatorFunc(m_checker_function->StartAddress());323324llvm::Value *dereferenced_ptr = nullptr;325326if (llvm::LoadInst *li = dyn_cast<llvm::LoadInst>(inst))327dereferenced_ptr = li->getPointerOperand();328else if (llvm::StoreInst *si = dyn_cast<llvm::StoreInst>(inst))329dereferenced_ptr = si->getPointerOperand();330else331return false;332333// Insert an instruction to call the helper with the result334CallInst::Create(m_valid_pointer_check_func, dereferenced_ptr, "", inst);335336return true;337}338339bool InspectInstruction(llvm::Instruction &i) override {340if (isa<llvm::LoadInst>(&i) || isa<llvm::StoreInst>(&i))341RegisterInstruction(i);342343return true;344}345346private:347llvm::FunctionCallee m_valid_pointer_check_func;348};349350class ObjcObjectChecker : public Instrumenter {351public:352ObjcObjectChecker(llvm::Module &module,353std::shared_ptr<UtilityFunction> checker_function)354: Instrumenter(module, checker_function),355m_objc_object_check_func(nullptr) {}356357~ObjcObjectChecker() override = default;358359enum msgSend_type {360eMsgSend = 0,361eMsgSendSuper,362eMsgSendSuper_stret,363eMsgSend_fpret,364eMsgSend_stret365};366367std::map<llvm::Instruction *, msgSend_type> msgSend_types;368369protected:370bool InstrumentInstruction(llvm::Instruction *inst) override {371CallInst *call_inst = dyn_cast<CallInst>(inst);372373if (!call_inst)374return false; // call_inst really shouldn't be nullptr, because otherwise375// InspectInstruction wouldn't have registered it376377if (!m_objc_object_check_func)378m_objc_object_check_func =379BuildObjectCheckerFunc(m_checker_function->StartAddress());380381// id objc_msgSend(id theReceiver, SEL theSelector, ...)382383llvm::Value *target_object;384llvm::Value *selector;385386switch (msgSend_types[inst]) {387case eMsgSend:388case eMsgSend_fpret:389// On arm64, clang uses objc_msgSend for scalar and struct return390// calls. The call instruction will record which was used.391if (call_inst->hasStructRetAttr()) {392target_object = call_inst->getArgOperand(1);393selector = call_inst->getArgOperand(2);394} else {395target_object = call_inst->getArgOperand(0);396selector = call_inst->getArgOperand(1);397}398break;399case eMsgSend_stret:400target_object = call_inst->getArgOperand(1);401selector = call_inst->getArgOperand(2);402break;403case eMsgSendSuper:404case eMsgSendSuper_stret:405return true;406}407408// These objects should always be valid according to Sean Calannan409assert(target_object);410assert(selector);411412// Insert an instruction to call the helper with the result413414llvm::Value *arg_array[2];415416arg_array[0] = target_object;417arg_array[1] = selector;418419ArrayRef<llvm::Value *> args(arg_array, 2);420421CallInst::Create(m_objc_object_check_func, args, "", inst);422423return true;424}425426static llvm::Function *GetFunction(llvm::Value *value) {427if (llvm::Function *function = llvm::dyn_cast<llvm::Function>(value)) {428return function;429}430431if (llvm::ConstantExpr *const_expr =432llvm::dyn_cast<llvm::ConstantExpr>(value)) {433switch (const_expr->getOpcode()) {434default:435return nullptr;436case llvm::Instruction::BitCast:437return GetFunction(const_expr->getOperand(0));438}439}440441return nullptr;442}443444static llvm::Function *GetCalledFunction(llvm::CallInst *inst) {445return GetFunction(inst->getCalledOperand());446}447448bool InspectInstruction(llvm::Instruction &i) override {449Log *log = GetLog(LLDBLog::Expressions);450451CallInst *call_inst = dyn_cast<CallInst>(&i);452453if (call_inst) {454const llvm::Function *called_function = GetCalledFunction(call_inst);455456if (!called_function)457return true;458459std::string name_str = called_function->getName().str();460const char *name_cstr = name_str.c_str();461462LLDB_LOGF(log, "Found call to %s: %s\n", name_cstr,463PrintValue(call_inst).c_str());464465if (name_str.find("objc_msgSend") == std::string::npos)466return true;467468if (!strcmp(name_cstr, "objc_msgSend")) {469RegisterInstruction(i);470msgSend_types[&i] = eMsgSend;471return true;472}473474if (!strcmp(name_cstr, "objc_msgSend_stret")) {475RegisterInstruction(i);476msgSend_types[&i] = eMsgSend_stret;477return true;478}479480if (!strcmp(name_cstr, "objc_msgSend_fpret")) {481RegisterInstruction(i);482msgSend_types[&i] = eMsgSend_fpret;483return true;484}485486if (!strcmp(name_cstr, "objc_msgSendSuper")) {487RegisterInstruction(i);488msgSend_types[&i] = eMsgSendSuper;489return true;490}491492if (!strcmp(name_cstr, "objc_msgSendSuper_stret")) {493RegisterInstruction(i);494msgSend_types[&i] = eMsgSendSuper_stret;495return true;496}497498LLDB_LOGF(log,499"Function name '%s' contains 'objc_msgSend' but is not handled",500name_str.c_str());501502return true;503}504505return true;506}507508private:509llvm::FunctionCallee m_objc_object_check_func;510};511512IRDynamicChecks::IRDynamicChecks(513ClangDynamicCheckerFunctions &checker_functions, const char *func_name)514: ModulePass(ID), m_func_name(func_name),515m_checker_functions(checker_functions) {}516517IRDynamicChecks::~IRDynamicChecks() = default;518519bool IRDynamicChecks::runOnModule(llvm::Module &M) {520Log *log = GetLog(LLDBLog::Expressions);521522llvm::Function *function = M.getFunction(StringRef(m_func_name));523524if (!function) {525LLDB_LOGF(log, "Couldn't find %s() in the module", m_func_name.c_str());526527return false;528}529530if (m_checker_functions.m_valid_pointer_check) {531ValidPointerChecker vpc(M, m_checker_functions.m_valid_pointer_check);532533if (!vpc.Inspect(*function))534return false;535536if (!vpc.Instrument())537return false;538}539540if (m_checker_functions.m_objc_object_check) {541ObjcObjectChecker ooc(M, m_checker_functions.m_objc_object_check);542543if (!ooc.Inspect(*function))544return false;545546if (!ooc.Instrument())547return false;548}549550if (log && log->GetVerbose()) {551std::string s;552raw_string_ostream oss(s);553554M.print(oss, nullptr);555556oss.flush();557558LLDB_LOGF(log, "Module after dynamic checks: \n%s", s.c_str());559}560561return true;562}563564void IRDynamicChecks::assignPassManager(PMStack &PMS, PassManagerType T) {}565566PassManagerType IRDynamicChecks::getPotentialPassManagerType() const {567return PMT_ModulePassManager;568}569570571