From e71d553cd4e95b4cb8c9ffd2f7122a2ca735467c Mon Sep 17 00:00:00 2001 From: Sean Callanan Date: Fri, 27 Aug 2010 23:31:21 +0000 Subject: [PATCH] Added a ClangUtilityFunction class that allows the debugger to insert self-contained functions for use by expressions (mainly for error-checking). In order to support detecting whether a crash occurred in one of these helpers -- currently our preferred way of reporting that an error-check failed -- added a bit of support for getting the extent of a JITted function in addition to just its base. llvm-svn: 112324 --- .../include/lldb/Expression/ClangExpression.h | 7 + .../lldb/Expression/ClangExpressionParser.h | 10 +- .../lldb/Expression/ClangUserExpression.h | 5 + .../lldb/Expression/ClangUtilityFunction.h | 176 ++++++++++++++++++ .../lldb/Expression/RecordingMemoryManager.h | 4 +- lldb/lldb.xcodeproj/project.pbxproj | 12 +- .../Expression/ClangExpressionParser.cpp | 7 +- lldb/source/Expression/ClangFunction.cpp | 4 +- .../source/Expression/ClangUserExpression.cpp | 8 +- .../Expression/ClangUtilityFunction.cpp | 116 ++++++++++++ 10 files changed, 341 insertions(+), 8 deletions(-) create mode 100644 lldb/include/lldb/Expression/ClangUtilityFunction.h create mode 100644 lldb/source/Expression/ClangUtilityFunction.cpp diff --git a/lldb/include/lldb/Expression/ClangExpression.h b/lldb/include/lldb/Expression/ClangExpression.h index 176167889a0c..2a2640aac251 100644 --- a/lldb/include/lldb/Expression/ClangExpression.h +++ b/lldb/include/lldb/Expression/ClangExpression.h @@ -41,6 +41,13 @@ class RecordingMemoryManager; class ClangExpression { public: + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ + virtual ~ClangExpression () + { + } + //------------------------------------------------------------------ /// Return the string that the parser should parse. Must be a full /// translation unit. diff --git a/lldb/include/lldb/Expression/ClangExpressionParser.h b/lldb/include/lldb/Expression/ClangExpressionParser.h index 63bd4cd66aae..b9e8c4795945 100644 --- a/lldb/include/lldb/Expression/ClangExpressionParser.h +++ b/lldb/include/lldb/Expression/ClangExpressionParser.h @@ -93,7 +93,12 @@ public: /// @param[out] func_addr /// The address to which the function has been written. /// - /// @para[in] exe_ctx + /// @param[out] func_end + /// The end of the function's allocated memory region. (func_addr + /// and func_end do not delimit an allocated region; the allocated + /// region may begin before func_addr.) + /// + /// @param[in] exe_ctx /// The execution context to write the function into. /// /// @return @@ -101,7 +106,8 @@ public: /// Test with Success(). //------------------------------------------------------------------ Error - MakeJIT (lldb::addr_t &func_addr, + MakeJIT (lldb::addr_t &func_addr, + lldb::addr_t &func_end, ExecutionContext &exe_ctx); //------------------------------------------------------------------ diff --git a/lldb/include/lldb/Expression/ClangUserExpression.h b/lldb/include/lldb/Expression/ClangUserExpression.h index 9dfeb5f9a68d..0c4c11cb9483 100644 --- a/lldb/include/lldb/Expression/ClangUserExpression.h +++ b/lldb/include/lldb/Expression/ClangUserExpression.h @@ -47,6 +47,11 @@ public: //------------------------------------------------------------------ ClangUserExpression (const char *expr); + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ + virtual ~ClangUserExpression (); + //------------------------------------------------------------------ /// Parse the expression /// diff --git a/lldb/include/lldb/Expression/ClangUtilityFunction.h b/lldb/include/lldb/Expression/ClangUtilityFunction.h new file mode 100644 index 000000000000..33ed53d70801 --- /dev/null +++ b/lldb/include/lldb/Expression/ClangUtilityFunction.h @@ -0,0 +1,176 @@ +//===-- ClangUtilityFunction.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_ClangUtilityFunction_h_ +#define liblldb_ClangUtilityFunction_h_ + +// C Includes +// C++ Includes +#include +#include +#include +#include + +// Other libraries and framework includes +// Project includes + +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private.h" +#include "lldb/Core/ClangForward.h" +#include "lldb/Expression/ClangExpression.h" + +namespace lldb_private +{ + +//---------------------------------------------------------------------- +/// @class ClangUtilityFunction ClangUtilityFunction.h "lldb/Expression/ClangUtilityFunction.h" +/// @brief Encapsulates a single expression for use with Clang +/// +/// LLDB uses expressions for various purposes, notably to call functions +/// and as a backend for the expr command. ClangUtilityFunction encapsulates +/// a self-contained function meant to be used from other code. Utility +/// functions can perform error-checking for ClangUserExpressions, +//---------------------------------------------------------------------- +class ClangUtilityFunction : public ClangExpression +{ +public: + //------------------------------------------------------------------ + /// Constructor + /// + /// @param[in] text + /// The text of the function. Must be a full translation unit. + /// + /// @param[in] name + /// The name of the function, as used in the text. + //------------------------------------------------------------------ + ClangUtilityFunction (const char *text, + const char *name); + + //------------------------------------------------------------------ + /// Install the utility function into a process + /// + /// @param[in] error_stream + /// A stream to print parse errors and warnings to. + /// + /// @param[in] exe_ctx + /// The execution context to install the utility function to. + /// + /// @return + /// True on success (no errors); false otherwise. + //------------------------------------------------------------------ + bool + Install (Stream &error_stream, ExecutionContext &exe_ctx); + + //------------------------------------------------------------------ + /// Check whether the given PC is inside the function + /// + /// Especially useful if the function dereferences NULL to indicate a failed + /// assert. + /// + /// @param[in] pc + /// The program counter to check. + /// + /// @return + /// True if the program counter falls within the function's bounds; + /// false if not (or the function is not JIT compiled) + //------------------------------------------------------------------ + bool + ContainsAddress (lldb::addr_t address) + { + // nothing is both >= LLDB_INVALID_ADDRESS and < LLDB_INVALID_ADDRESS, + // so this always returns false if the function is not JIT compiled yet + return (address >= m_jit_begin && address < m_jit_end); + } + + //------------------------------------------------------------------ + /// Return the address of the function's JIT-compiled code, or + /// LLDB_INVALID_ADDRESS if the function is not JIT compiled + //------------------------------------------------------------------ + lldb::addr_t + StartAddress () + { + return m_jit_begin; + } + + //------------------------------------------------------------------ + /// Return the string that the parser should parse. Must be a full + /// translation unit. + //------------------------------------------------------------------ + const char * + Text () + { + return m_function_text.c_str(); + } + + //------------------------------------------------------------------ + /// Return the function name that should be used for executing the + /// expression. Text() should contain the definition of this + /// function. + //------------------------------------------------------------------ + const char * + FunctionName () + { + return m_function_name.c_str(); + } + + //------------------------------------------------------------------ + /// Return the object that the parser should use when resolving external + /// values. May be NULL if everything should be self-contained. + //------------------------------------------------------------------ + ClangExpressionDeclMap * + DeclMap () + { + return NULL; + } + + //------------------------------------------------------------------ + /// Return the object that the parser should use when registering + /// local variables. May be NULL if the Expression doesn't care. + //------------------------------------------------------------------ + ClangExpressionVariableStore * + LocalVariables () + { + return NULL; + } + + //------------------------------------------------------------------ + /// Return the object that the parser should allow to access ASTs. + /// May be NULL if the ASTs do not need to be transformed. + /// + /// @param[in] passthrough + /// The ASTConsumer that the returned transformer should send + /// the ASTs to after transformation. + //------------------------------------------------------------------ + clang::ASTConsumer * + ASTTransformer (clang::ASTConsumer *passthrough) + { + return NULL; + } + + //------------------------------------------------------------------ + /// Return the stream that the parser should use to write DWARF + /// opcodes. + //------------------------------------------------------------------ + StreamString & + DwarfOpcodeStream () + { + return *((StreamString*)NULL); + } + +private: + std::string m_function_text; ///< The text of the function. Must be a well-formed translation unit. + std::string m_function_name; ///< The name of the function. + + lldb::addr_t m_jit_begin; ///< The address of the JITted code. LLDB_INVALID_ADDRESS if invalid. + lldb::addr_t m_jit_end; ///< The end of the JITted code. LLDB_INVALID_ADDRESS if invalid. +}; + +} // namespace lldb_private + +#endif // liblldb_ClangUtilityFunction_h_ diff --git a/lldb/include/lldb/Expression/RecordingMemoryManager.h b/lldb/include/lldb/Expression/RecordingMemoryManager.h index 50756ee828af..f1194bf3bf5f 100644 --- a/lldb/include/lldb/Expression/RecordingMemoryManager.h +++ b/lldb/include/lldb/Expression/RecordingMemoryManager.h @@ -52,7 +52,9 @@ namespace lldb_private { //---------------------------------------------------------------------- class RecordingMemoryManager : public llvm::JITMemoryManager { -friend Error ClangExpressionParser::MakeJIT (uint64_t &, ExecutionContext &); +friend Error ClangExpressionParser::MakeJIT (uint64_t &, + uint64_t&, + ExecutionContext &); public: //------------------------------------------------------------------ diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index a52197d7c3cc..453b38fc1162 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -336,6 +336,8 @@ 49445C2612245E3600C11A81 /* ClangExpressionParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49445C2512245E3600C11A81 /* ClangExpressionParser.cpp */; }; 49445C2A12245E5500C11A81 /* ClangExpressionParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 49445C2912245E5500C11A81 /* ClangExpressionParser.h */; }; 49445E351225AB6A00C11A81 /* ClangUserExpression.h in Headers */ = {isa = PBXBuildFile; fileRef = 49445E341225AB6A00C11A81 /* ClangUserExpression.h */; }; + 497C86BE122823D800B54702 /* ClangUtilityFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 497C86BD122823D800B54702 /* ClangUtilityFunction.cpp */; }; + 497C86C2122823F300B54702 /* ClangUtilityFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 497C86C1122823F300B54702 /* ClangUtilityFunction.h */; }; 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 */; }; @@ -919,6 +921,8 @@ 495BBACF119A0DE700418BEA /* PathMappingList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PathMappingList.h; path = include/lldb/Target/PathMappingList.h; sourceTree = ""; }; 497650CE11A21BEE008DDB57 /* ABIMacOSX_i386.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ABIMacOSX_i386.cpp; path = "ABI/MacOSX-i386/ABIMacOSX_i386.cpp"; sourceTree = ""; }; 497650CF11A21BEE008DDB57 /* ABIMacOSX_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ABIMacOSX_i386.h; path = "ABI/MacOSX-i386/ABIMacOSX_i386.h"; sourceTree = ""; }; + 497C86BD122823D800B54702 /* ClangUtilityFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangUtilityFunction.cpp; path = source/Expression/ClangUtilityFunction.cpp; sourceTree = ""; }; + 497C86C1122823F300B54702 /* ClangUtilityFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangUtilityFunction.h; path = include/lldb/Expression/ClangUtilityFunction.h; sourceTree = ""; }; 497E7B331188ED300065CCA1 /* ABI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ABI.h; path = include/lldb/Target/ABI.h; sourceTree = ""; }; 497E7B9D1188F6690065CCA1 /* ABI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ABI.cpp; path = source/Target/ABI.cpp; sourceTree = ""; }; 499F381E11A5B3F300F5CE02 /* CommandObjectArgs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectArgs.h; path = source/Commands/CommandObjectArgs.h; sourceTree = ""; }; @@ -1854,8 +1858,6 @@ 49D7072611B5AD03001AD875 /* ClangASTSource.h */, 49D7072811B5AD11001AD875 /* ClangASTSource.cpp */, 26BC7DC010F1B79500F91463 /* ClangExpression.h */, - 49445E341225AB6A00C11A81 /* ClangUserExpression.h */, - 26BC7ED510F1B86700F91463 /* ClangUserExpression.cpp */, 4C98D3E0118FB98F00E575D0 /* ClangFunction.h */, 4C98D3DA118FB96F00E575D0 /* ClangFunction.cpp */, 49F1A74911B338AE003ED505 /* ClangExpressionDeclMap.h */, @@ -1866,6 +1868,10 @@ 26BC7ED610F1B86700F91463 /* ClangExpressionVariable.cpp */, 49D4FE821210B5FB00CDB854 /* ClangPersistentVariables.h */, 49D4FE871210B61C00CDB854 /* ClangPersistentVariables.cpp */, + 49445E341225AB6A00C11A81 /* ClangUserExpression.h */, + 26BC7ED510F1B86700F91463 /* ClangUserExpression.cpp */, + 497C86C1122823F300B54702 /* ClangUtilityFunction.h */, + 497C86BD122823D800B54702 /* ClangUtilityFunction.cpp */, 26BC7DC310F1B79500F91463 /* DWARFExpression.h */, 26BC7ED810F1B86700F91463 /* DWARFExpression.cpp */, 49A8A3A311D568BF00AD3B68 /* ASTResultSynthesizer.h */, @@ -2243,6 +2249,7 @@ 49445C2A12245E5500C11A81 /* ClangExpressionParser.h in Headers */, 49445E351225AB6A00C11A81 /* ClangUserExpression.h in Headers */, 4911934C1226383D00578B7F /* ASTStructExtractor.h in Headers */, + 497C86C2122823F300B54702 /* ClangUtilityFunction.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2700,6 +2707,7 @@ 49FB515E121481B000DF8983 /* DWARFExpression.cpp in Sources */, 49445C2612245E3600C11A81 /* ClangExpressionParser.cpp in Sources */, 491193521226386000578B7F /* ASTStructExtractor.cpp in Sources */, + 497C86BE122823D800B54702 /* ClangUtilityFunction.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/lldb/source/Expression/ClangExpressionParser.cpp b/lldb/source/Expression/ClangExpressionParser.cpp index 05c237afdb98..7c4cc6a0d523 100644 --- a/lldb/source/Expression/ClangExpressionParser.cpp +++ b/lldb/source/Expression/ClangExpressionParser.cpp @@ -369,7 +369,9 @@ ClangExpressionParser::MakeDWARF () } Error -ClangExpressionParser::MakeJIT (lldb::addr_t &func_addr, ExecutionContext &exe_ctx) +ClangExpressionParser::MakeJIT (lldb::addr_t &func_addr, + lldb::addr_t &func_end, + ExecutionContext &exe_ctx) { Error err; @@ -507,7 +509,10 @@ ClangExpressionParser::MakeJIT (lldb::addr_t &func_addr, ExecutionContext &exe_c (*pos).m_remote_addr = m_jit_mm->GetRemoteAddressForLocal ((*pos).m_local_addr); if (!(*pos).m_name.compare(m_expr.FunctionName())) + { + func_end = m_jit_mm->GetRemoteRangeForLocal ((*pos).m_local_addr).second; func_addr = (*pos).m_remote_addr; + } } err.Clear(); diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/ClangFunction.cpp index be107ca8eb07..3044d51ed695 100644 --- a/lldb/source/Expression/ClangFunction.cpp +++ b/lldb/source/Expression/ClangFunction.cpp @@ -227,7 +227,9 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors) if (m_JITted) return true; - Error jit_error = m_parser->MakeJIT(m_wrapper_function_addr, exe_ctx); + lldb::addr_t wrapper_function_end; + + Error jit_error = m_parser->MakeJIT(m_wrapper_function_addr, wrapper_function_end, exe_ctx); if (!jit_error.Success()) return false; diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp index afd94bbd6a89..d8841d3b3e8d 100644 --- a/lldb/source/Expression/ClangUserExpression.cpp +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -45,6 +45,10 @@ ClangUserExpression::ClangUserExpression (const char *expr) : m_transformed_text = m_transformed_stream.GetData(); } +ClangUserExpression::~ClangUserExpression () +{ +} + clang::ASTConsumer * ClangUserExpression::ASTTransformer (clang::ASTConsumer *passthrough) { @@ -123,7 +127,9 @@ ClangUserExpression::Parse (Stream &error_stream, ExecutionContext &exe_ctx) m_dwarf_opcodes.reset(); - Error jit_error = parser.MakeJIT (m_jit_addr, exe_ctx); + lldb::addr_t jit_end; + + Error jit_error = parser.MakeJIT (m_jit_addr, jit_end, exe_ctx); if (jit_error.Success()) { diff --git a/lldb/source/Expression/ClangUtilityFunction.cpp b/lldb/source/Expression/ClangUtilityFunction.cpp new file mode 100644 index 000000000000..3acd3f283fa6 --- /dev/null +++ b/lldb/source/Expression/ClangUtilityFunction.cpp @@ -0,0 +1,116 @@ +//===-- ClangUserExpression.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +#include +#if HAVE_SYS_TYPES_H +# include +#endif + +// C++ Includes + +#include "lldb/Core/ConstString.h" +#include "lldb/Core/Stream.h" +#include "lldb/Expression/ClangExpressionParser.h" +#include "lldb/Expression/ClangUtilityFunction.h" +#include "lldb/Host/Host.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Target.h" + +using namespace lldb_private; + +//------------------------------------------------------------------ +/// Constructor +/// +/// @param[in] text +/// The text of the function. Must be a full translation unit. +/// +/// @param[in] name +/// The name of the function, as used in the text. +//------------------------------------------------------------------ +ClangUtilityFunction::ClangUtilityFunction (const char *text, + const char *name) : + m_function_text(text), + m_function_name(name) +{ +} + +//------------------------------------------------------------------ +/// Install the utility function into a process +/// +/// @param[in] error_stream +/// A stream to print parse errors and warnings to. +/// +/// @param[in] exe_ctx +/// The execution context to install the utility function to. +/// +/// @return +/// True on success (no errors); false otherwise. +//------------------------------------------------------------------ +bool +ClangUtilityFunction::Install (Stream &error_stream, + ExecutionContext &exe_ctx) +{ + //////////////////////////////////// + // Set up the target and compiler + // + + Target *target = exe_ctx.target; + + if (!target) + { + error_stream.PutCString ("error: invalid target\n"); + return false; + } + + ConstString target_triple; + + target->GetTargetTriple (target_triple); + + if (!target_triple) + target_triple = Host::GetTargetTriple (); + + if (!target_triple) + { + error_stream.PutCString ("error: invalid target triple\n"); + return false; + } + + ////////////////////////// + // Parse the expression + // + + ClangExpressionParser parser(target_triple.GetCString(), *this); + + unsigned num_errors = parser.Parse (error_stream); + + if (num_errors) + { + error_stream.Printf ("error: %d errors parsing expression\n", num_errors); + return false; + } + + ////////////////////////////////// + // JIT the output of the parser + // + + Error jit_error = parser.MakeJIT (m_jit_begin, m_jit_end, exe_ctx); + + if (jit_error.Success()) + { + return true; + } + else + { + error_stream.Printf ("error: expression can't be interpreted or run\n", num_errors); + return false; + } +} + +