//===-- IRDynamicChecks.h ---------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef liblldb_IRDynamicChecks_h_
#define liblldb_IRDynamicChecks_h_

#include "lldb/lldb-types.h"
#include "llvm/Pass.h"

namespace llvm {
    class BasicBlock;
    class CallInst;
    class Constant;
    class Function;
    class Instruction;
    class Module;
    class DataLayout;
    class Value;
}

namespace lldb_private
{

class ClangExpressionDeclMap;
class ExecutionContext;
class Stream;

//----------------------------------------------------------------------
/// @class DynamicCheckerFunctions IRDynamicChecks.h "lldb/Expression/IRDynamicChecks.h"
/// @brief Encapsulates dynamic check functions used by expressions.
///
/// Each of the utility functions encapsulated in this class is responsible
/// for validating some data that an expression is about to use.  Examples are:
///
/// a = *b;     // check that b is a valid pointer
/// [b init];   // check that b is a valid object to send "init" to
///
/// The class installs each checker function into the target process and
/// makes it available to IRDynamicChecks to use.
//----------------------------------------------------------------------
class DynamicCheckerFunctions
{
public:
    //------------------------------------------------------------------
    /// Constructor
    //------------------------------------------------------------------
    DynamicCheckerFunctions ();
    
    //------------------------------------------------------------------
    /// Destructor
    //------------------------------------------------------------------
    ~DynamicCheckerFunctions ();
    
    //------------------------------------------------------------------
    /// Install the utility functions into a process.  This binds the
    /// instance of DynamicCheckerFunctions to that process.
    ///
    /// @param[in] error_stream
    ///     A stream to print errors on.
    ///
    /// @param[in] exe_ctx
    ///     The execution context to install the functions into.
    ///
    /// @return
    ///     True on success; false on failure, or if the functions have
    ///     already been installed.
    //------------------------------------------------------------------
    bool Install (Stream &error_stream,
                  ExecutionContext &exe_ctx);
    
    bool DoCheckersExplainStop (lldb::addr_t addr, Stream &message);
    
    std::unique_ptr<UtilityFunction> m_valid_pointer_check;
    std::unique_ptr<UtilityFunction> m_objc_object_check;
};

//----------------------------------------------------------------------
/// @class IRDynamicChecks IRDynamicChecks.h "lldb/Expression/IRDynamicChecks.h"
/// @brief Adds dynamic checks to a user-entered expression to reduce its likelihood of crashing
///
/// When an IR function is executed in the target process, it may cause
/// crashes or hangs by dereferencing NULL pointers, trying to call Objective-C
/// methods on objects that do not respond to them, and so forth.
///
/// IRDynamicChecks adds calls to the functions in DynamicCheckerFunctions
/// to appropriate locations in an expression's IR.
//----------------------------------------------------------------------
class IRDynamicChecks : public llvm::ModulePass
{
public:
    //------------------------------------------------------------------
    /// Constructor
    ///
    /// @param[in] checker_functions
    ///     The checker functions for the target process.
    ///
    /// @param[in] func_name
    ///     The name of the function to prepare for execution in the target.
    ///
    /// @param[in] decl_map
    ///     The mapping used to look up entities in the target process. In
    ///     this case, used to find objc_msgSend
    //------------------------------------------------------------------
    IRDynamicChecks (DynamicCheckerFunctions &checker_functions,
                     const char* func_name = "$__lldb_expr");
    
    //------------------------------------------------------------------
    /// Destructor
    //------------------------------------------------------------------
    ~IRDynamicChecks() override;
    
    //------------------------------------------------------------------
    /// Run this IR transformer on a single module
    ///
    /// @param[in] M
    ///     The module to run on.  This module is searched for the function
    ///     $__lldb_expr, and that function is passed to the passes one by 
    ///     one.
    ///
    /// @return
    ///     True on success; false otherwise
    //------------------------------------------------------------------
    bool runOnModule(llvm::Module &M) override;
    
    //------------------------------------------------------------------
    /// Interface stub
    //------------------------------------------------------------------
    void assignPassManager(llvm::PMStack &PMS,
                           llvm::PassManagerType T = llvm::PMT_ModulePassManager)  override;
    
    //------------------------------------------------------------------
    /// Returns PMT_ModulePassManager
    //------------------------------------------------------------------
    llvm::PassManagerType getPotentialPassManagerType() const override;

private:
    //------------------------------------------------------------------
    /// A basic block-level pass to find all pointer dereferences and
    /// validate them before use.
    //------------------------------------------------------------------
    
    //------------------------------------------------------------------
    /// The top-level pass implementation
    ///
    /// @param[in] M
    ///     The module currently being processed.
    ///
    /// @param[in] BB
    ///     The basic block currently being processed.
    ///
    /// @return
    ///     True on success; false otherwise
    //------------------------------------------------------------------
    bool FindDataLoads(llvm::Module &M, 
                       llvm::BasicBlock &BB);
    
    std::string                 m_func_name;            ///< The name of the function to add checks to
    DynamicCheckerFunctions    &m_checker_functions;    ///< The checker functions for the process
};
    
} // namespace lldb_private

#endif // liblldb_IRDynamicChecks_h_
