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