static bool
    BreakpointOptionsCallbackFunction (void *baton,
                                       StoppointCallbackContext *context, 
                                       lldb::user_id_t break_id,
                                       lldb::user_id_t break_loc_id)
    {
        bool ret_value = true;
        if (baton == NULL)
            return true;
        
        
        BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton;
        StringList &commands = data->user_source;
        
        if (commands.GetSize() > 0)
        {
            ExecutionContext exe_ctx (context->exe_ctx_ref);
            Target *target = exe_ctx.GetTargetPtr();
            if (target)
            {
                CommandReturnObject result;
                Debugger &debugger = target->GetDebugger();
                // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously
                // if the debugger is set up that way.
                    
                StreamSP output_stream (debugger.GetAsyncOutputStream());
                StreamSP error_stream (debugger.GetAsyncErrorStream());
                result.SetImmediateOutputStream (output_stream);
                result.SetImmediateErrorStream (error_stream);
        
                CommandInterpreterRunOptions options;
                options.SetStopOnContinue(true);
                options.SetStopOnError (data->stop_on_error);
                options.SetEchoCommands (true);
                options.SetPrintResults (true);
                options.SetAddToHistory (false);

                debugger.GetCommandInterpreter().HandleCommands (commands,
                                                                 &exe_ctx,
                                                                 options,
                                                                 result);
                result.GetImmediateOutputStream()->Flush();
                result.GetImmediateErrorStream()->Flush();
           }
        }
        return ret_value;
    }    
    static bool
    WatchpointOptionsCallbackFunction (void *baton,
                                       StoppointCallbackContext *context,
                                       lldb::user_id_t watch_id)
    {
        bool ret_value = true;
        if (baton == NULL)
            return true;


        WatchpointOptions::CommandData *data = (WatchpointOptions::CommandData *) baton;
        StringList &commands = data->user_source;

        if (commands.GetSize() > 0)
        {
            ExecutionContext exe_ctx (context->exe_ctx_ref);
            Target *target = exe_ctx.GetTargetPtr();
            if (target)
            {
                CommandReturnObject result;
                Debugger &debugger = target->GetDebugger();
                // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously
                // if the debugger is set up that way.

                StreamSP output_stream (debugger.GetAsyncOutputStream());
                StreamSP error_stream (debugger.GetAsyncErrorStream());
                result.SetImmediateOutputStream (output_stream);
                result.SetImmediateErrorStream (error_stream);

                bool stop_on_continue = true;
                bool echo_commands    = false;
                bool print_results    = true;

                debugger.GetCommandInterpreter().HandleCommands (commands,
                        &exe_ctx,
                        stop_on_continue,
                        data->stop_on_error,
                        echo_commands,
                        print_results,
                        eLazyBoolNo,
                        result);
                result.GetImmediateOutputStream()->Flush();
                result.GetImmediateErrorStream()->Flush();
            }
        }
        return ret_value;
    }
