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