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