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