diff options
Diffstat (limited to 'lldb/source/Expression')
-rw-r--r-- | lldb/source/Expression/ASTStructExtractor.cpp | 2 | ||||
-rw-r--r-- | lldb/source/Expression/CMakeLists.txt | 6 | ||||
-rw-r--r-- | lldb/source/Expression/ClangASTSource.cpp | 1 | ||||
-rw-r--r-- | lldb/source/Expression/ClangExpressionParser.cpp | 33 | ||||
-rw-r--r-- | lldb/source/Expression/ClangFunctionCaller.cpp | 220 | ||||
-rw-r--r-- | lldb/source/Expression/ClangUserExpression.cpp | 669 | ||||
-rw-r--r-- | lldb/source/Expression/ClangUtilityFunction.cpp | 36 | ||||
-rw-r--r-- | lldb/source/Expression/Expression.cpp | 32 | ||||
-rw-r--r-- | lldb/source/Expression/FunctionCaller.cpp (renamed from lldb/source/Expression/ClangFunction.cpp) | 222 | ||||
-rw-r--r-- | lldb/source/Expression/IRDynamicChecks.cpp | 13 | ||||
-rw-r--r-- | lldb/source/Expression/UserExpression.cpp | 644 | ||||
-rw-r--r-- | lldb/source/Expression/UtilityFunction.cpp | 123 |
12 files changed, 1142 insertions, 859 deletions
diff --git a/lldb/source/Expression/ASTStructExtractor.cpp b/lldb/source/Expression/ASTStructExtractor.cpp index 98628dbc92b..049173e32f3 100644 --- a/lldb/source/Expression/ASTStructExtractor.cpp +++ b/lldb/source/Expression/ASTStructExtractor.cpp @@ -28,7 +28,7 @@ using namespace lldb_private; ASTStructExtractor::ASTStructExtractor(ASTConsumer *passthrough, const char *struct_name, - ClangFunction &function) : + ClangFunctionCaller &function) : m_ast_context (NULL), m_passthrough (passthrough), m_passthrough_sema (NULL), diff --git a/lldb/source/Expression/CMakeLists.txt b/lldb/source/Expression/CMakeLists.txt index 92f8f0863bf..4b689da027b 100644 --- a/lldb/source/Expression/CMakeLists.txt +++ b/lldb/source/Expression/CMakeLists.txt @@ -5,18 +5,22 @@ add_lldb_library(lldbExpression ClangASTSource.cpp ClangExpressionDeclMap.cpp ClangExpressionParser.cpp - ClangFunction.cpp + ClangFunctionCaller.cpp ClangModulesDeclVendor.cpp ClangPersistentVariables.cpp ClangUserExpression.cpp ClangUtilityFunction.cpp DWARFExpression.cpp + Expression.cpp ExpressionSourceCode.cpp ExpressionVariable.cpp + FunctionCaller.cpp IRDynamicChecks.cpp IRExecutionUnit.cpp IRForTarget.cpp IRInterpreter.cpp IRMemoryMap.cpp Materializer.cpp + UserExpression.cpp + UtilityFunction.cpp ) diff --git a/lldb/source/Expression/ClangASTSource.cpp b/lldb/source/Expression/ClangASTSource.cpp index ef778a1bca4..e6ddaa7e506 100644 --- a/lldb/source/Expression/ClangASTSource.cpp +++ b/lldb/source/Expression/ClangASTSource.cpp @@ -15,7 +15,6 @@ #include "lldb/Core/ModuleList.h" #include "lldb/Expression/ASTDumper.h" #include "lldb/Expression/ClangASTSource.h" -#include "lldb/Expression/ClangExpression.h" #include "lldb/Expression/ClangModulesDeclVendor.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/CompilerDeclContext.h" diff --git a/lldb/source/Expression/ClangExpressionParser.cpp b/lldb/source/Expression/ClangExpressionParser.cpp index d5dbaf16b4a..2a4663966cf 100644 --- a/lldb/source/Expression/ClangExpressionParser.cpp +++ b/lldb/source/Expression/ClangExpressionParser.cpp @@ -19,7 +19,7 @@ #include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" #include "lldb/Expression/ClangASTSource.h" -#include "lldb/Expression/ClangExpression.h" +#include "lldb/Expression/ClangExpressionHelper.h" #include "lldb/Expression/ClangExpressionDeclMap.h" #include "lldb/Expression/ClangModulesDeclVendor.h" #include "lldb/Expression/ClangPersistentVariables.h" @@ -37,6 +37,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ExternalASTSource.h" #include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" #include "clang/CodeGen/CodeGenAction.h" @@ -108,7 +109,7 @@ public: } virtual void moduleImport(SourceLocation import_location, - ModuleIdPath path, + clang::ModuleIdPath path, const clang::Module * /*null*/) { std::vector<ConstString> string_path; @@ -149,9 +150,9 @@ public: //===----------------------------------------------------------------------===// ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, - ClangExpression &expr, + Expression &expr, bool generate_debug_info) : - m_expr (expr), + ExpressionParser (exe_scope, expr, generate_debug_info), m_compiler (), m_code_generator (), m_pp_callbacks(nullptr) @@ -255,7 +256,7 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, m_compiler->getLangOpts().WChar = true; m_compiler->getLangOpts().Blocks = true; m_compiler->getLangOpts().DebuggerSupport = true; // Features specifically for debugger clients - if (expr.DesiredResultType() == ClangExpression::eResultTypeId) + if (expr.DesiredResultType() == Expression::eResultTypeId) m_compiler->getLangOpts().DebuggerCastResultToId = true; m_compiler->getLangOpts().CharIsSigned = @@ -346,7 +347,8 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, ast_context->InitBuiltinTypes(m_compiler->getTarget()); - ClangExpressionDeclMap *decl_map = m_expr.DeclMap(); + ClangExpressionHelper *type_system_helper = dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper()); + ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap(); if (decl_map) { @@ -430,9 +432,11 @@ ClangExpressionParser::Parse (Stream &stream) diag_buf->BeginSourceFile(m_compiler->getLangOpts(), &m_compiler->getPreprocessor()); - ASTConsumer *ast_transformer = m_expr.ASTTransformer(m_code_generator.get()); + ClangExpressionHelper *type_system_helper = dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper()); - if (ClangExpressionDeclMap *decl_map = m_expr.DeclMap()) + ASTConsumer *ast_transformer = type_system_helper->ASTTransformer(m_code_generator.get()); + + if (ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap()) decl_map->InstallCodeGenerator(m_code_generator.get()); if (ast_transformer) @@ -479,7 +483,7 @@ ClangExpressionParser::Parse (Stream &stream) if (!num_errors) { - if (m_expr.DeclMap() && !m_expr.DeclMap()->ResolveUnknownTypes()) + if (type_system_helper->DeclMap() && !type_system_helper->DeclMap()->ResolveUnknownTypes()) { stream.Printf("error: Couldn't infer the type of a variable\n"); num_errors++; @@ -552,7 +556,8 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, exe_ctx.GetTargetSP(), m_compiler->getTargetOpts().Features)); - ClangExpressionDeclMap *decl_map = m_expr.DeclMap(); // result can be NULL + ClangExpressionHelper *type_system_helper = dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper()); + ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap(); // result can be NULL if (decl_map) { @@ -640,11 +645,3 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, return err; } - -bool -ClangExpressionParser::GetGenerateDebugInfo () const -{ - if (m_compiler) - return m_compiler->getCodeGenOpts().getDebugInfo() == CodeGenOptions::FullDebugInfo; - return false; -} diff --git a/lldb/source/Expression/ClangFunctionCaller.cpp b/lldb/source/Expression/ClangFunctionCaller.cpp new file mode 100644 index 00000000000..628952fe6b8 --- /dev/null +++ b/lldb/source/Expression/ClangFunctionCaller.cpp @@ -0,0 +1,220 @@ +//===-- ClangFunctionCallerCaller.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 +// C++ Includes +// Other libraries and framework includes +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" +#include "clang/CodeGen/CodeGenAction.h" +#include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/IR/Module.h" + +// Project includes +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/State.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Core/ValueObjectList.h" +#include "lldb/Expression/ASTStructExtractor.h" +#include "lldb/Expression/ClangExpressionParser.h" +#include "lldb/Expression/ClangFunctionCaller.h" +#include "lldb/Expression/IRExecutionUnit.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlan.h" +#include "lldb/Target/ThreadPlanCallFunction.h" + +using namespace lldb_private; + +//---------------------------------------------------------------------- +// ClangFunctionCaller constructor +//---------------------------------------------------------------------- +ClangFunctionCaller::ClangFunctionCaller +( + ExecutionContextScope &exe_scope, + const CompilerType &return_type, + const Address& functionAddress, + const ValueList &arg_value_list, + const char *name +) : + FunctionCaller(exe_scope, return_type, functionAddress, arg_value_list, name), + m_type_system_helper (*this) +{ + m_jit_process_wp = lldb::ProcessWP(exe_scope.CalculateProcess()); + // Can't make a ClangFunctionCaller without a process. + assert (m_jit_process_wp.lock()); +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +ClangFunctionCaller::~ClangFunctionCaller() +{ +} + +unsigned +ClangFunctionCaller::CompileFunction (Stream &errors) +{ + if (m_compiled) + return 0; + + // FIXME: How does clang tell us there's no return value? We need to handle that case. + unsigned num_errors = 0; + + std::string return_type_str (m_function_return_type.GetTypeName().AsCString("")); + + // Cons up the function we're going to wrap our call in, then compile it... + // We declare the function "extern "C"" because the compiler might be in C++ + // mode which would mangle the name and then we couldn't find it again... + m_wrapper_function_text.clear(); + m_wrapper_function_text.append ("extern \"C\" void "); + m_wrapper_function_text.append (m_wrapper_function_name); + m_wrapper_function_text.append (" (void *input)\n{\n struct "); + m_wrapper_function_text.append (m_wrapper_struct_name); + m_wrapper_function_text.append (" \n {\n"); + m_wrapper_function_text.append (" "); + m_wrapper_function_text.append (return_type_str); + m_wrapper_function_text.append (" (*fn_ptr) ("); + + // Get the number of arguments. If we have a function type and it is prototyped, + // trust that, otherwise use the values we were given. + + // FIXME: This will need to be extended to handle Variadic functions. We'll need + // to pull the defined arguments out of the function, then add the types from the + // arguments list for the variable arguments. + + uint32_t num_args = UINT32_MAX; + bool trust_function = false; + // GetArgumentCount returns -1 for an unprototyped function. + CompilerType function_clang_type; + if (m_function_ptr) + { + function_clang_type = m_function_ptr->GetCompilerType(); + if (function_clang_type) + { + int num_func_args = function_clang_type.GetFunctionArgumentCount(); + if (num_func_args >= 0) + { + trust_function = true; + num_args = num_func_args; + } + } + } + + if (num_args == UINT32_MAX) + num_args = m_arg_values.GetSize(); + + std::string args_buffer; // This one stores the definition of all the args in "struct caller". + std::string args_list_buffer; // This one stores the argument list called from the structure. + for (size_t i = 0; i < num_args; i++) + { + std::string type_name; + + if (trust_function) + { + type_name = function_clang_type.GetFunctionArgumentTypeAtIndex(i).GetTypeName().AsCString(""); + } + else + { + CompilerType clang_qual_type = m_arg_values.GetValueAtIndex(i)->GetCompilerType (); + if (clang_qual_type) + { + type_name = clang_qual_type.GetTypeName().AsCString(""); + } + else + { + errors.Printf("Could not determine type of input value %" PRIu64 ".", (uint64_t)i); + return 1; + } + } + + m_wrapper_function_text.append (type_name); + if (i < num_args - 1) + m_wrapper_function_text.append (", "); + + char arg_buf[32]; + args_buffer.append (" "); + args_buffer.append (type_name); + snprintf(arg_buf, 31, "arg_%" PRIu64, (uint64_t)i); + args_buffer.push_back (' '); + args_buffer.append (arg_buf); + args_buffer.append (";\n"); + + args_list_buffer.append ("__lldb_fn_data->"); + args_list_buffer.append (arg_buf); + if (i < num_args - 1) + args_list_buffer.append (", "); + + } + m_wrapper_function_text.append (");\n"); // Close off the function calling prototype. + + m_wrapper_function_text.append (args_buffer); + + m_wrapper_function_text.append (" "); + m_wrapper_function_text.append (return_type_str); + m_wrapper_function_text.append (" return_value;"); + m_wrapper_function_text.append ("\n };\n struct "); + m_wrapper_function_text.append (m_wrapper_struct_name); + m_wrapper_function_text.append ("* __lldb_fn_data = (struct "); + m_wrapper_function_text.append (m_wrapper_struct_name); + m_wrapper_function_text.append (" *) input;\n"); + + m_wrapper_function_text.append (" __lldb_fn_data->return_value = __lldb_fn_data->fn_ptr ("); + m_wrapper_function_text.append (args_list_buffer); + m_wrapper_function_text.append (");\n}\n"); + + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + if (log) + log->Printf ("Expression: \n\n%s\n\n", m_wrapper_function_text.c_str()); + + // Okay, now compile this expression + + lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock()); + if (jit_process_sp) + { + const bool generate_debug_info = true; + m_parser.reset(new ClangExpressionParser(jit_process_sp.get(), *this, generate_debug_info)); + + num_errors = m_parser->Parse (errors); + } + else + { + errors.Printf("no process - unable to inject function"); + num_errors = 1; + } + + m_compiled = (num_errors == 0); + + if (!m_compiled) + return num_errors; + + return num_errors; +} + +clang::ASTConsumer * +ClangFunctionCaller::ClangFunctionCallerHelper::ASTTransformer (clang::ASTConsumer *passthrough) +{ + m_struct_extractor.reset(new ASTStructExtractor(passthrough, m_owner.GetWrapperStructName(), m_owner)); + + return m_struct_extractor.get(); +} diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp index 9239389753e..a6e5923bf28 100644 --- a/lldb/source/Expression/ClangUserExpression.cpp +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -25,7 +25,6 @@ #include "lldb/Expression/ASTResultSynthesizer.h" #include "lldb/Expression/ClangExpressionDeclMap.h" #include "lldb/Expression/ClangExpressionParser.h" -#include "lldb/Expression/ClangFunction.h" #include "lldb/Expression/ClangModulesDeclVendor.h" #include "lldb/Expression/ClangPersistentVariables.h" #include "lldb/Expression/ClangUserExpression.h" @@ -54,32 +53,13 @@ using namespace lldb_private; -ClangUserExpression::ClangUserExpression (const char *expr, +ClangUserExpression::ClangUserExpression (ExecutionContextScope &exe_scope, + const char *expr, const char *expr_prefix, lldb::LanguageType language, ResultType desired_type) : - ClangExpression (), - m_stack_frame_bottom (LLDB_INVALID_ADDRESS), - m_stack_frame_top (LLDB_INVALID_ADDRESS), - m_expr_text (expr), - m_expr_prefix (expr_prefix ? expr_prefix : ""), - m_language (language), - m_transformed_text (), - m_desired_type (desired_type), - m_expr_decl_map(), - m_execution_unit_sp(), - m_materializer_ap(), - m_result_synthesizer(), - m_jit_module_wp(), - m_enforce_valid_object (true), - m_in_cplusplus_method (false), - m_in_objectivec_method (false), - m_in_static_method(false), - m_needs_object_ptr (false), - m_const_object (false), - m_target (NULL), - m_can_interpret (false), - m_materialized_address (LLDB_INVALID_ADDRESS) + UserExpression (exe_scope, expr, expr_prefix, language, desired_type), + m_type_system_helper(*m_target_wp.lock().get()) { switch (m_language) { @@ -99,21 +79,6 @@ ClangUserExpression::ClangUserExpression (const char *expr, ClangUserExpression::~ClangUserExpression () { - if (m_target) - { - lldb::ModuleSP jit_module_sp (m_jit_module_wp.lock()); - if (jit_module_sp) - m_target->GetImages().Remove(jit_module_sp); - } -} - -clang::ASTConsumer * -ClangUserExpression::ASTTransformer (clang::ASTConsumer *passthrough) -{ - m_result_synthesizer.reset(new ASTResultSynthesizer(passthrough, - *m_target)); - - return m_result_synthesizer.get(); } void @@ -338,54 +303,6 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err) } } -void -ClangUserExpression::InstallContext (ExecutionContext &exe_ctx) -{ - m_process_wp = exe_ctx.GetProcessSP(); - - lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP(); - - if (frame_sp) - m_address = frame_sp->GetFrameCodeAddress(); -} - -bool -ClangUserExpression::LockAndCheckContext (ExecutionContext &exe_ctx, - lldb::TargetSP &target_sp, - lldb::ProcessSP &process_sp, - lldb::StackFrameSP &frame_sp) -{ - lldb::ProcessSP expected_process_sp = m_process_wp.lock(); - process_sp = exe_ctx.GetProcessSP(); - - if (process_sp != expected_process_sp) - return false; - - process_sp = exe_ctx.GetProcessSP(); - target_sp = exe_ctx.GetTargetSP(); - frame_sp = exe_ctx.GetFrameSP(); - - if (m_address.IsValid()) - { - if (!frame_sp) - return false; - else - return (0 == Address::CompareLoadAddress(m_address, frame_sp->GetFrameCodeAddress(), target_sp.get())); - } - - return true; -} - -bool -ClangUserExpression::MatchesContext (ExecutionContext &exe_ctx) -{ - lldb::TargetSP target_sp; - lldb::ProcessSP process_sp; - lldb::StackFrameSP frame_sp; - - return LockAndCheckContext(exe_ctx, target_sp, process_sp, frame_sp); -} - // This is a really nasty hack, meant to fix Objective-C expressions of the form // (int)[myArray count]. Right now, because the type information for count is // not available, [myArray count] returns id, which can't be directly cast to @@ -405,26 +322,6 @@ ApplyObjcCastHack(std::string &expr) #undef OBJC_CAST_HACK_FROM } -// Another hack, meant to allow use of unichar despite it not being available in -// the type information. Although we could special-case it in type lookup, -// hopefully we'll figure out a way to #include the same environment as is -// present in the original source file rather than try to hack specific type -// definitions in as needed. -//static void -//ApplyUnicharHack(std::string &expr) -//{ -//#define UNICHAR_HACK_FROM "unichar" -//#define UNICHAR_HACK_TO "unsigned short" -// -// size_t from_offset; -// -// while ((from_offset = expr.find(UNICHAR_HACK_FROM)) != expr.npos) -// expr.replace(from_offset, sizeof(UNICHAR_HACK_FROM) - 1, UNICHAR_HACK_TO); -// -//#undef UNICHAR_HACK_TO -//#undef UNICHAR_HACK_FROM -//} - bool ClangUserExpression::Parse (Stream &error_stream, ExecutionContext &exe_ctx, @@ -525,7 +422,7 @@ ClangUserExpression::Parse (Stream &error_stream, m_materializer_ap.reset(new Materializer()); - m_expr_decl_map.reset(new ClangExpressionDeclMap(keep_result_in_memory, exe_ctx)); + ResetDeclMap(exe_ctx, keep_result_in_memory); class OnExit { @@ -545,13 +442,13 @@ ClangUserExpression::Parse (Stream &error_stream, Callback m_callback; }; - OnExit on_exit([this]() { m_expr_decl_map.reset(); }); + OnExit on_exit([this]() { ResetDeclMap(); }); - if (!m_expr_decl_map->WillParse(exe_ctx, m_materializer_ap.get())) + if (!DeclMap()->WillParse(exe_ctx, m_materializer_ap.get())) { error_stream.PutCString ("error: current process state is unsuitable for expression parsing\n"); - m_expr_decl_map.reset(); // We are being careful here in the case of breakpoint conditions. + ResetDeclMap(); // We are being careful here in the case of breakpoint conditions. return false; } @@ -570,7 +467,7 @@ ClangUserExpression::Parse (Stream &error_stream, { error_stream.Printf ("error: %d errors parsing expression\n", num_errors); - m_expr_decl_map.reset(); // We are being careful here in the case of breakpoint conditions. + ResetDeclMap(); // We are being careful here in the case of breakpoint conditions. return false; } @@ -617,7 +514,7 @@ ClangUserExpression::Parse (Stream &error_stream, // } } - m_expr_decl_map.reset(); // Make this go away since we don't need any of its state after parsing. This also gets rid of any ClangASTImporter::Minions. + ResetDeclMap(); // Make this go away since we don't need any of its state after parsing. This also gets rid of any ClangASTImporter::Minions. if (jit_error.Success()) { @@ -636,537 +533,81 @@ ClangUserExpression::Parse (Stream &error_stream, } } -static lldb::addr_t -GetObjectPointer (lldb::StackFrameSP frame_sp, - ConstString &object_name, - Error &err) -{ - err.Clear(); - - if (!frame_sp) - { - err.SetErrorStringWithFormat("Couldn't load '%s' because the context is incomplete", object_name.AsCString()); - return LLDB_INVALID_ADDRESS; - } - - lldb::VariableSP var_sp; - lldb::ValueObjectSP valobj_sp; - - valobj_sp = frame_sp->GetValueForVariableExpressionPath(object_name.AsCString(), - lldb::eNoDynamicValues, - StackFrame::eExpressionPathOptionCheckPtrVsMember | - StackFrame::eExpressionPathOptionsNoFragileObjcIvar | - StackFrame::eExpressionPathOptionsNoSyntheticChildren | - StackFrame::eExpressionPathOptionsNoSyntheticArrayRange, - var_sp, - err); - - if (!err.Success() || !valobj_sp.get()) - return LLDB_INVALID_ADDRESS; - - lldb::addr_t ret = valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); - - if (ret == LLDB_INVALID_ADDRESS) - { - err.SetErrorStringWithFormat("Couldn't load '%s' because its value couldn't be evaluated", object_name.AsCString()); - return LLDB_INVALID_ADDRESS; - } - - return ret; -} - bool -ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream, - ExecutionContext &exe_ctx, - lldb::addr_t &struct_address, - lldb::addr_t &object_ptr, - lldb::addr_t &cmd_ptr) +ClangUserExpression::AddInitialArguments (ExecutionContext &exe_ctx, + std::vector<lldb::addr_t> &args, + Stream &error_stream) { - lldb::TargetSP target; - lldb::ProcessSP process; - lldb::StackFrameSP frame; - - if (!LockAndCheckContext(exe_ctx, - target, - process, - frame)) - { - error_stream.Printf("The context has changed before we could JIT the expression!\n"); - return false; - } - - if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret) + lldb::addr_t object_ptr = LLDB_INVALID_ADDRESS; + lldb::addr_t cmd_ptr = LLDB_INVALID_ADDRESS; + + if (m_needs_object_ptr) { - if (m_needs_object_ptr) - { - ConstString object_name; - - if (m_in_cplusplus_method) - { - object_name.SetCString("this"); - } - else if (m_in_objectivec_method) - { - object_name.SetCString("self"); - } - else - { - error_stream.Printf("Need object pointer but don't know the language\n"); - return false; - } - - Error object_ptr_error; - - object_ptr = GetObjectPointer(frame, object_name, object_ptr_error); - - if (!object_ptr_error.Success()) - { - error_stream.Printf("warning: couldn't get required object pointer (substituting NULL): %s\n", object_ptr_error.AsCString()); - object_ptr = 0; - } - - if (m_in_objectivec_method) - { - ConstString cmd_name("_cmd"); - - cmd_ptr = GetObjectPointer(frame, cmd_name, object_ptr_error); - - if (!object_ptr_error.Success()) - { - error_stream.Printf("warning: couldn't get cmd pointer (substituting NULL): %s\n", object_ptr_error.AsCString()); - cmd_ptr = 0; - } - } - } + lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP(); + if (!frame_sp) + return true; + + ConstString object_name; - if (m_materialized_address == LLDB_INVALID_ADDRESS) + if (m_in_cplusplus_method) { - Error alloc_error; - - IRMemoryMap::AllocationPolicy policy = m_can_interpret ? IRMemoryMap::eAllocationPolicyHostOnly : IRMemoryMap::eAllocationPolicyMirror; - - m_materialized_address = m_execution_unit_sp->Malloc(m_materializer_ap->GetStructByteSize(), - m_materializer_ap->GetStructAlignment(), - lldb::ePermissionsReadable | lldb::ePermissionsWritable, - policy, - alloc_error); - - if (!alloc_error.Success()) - { - error_stream.Printf("Couldn't allocate space for materialized struct: %s\n", alloc_error.AsCString()); - return false; - } + object_name.SetCString("this"); } - - struct_address = m_materialized_address; - - if (m_can_interpret && m_stack_frame_bottom == LLDB_INVALID_ADDRESS) + else if (m_in_objectivec_method) { - Error alloc_error; - - const size_t stack_frame_size = 512 * 1024; - - m_stack_frame_bottom = m_execution_unit_sp->Malloc(stack_frame_size, - 8, - lldb::ePermissionsReadable | lldb::ePermissionsWritable, - IRMemoryMap::eAllocationPolicyHostOnly, - alloc_error); - - m_stack_frame_top = m_stack_frame_bottom + stack_frame_size; - - if (!alloc_error.Success()) - { - error_stream.Printf("Couldn't allocate space for the stack frame: %s\n", alloc_error.AsCString()); - return false; - } + object_name.SetCString("self"); } - - Error materialize_error; - - m_dematerializer_sp = m_materializer_ap->Materialize(frame, *m_execution_unit_sp, struct_address, materialize_error); - - if (!materialize_error.Success()) + else { - error_stream.Printf("Couldn't materialize: %s\n", materialize_error.AsCString()); + error_stream.Printf("Need object pointer but don't know the language\n"); return false; } - } - return true; -} - -bool -ClangUserExpression::FinalizeJITExecution (Stream &error_stream, - ExecutionContext &exe_ctx, - lldb::ExpressionVariableSP &result, - lldb::addr_t function_stack_bottom, - lldb::addr_t function_stack_top) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - if (log) - log->Printf("-- [ClangUserExpression::FinalizeJITExecution] Dematerializing after execution --"); - if (!m_dematerializer_sp) - { - error_stream.Printf ("Couldn't apply expression side effects : no dematerializer is present"); - return false; - } - - Error dematerialize_error; - - m_dematerializer_sp->Dematerialize(dematerialize_error, result, function_stack_bottom, function_stack_top); - - if (!dematerialize_error.Success()) - { - error_stream.Printf ("Couldn't apply expression side effects : %s\n", dematerialize_error.AsCString("unknown error")); - return false; - } - - if (result) - result->TransferAddress(); - - m_dematerializer_sp.reset(); - - return true; -} - -lldb::ExpressionResults -ClangUserExpression::Execute (Stream &error_stream, - ExecutionContext &exe_ctx, - const EvaluateExpressionOptions& options, - lldb::ClangUserExpressionSP &shared_ptr_to_me, - lldb::ExpressionVariableSP &result) -{ - // The expression log is quite verbose, and if you're just tracking the execution of the - // expression, it's quite convenient to have these logs come out with the STEP log as well. - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); - - if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret) - { - lldb::addr_t struct_address = LLDB_INVALID_ADDRESS; + Error object_ptr_error; - lldb::addr_t object_ptr = 0; - lldb::addr_t cmd_ptr = 0; + object_ptr = GetObjectPointer(frame_sp, object_name, object_ptr_error); - if (!PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address, object_ptr, cmd_ptr)) + if (!object_ptr_error.Success()) { - error_stream.Printf("Errored out in %s, couldn't PrepareToExecuteJITExpression", __FUNCTION__); - return lldb::eExpressionSetupError; + error_stream.Printf("warning: couldn't get required object pointer (substituting NULL): %s\n", object_ptr_error.AsCString()); + object_ptr = 0; } - lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS; - lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS; - - if (m_can_interpret) + if (m_in_objectivec_method) { - llvm::Module *module = m_execution_unit_sp->GetModule(); - llvm::Function *function = m_execution_unit_sp->GetFunction(); - - if (!module || !function) - { - error_stream.Printf("Supposed to interpret, but nothing is there"); - return lldb::eExpressionSetupError; - } - - Error interpreter_error; - - llvm::SmallVector <lldb::addr_t, 3> args; - - if (m_needs_object_ptr) - { - args.push_back(object_ptr); + ConstString cmd_name("_cmd"); - if (m_in_objectivec_method) - args.push_back(cmd_ptr); - } - - args.push_back(struct_address); - - function_stack_bottom = m_stack_frame_bottom; - function_stack_top = m_stack_frame_top; - - IRInterpreter::Interpret (*module, - *function, - args, - *m_execution_unit_sp.get(), - interpreter_error, - function_stack_bottom, - function_stack_top, - exe_ctx); + cmd_ptr = GetObjectPointer(frame_sp, cmd_name, object_ptr_error); - if (!interpreter_error.Success()) + if (!object_ptr_error.Success()) { - error_stream.Printf("Supposed to interpret, but failed: %s", interpreter_error.AsCString()); - return lldb::eExpressionDiscarded; + error_stream.Printf("warning: couldn't get cmd pointer (substituting NULL): %s\n", object_ptr_error.AsCString()); + cmd_ptr = 0; } } - else - { - if (!exe_ctx.HasThreadScope()) - { - error_stream.Printf("ClangUserExpression::Execute called with no thread selected."); - return lldb::eExpressionSetupError; - } - - Address wrapper_address (m_jit_start_addr); - - llvm::SmallVector <lldb::addr_t, 3> args; - - if (m_needs_object_ptr) { - args.push_back(object_ptr); - if (m_in_objectivec_method) - args.push_back(cmd_ptr); - } - - args.push_back(struct_address); - - lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(), - wrapper_address, - args, - options, - shared_ptr_to_me)); - - if (!call_plan_sp || !call_plan_sp->ValidatePlan (&error_stream)) - return lldb::eExpressionSetupError; - - ThreadPlanCallUserExpression *user_expression_plan = static_cast<ThreadPlanCallUserExpression *>(call_plan_sp.get()); - - lldb::addr_t function_stack_pointer = user_expression_plan->GetFunctionStackPointer(); - - function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize(); - function_stack_top = function_stack_pointer; - - if (log) - log->Printf("-- [ClangUserExpression::Execute] Execution of expression begins --"); - - if (exe_ctx.GetProcessPtr()) - exe_ctx.GetProcessPtr()->SetRunningUserExpression(true); - - lldb::ExpressionResults execution_result = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx, - call_plan_sp, - options, - error_stream); - - if (exe_ctx.GetProcessPtr()) - exe_ctx.GetProcessPtr()->SetRunningUserExpression(false); - - if (log) - log->Printf("-- [ClangUserExpression::Execute] Execution of expression completed --"); + if (object_ptr) + args.push_back(object_ptr); - if (execution_result == lldb::eExpressionInterrupted || execution_result == lldb::eExpressionHitBreakpoint) - { - const char *error_desc = NULL; - - if (call_plan_sp) - { - lldb::StopInfoSP real_stop_info_sp = call_plan_sp->GetRealStopInfo(); - if (real_stop_info_sp) - error_desc = real_stop_info_sp->GetDescription(); - } - if (error_desc) - error_stream.Printf ("Execution was interrupted, reason: %s.", error_desc); - else - error_stream.PutCString ("Execution was interrupted."); - - if ((execution_result == lldb::eExpressionInterrupted && options.DoesUnwindOnError()) - || (execution_result == lldb::eExpressionHitBreakpoint && options.DoesIgnoreBreakpoints())) - error_stream.PutCString ("\nThe process has been returned to the state before expression evaluation."); - else - { - if (execution_result == lldb::eExpressionHitBreakpoint) - user_expression_plan->TransferExpressionOwnership(); - error_stream.PutCString ("\nThe process has been left at the point where it was interrupted, " - "use \"thread return -x\" to return to the state before expression evaluation."); - } + if (m_in_objectivec_method) + args.push_back(cmd_ptr); - return execution_result; - } - else if (execution_result == lldb::eExpressionStoppedForDebug) - { - error_stream.PutCString ("Execution was halted at the first instruction of the expression " - "function because \"debug\" was requested.\n" - "Use \"thread return -x\" to return to the state before expression evaluation."); - return execution_result; - } - else if (execution_result != lldb::eExpressionCompleted) - { - error_stream.Printf ("Couldn't execute function; result was %s\n", Process::ExecutionResultAsCString (execution_result)); - return execution_result; - } - } - if (FinalizeJITExecution (error_stream, exe_ctx, result, function_stack_bottom, function_stack_top)) - { - return lldb::eExpressionCompleted; - } - else - { - return lldb::eExpressionResultUnavailable; - } - } - else - { - error_stream.Printf("Expression can't be run, because there is no JIT compiled function"); - return lldb::eExpressionSetupError; } + return true; } -lldb::ExpressionResults -ClangUserExpression::Evaluate (ExecutionContext &exe_ctx, - const EvaluateExpressionOptions& options, - const char *expr_cstr, - const char *expr_prefix, - lldb::ValueObjectSP &result_valobj_sp, - Error &error) +void +ClangUserExpression::ClangUserExpressionHelper::ResetDeclMap(ExecutionContext &exe_ctx, bool keep_result_in_memory) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); - - lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy(); - const lldb::LanguageType language = options.GetLanguage(); - const ResultType desired_type = options.DoesCoerceToId() ? ClangUserExpression::eResultTypeId : ClangUserExpression::eResultTypeAny; - lldb::ExpressionResults execution_results = lldb::eExpressionSetupError; - - Process *process = exe_ctx.GetProcessPtr(); - - if (process == NULL || process->GetState() != lldb::eStateStopped) - { - if (execution_policy == eExecutionPolicyAlways) - { - if (log) - log->Printf("== [ClangUserExpression::Evaluate] Expression may not run, but is not constant =="); - - error.SetErrorString ("expression needed to run but couldn't"); - - return execution_results; - } - } - - if (process == NULL || !process->CanJIT()) - execution_policy = eExecutionPolicyNever; - - const char *full_prefix = NULL; - const char *option_prefix = options.GetPrefix(); - std::string full_prefix_storage; - if (expr_prefix && option_prefix) - { - full_prefix_storage.assign(expr_prefix); - full_prefix_storage.append(option_prefix); - if (!full_prefix_storage.empty()) - full_prefix = full_prefix_storage.c_str(); - } - else if (expr_prefix) - full_prefix = expr_prefix; - else - full_prefix = option_prefix; - - lldb::ClangUserExpressionSP user_expression_sp (new ClangUserExpression (expr_cstr, full_prefix, language, desired_type)); - - StreamString error_stream; - - if (log) - log->Printf("== [ClangUserExpression::Evaluate] Parsing expression %s ==", expr_cstr); - - const bool keep_expression_in_memory = true; - const bool generate_debug_info = options.GetGenerateDebugInfo(); - - if (options.InvokeCancelCallback (lldb::eExpressionEvaluationParse)) - { - error.SetErrorString ("expression interrupted by callback before parse"); - result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); - return lldb::eExpressionInterrupted; - } - - if (!user_expression_sp->Parse (error_stream, - exe_ctx, - execution_policy, - keep_expression_in_memory, - generate_debug_info)) - { - execution_results = lldb::eExpressionParseError; - if (error_stream.GetString().empty()) - error.SetExpressionError (execution_results, "expression failed to parse, unknown error"); - else - error.SetExpressionError (execution_results, error_stream.GetString().c_str()); - } - else - { - lldb::ExpressionVariableSP expr_result; - - if (execution_policy == eExecutionPolicyNever && - !user_expression_sp->CanInterpret()) - { - if (log) - log->Printf("== [ClangUserExpression::Evaluate] Expression may not run, but is not constant =="); - - if (error_stream.GetString().empty()) - error.SetExpressionError (lldb::eExpressionSetupError, "expression needed to run but couldn't"); - } - else - { - if (options.InvokeCancelCallback (lldb::eExpressionEvaluationExecution)) - { - error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback before execution"); - result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); - return lldb::eExpressionInterrupted; - } - - error_stream.GetString().clear(); - - if (log) - log->Printf("== [ClangUserExpression::Evaluate] Executing expression =="); - - execution_results = user_expression_sp->Execute (error_stream, - exe_ctx, - options, - user_expression_sp, - expr_result); - - if (options.GetResultIsInternal() && expr_result && process) - { - process->GetTarget().GetPersistentVariables().RemovePersistentVariable (expr_result); - } - - if (execution_results != lldb::eExpressionCompleted) - { - if (log) - log->Printf("== [ClangUserExpression::Evaluate] Execution completed abnormally =="); - - if (error_stream.GetString().empty()) - error.SetExpressionError (execution_results, "expression failed to execute, unknown error"); - else - error.SetExpressionError (execution_results, error_stream.GetString().c_str()); - } - else - { - if (expr_result) - { - result_valobj_sp = expr_result->GetValueObject(); - - if (log) - log->Printf("== [ClangUserExpression::Evaluate] Execution completed normally with result %s ==", - result_valobj_sp->GetValueAsCString()); - } - else - { - if (log) - log->Printf("== [ClangUserExpression::Evaluate] Execution completed normally with no result =="); - - error.SetError(ClangUserExpression::kNoResult, lldb::eErrorTypeGeneric); - } - } - } - } - - if (options.InvokeCancelCallback(lldb::eExpressionEvaluationComplete)) - { - error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback after complete"); - return lldb::eExpressionInterrupted; - } + m_expr_decl_map_up.reset(new ClangExpressionDeclMap(keep_result_in_memory, exe_ctx)); +} - if (result_valobj_sp.get() == NULL) - { - result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); - } +clang::ASTConsumer * +ClangUserExpression::ClangUserExpressionHelper::ASTTransformer (clang::ASTConsumer *passthrough) +{ + m_result_synthesizer_up.reset(new ASTResultSynthesizer(passthrough, + m_target)); - return execution_results; + return m_result_synthesizer_up.get(); } + diff --git a/lldb/source/Expression/ClangUtilityFunction.cpp b/lldb/source/Expression/ClangUtilityFunction.cpp index de5b0c1b03f..2a07a428803 100644 --- a/lldb/source/Expression/ClangUtilityFunction.cpp +++ b/lldb/source/Expression/ClangUtilityFunction.cpp @@ -40,29 +40,15 @@ using namespace lldb_private; /// @param[in] name /// The name of the function, as used in the text. //------------------------------------------------------------------ -ClangUtilityFunction::ClangUtilityFunction (const char *text, +ClangUtilityFunction::ClangUtilityFunction (ExecutionContextScope &exe_scope, + const char *text, const char *name) : - ClangExpression (), - m_expr_decl_map (), - m_execution_unit_sp (), - m_jit_module_wp (), - m_function_text (ExpressionSourceCode::g_expression_prefix), - m_function_name (name) + UtilityFunction (exe_scope, text, name) { - if (text && text[0]) - m_function_text.append (text); } ClangUtilityFunction::~ClangUtilityFunction () { - lldb::ProcessSP process_sp (m_jit_process_wp.lock()); - if (process_sp) - { - lldb::ModuleSP jit_module_sp (m_jit_module_wp.lock()); - if (jit_module_sp) - process_sp->GetTarget().GetImages().Remove(jit_module_sp); - } - } //------------------------------------------------------------------ @@ -113,9 +99,9 @@ ClangUtilityFunction::Install (Stream &error_stream, bool keep_result_in_memory = false; - m_expr_decl_map.reset(new ClangExpressionDeclMap(keep_result_in_memory, exe_ctx)); + ResetDeclMap(exe_ctx, keep_result_in_memory); - if (!m_expr_decl_map->WillParse(exe_ctx, NULL)) + if (!DeclMap()->WillParse(exe_ctx, NULL)) { error_stream.PutCString ("error: current process state is unsuitable for expression parsing\n"); return false; @@ -130,7 +116,7 @@ ClangUtilityFunction::Install (Stream &error_stream, { error_stream.Printf ("error: %d errors parsing expression\n", num_errors); - m_expr_decl_map.reset(); + ResetDeclMap(); return false; } @@ -176,9 +162,9 @@ ClangUtilityFunction::Install (Stream &error_stream, m_function_text.c_str()); #endif - m_expr_decl_map->DidParse(); + DeclMap()->DidParse(); - m_expr_decl_map.reset(); + ResetDeclMap(); if (jit_error.Success()) { @@ -195,4 +181,8 @@ ClangUtilityFunction::Install (Stream &error_stream, } } - +void +ClangUtilityFunction::ClangUtilityFunctionHelper::ResetDeclMap(ExecutionContext &exe_ctx, bool keep_result_in_memory) +{ + m_expr_decl_map_up.reset(new ClangExpressionDeclMap(keep_result_in_memory, exe_ctx)); +} diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp new file mode 100644 index 00000000000..e5dd9c03db7 --- /dev/null +++ b/lldb/source/Expression/Expression.cpp @@ -0,0 +1,32 @@ +//===-- Expression.h ---------------------------------------*- 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/Expression.h" +#include "lldb/Target/ExecutionContextScope.h" +#include "lldb/Target/Target.h" + +using namespace lldb_private; + +Expression::Expression (Target &target) : + m_target_wp (target.shared_from_this()), + m_jit_start_addr (LLDB_INVALID_ADDRESS), + m_jit_end_addr (LLDB_INVALID_ADDRESS) +{ + // Can't make any kind of expression without a target. + assert (m_target_wp.lock()); +} + +Expression::Expression (ExecutionContextScope &exe_scope) : + m_target_wp (exe_scope.CalculateTarget()), + m_jit_start_addr (LLDB_INVALID_ADDRESS), + m_jit_end_addr (LLDB_INVALID_ADDRESS) +{ + assert (m_target_wp.lock()); +} + diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/FunctionCaller.cpp index 3798c212059..acfc71c146e 100644 --- a/lldb/source/Expression/ClangFunction.cpp +++ b/lldb/source/Expression/FunctionCaller.cpp @@ -1,4 +1,4 @@ -//===-- ClangFunction.cpp ---------------------------------------*- C++ -*-===// +//===-- FunctionCaller.cpp ---------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -30,7 +30,7 @@ #include "lldb/Core/ValueObjectList.h" #include "lldb/Expression/ASTStructExtractor.h" #include "lldb/Expression/ClangExpressionParser.h" -#include "lldb/Expression/ClangFunction.h" +#include "lldb/Expression/FunctionCaller.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Symbol/ClangASTContext.h" @@ -47,9 +47,9 @@ using namespace lldb_private; //---------------------------------------------------------------------- -// ClangFunction constructor +// FunctionCaller constructor //---------------------------------------------------------------------- -ClangFunction::ClangFunction +FunctionCaller::FunctionCaller ( ExecutionContextScope &exe_scope, const CompilerType &return_type, @@ -57,6 +57,7 @@ ClangFunction::ClangFunction const ValueList &arg_value_list, const char *name ) : + Expression (exe_scope), m_execution_unit_sp(), m_parser(), m_jit_module_wp(), @@ -72,41 +73,14 @@ ClangFunction::ClangFunction m_JITted (false) { m_jit_process_wp = lldb::ProcessWP(exe_scope.CalculateProcess()); - // Can't make a ClangFunction without a process. + // Can't make a FunctionCaller without a process. assert (m_jit_process_wp.lock()); } -ClangFunction::ClangFunction -( - ExecutionContextScope &exe_scope, - Function &function, - ClangASTContext *ast_context, - const ValueList &arg_value_list, - const char *name -) : - m_name (name ? name : "<unknown>"), - m_function_ptr (&function), - m_function_addr (), - m_function_return_type (), - m_wrapper_function_name ("__lldb_function_caller"), - m_wrapper_struct_name ("__lldb_caller_struct"), - m_wrapper_args_addrs (), - m_arg_values (arg_value_list), - m_compiled (false), - m_JITted (false) -{ - m_jit_process_wp = exe_scope.CalculateProcess(); - // Can't make a ClangFunction without a process. - assert (m_jit_process_wp.lock()); - - m_function_addr = m_function_ptr->GetAddressRange().GetBaseAddress(); - m_function_return_type = m_function_ptr->GetCompilerType().GetFunctionReturnType(); -} - //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -ClangFunction::~ClangFunction() +FunctionCaller::~FunctionCaller() { lldb::ProcessSP process_sp (m_jit_process_wp.lock()); if (process_sp) @@ -117,147 +91,8 @@ ClangFunction::~ClangFunction() } } -unsigned -ClangFunction::CompileFunction (Stream &errors) -{ - if (m_compiled) - return 0; - - // FIXME: How does clang tell us there's no return value? We need to handle that case. - unsigned num_errors = 0; - - std::string return_type_str (m_function_return_type.GetTypeName().AsCString("")); - - // Cons up the function we're going to wrap our call in, then compile it... - // We declare the function "extern "C"" because the compiler might be in C++ - // mode which would mangle the name and then we couldn't find it again... - m_wrapper_function_text.clear(); - m_wrapper_function_text.append ("extern \"C\" void "); - m_wrapper_function_text.append (m_wrapper_function_name); - m_wrapper_function_text.append (" (void *input)\n{\n struct "); - m_wrapper_function_text.append (m_wrapper_struct_name); - m_wrapper_function_text.append (" \n {\n"); - m_wrapper_function_text.append (" "); - m_wrapper_function_text.append (return_type_str); - m_wrapper_function_text.append (" (*fn_ptr) ("); - - // Get the number of arguments. If we have a function type and it is prototyped, - // trust that, otherwise use the values we were given. - - // FIXME: This will need to be extended to handle Variadic functions. We'll need - // to pull the defined arguments out of the function, then add the types from the - // arguments list for the variable arguments. - - uint32_t num_args = UINT32_MAX; - bool trust_function = false; - // GetArgumentCount returns -1 for an unprototyped function. - CompilerType function_clang_type; - if (m_function_ptr) - { - function_clang_type = m_function_ptr->GetCompilerType(); - if (function_clang_type) - { - int num_func_args = function_clang_type.GetFunctionArgumentCount(); - if (num_func_args >= 0) - { - trust_function = true; - num_args = num_func_args; - } - } - } - - if (num_args == UINT32_MAX) - num_args = m_arg_values.GetSize(); - - std::string args_buffer; // This one stores the definition of all the args in "struct caller". - std::string args_list_buffer; // This one stores the argument list called from the structure. - for (size_t i = 0; i < num_args; i++) - { - std::string type_name; - - if (trust_function) - { - type_name = function_clang_type.GetFunctionArgumentTypeAtIndex(i).GetTypeName().AsCString(""); - } - else - { - CompilerType clang_qual_type = m_arg_values.GetValueAtIndex(i)->GetCompilerType (); - if (clang_qual_type) - { - type_name = clang_qual_type.GetTypeName().AsCString(""); - } - else - { - errors.Printf("Could not determine type of input value %" PRIu64 ".", (uint64_t)i); - return 1; - } - } - - m_wrapper_function_text.append (type_name); - if (i < num_args - 1) - m_wrapper_function_text.append (", "); - - char arg_buf[32]; - args_buffer.append (" "); - args_buffer.append (type_name); - snprintf(arg_buf, 31, "arg_%" PRIu64, (uint64_t)i); - args_buffer.push_back (' '); - args_buffer.append (arg_buf); - args_buffer.append (";\n"); - - args_list_buffer.append ("__lldb_fn_data->"); - args_list_buffer.append (arg_buf); - if (i < num_args - 1) - args_list_buffer.append (", "); - - } - m_wrapper_function_text.append (");\n"); // Close off the function calling prototype. - - m_wrapper_function_text.append (args_buffer); - - m_wrapper_function_text.append (" "); - m_wrapper_function_text.append (return_type_str); - m_wrapper_function_text.append (" return_value;"); - m_wrapper_function_text.append ("\n };\n struct "); - m_wrapper_function_text.append (m_wrapper_struct_name); - m_wrapper_function_text.append ("* __lldb_fn_data = (struct "); - m_wrapper_function_text.append (m_wrapper_struct_name); - m_wrapper_function_text.append (" *) input;\n"); - - m_wrapper_function_text.append (" __lldb_fn_data->return_value = __lldb_fn_data->fn_ptr ("); - m_wrapper_function_text.append (args_list_buffer); - m_wrapper_function_text.append (");\n}\n"); - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - if (log) - log->Printf ("Expression: \n\n%s\n\n", m_wrapper_function_text.c_str()); - - // Okay, now compile this expression - - lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock()); - if (jit_process_sp) - { - const bool generate_debug_info = true; - m_parser.reset(new ClangExpressionParser(jit_process_sp.get(), *this, generate_debug_info)); - - num_errors = m_parser->Parse (errors); - } - else - { - errors.Printf("no process - unable to inject function"); - num_errors = 1; - } - - m_compiled = (num_errors == 0); - - if (!m_compiled) - return num_errors; - - return num_errors; -} - bool -ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors) +FunctionCaller::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors) { Process *process = exe_ctx.GetProcessPtr(); @@ -310,18 +145,17 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors) } bool -ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, Stream &errors) +FunctionCaller::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, Stream &errors) { - return WriteFunctionArguments(exe_ctx, args_addr_ref, m_function_addr, m_arg_values, errors); + return WriteFunctionArguments(exe_ctx, args_addr_ref, m_arg_values, errors); } // FIXME: Assure that the ValueList we were passed in is consistent with the one that defined this function. bool -ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, +FunctionCaller::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, - Address function_address, - ValueList &arg_values, + ValueList &arg_values, Stream &errors) { // All the information to reconstruct the struct is provided by the @@ -363,7 +197,7 @@ ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, } // TODO: verify fun_addr needs to be a callable address - Scalar fun_addr (function_address.GetCallableLoadAddress(exe_ctx.GetTargetPtr())); + Scalar fun_addr (m_function_addr.GetCallableLoadAddress(exe_ctx.GetTargetPtr())); uint64_t first_offset = m_member_offsets[0]; process->WriteScalarToMemory(args_addr_ref + first_offset, fun_addr, process->GetAddressByteSize(), error); @@ -404,7 +238,7 @@ ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, } bool -ClangFunction::InsertFunction (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, Stream &errors) +FunctionCaller::InsertFunction (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, Stream &errors) { using namespace clang; @@ -423,7 +257,7 @@ ClangFunction::InsertFunction (ExecutionContext &exe_ctx, lldb::addr_t &args_add } lldb::ThreadPlanSP -ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, +FunctionCaller::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, lldb::addr_t args_addr, const EvaluateExpressionOptions &options, Stream &errors) @@ -431,7 +265,7 @@ ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); if (log) - log->Printf("-- [ClangFunction::GetThreadPlanToCallFunction] Creating thread plan to call function \"%s\" --", m_name.c_str()); + log->Printf("-- [FunctionCaller::GetThreadPlanToCallFunction] Creating thread plan to call function \"%s\" --", m_name.c_str()); // FIXME: Use the errors Stream for better error reporting. Thread *thread = exe_ctx.GetThreadPtr(); @@ -458,7 +292,7 @@ ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, } bool -ClangFunction::FetchFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t args_addr, Value &ret_value) +FunctionCaller::FetchFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t args_addr, Value &ret_value) { // Read the return value - it is the last field in the struct: // FIXME: How does clang tell us there's no return value? We need to handle that case. @@ -468,7 +302,7 @@ ClangFunction::FetchFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t arg Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); if (log) - log->Printf("-- [ClangFunction::FetchFunctionResults] Fetching function results for \"%s\"--", m_name.c_str()); + log->Printf("-- [FunctionCaller::FetchFunctionResults] Fetching function results for \"%s\"--", m_name.c_str()); Process *process = exe_ctx.GetProcessPtr(); @@ -492,7 +326,7 @@ ClangFunction::FetchFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t arg } void -ClangFunction::DeallocateFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t args_addr) +FunctionCaller::DeallocateFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t args_addr) { std::list<lldb::addr_t>::iterator pos; pos = std::find(m_wrapper_args_addrs.begin(), m_wrapper_args_addrs.end(), args_addr); @@ -503,7 +337,7 @@ ClangFunction::DeallocateFunctionResults (ExecutionContext &exe_ctx, lldb::addr_ } lldb::ExpressionResults -ClangFunction::ExecuteFunction( +FunctionCaller::ExecuteFunction( ExecutionContext &exe_ctx, lldb::addr_t *args_addr_ptr, const EvaluateExpressionOptions &options, @@ -513,7 +347,7 @@ ClangFunction::ExecuteFunction( using namespace clang; lldb::ExpressionResults return_value = lldb::eExpressionSetupError; - // ClangFunction::ExecuteFunction execution is always just to get the result. Do make sure we ignore + // FunctionCaller::ExecuteFunction execution is always just to get the result. Do make sure we ignore // breakpoints, unwind on error, and don't try to debug it. EvaluateExpressionOptions real_options = options; real_options.SetDebug(false); @@ -539,7 +373,7 @@ ClangFunction::ExecuteFunction( Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); if (log) - log->Printf("== [ClangFunction::ExecuteFunction] Executing function \"%s\" ==", m_name.c_str()); + log->Printf("== [FunctionCaller::ExecuteFunction] Executing function \"%s\" ==", m_name.c_str()); lldb::ThreadPlanSP call_plan_sp = GetThreadPlanToCallFunction (exe_ctx, args_addr, @@ -562,11 +396,11 @@ ClangFunction::ExecuteFunction( { if (return_value != lldb::eExpressionCompleted) { - log->Printf("== [ClangFunction::ExecuteFunction] Execution of \"%s\" completed abnormally ==", m_name.c_str()); + log->Printf("== [FunctionCaller::ExecuteFunction] Execution of \"%s\" completed abnormally ==", m_name.c_str()); } else { - log->Printf("== [ClangFunction::ExecuteFunction] Execution of \"%s\" completed normally ==", m_name.c_str()); + log->Printf("== [FunctionCaller::ExecuteFunction] Execution of \"%s\" completed normally ==", m_name.c_str()); } } @@ -586,11 +420,3 @@ ClangFunction::ExecuteFunction( return lldb::eExpressionCompleted; } - -clang::ASTConsumer * -ClangFunction::ASTTransformer (clang::ASTConsumer *passthrough) -{ - m_struct_extractor.reset(new ASTStructExtractor(passthrough, m_wrapper_struct_name.c_str(), *this)); - - return m_struct_extractor.get(); -} diff --git a/lldb/source/Expression/IRDynamicChecks.cpp b/lldb/source/Expression/IRDynamicChecks.cpp index aa5d28bb8aa..5c8d0e5288b 100644 --- a/lldb/source/Expression/IRDynamicChecks.cpp +++ b/lldb/source/Expression/IRDynamicChecks.cpp @@ -11,11 +11,12 @@ #include "lldb/Core/ConstString.h" #include "lldb/Core/Log.h" -#include "lldb/Expression/ClangUtilityFunction.h" +#include "lldb/Expression/UtilityFunction.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/Process.h" #include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" #include "llvm/Support/raw_ostream.h" #include "llvm/IR/Constants.h" @@ -52,8 +53,14 @@ bool DynamicCheckerFunctions::Install(Stream &error_stream, ExecutionContext &exe_ctx) { - m_valid_pointer_check.reset(new ClangUtilityFunction(g_valid_pointer_check_text, - VALID_POINTER_CHECK_NAME)); + Error error; + m_valid_pointer_check.reset(exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage(g_valid_pointer_check_text, + lldb::eLanguageTypeC, + VALID_POINTER_CHECK_NAME, + error)); + if (error.Fail()) + return false; + if (!m_valid_pointer_check->Install(error_stream, exe_ctx)) return false; diff --git a/lldb/source/Expression/UserExpression.cpp b/lldb/source/Expression/UserExpression.cpp new file mode 100644 index 00000000000..547c02a1317 --- /dev/null +++ b/lldb/source/Expression/UserExpression.cpp @@ -0,0 +1,644 @@ +//===-- UserExpression.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <stdio.h> +#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#include <cstdlib> +#include <string> +#include <map> + +#include "lldb/Core/ConstString.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Expression/ASTResultSynthesizer.h" +#include "lldb/Expression/ClangExpressionDeclMap.h" +#include "lldb/Expression/ClangExpressionParser.h" +#include "lldb/Expression/ClangModulesDeclVendor.h" +#include "lldb/Expression/ClangPersistentVariables.h" +#include "lldb/Expression/ExpressionSourceCode.h" +#include "lldb/Expression/IRExecutionUnit.h" +#include "lldb/Expression/IRInterpreter.h" +#include "lldb/Expression/Materializer.h" +#include "lldb/Expression/UserExpression.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/Block.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Symbol/ClangExternalASTSourceCommon.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/ThreadPlan.h" +#include "lldb/Target/ThreadPlanCallUserExpression.h" + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" + +using namespace lldb_private; + +UserExpression::UserExpression (ExecutionContextScope &exe_scope, + const char *expr, + const char *expr_prefix, + lldb::LanguageType language, + ResultType desired_type) : + Expression (exe_scope), + m_stack_frame_bottom (LLDB_INVALID_ADDRESS), + m_stack_frame_top (LLDB_INVALID_ADDRESS), + m_expr_text (expr), + m_expr_prefix (expr_prefix ? expr_prefix : ""), + m_language (language), + m_transformed_text (), + m_desired_type (desired_type), + m_execution_unit_sp(), + m_materializer_ap(), + m_jit_module_wp(), + m_enforce_valid_object (true), + m_in_cplusplus_method (false), + m_in_objectivec_method (false), + m_in_static_method(false), + m_needs_object_ptr (false), + m_const_object (false), + m_target (NULL), + m_can_interpret (false), + m_materialized_address (LLDB_INVALID_ADDRESS) +{ +} + +UserExpression::~UserExpression () +{ + if (m_target) + { + lldb::ModuleSP jit_module_sp (m_jit_module_wp.lock()); + if (jit_module_sp) + m_target->GetImages().Remove(jit_module_sp); + } +} + +void +UserExpression::InstallContext (ExecutionContext &exe_ctx) +{ + m_jit_process_wp = exe_ctx.GetProcessSP(); + + lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP(); + + if (frame_sp) + m_address = frame_sp->GetFrameCodeAddress(); +} + +bool +UserExpression::LockAndCheckContext (ExecutionContext &exe_ctx, + lldb::TargetSP &target_sp, + lldb::ProcessSP &process_sp, + lldb::StackFrameSP &frame_sp) +{ + lldb::ProcessSP expected_process_sp = m_jit_process_wp.lock(); + process_sp = exe_ctx.GetProcessSP(); + + if (process_sp != expected_process_sp) + return false; + + process_sp = exe_ctx.GetProcessSP(); + target_sp = exe_ctx.GetTargetSP(); + frame_sp = exe_ctx.GetFrameSP(); + + if (m_address.IsValid()) + { + if (!frame_sp) + return false; + else + return (0 == Address::CompareLoadAddress(m_address, frame_sp->GetFrameCodeAddress(), target_sp.get())); + } + + return true; +} + +bool +UserExpression::MatchesContext (ExecutionContext &exe_ctx) +{ + lldb::TargetSP target_sp; + lldb::ProcessSP process_sp; + lldb::StackFrameSP frame_sp; + + return LockAndCheckContext(exe_ctx, target_sp, process_sp, frame_sp); +} + +lldb::addr_t +UserExpression::GetObjectPointer (lldb::StackFrameSP frame_sp, + ConstString &object_name, + Error &err) +{ + err.Clear(); + + if (!frame_sp) + { + err.SetErrorStringWithFormat("Couldn't load '%s' because the context is incomplete", object_name.AsCString()); + return LLDB_INVALID_ADDRESS; + } + + lldb::VariableSP var_sp; + lldb::ValueObjectSP valobj_sp; + + valobj_sp = frame_sp->GetValueForVariableExpressionPath(object_name.AsCString(), + lldb::eNoDynamicValues, + StackFrame::eExpressionPathOptionCheckPtrVsMember | + StackFrame::eExpressionPathOptionsNoFragileObjcIvar | + StackFrame::eExpressionPathOptionsNoSyntheticChildren | + StackFrame::eExpressionPathOptionsNoSyntheticArrayRange, + var_sp, + err); + + if (!err.Success() || !valobj_sp.get()) + return LLDB_INVALID_ADDRESS; + + lldb::addr_t ret = valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); + + if (ret == LLDB_INVALID_ADDRESS) + { + err.SetErrorStringWithFormat("Couldn't load '%s' because its value couldn't be evaluated", object_name.AsCString()); + return LLDB_INVALID_ADDRESS; + } + + return ret; +} + +bool +UserExpression::PrepareToExecuteJITExpression (Stream &error_stream, + ExecutionContext &exe_ctx, + lldb::addr_t &struct_address) +{ + lldb::TargetSP target; + lldb::ProcessSP process; + lldb::StackFrameSP frame; + + if (!LockAndCheckContext(exe_ctx, + target, + process, + frame)) + { + error_stream.Printf("The context has changed before we could JIT the expression!\n"); + return false; + } + + if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret) + { + if (m_materialized_address == LLDB_INVALID_ADDRESS) + { + Error alloc_error; + + IRMemoryMap::AllocationPolicy policy = m_can_interpret ? IRMemoryMap::eAllocationPolicyHostOnly : IRMemoryMap::eAllocationPolicyMirror; + + m_materialized_address = m_execution_unit_sp->Malloc(m_materializer_ap->GetStructByteSize(), + m_materializer_ap->GetStructAlignment(), + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + policy, + alloc_error); + + if (!alloc_error.Success()) + { + error_stream.Printf("Couldn't allocate space for materialized struct: %s\n", alloc_error.AsCString()); + return false; + } + } + + struct_address = m_materialized_address; + + if (m_can_interpret && m_stack_frame_bottom == LLDB_INVALID_ADDRESS) + { + Error alloc_error; + + const size_t stack_frame_size = 512 * 1024; + + m_stack_frame_bottom = m_execution_unit_sp->Malloc(stack_frame_size, + 8, + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + IRMemoryMap::eAllocationPolicyHostOnly, + alloc_error); + + m_stack_frame_top = m_stack_frame_bottom + stack_frame_size; + + if (!alloc_error.Success()) + { + error_stream.Printf("Couldn't allocate space for the stack frame: %s\n", alloc_error.AsCString()); + return false; + } + } + + Error materialize_error; + + m_dematerializer_sp = m_materializer_ap->Materialize(frame, *m_execution_unit_sp, struct_address, materialize_error); + + if (!materialize_error.Success()) + { + error_stream.Printf("Couldn't materialize: %s\n", materialize_error.AsCString()); + return false; + } + } + return true; +} + +bool +UserExpression::FinalizeJITExecution (Stream &error_stream, + ExecutionContext &exe_ctx, + lldb::ExpressionVariableSP &result, + lldb::addr_t function_stack_bottom, + lldb::addr_t function_stack_top) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + if (log) + log->Printf("-- [UserExpression::FinalizeJITExecution] Dematerializing after execution --"); + + if (!m_dematerializer_sp) + { + error_stream.Printf ("Couldn't apply expression side effects : no dematerializer is present"); + return false; + } + + Error dematerialize_error; + + m_dematerializer_sp->Dematerialize(dematerialize_error, result, function_stack_bottom, function_stack_top); + + if (!dematerialize_error.Success()) + { + error_stream.Printf ("Couldn't apply expression side effects : %s\n", dematerialize_error.AsCString("unknown error")); + return false; + } + + if (result) + result->TransferAddress(); + + m_dematerializer_sp.reset(); + + return true; +} + +lldb::ExpressionResults +UserExpression::Execute (Stream &error_stream, + ExecutionContext &exe_ctx, + const EvaluateExpressionOptions& options, + lldb::UserExpressionSP &shared_ptr_to_me, + lldb::ExpressionVariableSP &result) +{ + // The expression log is quite verbose, and if you're just tracking the execution of the + // expression, it's quite convenient to have these logs come out with the STEP log as well. + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); + + if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret) + { + lldb::addr_t struct_address = LLDB_INVALID_ADDRESS; + + if (!PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address)) + { + error_stream.Printf("Errored out in %s, couldn't PrepareToExecuteJITExpression", __FUNCTION__); + return lldb::eExpressionSetupError; + } + + lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS; + lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS; + + if (m_can_interpret) + { + llvm::Module *module = m_execution_unit_sp->GetModule(); + llvm::Function *function = m_execution_unit_sp->GetFunction(); + + if (!module || !function) + { + error_stream.Printf("Supposed to interpret, but nothing is there"); + return lldb::eExpressionSetupError; + } + + Error interpreter_error; + + std::vector<lldb::addr_t> args; + + if (!AddInitialArguments(exe_ctx, args, error_stream)) + { + error_stream.Printf ("Errored out in %s, couldn't AddInitialArguments", __FUNCTION__); + return lldb::eExpressionSetupError; + } + + args.push_back(struct_address); + + function_stack_bottom = m_stack_frame_bottom; + function_stack_top = m_stack_frame_top; + + IRInterpreter::Interpret (*module, + *function, + args, + *m_execution_unit_sp.get(), + interpreter_error, + function_stack_bottom, + function_stack_top, + exe_ctx); + + if (!interpreter_error.Success()) + { + error_stream.Printf("Supposed to interpret, but failed: %s", interpreter_error.AsCString()); + return lldb::eExpressionDiscarded; + } + } + else + { + if (!exe_ctx.HasThreadScope()) + { + error_stream.Printf("UserExpression::Execute called with no thread selected."); + return lldb::eExpressionSetupError; + } + + Address wrapper_address (m_jit_start_addr); + + std::vector<lldb::addr_t> args; + + if (!AddInitialArguments(exe_ctx, args, error_stream)) + { + error_stream.Printf ("Errored out in %s, couldn't AddInitialArguments", __FUNCTION__); + return lldb::eExpressionSetupError; + } + + args.push_back(struct_address); + + lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(), + wrapper_address, + args, + options, + shared_ptr_to_me)); + + if (!call_plan_sp || !call_plan_sp->ValidatePlan (&error_stream)) + return lldb::eExpressionSetupError; + + ThreadPlanCallUserExpression *user_expression_plan = static_cast<ThreadPlanCallUserExpression *>(call_plan_sp.get()); + + lldb::addr_t function_stack_pointer = user_expression_plan->GetFunctionStackPointer(); + + function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize(); + function_stack_top = function_stack_pointer; + + if (log) + log->Printf("-- [UserExpression::Execute] Execution of expression begins --"); + + if (exe_ctx.GetProcessPtr()) + exe_ctx.GetProcessPtr()->SetRunningUserExpression(true); + + lldb::ExpressionResults execution_result = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx, + call_plan_sp, + options, + error_stream); + + if (exe_ctx.GetProcessPtr()) + exe_ctx.GetProcessPtr()->SetRunningUserExpression(false); + + if (log) + log->Printf("-- [UserExpression::Execute] Execution of expression completed --"); + + if (execution_result == lldb::eExpressionInterrupted || execution_result == lldb::eExpressionHitBreakpoint) + { + const char *error_desc = NULL; + + if (call_plan_sp) + { + lldb::StopInfoSP real_stop_info_sp = call_plan_sp->GetRealStopInfo(); + if (real_stop_info_sp) + error_desc = real_stop_info_sp->GetDescription(); + } + if (error_desc) + error_stream.Printf ("Execution was interrupted, reason: %s.", error_desc); + else + error_stream.PutCString ("Execution was interrupted."); + + if ((execution_result == lldb::eExpressionInterrupted && options.DoesUnwindOnError()) + || (execution_result == lldb::eExpressionHitBreakpoint && options.DoesIgnoreBreakpoints())) + error_stream.PutCString ("\nThe process has been returned to the state before expression evaluation."); + else + { + if (execution_result == lldb::eExpressionHitBreakpoint) + user_expression_plan->TransferExpressionOwnership(); + error_stream.PutCString ("\nThe process has been left at the point where it was interrupted, " + "use \"thread return -x\" to return to the state before expression evaluation."); + } + + return execution_result; + } + else if (execution_result == lldb::eExpressionStoppedForDebug) + { + error_stream.PutCString ("Execution was halted at the first instruction of the expression " + "function because \"debug\" was requested.\n" + "Use \"thread return -x\" to return to the state before expression evaluation."); + return execution_result; + } + else if (execution_result != lldb::eExpressionCompleted) + { + error_stream.Printf ("Couldn't execute function; result was %s\n", Process::ExecutionResultAsCString (execution_result)); + return execution_result; + } + } + + if (FinalizeJITExecution (error_stream, exe_ctx, result, function_stack_bottom, function_stack_top)) + { + return lldb::eExpressionCompleted; + } + else + { + return lldb::eExpressionResultUnavailable; + } + } + else + { + error_stream.Printf("Expression can't be run, because there is no JIT compiled function"); + return lldb::eExpressionSetupError; + } +} + +lldb::ExpressionResults +UserExpression::Evaluate (ExecutionContext &exe_ctx, + const EvaluateExpressionOptions& options, + const char *expr_cstr, + const char *expr_prefix, + lldb::ValueObjectSP &result_valobj_sp, + Error &error) +{ + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); + + lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy(); + const lldb::LanguageType language = options.GetLanguage(); + const ResultType desired_type = options.DoesCoerceToId() ? UserExpression::eResultTypeId : UserExpression::eResultTypeAny; + lldb::ExpressionResults execution_results = lldb::eExpressionSetupError; + + Target *target = exe_ctx.GetTargetPtr(); + if (!target) + { + if (log) + log->Printf("== [UserExpression::Evaluate] Passed a NULL target, can't run expressions."); + return lldb::eExpressionSetupError; + } + + Process *process = exe_ctx.GetProcessPtr(); + + if (process == NULL || process->GetState() != lldb::eStateStopped) + { + if (execution_policy == eExecutionPolicyAlways) + { + if (log) + log->Printf("== [UserExpression::Evaluate] Expression may not run, but is not constant =="); + + error.SetErrorString ("expression needed to run but couldn't"); + + return execution_results; + } + } + + if (process == NULL || !process->CanJIT()) + execution_policy = eExecutionPolicyNever; + + const char *full_prefix = NULL; + const char *option_prefix = options.GetPrefix(); + std::string full_prefix_storage; + if (expr_prefix && option_prefix) + { + full_prefix_storage.assign(expr_prefix); + full_prefix_storage.append(option_prefix); + if (!full_prefix_storage.empty()) + full_prefix = full_prefix_storage.c_str(); + } + else if (expr_prefix) + full_prefix = expr_prefix; + else + full_prefix = option_prefix; + + lldb::UserExpressionSP user_expression_sp(target->GetUserExpressionForLanguage (expr_cstr, + full_prefix, + language, + desired_type, + error)); + if (error.Fail()) + { + if (log) + log->Printf ("== [UserExpression::Evaluate] Getting expression: %s ==", error.AsCString()); + return lldb::eExpressionSetupError; + } + + StreamString error_stream; + + if (log) + log->Printf("== [UserExpression::Evaluate] Parsing expression %s ==", expr_cstr); + + const bool keep_expression_in_memory = true; + const bool generate_debug_info = options.GetGenerateDebugInfo(); + + if (options.InvokeCancelCallback (lldb::eExpressionEvaluationParse)) + { + error.SetErrorString ("expression interrupted by callback before parse"); + result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); + return lldb::eExpressionInterrupted; + } + + if (!user_expression_sp->Parse (error_stream, + exe_ctx, + execution_policy, + keep_expression_in_memory, + generate_debug_info)) + { + execution_results = lldb::eExpressionParseError; + if (error_stream.GetString().empty()) + error.SetExpressionError (execution_results, "expression failed to parse, unknown error"); + else + error.SetExpressionError (execution_results, error_stream.GetString().c_str()); + } + else + { + lldb::ExpressionVariableSP expr_result; + + if (execution_policy == eExecutionPolicyNever && + !user_expression_sp->CanInterpret()) + { + if (log) + log->Printf("== [UserExpression::Evaluate] Expression may not run, but is not constant =="); + + if (error_stream.GetString().empty()) + error.SetExpressionError (lldb::eExpressionSetupError, "expression needed to run but couldn't"); + } + else + { + if (options.InvokeCancelCallback (lldb::eExpressionEvaluationExecution)) + { + error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback before execution"); + result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); + return lldb::eExpressionInterrupted; + } + + error_stream.GetString().clear(); + + if (log) + log->Printf("== [UserExpression::Evaluate] Executing expression =="); + + execution_results = user_expression_sp->Execute (error_stream, + exe_ctx, + options, + user_expression_sp, + expr_result); + + if (options.GetResultIsInternal() && expr_result && process) + { + process->GetTarget().GetPersistentVariables().RemovePersistentVariable (expr_result); + } + + if (execution_results != lldb::eExpressionCompleted) + { + if (log) + log->Printf("== [UserExpression::Evaluate] Execution completed abnormally =="); + + if (error_stream.GetString().empty()) + error.SetExpressionError (execution_results, "expression failed to execute, unknown error"); + else + error.SetExpressionError (execution_results, error_stream.GetString().c_str()); + } + else + { + if (expr_result) + { + result_valobj_sp = expr_result->GetValueObject(); + + if (log) + log->Printf("== [UserExpression::Evaluate] Execution completed normally with result %s ==", + result_valobj_sp->GetValueAsCString()); + } + else + { + if (log) + log->Printf("== [UserExpression::Evaluate] Execution completed normally with no result =="); + + error.SetError(UserExpression::kNoResult, lldb::eErrorTypeGeneric); + } + } + } + } + + if (options.InvokeCancelCallback(lldb::eExpressionEvaluationComplete)) + { + error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback after complete"); + return lldb::eExpressionInterrupted; + } + + if (result_valobj_sp.get() == NULL) + { + result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); + } + + return execution_results; +} diff --git a/lldb/source/Expression/UtilityFunction.cpp b/lldb/source/Expression/UtilityFunction.cpp new file mode 100644 index 00000000000..fad6e2f2568 --- /dev/null +++ b/lldb/source/Expression/UtilityFunction.cpp @@ -0,0 +1,123 @@ +//===-- 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 <stdio.h> +#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +// C++ Includes + +#include "lldb/Core/ConstString.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Expression/FunctionCaller.h" +#include "lldb/Expression/UtilityFunction.h" +#include "lldb/Expression/ExpressionSourceCode.h" +#include "lldb/Expression/IRExecutionUnit.h" +#include "lldb/Host/Host.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Target.h" + +using namespace lldb_private; +using namespace lldb; + +//------------------------------------------------------------------ +/// 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. +//------------------------------------------------------------------ +UtilityFunction::UtilityFunction (ExecutionContextScope &exe_scope, + const char *text, + const char *name) : + Expression (exe_scope), + m_execution_unit_sp (), + m_jit_module_wp (), + m_function_text (ExpressionSourceCode::g_expression_prefix), + m_function_name (name) +{ + if (text && text[0]) + m_function_text.append (text); +} + +UtilityFunction::~UtilityFunction () +{ + lldb::ProcessSP process_sp (m_jit_process_wp.lock()); + if (process_sp) + { + lldb::ModuleSP jit_module_sp (m_jit_module_wp.lock()); + if (jit_module_sp) + process_sp->GetTarget().GetImages().Remove(jit_module_sp); + } + +} + +// FIXME: We should check that every time this is called it is called with the same return type & arguments... + +FunctionCaller * +UtilityFunction::MakeFunctionCaller (const CompilerType &return_type, const ValueList &arg_value_list, Error &error) +{ + if (m_caller_up) + return m_caller_up.get(); + + ProcessSP process_sp = m_jit_process_wp.lock(); + if (!process_sp) + return nullptr; + + Address impl_code_address; + impl_code_address.SetOffset(StartAddress()); + std::string name(m_function_name); + name.append("-caller"); + + m_caller_up.reset (process_sp->GetTarget().GetFunctionCallerForLanguage (Language(), + return_type, + impl_code_address, + arg_value_list, + name.c_str(), + error)); + if (error.Fail()) + { + + return nullptr; + } + if (m_caller_up) + { + StreamString errors; + errors.Clear(); + unsigned num_errors = m_caller_up->CompileFunction(errors); + if (num_errors) + { + error.SetErrorStringWithFormat ("Error compiling %s caller function: \"%s\".", + m_function_name.c_str(), + errors.GetData()); + m_caller_up.reset(); + return nullptr; + } + + errors.Clear(); + ExecutionContext exe_ctx(process_sp); + + if (!m_caller_up->WriteFunctionWrapper(exe_ctx, errors)) + { + error.SetErrorStringWithFormat ("Error inserting caller function for %s: \"%s\".", + m_function_name.c_str(), + errors.GetData()); + m_caller_up.reset(); + return nullptr; + } + } + return m_caller_up.get(); +} |