Beispiel #3
0
void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
  lldb::StreamFileSP output_sp(io_handler.GetOutputStreamFile());
  lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFile());
  bool extra_line = false;
  bool did_quit = false;

  if (code.empty()) {
    m_code.AppendString("");
    static_cast<IOHandlerEditline &>(io_handler)
        .SetBaseLineNumber(m_code.GetSize() + 1);
  } else {
    Debugger &debugger = m_target.GetDebugger();
    CommandInterpreter &ci = debugger.GetCommandInterpreter();
    extra_line = ci.GetSpaceReplPrompts();

    ExecutionContext exe_ctx(m_target.GetProcessSP()
                                 ->GetThreadList()
                                 .GetSelectedThread()
                                 ->GetSelectedFrame()
                                 .get());

    lldb::ProcessSP process_sp(exe_ctx.GetProcessSP());

    if (code[0] == ':') {
      // Meta command
      // Strip the ':'
      code.erase(0, 1);
      if (Args::StripSpaces(code)) {
        // "lldb" was followed by arguments, so just execute the command dump
        // the results

        // Turn off prompt on quit in case the user types ":quit"
        const bool saved_prompt_on_quit = ci.GetPromptOnQuit();
        if (saved_prompt_on_quit)
          ci.SetPromptOnQuit(false);

        // Execute the command
        CommandReturnObject result;
        result.SetImmediateOutputStream(output_sp);
        result.SetImmediateErrorStream(error_sp);
        ci.HandleCommand(code.c_str(), eLazyBoolNo, result);

        if (saved_prompt_on_quit)
          ci.SetPromptOnQuit(true);

        if (result.GetStatus() == lldb::eReturnStatusQuit) {
          did_quit = true;
          io_handler.SetIsDone(true);
          if (debugger.CheckTopIOHandlerTypes(
                  IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter)) {
            // We typed "quit" or an alias to quit so we need to check if the
            // command interpreter is above us and tell it that it is done as
            // well
            // so we don't drop back into the command interpreter if we have
            // already
            // quit
            lldb::IOHandlerSP io_handler_sp(ci.GetIOHandler());
            if (io_handler_sp)
              io_handler_sp->SetIsDone(true);
          }
        }
      } else {
        // ":" was followed by no arguments, so push the LLDB command prompt
        if (debugger.CheckTopIOHandlerTypes(
                IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter)) {
          // If the user wants to get back to the command interpreter and the
          // command interpreter is what launched the REPL, then just let the
          // REPL exit and fall back to the command interpreter.
          io_handler.SetIsDone(true);
        } else {
          // The REPL wasn't launched the by the command interpreter, it is the
          // base IOHandler, so we need to get the command interpreter and
          lldb::IOHandlerSP io_handler_sp(ci.GetIOHandler());
          if (io_handler_sp) {
            io_handler_sp->SetIsDone(false);
            debugger.PushIOHandler(ci.GetIOHandler());
          }
        }
      }
    } else {
      // Unwind any expression we might have been running in case our REPL
      // expression crashed and the user was looking around
      if (m_dedicated_repl_mode) {
        Thread *thread = exe_ctx.GetThreadPtr();
        if (thread && thread->UnwindInnermostExpression().Success()) {
          thread->SetSelectedFrameByIndex(0, false);
          exe_ctx.SetFrameSP(thread->GetSelectedFrame());
        }
      }

      const bool colorize_err = error_sp->GetFile().GetIsTerminalWithColors();

      EvaluateExpressionOptions expr_options;
      expr_options.SetCoerceToId(m_varobj_options.use_objc);
      expr_options.SetUnwindOnError(m_command_options.unwind_on_error);
      expr_options.SetIgnoreBreakpoints(m_command_options.ignore_breakpoints);
      expr_options.SetKeepInMemory(true);
      expr_options.SetUseDynamic(m_varobj_options.use_dynamic);
      expr_options.SetTryAllThreads(m_command_options.try_all_threads);
      expr_options.SetGenerateDebugInfo(true);
      expr_options.SetREPLEnabled(true);
      expr_options.SetColorizeErrors(colorize_err);
      expr_options.SetPoundLine(m_repl_source_path.c_str(),
                                m_code.GetSize() + 1);
      if (m_command_options.timeout > 0)
        expr_options.SetTimeout(std::chrono::microseconds(m_command_options.timeout));
      else
        expr_options.SetTimeout(llvm::None);

      expr_options.SetLanguage(GetLanguage());

      PersistentExpressionState *persistent_state =
          m_target.GetPersistentExpressionStateForLanguage(GetLanguage());

      const size_t var_count_before = persistent_state->GetSize();

      const char *expr_prefix = nullptr;
      lldb::ValueObjectSP result_valobj_sp;
      Error error;
      lldb::ModuleSP jit_module_sp;
      lldb::ExpressionResults execution_results =
          UserExpression::Evaluate(exe_ctx, expr_options, code.c_str(),
                                   expr_prefix, result_valobj_sp, error,
                                   0,       // Line offset
                                   nullptr, // Fixed Expression
                                   &jit_module_sp);

      // CommandInterpreter &ci = debugger.GetCommandInterpreter();

      if (process_sp && process_sp->IsAlive()) {
        bool add_to_code = true;
        bool handled = false;
        if (result_valobj_sp) {
          lldb::Format format = m_format_options.GetFormat();

          if (result_valobj_sp->GetError().Success()) {
            handled |= PrintOneVariable(debugger, output_sp, result_valobj_sp);
          } else if (result_valobj_sp->GetError().GetError() ==
                     UserExpression::kNoResult) {
            if (format != lldb::eFormatVoid && debugger.GetNotifyVoid()) {
              error_sp->PutCString("(void)\n");
              handled = true;
            }
          }
        }

        if (debugger.GetPrintDecls()) {
          for (size_t vi = var_count_before, ve = persistent_state->GetSize();
               vi != ve; ++vi) {
            lldb::ExpressionVariableSP persistent_var_sp =
                persistent_state->GetVariableAtIndex(vi);
            lldb::ValueObjectSP valobj_sp = persistent_var_sp->GetValueObject();

            PrintOneVariable(debugger, output_sp, valobj_sp,
                             persistent_var_sp.get());
          }
        }

        if (!handled) {
          bool useColors = error_sp->GetFile().GetIsTerminalWithColors();
          switch (execution_results) {
          case lldb::eExpressionSetupError:
          case lldb::eExpressionParseError:
            add_to_code = false;
            LLVM_FALLTHROUGH;
          case lldb::eExpressionDiscarded:
            error_sp->Printf("%s\n", error.AsCString());
            break;

          case lldb::eExpressionCompleted:
            break;
          case lldb::eExpressionInterrupted:
            if (useColors) {
              error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
              error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
            }
            error_sp->Printf("Execution interrupted. ");
            if (useColors)
              error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
            error_sp->Printf("Enter code to recover and continue.\nEnter LLDB "
                             "commands to investigate (type :help for "
                             "assistance.)\n");
            break;

          case lldb::eExpressionHitBreakpoint:
            // Breakpoint was hit, drop into LLDB command interpreter
            if (useColors) {
              error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
              error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
            }
            output_sp->Printf("Execution stopped at breakpoint.  ");
            if (useColors)
              error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
            output_sp->Printf("Enter LLDB commands to investigate (type help "
                              "for assistance.)\n");
            {
              lldb::IOHandlerSP io_handler_sp(ci.GetIOHandler());
              if (io_handler_sp) {
                io_handler_sp->SetIsDone(false);
                debugger.PushIOHandler(ci.GetIOHandler());
              }
            }
            break;

          case lldb::eExpressionTimedOut:
            error_sp->Printf("error: timeout\n");
            if (error.AsCString())
              error_sp->Printf("error: %s\n", error.AsCString());
            break;
          case lldb::eExpressionResultUnavailable:
            // Shoulnd't happen???
            error_sp->Printf("error: could not fetch result -- %s\n",
                             error.AsCString());
            break;
          case lldb::eExpressionStoppedForDebug:
            // Shoulnd't happen???
            error_sp->Printf("error: stopped for debug -- %s\n",
                             error.AsCString());
            break;
          }
        }

        if (add_to_code) {
          const uint32_t new_default_line = m_code.GetSize() + 1;

          m_code.SplitIntoLines(code);

          // Update our code on disk
          if (!m_repl_source_path.empty()) {
            lldb_private::File file(m_repl_source_path.c_str(),
                                    File::eOpenOptionWrite |
                                        File::eOpenOptionTruncate |
                                        File::eOpenOptionCanCreate,
                                    lldb::eFilePermissionsFileDefault);
            std::string code(m_code.CopyList());
            code.append(1, '\n');
            size_t bytes_written = code.size();
            file.Write(code.c_str(), bytes_written);
            file.Close();

            // Now set the default file and line to the REPL source file
            m_target.GetSourceManager().SetDefaultFileAndLine(
                FileSpec(m_repl_source_path, false), new_default_line);
          }
          static_cast<IOHandlerEditline &>(io_handler)
              .SetBaseLineNumber(m_code.GetSize() + 1);
        }
        if (extra_line) {
          fprintf(output_sp->GetFile().GetStream(), "\n");
        }
      }
    }

    // Don't complain about the REPL process going away if we are in the process
    // of quitting.
    if (!did_quit && (!process_sp || !process_sp->IsAlive())) {
      error_sp->Printf(
          "error: REPL process is no longer alive, exiting REPL\n");
      io_handler.SetIsDone(true);
    }
  }
}