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/Host/Config.h" 13 #include "lldb/Utility/CompletionRequest.h" 14 #include "lldb/Utility/Flags.h" 15 #include "lldb/Utility/Predicate.h" 16 #include "lldb/Utility/Stream.h" 17 #include "lldb/Utility/StringList.h" 18 #include "lldb/lldb-defines.h" 19 #include "lldb/lldb-forward.h" 20 #include "llvm/ADT/StringRef.h" 21 22 #include <memory> 23 #include <mutex> 24 #include <optional> 25 #include <string> 26 #include <vector> 27 28 #include <cstdint> 29 #include <cstdio> 30 31 namespace lldb_private { 32 class Debugger; 33 } // namespace lldb_private 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 LuaInterpreter, 54 PythonCode, 55 Other 56 }; 57 58 IOHandler(Debugger &debugger, IOHandler::Type type); 59 60 IOHandler(Debugger &debugger, IOHandler::Type type, 61 const lldb::FileSP &input_sp, 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 83 bool IsActive() { return m_active && !m_done; } 84 85 void SetIsDone(bool b) { m_done = b; } 86 87 bool GetIsDone() { return m_done; } 88 89 Type GetType() const { return m_type; } 90 91 virtual void Activate() { m_active = true; } 92 93 virtual void Deactivate() { m_active = false; } 94 95 virtual void TerminalSizeChanged() {} 96 97 virtual const char *GetPrompt() { 98 // Prompt support isn't mandatory 99 return nullptr; 100 } 101 102 virtual bool SetPrompt(llvm::StringRef prompt) { 103 // Prompt support isn't mandatory 104 return false; 105 } 106 bool SetPrompt(const char *) = delete; 107 108 virtual llvm::StringRef GetControlSequence(char ch) { return {}; } 109 110 virtual const char *GetCommandPrefix() { return nullptr; } 111 112 virtual const char *GetHelpPrologue() { return nullptr; } 113 114 int GetInputFD(); 115 116 int GetOutputFD(); 117 118 int GetErrorFD(); 119 120 FILE *GetInputFILE(); 121 122 FILE *GetOutputFILE(); 123 124 FILE *GetErrorFILE(); 125 126 lldb::FileSP GetInputFileSP(); 127 128 lldb::StreamFileSP GetOutputStreamFileSP(); 129 130 lldb::StreamFileSP GetErrorStreamFileSP(); 131 132 Debugger &GetDebugger() { return m_debugger; } 133 134 void *GetUserData() { return m_user_data; } 135 136 void SetUserData(void *user_data) { m_user_data = user_data; } 137 138 Flags &GetFlags() { return m_flags; } 139 140 const Flags &GetFlags() const { return m_flags; } 141 142 /// Check if the input is being supplied interactively by a user 143 /// 144 /// This will return true if the input stream is a terminal (tty or 145 /// pty) and can cause IO handlers to do different things (like 146 /// for a confirmation when deleting all breakpoints). 147 bool GetIsInteractive(); 148 149 /// Check if the input is coming from a real terminal. 150 /// 151 /// A real terminal has a valid size with a certain number of rows 152 /// and columns. If this function returns true, then terminal escape 153 /// sequences are expected to work (cursor movement escape sequences, 154 /// clearing lines, etc). 155 bool GetIsRealTerminal(); 156 157 void SetPopped(bool b); 158 159 void WaitForPop(); 160 161 virtual void PrintAsync(const char *s, size_t len, bool is_stdout); 162 163 std::recursive_mutex &GetOutputMutex() { return m_output_mutex; } 164 165 protected: 166 Debugger &m_debugger; 167 lldb::FileSP m_input_sp; 168 lldb::StreamFileSP m_output_sp; 169 lldb::StreamFileSP m_error_sp; 170 std::recursive_mutex m_output_mutex; 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 IOHandler(const IOHandler &) = delete; 180 const IOHandler &operator=(const IOHandler &) = delete; 181 }; 182 183 /// A delegate class for use with IOHandler subclasses. 184 /// 185 /// The IOHandler delegate is designed to be mixed into classes so 186 /// they can use an IOHandler subclass to fetch input and notify the 187 /// object that inherits from this delegate class when a token is 188 /// received. 189 class IOHandlerDelegate { 190 public: 191 enum class Completion { None, LLDBCommand, Expression }; 192 193 IOHandlerDelegate(Completion completion = Completion::None) 194 : m_completion(completion) {} 195 196 virtual ~IOHandlerDelegate() = default; 197 198 virtual void IOHandlerActivated(IOHandler &io_handler, bool interactive) {} 199 200 virtual void IOHandlerDeactivated(IOHandler &io_handler) {} 201 202 virtual std::optional<std::string> IOHandlerSuggestion(IOHandler &io_handler, 203 llvm::StringRef line); 204 205 virtual void IOHandlerComplete(IOHandler &io_handler, 206 CompletionRequest &request); 207 208 virtual const char *IOHandlerGetFixIndentationCharacters() { return nullptr; } 209 210 /// Called when a new line is created or one of an identified set of 211 /// indentation characters is typed. 212 /// 213 /// This function determines how much indentation should be added 214 /// or removed to match the recommended amount for the final line. 215 /// 216 /// \param[in] io_handler 217 /// The IOHandler that responsible for input. 218 /// 219 /// \param[in] lines 220 /// The current input up to the line to be corrected. Lines 221 /// following the line containing the cursor are not included. 222 /// 223 /// \param[in] cursor_position 224 /// The number of characters preceding the cursor on the final 225 /// line at the time. 226 /// 227 /// \return 228 /// Returns an integer describing the number of spaces needed 229 /// to correct the indentation level. Positive values indicate 230 /// that spaces should be added, while negative values represent 231 /// spaces that should be removed. 232 virtual int IOHandlerFixIndentation(IOHandler &io_handler, 233 const StringList &lines, 234 int cursor_position) { 235 return 0; 236 } 237 238 /// Called when a line or lines have been retrieved. 239 /// 240 /// This function can handle the current line and possibly call 241 /// IOHandler::SetIsDone(true) when the IO handler is done like when 242 /// "quit" is entered as a command, of when an empty line is 243 /// received. It is up to the delegate to determine when a line 244 /// should cause a IOHandler to exit. 245 virtual void IOHandlerInputComplete(IOHandler &io_handler, 246 std::string &data) = 0; 247 248 virtual void IOHandlerInputInterrupted(IOHandler &io_handler, 249 std::string &data) {} 250 251 /// Called to determine whether typing enter after the last line in 252 /// \a lines should end input. This function will not be called on 253 /// IOHandler objects that are getting single lines. 254 /// \param[in] io_handler 255 /// The IOHandler that responsible for updating the lines. 256 /// 257 /// \param[in] lines 258 /// The current multi-line content. May be altered to provide 259 /// alternative input when complete. 260 /// 261 /// \return 262 /// Return an boolean to indicate whether input is complete, 263 /// true indicates that no additional input is necessary, while 264 /// false indicates that more input is required. 265 virtual bool IOHandlerIsInputComplete(IOHandler &io_handler, 266 StringList &lines) { 267 // Impose no requirements for input to be considered complete. subclasses 268 // should do something more intelligent. 269 return true; 270 } 271 272 virtual llvm::StringRef IOHandlerGetControlSequence(char ch) { return {}; } 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(llvm::StringRef end_line, 295 Completion completion = Completion::None) 296 : IOHandlerDelegate(completion), m_end_line(end_line.str() + "\n") {} 297 298 ~IOHandlerDelegateMultiline() override = default; 299 300 llvm::StringRef IOHandlerGetControlSequence(char ch) override { 301 if (ch == 'd') 302 return m_end_line; 303 return {}; 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 const llvm::StringRef end_line = 311 llvm::StringRef(m_end_line).drop_back(1); // Drop '\n' 312 if (num_lines > 0 && llvm::StringRef(lines[num_lines - 1]) == end_line) { 313 // Remove the terminal line from "lines" so it doesn't appear in the 314 // resulting input and return true to indicate we are done getting lines 315 lines.PopBack(); 316 return true; 317 } 318 return false; 319 } 320 321 protected: 322 const std::string m_end_line; 323 }; 324 325 class IOHandlerEditline : public IOHandler { 326 public: 327 IOHandlerEditline(Debugger &debugger, IOHandler::Type type, 328 const char *editline_name, // Used for saving history files 329 llvm::StringRef prompt, llvm::StringRef continuation_prompt, 330 bool multi_line, bool color, 331 uint32_t line_number_start, // If non-zero show line numbers 332 // starting at 333 // 'line_number_start' 334 IOHandlerDelegate &delegate); 335 336 IOHandlerEditline(Debugger &debugger, IOHandler::Type type, 337 const lldb::FileSP &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, 343 uint32_t line_number_start, // If non-zero show line numbers 344 // starting at 345 // 'line_number_start' 346 IOHandlerDelegate &delegate); 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::FileSP &, 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 void TerminalSizeChanged() override; 372 373 llvm::StringRef GetControlSequence(char ch) override { 374 return m_delegate.IOHandlerGetControlSequence(ch); 375 } 376 377 const char *GetCommandPrefix() override { 378 return m_delegate.IOHandlerGetCommandPrefix(); 379 } 380 381 const char *GetHelpPrologue() override { 382 return m_delegate.IOHandlerGetHelpPrologue(); 383 } 384 385 const char *GetPrompt() override; 386 387 bool SetPrompt(llvm::StringRef prompt) override; 388 bool SetPrompt(const char *prompt) = delete; 389 390 const char *GetContinuationPrompt(); 391 392 void SetContinuationPrompt(llvm::StringRef prompt); 393 void SetContinuationPrompt(const char *) = delete; 394 395 bool GetLine(std::string &line, bool &interrupted); 396 397 bool GetLines(StringList &lines, bool &interrupted); 398 399 void SetBaseLineNumber(uint32_t line); 400 401 bool GetInterruptExits() { return m_interrupt_exits; } 402 403 void SetInterruptExits(bool b) { m_interrupt_exits = b; } 404 405 StringList GetCurrentLines() const; 406 407 uint32_t GetCurrentLineIndex() const; 408 409 void PrintAsync(const char *s, size_t len, bool is_stdout) override; 410 411 private: 412 #if LLDB_ENABLE_LIBEDIT 413 bool IsInputCompleteCallback(Editline *editline, StringList &lines); 414 415 int FixIndentationCallback(Editline *editline, const StringList &lines, 416 int cursor_position); 417 418 std::optional<std::string> SuggestionCallback(llvm::StringRef line); 419 420 void AutoCompleteCallback(CompletionRequest &request); 421 #endif 422 423 protected: 424 #if LLDB_ENABLE_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; 435 bool m_interrupt_exits; 436 std::string m_line_buffer; 437 }; 438 439 // The order of base classes is important. Look at the constructor of 440 // IOHandlerConfirm to see how. 441 class IOHandlerConfirm : public IOHandlerDelegate, public IOHandlerEditline { 442 public: 443 IOHandlerConfirm(Debugger &debugger, llvm::StringRef prompt, 444 bool default_response); 445 446 ~IOHandlerConfirm() override; 447 448 bool GetResponse() const { return m_user_response; } 449 450 void IOHandlerComplete(IOHandler &io_handler, 451 CompletionRequest &request) override; 452 453 void IOHandlerInputComplete(IOHandler &io_handler, 454 std::string &data) override; 455 456 protected: 457 const bool m_default_response; 458 bool m_user_response; 459 }; 460 461 class IOHandlerStack { 462 public: 463 IOHandlerStack() = default; 464 465 size_t GetSize() const { 466 std::lock_guard<std::recursive_mutex> guard(m_mutex); 467 return m_stack.size(); 468 } 469 470 void Push(const lldb::IOHandlerSP &sp) { 471 if (sp) { 472 std::lock_guard<std::recursive_mutex> guard(m_mutex); 473 sp->SetPopped(false); 474 m_stack.push_back(sp); 475 // Set m_top the non-locking IsTop() call 476 m_top = sp.get(); 477 } 478 } 479 480 bool IsEmpty() const { 481 std::lock_guard<std::recursive_mutex> guard(m_mutex); 482 return m_stack.empty(); 483 } 484 485 lldb::IOHandlerSP Top() { 486 lldb::IOHandlerSP sp; 487 { 488 std::lock_guard<std::recursive_mutex> guard(m_mutex); 489 if (!m_stack.empty()) 490 sp = m_stack.back(); 491 } 492 return sp; 493 } 494 495 void Pop() { 496 std::lock_guard<std::recursive_mutex> guard(m_mutex); 497 if (!m_stack.empty()) { 498 lldb::IOHandlerSP sp(m_stack.back()); 499 m_stack.pop_back(); 500 sp->SetPopped(true); 501 } 502 // Set m_top the non-locking IsTop() call 503 504 m_top = (m_stack.empty() ? nullptr : m_stack.back().get()); 505 } 506 507 std::recursive_mutex &GetMutex() { return m_mutex; } 508 509 bool IsTop(const lldb::IOHandlerSP &io_handler_sp) const { 510 return m_top == io_handler_sp.get(); 511 } 512 513 bool CheckTopIOHandlerTypes(IOHandler::Type top_type, 514 IOHandler::Type second_top_type) { 515 std::lock_guard<std::recursive_mutex> guard(m_mutex); 516 const size_t num_io_handlers = m_stack.size(); 517 return (num_io_handlers >= 2 && 518 m_stack[num_io_handlers - 1]->GetType() == top_type && 519 m_stack[num_io_handlers - 2]->GetType() == second_top_type); 520 } 521 522 llvm::StringRef GetTopIOHandlerControlSequence(char ch) { 523 return ((m_top != nullptr) ? m_top->GetControlSequence(ch) 524 : llvm::StringRef()); 525 } 526 527 const char *GetTopIOHandlerCommandPrefix() { 528 return ((m_top != nullptr) ? m_top->GetCommandPrefix() : nullptr); 529 } 530 531 const char *GetTopIOHandlerHelpPrologue() { 532 return ((m_top != nullptr) ? m_top->GetHelpPrologue() : nullptr); 533 } 534 535 bool PrintAsync(const char *s, size_t len, bool is_stdout); 536 537 protected: 538 typedef std::vector<lldb::IOHandlerSP> collection; 539 collection m_stack; 540 mutable std::recursive_mutex m_mutex; 541 IOHandler *m_top = nullptr; 542 543 private: 544 IOHandlerStack(const IOHandlerStack &) = delete; 545 const IOHandlerStack &operator=(const IOHandlerStack &) = delete; 546 }; 547 548 } // namespace lldb_private 549 550 #endif // LLDB_CORE_IOHANDLER_H 551