diff --git a/lldb/include/lldb/Expression/IRDynamicChecks.h b/lldb/include/lldb/Expression/IRDynamicChecks.h new file mode 100644 index 000000000000..bb875ae8f5a3 --- /dev/null +++ b/lldb/include/lldb/Expression/IRDynamicChecks.h @@ -0,0 +1,141 @@ +//===-- 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 "llvm/Pass.h" + +namespace llvm { + class BasicBlock; + class CallInst; + class Constant; + class Function; + class Instruction; + class Module; + class TargetData; + class Value; +} + +namespace lldb_private +{ + +class ClangExpressionDeclMap; +class ClangUtilityFunction; +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); + + std::auto_ptr m_valid_pointer_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. + //------------------------------------------------------------------ + IRDynamicChecks(DynamicCheckerFunctions &checker_functions, + const char* func_name = "___clang_expr"); + + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ + ~IRDynamicChecks(); + + //------------------------------------------------------------------ + /// Run this IR transformer on a single module + /// + /// @param[in] M + /// The module to run on. This module is searched for the function + /// ___clang_expr, and that function is passed to the passes one by + /// one. + /// + /// @return + /// True on success; false otherwise + //------------------------------------------------------------------ + bool runOnModule(llvm::Module &M); + + //------------------------------------------------------------------ + /// Interface stub + //------------------------------------------------------------------ + void assignPassManager(llvm::PMStack &PMS, + llvm::PassManagerType T = llvm::PMT_ModulePassManager); + + //------------------------------------------------------------------ + /// Returns PMT_ModulePassManager + //------------------------------------------------------------------ + llvm::PassManagerType getPotentialPassManagerType() const; +private: + std::string m_func_name; ///< The name of the function to add checks to + DynamicCheckerFunctions &m_checker_functions; ///< The checker functions for the process +}; + +} + +#endif diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index 9664e94bb8de..d8e86370ae84 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -26,6 +26,7 @@ #include "lldb/Core/PluginInterface.h" #include "lldb/Breakpoint/BreakpointSiteList.h" #include "lldb/Expression/ClangPersistentVariables.h" +#include "lldb/Expression/IRDynamicChecks.h" #include "lldb/Target/ExecutionContextScope.h" #include "lldb/Target/ObjCObjectPrinter.h" #include "lldb/Target/ThreadList.h" @@ -1353,6 +1354,16 @@ public: bool IsRunning () const; + + DynamicCheckerFunctions *GetDynamicCheckers() + { + return m_dynamic_checkers.get(); + } + + void SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers) + { + m_dynamic_checkers.reset(dynamic_checkers); + } //------------------------------------------------------------------ // lldb::ExecutionContextScope pure virtual functions @@ -1405,6 +1416,7 @@ protected: BreakpointSiteList m_breakpoint_site_list; ///< This is the list of breakpoint locations we intend ///< to insert in the target. ClangPersistentVariables m_persistent_vars; ///< These are the persistent variables associated with this process for the expression parser. + std::auto_ptr m_dynamic_checkers; ///< The functions used by the expression parser to validate data that expressions use. UnixSignals m_unix_signals; /// This is the current signal set for this process. ConstString m_target_triple; lldb::ABISP m_abi_sp; diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 29a29924de34..267a01f2ca69 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -341,6 +341,8 @@ 49A8A3A011D568A300AD3B68 /* ASTResultSynthesizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49A8A39F11D568A300AD3B68 /* ASTResultSynthesizer.cpp */; }; 49A8A3A411D568BF00AD3B68 /* ASTResultSynthesizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 49A8A3A311D568BF00AD3B68 /* ASTResultSynthesizer.h */; }; 49BB309611F79450001A4197 /* TaggedASTType.h in Headers */ = {isa = PBXBuildFile; fileRef = 49BB309511F79450001A4197 /* TaggedASTType.h */; }; + 49CF982A122C70BD007A0B96 /* IRDynamicChecks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49CF9829122C70BD007A0B96 /* IRDynamicChecks.cpp */; }; + 49CF9834122C718B007A0B96 /* IRDynamicChecks.h in Headers */ = {isa = PBXBuildFile; fileRef = 49CF9833122C718B007A0B96 /* IRDynamicChecks.h */; }; 49D4FE831210B5FB00CDB854 /* ClangPersistentVariables.h in Headers */ = {isa = PBXBuildFile; fileRef = 49D4FE821210B5FB00CDB854 /* ClangPersistentVariables.h */; }; 49D4FE891210B61C00CDB854 /* ClangPersistentVariables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49D4FE871210B61C00CDB854 /* ClangPersistentVariables.cpp */; }; 49D7072711B5AD03001AD875 /* ClangASTSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 49D7072611B5AD03001AD875 /* ClangASTSource.h */; }; @@ -933,6 +935,8 @@ 49BB309511F79450001A4197 /* TaggedASTType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TaggedASTType.h; path = include/lldb/Symbol/TaggedASTType.h; sourceTree = ""; }; 49BF48DC11ADF356008863BD /* ObjCObjectPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ObjCObjectPrinter.cpp; path = source/Target/ObjCObjectPrinter.cpp; sourceTree = ""; }; 49BF48E011ADF37D008863BD /* ObjCObjectPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ObjCObjectPrinter.h; path = include/lldb/Target/ObjCObjectPrinter.h; sourceTree = ""; }; + 49CF9829122C70BD007A0B96 /* IRDynamicChecks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IRDynamicChecks.cpp; path = source/Expression/IRDynamicChecks.cpp; sourceTree = ""; }; + 49CF9833122C718B007A0B96 /* IRDynamicChecks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IRDynamicChecks.h; path = include/lldb/Expression/IRDynamicChecks.h; sourceTree = ""; }; 49D4FE821210B5FB00CDB854 /* ClangPersistentVariables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangPersistentVariables.h; path = include/lldb/Expression/ClangPersistentVariables.h; sourceTree = ""; }; 49D4FE871210B61C00CDB854 /* ClangPersistentVariables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangPersistentVariables.cpp; path = source/Expression/ClangPersistentVariables.cpp; sourceTree = ""; }; 49D7072611B5AD03001AD875 /* ClangASTSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangASTSource.h; path = include/lldb/Expression/ClangASTSource.h; sourceTree = ""; }; @@ -1882,6 +1886,8 @@ 49A8A39F11D568A300AD3B68 /* ASTResultSynthesizer.cpp */, 4911934B1226383D00578B7F /* ASTStructExtractor.h */, 491193501226386000578B7F /* ASTStructExtractor.cpp */, + 49CF9833122C718B007A0B96 /* IRDynamicChecks.h */, + 49CF9829122C70BD007A0B96 /* IRDynamicChecks.cpp */, 49307AB111DEA4F20081F992 /* IRForTarget.h */, 49307AAD11DEA4D90081F992 /* IRForTarget.cpp */, 49DA743411DE6BB2006AEF7E /* IRToDWARF.h */, @@ -2254,6 +2260,7 @@ 49445E351225AB6A00C11A81 /* ClangUserExpression.h in Headers */, 4911934C1226383D00578B7F /* ASTStructExtractor.h in Headers */, 497C86C2122823F300B54702 /* ClangUtilityFunction.h in Headers */, + 49CF9834122C718B007A0B96 /* IRDynamicChecks.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2308,7 +2315,6 @@ isa = PBXProject; buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "lldb" */; compatibilityVersion = "Xcode 3.1"; - developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( en, @@ -2713,6 +2719,7 @@ 49445C2612245E3600C11A81 /* ClangExpressionParser.cpp in Sources */, 491193521226386000578B7F /* ASTStructExtractor.cpp in Sources */, 497C86BE122823D800B54702 /* ClangUtilityFunction.cpp in Sources */, + 49CF982A122C70BD007A0B96 /* IRDynamicChecks.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index b29c0c7777d6..9026b743a0ee 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -190,6 +190,27 @@ bool CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream &output_stream, Stream &error_stream, CommandReturnObject *result) { + if (!m_exe_ctx.process) + { + error_stream.Printf ("Execution context doesn't contain a process"); + return false; + } + + if (!m_exe_ctx.process->GetDynamicCheckers()) + { + DynamicCheckerFunctions *dynamic_checkers = new DynamicCheckerFunctions(); + + StreamString install_errors; + + if (!dynamic_checkers->Install(install_errors, m_exe_ctx)) + { + error_stream.Printf("Couldn't install dynamic checkers into the execution context: %s", install_errors.GetData()); + return false; + } + + m_exe_ctx.process->SetDynamicCheckers(dynamic_checkers); + } + ClangUserExpression user_expression (expr); if (!user_expression.Parse (error_stream, m_exe_ctx)) diff --git a/lldb/source/Expression/ClangExpressionParser.cpp b/lldb/source/Expression/ClangExpressionParser.cpp index 7c4cc6a0d523..1bc8866975ba 100644 --- a/lldb/source/Expression/ClangExpressionParser.cpp +++ b/lldb/source/Expression/ClangExpressionParser.cpp @@ -13,8 +13,10 @@ #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/Disassembler.h" #include "lldb/Core/Stream.h" +#include "lldb/Core/StreamString.h" #include "lldb/Expression/ClangASTSource.h" #include "lldb/Expression/ClangExpression.h" +#include "lldb/Expression/IRDynamicChecks.h" #include "lldb/Expression/IRForTarget.h" #include "lldb/Expression/IRToDWARF.h" #include "lldb/Expression/RecordingMemoryManager.h" @@ -409,6 +411,15 @@ ClangExpressionParser::MakeJIT (lldb::addr_t &func_addr, err.SetErrorString("Couldn't convert the expression to DWARF"); return err; } + + IRDynamicChecks ir_dynamic_checks(*exe_ctx.process->GetDynamicCheckers(), m_expr.FunctionName()); + + if (!ir_dynamic_checks.runOnModule(*module)) + { + err.SetErrorToGenericError(); + err.SetErrorString("Couldn't add dynamic checks to the expression"); + return err; + } } m_jit_mm = new RecordingMemoryManager(); diff --git a/lldb/source/Expression/ClangUtilityFunction.cpp b/lldb/source/Expression/ClangUtilityFunction.cpp index 3acd3f283fa6..17ba7dba3311 100644 --- a/lldb/source/Expression/ClangUtilityFunction.cpp +++ b/lldb/source/Expression/ClangUtilityFunction.cpp @@ -37,7 +37,9 @@ using namespace lldb_private; ClangUtilityFunction::ClangUtilityFunction (const char *text, const char *name) : m_function_text(text), - m_function_name(name) + m_function_name(name), + m_jit_begin(LLDB_INVALID_ADDRESS), + m_jit_end(LLDB_INVALID_ADDRESS) { } @@ -56,7 +58,13 @@ ClangUtilityFunction::ClangUtilityFunction (const char *text, bool ClangUtilityFunction::Install (Stream &error_stream, ExecutionContext &exe_ctx) -{ +{ + if (m_jit_begin != LLDB_INVALID_ADDRESS) + { + error_stream.PutCString("error: already installed\n"); + return false; + } + //////////////////////////////////// // Set up the target and compiler // diff --git a/lldb/source/Expression/IRDynamicChecks.cpp b/lldb/source/Expression/IRDynamicChecks.cpp new file mode 100644 index 000000000000..21fd7d26250f --- /dev/null +++ b/lldb/source/Expression/IRDynamicChecks.cpp @@ -0,0 +1,117 @@ +//===-- IRDynamicChecks.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Expression/IRDynamicChecks.h" +#include "lldb/Expression/ClangUtilityFunction.h" + +#include "lldb/Core/Log.h" + +#include "llvm/Support/raw_ostream.h" +#include "llvm/Function.h" +#include "llvm/Module.h" +#include "llvm/Value.h" + +using namespace llvm; +using namespace lldb_private; + +static char ID; + +static const char valid_pointer_check_text[] = + "extern \"C\" void " + "___clang_valid_pointer_check (unsigned char *ptr)" + "{" + "unsigned char val = *ptr;" + "}"; + +static const char valid_pointer_check_name[] = + "___clang_valid_pointer_check"; + +DynamicCheckerFunctions::DynamicCheckerFunctions () +{ + m_valid_pointer_check.reset(new ClangUtilityFunction(valid_pointer_check_text, + valid_pointer_check_name)); +} + +DynamicCheckerFunctions::~DynamicCheckerFunctions () +{ +} + +bool +DynamicCheckerFunctions::Install(Stream &error_stream, + ExecutionContext &exe_ctx) +{ + if (!m_valid_pointer_check->Install(error_stream, exe_ctx)) + return false; + + return true; +} + +IRDynamicChecks::IRDynamicChecks(DynamicCheckerFunctions &checker_functions, + const char *func_name) : + ModulePass(&ID), + m_checker_functions(checker_functions), + m_func_name(func_name) +{ +} + +/* A handy utility function used at several places in the code */ + +static std::string +PrintValue(llvm::Value *V, bool truncate = false) +{ + std::string s; + raw_string_ostream rso(s); + V->print(rso); + rso.flush(); + if (truncate) + s.resize(s.length() - 1); + return s; +} + +IRDynamicChecks::~IRDynamicChecks() +{ +} + +bool +IRDynamicChecks::runOnModule(llvm::Module &M) +{ + lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); + + llvm::Function* function = M.getFunction(StringRef(m_func_name.c_str())); + + if (!function) + { + if (log) + log->Printf("Couldn't find %s() in the module", m_func_name.c_str()); + + return false; + } + + llvm::Function::iterator bbi; + + for (bbi = function->begin(); + bbi != function->end(); + ++bbi) + { + } + + return true; +} + +void +IRDynamicChecks::assignPassManager(PMStack &PMS, + PassManagerType T) +{ +} + +PassManagerType +IRDynamicChecks::getPotentialPassManagerType() const +{ + return PMT_ModulePassManager; +}