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