xref: /freebsd/contrib/llvm-project/lldb/include/lldb/Core/IOHandler.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===-- IOHandler.h ---------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLDB_CORE_IOHANDLER_H
10 #define LLDB_CORE_IOHANDLER_H
11 
12 #include "lldb/Host/Config.h"
13 #include "lldb/Utility/CompletionRequest.h"
14 #include "lldb/Utility/Flags.h"
15 #include "lldb/Utility/Predicate.h"
16 #include "lldb/Utility/Stream.h"
17 #include "lldb/Utility/StringList.h"
18 #include "lldb/lldb-defines.h"
19 #include "lldb/lldb-forward.h"
20 #include "llvm/ADT/StringRef.h"
21 
22 #include <memory>
23 #include <mutex>
24 #include <optional>
25 #include <string>
26 #include <vector>
27 
28 #include <cstdint>
29 #include <cstdio>
30 
31 namespace lldb_private {
32 class Debugger;
33 } // namespace lldb_private
34 
35 namespace lldb_private {
36 
37 class IOHandler {
38 public:
39   enum class Type {
40     CommandInterpreter,
41     CommandList,
42     Confirm,
43     Curses,
44     Expression,
45     REPL,
46     ProcessIO,
47     PythonInterpreter,
48     LuaInterpreter,
49     PythonCode,
50     Other
51   };
52 
53   IOHandler(Debugger &debugger, IOHandler::Type type);
54 
55   IOHandler(Debugger &debugger, IOHandler::Type type,
56             const lldb::FileSP &input_sp,
57             const lldb::LockableStreamFileSP &output_sp,
58             const lldb::LockableStreamFileSP &error_sp, uint32_t flags);
59 
60   virtual ~IOHandler();
61 
62   // Each IOHandler gets to run until it is done. It should read data from the
63   // "in" and place output into "out" and "err and return when done.
64   virtual void Run() = 0;
65 
66   // Called when an input reader should relinquish its control so another can
67   // be pushed onto the IO handler stack, or so the current IO handler can pop
68   // itself off the stack
69 
70   virtual void Cancel() = 0;
71 
72   // Called when CTRL+C is pressed which usually causes
73   // Debugger::DispatchInputInterrupt to be called.
74 
75   virtual bool Interrupt() = 0;
76 
77   virtual void GotEOF() = 0;
78 
IsActive()79   bool IsActive() { return m_active && !m_done; }
80 
SetIsDone(bool b)81   void SetIsDone(bool b) { m_done = b; }
82 
GetIsDone()83   bool GetIsDone() { return m_done; }
84 
GetType()85   Type GetType() const { return m_type; }
86 
Activate()87   virtual void Activate() { m_active = true; }
88 
Deactivate()89   virtual void Deactivate() { m_active = false; }
90 
TerminalSizeChanged()91   virtual void TerminalSizeChanged() {}
92 
Refresh()93   virtual void Refresh() {}
94 
GetPrompt()95   virtual const char *GetPrompt() {
96     // Prompt support isn't mandatory
97     return nullptr;
98   }
99 
SetPrompt(llvm::StringRef prompt)100   virtual bool SetPrompt(llvm::StringRef prompt) {
101     // Prompt support isn't mandatory
102     return false;
103   }
104 
SetUseColor(bool use_color)105   virtual bool SetUseColor(bool use_color) {
106     // Color support isn't mandatory.
107     return false;
108   };
109 
110   bool SetPrompt(const char *) = delete;
111 
GetControlSequence(char ch)112   virtual llvm::StringRef GetControlSequence(char ch) { return {}; }
113 
GetCommandPrefix()114   virtual const char *GetCommandPrefix() { return nullptr; }
115 
GetHelpPrologue()116   virtual const char *GetHelpPrologue() { return nullptr; }
117 
118   int GetInputFD();
119 
120   int GetOutputFD();
121 
122   int GetErrorFD();
123 
124   lldb::FileSP GetInputFileSP();
125 
126   lldb::LockableStreamFileSP GetOutputStreamFileSP();
127 
128   lldb::LockableStreamFileSP GetErrorStreamFileSP();
129 
GetDebugger()130   Debugger &GetDebugger() { return m_debugger; }
131 
GetUserData()132   void *GetUserData() { return m_user_data; }
133 
SetUserData(void * user_data)134   void SetUserData(void *user_data) { m_user_data = user_data; }
135 
GetFlags()136   Flags &GetFlags() { return m_flags; }
137 
GetFlags()138   const Flags &GetFlags() const { return m_flags; }
139 
140   /// Check if the input is being supplied interactively by a user
141   ///
142   /// This will return true if the input stream is a terminal (tty or
143   /// pty) and can cause IO handlers to do different things (like
144   /// for a confirmation when deleting all breakpoints).
145   bool GetIsInteractive();
146 
147   /// Check if the input is coming from a real terminal.
148   ///
149   /// A real terminal has a valid size with a certain number of rows
150   /// and columns. If this function returns true, then terminal escape
151   /// sequences are expected to work (cursor movement escape sequences,
152   /// clearing lines, etc).
153   bool GetIsRealTerminal();
154 
155   void SetPopped(bool b);
156 
157   void WaitForPop();
158 
159   virtual void PrintAsync(const char *s, size_t len, bool is_stdout);
160 
161 protected:
162   Debugger &m_debugger;
163   lldb::FileSP m_input_sp;
164   lldb::LockableStreamFileSP m_output_sp;
165   lldb::LockableStreamFileSP m_error_sp;
166   Predicate<bool> m_popped;
167   Flags m_flags;
168   Type m_type;
169   void *m_user_data;
170   bool m_done;
171   bool m_active;
172 
173 private:
174   IOHandler(const IOHandler &) = delete;
175   const IOHandler &operator=(const IOHandler &) = delete;
176 };
177 
178 /// A delegate class for use with IOHandler subclasses.
179 ///
180 /// The IOHandler delegate is designed to be mixed into classes so
181 /// they can use an IOHandler subclass to fetch input and notify the
182 /// object that inherits from this delegate class when a token is
183 /// received.
184 class IOHandlerDelegate {
185 public:
186   enum class Completion { None, LLDBCommand, Expression };
187 
188   IOHandlerDelegate(Completion completion = Completion::None)
m_completion(completion)189       : m_completion(completion) {}
190 
191   virtual ~IOHandlerDelegate() = default;
192 
IOHandlerActivated(IOHandler & io_handler,bool interactive)193   virtual void IOHandlerActivated(IOHandler &io_handler, bool interactive) {}
194 
IOHandlerDeactivated(IOHandler & io_handler)195   virtual void IOHandlerDeactivated(IOHandler &io_handler) {}
196 
197   virtual std::optional<std::string> IOHandlerSuggestion(IOHandler &io_handler,
198                                                          llvm::StringRef line);
199 
200   virtual void IOHandlerComplete(IOHandler &io_handler,
201                                  CompletionRequest &request);
202 
IOHandlerGetFixIndentationCharacters()203   virtual const char *IOHandlerGetFixIndentationCharacters() { return nullptr; }
204 
205   /// Called when a new line is created or one of an identified set of
206   /// indentation characters is typed.
207   ///
208   /// This function determines how much indentation should be added
209   /// or removed to match the recommended amount for the final line.
210   ///
211   /// \param[in] io_handler
212   ///     The IOHandler that responsible for input.
213   ///
214   /// \param[in] lines
215   ///     The current input up to the line to be corrected.  Lines
216   ///     following the line containing the cursor are not included.
217   ///
218   /// \param[in] cursor_position
219   ///     The number of characters preceding the cursor on the final
220   ///     line at the time.
221   ///
222   /// \return
223   ///     Returns an integer describing the number of spaces needed
224   ///     to correct the indentation level.  Positive values indicate
225   ///     that spaces should be added, while negative values represent
226   ///     spaces that should be removed.
IOHandlerFixIndentation(IOHandler & io_handler,const StringList & lines,int cursor_position)227   virtual int IOHandlerFixIndentation(IOHandler &io_handler,
228                                       const StringList &lines,
229                                       int cursor_position) {
230     return 0;
231   }
232 
233   /// Called when a line or lines have been retrieved.
234   ///
235   /// This function can handle the current line and possibly call
236   /// IOHandler::SetIsDone(true) when the IO handler is done like when
237   /// "quit" is entered as a command, of when an empty line is
238   /// received. It is up to the delegate to determine when a line
239   /// should cause a IOHandler to exit.
240   virtual void IOHandlerInputComplete(IOHandler &io_handler,
241                                       std::string &data) = 0;
242 
IOHandlerInputInterrupted(IOHandler & io_handler,std::string & data)243   virtual void IOHandlerInputInterrupted(IOHandler &io_handler,
244                                          std::string &data) {}
245 
246   /// Called to determine whether typing enter after the last line in
247   /// \a lines should end input.  This function will not be called on
248   /// IOHandler objects that are getting single lines.
249   /// \param[in] io_handler
250   ///     The IOHandler that responsible for updating the lines.
251   ///
252   /// \param[in] lines
253   ///     The current multi-line content.  May be altered to provide
254   ///     alternative input when complete.
255   ///
256   /// \return
257   ///     Return an boolean to indicate whether input is complete,
258   ///     true indicates that no additional input is necessary, while
259   ///     false indicates that more input is required.
IOHandlerIsInputComplete(IOHandler & io_handler,StringList & lines)260   virtual bool IOHandlerIsInputComplete(IOHandler &io_handler,
261                                         StringList &lines) {
262     // Impose no requirements for input to be considered complete.  subclasses
263     // should do something more intelligent.
264     return true;
265   }
266 
IOHandlerGetControlSequence(char ch)267   virtual llvm::StringRef IOHandlerGetControlSequence(char ch) { return {}; }
268 
IOHandlerGetCommandPrefix()269   virtual const char *IOHandlerGetCommandPrefix() { return nullptr; }
270 
IOHandlerGetHelpPrologue()271   virtual const char *IOHandlerGetHelpPrologue() { return nullptr; }
272 
273   // Intercept the IOHandler::Interrupt() calls and do something.
274   //
275   // Return true if the interrupt was handled, false if the IOHandler should
276   // continue to try handle the interrupt itself.
IOHandlerInterrupt(IOHandler & io_handler)277   virtual bool IOHandlerInterrupt(IOHandler &io_handler) { return false; }
278 
279 protected:
280   Completion m_completion; // Support for common builtin completions
281 };
282 
283 // IOHandlerDelegateMultiline
284 //
285 // A IOHandlerDelegate that handles terminating multi-line input when
286 // the last line is equal to "end_line" which is specified in the constructor.
287 class IOHandlerDelegateMultiline : public IOHandlerDelegate {
288 public:
289   IOHandlerDelegateMultiline(llvm::StringRef end_line,
290                              Completion completion = Completion::None)
IOHandlerDelegate(completion)291       : IOHandlerDelegate(completion), m_end_line(end_line.str() + "\n") {}
292 
293   ~IOHandlerDelegateMultiline() override = default;
294 
IOHandlerGetControlSequence(char ch)295   llvm::StringRef IOHandlerGetControlSequence(char ch) override {
296     if (ch == 'd')
297       return m_end_line;
298     return {};
299   }
300 
IOHandlerIsInputComplete(IOHandler & io_handler,StringList & lines)301   bool IOHandlerIsInputComplete(IOHandler &io_handler,
302                                 StringList &lines) override {
303     // Determine whether the end of input signal has been entered
304     const size_t num_lines = lines.GetSize();
305     const llvm::StringRef end_line =
306         llvm::StringRef(m_end_line).drop_back(1); // Drop '\n'
307     if (num_lines > 0 && llvm::StringRef(lines[num_lines - 1]) == end_line) {
308       // Remove the terminal line from "lines" so it doesn't appear in the
309       // resulting input and return true to indicate we are done getting lines
310       lines.PopBack();
311       return true;
312     }
313     return false;
314   }
315 
316 protected:
317   const std::string m_end_line;
318 };
319 
320 class IOHandlerEditline : public IOHandler {
321 public:
322   IOHandlerEditline(Debugger &debugger, IOHandler::Type type,
323                     const char *editline_name, // Used for saving history files
324                     llvm::StringRef prompt, llvm::StringRef continuation_prompt,
325                     bool multi_line, bool color,
326                     uint32_t line_number_start, // If non-zero show line numbers
327                                                 // starting at
328                                                 // 'line_number_start'
329                     IOHandlerDelegate &delegate);
330 
331   IOHandlerEditline(Debugger &debugger, IOHandler::Type type,
332                     const lldb::FileSP &input_sp,
333                     const lldb::LockableStreamFileSP &output_sp,
334                     const lldb::LockableStreamFileSP &error_sp, uint32_t flags,
335                     const char *editline_name, // Used for saving history files
336                     llvm::StringRef prompt, llvm::StringRef continuation_prompt,
337                     bool multi_line, bool color,
338                     uint32_t line_number_start, // If non-zero show line numbers
339                                                 // starting at
340                                                 // 'line_number_start'
341                     IOHandlerDelegate &delegate);
342 
343   IOHandlerEditline(Debugger &, IOHandler::Type, const char *, const char *,
344                     const char *, bool, bool, uint32_t,
345                     IOHandlerDelegate &) = delete;
346 
347   IOHandlerEditline(Debugger &, IOHandler::Type, const lldb::FileSP &,
348                     const lldb::LockableStreamFileSP &,
349                     const lldb::LockableStreamFileSP &, uint32_t, const char *,
350                     const char *, const char *, bool, bool, uint32_t,
351                     IOHandlerDelegate &) = delete;
352 
353   ~IOHandlerEditline() override;
354 
355   void Run() override;
356 
357   void Cancel() override;
358 
359   bool Interrupt() override;
360 
361   void GotEOF() override;
362 
363   void Activate() override;
364 
365   void Deactivate() override;
366 
367   void TerminalSizeChanged() override;
368 
GetControlSequence(char ch)369   llvm::StringRef GetControlSequence(char ch) override {
370     return m_delegate.IOHandlerGetControlSequence(ch);
371   }
372 
GetCommandPrefix()373   const char *GetCommandPrefix() override {
374     return m_delegate.IOHandlerGetCommandPrefix();
375   }
376 
GetHelpPrologue()377   const char *GetHelpPrologue() override {
378     return m_delegate.IOHandlerGetHelpPrologue();
379   }
380 
381   const char *GetPrompt() override;
382 
383   bool SetPrompt(llvm::StringRef prompt) override;
384   bool SetPrompt(const char *prompt) = delete;
385 
386   bool SetUseColor(bool use_color) override;
387 
388   const char *GetContinuationPrompt();
389 
390   void SetContinuationPrompt(llvm::StringRef prompt);
391   void SetContinuationPrompt(const char *) = delete;
392 
393   bool GetLine(std::string &line, bool &interrupted);
394 
395   bool GetLines(StringList &lines, bool &interrupted);
396 
397   void SetBaseLineNumber(uint32_t line);
398 
GetInterruptExits()399   bool GetInterruptExits() { return m_interrupt_exits; }
400 
SetInterruptExits(bool b)401   void SetInterruptExits(bool b) { m_interrupt_exits = b; }
402 
403   StringList GetCurrentLines() const;
404 
405   uint32_t GetCurrentLineIndex() const;
406 
407   void PrintAsync(const char *s, size_t len, bool is_stdout) override;
408 
409   void Refresh() override;
410 
411 private:
412 #if LLDB_ENABLE_LIBEDIT
413   bool IsInputCompleteCallback(Editline *editline, StringList &lines);
414 
415   int FixIndentationCallback(Editline *editline, const StringList &lines,
416                              int cursor_position);
417 
418   std::optional<std::string> SuggestionCallback(llvm::StringRef line);
419 
420   void AutoCompleteCallback(CompletionRequest &request);
421 
422   void RedrawCallback();
423 #endif
424 
425 protected:
426 #if LLDB_ENABLE_LIBEDIT
427   std::unique_ptr<Editline> m_editline_up;
428 #endif
429   IOHandlerDelegate &m_delegate;
430   std::string m_prompt;
431   std::string m_continuation_prompt;
432   StringList *m_current_lines_ptr;
433   uint32_t m_base_line_number; // If non-zero, then show line numbers in prompt
434   uint32_t m_curr_line_idx;
435   bool m_multi_line;
436   bool m_color;
437   bool m_interrupt_exits;
438   std::string m_line_buffer;
439 };
440 
441 // The order of base classes is important. Look at the constructor of
442 // IOHandlerConfirm to see how.
443 class IOHandlerConfirm : public IOHandlerDelegate, public IOHandlerEditline {
444 public:
445   IOHandlerConfirm(Debugger &debugger, llvm::StringRef prompt,
446                    bool default_response);
447 
448   ~IOHandlerConfirm() override;
449 
GetResponse()450   bool GetResponse() const { return m_user_response; }
451 
452   void IOHandlerComplete(IOHandler &io_handler,
453                          CompletionRequest &request) override;
454 
455   void IOHandlerInputComplete(IOHandler &io_handler,
456                               std::string &data) override;
457 
458 protected:
459   const bool m_default_response;
460   bool m_user_response;
461 };
462 
463 class IOHandlerStack {
464 public:
465   IOHandlerStack() = default;
466 
GetSize()467   size_t GetSize() const {
468     std::lock_guard<std::recursive_mutex> guard(m_mutex);
469     return m_stack.size();
470   }
471 
Push(const lldb::IOHandlerSP & sp)472   void Push(const lldb::IOHandlerSP &sp) {
473     if (sp) {
474       std::lock_guard<std::recursive_mutex> guard(m_mutex);
475       sp->SetPopped(false);
476       m_stack.push_back(sp);
477       // Set m_top the non-locking IsTop() call
478       m_top = sp.get();
479     }
480   }
481 
IsEmpty()482   bool IsEmpty() const {
483     std::lock_guard<std::recursive_mutex> guard(m_mutex);
484     return m_stack.empty();
485   }
486 
Top()487   lldb::IOHandlerSP Top() {
488     lldb::IOHandlerSP sp;
489     {
490       std::lock_guard<std::recursive_mutex> guard(m_mutex);
491       if (!m_stack.empty())
492         sp = m_stack.back();
493     }
494     return sp;
495   }
496 
Pop()497   void Pop() {
498     std::lock_guard<std::recursive_mutex> guard(m_mutex);
499     if (!m_stack.empty()) {
500       lldb::IOHandlerSP sp(m_stack.back());
501       m_stack.pop_back();
502       sp->SetPopped(true);
503     }
504     // Set m_top the non-locking IsTop() call
505 
506     m_top = (m_stack.empty() ? nullptr : m_stack.back().get());
507   }
508 
GetMutex()509   std::recursive_mutex &GetMutex() { return m_mutex; }
510 
IsTop(const lldb::IOHandlerSP & io_handler_sp)511   bool IsTop(const lldb::IOHandlerSP &io_handler_sp) const {
512     return m_top == io_handler_sp.get();
513   }
514 
CheckTopIOHandlerTypes(IOHandler::Type top_type,IOHandler::Type second_top_type)515   bool CheckTopIOHandlerTypes(IOHandler::Type top_type,
516                               IOHandler::Type second_top_type) {
517     std::lock_guard<std::recursive_mutex> guard(m_mutex);
518     const size_t num_io_handlers = m_stack.size();
519     return (num_io_handlers >= 2 &&
520             m_stack[num_io_handlers - 1]->GetType() == top_type &&
521             m_stack[num_io_handlers - 2]->GetType() == second_top_type);
522   }
523 
GetTopIOHandlerControlSequence(char ch)524   llvm::StringRef GetTopIOHandlerControlSequence(char ch) {
525     return ((m_top != nullptr) ? m_top->GetControlSequence(ch)
526                                : llvm::StringRef());
527   }
528 
GetTopIOHandlerCommandPrefix()529   const char *GetTopIOHandlerCommandPrefix() {
530     return ((m_top != nullptr) ? m_top->GetCommandPrefix() : nullptr);
531   }
532 
GetTopIOHandlerHelpPrologue()533   const char *GetTopIOHandlerHelpPrologue() {
534     return ((m_top != nullptr) ? m_top->GetHelpPrologue() : nullptr);
535   }
536 
537   bool PrintAsync(const char *s, size_t len, bool is_stdout);
538 
539 protected:
540   typedef std::vector<lldb::IOHandlerSP> collection;
541   collection m_stack;
542   mutable std::recursive_mutex m_mutex;
543   IOHandler *m_top = nullptr;
544 
545 private:
546   IOHandlerStack(const IOHandlerStack &) = delete;
547   const IOHandlerStack &operator=(const IOHandlerStack &) = delete;
548 };
549 
550 } // namespace lldb_private
551 
552 #endif // LLDB_CORE_IOHANDLER_H
553