forked from OSchip/llvm-project
Documented ClangExpression and made parts of it
more sane (i.e., removed dead arguments, made sensible defaults, etc.) llvm-svn: 110990
This commit is contained in:
parent
e7c1fe6ab7
commit
b269b6eabb
|
@ -35,94 +35,252 @@ namespace lldb_private {
|
|||
|
||||
class RecordingMemoryManager;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
/// @class ClangExpression ClangExpression.h "lldb/Expression/ClangExpression.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. ClangExpression encapsulates
|
||||
/// the objects needed to parse and interpret or JIT an expression. It
|
||||
/// uses the Clang parser to produce LLVM IR from the expression.
|
||||
//----------------------------------------------------------------------
|
||||
class ClangExpression
|
||||
{
|
||||
public:
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Constructors and Destructors
|
||||
/// Constructor
|
||||
///
|
||||
/// Initializes class variabes.
|
||||
///
|
||||
/// @param[in] target_triple
|
||||
/// The LLVM-friendly target triple for use in initializing the
|
||||
/// compiler.
|
||||
///
|
||||
/// @param[in] expr_decl_map
|
||||
/// The object that looks up externally-defined names in LLDB's
|
||||
/// debug information.
|
||||
//------------------------------------------------------------------
|
||||
ClangExpression(const char *target_triple,
|
||||
ClangExpressionDeclMap *expr_decl_map);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Destructor
|
||||
//------------------------------------------------------------------
|
||||
~ClangExpression();
|
||||
|
||||
unsigned Compile();
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Parse a single expression and convert it to IR using Clang. Wrap
|
||||
/// the expression in a function with signature void ___clang_expr(void*).
|
||||
///
|
||||
/// @param[in] expr_text
|
||||
/// The text of the expression to be parsed.
|
||||
///
|
||||
/// @param[in] stream
|
||||
/// The stream to print errors to.
|
||||
///
|
||||
/// @param[in] add_result_var
|
||||
/// True if a special result variable should be generated for
|
||||
/// the expression.
|
||||
///
|
||||
/// @return
|
||||
/// The number of errors encountered during parsing. 0 means
|
||||
/// success.
|
||||
//------------------------------------------------------------------
|
||||
unsigned
|
||||
ParseExpression (const char *expr_text,
|
||||
Stream &stream,
|
||||
bool add_result_var = false);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Parse a single expression and convert it to IR using Clang. Don't
|
||||
/// wrap the expression in anything at all.
|
||||
///
|
||||
/// @param[in] expr_text
|
||||
/// The text of the expression to be parsed.
|
||||
///
|
||||
/// @param[in] stream
|
||||
/// The stream to print errors to.
|
||||
///
|
||||
/// @param[in] add_result_var
|
||||
/// True if a special result variable should be generated for
|
||||
/// the expression.
|
||||
///
|
||||
/// @return
|
||||
/// The number of errors encountered during parsing. 0 means
|
||||
/// success.
|
||||
//------------------------------------------------------------------
|
||||
unsigned
|
||||
ParseBareExpression (llvm::StringRef expr_text,
|
||||
Stream &stream,
|
||||
bool add_result_var = false);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Convert the IR for an already-parsed expression to DWARF if possible.
|
||||
///
|
||||
/// @param[in] expr_local_variable_list
|
||||
/// The list of local variables the expression uses, with types, for
|
||||
/// use by the DWARF parser.
|
||||
///
|
||||
/// @param[in] dwarf_opcode_strm
|
||||
/// The stream to place the resulting DWARF code into.
|
||||
///
|
||||
/// @return
|
||||
/// True on success; false on failure. On failure, it may be appropriate
|
||||
/// to call PrepareIRForTarget().
|
||||
//------------------------------------------------------------------
|
||||
bool
|
||||
ConvertIRToDWARF (ClangExpressionVariableList &excpr_local_variable_list,
|
||||
StreamString &dwarf_opcode_strm);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Prepare the IR for an already-parsed expression for execution in the
|
||||
/// target process by (among other things) making all externally-defined
|
||||
/// variables point to offsets from the void* argument.
|
||||
///
|
||||
/// @return
|
||||
/// True on success; false on failure. On failure, this expression
|
||||
/// cannot be executed by LLDB.
|
||||
//------------------------------------------------------------------
|
||||
bool
|
||||
PrepareIRForTarget (ClangExpressionVariableList &excpr_local_variable_list);
|
||||
PrepareIRForTarget ();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Use the JIT to compile an already-prepared expression from IR into
|
||||
/// machine code, but keep the code in the current process for now.
|
||||
///
|
||||
/// @param[in] func_name
|
||||
/// The name of the function to be JITted. By default, the function
|
||||
/// wrapped by ParseExpression().
|
||||
///
|
||||
/// @return
|
||||
/// True on success; false otherwise.
|
||||
//------------------------------------------------------------------
|
||||
bool
|
||||
JITFunction (const ExecutionContext &exc_context, const char *func_name);
|
||||
JITFunction (const char *func_name = "___clang_expr");
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Write the machine code generated by the JIT into the target's memory.
|
||||
///
|
||||
/// @param[in] exc_context
|
||||
/// The execution context that the JITted code must be copied into.
|
||||
///
|
||||
/// @return
|
||||
/// True on success; false otherwise.
|
||||
//------------------------------------------------------------------
|
||||
bool
|
||||
WriteJITCode (const ExecutionContext &exc_context);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Write the machine code generated by the JIT into the target process.
|
||||
///
|
||||
/// @param[in] func_name
|
||||
/// The name of the function whose address is being requested.
|
||||
/// By default, the function wrapped by ParseExpression().
|
||||
///
|
||||
/// @return
|
||||
/// True on success; false otherwise.
|
||||
//------------------------------------------------------------------
|
||||
lldb::addr_t
|
||||
GetFunctionAddress (const char *name);
|
||||
GetFunctionAddress (const char *func_name = "___clang_expr");
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Disassemble the machine code for a JITted function from the target
|
||||
/// process's memory and print the result to a stream.
|
||||
///
|
||||
/// @param[in] stream
|
||||
/// The stream to print disassembly to.
|
||||
///
|
||||
/// @param[in] exc_context
|
||||
/// The execution context to get the machine code from.
|
||||
///
|
||||
/// @param[in] func_name
|
||||
/// The name of the function to be disassembled. By default, the
|
||||
/// function wrapped by ParseExpression().
|
||||
///
|
||||
/// @return
|
||||
/// The error generated. If .Success() is true, disassembly succeeded.
|
||||
//------------------------------------------------------------------
|
||||
Error
|
||||
DisassembleFunction (Stream &stream, ExecutionContext &exc_context, const char *name);
|
||||
DisassembleFunction (Stream &stream, ExecutionContext &exc_context, const char *func_name = "___clang_expr");
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return the Clang compiler instance being used by this expression.
|
||||
//------------------------------------------------------------------
|
||||
clang::CompilerInstance *
|
||||
GetCompilerInstance ()
|
||||
{
|
||||
return m_clang_ap.get();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return the AST context being used by this expression.
|
||||
//------------------------------------------------------------------
|
||||
clang::ASTContext *
|
||||
GetASTContext ();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return the mutex being used to serialize access to Clang.
|
||||
//------------------------------------------------------------------
|
||||
static Mutex &
|
||||
GetClangMutex ();
|
||||
protected:
|
||||
|
||||
// This class is a pass-through for the default JIT memory manager,
|
||||
// which just records the memory regions that were handed out so we
|
||||
// can copy them into the target later on.
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Classes that inherit from ClangExpression can see and modify these
|
||||
//------------------------------------------------------------------
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
/// @class JittedFunction ClangExpression.h "lldb/Expression/ClangExpression.h"
|
||||
/// @brief Encapsulates a single function that has been generated by the JIT.
|
||||
///
|
||||
/// Functions that have been generated by the JIT are first resident in the
|
||||
/// local process, and then placed in the target process. JittedFunction
|
||||
/// represents a function possibly resident in both.
|
||||
//----------------------------------------------------------------------
|
||||
struct JittedFunction {
|
||||
std::string m_name;
|
||||
lldb::addr_t m_local_addr;
|
||||
lldb::addr_t m_remote_addr;
|
||||
std::string m_name; ///< The function's name
|
||||
lldb::addr_t m_local_addr; ///< The address of the function in LLDB's memory
|
||||
lldb::addr_t m_remote_addr; ///< The address of the function in the target's memory
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Constructor
|
||||
///
|
||||
/// Initializes class variabes.
|
||||
///
|
||||
/// @param[in] name
|
||||
/// The name of the function.
|
||||
///
|
||||
/// @param[in] local_addr
|
||||
/// The address of the function in LLDB, or LLDB_INVALID_ADDRESS if
|
||||
/// it is not present in LLDB's memory.
|
||||
///
|
||||
/// @param[in] remote_addr
|
||||
/// The address of the function in the target, or LLDB_INVALID_ADDRESS
|
||||
/// if it is not present in the target's memory.
|
||||
//------------------------------------------------------------------
|
||||
JittedFunction (const char *name,
|
||||
lldb::addr_t local_addr = LLDB_INVALID_ADDRESS,
|
||||
lldb::addr_t remote_addr = LLDB_INVALID_ADDRESS) :
|
||||
lldb::addr_t local_addr = LLDB_INVALID_ADDRESS,
|
||||
lldb::addr_t remote_addr = LLDB_INVALID_ADDRESS) :
|
||||
m_name (name),
|
||||
m_local_addr (local_addr),
|
||||
m_remote_addr (remote_addr) {}
|
||||
};
|
||||
|
||||
std::string m_target_triple;
|
||||
ClangExpressionDeclMap *m_decl_map;
|
||||
std::auto_ptr<clang::CompilerInstance> m_clang_ap;
|
||||
clang::CodeGenerator *m_code_generator_ptr; // This will be deleted by the Execution Engine.
|
||||
RecordingMemoryManager *m_jit_mm_ptr; // This will be deleted by the Execution Engine.
|
||||
std::auto_ptr<llvm::ExecutionEngine> m_execution_engine;
|
||||
std::vector<JittedFunction> m_jitted_functions;
|
||||
std::string m_target_triple; ///< The target triple used to initialize LLVM
|
||||
ClangExpressionDeclMap *m_decl_map; ///< The class used to look up entities defined in the debug info
|
||||
std::auto_ptr<clang::CompilerInstance> m_clang_ap; ///< The Clang compiler used to parse expressions into IR
|
||||
clang::CodeGenerator *m_code_generator_ptr; ///< [owned by the Execution Engine] The Clang object that generates IR
|
||||
RecordingMemoryManager *m_jit_mm_ptr; ///< [owned by the Execution Engine] The memory manager that allocates code pages on the JIT's behalf
|
||||
std::auto_ptr<llvm::ExecutionEngine> m_execution_engine; ///< The LLVM JIT
|
||||
std::vector<JittedFunction> m_jitted_functions; ///< A vector of all functions that have been JITted into machine code (just one, if ParseExpression() was called)
|
||||
private:
|
||||
|
||||
bool CreateCompilerInstance(bool &IsAST);
|
||||
//------------------------------------------------------------------
|
||||
/// Initialize m_clang_ap to a compiler instance with all the options
|
||||
/// required by the expression parser.
|
||||
///
|
||||
/// @return
|
||||
/// True on success; false otherwise.
|
||||
//------------------------------------------------------------------
|
||||
bool CreateCompilerInstance();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// For ClangExpression only
|
||||
|
|
|
@ -267,7 +267,7 @@ CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream
|
|||
{
|
||||
if (log)
|
||||
log->Printf("Code cannot be interpreted and must be run in the target.");
|
||||
success = clang_expr.PrepareIRForTarget (expr_local_vars);
|
||||
success = clang_expr.PrepareIRForTarget ();
|
||||
}
|
||||
|
||||
if (!success)
|
||||
|
@ -283,7 +283,7 @@ CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!clang_expr.JITFunction (m_exe_ctx, "___clang_expr"))
|
||||
if (!clang_expr.JITFunction ())
|
||||
{
|
||||
error_stream.PutCString ("error: IR could not be JIT compiled\n");
|
||||
return false;
|
||||
|
@ -295,7 +295,7 @@ CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream
|
|||
return false;
|
||||
}
|
||||
|
||||
lldb::addr_t function_address(clang_expr.GetFunctionAddress ("___clang_expr"));
|
||||
lldb::addr_t function_address(clang_expr.GetFunctionAddress ());
|
||||
|
||||
if (function_address == LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
|
@ -318,7 +318,7 @@ CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream
|
|||
|
||||
StreamString insns;
|
||||
|
||||
Error err = clang_expr.DisassembleFunction(insns, m_exe_ctx, "___clang_expr");
|
||||
Error err = clang_expr.DisassembleFunction(insns, m_exe_ctx);
|
||||
|
||||
if (!err.Success())
|
||||
{
|
||||
|
|
|
@ -217,7 +217,7 @@ ClangExpression::~ClangExpression()
|
|||
}
|
||||
|
||||
bool
|
||||
ClangExpression::CreateCompilerInstance (bool &IsAST)
|
||||
ClangExpression::CreateCompilerInstance ()
|
||||
{
|
||||
// Initialize targets first, so that --version shows registered targets.
|
||||
static struct InitializeLLVM {
|
||||
|
@ -313,8 +313,7 @@ ClangExpression::ParseBareExpression (llvm::StringRef expr_text,
|
|||
|
||||
TextDiagnosticBuffer text_diagnostic_buffer;
|
||||
|
||||
bool IsAST = false;
|
||||
if (!CreateCompilerInstance (IsAST))
|
||||
if (!CreateCompilerInstance ())
|
||||
{
|
||||
stream.Printf("error: couldn't create compiler instance\n");
|
||||
return 1;
|
||||
|
@ -462,7 +461,7 @@ ClangExpression::ConvertIRToDWARF (ClangExpressionVariableList &expr_local_varia
|
|||
}
|
||||
|
||||
bool
|
||||
ClangExpression::PrepareIRForTarget (ClangExpressionVariableList &expr_local_variable_list)
|
||||
ClangExpression::PrepareIRForTarget ()
|
||||
{
|
||||
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
|
||||
|
||||
|
@ -498,7 +497,7 @@ ClangExpression::PrepareIRForTarget (ClangExpressionVariableList &expr_local_var
|
|||
}
|
||||
|
||||
bool
|
||||
ClangExpression::JITFunction (const ExecutionContext &exc_context, const char *name)
|
||||
ClangExpression::JITFunction (const char *name)
|
||||
{
|
||||
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
|
||||
|
||||
|
@ -747,89 +746,3 @@ ClangExpression::DisassembleFunction (Stream &stream, ExecutionContext &exe_ctx,
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned
|
||||
ClangExpression::Compile()
|
||||
{
|
||||
Mutex::Locker locker(GetClangMutex ());
|
||||
bool IsAST = false;
|
||||
|
||||
if (CreateCompilerInstance(IsAST))
|
||||
{
|
||||
// Validate/process some options
|
||||
if (m_clang_ap->getHeaderSearchOpts().Verbose)
|
||||
llvm::errs() << "clang-cc version " CLANG_VERSION_STRING
|
||||
<< " based upon " << PACKAGE_STRING
|
||||
<< " hosted on " << llvm::sys::getHostTriple() << "\n";
|
||||
|
||||
// Enforce certain implications.
|
||||
if (!m_clang_ap->getFrontendOpts().ViewClassInheritance.empty())
|
||||
m_clang_ap->getFrontendOpts().ProgramAction = frontend::InheritanceView;
|
||||
// if (!compiler_instance->getFrontendOpts().FixItSuffix.empty())
|
||||
// compiler_instance->getFrontendOpts().ProgramAction = frontend::FixIt;
|
||||
|
||||
for (unsigned i = 0, e = m_clang_ap->getFrontendOpts().Inputs.size(); i != e; ++i) {
|
||||
|
||||
// If we aren't using an AST file, setup the file and source managers and
|
||||
// the preprocessor.
|
||||
if (!IsAST) {
|
||||
if (!i) {
|
||||
// Create a file manager object to provide access to and cache the
|
||||
// filesystem.
|
||||
m_clang_ap->createFileManager();
|
||||
|
||||
// Create the source manager.
|
||||
m_clang_ap->createSourceManager();
|
||||
} else {
|
||||
// Reset the ID tables if we are reusing the SourceManager.
|
||||
m_clang_ap->getSourceManager().clearIDTables();
|
||||
}
|
||||
|
||||
// Create the preprocessor.
|
||||
m_clang_ap->createPreprocessor();
|
||||
}
|
||||
|
||||
llvm::OwningPtr<FrontendAction> Act(CreateFrontendAction(*m_clang_ap.get()));
|
||||
if (!Act)
|
||||
break;
|
||||
|
||||
if (Act->BeginSourceFile(*m_clang_ap,
|
||||
m_clang_ap->getFrontendOpts().Inputs[i].second,
|
||||
m_clang_ap->getFrontendOpts().Inputs[i].first)) {
|
||||
Act->Execute();
|
||||
Act->EndSourceFile();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_clang_ap->getDiagnosticOpts().ShowCarets)
|
||||
{
|
||||
unsigned NumWarnings = m_clang_ap->getDiagnostics().getNumWarnings();
|
||||
unsigned NumErrors = m_clang_ap->getDiagnostics().getNumErrors() -
|
||||
m_clang_ap->getDiagnostics().getNumErrorsSuppressed();
|
||||
|
||||
if (NumWarnings || NumErrors)
|
||||
{
|
||||
if (NumWarnings)
|
||||
fprintf (stderr, "%u warning%s%s", NumWarnings, (NumWarnings == 1 ? "" : "s"), (NumErrors ? " and " : ""));
|
||||
if (NumErrors)
|
||||
fprintf (stderr, "%u error%s", NumErrors, (NumErrors == 1 ? "" : "s"));
|
||||
fprintf (stderr, " generated.\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (m_clang_ap->getFrontendOpts().ShowStats) {
|
||||
m_clang_ap->getFileManager().PrintStats();
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
// Return the appropriate status when verifying diagnostics.
|
||||
//
|
||||
// FIXME: If we could make getNumErrors() do the right thing, we wouldn't need
|
||||
// this.
|
||||
if (m_clang_ap->getDiagnosticOpts().VerifyDiagnostics)
|
||||
return static_cast<VerifyDiagnosticsClient&>(m_clang_ap->getDiagnosticClient()).HadErrors();
|
||||
|
||||
return m_clang_ap->getDiagnostics().getNumErrors();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -258,7 +258,7 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors)
|
|||
if (!m_JITted)
|
||||
{
|
||||
// Next we should JIT it and insert the result into the target program.
|
||||
if (!JITFunction (exe_ctx, m_wrapper_function_name.c_str()))
|
||||
if (!JITFunction (m_wrapper_function_name.c_str()))
|
||||
return false;
|
||||
|
||||
if (!WriteJITCode (exe_ctx))
|
||||
|
|
Loading…
Reference in New Issue