brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.9 KiB · be17c54 Raw
475 lines · cpp
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-exception6//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 31using namespace llvm;32using namespace lldb_private;33 34static char ID;35 36#define VALID_OBJC_OBJECT_CHECK_NAME "$__lldb_objc_object_check"37 38ClangDynamicCheckerFunctions::ClangDynamicCheckerFunctions()39    : DynamicCheckerFunctions(DCF_Clang) {}40 41ClangDynamicCheckerFunctions::~ClangDynamicCheckerFunctions() = default;42 43llvm::Error44ClangDynamicCheckerFunctions::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 68bool ClangDynamicCheckerFunctions::DoCheckersExplainStop(lldb::addr_t addr,69                                                         Stream &message) {70  // FIXME: We have to get the checkers to know why they scotched the call in71  // 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 81static 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.cpp91/// Finds and instruments individual LLVM IR instructions92///93/// When instrumenting LLVM IR, it is frequently desirable to first search for94/// instructions, and then later modify them.  This way iterators remain95/// intact, and multiple passes can look at the same code base without96/// treading on each other's toes.97///98/// The Instrumenter class implements this functionality.  A client first99/// calls Inspect on a function, which populates a list of instructions to be100/// instrumented.  Then, later, when all passes' Inspect functions have been101/// called, the client calls Instrument, which adds the desired102/// instrumentation.103///104/// A subclass of Instrumenter must override InstrumentInstruction, which105/// 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 a112///   basic block calling InspectInstruction]113///114/// - InspectFunction [default: iterates through the basic blocks in a115///   function calling InspectBasicBlock]116class Instrumenter {117public:118  /// Constructor119  ///120  /// \param[in] module121  ///     The module being instrumented.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 instrument129  ///130  /// \param[in] function131  ///     The function to inspect.132  ///133  /// \return134  ///     True on success; false on error.135  bool Inspect(llvm::Function &function) { return InspectFunction(function); }136 137  /// Instrument all the instructions found by Inspect()138  ///139  /// \return140  ///     True on success; false on error.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 152protected:153  /// Add instrumentation to a single instruction154  ///155  /// \param[in] inst156  ///     The instruction to be instrumented.157  ///158  /// \return159  ///     True on success; false otherwise.160  virtual bool InstrumentInstruction(llvm::Instruction *inst) = 0;161 162  /// Register a single instruction to be instrumented163  ///164  /// \param[in] inst165  ///     The instruction to be instrumented.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 RegisterInstruction172  ///173  /// \param[in] i174  ///     The instruction to be inspected.175  ///176  /// \return177  ///     False if there was an error scanning; true otherwise.178  virtual bool InspectInstruction(llvm::Instruction &i) { return true; }179 180  /// Scan a basic block to see if any instructions are interesting181  ///182  /// \param[in] bb183  ///     The basic block to be inspected.184  ///185  /// \return186  ///     False if there was an error scanning; true otherwise.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 interesting198  ///199  /// \param[in] f200  ///     The function to be inspected.201  ///202  /// \return203  ///     False if there was an error scanning; true otherwise.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 void215  /// (*)(uint8_t*, uint8_t*) with a given address216  ///217  /// \param[in] start_address218  ///     The address of the function.219  ///220  /// \return221  ///     The function pointer, for use in a CallInst.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 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 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 found259  llvm::Module &m_module;     ///< The module which is being instrumented260  std::shared_ptr<UtilityFunction>261      m_checker_function; ///< The dynamic checker function for the process262 263private:264  PointerType *m_i8ptr_ty = nullptr;265  IntegerType *m_intptr_ty = nullptr;266};267 268class ObjcObjectChecker : public Instrumenter {269public: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_stret283  };284 285  std::map<llvm::Instruction *, msgSend_type> msgSend_types;286 287protected: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 otherwise293                    // InspectInstruction wouldn't have registered it294 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 return308      // 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 Calannan327    assert(target_object);328    assert(selector);329 330    // Insert an instruction to call the helper with the result331 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 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 362  static llvm::Function *GetCalledFunction(llvm::CallInst *inst) {363    return GetFunction(inst->getCalledOperand());364  }365 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 426private:427  llvm::FunctionCallee m_objc_object_check_func;428};429 430IRDynamicChecks::IRDynamicChecks(431    ClangDynamicCheckerFunctions &checker_functions, const char *func_name)432    : ModulePass(ID), m_func_name(func_name),433      m_checker_functions(checker_functions) {}434 435IRDynamicChecks::~IRDynamicChecks() = default;436 437bool 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 470void IRDynamicChecks::assignPassManager(PMStack &PMS, PassManagerType T) {}471 472PassManagerType IRDynamicChecks::getPotentialPassManagerType() const {473  return PMT_ModulePassManager;474}475