ThreadPlanCallFunction::ThreadPlanCallFunction(Thread &thread,
                                               const Address &function,
                                               const EvaluateExpressionOptions &options) :
    ThreadPlan(ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
    m_valid(false),
    m_stop_other_threads(options.GetStopOthers()),
    m_unwind_on_error(options.DoesUnwindOnError()),
    m_ignore_breakpoints(options.DoesIgnoreBreakpoints()),
    m_debug_execution(options.GetDebug()),
    m_trap_exceptions(options.GetTrapExceptions()),
    m_function_addr(function),
    m_function_sp(0),
    m_takedown_done(false),
    m_should_clear_objc_exception_bp(false),
    m_should_clear_cxx_exception_bp(false),
    m_stop_address(LLDB_INVALID_ADDRESS),
    m_return_type(CompilerType())
{
}
ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
                                                const Address &function,
                                                const CompilerType &return_type,
                                                llvm::ArrayRef<addr_t> args,
                                                const EvaluateExpressionOptions &options) :
    ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
    m_valid (false),
    m_stop_other_threads (options.GetStopOthers()),
    m_unwind_on_error (options.DoesUnwindOnError()),
    m_ignore_breakpoints (options.DoesIgnoreBreakpoints()),
    m_debug_execution (options.GetDebug()),
    m_trap_exceptions (options.GetTrapExceptions()),
    m_function_addr (function),
    m_function_sp (0),
    m_takedown_done (false),
    m_should_clear_objc_exception_bp(false),
    m_should_clear_cxx_exception_bp (false),
    m_stop_address (LLDB_INVALID_ADDRESS),
    m_expression_language (options.GetLanguage()),
    m_hit_error_backstop(false),
    m_return_type (return_type)
{
    lldb::addr_t start_load_addr = LLDB_INVALID_ADDRESS;
    lldb::addr_t function_load_addr = LLDB_INVALID_ADDRESS;
    ABI *abi = nullptr;

    if (!ConstructorSetup (thread, abi, start_load_addr, function_load_addr))
        return;

    if (!abi->PrepareTrivialCall(thread,
                                 m_function_sp,
                                 function_load_addr,
                                 start_load_addr,
                                 args))
        return;

    ReportRegisterState ("Function call was set up.  Register state was:");

    m_valid = true;    
}
Esempio n. 3
0
lldb::ExpressionResults
ClangUserExpression::Execute (Stream &error_stream,
                              ExecutionContext &exe_ctx,
                              const EvaluateExpressionOptions& options,
                              ClangUserExpression::ClangUserExpressionSP &shared_ptr_to_me,
                              lldb::ClangExpressionVariableSP &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;

        lldb::addr_t object_ptr = 0;
        lldb::addr_t cmd_ptr = 0;

        if (!PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address, object_ptr, cmd_ptr))
        {
            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;

            llvm::SmallVector <lldb::addr_t, 3> args;

            if (m_needs_object_ptr)
            {
                args.push_back(object_ptr);

                if (m_objectivec)
                    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);

            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("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_objectivec)
                    args.push_back(cmd_ptr);
            }

            args.push_back(struct_address);
         
            ThreadPlanCallUserExpression *user_expression_plan = 
                    new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(),
                                                      wrapper_address, 
                                                      args,
                                                      options,
                                                      shared_ptr_to_me);
            lldb::ThreadPlanSP call_plan_sp(user_expression_plan);

            if (!call_plan_sp || !call_plan_sp->ValidatePlan (&error_stream))
                return lldb::eExpressionSetupError;

            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 (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;
    }
}
Esempio n. 4
0
lldb::ExpressionResults
LLVMUserExpression::DoExecute(DiagnosticManager &diagnostic_manager,
                              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(diagnostic_manager, exe_ctx,
                                       struct_address)) {
      diagnostic_manager.Printf(
          eDiagnosticSeverityError,
          "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;

    lldb::ValueObjectSP error_backstop_result_sp;

    if (m_can_interpret) {
      llvm::Module *module = m_execution_unit_sp->GetModule();
      llvm::Function *function = m_execution_unit_sp->GetFunction();

      if (!module || !function) {
        diagnostic_manager.PutCString(
            eDiagnosticSeverityError,
            "supposed to interpret, but nothing is there");
        return lldb::eExpressionSetupError;
      }

      Error interpreter_error;

      std::vector<lldb::addr_t> args;

      if (!AddArguments(exe_ctx, args, struct_address, diagnostic_manager)) {
        diagnostic_manager.Printf(eDiagnosticSeverityError,
                                  "errored out in %s, couldn't AddArguments",
                                  __FUNCTION__);
        return lldb::eExpressionSetupError;
      }

      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()) {
        diagnostic_manager.Printf(eDiagnosticSeverityError,
                                  "supposed to interpret, but failed: %s",
                                  interpreter_error.AsCString());
        return lldb::eExpressionDiscarded;
      }
    } else {
      if (!exe_ctx.HasThreadScope()) {
        diagnostic_manager.Printf(eDiagnosticSeverityError,
                                  "%s called with no thread selected",
                                  __FUNCTION__);
        return lldb::eExpressionSetupError;
      }

      Address wrapper_address(m_jit_start_addr);

      std::vector<lldb::addr_t> args;

      if (!AddArguments(exe_ctx, args, struct_address, diagnostic_manager)) {
        diagnostic_manager.Printf(eDiagnosticSeverityError,
                                  "errored out in %s, couldn't AddArguments",
                                  __FUNCTION__);
        return lldb::eExpressionSetupError;
      }

      lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression(
          exe_ctx.GetThreadRef(), wrapper_address, args, options,
          shared_ptr_to_me));

      StreamString ss;
      if (!call_plan_sp || !call_plan_sp->ValidatePlan(&ss)) {
        diagnostic_manager.PutCString(eDiagnosticSeverityError, ss.GetData());
        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,
                                                diagnostic_manager);

      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)
          diagnostic_manager.Printf(eDiagnosticSeverityError,
                                    "Execution was interrupted, reason: %s.",
                                    error_desc);
        else
          diagnostic_manager.PutCString(eDiagnosticSeverityError,
                                        "Execution was interrupted.");

        if ((execution_result == lldb::eExpressionInterrupted &&
             options.DoesUnwindOnError()) ||
            (execution_result == lldb::eExpressionHitBreakpoint &&
             options.DoesIgnoreBreakpoints()))
          diagnostic_manager.AppendMessageToDiagnostic(
              "The process has been returned to the state before expression "
              "evaluation.");
        else {
          if (execution_result == lldb::eExpressionHitBreakpoint)
            user_expression_plan->TransferExpressionOwnership();
          diagnostic_manager.AppendMessageToDiagnostic(
              "The 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) {
        diagnostic_manager.PutCString(
            eDiagnosticSeverityRemark,
            "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) {
        if (user_expression_plan->HitErrorBackstop()) {
          // This should only happen in Playground & REPL.  The code threw an
          // uncaught error, so we already rolled up
          // the stack past our execution point.  We're not going to be able to
          // get any or our expression variables
          // since they've already gone out of scope.  But at least we can
          // gather the error result...
          if (user_expression_plan->GetReturnValueObject() &&
              user_expression_plan->GetReturnValueObject()
                  ->GetError()
                  .Success()) {
            error_backstop_result_sp =
                user_expression_plan->GetReturnValueObject();
          }
        }
      } else {
        diagnostic_manager.Printf(
            eDiagnosticSeverityError,
            "Couldn't execute function; result was %s",
            Process::ExecutionResultAsCString(execution_result));
        return execution_result;
      }
    }

    if (error_backstop_result_sp) {
      // This should only happen in Playground & REPL.  The code threw an
      // uncaught error, so we already rolled up
      // the stack past our execution point.  We're not going to be able to get
      // any or our expression variables
      // since they've already gone out of scope.  But at least we can gather
      // the error result...
      Target *target = exe_ctx.GetTargetPtr();
      PersistentExpressionState *expression_state =
          target->GetPersistentExpressionStateForLanguage(Language());
      if (expression_state)
        result = expression_state->CreatePersistentVariable(
            error_backstop_result_sp);

      return lldb::eExpressionCompleted;
    } else if (FinalizeJITExecution(diagnostic_manager, exe_ctx, result,
                                    function_stack_bottom,
                                    function_stack_top)) {
      return lldb::eExpressionCompleted;
    } else {
      return lldb::eExpressionResultUnavailable;
    }
  } else {
    diagnostic_manager.PutCString(
        eDiagnosticSeverityError,
        "Expression can't be run, because there is no JIT compiled function");
    return lldb::eExpressionSetupError;
  }
}