diff --git a/lldb/include/lldb/Expression/ClangExpressionParser.h b/lldb/include/lldb/Expression/ClangExpressionParser.h index d462015648bb..7192d8e8de19 100644 --- a/lldb/include/lldb/Expression/ClangExpressionParser.h +++ b/lldb/include/lldb/Expression/ClangExpressionParser.h @@ -114,8 +114,7 @@ public: lldb::addr_t &func_end, STD_UNIQUE_PTR(IRExecutionUnit) &execution_unit_ap, ExecutionContext &exe_ctx, - bool &evaluated_statically, - lldb::ClangExpressionVariableSP &const_result, + bool &can_interpret, lldb_private::ExecutionPolicy execution_policy); //------------------------------------------------------------------ diff --git a/lldb/include/lldb/Expression/ClangUserExpression.h b/lldb/include/lldb/Expression/ClangUserExpression.h index 553722c2a710..51e00614e465 100644 --- a/lldb/include/lldb/Expression/ClangUserExpression.h +++ b/lldb/include/lldb/Expression/ClangUserExpression.h @@ -25,6 +25,7 @@ #include "lldb/Expression/ClangExpression.h" #include "lldb/Expression/ClangExpressionVariable.h" #include "lldb/Expression/IRForTarget.h" +#include "lldb/Expression/Materializer.h" #include "lldb/Symbol/TaggedASTType.h" #include "lldb/Target/ExecutionContext.h" @@ -105,6 +106,12 @@ public: lldb_private::ExecutionPolicy execution_policy, bool keep_result_in_memory); + bool + CanInterpret () + { + return m_can_interpret; + } + //------------------------------------------------------------------ /// Execute the parsed expression /// @@ -375,12 +382,6 @@ private: lldb::addr_t &object_ptr, lldb::addr_t &cmd_ptr); - bool - EvaluatedStatically () - { - return m_evaluated_statically; - } - void InstallContext (ExecutionContext &exe_ctx) { @@ -432,8 +433,9 @@ private: bool m_const_object; ///< True if "this" is const. Target *m_target; ///< The target for storing persistent data like types and variables. - bool m_evaluated_statically; ///< True if the expression could be evaluated statically; false otherwise. - lldb::ClangExpressionVariableSP m_const_result; ///< The statically-computed result of the expression. NULL if it could not be computed statically or the expression has side effects. + bool m_can_interpret; ///< True if the expression could be evaluated statically; false otherwise. + lldb::addr_t m_materialized_address; ///< The address at which the arguments to the expression have been materialized. + Materializer::DematerializerSP m_dematerializer_sp; ///< The dematerializer. }; } // namespace lldb_private diff --git a/lldb/include/lldb/Expression/IRForTarget.h b/lldb/include/lldb/Expression/IRForTarget.h index 49a1cb52cbf8..50bb5e7c5bb9 100644 --- a/lldb/include/lldb/Expression/IRForTarget.h +++ b/lldb/include/lldb/Expression/IRForTarget.h @@ -90,8 +90,6 @@ public: //------------------------------------------------------------------ IRForTarget(lldb_private::ClangExpressionDeclMap *decl_map, bool resolve_vars, - lldb_private::ExecutionPolicy execution_policy, - lldb::ClangExpressionVariableSP &const_result, lldb_private::IRExecutionUnit &execution_unit, lldb_private::Stream *error_stream, const char* func_name = "$__lldb_expr"); @@ -139,18 +137,6 @@ public: //------------------------------------------------------------------ virtual llvm::PassManagerType getPotentialPassManagerType() const; - - //------------------------------------------------------------------ - /// Checks whether the IR interpreter successfully interpreted the - /// expression. - /// - /// Returns true if it did; false otherwise. - //------------------------------------------------------------------ - lldb_private::Error & - getInterpreterError () - { - return m_interpreter_error; - } private: //------------------------------------------------------------------ @@ -664,8 +650,6 @@ private: /// Flags bool m_resolve_vars; ///< True if external variable references and persistent variable references should be resolved - lldb_private::ExecutionPolicy m_execution_policy; ///< True if the interpreter should be used to attempt to get a static result - bool m_interpret_success; ///< True if the interpreter successfully handled the whole expression std::string m_func_name; ///< The name of the function to translate lldb_private::ConstString m_result_name; ///< The name of the result variable ($0, $1, ...) lldb_private::TypeFromParser m_result_type; ///< The type of the result variable. @@ -676,9 +660,7 @@ private: lldb_private::IRMemoryMap &m_memory_map; ///< The memory map to pass to the IR interpreter llvm::Constant *m_CFStringCreateWithBytes; ///< The address of the function CFStringCreateWithBytes, cast to the appropriate function pointer type llvm::Constant *m_sel_registerName; ///< The address of the function sel_registerName, cast to the appropriate function pointer type - lldb::ClangExpressionVariableSP &m_const_result; ///< This value should be set to the return value of the expression if it is constant and the expression has no side effects lldb_private::Stream *m_error_stream; ///< If non-NULL, the stream on which errors should be printed - lldb_private::Error m_interpreter_error; ///< The error result from the IR interpreter bool m_has_side_effects; ///< True if the function's result cannot be simply determined statically llvm::StoreInst *m_result_store; ///< If non-NULL, the store instruction that writes to the result variable. If m_has_side_effects is true, this is NULL. diff --git a/lldb/include/lldb/Expression/IRInterpreter.h b/lldb/include/lldb/Expression/IRInterpreter.h index b7ee7f0d0f0e..c486444d7e02 100644 --- a/lldb/include/lldb/Expression/IRInterpreter.h +++ b/lldb/include/lldb/Expression/IRInterpreter.h @@ -14,6 +14,7 @@ #include "lldb/Core/ConstString.h" #include "lldb/Core/Stream.h" #include "lldb/Symbol/TaggedASTType.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/Pass.h" namespace llvm { @@ -88,6 +89,7 @@ public: static bool Interpret (llvm::Module &module, llvm::Function &function, + llvm::ArrayRef args, lldb_private::IRMemoryMap &memory_map, lldb_private::Error &error); diff --git a/lldb/include/lldb/Expression/Materializer.h b/lldb/include/lldb/Expression/Materializer.h index 58ad97fa16b2..2d96f99f9723 100644 --- a/lldb/include/lldb/Expression/Materializer.h +++ b/lldb/include/lldb/Expression/Materializer.h @@ -43,6 +43,7 @@ public: } void Dematerialize (Error &err, + lldb::ClangExpressionVariableSP &result_sp, lldb::addr_t frame_top, lldb::addr_t frame_bottom); @@ -75,11 +76,11 @@ public: typedef STD_SHARED_PTR(Dematerializer) DematerializerSP; typedef STD_WEAK_PTR(Dematerializer) DematerializerWP; - DematerializerSP Materialize (lldb::StackFrameSP &frame_sp, lldb::ClangExpressionVariableSP &result_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err); + DematerializerSP Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err); uint32_t AddPersistentVariable (lldb::ClangExpressionVariableSP &persistent_variable_sp, Error &err); uint32_t AddVariable (lldb::VariableSP &variable_sp, Error &err); - uint32_t AddResultVariable (const ClangASTType &type, bool keep_in_memory, Error &err); + uint32_t AddResultVariable (const TypeFromUser &type, bool is_lvalue, bool keep_in_memory, Error &err); uint32_t AddSymbol (const Symbol &symbol_sp, Error &err); uint32_t AddRegister (const RegisterInfo ®ister_info, Error &err); @@ -93,6 +94,14 @@ public: return m_current_offset; } + uint32_t GetResultOffset () + { + if (m_result_entity) + return m_result_entity->GetOffset(); + else + return UINT32_MAX; + } + class Entity { public: @@ -149,6 +158,7 @@ private: unsigned m_result_index; DematerializerWP m_dematerializer_wp; EntityVector m_entities; + Entity *m_result_entity; uint32_t m_current_offset; uint32_t m_struct_alignment; }; diff --git a/lldb/source/Expression/ClangExpressionDeclMap.cpp b/lldb/source/Expression/ClangExpressionDeclMap.cpp index ec2dbf6b8a03..ca7da77f7192 100644 --- a/lldb/source/Expression/ClangExpressionDeclMap.cpp +++ b/lldb/source/Expression/ClangExpressionDeclMap.cpp @@ -459,6 +459,51 @@ ClangExpressionDeclMap::AddPersistentVariable { assert (m_parser_vars.get()); + if (m_parser_vars->m_materializer && is_result) + { + Error err; + + ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx; + Target *target = exe_ctx.GetTargetPtr(); + if (target == NULL) + return false; + + ASTContext *context(target->GetScratchClangASTContext()->getASTContext()); + + TypeFromUser user_type(m_ast_importer->DeportType(context, + parser_type.GetASTContext(), + parser_type.GetOpaqueQualType()), + context); + + uint32_t offset = m_parser_vars->m_materializer->AddResultVariable(user_type, is_lvalue, m_keep_result_in_memory, err); + + m_found_entities.CreateVariable(exe_ctx.GetBestExecutionContextScope(), + name, + user_type, + m_parser_vars->m_target_info.byte_order, + m_parser_vars->m_target_info.address_byte_size); + + ClangExpressionVariableSP var_sp (m_found_entities.GetVariable(name)); + + if (!var_sp) + return false; + + var_sp->EnableParserVars(GetParserID()); + + ClangExpressionVariable::ParserVars *parser_vars = var_sp->GetParserVars(GetParserID()); + + parser_vars->m_named_decl = decl; + parser_vars->m_parser_type = parser_type; + + var_sp->EnableJITVars(GetParserID()); + + ClangExpressionVariable::JITVars *jit_vars = var_sp->GetJITVars(GetParserID()); + + jit_vars->m_offset = offset; + + return true; + } + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx; Target *target = exe_ctx.GetTargetPtr(); @@ -526,12 +571,6 @@ ClangExpressionDeclMap::AddPersistentVariable parser_vars->m_named_decl = decl; parser_vars->m_parser_type = parser_type; - if (m_parser_vars->m_materializer) - { - Error err; - m_parser_vars->m_materializer->AddResultVariable(user_type, m_keep_result_in_memory, err); - } - return true; } @@ -581,6 +620,14 @@ ClangExpressionDeclMap::AddValueToStruct parser_vars->m_llvm_value = value; + if (ClangExpressionVariable::JITVars *jit_vars = var_sp->GetJITVars(GetParserID())) + { + // We already laid this out; do not touch + + if (log) + log->Printf("Already placed at 0x%llx", (unsigned long long)jit_vars->m_offset); + } + var_sp->EnableJITVars(GetParserID()); ClangExpressionVariable::JITVars *jit_vars = var_sp->GetJITVars(GetParserID()); @@ -1593,7 +1640,9 @@ ClangExpressionDeclMap::DoMaterialize bool ret = true; - m_material_vars->m_dematerializer_sp->Dematerialize(dematerialize_error, stack_frame_top, stack_frame_bottom); + ClangExpressionVariableSP result; + + m_material_vars->m_dematerializer_sp->Dematerialize(dematerialize_error, result, stack_frame_top, stack_frame_bottom); m_material_vars->m_dematerializer_sp.reset(); if (!dematerialize_error.Success()) @@ -1663,7 +1712,7 @@ ClangExpressionDeclMap::DoMaterialize Error materialize_error; - m_material_vars->m_dematerializer_sp = m_parser_vars->m_materializer->Materialize(frame_sp, result_sp, map, m_material_vars->m_materialized_location, materialize_error); + m_material_vars->m_dematerializer_sp = m_parser_vars->m_materializer->Materialize(frame_sp, map, m_material_vars->m_materialized_location, materialize_error); if (!materialize_error.Success()) { diff --git a/lldb/source/Expression/ClangExpressionParser.cpp b/lldb/source/Expression/ClangExpressionParser.cpp index 2922898a0ca4..5e4b934822b8 100644 --- a/lldb/source/Expression/ClangExpressionParser.cpp +++ b/lldb/source/Expression/ClangExpressionParser.cpp @@ -22,6 +22,7 @@ #include "lldb/Expression/ClangExpressionDeclMap.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Expression/IRDynamicChecks.h" +#include "lldb/Expression/IRInterpreter.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/Process.h" @@ -464,8 +465,7 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, lldb::addr_t &func_end, STD_UNIQUE_PTR(IRExecutionUnit) &execution_unit_ap, ExecutionContext &exe_ctx, - bool &evaluated_statically, - lldb::ClangExpressionVariableSP &const_result, + bool &can_interpret, ExecutionPolicy execution_policy) { func_addr = LLDB_INVALID_ADDRESS; @@ -518,50 +518,39 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, IRForTarget ir_for_target(decl_map, m_expr.NeedsVariableResolution(), - execution_policy, - const_result, *m_execution_unit, error_stream, function_name.AsCString()); bool ir_can_run = ir_for_target.runOnModule(*m_execution_unit->GetModule()); - Error &interpreter_error(ir_for_target.getInterpreterError()); + Error interpret_error; - if (execution_policy != eExecutionPolicyAlways && interpreter_error.Success()) - { - if (const_result) - const_result->TransferAddress(); - evaluated_statically = true; - err.Clear(); - return err; - } + can_interpret = IRInterpreter::CanInterpret(*m_execution_unit->GetModule(), *m_execution_unit->GetFunction(), interpret_error); Process *process = exe_ctx.GetProcessPtr(); - - if (!process || execution_policy == eExecutionPolicyNever) + + if (!ir_can_run) { - err.SetErrorToGenericError(); - if (execution_policy == eExecutionPolicyAlways) - err.SetErrorString("Execution needed to run in the target, but the target can't be run"); - else - err.SetErrorStringWithFormat("Interpreting the expression locally failed: %s", interpreter_error.AsCString()); - - return err; - } - else if (!ir_can_run) - { - err.SetErrorToGenericError(); err.SetErrorString("The expression could not be prepared to run in the target"); - return err; } - if (execution_policy != eExecutionPolicyNever && - m_expr.NeedsValidation() && - process) + if (!can_interpret && execution_policy == eExecutionPolicyNever) { - if (!process->GetDynamicCheckers()) + err.SetErrorStringWithFormat("Can't run the expression locally: %s", interpret_error.AsCString()); + return err; + } + + if (!process && execution_policy == eExecutionPolicyAlways) + { + err.SetErrorString("Expression needed to run in the target, but the target can't be run"); + return err; + } + + if (execution_policy == eExecutionPolicyAlways || !can_interpret) + { + if (!process->GetDynamicCheckers() && m_expr.NeedsValidation()) { DynamicCheckerFunctions *dynamic_checkers = new DynamicCheckerFunctions(); @@ -581,20 +570,24 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, if (log) log->Printf("== [ClangUserExpression::Evaluate] Finished installing dynamic checkers =="); + + IRDynamicChecks ir_dynamic_checks(*process->GetDynamicCheckers(), function_name.AsCString()); + + if (!ir_dynamic_checks.runOnModule(*m_execution_unit->GetModule())) + { + err.SetErrorToGenericError(); + err.SetErrorString("Couldn't add dynamic checks to the expression"); + return err; + } } - IRDynamicChecks ir_dynamic_checks(*process->GetDynamicCheckers(), function_name.AsCString()); - - if (!ir_dynamic_checks.runOnModule(*m_execution_unit->GetModule())) - { - err.SetErrorToGenericError(); - err.SetErrorString("Couldn't add dynamic checks to the expression"); - return err; - } + m_execution_unit->GetRunnableInfo(err, func_addr, func_end); } } - - m_execution_unit->GetRunnableInfo(err, func_addr, func_end); + else + { + m_execution_unit->GetRunnableInfo(err, func_addr, func_end); + } execution_unit_ap.reset (m_execution_unit.release()); diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/ClangFunction.cpp index c0131b06a582..e37a16a4fb76 100644 --- a/lldb/source/Expression/ClangFunction.cpp +++ b/lldb/source/Expression/ClangFunction.cpp @@ -260,17 +260,14 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors) if (m_JITted) return true; - - lldb::ClangExpressionVariableSP const_result; - - bool evaluated_statically = false; // should stay that way + + bool can_interpret = false; // should stay that way Error jit_error (m_parser->PrepareForExecution (m_jit_start_addr, m_jit_end_addr, m_execution_unit_ap, exe_ctx, - evaluated_statically, - const_result, + can_interpret, eExecutionPolicyAlways)); if (!jit_error.Success()) diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp index 6f65b11a6869..083f67aa2cf4 100644 --- a/lldb/source/Expression/ClangUserExpression.cpp +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -30,6 +30,7 @@ #include "lldb/Expression/ClangUserExpression.h" #include "lldb/Expression/ExpressionSourceCode.h" #include "lldb/Expression/IRExecutionUnit.h" +#include "lldb/Expression/IRInterpreter.h" #include "lldb/Expression/Materializer.h" #include "lldb/Host/Host.h" #include "lldb/Symbol/Block.h" @@ -67,8 +68,7 @@ ClangUserExpression::ClangUserExpression (const char *expr, m_needs_object_ptr (false), m_const_object (false), m_target (NULL), - m_evaluated_statically (false), - m_const_result () + m_can_interpret (false) { switch (m_language) { @@ -469,8 +469,7 @@ ClangUserExpression::Parse (Stream &error_stream, m_jit_end_addr, m_execution_unit_ap, exe_ctx, - m_evaluated_statically, - m_const_result, + m_can_interpret, execution_policy); if (jit_error.Success()) @@ -490,6 +489,46 @@ 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::eExpressionPathOptionsAllowDirectIVarAccess || + StackFrame::eExpressionPathOptionsNoFragileObjcIvar || + StackFrame::eExpressionPathOptionsNoSyntheticChildren || + StackFrame::eExpressionPathOptionsNoSyntheticArrayRange, + var_sp, + err); + + if (!err.Success()) + 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, @@ -497,8 +536,6 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream, lldb::addr_t &object_ptr, lldb::addr_t &cmd_ptr) { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - lldb::TargetSP target; lldb::ProcessSP process; lldb::StackFrameSP frame; @@ -512,10 +549,8 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream, return false; } - if (m_jit_start_addr != LLDB_INVALID_ADDRESS) - { - Error materialize_error; - + if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret) + { if (m_needs_object_ptr) { ConstString object_name; @@ -534,9 +569,13 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream, return false; } - if (!(m_expr_decl_map->GetObjectPointer(object_ptr, object_name, materialize_error))) + 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", materialize_error.AsCString()); + error_stream.Printf("warning: couldn't get required object pointer (substituting NULL): %s\n", object_ptr_error.AsCString()); object_ptr = 0; } @@ -544,53 +583,41 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream, { ConstString cmd_name("_cmd"); - if (!(m_expr_decl_map->GetObjectPointer(cmd_ptr, cmd_name, materialize_error, true))) + cmd_ptr = GetObjectPointer(frame, cmd_name, object_ptr_error); + + if (!object_ptr_error.Success()) { - error_stream.Printf("warning: couldn't get object pointer (substituting NULL): %s\n", materialize_error.AsCString()); + error_stream.Printf("warning: couldn't get cmd pointer (substituting NULL): %s\n", object_ptr_error.AsCString()); cmd_ptr = 0; } } } - - if (!m_expr_decl_map->Materialize(*m_execution_unit_ap, struct_address, materialize_error)) + + Error alloc_error; + + struct_address = m_execution_unit_ap->Malloc(m_materializer_ap->GetStructByteSize(), + m_materializer_ap->GetStructAlignment(), + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + IRMemoryMap::eAllocationPolicyMirror, + alloc_error); + + if (!alloc_error.Success()) + { + error_stream.Printf("Couldn't allocate space for materialized struct: %s\n", alloc_error.AsCString()); + return false; + } + + m_materialized_address = struct_address; + + Error materialize_error; + + m_dematerializer_sp = m_materializer_ap->Materialize(frame, *m_execution_unit_ap, struct_address, materialize_error); + + if (!materialize_error.Success()) { error_stream.Printf("Couldn't materialize struct: %s\n", materialize_error.AsCString()); return false; } - -#if 0 - // jingham: look here - StreamFile logfile ("/tmp/exprs.txt", "a"); - logfile.Printf("0x%16.16" PRIx64 ": thread = 0x%4.4x, expr = '%s'\n", m_jit_start_addr, exe_ctx.thread ? exe_ctx.thread->GetID() : -1, m_expr_text.c_str()); -#endif - - if (log) - { - log->Printf("-- [ClangUserExpression::PrepareToExecuteJITExpression] Materializing for execution --"); - - log->Printf(" Function address : 0x%" PRIx64, (uint64_t)m_jit_start_addr); - - if (m_needs_object_ptr) - log->Printf(" Object pointer : 0x%" PRIx64, (uint64_t)object_ptr); - - log->Printf(" Structure address : 0x%" PRIx64, (uint64_t)struct_address); - - StreamString args; - - Error dump_error; - - if (struct_address) - { - if (!m_expr_decl_map->DumpMaterializedStruct(args, dump_error)) - { - log->Printf(" Couldn't extract variable values : %s", dump_error.AsCString("unknown error")); - } - else - { - log->Printf(" Structure contents:\n%s", args.GetData()); - } - } - } } return true; } @@ -635,35 +662,31 @@ ClangUserExpression::FinalizeJITExecution (Stream &error_stream, Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); if (log) - { log->Printf("-- [ClangUserExpression::FinalizeJITExecution] Dematerializing after execution --"); - StreamString args; - - Error dump_error; - - if (!m_expr_decl_map->DumpMaterializedStruct(args, dump_error)) - { - log->Printf(" Couldn't extract variable values : %s", dump_error.AsCString("unknown error")); - } - else - { - log->Printf(" Structure contents:\n%s", args.GetData()); - } - } - lldb::addr_t function_stack_bottom = function_stack_pointer - Host::GetPageSize(); - - if (!m_expr_decl_map->Dematerialize(result, *m_execution_unit_ap, function_stack_pointer, function_stack_bottom, expr_error)) + if (!m_dematerializer_sp) + { + error_stream.Printf ("Couldn't dematerialize struct : no dematerializer is present"); + return false; + } + + Error dematerialize_error; + + m_dematerializer_sp->Dematerialize(dematerialize_error, result, function_stack_pointer, function_stack_bottom); + + if (!dematerialize_error.Success()) { error_stream.Printf ("Couldn't dematerialize struct : %s\n", expr_error.AsCString("unknown error")); return false; } - + if (result) result->TransferAddress(); + m_dematerializer_sp.reset(); + return true; } @@ -681,7 +704,7 @@ ClangUserExpression::Execute (Stream &error_stream, // 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) + if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret) { lldb::addr_t struct_address = LLDB_INVALID_ADDRESS; @@ -694,73 +717,115 @@ ClangUserExpression::Execute (Stream &error_stream, return eExecutionSetupError; } - const bool stop_others = true; - const bool try_all_threads = run_others; + lldb::addr_t function_stack_pointer = NULL; - Address wrapper_address (m_jit_start_addr); - lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(), - wrapper_address, - struct_address, - stop_others, - unwind_on_error, - ignore_breakpoints, - (m_needs_object_ptr ? &object_ptr : NULL), - ((m_needs_object_ptr && m_objectivec) ? &cmd_ptr : NULL), - shared_ptr_to_me)); - - if (!call_plan_sp || !call_plan_sp->ValidatePlan (&error_stream)) - return eExecutionSetupError; - - lldb::addr_t function_stack_pointer = static_cast(call_plan_sp.get())->GetFunctionStackPointer(); - - if (log) - log->Printf("-- [ClangUserExpression::Execute] Execution of expression begins --"); - - if (exe_ctx.GetProcessPtr()) - exe_ctx.GetProcessPtr()->SetRunningUserExpression(true); + if (m_can_interpret) + { + llvm::Module *module = m_execution_unit_ap->GetModule(); + llvm::Function *function = m_execution_unit_ap->GetFunction(); - ExecutionResults execution_result = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx, - call_plan_sp, - stop_others, - try_all_threads, - unwind_on_error, - ignore_breakpoints, - timeout_usec, - error_stream); - - if (exe_ctx.GetProcessPtr()) - exe_ctx.GetProcessPtr()->SetRunningUserExpression(false); - - if (log) - log->Printf("-- [ClangUserExpression::Execute] Execution of expression completed --"); - - if (execution_result == eExecutionInterrupted || execution_result == eExecutionHitBreakpoint) - { - const char *error_desc = NULL; - - if (call_plan_sp) + if (!module || !function) { - lldb::StopInfoSP real_stop_info_sp = call_plan_sp->GetRealStopInfo(); - if (real_stop_info_sp) - error_desc = real_stop_info_sp->GetDescription(); + error_stream.Printf("Supposed to interpret, but nothing is there"); + return eExecutionSetupError; } - if (error_desc) - error_stream.Printf ("Execution was interrupted, reason: %s.", error_desc); - else - error_stream.Printf ("Execution was interrupted."); - - if ((execution_result == eExecutionInterrupted && unwind_on_error) - || (execution_result == eExecutionHitBreakpoint && ignore_breakpoints)) - error_stream.Printf ("\nThe process has been returned to the state before expression evaluation."); - else - error_stream.Printf ("\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; + Error interpreter_error; + + llvm::SmallVector args; + + if (m_needs_object_ptr) + { + args.push_back(object_ptr); + + if (m_objectivec) + args.push_back(cmd_ptr); + } + + args.push_back(struct_address); + + IRInterpreter::Interpret (*module, + *function, + args, + *m_execution_unit_ap.get(), + interpreter_error); + + if (!interpreter_error.Success()) + { + error_stream.Printf("Supposed to interpret, but failed: %s", interpreter_error.AsCString()); + return eExecutionDiscarded; + } } - else if (execution_result != eExecutionCompleted) + else { - error_stream.Printf ("Couldn't execute function; result was %s\n", Process::ExecutionResultAsCString (execution_result)); - return execution_result; + const bool stop_others = true; + const bool try_all_threads = run_others; + + Address wrapper_address (m_jit_start_addr); + lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(), + wrapper_address, + struct_address, + stop_others, + unwind_on_error, + ignore_breakpoints, + (m_needs_object_ptr ? &object_ptr : NULL), + ((m_needs_object_ptr && m_objectivec) ? &cmd_ptr : NULL), + shared_ptr_to_me)); + + if (!call_plan_sp || !call_plan_sp->ValidatePlan (&error_stream)) + return eExecutionSetupError; + + function_stack_pointer = static_cast(call_plan_sp.get())->GetFunctionStackPointer(); + + if (log) + log->Printf("-- [ClangUserExpression::Execute] Execution of expression begins --"); + + if (exe_ctx.GetProcessPtr()) + exe_ctx.GetProcessPtr()->SetRunningUserExpression(true); + + ExecutionResults execution_result = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx, + call_plan_sp, + stop_others, + try_all_threads, + unwind_on_error, + ignore_breakpoints, + timeout_usec, + error_stream); + + if (exe_ctx.GetProcessPtr()) + exe_ctx.GetProcessPtr()->SetRunningUserExpression(false); + + if (log) + log->Printf("-- [ClangUserExpression::Execute] Execution of expression completed --"); + + if (execution_result == eExecutionInterrupted || execution_result == eExecutionHitBreakpoint) + { + 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.Printf ("Execution was interrupted."); + + if ((execution_result == eExecutionInterrupted && unwind_on_error) + || (execution_result == eExecutionHitBreakpoint && ignore_breakpoints)) + error_stream.Printf ("\nThe process has been returned to the state before expression evaluation."); + else + error_stream.Printf ("\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 != eExecutionCompleted) + { + 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_pointer)) @@ -862,19 +927,8 @@ ClangUserExpression::EvaluateWithError (ExecutionContext &exe_ctx, { lldb::ClangExpressionVariableSP expr_result; - if (user_expression_sp->EvaluatedStatically()) - { - if (log) - log->Printf("== [ClangUserExpression::Evaluate] Expression evaluated as a constant =="); - - if (user_expression_sp->m_const_result) - result_valobj_sp = user_expression_sp->m_const_result->GetValueObject(); - else - error.SetError(ClangUserExpression::kNoResult, lldb::eErrorTypeGeneric); - - execution_results = eExecutionCompleted; - } - else if (execution_policy == eExecutionPolicyNever) + if (execution_policy == eExecutionPolicyNever && + !user_expression_sp->CanInterpret()) { if (log) log->Printf("== [ClangUserExpression::Evaluate] Expression may not run, but is not constant =="); diff --git a/lldb/source/Expression/ClangUtilityFunction.cpp b/lldb/source/Expression/ClangUtilityFunction.cpp index aed0e244e7f8..c911c279993f 100644 --- a/lldb/source/Expression/ClangUtilityFunction.cpp +++ b/lldb/source/Expression/ClangUtilityFunction.cpp @@ -125,17 +125,14 @@ ClangUtilityFunction::Install (Stream &error_stream, ////////////////////////////////// // JIT the output of the parser // - - lldb::ClangExpressionVariableSP const_result; - - bool evaluated_statically = false; // should stay that way + + bool can_interpret = false; // should stay that way Error jit_error = parser.PrepareForExecution (m_jit_start_addr, m_jit_end_addr, m_execution_unit_ap, exe_ctx, - evaluated_statically, - const_result, + can_interpret, eExecutionPolicyAlways); if (m_jit_start_addr != LLDB_INVALID_ADDRESS) diff --git a/lldb/source/Expression/IRForTarget.cpp b/lldb/source/Expression/IRForTarget.cpp index 2b3618a53a7b..1c1f120b86cc 100644 --- a/lldb/source/Expression/IRForTarget.cpp +++ b/lldb/source/Expression/IRForTarget.cpp @@ -42,6 +42,7 @@ static char ID; IRForTarget::StaticDataAllocator::StaticDataAllocator(lldb_private::IRExecutionUnit &execution_unit) : m_execution_unit(execution_unit), + m_stream_string(lldb_private::Stream::eBinary, execution_unit.GetAddressByteSize(), execution_unit.GetByteOrder()), m_allocation(LLDB_INVALID_ADDRESS) { } @@ -63,15 +64,11 @@ lldb::addr_t IRForTarget::StaticDataAllocator::Allocate() IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map, bool resolve_vars, - lldb_private::ExecutionPolicy execution_policy, - lldb::ClangExpressionVariableSP &const_result, lldb_private::IRExecutionUnit &execution_unit, lldb_private::Stream *error_stream, const char *func_name) : ModulePass(ID), m_resolve_vars(resolve_vars), - m_execution_policy(execution_policy), - m_interpret_success(false), m_func_name(func_name), m_module(NULL), m_decl_map(decl_map), @@ -79,7 +76,6 @@ IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map, m_memory_map(execution_unit), m_CFStringCreateWithBytes(NULL), m_sel_registerName(NULL), - m_const_result(const_result), m_error_stream(error_stream), m_has_side_effects(false), m_result_store(NULL), @@ -444,97 +440,6 @@ IRForTarget::DeclForGlobal (GlobalValue *global_val) return DeclForGlobal(global_val, m_module); } -void -IRForTarget::MaybeSetConstantResult (llvm::Constant *initializer, - const lldb_private::ConstString &name, - lldb_private::TypeFromParser type) -{ - if (llvm::ConstantExpr *init_expr = dyn_cast(initializer)) - { - switch (init_expr->getOpcode()) - { - default: - return; - case Instruction::IntToPtr: - MaybeSetConstantResult (init_expr->getOperand(0), name, type); - return; - } - } - else if (llvm::ConstantInt *init_int = dyn_cast(initializer)) - { - m_const_result = m_decl_map->BuildIntegerVariable(name, type, init_int->getValue()); - } -} - -void -IRForTarget::MaybeSetCastResult (lldb_private::TypeFromParser type) -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - if (!m_result_store) - return; - - LoadInst *original_load = NULL; - - for (llvm::Value *current_value = m_result_store->getValueOperand(), *next_value; - current_value != NULL; - current_value = next_value) - { - CastInst *cast_inst = dyn_cast(current_value); - LoadInst *load_inst = dyn_cast(current_value); - - if (cast_inst) - { - next_value = cast_inst->getOperand(0); - } - else if (load_inst) - { - if (isa(load_inst->getPointerOperand())) - { - next_value = load_inst->getPointerOperand(); - } - else - { - original_load = load_inst; - break; - } - } - else - { - return; - } - } - - if (!original_load) - return; - - Value *loaded_value = original_load->getPointerOperand(); - GlobalVariable *loaded_global = dyn_cast(loaded_value); - - if (!loaded_global) - return; - - clang::NamedDecl *loaded_decl = DeclForGlobal(loaded_global); - - if (!loaded_decl) - return; - - clang::VarDecl *loaded_var = dyn_cast(loaded_decl); - - if (!loaded_var) - return; - - if (log) - { - lldb_private::StreamString type_desc_stream; - type.DumpTypeDescription(&type_desc_stream); - - log->Printf("Type to cast variable to: \"%s\"", type_desc_stream.GetString().c_str()); - } - - m_const_result = m_decl_map->BuildCastVariable(m_result_name, loaded_var, type); -} - bool IRForTarget::CreateResultVariable (llvm::Function &llvm_function) { @@ -714,7 +619,7 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function) log->Printf("Result decl type: \"%s\"", type_desc_stream.GetData()); } - m_result_name = m_decl_map->GetPersistentResultName(); + m_result_name = lldb_private::ConstString("$RESULT_NAME"); if (log) log->Printf("Creating a new result global: \"%s\" with size 0x%" PRIx64, @@ -806,15 +711,14 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function) result_global->replaceAllUsesWith(new_result_global); } - - if (!m_const_result) - if (!m_decl_map->AddPersistentVariable(result_decl, - m_result_name, - m_result_type, - true, - m_result_is_pointer)) - return false; + if (!m_decl_map->AddPersistentVariable(result_decl, + m_result_name, + m_result_type, + true, + m_result_is_pointer)) + return false; + result_global->eraseFromParent(); return true; @@ -2138,10 +2042,11 @@ IRForTarget::ReplaceStaticLiterals (llvm::BasicBlock &basic_block) llvm::Instruction *inst = *user_iter; ConstantFP *operand_constant_fp = dyn_cast(operand_val); - Type *operand_type = operand_constant_fp->getType(); if (operand_constant_fp) { + Type *operand_type = operand_constant_fp->getType(); + APFloat operand_apfloat = operand_constant_fp->getValueAPF(); APInt operand_apint = operand_apfloat.bitcastToAPInt(); @@ -2195,7 +2100,7 @@ IRForTarget::ReplaceStaticLiterals (llvm::BasicBlock &basic_block) llvm::Type *fp_ptr_ty = operand_constant_fp->getType()->getPointerTo(); - Constant *new_pointer = BuildRelocation(fp_ptr_ty, offset); + Constant *new_pointer = BuildRelocation(fp_ptr_ty, aligned_offset); llvm::LoadInst *fp_load = new llvm::LoadInst(new_pointer, "fp_load", inst); @@ -2762,12 +2667,6 @@ IRForTarget::runOnModule (Module &llvm_module) return false; } - - if (m_const_result && m_execution_policy != lldb_private::eExecutionPolicyAlways) - { - m_interpret_success = true; - return true; - } for (bbi = function->begin(); bbi != function->end(); @@ -2804,20 +2703,6 @@ IRForTarget::runOnModule (Module &llvm_module) } } - if (m_decl_map && m_execution_policy != lldb_private::eExecutionPolicyAlways) - { - IRInterpreter::maybeRunOnFunction(m_decl_map, m_memory_map, m_error_stream,m_const_result, m_result_name, m_result_type, *function, llvm_module, m_interpreter_error); - - if (m_interpreter_error.Success()) - return true; - } - - if (m_execution_policy == lldb_private::eExecutionPolicyNever) { - if (m_result_name) - m_decl_map->RemoveResultVariable(m_result_name); - return false; - } - if (log && log->GetVerbose()) { std::string s; diff --git a/lldb/source/Expression/IRInterpreter.cpp b/lldb/source/Expression/IRInterpreter.cpp index 622156302ae7..bfd8abe793ab 100644 --- a/lldb/source/Expression/IRInterpreter.cpp +++ b/lldb/source/Expression/IRInterpreter.cpp @@ -89,6 +89,10 @@ public: BasicBlock::const_iterator m_ii; BasicBlock::const_iterator m_ie; + lldb::addr_t m_frame_process_address; + size_t m_frame_size; + lldb::addr_t m_stack_pointer; + lldb::ByteOrder m_byte_order; size_t m_addr_byte_size; @@ -101,6 +105,36 @@ public: { m_byte_order = (target_data.isLittleEndian() ? lldb::eByteOrderLittle : lldb::eByteOrderBig); m_addr_byte_size = (target_data.getPointerSize(0)); + + m_frame_size = 512 * 1024; + + lldb_private::Error alloc_error; + + m_frame_process_address = memory_map.Malloc(m_frame_size, + m_addr_byte_size, + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + lldb_private::IRMemoryMap::eAllocationPolicyMirror, + alloc_error); + + if (alloc_error.Success()) + { + m_stack_pointer = m_frame_process_address + m_frame_size; + } + else + { + m_frame_process_address = LLDB_INVALID_ADDRESS; + m_stack_pointer = LLDB_INVALID_ADDRESS; + } + } + + ~InterpreterStackFrame () + { + if (m_frame_process_address != LLDB_INVALID_ADDRESS) + { + lldb_private::Error free_error; + m_memory_map.Free(m_frame_process_address, free_error); + m_frame_process_address = LLDB_INVALID_ADDRESS; + } } void Jump (const BasicBlock *bb) @@ -216,57 +250,106 @@ public: bool ResolveConstantValue (APInt &value, const Constant *constant) { - if (const ConstantInt *constant_int = dyn_cast(constant)) + switch (constant->getValueID()) { - value = constant_int->getValue(); - return true; - } - else if (const ConstantFP *constant_fp = dyn_cast(constant)) - { - value = constant_fp->getValueAPF().bitcastToAPInt(); - return true; - } - else if (const ConstantExpr *constant_expr = dyn_cast(constant)) - { - switch (constant_expr->getOpcode()) + default: + break; + case Value::ConstantIntVal: + if (const ConstantInt *constant_int = dyn_cast(constant)) { - default: - return false; - case Instruction::IntToPtr: - case Instruction::PtrToInt: - case Instruction::BitCast: - return ResolveConstantValue(value, constant_expr->getOperand(0)); - case Instruction::GetElementPtr: + value = constant_int->getValue(); + return true; + } + break; + case Value::ConstantFPVal: + if (const ConstantFP *constant_fp = dyn_cast(constant)) + { + value = constant_fp->getValueAPF().bitcastToAPInt(); + return true; + } + break; + case Value::ConstantExprVal: + if (const ConstantExpr *constant_expr = dyn_cast(constant)) + { + switch (constant_expr->getOpcode()) { - ConstantExpr::const_op_iterator op_cursor = constant_expr->op_begin(); - ConstantExpr::const_op_iterator op_end = constant_expr->op_end(); - - Constant *base = dyn_cast(*op_cursor); - - if (!base) + default: return false; - - if (!ResolveConstantValue(value, base)) - return false; - - op_cursor++; - - if (op_cursor == op_end) - return true; // no offset to apply! - - SmallVector indices (op_cursor, op_end); - - uint64_t offset = m_target_data.getIndexedOffset(base->getType(), indices); - - const bool is_signed = true; - value += APInt(value.getBitWidth(), offset, is_signed); - - return true; + case Instruction::IntToPtr: + case Instruction::PtrToInt: + case Instruction::BitCast: + return ResolveConstantValue(value, constant_expr->getOperand(0)); + case Instruction::GetElementPtr: + { + ConstantExpr::const_op_iterator op_cursor = constant_expr->op_begin(); + ConstantExpr::const_op_iterator op_end = constant_expr->op_end(); + + Constant *base = dyn_cast(*op_cursor); + + if (!base) + return false; + + if (!ResolveConstantValue(value, base)) + return false; + + op_cursor++; + + if (op_cursor == op_end) + return true; // no offset to apply! + + SmallVector indices (op_cursor, op_end); + + uint64_t offset = m_target_data.getIndexedOffset(base->getType(), indices); + + const bool is_signed = true; + value += APInt(value.getBitWidth(), offset, is_signed); + + return true; + } } } + break; + case Value::ConstantPointerNullVal: + if (isa(constant)) + { + value = APInt(m_target_data.getPointerSizeInBits(), 0); + return true; + } + break; + } + return false; + } + + bool MakeArgument(const Argument *value, uint64_t address) + { + lldb::addr_t data_address = Malloc(value->getType()); + + if (data_address == LLDB_INVALID_ADDRESS) + return false; + + lldb_private::Error write_error; + + m_memory_map.WritePointerToMemory(data_address, address, write_error); + + if (!write_error.Success()) + { + lldb_private::Error free_error; + m_memory_map.Free(data_address, free_error); + return false; } - return false; + m_values[value] = data_address; + + lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + if (log) + { + log->Printf("Made an allocation for argument %s", PrintValue(value).c_str()); + log->Printf(" Data region : %llx", (unsigned long long)address); + log->Printf(" Ref region : %llx", (unsigned long long)data_address); + } + + return true; } bool ResolveConstant (lldb::addr_t process_address, const Constant *constant) @@ -287,31 +370,30 @@ public: return write_error.Success(); } + lldb::addr_t Malloc (size_t size, uint8_t byte_alignment) + { + lldb::addr_t ret = m_stack_pointer; + + ret -= size; + ret -= (ret % byte_alignment); + + if (ret < m_frame_process_address) + return LLDB_INVALID_ADDRESS; + + m_stack_pointer = ret; + return ret; + } + lldb::addr_t MallocPointer () { - lldb_private::Error alloc_error; - - lldb::addr_t ret = m_memory_map.Malloc(m_target_data.getPointerSize(), m_target_data.getPointerPrefAlignment(), lldb::ePermissionsReadable | lldb::ePermissionsWritable, lldb_private::IRMemoryMap::eAllocationPolicyMirror, alloc_error); - - if (alloc_error.Success()) - return ret; - else - return LLDB_INVALID_ADDRESS; + return Malloc(m_target_data.getPointerSize(), m_target_data.getPointerPrefAlignment()); } - lldb::addr_t Malloc (llvm::Type *type, size_t override_byte_size = 0) + lldb::addr_t Malloc (llvm::Type *type) { lldb_private::Error alloc_error; - if (!override_byte_size) - override_byte_size = m_target_data.getTypeStoreSize(type); - - lldb::addr_t ret = m_memory_map.Malloc(override_byte_size, m_target_data.getPrefTypeAlignment(type), lldb::ePermissionsReadable | lldb::ePermissionsWritable, lldb_private::IRMemoryMap::eAllocationPolicyMirror, alloc_error); - - if (alloc_error.Success()) - return ret; - else - return LLDB_INVALID_ADDRESS; + return Malloc(m_target_data.getTypeAllocSize(type), m_target_data.getPrefTypeAlignment(type)); } lldb::addr_t PlaceLLDBValue (const llvm::Value *value, lldb_private::Value lldb_value) @@ -325,6 +407,7 @@ public: lldb::addr_t ret; size_t value_size = m_target_data.getTypeStoreSize(value->getType()); + size_t value_align = m_target_data.getPrefTypeAlignment(value->getType()); if (reg_info && (reg_info->encoding == lldb::eEncodingVector)) value_size = reg_info->byte_size; @@ -332,7 +415,7 @@ public: if (!reg_info && (lldb_value.GetValueType() == lldb_private::Value::eValueTypeLoadAddress)) return lldb_value.GetScalar().ULongLong(); - ret = Malloc(value->getType(), value_size); + ret = Malloc(value_size, value_align); if (ret == LLDB_INVALID_ADDRESS) return LLDB_INVALID_ADDRESS; @@ -403,14 +486,28 @@ public: lldb::addr_t ResolveValue (const Value *value, Module &module) { - if (!m_decl_map) - return LLDB_INVALID_ADDRESS; - ValueMap::iterator i = m_values.find(value); if (i != m_values.end()) return i->second; + // Fall back and allocate space [allocation type Alloca] + + lldb::addr_t data_address = Malloc(value->getType()); + + if (const Constant *constant = dyn_cast(value)) + { + if (!ResolveConstant (data_address, constant)) + { + lldb_private::Error free_error; + m_memory_map.Free(data_address, free_error); + return LLDB_INVALID_ADDRESS; + } + } + + m_values[value] = data_address; + return data_address; + const GlobalValue *global_value = dyn_cast(value); // If the variable is indirected through the argument @@ -686,23 +783,6 @@ public: } } while(0); - - // Fall back and allocate space [allocation type Alloca] - - lldb::addr_t data_address = Malloc(value->getType()); - - if (const Constant *constant = dyn_cast(value)) - { - if (!ResolveConstant (data_address, constant)) - { - lldb_private::Error free_error; - m_memory_map.Free(data_address, free_error); - return LLDB_INVALID_ADDRESS; - } - } - - m_values[value] = data_address; - return data_address; } bool ConstructResult (lldb::ClangExpressionVariableSP &result, @@ -1698,15 +1778,50 @@ IRInterpreter::CanInterpret (llvm::Module &module, bool IRInterpreter::Interpret (llvm::Module &module, llvm::Function &function, + llvm::ArrayRef args, lldb_private::IRMemoryMap &memory_map, lldb_private::Error &error) { lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + if (log) + { + std::string s; + raw_string_ostream oss(s); + + module.print(oss, NULL); + + oss.flush(); + + log->Printf("Module as passed in to IRInterpreter::Interpret: \n\"%s\"", s.c_str()); + } + DataLayout data_layout(&module); InterpreterStackFrame frame(data_layout, NULL, memory_map); + if (frame.m_frame_process_address == LLDB_INVALID_ADDRESS) + { + error.SetErrorString("Couldn't allocate stack frame"); + } + + int arg_index = 0; + + for (llvm::Function::arg_iterator ai = function.arg_begin(), ae = function.arg_end(); + ai != ae; + ++ai, ++arg_index) + { + if (args.size() < arg_index) + { + error.SetErrorString ("Not enough arguments passed in to function"); + return false; + } + + lldb::addr_t ptr = args[arg_index]; + + frame.MakeArgument(ai, ptr); + } + uint32_t num_insts = 0; frame.Jump(function.begin()); diff --git a/lldb/source/Expression/IRMemoryMap.cpp b/lldb/source/Expression/IRMemoryMap.cpp index fedbc2497351..cd334cddac7f 100644 --- a/lldb/source/Expression/IRMemoryMap.cpp +++ b/lldb/source/Expression/IRMemoryMap.cpp @@ -85,6 +85,9 @@ IRMemoryMap::ContainsHostOnlyAllocations () IRMemoryMap::AllocationMap::iterator IRMemoryMap::FindAllocation (lldb::addr_t addr, size_t size) { + if (addr == LLDB_INVALID_ADDRESS) + return m_allocations.end(); + AllocationMap::iterator iter = m_allocations.lower_bound (addr); if (iter == m_allocations.end() || diff --git a/lldb/source/Expression/Materializer.cpp b/lldb/source/Expression/Materializer.cpp index 7f5400177796..9cbc01c69c84 100644 --- a/lldb/source/Expression/Materializer.cpp +++ b/lldb/source/Expression/Materializer.cpp @@ -20,6 +20,7 @@ #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" using namespace lldb_private; @@ -179,11 +180,8 @@ public: } else { - // This is the result variable - /* err.SetErrorToGenericError(); err.SetErrorStringWithFormat("No materialization happened for persistent variable %s", m_persistent_variable_sp->GetName().AsCString()); - */ return; } } @@ -280,6 +278,7 @@ public: if (!read_error.Success()) { + err.SetErrorToGenericError(); err.SetErrorStringWithFormat ("Couldn't read the contents of %s from memory: %s", m_persistent_variable_sp->GetName().GetCString(), read_error.AsCString()); return; } @@ -468,7 +467,7 @@ public: DataExtractor data; valobj_sp->GetData(data); - if (m_temporary_allocation == LLDB_INVALID_ADDRESS) + if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { err.SetErrorToGenericError(); err.SetErrorStringWithFormat("Trying to create a temporary region for %s but one exists", m_variable_sp->GetName().AsCString()); @@ -580,7 +579,7 @@ public: if (!free_error.Success()) { err.SetErrorToGenericError(); - err.SetErrorStringWithFormat("Couldn'tfree the temporary region for %s: %s", m_variable_sp->GetName().AsCString(), free_error.AsCString()); + err.SetErrorStringWithFormat("Couldn't free the temporary region for %s: %s", m_variable_sp->GetName().AsCString(), free_error.AsCString()); return; } @@ -593,9 +592,11 @@ public: { StreamString dump_stream; - Error err; + dump_stream.Printf("0x%llx: EntityVariable\n", (unsigned long long)process_address + m_offset); - dump_stream.Printf("0x%llx: EntityVariable (%s)\n", (unsigned long long)process_address + m_offset, m_variable_sp->GetName().AsCString()); + Error err; + + lldb::addr_t ptr = LLDB_INVALID_ADDRESS; { dump_stream.Printf("Pointer:\n"); @@ -614,18 +615,29 @@ public: extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, process_address + m_offset); + lldb::offset_t offset; + + ptr = extractor.GetPointer(&offset); + dump_stream.PutChar('\n'); } } if (m_temporary_allocation == LLDB_INVALID_ADDRESS) { - dump_stream.Printf("Points to process memory.\n"); + dump_stream.Printf("Points to process memory:\n"); } else { dump_stream.Printf("Temporary allocation:\n"); - + } + + if (ptr == LLDB_INVALID_ADDRESS) + { + dump_stream.Printf(" \n"); + } + else + { DataBufferHeap data (m_temporary_allocation_size, 0); map.ReadMemory(data.GetBytes(), m_temporary_allocation, m_temporary_allocation_size, err); @@ -680,21 +692,157 @@ Materializer::AddVariable (lldb::VariableSP &variable_sp, Error &err) class EntityResultVariable : public Materializer::Entity { public: - EntityResultVariable (const ClangASTType &type, bool keep_in_memory) : + EntityResultVariable (const TypeFromUser &type, bool is_program_reference, bool keep_in_memory) : Entity(), m_type(type), - m_keep_in_memory(keep_in_memory) + m_is_program_reference(is_program_reference), + m_keep_in_memory(keep_in_memory), + m_temporary_allocation(LLDB_INVALID_ADDRESS), + m_temporary_allocation_size(0) { - SetSizeAndAlignmentFromType(m_type); + // Hard-coding to maximum size of a pointer since all results are materialized by reference + m_size = 8; + m_alignment = 8; } void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err) { + if (!m_is_program_reference) + { + if (m_temporary_allocation != LLDB_INVALID_ADDRESS) + { + err.SetErrorToGenericError(); + err.SetErrorString("Trying to create a temporary region for the result but one exists"); + return; + } + + size_t byte_size = m_type.GetTypeByteSize(); + size_t bit_align = m_type.GetTypeBitAlign(); + size_t byte_align = (bit_align + 7) / 8; + + Error alloc_error; + + m_temporary_allocation = map.Malloc(byte_size, byte_align, lldb::ePermissionsReadable | lldb::ePermissionsWritable, IRMemoryMap::eAllocationPolicyMirror, alloc_error); + m_temporary_allocation_size = byte_size; + + if (!alloc_error.Success()) + { + err.SetErrorToGenericError(); + err.SetErrorStringWithFormat("Couldn't allocate a temporary region for the result: %s", alloc_error.AsCString()); + return; + } + + Error pointer_write_error; + + map.WritePointerToMemory(process_address + m_offset, m_temporary_allocation, pointer_write_error); + + if (!pointer_write_error.Success()) + { + err.SetErrorToGenericError(); + err.SetErrorStringWithFormat("Couldn't write the address of the temporary region for the result: %s", pointer_write_error.AsCString()); + } + } } void Dematerialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, - lldb::addr_t frame_top, lldb::addr_t frame_bottom, Error &err) + lldb::addr_t frame_top, lldb::addr_t frame_bottom, Error &err) { + err.SetErrorToGenericError(); + err.SetErrorString("Tried to detmaterialize a result variable with the normal Dematerialize method"); + } + + void Dematerialize (lldb::ClangExpressionVariableSP &result_variable_sp, + lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, + lldb::addr_t frame_top, lldb::addr_t frame_bottom, Error &err) + { + err.Clear(); + + ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope(); + + if (!exe_scope) + { + err.SetErrorToGenericError(); + err.SetErrorString("Couldn't dematerialize a result variable: invalid execution context scope"); + return; + } + + lldb::addr_t address; + Error read_error; + + map.ReadPointerFromMemory (&address, process_address + m_offset, read_error); + + if (!read_error.Success()) + { + err.SetErrorToGenericError(); + err.SetErrorString("Couldn't dematerialize a result variable: couldn't read its address"); + return; + } + + lldb::TargetSP target_sp = exe_scope->CalculateTarget(); + + if (!target_sp) + { + err.SetErrorToGenericError(); + err.SetErrorString("Couldn't dematerialize a result variable: no target"); + return; + } + + ConstString name = target_sp->GetPersistentVariables().GetNextPersistentVariableName(); + + lldb::ClangExpressionVariableSP ret; + + ret = target_sp->GetPersistentVariables().CreateVariable(exe_scope, + name, + m_type, + map.GetByteOrder(), + map.GetAddressByteSize()); + + if (!ret) + { + err.SetErrorToGenericError(); + err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: failed to make persistent variable %s", name.AsCString()); + return; + } + + ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, + m_type.GetASTContext(), + m_type.GetOpaqueQualType(), + name, + address, + eAddressTypeLoad, + ret->GetByteSize()); + + ret->ValueUpdated(); + + const size_t pvar_byte_size = ret->GetByteSize(); + uint8_t *pvar_data = ret->GetValueBytes(); + + map.ReadMemory(pvar_data, address, pvar_byte_size, read_error); + + if (!read_error.Success()) + { + err.SetErrorToGenericError(); + err.SetErrorString("Couldn't dematerialize a result variable: couldn't read its memory"); + return; + } + + result_variable_sp = ret; + + if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) + { + ret->m_flags |= ClangExpressionVariable::EVNeedsAllocation; + + Error free_error; + + map.Free(m_temporary_allocation, free_error); + } + else + { + ret->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated; + } + + m_temporary_allocation = LLDB_INVALID_ADDRESS; + m_temporary_allocation_size = 0; } void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log) @@ -703,24 +851,100 @@ public: dump_stream.Printf("0x%llx: EntityResultVariable\n", (unsigned long long)process_address + m_offset); + Error err; + + lldb::addr_t ptr = LLDB_INVALID_ADDRESS; + + { + dump_stream.Printf("Pointer:\n"); + + DataBufferHeap data (m_size, 0); + + map.ReadMemory(data.GetBytes(), process_address + m_offset, m_size, err); + + if (!err.Success()) + { + dump_stream.Printf(" \n"); + } + else + { + DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize()); + + extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, process_address + m_offset); + + lldb::offset_t offset; + + ptr = extractor.GetPointer(&offset); + + dump_stream.PutChar('\n'); + } + } + + if (m_temporary_allocation == LLDB_INVALID_ADDRESS) + { + dump_stream.Printf("Points to process memory:\n"); + } + else + { + dump_stream.Printf("Temporary allocation:\n"); + } + + if (ptr == LLDB_INVALID_ADDRESS) + { + dump_stream.Printf(" \n"); + } + else + { + DataBufferHeap data (m_temporary_allocation_size, 0); + + map.ReadMemory(data.GetBytes(), m_temporary_allocation, m_temporary_allocation_size, err); + + if (!err.Success()) + { + dump_stream.Printf(" \n"); + } + else + { + DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize()); + + extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, process_address + m_offset); + + dump_stream.PutChar('\n'); + } + } + log->PutCString(dump_stream.GetData()); } void Wipe (IRMemoryMap &map, lldb::addr_t process_address) { + if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) + { + Error free_error; + + map.Free(m_temporary_allocation, free_error); + } + + m_temporary_allocation = LLDB_INVALID_ADDRESS; + m_temporary_allocation_size = 0; } private: - ClangASTType m_type; + TypeFromUser m_type; + bool m_is_program_reference; bool m_keep_in_memory; + + lldb::addr_t m_temporary_allocation; + size_t m_temporary_allocation_size; }; uint32_t -Materializer::AddResultVariable (const ClangASTType &type, bool keep_in_memory, Error &err) +Materializer::AddResultVariable (const TypeFromUser &type, bool is_program_reference, bool keep_in_memory, Error &err) { EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); - iter->reset (new EntityResultVariable (type, keep_in_memory)); + iter->reset (new EntityResultVariable (type, is_program_reference, keep_in_memory)); uint32_t ret = AddStructMember(**iter); (*iter)->SetOffset(ret); + m_result_entity = iter->get(); return ret; } @@ -1008,6 +1232,7 @@ Materializer::AddRegister (const RegisterInfo ®ister_info, Error &err) Materializer::Materializer () : m_dematerializer_wp(), + m_result_entity(NULL), m_current_offset(0), m_struct_alignment(8) { @@ -1022,7 +1247,7 @@ Materializer::~Materializer () } Materializer::DematerializerSP -Materializer::Materialize (lldb::StackFrameSP &frame_sp, lldb::ClangExpressionVariableSP &result_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &error) +Materializer::Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &error) { ExecutionContextScope *exe_scope = frame_sp.get(); @@ -1066,7 +1291,7 @@ Materializer::Materialize (lldb::StackFrameSP &frame_sp, lldb::ClangExpressionVa } void -Materializer::Dematerializer::Dematerialize (Error &error, lldb::addr_t frame_top, lldb::addr_t frame_bottom) +Materializer::Dematerializer::Dematerialize (Error &error, lldb::ClangExpressionVariableSP &result_sp, lldb::addr_t frame_top, lldb::addr_t frame_bottom) { lldb::StackFrameSP frame_sp = m_frame_wp.lock(); @@ -1094,8 +1319,15 @@ Materializer::Dematerializer::Dematerialize (Error &error, lldb::addr_t frame_to for (EntityUP &entity_up : m_materializer->m_entities) { - entity_up->Dematerialize (frame_sp, *m_map, m_process_address, frame_top, frame_bottom, error); - + if (entity_up.get() == m_materializer->m_result_entity) + { + static_cast(m_materializer->m_result_entity)->Dematerialize (result_sp, frame_sp, *m_map, m_process_address, frame_top, frame_bottom, error); + } + else + { + entity_up->Dematerialize (frame_sp, *m_map, m_process_address, frame_top, frame_bottom, error); + } + if (!error.Success()) break; }