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 int skip_first_n_matches, int max_matches, 204 StringList &matches, StringList &descriptions); 205 206 virtual const char *IOHandlerGetFixIndentationCharacters() { return nullptr; } 207 208 /// Called when a new line is created or one of an identified set of 209 /// indentation characters is typed. 210 /// 211 /// This function determines how much indentation should be added 212 /// or removed to match the recommended amount for the final line. 213 /// 214 /// \param[in] io_handler 215 /// The IOHandler that responsible for input. 216 /// 217 /// \param[in] lines 218 /// The current input up to the line to be corrected. Lines 219 /// following the line containing the cursor are not included. 220 /// 221 /// \param[in] cursor_position 222 /// The number of characters preceding the cursor on the final 223 /// line at the time. 224 /// 225 /// \return 226 /// Returns an integer describing the number of spaces needed 227 /// to correct the indentation level. Positive values indicate 228 /// that spaces should be added, while negative values represent 229 /// spaces that should be removed. 230 virtual int IOHandlerFixIndentation(IOHandler &io_handler, 231 const StringList &lines, 232 int cursor_position) { 233 return 0; 234 } 235 236 /// Called when a line or lines have been retrieved. 237 /// 238 /// This function can handle the current line and possibly call 239 /// IOHandler::SetIsDone(true) when the IO handler is done like when 240 /// "quit" is entered as a command, of when an empty line is 241 /// received. It is up to the delegate to determine when a line 242 /// should cause a IOHandler to exit. 243 virtual void IOHandlerInputComplete(IOHandler &io_handler, 244 std::string &data) = 0; 245 246 virtual void IOHandlerInputInterrupted(IOHandler &io_handler, 247 std::string &data) {} 248 249 /// Called to determine whether typing enter after the last line in 250 /// \a lines should end input. This function will not be called on 251 /// IOHandler objects that are getting single lines. 252 /// \param[in] io_handler 253 /// The IOHandler that responsible for updating the lines. 254 /// 255 /// \param[in] lines 256 /// The current multi-line content. May be altered to provide 257 /// alternative input when complete. 258 /// 259 /// \return 260 /// Return an boolean to indicate whether input is complete, 261 /// true indicates that no additional input is necessary, while 262 /// false indicates that more input is required. 263 virtual bool IOHandlerIsInputComplete(IOHandler &io_handler, 264 StringList &lines) { 265 // Impose no requirements for input to be considered complete. subclasses 266 // should do something more intelligent. 267 return true; 268 } 269 270 virtual ConstString IOHandlerGetControlSequence(char ch) { 271 return ConstString(); 272 } 273 274 virtual const char *IOHandlerGetCommandPrefix() { return nullptr; } 275 276 virtual const char *IOHandlerGetHelpPrologue() { return nullptr; } 277 278 // Intercept the IOHandler::Interrupt() calls and do something. 279 // 280 // Return true if the interrupt was handled, false if the IOHandler should 281 // continue to try handle the interrupt itself. 282 virtual bool IOHandlerInterrupt(IOHandler &io_handler) { return false; } 283 284 protected: 285 Completion m_completion; // Support for common builtin completions 286 }; 287 288 // IOHandlerDelegateMultiline 289 // 290 // A IOHandlerDelegate that handles terminating multi-line input when 291 // the last line is equal to "end_line" which is specified in the constructor. 292 class IOHandlerDelegateMultiline : public IOHandlerDelegate { 293 public: 294 IOHandlerDelegateMultiline(const char *end_line, 295 Completion completion = Completion::None) 296 : IOHandlerDelegate(completion), 297 m_end_line((end_line && end_line[0]) ? end_line : "") {} 298 299 ~IOHandlerDelegateMultiline() override = default; 300 301 ConstString IOHandlerGetControlSequence(char ch) override { 302 if (ch == 'd') 303 return ConstString(m_end_line + "\n"); 304 return ConstString(); 305 } 306 307 bool IOHandlerIsInputComplete(IOHandler &io_handler, 308 StringList &lines) override { 309 // Determine whether the end of input signal has been entered 310 const size_t num_lines = lines.GetSize(); 311 if (num_lines > 0 && lines[num_lines - 1] == m_end_line) { 312 // Remove the terminal line from "lines" so it doesn't appear in the 313 // resulting input and return true to indicate we are done getting lines 314 lines.PopBack(); 315 return true; 316 } 317 return false; 318 } 319 320 protected: 321 const std::string m_end_line; 322 }; 323 324 class IOHandlerEditline : public IOHandler { 325 public: 326 IOHandlerEditline(Debugger &debugger, IOHandler::Type type, 327 const char *editline_name, // Used for saving history files 328 llvm::StringRef prompt, llvm::StringRef continuation_prompt, 329 bool multi_line, bool color_prompts, 330 uint32_t line_number_start, // If non-zero show line numbers 331 // starting at 332 // 'line_number_start' 333 IOHandlerDelegate &delegate, 334 repro::DataRecorder *data_recorder); 335 336 IOHandlerEditline(Debugger &debugger, IOHandler::Type type, 337 const lldb::StreamFileSP &input_sp, 338 const lldb::StreamFileSP &output_sp, 339 const lldb::StreamFileSP &error_sp, uint32_t flags, 340 const char *editline_name, // Used for saving history files 341 llvm::StringRef prompt, llvm::StringRef continuation_prompt, 342 bool multi_line, bool color_prompts, 343 uint32_t line_number_start, // If non-zero show line numbers 344 // starting at 345 // 'line_number_start' 346 IOHandlerDelegate &delegate, 347 repro::DataRecorder *data_recorder); 348 349 IOHandlerEditline(Debugger &, IOHandler::Type, const char *, const char *, 350 const char *, bool, bool, uint32_t, 351 IOHandlerDelegate &) = delete; 352 353 IOHandlerEditline(Debugger &, IOHandler::Type, const lldb::StreamFileSP &, 354 const lldb::StreamFileSP &, const lldb::StreamFileSP &, 355 uint32_t, const char *, const char *, const char *, bool, 356 bool, uint32_t, IOHandlerDelegate &) = delete; 357 358 ~IOHandlerEditline() override; 359 360 void Run() override; 361 362 void Cancel() override; 363 364 bool Interrupt() override; 365 366 void GotEOF() override; 367 368 void Activate() override; 369 370 void Deactivate() override; 371 372 ConstString GetControlSequence(char ch) override { 373 return m_delegate.IOHandlerGetControlSequence(ch); 374 } 375 376 const char *GetCommandPrefix() override { 377 return m_delegate.IOHandlerGetCommandPrefix(); 378 } 379 380 const char *GetHelpPrologue() override { 381 return m_delegate.IOHandlerGetHelpPrologue(); 382 } 383 384 const char *GetPrompt() override; 385 386 bool SetPrompt(llvm::StringRef prompt) override; 387 bool SetPrompt(const char *prompt) = delete; 388 389 const char *GetContinuationPrompt(); 390 391 void SetContinuationPrompt(llvm::StringRef prompt); 392 void SetContinuationPrompt(const char *) = delete; 393 394 bool GetLine(std::string &line, bool &interrupted); 395 396 bool GetLines(StringList &lines, bool &interrupted); 397 398 void SetBaseLineNumber(uint32_t line); 399 400 bool GetInterruptExits() { return m_interrupt_exits; } 401 402 void SetInterruptExits(bool b) { m_interrupt_exits = b; } 403 404 const StringList *GetCurrentLines() const { return m_current_lines_ptr; } 405 406 uint32_t GetCurrentLineIndex() const; 407 408 void PrintAsync(Stream *stream, const char *s, size_t len) override; 409 410 private: 411 #ifndef LLDB_DISABLE_LIBEDIT 412 static bool IsInputCompleteCallback(Editline *editline, StringList &lines, 413 void *baton); 414 415 static int FixIndentationCallback(Editline *editline, const StringList &lines, 416 int cursor_position, void *baton); 417 418 static int AutoCompleteCallback(const char *current_line, const char *cursor, 419 const char *last_char, 420 int skip_first_n_matches, int max_matches, 421 StringList &matches, StringList &descriptions, 422 void *baton); 423 #endif 424 425 protected: 426 #ifndef LLDB_DISABLE_LIBEDIT 427 std::unique_ptr<Editline> m_editline_up; 428 #endif 429 IOHandlerDelegate &m_delegate; 430 std::string m_prompt; 431 std::string m_continuation_prompt; 432 StringList *m_current_lines_ptr; 433 uint32_t m_base_line_number; // If non-zero, then show line numbers in prompt 434 uint32_t m_curr_line_idx; 435 bool m_multi_line; 436 bool m_color_prompts; 437 bool m_interrupt_exits; 438 bool m_editing; // Set to true when fetching a line manually (not using 439 // libedit) 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 451 bool GetResponse() const { return m_user_response; } 452 453 int IOHandlerComplete(IOHandler &io_handler, const char *current_line, 454 const char *cursor, const char *last_char, 455 int skip_first_n_matches, int max_matches, 456 StringList &matches, StringList &descriptions) override; 457 458 void IOHandlerInputComplete(IOHandler &io_handler, 459 std::string &data) override; 460 461 protected: 462 const bool m_default_response; 463 bool m_user_response; 464 }; 465 466 class IOHandlerCursesGUI : public IOHandler { 467 public: 468 IOHandlerCursesGUI(Debugger &debugger); 469 470 ~IOHandlerCursesGUI() override; 471 472 void Run() override; 473 474 void Cancel() override; 475 476 bool Interrupt() override; 477 478 void GotEOF() override; 479 480 void Activate() override; 481 482 void Deactivate() override; 483 484 protected: 485 curses::ApplicationAP m_app_ap; 486 }; 487 488 class IOHandlerCursesValueObjectList : public IOHandler { 489 public: 490 IOHandlerCursesValueObjectList(Debugger &debugger, 491 ValueObjectList &valobj_list); 492 493 ~IOHandlerCursesValueObjectList() override; 494 495 void Run() override; 496 497 void GotEOF() override; 498 499 protected: 500 ValueObjectList m_valobj_list; 501 }; 502 503 class IOHandlerStack { 504 public: 505 IOHandlerStack() : m_stack(), m_mutex(), m_top(nullptr) {} 506 507 ~IOHandlerStack() = default; 508 509 size_t GetSize() const { 510 std::lock_guard<std::recursive_mutex> guard(m_mutex); 511 return m_stack.size(); 512 } 513 514 void Push(const lldb::IOHandlerSP &sp) { 515 if (sp) { 516 std::lock_guard<std::recursive_mutex> guard(m_mutex); 517 sp->SetPopped(false); 518 m_stack.push_back(sp); 519 // Set m_top the non-locking IsTop() call 520 m_top = sp.get(); 521 } 522 } 523 524 bool IsEmpty() const { 525 std::lock_guard<std::recursive_mutex> guard(m_mutex); 526 return m_stack.empty(); 527 } 528 529 lldb::IOHandlerSP Top() { 530 lldb::IOHandlerSP sp; 531 { 532 std::lock_guard<std::recursive_mutex> guard(m_mutex); 533 if (!m_stack.empty()) 534 sp = m_stack.back(); 535 } 536 return sp; 537 } 538 539 void Pop() { 540 std::lock_guard<std::recursive_mutex> guard(m_mutex); 541 if (!m_stack.empty()) { 542 lldb::IOHandlerSP sp(m_stack.back()); 543 m_stack.pop_back(); 544 sp->SetPopped(true); 545 } 546 // Set m_top the non-locking IsTop() call 547 548 m_top = (m_stack.empty() ? nullptr : m_stack.back().get()); 549 } 550 551 std::recursive_mutex &GetMutex() { return m_mutex; } 552 553 bool IsTop(const lldb::IOHandlerSP &io_handler_sp) const { 554 return m_top == io_handler_sp.get(); 555 } 556 557 bool CheckTopIOHandlerTypes(IOHandler::Type top_type, 558 IOHandler::Type second_top_type) { 559 std::lock_guard<std::recursive_mutex> guard(m_mutex); 560 const size_t num_io_handlers = m_stack.size(); 561 return (num_io_handlers >= 2 && 562 m_stack[num_io_handlers - 1]->GetType() == top_type && 563 m_stack[num_io_handlers - 2]->GetType() == second_top_type); 564 } 565 566 ConstString GetTopIOHandlerControlSequence(char ch) { 567 return ((m_top != nullptr) ? m_top->GetControlSequence(ch) : ConstString()); 568 } 569 570 const char *GetTopIOHandlerCommandPrefix() { 571 return ((m_top != nullptr) ? m_top->GetCommandPrefix() : nullptr); 572 } 573 574 const char *GetTopIOHandlerHelpPrologue() { 575 return ((m_top != nullptr) ? m_top->GetHelpPrologue() : nullptr); 576 } 577 578 void PrintAsync(Stream *stream, const char *s, size_t len); 579 580 protected: 581 typedef std::vector<lldb::IOHandlerSP> collection; 582 collection m_stack; 583 mutable std::recursive_mutex m_mutex; 584 IOHandler *m_top; 585 586 private: 587 DISALLOW_COPY_AND_ASSIGN(IOHandlerStack); 588 }; 589 590 } // namespace lldb_private 591 592 #endif // liblldb_IOHandler_h_ 593