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