Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:42:45

0001 //===-- IOHandler.h ---------------------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 
0009 #ifndef LLDB_CORE_IOHANDLER_H
0010 #define LLDB_CORE_IOHANDLER_H
0011 
0012 #include "lldb/Host/Config.h"
0013 #include "lldb/Utility/CompletionRequest.h"
0014 #include "lldb/Utility/Flags.h"
0015 #include "lldb/Utility/Predicate.h"
0016 #include "lldb/Utility/Stream.h"
0017 #include "lldb/Utility/StringList.h"
0018 #include "lldb/lldb-defines.h"
0019 #include "lldb/lldb-forward.h"
0020 #include "llvm/ADT/StringRef.h"
0021 
0022 #include <memory>
0023 #include <mutex>
0024 #include <optional>
0025 #include <string>
0026 #include <vector>
0027 
0028 #include <cstdint>
0029 #include <cstdio>
0030 
0031 namespace lldb_private {
0032 class Debugger;
0033 } // namespace lldb_private
0034 
0035 namespace curses {
0036 class Application;
0037 typedef std::unique_ptr<Application> ApplicationAP;
0038 } // namespace curses
0039 
0040 namespace lldb_private {
0041 
0042 class IOHandler {
0043 public:
0044   enum class Type {
0045     CommandInterpreter,
0046     CommandList,
0047     Confirm,
0048     Curses,
0049     Expression,
0050     REPL,
0051     ProcessIO,
0052     PythonInterpreter,
0053     LuaInterpreter,
0054     PythonCode,
0055     Other
0056   };
0057 
0058   IOHandler(Debugger &debugger, IOHandler::Type type);
0059 
0060   IOHandler(Debugger &debugger, IOHandler::Type type,
0061             const lldb::FileSP &input_sp, const lldb::StreamFileSP &output_sp,
0062             const lldb::StreamFileSP &error_sp, uint32_t flags);
0063 
0064   virtual ~IOHandler();
0065 
0066   // Each IOHandler gets to run until it is done. It should read data from the
0067   // "in" and place output into "out" and "err and return when done.
0068   virtual void Run() = 0;
0069 
0070   // Called when an input reader should relinquish its control so another can
0071   // be pushed onto the IO handler stack, or so the current IO handler can pop
0072   // itself off the stack
0073 
0074   virtual void Cancel() = 0;
0075 
0076   // Called when CTRL+C is pressed which usually causes
0077   // Debugger::DispatchInputInterrupt to be called.
0078 
0079   virtual bool Interrupt() = 0;
0080 
0081   virtual void GotEOF() = 0;
0082 
0083   bool IsActive() { return m_active && !m_done; }
0084 
0085   void SetIsDone(bool b) { m_done = b; }
0086 
0087   bool GetIsDone() { return m_done; }
0088 
0089   Type GetType() const { return m_type; }
0090 
0091   virtual void Activate() { m_active = true; }
0092 
0093   virtual void Deactivate() { m_active = false; }
0094 
0095   virtual void TerminalSizeChanged() {}
0096 
0097   virtual const char *GetPrompt() {
0098     // Prompt support isn't mandatory
0099     return nullptr;
0100   }
0101 
0102   virtual bool SetPrompt(llvm::StringRef prompt) {
0103     // Prompt support isn't mandatory
0104     return false;
0105   }
0106   bool SetPrompt(const char *) = delete;
0107 
0108   virtual llvm::StringRef GetControlSequence(char ch) { return {}; }
0109 
0110   virtual const char *GetCommandPrefix() { return nullptr; }
0111 
0112   virtual const char *GetHelpPrologue() { return nullptr; }
0113 
0114   int GetInputFD();
0115 
0116   int GetOutputFD();
0117 
0118   int GetErrorFD();
0119 
0120   FILE *GetInputFILE();
0121 
0122   FILE *GetOutputFILE();
0123 
0124   FILE *GetErrorFILE();
0125 
0126   lldb::FileSP GetInputFileSP();
0127 
0128   lldb::StreamFileSP GetOutputStreamFileSP();
0129 
0130   lldb::StreamFileSP GetErrorStreamFileSP();
0131 
0132   Debugger &GetDebugger() { return m_debugger; }
0133 
0134   void *GetUserData() { return m_user_data; }
0135 
0136   void SetUserData(void *user_data) { m_user_data = user_data; }
0137 
0138   Flags &GetFlags() { return m_flags; }
0139 
0140   const Flags &GetFlags() const { return m_flags; }
0141 
0142   /// Check if the input is being supplied interactively by a user
0143   ///
0144   /// This will return true if the input stream is a terminal (tty or
0145   /// pty) and can cause IO handlers to do different things (like
0146   /// for a confirmation when deleting all breakpoints).
0147   bool GetIsInteractive();
0148 
0149   /// Check if the input is coming from a real terminal.
0150   ///
0151   /// A real terminal has a valid size with a certain number of rows
0152   /// and columns. If this function returns true, then terminal escape
0153   /// sequences are expected to work (cursor movement escape sequences,
0154   /// clearing lines, etc).
0155   bool GetIsRealTerminal();
0156 
0157   void SetPopped(bool b);
0158 
0159   void WaitForPop();
0160 
0161   virtual void PrintAsync(const char *s, size_t len, bool is_stdout);
0162 
0163   std::recursive_mutex &GetOutputMutex() { return m_output_mutex; }
0164 
0165 protected:
0166   Debugger &m_debugger;
0167   lldb::FileSP m_input_sp;
0168   lldb::StreamFileSP m_output_sp;
0169   lldb::StreamFileSP m_error_sp;
0170   std::recursive_mutex m_output_mutex;
0171   Predicate<bool> m_popped;
0172   Flags m_flags;
0173   Type m_type;
0174   void *m_user_data;
0175   bool m_done;
0176   bool m_active;
0177 
0178 private:
0179   IOHandler(const IOHandler &) = delete;
0180   const IOHandler &operator=(const IOHandler &) = delete;
0181 };
0182 
0183 /// A delegate class for use with IOHandler subclasses.
0184 ///
0185 /// The IOHandler delegate is designed to be mixed into classes so
0186 /// they can use an IOHandler subclass to fetch input and notify the
0187 /// object that inherits from this delegate class when a token is
0188 /// received.
0189 class IOHandlerDelegate {
0190 public:
0191   enum class Completion { None, LLDBCommand, Expression };
0192 
0193   IOHandlerDelegate(Completion completion = Completion::None)
0194       : m_completion(completion) {}
0195 
0196   virtual ~IOHandlerDelegate() = default;
0197 
0198   virtual void IOHandlerActivated(IOHandler &io_handler, bool interactive) {}
0199 
0200   virtual void IOHandlerDeactivated(IOHandler &io_handler) {}
0201 
0202   virtual std::optional<std::string> IOHandlerSuggestion(IOHandler &io_handler,
0203                                                          llvm::StringRef line);
0204 
0205   virtual void IOHandlerComplete(IOHandler &io_handler,
0206                                  CompletionRequest &request);
0207 
0208   virtual const char *IOHandlerGetFixIndentationCharacters() { return nullptr; }
0209 
0210   /// Called when a new line is created or one of an identified set of
0211   /// indentation characters is typed.
0212   ///
0213   /// This function determines how much indentation should be added
0214   /// or removed to match the recommended amount for the final line.
0215   ///
0216   /// \param[in] io_handler
0217   ///     The IOHandler that responsible for input.
0218   ///
0219   /// \param[in] lines
0220   ///     The current input up to the line to be corrected.  Lines
0221   ///     following the line containing the cursor are not included.
0222   ///
0223   /// \param[in] cursor_position
0224   ///     The number of characters preceding the cursor on the final
0225   ///     line at the time.
0226   ///
0227   /// \return
0228   ///     Returns an integer describing the number of spaces needed
0229   ///     to correct the indentation level.  Positive values indicate
0230   ///     that spaces should be added, while negative values represent
0231   ///     spaces that should be removed.
0232   virtual int IOHandlerFixIndentation(IOHandler &io_handler,
0233                                       const StringList &lines,
0234                                       int cursor_position) {
0235     return 0;
0236   }
0237 
0238   /// Called when a line or lines have been retrieved.
0239   ///
0240   /// This function can handle the current line and possibly call
0241   /// IOHandler::SetIsDone(true) when the IO handler is done like when
0242   /// "quit" is entered as a command, of when an empty line is
0243   /// received. It is up to the delegate to determine when a line
0244   /// should cause a IOHandler to exit.
0245   virtual void IOHandlerInputComplete(IOHandler &io_handler,
0246                                       std::string &data) = 0;
0247 
0248   virtual void IOHandlerInputInterrupted(IOHandler &io_handler,
0249                                          std::string &data) {}
0250 
0251   /// Called to determine whether typing enter after the last line in
0252   /// \a lines should end input.  This function will not be called on
0253   /// IOHandler objects that are getting single lines.
0254   /// \param[in] io_handler
0255   ///     The IOHandler that responsible for updating the lines.
0256   ///
0257   /// \param[in] lines
0258   ///     The current multi-line content.  May be altered to provide
0259   ///     alternative input when complete.
0260   ///
0261   /// \return
0262   ///     Return an boolean to indicate whether input is complete,
0263   ///     true indicates that no additional input is necessary, while
0264   ///     false indicates that more input is required.
0265   virtual bool IOHandlerIsInputComplete(IOHandler &io_handler,
0266                                         StringList &lines) {
0267     // Impose no requirements for input to be considered complete.  subclasses
0268     // should do something more intelligent.
0269     return true;
0270   }
0271 
0272   virtual llvm::StringRef IOHandlerGetControlSequence(char ch) { return {}; }
0273 
0274   virtual const char *IOHandlerGetCommandPrefix() { return nullptr; }
0275 
0276   virtual const char *IOHandlerGetHelpPrologue() { return nullptr; }
0277 
0278   // Intercept the IOHandler::Interrupt() calls and do something.
0279   //
0280   // Return true if the interrupt was handled, false if the IOHandler should
0281   // continue to try handle the interrupt itself.
0282   virtual bool IOHandlerInterrupt(IOHandler &io_handler) { return false; }
0283 
0284 protected:
0285   Completion m_completion; // Support for common builtin completions
0286 };
0287 
0288 // IOHandlerDelegateMultiline
0289 //
0290 // A IOHandlerDelegate that handles terminating multi-line input when
0291 // the last line is equal to "end_line" which is specified in the constructor.
0292 class IOHandlerDelegateMultiline : public IOHandlerDelegate {
0293 public:
0294   IOHandlerDelegateMultiline(llvm::StringRef end_line,
0295                              Completion completion = Completion::None)
0296       : IOHandlerDelegate(completion), m_end_line(end_line.str() + "\n") {}
0297 
0298   ~IOHandlerDelegateMultiline() override = default;
0299 
0300   llvm::StringRef IOHandlerGetControlSequence(char ch) override {
0301     if (ch == 'd')
0302       return m_end_line;
0303     return {};
0304   }
0305 
0306   bool IOHandlerIsInputComplete(IOHandler &io_handler,
0307                                 StringList &lines) override {
0308     // Determine whether the end of input signal has been entered
0309     const size_t num_lines = lines.GetSize();
0310     const llvm::StringRef end_line =
0311         llvm::StringRef(m_end_line).drop_back(1); // Drop '\n'
0312     if (num_lines > 0 && llvm::StringRef(lines[num_lines - 1]) == end_line) {
0313       // Remove the terminal line from "lines" so it doesn't appear in the
0314       // resulting input and return true to indicate we are done getting lines
0315       lines.PopBack();
0316       return true;
0317     }
0318     return false;
0319   }
0320 
0321 protected:
0322   const std::string m_end_line;
0323 };
0324 
0325 class IOHandlerEditline : public IOHandler {
0326 public:
0327   IOHandlerEditline(Debugger &debugger, IOHandler::Type type,
0328                     const char *editline_name, // Used for saving history files
0329                     llvm::StringRef prompt, llvm::StringRef continuation_prompt,
0330                     bool multi_line, bool color,
0331                     uint32_t line_number_start, // If non-zero show line numbers
0332                                                 // starting at
0333                                                 // 'line_number_start'
0334                     IOHandlerDelegate &delegate);
0335 
0336   IOHandlerEditline(Debugger &debugger, IOHandler::Type type,
0337                     const lldb::FileSP &input_sp,
0338                     const lldb::StreamFileSP &output_sp,
0339                     const lldb::StreamFileSP &error_sp, uint32_t flags,
0340                     const char *editline_name, // Used for saving history files
0341                     llvm::StringRef prompt, llvm::StringRef continuation_prompt,
0342                     bool multi_line, bool color,
0343                     uint32_t line_number_start, // If non-zero show line numbers
0344                                                 // starting at
0345                                                 // 'line_number_start'
0346                     IOHandlerDelegate &delegate);
0347 
0348   IOHandlerEditline(Debugger &, IOHandler::Type, const char *, const char *,
0349                     const char *, bool, bool, uint32_t,
0350                     IOHandlerDelegate &) = delete;
0351 
0352   IOHandlerEditline(Debugger &, IOHandler::Type, const lldb::FileSP &,
0353                     const lldb::StreamFileSP &, const lldb::StreamFileSP &,
0354                     uint32_t, const char *, const char *, const char *, bool,
0355                     bool, uint32_t, IOHandlerDelegate &) = delete;
0356 
0357   ~IOHandlerEditline() override;
0358 
0359   void Run() override;
0360 
0361   void Cancel() override;
0362 
0363   bool Interrupt() override;
0364 
0365   void GotEOF() override;
0366 
0367   void Activate() override;
0368 
0369   void Deactivate() override;
0370 
0371   void TerminalSizeChanged() override;
0372 
0373   llvm::StringRef GetControlSequence(char ch) override {
0374     return m_delegate.IOHandlerGetControlSequence(ch);
0375   }
0376 
0377   const char *GetCommandPrefix() override {
0378     return m_delegate.IOHandlerGetCommandPrefix();
0379   }
0380 
0381   const char *GetHelpPrologue() override {
0382     return m_delegate.IOHandlerGetHelpPrologue();
0383   }
0384 
0385   const char *GetPrompt() override;
0386 
0387   bool SetPrompt(llvm::StringRef prompt) override;
0388   bool SetPrompt(const char *prompt) = delete;
0389 
0390   const char *GetContinuationPrompt();
0391 
0392   void SetContinuationPrompt(llvm::StringRef prompt);
0393   void SetContinuationPrompt(const char *) = delete;
0394 
0395   bool GetLine(std::string &line, bool &interrupted);
0396 
0397   bool GetLines(StringList &lines, bool &interrupted);
0398 
0399   void SetBaseLineNumber(uint32_t line);
0400 
0401   bool GetInterruptExits() { return m_interrupt_exits; }
0402 
0403   void SetInterruptExits(bool b) { m_interrupt_exits = b; }
0404 
0405   StringList GetCurrentLines() const;
0406 
0407   uint32_t GetCurrentLineIndex() const;
0408 
0409   void PrintAsync(const char *s, size_t len, bool is_stdout) override;
0410 
0411 private:
0412 #if LLDB_ENABLE_LIBEDIT
0413   bool IsInputCompleteCallback(Editline *editline, StringList &lines);
0414 
0415   int FixIndentationCallback(Editline *editline, const StringList &lines,
0416                              int cursor_position);
0417 
0418   std::optional<std::string> SuggestionCallback(llvm::StringRef line);
0419 
0420   void AutoCompleteCallback(CompletionRequest &request);
0421 #endif
0422 
0423 protected:
0424 #if LLDB_ENABLE_LIBEDIT
0425   std::unique_ptr<Editline> m_editline_up;
0426 #endif
0427   IOHandlerDelegate &m_delegate;
0428   std::string m_prompt;
0429   std::string m_continuation_prompt;
0430   StringList *m_current_lines_ptr;
0431   uint32_t m_base_line_number; // If non-zero, then show line numbers in prompt
0432   uint32_t m_curr_line_idx;
0433   bool m_multi_line;
0434   bool m_color;
0435   bool m_interrupt_exits;
0436   std::string m_line_buffer;
0437 };
0438 
0439 // The order of base classes is important. Look at the constructor of
0440 // IOHandlerConfirm to see how.
0441 class IOHandlerConfirm : public IOHandlerDelegate, public IOHandlerEditline {
0442 public:
0443   IOHandlerConfirm(Debugger &debugger, llvm::StringRef prompt,
0444                    bool default_response);
0445 
0446   ~IOHandlerConfirm() override;
0447 
0448   bool GetResponse() const { return m_user_response; }
0449 
0450   void IOHandlerComplete(IOHandler &io_handler,
0451                          CompletionRequest &request) override;
0452 
0453   void IOHandlerInputComplete(IOHandler &io_handler,
0454                               std::string &data) override;
0455 
0456 protected:
0457   const bool m_default_response;
0458   bool m_user_response;
0459 };
0460 
0461 class IOHandlerStack {
0462 public:
0463   IOHandlerStack() = default;
0464 
0465   size_t GetSize() const {
0466     std::lock_guard<std::recursive_mutex> guard(m_mutex);
0467     return m_stack.size();
0468   }
0469 
0470   void Push(const lldb::IOHandlerSP &sp) {
0471     if (sp) {
0472       std::lock_guard<std::recursive_mutex> guard(m_mutex);
0473       sp->SetPopped(false);
0474       m_stack.push_back(sp);
0475       // Set m_top the non-locking IsTop() call
0476       m_top = sp.get();
0477     }
0478   }
0479 
0480   bool IsEmpty() const {
0481     std::lock_guard<std::recursive_mutex> guard(m_mutex);
0482     return m_stack.empty();
0483   }
0484 
0485   lldb::IOHandlerSP Top() {
0486     lldb::IOHandlerSP sp;
0487     {
0488       std::lock_guard<std::recursive_mutex> guard(m_mutex);
0489       if (!m_stack.empty())
0490         sp = m_stack.back();
0491     }
0492     return sp;
0493   }
0494 
0495   void Pop() {
0496     std::lock_guard<std::recursive_mutex> guard(m_mutex);
0497     if (!m_stack.empty()) {
0498       lldb::IOHandlerSP sp(m_stack.back());
0499       m_stack.pop_back();
0500       sp->SetPopped(true);
0501     }
0502     // Set m_top the non-locking IsTop() call
0503 
0504     m_top = (m_stack.empty() ? nullptr : m_stack.back().get());
0505   }
0506 
0507   std::recursive_mutex &GetMutex() { return m_mutex; }
0508 
0509   bool IsTop(const lldb::IOHandlerSP &io_handler_sp) const {
0510     return m_top == io_handler_sp.get();
0511   }
0512 
0513   bool CheckTopIOHandlerTypes(IOHandler::Type top_type,
0514                               IOHandler::Type second_top_type) {
0515     std::lock_guard<std::recursive_mutex> guard(m_mutex);
0516     const size_t num_io_handlers = m_stack.size();
0517     return (num_io_handlers >= 2 &&
0518             m_stack[num_io_handlers - 1]->GetType() == top_type &&
0519             m_stack[num_io_handlers - 2]->GetType() == second_top_type);
0520   }
0521 
0522   llvm::StringRef GetTopIOHandlerControlSequence(char ch) {
0523     return ((m_top != nullptr) ? m_top->GetControlSequence(ch)
0524                                : llvm::StringRef());
0525   }
0526 
0527   const char *GetTopIOHandlerCommandPrefix() {
0528     return ((m_top != nullptr) ? m_top->GetCommandPrefix() : nullptr);
0529   }
0530 
0531   const char *GetTopIOHandlerHelpPrologue() {
0532     return ((m_top != nullptr) ? m_top->GetHelpPrologue() : nullptr);
0533   }
0534 
0535   bool PrintAsync(const char *s, size_t len, bool is_stdout);
0536 
0537 protected:
0538   typedef std::vector<lldb::IOHandlerSP> collection;
0539   collection m_stack;
0540   mutable std::recursive_mutex m_mutex;
0541   IOHandler *m_top = nullptr;
0542 
0543 private:
0544   IOHandlerStack(const IOHandlerStack &) = delete;
0545   const IOHandlerStack &operator=(const IOHandlerStack &) = delete;
0546 };
0547 
0548 } // namespace lldb_private
0549 
0550 #endif // LLDB_CORE_IOHANDLER_H