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