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